ポーズ ランドマーク タスクを使用すると、画像または動画内の人体のランドマークを検出できます。このタスクを使用すると、体の主要な位置を特定し、姿勢を分析して、動きを分類できます。このタスクでは、単一の画像または動画を処理する ML モデルを使用します。このタスクは、画像座標と 3 次元ワールド座標でボディポーズのランドマークを出力します。
以下の手順では、iOS アプリでポーズ ランドマークを使用する方法について説明します。この手順で説明するコードサンプルは GitHub で入手できます。
このタスクの動作を確認するには、こちらのウェブデモをご覧ください。このタスクの機能、モデル、構成オプションの詳細については、概要をご覧ください。
サンプルコード
MediaPipe Tasks のサンプルコードは、iOS 向けのポーズ ランドマークアプリの基本的な実装です。この例では、物理的な iOS デバイスのカメラを使用して、連続した動画ストリームでポーズを検出します。デバイスのギャラリーにある画像や動画のポーズも検出できます。
このアプリは、独自の iOS アプリの開始点として使用できます。また、既存のアプリを変更する際にも参照できます。Pose Landmarker の例コードは GitHub でホストされています。
コードをダウンロードする
次の手順では、git コマンドライン ツールを使用してサンプルコードのローカルコピーを作成する方法について説明します。
サンプルコードをダウンロードするには:
- 次のコマンドを使用して、Git リポジトリのクローンを作成します。 - git clone https://github.com/google-ai-edge/mediapipe-samples
- 必要に応じて、スパース チェックアウトを使用するように Git インスタンスを構成して、Pose Landmarker サンプルアプリのファイルのみを取得します。 - cd mediapipe-samples git sparse-checkout init --cone git sparse-checkout set examples/pose_landmarker/ios/
ローカル バージョンのサンプルコードを作成したら、MediaPipe タスク ライブラリをインストールし、Xcode を使用してプロジェクトを開いてアプリを実行できます。手順については、iOS 用セットアップ ガイドをご覧ください。
主要コンポーネント
次のファイルには、Pose Landmarker サンプル アプリケーションの重要なコードが含まれています。
- PoseLandmarkerService.swift: ランドマークを初期化し、モデル選択を処理し、入力データに対して推論を実行します。
- CameraViewController: ライブカメラ フィード入力モードの UI を実装し、ランドマークを可視化します。
- MediaLibraryViewController.swift: 静止画像と動画ファイルの入力モードの UI を実装し、ランドマークを可視化します。
セットアップ
このセクションでは、Pose Landmarker を使用するように開発環境とコード プロジェクトを設定する主な手順について説明します。プラットフォーム バージョンの要件など、MediaPipe タスクを使用する開発環境の設定に関する一般的な情報については、iOS 用セットアップ ガイドをご覧ください。
依存関係
Pose Landmarker は MediaPipeTasksVision ライブラリを使用します。このライブラリは CocoaPods を使用してインストールする必要があります。このライブラリは Swift アプリと Objective-C アプリの両方に対応しており、言語固有の追加設定は必要ありません。
macOS に CocoaPods をインストールする手順については、CocoaPods インストール ガイドをご覧ください。アプリに必要な Pod を使用して Podfile を作成する方法については、CocoaPods の使用をご覧ください。
次のコードを使用して、Podfile に MediaPipeTasksVision Pod を追加します。
target 'MyPoseLandmarkerApp' do
  use_frameworks!
  pod 'MediaPipeTasksVision'
