2021-04-05 08:52:32

오늘은 openpose 라이브러리를 이용해서 관절 포인트들을 검출해보겠습니다. 한 장의 이미지를 이미 훈련된 pose estimation 모델에 넣어줘서 key point(관절 포인트)들이 검출된 결과를 얻어볼 것입니다. 

 

우선 CMU-Perceptual-Computing-Lab의 깃헙에서 openpose를 다운로드 받습니다. github.com/CMU-Perceptual-Computing-Lab/openpose

 

 

별의 갯수와 fork의 숫자를 보니 정말 많은 사람들이 사용하는 라이브러리네요. 

 

openpose 라이브러리 다운로드가 완료되었다면, 압축을 푼 후에 models 디렉토리로 이동한 후에 getModels.bat을 실행합니다. 더블클릭하면 됩니다. 그러면 다음과 같은 창이 뜨면서 이런 저런 모델들을 다운로드하기 시작합니다. 꽤 오래 걸리니 다른 급한 일 처리하고 계셔도 됩니다.  

 

 

다운로드가 완료되면 저절로 창이 닫힙니다. 

 

그러면 여러 훈련된 모델들 중에 저는 MPII Human Pose Dataset에서 훈련된 관절 검출 모델을 사용해보겠습니다. MPII 데이터셋은 관절 부위가 라벨링된 25000장의 이미지를 제공합니다. 

 

models/pose/mpi/ 디렉토리 안에 있는 pose_deploy_linevecpose_deploy_linevec_faster_4_stages.prototxt와 pose_iter_160000.caffemodel를 복사해서 파이썬 스크립트 파일이 있는 위치에 붙여넣어줍니다. 만약 좀 더 무겁지만 정확한 모델을 사용하고 싶다면, pose_deloy_linevec_faster_4_stages.prototxt 대신에 pose_deploy_linevec.prototxt를 사용하시면 됩니다.

 

 

이전에 물론 파이참이나 아나콘다 등의 IDE를 이용해서 개발환경 세팅을 해줘야합니다. 그리고 opencv 라이브러리도 설치해줘야 합니다. 

 

pip install opencv-python

 

그리고 테스트에 사용할 이미지를 하나 준비해줍니다. 저는 다음과 같은 이미지를 테스트 이미지로 준비했습니다. 

 

test.JPG

 

이제 파이썬 스크립트 파일에 다음과 같은 코드를 복사해서 붙여넣어줍니다. 아래 코드는 m.blog.naver.com/rhrkdfus/221531159811 블로그(코칸리's 코오딩)에서 제공한 코드를 제 상황에 맞게 살짝 수정한 것입니다. 

 

test.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
import cv2
 
# 관절 번호: 머리는 0, 목은 1 등등
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"]]
 
# 훈련된 network 세팅
protoFile = "pose_deploy_linevec_faster_4_stages.prototxt"
weightsFile = "pose_iter_160000.caffemodel"
net = cv2.dnn.readNetFromCaffe(protoFile, weightsFile)
 
# 테스트 이미지 읽기
image = cv2.imread("test.JPG")
 
# 테스트 이미지에서 height, width, color 정보 파악
imageHeight, imageWidth, imageColor = image.shape
 
# 테스트 이미지를 network에 넣기 위해 전처리
inpBlob = cv2.dnn.blobFromImage(image, 1.0 / 255, (imageWidth, imageHeight), (000), swapRB=False, crop=False)
 
# 테스트 이미지를 network에 넣어줌
net.setInput(inpBlob)
 
# 결과 받아오기
output = net.forward()
 
= output.shape[2]
= output.shape[3]
 
# 검출된 관절 포인트를 테스트 이미지에 그려주기
points = []
for i in range(015):
    # 해당 관절 신뢰도 얻기
    probMap = output[0, i, :, :]
 
    # global 최대값 찾기
    minVal, prob, minLoc, point = cv2.minMaxLoc(probMap)
 
    # 원래 이미지에 맞게 점 위치 변경
    x = (imageWidth * point[0]) / W
    y = (imageHeight * point[1]) / H
 
    # 키포인트 검출한 결과가 0.1보다 크면(검출한곳이 위 BODY_PARTS랑 맞는 부위면) points에 추가, 검출했는데 부위가 없으면 None으로
    if prob > 0.1:
        cv2.circle(image, (int(x), int(y)), 3, (0255255), thickness=-1,
                   lineType=cv2.FILLED)  # circle(그릴곳, 원의 중심, 반지름, 색)
        cv2.putText(image, "{}".format(i), (int(x), int(y)), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (00255), 1,
                    lineType=cv2.LINE_AA)
        points.append((int(x), int(y)))
    else:
        points.append(None)
 
cv2.imshow("Output-Keypoints", image)
cv2.waitKey(0)
 
# 관절들을 선으로 연결해주기
for pair in POSE_PAIRS:
    partA = pair[0]  # Head
    partA = BODY_PARTS[partA]  # 0
    partB = pair[1]  # Neck
    partB = BODY_PARTS[partB]  # 1
 
    # print(partA," 와 ", partB, " 연결\n")
    if points[partA] and points[partB]:
        cv2.line(image, points[partA], points[partB], (25500), 2)
 
cv2.imshow("Output-Keypoints-with-Lines", image)
cv2.waitKey(0)
cv2.destroyAllWindows()
cs

 

이제 위 파일을 실행시켜보겠습니다. 

 

python test.py

 

실행 결과 두 개의 이미지가 순차적으로 화면에 뜹니다. 

 

꼬장님 안녕?

 

 

보시다시피 상반신의 관절들은 가슴 포인트(14번)를 제외하고 잘 검출되었지만, 하반신 쪽 포인트들(8-13번)은 약간 엉망으로 검출되었습니다. 관절 포인트들을 연결해놓은 이미지를 보니 목이 긴 괴물처럼 되었죠. ㅋㅋ

 

오늘은 일단 관절 포인트 검출을 해봤다는 것에 의의를 두고 글을 마치도록 하겠습니다. 

 

참고자료

[1] m.blog.naver.com/rhrkdfus/221531159811, 코칸리's 코오딩, "[OpenPose] Python OpenPose 시작하기"