본문 바로가기
Python/OpenPose

[OpenPose] 이미지 인물 뼈대(skeleton) 검출

by hotelshoe 2022. 2. 21.
반응형

OpenPose를 활용한 이미지 속 인물들의 뼈대(skeleton)를 검출해보겠습니다. 테스트 전 필요한 모델 파일은 하단 링크를 참조하여 다운로드하면 되겠습니다.

https://prlabhotelshoe.tistory.com/25?category=1005609 

 

[OpenPose] 영상 손가락 마디&관절 인식

사진 혹은 영상 속 인물들의 스켈레톤 검출에 대표적으로 쓰이는 OpenPose의 모델과 OpenCV를 활용하여 영상에서의 손가락 관절과 마디를 검출하도록 하겠습니다. 1. 모델파일 설치 필요한 파일은 'p

prlabhotelshoe.tistory.com

이번 테스트에 필요한 파일인 pose_deploy_linevec_faster_4_stages.prototxt 파일은 다운받은 openpose 폴더의 openpose-master -> models -> pose -> mpi 의 경로에 위치해 있습니다.

 

추가적으로 필요한 pose_iter_160000.caffemodel 파일의 경우 하단 링크를 통해 직접 내려받을 수 있습니다.

http://posefs1.perception.cs.cmu.edu/OpenPose/models/pose/mpi/pose_iter_160000.caffemodel

 


소스코드

import cv2

#-- 파츠명 선언
BODY_PARTS = { "Head": 0, "Neck": 1, "RShoulder": 2, "RElbow": 3, "RWrist": 4,
                "LShoulder": 5, "LElbow": 6, "LWrist": 7, "RHip": 8, "RKnee": 9,
                "RAnkle": 10, "LHip": 11, "LKnee": 12, "LAnkle": 13, "Chest": 14,
                "Background": 15 }

POSE_PAIRS = [ ["Head", "Neck"], ["Neck", "RShoulder"], ["RShoulder", "RElbow"],
                ["RElbow", "RWrist"], ["Neck", "LShoulder"], ["LShoulder", "LElbow"],
                ["LElbow", "LWrist"], ["Neck", "Chest"], ["Chest", "RHip"], ["RHip", "RKnee"],
                ["RKnee", "RAnkle"], ["Chest", "LHip"], ["LHip", "LKnee"], ["LKnee", "LAnkle"] ]
    
#-- 모델 파일 불러오기
protoFile = "./pose_deploy_linevec_faster_4_stages.prototxt" #-- 자신의 환경에 맞게 경로 변경할 것
weightsFile = "./pose_iter_160000.caffemodel" #-- 자신의 환경에 맞게 경로 변경할 것
 
#-- network 불러오기
net = cv2.dnn.readNetFromCaffe(protoFile, weightsFile)

#-- 이미지 불러오기
image = cv2.imread("./img.jpg")

imageHeight, imageWidth, _ = image.shape #-- 불러온 이미지에서 height, width, color를 가져옴
 
inpBlob = cv2.dnn.blobFromImage(image, 1.0 / 255, (imageWidth, imageHeight), (0, 0, 0), swapRB=False, crop=False) #-- network에 적용하기 위한 전처리
 
net.setInput(inpBlob)

output = net.forward()

H = output.shape[2]
W = output.shape[3]

#-- 검출된 키포인트 적용 
points = []
for i in range(0,15):
    probMap = output[0, i, :, :]
 
    minVal, prob, minLoc, point = cv2.minMaxLoc(probMap)

    #-- 원본 이미지에 맞도록 포인트 위치 적용
    x = (imageWidth * point[0]) / W
    y = (imageHeight * point[1]) / H

    #-- 검출된 포인트가 BODY_PARRTS와 대응되면 포인트 추가(검출 결과가 0.1보다 크면) / 검출했으나 해당 파츠가 없는 경우 None    
    if prob > 0.1 :    
        cv2.circle(image, (int(x), int(y)), 3, (0, 255, 255), thickness=-1, lineType=cv2.FILLED) #-- circle(이미지, 원의 중심, 반지름, 컬러)
        cv2.putText(image, "{}".format(i), (int(x), int(y)), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 255), 1, lineType=cv2.LINE_AA)
        points.append((int(x), int(y)))
    else :
        points.append(None)

#-- 생성된 POSE_PAIRS에 맞게 라인 생성
for pair in POSE_PAIRS:
    partA = pair[0]             #-- 머리
    partA = BODY_PARTS[partA]   
    partB = pair[1]             #-- 목
    partB = BODY_PARTS[partB]   
    
    if points[partA] and points[partB]:
        cv2.line(image, points[partA], points[partB], (0, 255, 0), 2)


cv2.imshow("OpenPoseImgTest",image)
cv2.waitKey(0)
cv2.destroyAllWindows()

테스트

 

출력 예시

출력 결과

이미지 속 한 명의 인물에 대해선 대체적으로 검출이 잘 되는 모습이다. (머리카락 끝을 오른쪽 팔꿈치로 인식한 오류가 있다..) 

 

출력 예시

여려명에 대해서의 출력 결과

아무래도 한 명에 대해서만 검출이 가능하여 인물이 여려명일 경우 인식이 제대로 이루어지지 않는 점을 볼 수 있다.

반응형

댓글