姿勢の分類オプション

ML Kit Pose Detection API を使用すると、意味のある解釈を導き出すことができます。 さまざまな部位の相対位置を確認することで、ポーズのモデルを評価します。このページでは、いくつかの例を示します。

k-NN アルゴリズムによるポーズの分類と繰り返しのカウント

姿勢検出の最も一般的な用途の 1 つは、フィットネス トラッキングです。 特定のフィットネスのポーズとカウントを認識するポーズ分類器の作成 繰り返しはデベロッパーにとって厄介な作業です

このセクションでは、MediaPipe Colab を使用してカスタム ポーズ分類システムを作成する方法について説明します。また、ML Kit サンプルアプリで動作する分類システムを紹介します。

Google Colaboratory に慣れていない場合は、紹介ガイドをご覧ください。

ポーズを認識するために、k 最近傍探索アルゴリズム(k-NN)を使用します。これは、シンプルで簡単に始められるためです。オブジェクトのクラスは、アルゴリズムが 最も近いサンプルを取得します

認識ツールを構築してトレーニングする手順は次のとおりです。

1. 画像サンプルを収集する

さまざまなソースから対象のエクササイズの画像サンプルを収集しました。水 トレーニング用の画像を数百枚ほど「down」と入力します。位置 腕立て伏せに使用していますさまざまなカメラアングル、環境条件、体型、エクササイズのバリエーションを網羅するサンプルを収集することが重要です。

図 1. 上腕を上げ下げするプッシュアップの姿勢

2. サンプル画像でポーズ検出を実行する

これにより、トレーニングに使用する一連のポーズ ランドマークが生成されます。私たちは ポーズ検出機能に興味がある方もいるでしょう。このトレーニングでは、 独自のモデルを作成します。

カスタムのポーズ分類用に選択した k-NN アルゴリズムでは、 各サンプルの特徴ベクトル表現と計算する指標 2 つのベクトル間の距離を計算し、ポーズ サンプルに最も近いターゲットを見つけます。 つまり、先ほど取得したポーズ ランドマークを変換する必要があります。

ポーズ ランドマークを特徴ベクトルに変換するには、特徴ベクトルのペアごとの距離を使用します。 リスト間の距離(手首と指の間の距離など)を 肩、足首、腰、左手首と右手首です。画像のスケールは、 変化があるため、胴体のサイズと胴体の垂直方向が同じになるようにポーズを正規化しました。 画像の向きを確認します

3. モデルをトレーニングして繰り返しをカウントする

MediaPipe Colab を使用して分類器のコードにアクセスし、 モデルをトレーニングします。

繰り返し回数をカウントするために、別の Colab アルゴリズムを使用して、 ターゲットポーズ位置のしきい値です。例:

  • 「下」ポーズクラスの確率が初めて特定のしきい値を超えると、アルゴリズムは「下」ポーズクラスが入力されたことをマークします。
  • 確率がしきい値を下回ると、アルゴリズムは「ダウン」ポーズクラスが終了したことをマークし、カウンタを増やします。
図 2. 繰り返しカウントの例

4. ML Kit クイックスタート アプリと統合する

上記の Colab では、すべてのポーズを入力できる CSV ファイルが生成されます 提供しますこのセクションでは、CSV ファイルを カスタムの姿勢分類をリアルタイムで表示する ML Kit Android クイックスタート アプリ

クイックスタート アプリにバンドルされたサンプルでポーズ分類を試す

  • ML Kit Android クイックスタート アプリ プロジェクトを入手する ビルドして動作することを確認します。
  • LivePreviewActivity に移動し、[設定] ページでポーズ検出 Run classification を有効にします。これで、腕立て伏せとスクワットを分類できるようになりました。

独自の CSV を追加

  • CSV ファイルをアプリのアセット フォルダに追加します。
  • PoseClassifierProcessor で、 POSE_SAMPLES_FILE 変数と POSE_CLASSES 変数を、 CSV ファイルとポーズのサンプル。
  • アプリをビルドして実行します。

サンプル数が十分でない場合、分類がうまく機能しないことがあります。通常、ポーズクラスごとに約 100 個のサンプルが必要です。

詳細を確認して試すには、MediaPipe Colab をご覧ください。 および MediaPipe 分類ガイドをご覧ください。

ランドマークの距離を計算して簡単なジェスチャーを認識する

2 つ以上のランドマークが互いに近接している場合、 ジェスチャーを認識できます。たとえば、画面上の 1 本以上の指のランドマークが 手が鼻のランドマークに近い場合は、ユーザーが最も 顔に触れている可能性が高まります

図 3. ポーズを解釈する

角度のヒューリスティックを使用してヨガのポーズを認識する

さまざまな関節の角度を計算することで、ヨガのポーズを特定できます。たとえば、下の図 2 はヨガの戦士 II のポーズを示しています。このポーズを識別するおおよその角度は次のとおりです。

図 4. ポーズを複数の角度に分割する

このポーズは、身体部分の角度の近似値の組み合わせとして次のように記述できます。

  • 両肩が 90 度になるようにする
  • 両肘を 180 度曲げる
  • 前脚とウエストを 90 度に開けた状態
  • 後ろの膝が 180 度に曲がっている
  • ウエストの角度 135 度

ポーズ ランドマークを使用して、これらの角度を計算できます。たとえば、右前脚と腰の角度は、右肩から右臀部までの線と、右臀部から右膝までの線の間の角度です。

ポーズの特定に必要な角度をすべて計算したら、 一致するものがあるかどうかを確認します。一致する場合はポーズを認識します。

以下のコード スニペットは、X 座標と Y 座標を使用して、 2 つの部位の間の角度を計算します。この分類方法にはいくつかの制限があります。X と Y だけをチェックすると、計算される角度が変わります。 被写体とカメラの角度に応じて決まります。水平で正面から撮影した画像が最適です。また、Z 座標を使用してこのアルゴリズムを拡張し、ユースケースでパフォーマンスが向上するかどうかを確認することもできます。

Android でランドマークの角度を計算する

次のメソッドは、任意の 3 つのランドマーク間の角度を計算します。これにより、返される角度は、 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 でのランドマーク角度の計算

次のメソッドでは、任意の 3 つの線間の角度が 使用できます。これにより、返される角度は、 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]];