end
アプリに単体テスト ターゲットが含まれている場合は、Podfile の設定について詳しくは、iOS 用セットアップ ガイドをご覧ください。
モデル
MediaPipe Pose Landmarker タスクには、このタスクと互換性のあるトレーニング済みバンドルが必要です。Pose Landmarker で使用可能なトレーニング済みモデルの詳細については、タスクの概要のモデルセクションをご覧ください。
download_models.sh スクリプトを使用してモデルをダウンロードし、Xcode を使用してプロジェクト ディレクトリに追加します。Xcode プロジェクトにファイルを追加する方法については、Xcode プロジェクト内のファイルとフォルダを管理するをご覧ください。
BaseOptions.modelAssetPath プロパティを使用して、アプリバンドルのモデルのパスを指定します。コード例については、次のセクションをご覧ください。
タスクを作成する
Pose Landmarker タスクを作成するには、いずれかの初期化子を呼び出します。PoseLandmarker(options:) イニシャライザは、構成オプションの値を受け入れます。
カスタマイズされた構成オプションで初期化されたポーズ ランドマークが不要な場合は、PoseLandmarker(modelPath:) イニシャライザを使用して、デフォルト オプションでポーズ ランドマークを作成できます。構成オプションの詳細については、構成の概要をご覧ください。
Pose Landmarker タスクは、静止画像、動画ファイル、ライブ動画ストリームの 3 つの入力データ型をサポートしています。デフォルトでは、PoseLandmarker(modelPath:) は静止画像のタスクを初期化します。動画ファイルまたはライブ動画ストリームを処理するようにタスクを初期化する場合は、PoseLandmarker(options:) を使用して動画またはライブ配信の実行モードを指定します。ライブ配信モードでは、Pose Landmarker がポーズ ランドマーク検出結果をデリゲータに非同期で配信できるように、追加の poseLandmarkerLiveStreamDelegate 構成オプションも必要です。
実行モードに対応するタブを選択して、タスクを作成し推論を実行する方法を確認します。
Swift
画像
import MediaPipeTasksVision let modelPath = Bundle.main.path(forResource: "pose_landmarker", ofType: "task") let options = PoseLandmarkerOptions() options.baseOptions.modelAssetPath = modelPath options.runningMode = .image options.minPoseDetectionConfidence = minPoseDetectionConfidence options.minPosePresenceConfidence = minPosePresenceConfidence options.minTrackingConfidence = minTrackingConfidence options.numPoses = numPoses let poseLandmarker = try PoseLandmarker(options: options)
動画
import MediaPipeTasksVision let modelPath = Bundle.main.path(forResource: "pose_landmarker", ofType: "task") let options = PoseLandmarkerOptions() options.baseOptions.modelAssetPath = modelPath options.runningMode = .video options.minPoseDetectionConfidence = minPoseDetectionConfidence options.minPosePresenceConfidence = minPosePresenceConfidence options.minTrackingConfidence = minTrackingConfidence options.numPoses = numPoses let poseLandmarker = try PoseLandmarker(options: options)
ライブ配信
import MediaPipeTasksVision // Class that conforms to the `PoseLandmarkerLiveStreamDelegate` protocol and // implements the method that the pose landmarker calls once it finishes // performing pose landmark detection in each input frame. class PoseLandmarkerResultProcessor: NSObject, PoseLandmarkerLiveStreamDelegate { func poseLandmarker( _ poseLandmarker: PoseLandmarker, didFinishDetection result: PoseLandmarkerResult?, timestampInMilliseconds: Int, error: Error?) { // Process the pose landmarker result or errors here. } } let modelPath = Bundle.main.path(forResource: "pose_landmarker", ofType: "task") let options = PoseLandmarkerOptions() options.baseOptions.modelAssetPath = modelPath options.runningMode = .liveStream options.minPoseDetectionConfidence = minPoseDetectionConfidence options.minPosePresenceConfidence = minPosePresenceConfidence options.minTrackingConfidence = minTrackingConfidence options.numPoses = numPoses // Assign an object of the class to the `poseLandmarkerLiveStreamDelegate` // property. let processor = PoseLandmarkerResultProcessor() options.poseLandmarkerLiveStreamDelegate = processor let poseLandmarker = try PoseLandmarker(options: options)
Objective-C
画像
@import MediaPipeTasksVision; NSString *modelPath = [[NSBundle mainBundle] pathForResource:@"pose_landmarker" ofType:@"task"]; MPPPoseLandmarkerOptions *options = [[MPPPoseLandmarkerOptions alloc] init]; options.baseOptions.modelAssetPath = modelPath; options.runningMode = MPPRunningModeImage; options.minPoseDetectionConfidence = minPoseDetectionConfidence; options.minPosePresenceConfidence = minPosePresenceConfidence; options.minTrackingConfidence = minTrackingConfidence; options.numPoses = numPoses; MPPPoseLandmarker *poseLandmarker = [[MPPPoseLandmarker alloc] initWithOptions:options error:nil];
動画
@import MediaPipeTasksVision; NSString *modelPath = [[NSBundle mainBundle] pathForResource:@"pose_landmarker" ofType:@"task"]; MPPPoseLandmarkerOptions *options = [[MPPPoseLandmarkerOptions alloc] init]; options.baseOptions.modelAssetPath = modelPath; options.runningMode = MPPRunningModeVideo; options.minPoseDetectionConfidence = minPoseDetectionConfidence; options.minPosePresenceConfidence = minPosePresenceConfidence; options.minTrackingConfidence = minTrackingConfidence; options.numPoses = numPoses; MPPPoseLandmarker *poseLandmarker = [[MPPPoseLandmarker alloc] initWithOptions:options error:nil];
ライブ配信
@import MediaPipeTasksVision; // Class that conforms to the `MPPPoseLandmarkerLiveStreamDelegate` protocol // and implements the method that the pose landmarker calls once it finishes // performing pose landmarks= detection in each input frame. @interface APPPoseLandmarkerResultProcessor : NSObject@end @implementation APPPoseLandmarkerResultProcessor - (void)poseLandmarker:(MPPPoseLandmarker *)poseLandmarker didFinishDetectionWithResult:(MPPPoseLandmarkerResult *)poseLandmarkerResult timestampInMilliseconds:(NSInteger)timestampInMilliseconds error:(NSError *)error { // Process the pose landmarker result or errors here. } @end NSString *modelPath = [[NSBundle mainBundle] pathForResource:@"pose_landmarker" ofType:@"task"]; MPPPoseLandmarkerOptions *options = [[MPPPoseLandmarkerOptions alloc] init]; options.baseOptions.modelAssetPath = modelPath; options.runningMode = MPPRunningModeLiveStream; options.minPoseDetectionConfidence = minPoseDetectionConfidence; options.minPosePresenceConfidence = minPosePresenceConfidence; options.minTrackingConfidence = minTrackingConfidence; options.numPoses = numPoses; // Assign an object of the class to the `poseLandmarkerLiveStreamDelegate` // property. APPPoseLandmarkerResultProcessor *processor = [APPPoseLandmarkerResultProcessor new]; options.poseLandmarkerLiveStreamDelegate = processor; MPPPoseLandmarker *poseLandmarker = [[MPPPoseLandmarker alloc] initWithOptions:options error:nil]; 
注: 動画モードまたはライブ配信モードを使用している場合、Pose Landmarker はトラッキングを使用して、フレームごとに手のひら検出モデルをトリガーしないようにします。これにより、レイテンシを短縮できます。
設定オプション
このタスクには、iOS アプリ用の次の構成オプションがあります。
| オプション名 | 説明 | 値の範囲 | デフォルト値 | 
|---|---|---|---|
| running_mode | タスクの実行モードを設定します。モードは次の 3 つです。 IMAGE: 単一画像入力のモード。 動画: 動画のデコードされたフレームのモード。 LIVE_STREAM: カメラなどからの入力データのライブ配信モード。 このモードでは、ポーズ ランドマーク検出を非同期で実行した結果を受け取るために、 poseLandmarkerLiveStreamDelegateをPoseLandmarkerLiveStreamDelegateを実装するクラスのインスタンスに設定する必要があります。 | { RunningMode.image, RunningMode.video, RunningMode.liveStream} | RunningMode.image | 
| num_poses | Pose Landmarker で検出できるポーズの最大数。 | Integer > 0 | 1 | 
| min_pose_detection_confidence | ポーズ検出が成功と見なされるための最小信頼度スコア。 | Float [0.0,1.0] | 0.5 | 
| min_pose_presence_confidence | ポーズランドマーク検出でのポーズ存在スコアの最小信頼度スコア。 | Float [0.0,1.0] | 0.5 | 
| min_tracking_confidence | ポーズ トラッキングが成功とみなされるための最小信頼スコア。 | Float [0.0,1.0] | 0.5 | 
| output_segmentation_masks | Pose Landmarker が検出されたポーズのセグメンテーション マスクを出力するかどうか。 | Boolean | False | 
| result_callback | Pose Landmarker がライブ配信モードの場合に、ランドマークの結果を非同期で受信するように結果リスナーを設定します。実行モードが LIVE_STREAMに設定されている場合にのみ使用できます。 | ResultListener | N/A | 
ライブ配信の設定
実行モードがライブ配信に設定されている場合、Pose Landmarker には追加の poseLandmarkerLiveStreamDelegate 構成オプションが必要です。これにより、Pose Landmarker はポーズ ランドマーク検出結果を非同期で提供できます。デリゲートには poseLandmarker(_:didFinishDetection:timestampInMilliseconds:error:) メソッドを実装する必要があります。このメソッドは、Pose Landmarker が各フレームでポーズ ランドマーク検出を実行した結果を処理した後に呼び出されます。
| オプション名 | 説明 | 値の範囲 | デフォルト値 | 
|---|---|---|---|
| poseLandmarkerLiveStreamDelegate | Pose Landmarker がライブ配信モードでポーズ ランドマーク検出を非同期的に実行した結果を受け取れるようにします。このプロパティにインスタンスが設定されているクラスは、 poseLandmarker(_:didFinishDetection:timestampInMilliseconds:error:)メソッドを実装する必要があります。 | 該当なし | 未設定 | 
データの準備
入力画像またはフレームを Pose Landmarker に渡す前に、MPImage オブジェクトに変換する必要があります。MPImage はさまざまな種類の iOS 画像形式をサポートしており、推論の実行モードで使用できます。MPImage の詳細については、MPImage API をご覧ください。
ユースケースと、アプリに必要な実行モードに基づいて iOS イメージ形式を選択します。MPImage は、UIImage、CVPixelBuffer、CMSampleBuffer の iOS イメージ形式を受け入れます。
UIImage
UIImage 形式は、次の実行モードに適しています。
- 画像: アプリバンドル、ユーザー ギャラリー、または - UIImageイメージとしてフォーマットされたファイル システムの画像は、- MPImageオブジェクトに変換できます。
- 動画: AVAssetImageGenerator を使用して動画フレームを CGImage 形式に抽出し、 - UIImage画像に変換します。
Swift
// Load an image on the user's device as an iOS `UIImage` object. // Convert the `UIImage` object to a MediaPipe's Image object having the default // orientation `UIImage.Orientation.up`. let image = try MPImage(uiImage: image)
Objective-C
// Load an image on the user's device as an iOS `UIImage` object. // Convert the `UIImage` object to a MediaPipe's Image object having the default // orientation `UIImageOrientationUp`. MPImage *image = [[MPPImage alloc] initWithUIImage:image error:nil];
この例では、デフォルトの UIImage.Orientation.Up の向きで MPImage を初期化しています。MPImage は、サポートされている UIImage.Orientation 値のいずれかで初期化できます。Pose Landmarker は、.upMirrored、.downMirrored、.leftMirrored、.rightMirrored などのミラーリングされた向きをサポートしていません。
UIImage の詳細については、UIImage Apple デベロッパー ドキュメントをご覧ください。
CVPixelBuffer
CVPixelBuffer 形式は、フレームを生成し、iOS の CoreImage フレームワークを使用して処理するアプリケーションに適しています。
CVPixelBuffer 形式は、次の実行モードに適しています。
- 画像: iOS の - CoreImageフレームワークを使用して処理を行った後に- CVPixelBuffer画像を生成するアプリは、画像実行モードで Pose Landmarker に送信できます。
- 動画: 動画フレームは処理用に - CVPixelBuffer形式に変換し、動画モードで Pose Landmarker に送信できます。
- ライブ配信: iOS カメラを使用してフレームを生成するアプリは、ライブ配信モードで Pose Landmarker に送信される前に、処理のために - CVPixelBuffer形式に変換される場合があります。
Swift
// Obtain a CVPixelBuffer. // Convert the `CVPixelBuffer` object to a MediaPipe's Image object having the default // orientation `UIImage.Orientation.up`. let image = try MPImage(pixelBuffer: pixelBuffer)
Objective-C
// Obtain a CVPixelBuffer. // Convert the `CVPixelBuffer` object to a MediaPipe's Image object having the // default orientation `UIImageOrientationUp`. MPImage *image = [[MPPImage alloc] initWithUIImage:image error:nil];
CVPixelBuffer の詳細については、CVPixelBuffer Apple デベロッパー ドキュメントをご覧ください。
CMSampleBuffer
CMSampleBuffer 形式は、統一されたメディアタイプのメディア サンプルを保存し、ライブ配信の実行モードに適しています。iOS カメラのライブフレームは、iOS の AVCaptureVideoDataOutput によって CMSampleBuffer 形式で非同期的に配信されます。
Swift
// Obtain a CMSampleBuffer. // Convert the `CMSampleBuffer` object to a MediaPipe's Image object having the default // orientation `UIImage.Orientation.up`. let image = try MPImage(sampleBuffer: sampleBuffer)
Objective-C
// Obtain a `CMSampleBuffer`. // Convert the `CMSampleBuffer` object to a MediaPipe's Image object having the // default orientation `UIImageOrientationUp`. MPImage *image = [[MPPImage alloc] initWithSampleBuffer:sampleBuffer error:nil];
CMSampleBuffer の詳細については、CMSampleBuffer Apple デベロッパー ドキュメントをご覧ください。
タスクを実行する
Pose Landmarker を実行するには、割り当てられた実行モードに固有の detect() メソッドを使用します。
- 静止画像: detect(image:)
- 動画: detect(videoFrame:timestampInMilliseconds:)
- ライブ配信: detectAsync(image:timestampInMilliseconds:)
次のコードサンプルは、これらのさまざまな実行モードで Pose Landmarker を実行する方法の簡単な例を示しています。
Swift
画像
let result = try poseLandmarker.detect(image: image)
    動画
