有了 ML Kit Pose Detection API,您可以解讀有意義的解釋。 檢視不同身體部位的相對位置。這個頁面 以上示範了幾項範例
使用 k-NN 演算法進行姿勢分類和重複計數
健身追蹤是最常用姿勢偵測姿勢之一。 打造可辨識特定健身姿勢和次數的姿勢分類器 重複出現對開發人員來說並不是件容易的事。
本節會說明我們如何建構自訂姿勢 使用 MediaPipe Colab 分類類別,以及 示範可用分類器在 ML Kit 範例應用程式中
如果你不熟悉 Google Colaboratory,請參閱 簡介指南。
為了辨識姿勢,我們使用 k-nearest 鄰居演算法 (k-NN) 很簡單, 而且易於上手演算法會根據 訓練集中內最接近的樣本
請按照下列步驟建構並訓練辨識工具:
1. 收集圖片樣本
我們從多種來源蒐集目標運動的圖片樣本。三 為每項運動選擇數百張圖片,例如「向上」和「down」位置 。請務必收集涵蓋不同鏡頭的樣本 角度、環境條件、身體形狀和運動變化版本。
![](https://developers-dot-devsite-v2-prod.appspot.com/static/ml-kit/images/vision/pose-detection/terminal_pose.png?authuser=9&hl=zh-tw)
2. 對範例圖片執行姿勢偵測
這樣會產生一組姿勢地標,可用於訓練。我們並非 偵測自己的姿勢,因為我們會訓練模型 自己的模型
我們為自訂姿勢分類選擇的 k-NN 演算法需要 每個樣本的特徵向量表示法 尋找兩個向量之間的距離,以尋找最接近姿勢樣本的目標。 這意味著我們必須轉換剛剛取得的姿勢地標。
如要將姿勢地標轉換成特徵向量,我們會使用成對的距離 預先定義的姿勢接合清單之間的差異,例如手腕與 肩膀、腳踝和臀部,以及左右手腕。由於圖片是 我們可以將姿勢正規化,讓身體大小和垂直軀幹相同 才能轉換地標。
3. 訓練模型並計算重複次數
我們使用 MediaPipe Colab 存取分類器的程式碼, 來訓練模型
為計算重複次數,我們使用其他 Colab 演算法監控 做出目標排名門檻例如:
- 當「往下」機率分佈pose 類別通過特定門檻 第一次測量時,演算法會標示「向下」就會輸入 pose 類別
- 如果機率下降到門檻以下,演算法會標記 「向下」pose 類別退出,並增加計數器。
![](https://developers-dot-devsite-v2-prod.appspot.com/static/ml-kit/images/vision/pose-detection/pose_classification.gif?authuser=9&hl=zh-tw)
4. 與 ML Kit 快速入門導覽課程應用程式整合
Colab 產生的 CSV 檔案可填入你的所有姿勢 樣本。本節將說明如何整合 CSV 檔案與 使用 ML Kit Android 快速入門導覽課程應用程式,查看即時自訂姿勢分類。
嘗試在快速入門導覽課程應用程式中,使用帶有範例的姿勢分類
- 取得 ML Kit Android 快速入門導覽課程應用程式專案 ,確保建構和運作順暢
- 前往「
LivePreviewActivity
」並啟用姿勢偵測功能Run classification
前往「設定」頁面。現在,您應該可以分類伏地挺身和深蹲。
新增自己的 CSV
- 將 CSV 檔案新增至應用程式的素材資源資料夾。
- 在「PoseClassifierProcessor」PoseClassifierProcessor中
請更新
POSE_SAMPLES_FILE
和POSE_CLASSES
變數,使其與您的 CSV 檔案和姿勢範例 - 建構並執行應用程式。
請注意,如果樣本數量不足,這項分類功能可能就無法發揮最佳成效。 一般來說,每個姿勢類別都需要大約 100 個樣本。
歡迎前往 MediaPipe Colab 瞭解詳情並自行試用。 和 MediaPipe 分類指南。
計算地標距離來辨識簡單的手勢
當兩個以上的地標相鄰時, 辨識手勢例如以單指或多指 一隻手靠近鼻子的地標,因此你可以推測使用者 可能碰到臉的孩子
![](https://developers-dot-devsite-v2-prod.appspot.com/static/ml-kit/images/vision/pose-detection/touching_face.gif?authuser=9&hl=zh-tw)
以角度經驗法則辨識瑜珈姿勢
您可以計算不同關節的角度,找出瑜珈姿勢。適用對象 例如,下方的圖 2 顯示戰士 II 瑜珈姿勢。近似角度 識別這種姿態的寫法如下:
![](https://developers-dot-devsite-v2-prod.appspot.com/static/ml-kit/images/vision/pose-detection/warrier2_sketch.png?authuser=9&hl=zh-tw)
這種姿勢可以描述為以下概略身體的組合 半角:
- 兩個肩帶的 90 度角
- 雙肘同時保持在 180 度
- 90 度角,前腿和腰部
- 後方膝蓋的 180 度角
- 135 度角腰帶
您可以使用姿勢地標來計算這些角度。例如 右前腿和腰部是指從右側線條之間的角度 從右臀部到右膝。
計算出確定姿勢所需的所有角度後,就可以查看 看看是否有相符項目,這樣您已認出該姿勢。
以下程式碼片段示範如何使用 X 和 Y 座標 計算兩個身體部位的角度。這種分類方式 有一些限制只檢查 X 和 Y 的計算角度會有所差異 根據拍攝目標和相機之間的視角進行調整。您將會取得 最好能呈現水平、正向、頭頂上的圖像,以獲得最佳效果。你也可以 請嘗試使用 Z 座標 看看它是否對您的用途有幫助
在 Android 上計算地標角度
以下方法會計算任一三個點之間的角度 地標。可確保傳回的角度介於 0 到 180 度。
Kotlin
fun getAngle(firstPoint: PoseLandmark, midPoint: PoseLandmark, lastPoint: PoseLandmark): Double { var result = Math.toDegrees(atan2(lastPoint.getPosition().y - midPoint.getPosition().y, lastPoint.getPosition().x - midPoint.getPosition().x) - atan2(firstPoint.getPosition().y - midPoint.getPosition().y, firstPoint.getPosition().x - midPoint.getPosition().x)) result = Math.abs(result) // Angle should never be negative if (result > 180) { result = 360.0 - result // Always get the acute representation of the angle } return result }
Java
static double getAngle(PoseLandmark firstPoint, PoseLandmark midPoint, PoseLandmark lastPoint) { double result = Math.toDegrees( atan2(lastPoint.getPosition().y - midPoint.getPosition().y, lastPoint.getPosition().x - midPoint.getPosition().x) - atan2(firstPoint.getPosition().y - midPoint.getPosition().y, firstPoint.getPosition().x - midPoint.getPosition().x)); result = Math.abs(result); // Angle should never be negative if (result > 180) { result = (360.0 - result); // Always get the acute representation of the angle } return result; }
計算右側角角度的方式如下:
Kotlin
val rightHipAngle = getAngle( pose.getPoseLandmark(PoseLandmark.Type.RIGHT_SHOULDER), pose.getPoseLandmark(PoseLandmark.Type.RIGHT_HIP), pose.getPoseLandmark(PoseLandmark.Type.RIGHT_KNEE))
Java
double rightHipAngle = getAngle( pose.getPoseLandmark(PoseLandmark.Type.RIGHT_SHOULDER), pose.getPoseLandmark(PoseLandmark.Type.RIGHT_HIP), pose.getPoseLandmark(PoseLandmark.Type.RIGHT_KNEE));
在 iOS 上計算地標角度
以下方法會計算任一三個點之間的角度 地標。可確保傳回的角度介於 0 到 180 度。
Swift
func angle( firstLandmark: PoseLandmark, midLandmark: PoseLandmark, lastLandmark: PoseLandmark ) -> CGFloat { let radians: CGFloat = atan2(lastLandmark.position.y - midLandmark.position.y, lastLandmark.position.x - midLandmark.position.x) - atan2(firstLandmark.position.y - midLandmark.position.y, firstLandmark.position.x - midLandmark.position.x) var degrees = radians * 180.0 / .pi degrees = abs(degrees) // Angle should never be negative if degrees > 180.0 { degrees = 360.0 - degrees // Always get the acute representation of the angle } return degrees }
Objective-C
(CGFloat)angleFromFirstLandmark:(MLKPoseLandmark *)firstLandmark midLandmark:(MLKPoseLandmark *)midLandmark lastLandmark:(MLKPoseLandmark *)lastLandmark { CGFloat radians = atan2(lastLandmark.position.y - midLandmark.position.y, lastLandmark.position.x - midLandmark.position.x) - atan2(firstLandmark.position.y - midLandmark.position.y, firstLandmark.position.x - midLandmark.position.x); CGFloat degrees = radians * 180.0 / M_PI; degrees = fabs(degrees); // Angle should never be negative if (degrees > 180.0) { degrees = 360.0 - degrees; // Always get the acute representation of the angle } return degrees; }
計算右側角角度的方式如下:
Swift
let rightHipAngle = angle( firstLandmark: pose.landmark(ofType: .rightShoulder), midLandmark: pose.landmark(ofType: .rightHip), lastLandmark: pose.landmark(ofType: .rightKnee))
Objective-C
CGFloat rightHipAngle = [self angleFromFirstLandmark:[pose landmarkOfType:MLKPoseLandmarkTypeRightShoulder] midLandmark:[pose landmarkOfType:MLKPoseLandmarkTypeRightHip] lastLandmark:[pose landmarkOfType:MLKPoseLandmarkTypeRightKnee]];