import cv2
필요한 모듈 import
def output_keypoints(frame, net, threshold, BODY_PARTS, now_frame, total_frame):
global points
# 입력 이미지의 사이즈 정의
image_height = 368
image_width = 368
# 네트워크에 넣기 위한 전처리
input_blob = cv2.dnn.blobFromImage(frame, 1.0 / 255, (image_width, image_height), (0, 0, 0), swapRB=False, crop=False)
# 전처리된 blob 네트워크에 입력
net.setInput(input_blob)
# 결과 받아오기
out = net.forward()
# The output is a 4D matrix :
# The first dimension being the image ID ( in case you pass more than one image to the network ).
# The second dimension indicates the index of a keypoint.
# The model produces Confidence Maps and Part Affinity maps which are all concatenated.
# For COCO model it consists of 57 parts – 18 keypoint confidence Maps + 1 background + 19*2 Part Affinity Maps. Similarly, for MPI, it produces 44 points.
# We will be using only the first few points which correspond to Keypoints.
# The third dimension is the height of the output map.
out_height = out.shape[2]
# The fourth dimension is the width of the output map.
out_width = out.shape[3]
# 원본 이미지의 높이, 너비를 받아오기
frame_height, frame_width = frame.shape[:2]
# 포인트 리스트 초기화
points = []
print(f"============================== frame: {now_frame:.0f} / {total_frame:.0f} ==============================")
for i in range(len(BODY_PARTS)):
# 신체 부위의 confidence map
prob_map = out[0, i, :, :]
# 최소값, 최대값, 최소값 위치, 최대값 위치
min_val, prob, min_loc, point = cv2.minMaxLoc(prob_map)
# 원본 이미지에 맞게 포인트 위치 조정
x = (frame_width * point[0]) / out_width
x = int(x)
y = (frame_height * point[1]) / out_height
y = int(y)
if prob > threshold: # [pointed]
cv2.circle(frame, (x, y), 5, (0, 255, 255), thickness=-1, lineType=cv2.FILLED)
cv2.putText(frame, str(i), (x, y), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 0, 255), 1, lineType=cv2.LINE_AA)
points.append((x, y))
print(f"[pointed] {BODY_PARTS[i]} ({i}) => prob: {prob:.5f} / x: {x} / y: {y}")
else: # [not pointed]
cv2.circle(frame, (x, y), 5, (0, 255, 255), thickness=-1, lineType=cv2.FILLED)
cv2.putText(frame, str(i), (x, y), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (255, 0, 0), 1, lineType=cv2.LINE_AA)
points.append(None)
print(f"[not pointed] {BODY_PARTS[i]} ({i}) => prob: {prob:.5f} / x: {x} / y: {y}")
return frame
입력받은 frame에 BODY_PARTS를 참고하여 노란색 점을 포인팅 하는 함수
def output_keypoints_with_lines(frame, POSE_PAIRS):
for pair in POSE_PAIRS:
part_a = pair[0] # 0 (Head)
part_b = pair[1] # 1 (Neck)
if points[part_a] and points[part_b]:
print(f"[linked] {part_a} {points[part_a]} <=> {part_b} {points[part_b]}")
cv2.line(frame, points[part_a], points[part_b], (0, 255, 0), 3)
else:
print(f"[not linked] {part_a} {points[part_a]} <=> {part_b} {points[part_b]}")
return frame
입력받은 frame에 POSE_PAIRS를 참고하여 노란색 점을 초록색 선으로 잇는 함수
def output_keypoints_with_lines_video(proto_file, weights_file, video_path, threshold, BODY_PARTS, POSE_PAIRS):
# 네트워크 불러오기
net = cv2.dnn.readNetFromCaffe(proto_file, weights_file)
# GPU 사용
# net.setPreferableBackend(cv2.dnn.DNN_BACKEND_CUDA)
# net.setPreferableTarget(cv2.dnn.DNN_TARGET_CUDA)
# 비디오 읽어오기
capture = cv2.VideoCapture(video_path)
while True:
now_frame_boy = capture.get(cv2.CAP_PROP_POS_FRAMES)
total_frame_boy = capture.get(cv2.CAP_PROP_FRAME_COUNT)
if now_frame_boy == total_frame_boy:
break
ret, frame_boy = capture.read()
frame_boy = output_keypoints(frame=frame_boy, net=net, threshold=threshold, BODY_PARTS=BODY_PARTS, now_frame=now_frame_boy, total_frame=total_frame_boy)
frame_boy = output_keypoints_with_lines(frame=frame_boy, POSE_PAIRS=POSE_PAIRS)
cv2.imshow("Output_Keypoints", frame_boy)
if cv2.waitKey(10) == 27: # esc 입력시 종료
break
capture.release()
cv2.destroyAllWindows()
위에서 만든 두 함수 output_keypoints() 와 output_keypoints_with_lines()를 호출하면서 imshow를 통해 포인트 및 링크된 frame을 시각화하는 함수
GPU를 사용하려면 OpenCV = CUDA 빌드가 필요함
BODY_PARTS_MPI = {0: "Head", 1: "Neck", 2: "RShoulder", 3: "RElbow", 4: "RWrist",
5: "LShoulder", 6: "LElbow", 7: "LWrist", 8: "RHip", 9: "RKnee",
10: "RAnkle", 11: "LHip", 12: "LKnee", 13: "LAnkle", 14: "Chest",
15: "Background"}
POSE_PAIRS_MPI = [[0, 1], [1, 2], [1, 5], [1, 14], [2, 3], [3, 4], [5, 6],
[6, 7], [8, 9], [9, 10], [11, 12], [12, 13], [14, 8], [14, 11]]
BODY_PARTS_COCO = {0: "Nose", 1: "Neck", 2: "RShoulder", 3: "RElbow", 4: "RWrist",
5: "LShoulder", 6: "LElbow", 7: "LWrist", 8: "RHip", 9: "RKnee",
10: "RAnkle", 11: "LHip", 12: "LKnee", 13: "LAnkle", 14: "REye",
15: "LEye", 16: "REar", 17: "LEar", 18: "Background"}
POSE_PAIRS_COCO = [[0, 1], [0, 14], [0, 15], [1, 2], [1, 5], [1, 8], [1, 11], [2, 3], [3, 4],
[5, 6], [6, 7], [8, 9], [9, 10], [12, 13], [11, 12], [14, 16], [15, 17]]
BODY_PARTS_BODY_25 = {0: "Nose", 1: "Neck", 2: "RShoulder", 3: "RElbow", 4: "RWrist",
5: "LShoulder", 6: "LElbow", 7: "LWrist", 8: "MidHip", 9: "RHip",
10: "RKnee", 11: "RAnkle", 12: "LHip", 13: "LKnee", 14: "LAnkle",
15: "REye", 16: "LEye", 17: "REar", 18: "LEar", 19: "LBigToe",
20: "LSmallToe", 21: "LHeel", 22: "RBigToe", 23: "RSmallToe", 24: "RHeel", 25: "Background"}
POSE_PAIRS_BODY_25 = [[0, 1], [0, 15], [0, 16], [1, 2], [1, 5], [1, 8], [8, 9], [8, 12], [9, 10], [12, 13], [2, 3],
[3, 4], [5, 6], [6, 7], [10, 11], [13, 14], [15, 17], [16, 18], [14, 21], [19, 21], [20, 21],
[11, 24], [22, 24], [23, 24]]
# 신경 네트워크의 구조를 지정하는 prototxt 파일 (다양한 계층이 배열되는 방법 등)
protoFile_mpi = "C:\\openpose\\models\\pose\\mpi\\pose_deploy_linevec.prototxt"
protoFile_mpi_faster = "C:\\openpose\\models\\pose\\mpi\\pose_deploy_linevec_faster_4_stages.prototxt"
protoFile_coco = "C:\\openpose\\models\\pose\\coco\\pose_deploy_linevec.prototxt"
protoFile_body_25 = "C:\\openpose\\models\\pose\\body_25\\pose_deploy.prototxt"
# 훈련된 모델의 weight 를 저장하는 caffemodel 파일
weightsFile_mpi = "C:\\openpose\\models\\pose\\mpi\\pose_iter_160000.caffemodel"
weightsFile_coco = "C:\\openpose\\models\\pose\\coco\\pose_iter_440000.caffemodel"
weightsFile_body_25 = "C:\\openpose\\models\\pose\\body_25\\pose_iter_584000.caffemodel"
# 비디오 경로
man = "C:\\Users\\user\\Pictures\\Saved Pictures\\sample_video\\man.mp4" # (출처: https://pixabay.com/videos/id-25553/)
# 키포인트를 저장할 빈 리스트
points = []
output_keypoints_with_lines_video(proto_file=protoFile_mpi_faster, weights_file=weightsFile_mpi, video_path=man,
threshold=0.1, BODY_PARTS=BODY_PARTS_MPI, POSE_PAIRS=POSE_PAIRS_MPI)
output_keypoints_with_lines_video(proto_file=protoFile_coco, weights_file=weightsFile_coco, video_path=man,
threshold=0.1, BODY_PARTS=BODY_PARTS_COCO, POSE_PAIRS=POSE_PAIRS_COCO)
output_keypoints_with_lines_video(proto_file=protoFile_body_25, weights_file=weightsFile_body_25, video_path=man,
threshold=0.1, BODY_PARTS=BODY_PARTS_BODY_25, POSE_PAIRS=POSE_PAIRS_BODY_25)
비디오 출처: https://pixabay.com/videos/id-25553/
가장 해상도가 낮은 파일을 사용했음
'파이썬' 카테고리의 다른 글
[파이썬] OpenCV, YOLO를 이용하여 이미지 속 객체 인식 (5) | 2020.07.27 |
---|---|
다리를 지나는 트럭 (Python Queue) (1) | 2020.07.22 |
OpenCV, OpenPose, math를 이용하여 옆모습 사진 속 인물의 허리가 숙여졌는지 추정 (Python) (2) | 2020.07.20 |
Selenium을 이용하여 구글 이미지 크롤링 (Python) (5) | 2020.07.18 |
[파이썬] OpenCV, OpenPose를 이용하여 사진 속 인물의 자세 추정 (6) | 2020.07.16 |