let result = try poseLandmarker.detect(
  videoFrame: image,
  timestampInMilliseconds: timestamp)
    ライブ配信
try poseLandmarker.detectAsync(
  image: image,
  timestampInMilliseconds: timestamp)
    Objective-C
画像
MPPPoseLandmarkerResult *result = [poseLandmarker detectImage:image error:nil];
動画
MPPPoseLandmarkerResult *result = [poseLandmarker detectVideoFrame:image timestampInMilliseconds:timestamp error:nil];
ライブ配信
BOOL success = [poseLandmarker detectAsyncImage:image timestampInMilliseconds:timestamp error:nil];
Pose Landmarker のコードサンプルでは、これらのモード(detect(image:)、detect(videoFrame:timestampInMilliseconds:)、detectAsync(image:timestampInMilliseconds:))の各実装について詳しく説明しています。サンプルコードでは、ユーザーが処理モードを切り替えることができますが、ユースケースで必要でない場合があります。
次の点にご注意ください。
- 動画モードまたはライブ配信モードで実行する場合は、入力フレームのタイムスタンプを Pose Landmarker タスクに指定する必要があります。 
- 画像モードまたは動画モードで実行する場合、Pose Landmarker タスクは、入力画像またはフレームの処理が完了するまで現在のスレッドをブロックします。現在のスレッドをブロックしないようにするには、iOS の Dispatch フレームワークまたは NSOperation フレームワークを使用して、バックグラウンド スレッドで処理を実行します。 
- ライブ配信モードで実行すると、Pose Landmarker タスクはすぐに返され、現在のスレッドはブロックされません。各入力フレームを処理した後、ポーズ ランドマークの結果を使用して - poseLandmarker(_:didFinishDetection:timestampInMilliseconds:error:)メソッドを呼び出します。Pose Landmarker は、専用のシリアル ディスパッチ キューでこのメソッドを非同期的に呼び出します。結果をユーザー インターフェースに表示するには、結果を処理した後に結果をメインキューにディスパッチします。Pose Landmarker タスクが別のフレームの処理でビジー状態になっているときに- detectAsync関数が呼び出されると、Pose Landmarker は新しい入力フレームを無視します。
結果を処理して表示する
推論を実行すると、Pose Landmarker タスクは、各ポーズ ランドマークの座標を含む PoseLandmarkerResult を返します。
このタスクの出力データの例を次に示します。
PoseLandmarkerResult:
  Landmarks:
    Landmark #0:
      x            : 0.638852
      y            : 0.671197
      z            : 0.129959
      visibility   : 0.9999997615814209
      presence     : 0.9999984502792358
    Landmark #1:
      x            : 0.634599
      y            : 0.536441
      z            : -0.06984
      visibility   : 0.999909
      presence     : 0.999958
    ... (33 landmarks per pose)
  WorldLandmarks:
    Landmark #0:
      x            : 0.067485
      y            : 0.031084
      z            : 0.055223
      visibility   : 0.9999997615814209
      presence     : 0.9999984502792358
    Landmark #1:
      x            : 0.063209
      y            : -0.00382
      z            : 0.020920
      visibility   : 0.999976
      presence     : 0.999998
    ... (33 world landmarks per pose)
  SegmentationMasks:
    ... (pictured below)
出力には、各ランドマークの正規化された座標(Landmarks)とワールド座標(WorldLandmarks)の両方が含まれます。
出力には、次の正規化された座標(Landmarks)が含まれます。
- x、- y: 画像の幅(- x)と高さ(- y)で 0.0 ~ 1.0 に正規化されたランドマークの座標。
- z: ランドマークの深さ。腰の中央を原点として測定します。値が小さいほど、ランドマークはカメラに近くなります。z の振幅は、- xとほぼ同じスケールを使用します。
- visibility: ランドマークが画像内に表示される確率。
出力には、次のワールド座標(WorldLandmarks)が含まれます。
- x、- y、- z: ヒップの中間点を原点とする、メートル単位の現実世界の 3 次元座標。
- visibility: ランドマークが画像内に表示される確率。
次の図は、タスク出力の可視化を示しています。
 
 
省略可能なセグメンテーション マスクは、各ピクセルが検出された人物に属する可能性を表します。次の画像は、タスク出力の分割マスクです。
 
 
Pose Landmarker のサンプルコードは、Pose Landmarker の結果を表示する方法を示しています。