Spaces:
Runtime error
Runtime error
| #!/usr/bin/env python | |
| # -*- coding: utf-8 -*- | |
| import copy | |
| import math | |
| import argparse | |
| import cv2 as cv | |
| import numpy as np | |
| import mediapipe as mp | |
| from utils import CvFpsCalc | |
| def get_args(): | |
| parser = argparse.ArgumentParser() | |
| parser.add_argument("--device", type=int, default=0) | |
| parser.add_argument("--width", help='cap width', type=int, default=640) | |
| parser.add_argument("--height", help='cap height', type=int, default=360) | |
| parser.add_argument('--static_image_mode', action='store_true') | |
| parser.add_argument("--model_complexity", | |
| help='model_complexity(0,1(default),2)', | |
| type=int, | |
| default=1) | |
| parser.add_argument("--min_detection_confidence", | |
| help='min_detection_confidence', | |
| type=float, | |
| default=0.5) | |
| parser.add_argument("--min_tracking_confidence", | |
| help='min_tracking_confidence', | |
| type=int, | |
| default=0.5) | |
| parser.add_argument('--rev_color', action='store_true') | |
| args = parser.parse_args() | |
| return args | |
| def main(): | |
| # 引数解析 ################################################################# | |
| args = get_args() | |
| cap_device = args.device | |
| cap_width = args.width | |
| cap_height = args.height | |
| static_image_mode = args.static_image_mode | |
| model_complexity = args.model_complexity | |
| min_detection_confidence = args.min_detection_confidence | |
| min_tracking_confidence = args.min_tracking_confidence | |
| rev_color = args.rev_color | |
| # カメラ準備 ############################################################### | |
| cap = cv.VideoCapture(cap_device) | |
| cap.set(cv.CAP_PROP_FRAME_WIDTH, cap_width) | |
| cap.set(cv.CAP_PROP_FRAME_HEIGHT, cap_height) | |
| # モデルロード ############################################################# | |
| mp_pose = mp.solutions.pose | |
| pose = mp_pose.Pose( | |
| static_image_mode=static_image_mode, | |
| model_complexity=model_complexity, | |
| min_detection_confidence=min_detection_confidence, | |
| min_tracking_confidence=min_tracking_confidence, | |
| ) | |
| # FPS計測モジュール ######################################################## | |
| cvFpsCalc = CvFpsCalc(buffer_len=10) | |
| # 色指定 | |
| if rev_color: | |
| color = (255, 255, 255) | |
| bg_color = (100, 33, 3) | |
| else: | |
| color = (100, 33, 3) | |
| bg_color = (255, 255, 255) | |
| while True: | |
| display_fps = cvFpsCalc.get() | |
| # カメラキャプチャ ##################################################### | |
| ret, image = cap.read() | |
| if not ret: | |
| break | |
| image = cv.flip(image, 1) # ミラー表示 | |
| debug_image01 = copy.deepcopy(image) | |
| debug_image02 = np.zeros((image.shape[0], image.shape[1], 3), np.uint8) | |
| cv.rectangle(debug_image02, (0, 0), (image.shape[1], image.shape[0]), | |
| bg_color, | |
| thickness=-1) | |
| # 検出実施 ############################################################# | |
| image = cv.cvtColor(image, cv.COLOR_BGR2RGB) | |
| results = pose.process(image) | |
| # 描画 ################################################################ | |
| if results.pose_landmarks is not None: | |
| # 描画 | |
| debug_image01 = draw_landmarks( | |
| debug_image01, | |
| results.pose_landmarks, | |
| ) | |
| debug_image02 = draw_stick_figure( | |
| debug_image02, | |
| results.pose_landmarks, | |
| color=color, | |
| bg_color=bg_color, | |
| ) | |
| cv.putText(debug_image01, "FPS:" + str(display_fps), (10, 30), | |
| cv.FONT_HERSHEY_SIMPLEX, 1.0, (0, 255, 0), 2, cv.LINE_AA) | |
| cv.putText(debug_image02, "FPS:" + str(display_fps), (10, 30), | |
| cv.FONT_HERSHEY_SIMPLEX, 1.0, color, 2, cv.LINE_AA) | |
| # キー処理(ESC:終了) ################################################# | |
| key = cv.waitKey(1) | |
| if key == 27: # ESC | |
| break | |
| # 画面反映 ############################################################# | |
| cv.imshow('Tokyo2020 Debug', debug_image01) | |
| cv.imshow('Tokyo2020 Pictogram', debug_image02) | |
| cap.release() | |
| cv.destroyAllWindows() | |
| def draw_stick_figure( | |
| image, | |
| landmarks, | |
| color=(100, 33, 3), | |
| bg_color=(255, 255, 255), | |
| visibility_th=0.5, | |
| ): | |
| image_width, image_height = image.shape[1], image.shape[0] | |
| # 各ランドマーク算出 | |
| landmark_point = [] | |
| for index, landmark in enumerate(landmarks.landmark): | |
| landmark_x = min(int(landmark.x * image_width), image_width - 1) | |
| landmark_y = min(int(landmark.y * image_height), image_height - 1) | |
| landmark_z = landmark.z | |
| landmark_point.append( | |
| [index, landmark.visibility, (landmark_x, landmark_y), landmark_z]) | |
| # 脚の付け根の位置を腰の中点に修正 | |
| right_leg = landmark_point[23] | |
| left_leg = landmark_point[24] | |
| leg_x = int((right_leg[2][0] + left_leg[2][0]) / 2) | |
| leg_y = int((right_leg[2][1] + left_leg[2][1]) / 2) | |
| landmark_point[23][2] = (leg_x, leg_y) | |
| landmark_point[24][2] = (leg_x, leg_y) | |
| # 距離順にソート | |
| sorted_landmark_point = sorted(landmark_point, | |
| reverse=True, | |
| key=lambda x: x[3]) | |
| # 各サイズ算出 | |
| (face_x, face_y), face_radius = min_enclosing_face_circle(landmark_point) | |
| face_x = int(face_x) | |
| face_y = int(face_y) | |
| face_radius = int(face_radius * 1.5) | |
| stick_radius01 = int(face_radius * (4 / 5)) | |
| stick_radius02 = int(stick_radius01 * (3 / 4)) | |
| stick_radius03 = int(stick_radius02 * (3 / 4)) | |
| # 描画対象リスト | |
| draw_list = [ | |
| 11, # 右腕 | |
| 12, # 左腕 | |
| 23, # 右脚 | |
| 24, # 左脚 | |
| ] | |
| # 背景色 | |
| cv.rectangle(image, (0, 0), (image_width, image_height), | |
| bg_color, | |
| thickness=-1) | |
| # 顔 描画 | |
| cv.circle(image, (face_x, face_y), face_radius, color, -1) | |
| # 腕/脚 描画 | |
| for landmark_info in sorted_landmark_point: | |
| index = landmark_info[0] | |
| if index in draw_list: | |
| point01 = [p for p in landmark_point if p[0] == index][0] | |
| point02 = [p for p in landmark_point if p[0] == (index + 2)][0] | |
| point03 = [p for p in landmark_point if p[0] == (index + 4)][0] | |
| if point01[1] > visibility_th and point02[1] > visibility_th: | |
| image = draw_stick( | |
| image, | |
| point01[2], | |
| stick_radius01, | |
| point02[2], | |
| stick_radius02, | |
| color=color, | |
| bg_color=bg_color, | |
| ) | |
| if point02[1] > visibility_th and point03[1] > visibility_th: | |
| image = draw_stick( | |
| image, | |
| point02[2], | |
| stick_radius02, | |
| point03[2], | |
| stick_radius03, | |
| color=color, | |
| bg_color=bg_color, | |
| ) | |
| return image | |
| def min_enclosing_face_circle(landmark_point): | |
| landmark_array = np.empty((0, 2), int) | |
| index_list = [1, 4, 7, 8, 9, 10] | |
| for index in index_list: | |
| np_landmark_point = [ | |
| np.array( | |
| (landmark_point[index][2][0], landmark_point[index][2][1])) | |
| ] | |
| landmark_array = np.append(landmark_array, np_landmark_point, axis=0) | |
| center, radius = cv.minEnclosingCircle(points=landmark_array) | |
| return center, radius | |
| def draw_stick( | |
| image, | |
| point01, | |
| point01_radius, | |
| point02, | |
| point02_radius, | |
| color=(100, 33, 3), | |
| bg_color=(255, 255, 255), | |
| ): | |
| cv.circle(image, point01, point01_radius, color, -1) | |
| cv.circle(image, point02, point02_radius, color, -1) | |
| draw_list = [] | |
| for index in range(2): | |
| rad = math.atan2(point02[1] - point01[1], point02[0] - point01[0]) | |
| rad = rad + (math.pi / 2) + (math.pi * index) | |
| point_x = int(point01_radius * math.cos(rad)) + point01[0] | |
| point_y = int(point01_radius * math.sin(rad)) + point01[1] | |
| draw_list.append([point_x, point_y]) | |
| point_x = int(point02_radius * math.cos(rad)) + point02[0] | |
| point_y = int(point02_radius * math.sin(rad)) + point02[1] | |
| draw_list.append([point_x, point_y]) | |
| points = np.array((draw_list[0], draw_list[1], draw_list[3], draw_list[2])) | |
| cv.fillConvexPoly(image, points=points, color=color) | |
| return image | |
| def draw_landmarks( | |
| image, | |
| landmarks, | |
| # upper_body_only, | |
| visibility_th=0.5, | |
| ): | |
| image_width, image_height = image.shape[1], image.shape[0] | |
| landmark_point = [] | |
| for index, landmark in enumerate(landmarks.landmark): | |
| landmark_x = min(int(landmark.x * image_width), image_width - 1) | |
| landmark_y = min(int(landmark.y * image_height), image_height - 1) | |
| landmark_z = landmark.z | |
| landmark_point.append([landmark.visibility, (landmark_x, landmark_y)]) | |
| if landmark.visibility < visibility_th: | |
| continue | |
| if index == 0: # 鼻 | |
| cv.circle(image, (landmark_x, landmark_y), 5, (0, 255, 0), 2) | |
| if index == 1: # 右目:目頭 | |
| cv.circle(image, (landmark_x, landmark_y), 5, (0, 255, 0), 2) | |
| if index == 2: # 右目:瞳 | |
| cv.circle(image, (landmark_x, landmark_y), 5, (0, 255, 0), 2) | |
| if index == 3: # 右目:目尻 | |
| cv.circle(image, (landmark_x, landmark_y), 5, (0, 255, 0), 2) | |
| if index == 4: # 左目:目頭 | |
| cv.circle(image, (landmark_x, landmark_y), 5, (0, 255, 0), 2) | |
| if index == 5: # 左目:瞳 | |
| cv.circle(image, (landmark_x, landmark_y), 5, (0, 255, 0), 2) | |
| if index == 6: # 左目:目尻 | |
| cv.circle(image, (landmark_x, landmark_y), 5, (0, 255, 0), 2) | |
| if index == 7: # 右耳 | |
| cv.circle(image, (landmark_x, landmark_y), 5, (0, 255, 0), 2) | |
| if index == 8: # 左耳 | |
| cv.circle(image, (landmark_x, landmark_y), 5, (0, 255, 0), 2) | |
| if index == 9: # 口:左端 | |
| cv.circle(image, (landmark_x, landmark_y), 5, (0, 255, 0), 2) | |
| if index == 10: # 口:左端 | |
| cv.circle(image, (landmark_x, landmark_y), 5, (0, 255, 0), 2) | |
| if index == 11: # 右肩 | |
| cv.circle(image, (landmark_x, landmark_y), 5, (0, 255, 0), 2) | |
| if index == 12: # 左肩 | |
| cv.circle(image, (landmark_x, landmark_y), 5, (0, 255, 0), 2) | |
| if index == 13: # 右肘 | |
| cv.circle(image, (landmark_x, landmark_y), 5, (0, 255, 0), 2) | |
| if index == 14: # 左肘 | |
| cv.circle(image, (landmark_x, landmark_y), 5, (0, 255, 0), 2) | |
| if index == 15: # 右手首 | |
| cv.circle(image, (landmark_x, landmark_y), 5, (0, 255, 0), 2) | |
| if index == 16: # 左手首 | |
| cv.circle(image, (landmark_x, landmark_y), 5, (0, 255, 0), 2) | |
| if index == 17: # 右手1(外側端) | |
| cv.circle(image, (landmark_x, landmark_y), 5, (0, 255, 0), 2) | |
| if index == 18: # 左手1(外側端) | |
| cv.circle(image, (landmark_x, landmark_y), 5, (0, 255, 0), 2) | |
| if index == 19: # 右手2(先端) | |
| cv.circle(image, (landmark_x, landmark_y), 5, (0, 255, 0), 2) | |
| if index == 20: # 左手2(先端) | |
| cv.circle(image, (landmark_x, landmark_y), 5, (0, 255, 0), 2) | |
| if index == 21: # 右手3(内側端) | |
| cv.circle(image, (landmark_x, landmark_y), 5, (0, 255, 0), 2) | |
| if index == 22: # 左手3(内側端) | |
| cv.circle(image, (landmark_x, landmark_y), 5, (0, 255, 0), 2) | |
| if index == 23: # 腰(右側) | |
| cv.circle(image, (landmark_x, landmark_y), 5, (0, 255, 0), 2) | |
| if index == 24: # 腰(左側) | |
| cv.circle(image, (landmark_x, landmark_y), 5, (0, 255, 0), 2) | |
| if index == 25: # 右ひざ | |
| cv.circle(image, (landmark_x, landmark_y), 5, (0, 255, 0), 2) | |
| if index == 26: # 左ひざ | |
| cv.circle(image, (landmark_x, landmark_y), 5, (0, 255, 0), 2) | |
| if index == 27: # 右足首 | |
| cv.circle(image, (landmark_x, landmark_y), 5, (0, 255, 0), 2) | |
| if index == 28: # 左足首 | |
| cv.circle(image, (landmark_x, landmark_y), 5, (0, 255, 0), 2) | |
| if index == 29: # 右かかと | |
| cv.circle(image, (landmark_x, landmark_y), 5, (0, 255, 0), 2) | |
| if index == 30: # 左かかと | |
| cv.circle(image, (landmark_x, landmark_y), 5, (0, 255, 0), 2) | |
| if index == 31: # 右つま先 | |
| cv.circle(image, (landmark_x, landmark_y), 5, (0, 255, 0), 2) | |
| if index == 32: # 左つま先 | |
| cv.circle(image, (landmark_x, landmark_y), 5, (0, 255, 0), 2) | |
| # if not upper_body_only: | |
| if True: | |
| cv.putText(image, "z:" + str(round(landmark_z, 3)), | |
| (landmark_x - 10, landmark_y - 10), | |
| cv.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 1, | |
| cv.LINE_AA) | |
| # 右目 | |
| if landmark_point[1][0] > visibility_th and landmark_point[2][ | |
| 0] > visibility_th: | |
| cv.line(image, landmark_point[1][1], landmark_point[2][1], | |
| (0, 255, 0), 2) | |
| if landmark_point[2][0] > visibility_th and landmark_point[3][ | |
| 0] > visibility_th: | |
| cv.line(image, landmark_point[2][1], landmark_point[3][1], | |
| (0, 255, 0), 2) | |
| # 左目 | |
| if landmark_point[4][0] > visibility_th and landmark_point[5][ | |
| 0] > visibility_th: | |
| cv.line(image, landmark_point[4][1], landmark_point[5][1], | |
| (0, 255, 0), 2) | |
| if landmark_point[5][0] > visibility_th and landmark_point[6][ | |
| 0] > visibility_th: | |
| cv.line(image, landmark_point[5][1], landmark_point[6][1], | |
| (0, 255, 0), 2) | |
| # 口 | |
| if landmark_point[9][0] > visibility_th and landmark_point[10][ | |
| 0] > visibility_th: | |
| cv.line(image, landmark_point[9][1], landmark_point[10][1], | |
| (0, 255, 0), 2) | |
| # 肩 | |
| if landmark_point[11][0] > visibility_th and landmark_point[12][ | |
| 0] > visibility_th: | |
| cv.line(image, landmark_point[11][1], landmark_point[12][1], | |
| (0, 255, 0), 2) | |
| # 右腕 | |
| if landmark_point[11][0] > visibility_th and landmark_point[13][ | |
| 0] > visibility_th: | |
| cv.line(image, landmark_point[11][1], landmark_point[13][1], | |
| (0, 255, 0), 2) | |
| if landmark_point[13][0] > visibility_th and landmark_point[15][ | |
| 0] > visibility_th: | |
| cv.line(image, landmark_point[13][1], landmark_point[15][1], | |
| (0, 255, 0), 2) | |
| # 左腕 | |
| if landmark_point[12][0] > visibility_th and landmark_point[14][ | |
| 0] > visibility_th: | |
| cv.line(image, landmark_point[12][1], landmark_point[14][1], | |
| (0, 255, 0), 2) | |
| if landmark_point[14][0] > visibility_th and landmark_point[16][ | |
| 0] > visibility_th: | |
| cv.line(image, landmark_point[14][1], landmark_point[16][1], | |
| (0, 255, 0), 2) | |
| # 右手 | |
| if landmark_point[15][0] > visibility_th and landmark_point[17][ | |
| 0] > visibility_th: | |
| cv.line(image, landmark_point[15][1], landmark_point[17][1], | |
| (0, 255, 0), 2) | |
| if landmark_point[17][0] > visibility_th and landmark_point[19][ | |
| 0] > visibility_th: | |
| cv.line(image, landmark_point[17][1], landmark_point[19][1], | |
| (0, 255, 0), 2) | |
| if landmark_point[19][0] > visibility_th and landmark_point[21][ | |
| 0] > visibility_th: | |
| cv.line(image, landmark_point[19][1], landmark_point[21][1], | |
| (0, 255, 0), 2) | |
| if landmark_point[21][0] > visibility_th and landmark_point[15][ | |
| 0] > visibility_th: | |
| cv.line(image, landmark_point[21][1], landmark_point[15][1], | |
| (0, 255, 0), 2) | |
| # 左手 | |
| if landmark_point[16][0] > visibility_th and landmark_point[18][ | |
| 0] > visibility_th: | |
| cv.line(image, landmark_point[16][1], landmark_point[18][1], | |
| (0, 255, 0), 2) | |
| if landmark_point[18][0] > visibility_th and landmark_point[20][ | |
| 0] > visibility_th: | |
| cv.line(image, landmark_point[18][1], landmark_point[20][1], | |
| (0, 255, 0), 2) | |
| if landmark_point[20][0] > visibility_th and landmark_point[22][ | |
| 0] > visibility_th: | |
| cv.line(image, landmark_point[20][1], landmark_point[22][1], | |
| (0, 255, 0), 2) | |
| if landmark_point[22][0] > visibility_th and landmark_point[16][ | |
| 0] > visibility_th: | |
| cv.line(image, landmark_point[22][1], landmark_point[16][1], | |
| (0, 255, 0), 2) | |
| # 胴体 | |
| if landmark_point[11][0] > visibility_th and landmark_point[23][ | |
| 0] > visibility_th: | |
| cv.line(image, landmark_point[11][1], landmark_point[23][1], | |
| (0, 255, 0), 2) | |
| if landmark_point[12][0] > visibility_th and landmark_point[24][ | |
| 0] > visibility_th: | |
| cv.line(image, landmark_point[12][1], landmark_point[24][1], | |
| (0, 255, 0), 2) | |
| if landmark_point[23][0] > visibility_th and landmark_point[24][ | |
| 0] > visibility_th: | |
| cv.line(image, landmark_point[23][1], landmark_point[24][1], | |
| (0, 255, 0), 2) | |
| if len(landmark_point) > 25: | |
| # 右足 | |
| if landmark_point[23][0] > visibility_th and landmark_point[25][ | |
| 0] > visibility_th: | |
| cv.line(image, landmark_point[23][1], landmark_point[25][1], | |
| (0, 255, 0), 2) | |
| if landmark_point[25][0] > visibility_th and landmark_point[27][ | |
| 0] > visibility_th: | |
| cv.line(image, landmark_point[25][1], landmark_point[27][1], | |
| (0, 255, 0), 2) | |
| if landmark_point[27][0] > visibility_th and landmark_point[29][ | |
| 0] > visibility_th: | |
| cv.line(image, landmark_point[27][1], landmark_point[29][1], | |
| (0, 255, 0), 2) | |
| if landmark_point[29][0] > visibility_th and landmark_point[31][ | |
| 0] > visibility_th: | |
| cv.line(image, landmark_point[29][1], landmark_point[31][1], | |
| (0, 255, 0), 2) | |
| # 左足 | |
| if landmark_point[24][0] > visibility_th and landmark_point[26][ | |
| 0] > visibility_th: | |
| cv.line(image, landmark_point[24][1], landmark_point[26][1], | |
| (0, 255, 0), 2) | |
| if landmark_point[26][0] > visibility_th and landmark_point[28][ | |
| 0] > visibility_th: | |
| cv.line(image, landmark_point[26][1], landmark_point[28][1], | |
| (0, 255, 0), 2) | |
| if landmark_point[28][0] > visibility_th and landmark_point[30][ | |
| 0] > visibility_th: | |
| cv.line(image, landmark_point[28][1], landmark_point[30][1], | |
| (0, 255, 0), 2) | |
| if landmark_point[30][0] > visibility_th and landmark_point[32][ | |
| 0] > visibility_th: | |
| cv.line(image, landmark_point[30][1], landmark_point[32][1], | |
| (0, 255, 0), 2) | |
| return image | |
| if __name__ == '__main__': | |
| main() | |