#!/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()