2022年南港瓶蓋工廠所舉行的Maker Faire 中,在公司的攤位上,最受到矚目與歡迎的,就是Google MediaPipe 的深蹲偵測互動遊戲了,達到一定的深蹲次數不僅買徽章可以折價,還可以免費獲得摩艾石像3D列印一個,吸引了很多大小朋友,一起來看看當時熱鬧的畫面吧!
VIDEO
原理及功能說明
本次的深蹲互動專題,以這篇[累累累] Google Mediapipe 深蹲偵測,結合 Arduino 首次接觸就上手 所改編的,一樣著重於偵測身體大腿及小腿的角度小於一定的數值,將深蹲次數顯示出來外,並取消了和Arduino的連線。而MediaPipe已經將人體簡化成由點和線所構成的人體線條骨架的樣貌,如下圖所示。
由上圖所示,就是偵測左腿點23(left_hip)到點25(left _knee)的直線距離,和點25(left _knee)到點27(left _ankle)的直線距離,兩條直線所產生的夾角小於120;右腿則是點24(right_hip)到點26(right _knee)的直線距離,和點28(right _knee)到點27(right _ankle)的直線距離,兩條直線所產生的夾角小於120。
也就是說,當左右腳膝蓋彎曲角度小於120度時,字體顏色就會變綠色。只要螢幕上顯示的字體「Left Angle」、「Right Angle」、「Pose」皆為綠色時,次數會加1。
再來是遊戲互動體驗,筆者使用了一顆超大的Enter鍵,當程式開始執行時,畫面會出現指示「Press Enter To Start」,Enter鍵按下去後就可以開始深蹲遊戲,此時就會開始計算深蹲次數。再按一次Enter鍵,次數會歸零,同時又會回到「Press Enter To Start」的畫面。而筆者在每次計算深蹲次數後,都會加上音效,以確保動作完成,如以下所示。
再來是場地架設,以當時在Maker Faire南港瓶蓋工廠場地為例,筆者使用的是羅技C270的攝影鏡頭,鏡頭距離地面高度需2公尺,距離人的身體約3公尺,才能偵測得到全身骨架畫面,由下圖所示。
程式撰寫
由於程式過長,故說明重要片段,如下列程式所示。
以下程式為影像訊號來源。第1行為攝影機訊號;第2行可撥放影片。
cam = cv2.VideoCapture(3) #cam=cv2.VideoCapture("POSE1.mp4")
以下程式為計算身體比率函式。
def get_body_ratio(landmarks): r_body = abs(landmarks[mppose.PoseLandmark["RIGHT_SHOULDER"].value].y - landmarks[mppose.PoseLandmark["RIGHT_HIP"].value].y) l_body = abs(landmarks[mppose.PoseLandmark["LEFT_SHOULDER"].value].y - landmarks[mppose.PoseLandmark["LEFT_HIP"].value].y) avg_body = (r_body + l_body) / 2 r_leg = abs(landmarks[mppose.PoseLandmark["RIGHT_HIP"].value].y - landmarks[mppose.PoseLandmark["RIGHT_ANKLE"].value].y) l_leg = abs(landmarks[mppose.PoseLandmark["LEFT_HIP"].value].y - landmarks[mppose.PoseLandmark["LEFT_ANKLE"].value].y) if r_leg > l_leg: return r_leg / avg_body else: return l_leg / avg_body
以下程式為計算左右腳的角度函式。
def get_knee_angle(landmarks): r_hip = get_landmark(landmarks, "RIGHT_HIP") l_hip = get_landmark(landmarks, "LEFT_HIP") r_knee = get_landmark(landmarks, "RIGHT_KNEE") l_knee = get_landmark(landmarks, "LEFT_KNEE") r_ankle = get_landmark(landmarks, "RIGHT_ANKLE") l_ankle = get_landmark(landmarks, "LEFT_ANKLE") r_angle = calc_angles(r_hip, r_knee, r_ankle) l_angle = calc_angles(l_hip, l_knee, l_ankle) #print(r_hip) m_hip = (r_hip + l_hip) m_hip = [x / 2 for x in m_hip] m_knee = (r_knee + l_knee) m_knee = [x / 2 for x in m_knee] m_ankle = (r_ankle + l_ankle) m_ankle = [x / 2 for x in m_ankle] mid_angle = calc_angles(m_hip, m_knee, m_ankle) return [int(r_angle),int(l_angle) ,int(mid_angle)]
以下程式為計算按下Enter鍵的次數,可觸發遊戲開始。
if (read_dir_key == 13): sport['count'] = 0 run_flag += 1 if (run_flag == 2): run_flag = 0
以下程式為左腳膝蓋彎曲角度之顏色顯示。小於120度綠色,介於120~130度黃色,大於130度紅色。
而檔案POSE_entercount_sound.py 中的第226~248行則為顯示右腳膝蓋彎曲角度之顏色顯示。
if knee_angles[0] < 120: cv2.putText(preview, "Left Angle: {:d}".format(knee_angles[0]), (400, 360) , cv2.FONT_HERSHEY_SIMPLEX, 0.8, (82, 169, 255), 4, cv2.LINE_AA) cv2.putText(preview, "Left Angle: {:d}".format(knee_angles[0]), (400, 360) , cv2.FONT_HERSHEY_SIMPLEX, 0.8, (0, 255, 0), 1, cv2.LINE_AA) elif knee_angles[0] < 130: cv2.putText(preview, "Left Angle: {:d}".format(knee_angles[0]), (400, 360) , cv2.FONT_HERSHEY_SIMPLEX, 0.8, (82, 169, 255), 4, cv2.LINE_AA) cv2.putText(preview, "Left Angle: {:d}".format(knee_angles[0]), (400, 360) , cv2.FONT_HERSHEY_SIMPLEX, 0.8, (0, 255, 255), 1, cv2.LINE_AA) else: cv2.putText(preview, "Left Angle: {:d}".format(knee_angles[0]), (400, 360) , cv2.FONT_HERSHEY_SIMPLEX, 0.8, (82, 169, 255), 4, cv2.LINE_AA) cv2.putText(preview, "Left Angle: {:d}".format(knee_angles[0]), (400, 360) , cv2.FONT_HERSHEY_SIMPLEX, 0.8, (0, 0, 255), 1, cv2.LINE_AA)
決定深蹲的次數,如果次數已加1,則會撥放音效。
if status: if avg_angle > 160: status = False pass_time = time.time() - start_time start_time = 0 if 3000 > pass_time > 0.5: sport['count'] = sport['count'] + 1 while (pygame.mixer.music.get_busy()!=1): pygame.mixer.music.load('coin05.mp3') pygame.mixer.music.play() sport['calories'] = sport['calories'] + int(0.66 * pass_time) logger(sport['count'], sport['calories']) tmp = f"a{sport['count']}\n" #ser.write(str.encode(tmp)) tmp = f"b{sport['calories']}\n" #ser.write(str.encode(tmp)) #print(pass_time) else: if avg_angle < 120 and body_ratio < 1.2: start_time = time.time() status = True
在螢幕上顯示”Press Enter To Start”,以開始深蹲遊戲
cv2.putText(preview, "Press Enter To Start", (10, 80) , cv2.FONT_HERSHEY_SIMPLEX, 1.5, (0, 0, 0), 5, cv2.LINE_AA) cv2.putText(preview, "Press Enter To Start", (10, 80) , cv2.FONT_HERSHEY_SIMPLEX, 1.5, (0, 255, 0), 2, cv2.LINE_AA)
以上程式傳送門-連結
下載解壓縮後,電腦中需依本文 安裝Python的執行環境(操作至圖 21)。
執行程式
cd pose_detection python POSE_entercount_sound.py
影片展示
以下影片為腦波弱老闆在南港瓶蓋工廠所示範的深蹲畫面,一起來看看吧!
VIDEO
Post Views: 390