MediaPipe Gesture Recognizer タスクを使用すると、手ジェスチャーをリアルタイムで認識し、認識された手ジェスチャーの結果と検出された手のランドマークを取得できます。以下では、iOS アプリでジェスチャー認識ツールを使用する方法について説明します。
このタスクの動作を確認するには、ウェブデモをご覧ください。このタスクの機能、モデル、構成オプションの詳細については、概要をご覧ください。
サンプルコード
MediaPipe Tasks のサンプルコードは、iOS 向けのジェスチャー認識アプリの基本的な実装です。この例では、物理的な iOS デバイスのカメラを使用して手ジェスチャーを継続的に検出します。また、デバイスのギャラリーにある画像や動画を使用して、ジェスチャーを静的に検出することもできます。
このアプリは、独自の iOS アプリの開始点として使用できます。また、既存のアプリを変更する際にも参照できます。ジェスチャー認識ツールのサンプルコードは GitHub でホストされています。
コードをダウンロードする
次の手順では、git コマンドライン ツールを使用してサンプルコードのローカルコピーを作成する方法について説明します。
サンプルコードをダウンロードするには:
次のコマンドを使用して、Git リポジトリのクローンを作成します。
git clone https://github.com/google-ai-edge/mediapipe-samples
必要に応じて、スパース チェックアウトを使用するように Git インスタンスを構成して、ジェスチャー認識ツールのサンプルアプリのファイルのみを取得します。
cd mediapipe git sparse-checkout init --cone git sparse-checkout set examples/gesture_recognizer/ios/
ローカル バージョンのサンプルコードを作成したら、MediaPipe タスク ライブラリをインストールし、Xcode を使用してプロジェクトを開いてアプリを実行できます。手順については、iOS のセットアップ ガイドをご覧ください。
主要コンポーネント
次のファイルには、ジェスチャー認識ツール サンプルアプリに不可欠なコードが含まれています。
- GestureRecognizerService.swift: ジェスチャー認識ツールを初期化し、モデル選択を処理し、入力データに対して推論を実行します。
- CameraViewController.swift: ライブカメラ フィード入力モードの UI を実装し、結果を可視化します。
- MediaLibraryViewController.swift: 静止画像と動画ファイルの入力モードの UI を実装し、結果を可視化します。
セットアップ
このセクションでは、ジェスチャー認識機能を使用するように開発環境とコード プロジェクトを設定する主な手順について説明します。プラットフォーム バージョンの要件など、MediaPipe タスクを使用する開発環境の設定に関する一般的な情報については、iOS 用セットアップ ガイドをご覧ください。
依存関係
ジェスチャー認識ツールは MediaPipeTasksVision
ライブラリを使用します。このライブラリは CocoaPods を使用してインストールする必要があります。このライブラリは Swift アプリと Objective-C アプリの両方に対応しており、言語固有の追加設定は必要ありません。
macOS に CocoaPods をインストールする手順については、CocoaPods インストール ガイドをご覧ください。アプリに必要な Pod を使用して Podfile
を作成する方法については、CocoaPods の使用をご覧ください。
次のコードを使用して、Podfile
に MediaPipeTasksVision Pod を追加します。
target 'MyGestureRecognizerApp' do
use_frameworks!
pod 'MediaPipeTasksVision'
end
アプリに単体テスト ターゲットが含まれている場合は、Podfile
の設定について詳しくは、iOS 用セットアップ ガイドをご覧ください。
モデル
MediaPipe ジェスチャー認識タスクには、このタスクに対応したトレーニング済みモデルが必要です。ジェスチャー認識ツールで使用可能なトレーニング済みモデルの詳細については、タスクの概要のモデルセクションをご覧ください。
モデルを選択してダウンロードし、Xcode を使用してプロジェクト ディレクトリに追加します。Xcode プロジェクトにファイルを追加する方法については、Xcode プロジェクト内のファイルとフォルダの管理をご覧ください。
BaseOptions.modelAssetPath
プロパティを使用して、App Bundle 内のモデルのパスを指定します。コード例については、次のセクションをご覧ください。
タスクを作成する
ジェスチャー認識タスクは、いずれかの初期化子を呼び出すことで作成できます。GestureRecognizer(options:)
イニシャライザは、構成オプションの値を受け入れます。
カスタマイズされた構成オプションで初期化されたジェスチャー認識ツールが不要な場合は、GestureRecognizer(modelPath:)
イニシャライザを使用して、デフォルトのオプションでジェスチャー認識ツールを作成できます。構成オプションの詳細については、構成の概要をご覧ください。
ジェスチャー認識タスクは、静止画像、動画ファイル、ライブ動画ストリームの 3 つの入力データ型をサポートしています。デフォルトでは、GestureRecognizer(modelPath:)
は静止画像のタスクを初期化します。動画ファイルまたはライブ動画ストリームを処理するようにタスクを初期化する場合は、GestureRecognizer(options:)
を使用して動画またはライブ配信の実行モードを指定します。ライブ配信モードでは、ジェスチャー認識ツールがジェスチャー認識結果をデリゲートに非同期で配信できるように、gestureRecognizerLiveStreamDelegate
構成オプションも追加する必要があります。
ランニング モードに対応するタブを選択して、タスクの作成方法と推論の実行方法を確認します。
Swift
画像
import MediaPipeTasksVision let modelPath = Bundle.main.path(forResource: "gesture_recognizer", ofType: "task") let options = GestureRecognizerOptions() options.baseOptions.modelAssetPath = modelPath options.runningMode = .image options.minHandDetectionConfidence = minHandDetectionConfidence options.minHandPresenceConfidence = minHandPresenceConfidence options.minTrackingConfidence = minHandTrackingConfidence options.numHands = numHands let gestureRecognizer = try GestureRecognizer(options: options)
動画
import MediaPipeTasksVision let modelPath = Bundle.main.path(forResource: "gesture_recognizer", ofType: "task") let options = GestureRecognizerOptions() options.baseOptions.modelAssetPath = modelPath options.runningMode = .video options.minHandDetectionConfidence = minHandDetectionConfidence options.minHandPresenceConfidence = minHandPresenceConfidence options.minTrackingConfidence = minHandTrackingConfidence options.numHands = numHands let gestureRecognizer = try GestureRecognizer(options: options)
ライブ配信
import MediaPipeTasksVision // Class that conforms to the `GestureRecognizerLiveStreamDelegate` protocol and // implements the method that the gesture recognizer calls once it finishes // performing recognizing hand gestures in each input frame. class GestureRecognizerResultProcessor: NSObject, GestureRecognizerLiveStreamDelegate { func gestureRecognizer( _ gestureRecognizer: GestureRecognizer, didFinishRecognition result: GestureRecognizerResult?, timestampInMilliseconds: Int, error: Error?) { // Process the gesture recognizer result or errors here. } } let modelPath = Bundle.main.path( forResource: "gesture_recognizer", ofType: "task") let options = GestureRecognizerOptions() options.baseOptions.modelAssetPath = modelPath options.runningMode = .liveStream options.minHandDetectionConfidence = minHandDetectionConfidence options.minHandPresenceConfidence = minHandPresenceConfidence options.minTrackingConfidence = minHandTrackingConfidence options.numHands = numHands // Assign an object of the class to the `gestureRecognizerLiveStreamDelegate` // property. let processor = GestureRecognizerResultProcessor() options.gestureRecognizerLiveStreamDelegate = processor let gestureRecognizer = try GestureRecognizer(options: options)
Objective-C
画像
@import MediaPipeTasksVision; NSString *modelPath = [[NSBundle mainBundle] pathForResource:@"gesture_recognizer" ofType:@"task"]; MPPGestureRecognizerOptions *options = [[MPPGestureRecognizerOptions alloc] init]; options.baseOptions.modelAssetPath = modelPath; options.runningMode = MPPRunningModeImage; options.minHandDetectionConfidence = minHandDetectionConfidence options.minHandPresenceConfidence = minHandPresenceConfidence options.minTrackingConfidence = minHandTrackingConfidence options.numHands = numHands MPPGestureRecognizer *gestureRecognizer = [[MPPGestureRecognizer alloc] initWithOptions:options error:nil];
動画
@import MediaPipeTasksVision; NSString *modelPath = [[NSBundle mainBundle] pathForResource:@"gesture_recognizer" ofType:@"task"]; MPPGestureRecognizerOptions *options = [[MPPGestureRecognizerOptions alloc] init]; options.baseOptions.modelAssetPath = modelPath; options.runningMode = MPPRunningModeVideo; options.minHandDetectionConfidence = minHandDetectionConfidence options.minHandPresenceConfidence = minHandPresenceConfidence options.minTrackingConfidence = minHandTrackingConfidence options.numHands = numHands MPPGestureRecognizer *gestureRecognizer = [[MPPGestureRecognizer alloc] initWithOptions:options error:nil];
ライブ配信
@import MediaPipeTasksVision; // Class that conforms to the `MPPGestureRecognizerLiveStreamDelegate` protocol // and implements the method that the gesture recognizer calls once it finishes // performing gesture recognition on each input frame. @interface APPGestureRecognizerResultProcessor : NSObject@end @implementation APPGestureRecognizerResultProcessor - (void)gestureRecognizer:(MPPGestureRecognizer *)gestureRecognizer didFinishRecognitionWithResult:(MPPGestureRecognizerResult *)gestureRecognizerResult timestampInMilliseconds:(NSInteger)timestampInMilliseconds error:(NSError *)error { // Process the gesture recognizer result or errors here. } @end NSString *modelPath = [[NSBundle mainBundle] pathForResource:@"gesture_recognizer" ofType:@"task"]; MPPGestureRecognizerOptions *options = [[MPPGestureRecognizerOptions alloc] init]; options.baseOptions.modelAssetPath = modelPath; options.runningMode = MPPRunningModeLiveStream; options.minHandDetectionConfidence = minHandDetectionConfidence options.minHandPresenceConfidence = minHandPresenceConfidence options.minTrackingConfidence = minHandTrackingConfidence options.numHands = numHands // Assign an object of the class to the `gestureRecognizerLiveStreamDelegate` // property. APPGestureRecognizerResultProcessor *processor = [APPGestureRecognizerResultProcessor new]; options.gestureRecognizerLiveStreamDelegate = processor; MPPGestureRecognizer *gestureRecognizer = [[MPPGestureRecognizer alloc] initWithOptions:options error:nil];
設定オプション
このタスクには、iOS アプリ用の次の構成オプションがあります。
オプション名 | 説明 | 値の範囲 | デフォルト値 | |
---|---|---|---|---|
runningMode |
タスクの実行モードを設定します。モードは次の 3 つです。 IMAGE: 単一画像入力のモード。 動画: 動画のデコードされたフレームのモード。 LIVE_STREAM: カメラなどからの入力データのライブ配信モード。このモードでは、resultListener を呼び出して、結果を非同期で受信するリスナーを設定する必要があります。このモードでは、ジェスチャー認識を非同期で実行した結果を受け取るために、 GestureRecognizerLiveStreamDelegate を実装するクラスのインスタンスに gestureRecognizerLiveStreamDelegate を設定する必要があります。
|
{RunningMode.image, RunningMode.video, RunningMode.liveStream } |
RunningMode.image |
|
num_hands |
検出できる手の最大数は GestureRecognizer によって決まります。 |
Any integer > 0 |
1 |
|
min_hand_detection_confidence |
手の検出が成功と見なされるために必要な、手のひら検出モデルの信頼度の最小スコア。 | 0.0 - 1.0 |
0.5 |
|
min_hand_presence_confidence |
手のランドマーク検出モデルにおける手の存在スコアの最小信頼度スコア。ジェスチャー認識ツールの動画モードとライブ配信モードでは、手のランドマーク モデルからの手の存在の信頼スコアがこのしきい値を下回ると、手のひら検出モデルがトリガーされます。それ以外の場合は、軽量の手トラッキング アルゴリズムを使用して、その後のランドマーク検出のために手の位置を決定します。 | 0.0 - 1.0 |
0.5 |
|
min_tracking_confidence |
ハンド トラッキングが成功とみなされる最小信頼スコア。これは、現在のフレームと最後のフレームの手の間の境界ボックスの IoU しきい値です。ジェスチャー認識機能の動画モードとストリーミング モードでは、トラッキングに失敗すると、ジェスチャー認識機能が手の検出をトリガーします。それ以外の場合、手の検出はスキップされます。 | 0.0 - 1.0 |
0.5 |
|
canned_gestures_classifier_options |
定型ジェスチャー分類システムの動作を構成するためのオプション。定型ジェスチャーは ["None", "Closed_Fist", "Open_Palm", "Pointing_Up", "Thumb_Down", "Thumb_Up", "Victory", "ILoveYou"] です。 |
|
|
|
custom_gestures_classifier_options |
カスタム ジェスチャー分類システムの動作を構成するためのオプション。 |
|
|
|
result_listener |
ジェスチャー認識機能がライブ ストリーム モードのときに、分類結果を非同期で受信するように結果リスナーを設定します。実行モードが LIVE_STREAM に設定されている場合にのみ使用できます |
ResultListener |
なし | なし |
実行モードがライブ ストリームに設定されている場合、ジェスチャー認識ツールには追加の gestureRecognizerLiveStreamDelegate
構成オプションが必要です。これにより、ジェスチャー認識ツールはジェスチャー認識の結果を非同期で配信できます。デリゲートは gestureRecognizer(_:didFinishRecognition:timestampInMilliseconds:error:)
メソッドを実装する必要があります。このメソッドは、各フレームでジェスチャー認識の結果を処理した後にジェスチャー認識ツールによって呼び出されます。
オプション名 | 説明 | 値の範囲 | デフォルト値 |
---|---|---|---|
gestureRecognizerLiveStreamDelegate |
ジェスチャー認識がライブ配信モードでジェスチャー認識結果を非同期で受信できるようにします。このプロパティにインスタンスが設定されているクラスは、gestureRecognizer(_:didFinishRecognition:timestampInMilliseconds:error:) メソッドを実装する必要があります。 |
該当なし | 未設定 |
データの準備
入力画像またはフレームをジェスチャー認識ツールに渡す前に、MPImage
オブジェクトに変換する必要があります。MPImage
はさまざまな種類の iOS 画像形式をサポートしており、推論の実行モードで使用できます。MPImage
の詳細については、MPImage API をご覧ください。
ユースケースと、アプリに必要な実行モードに基づいて iOS イメージ形式を選択します。MPImage
は、UIImage
、CVPixelBuffer
、CMSampleBuffer
の iOS イメージ形式を受け入れます。
UIImage
UIImage
形式は、次の実行モードに適しています。
画像: App Bundle、ユーザー ギャラリー、
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 値のいずれかで初期化できます。ジェスチャー認識機能は、.upMirrored
、.downMirrored
、.leftMirrored
、.rightMirrored
などのミラーリングされた向きをサポートしていません。
UIImage
の詳細については、UIImage Apple デベロッパー ドキュメントをご覧ください。
CVPixelBuffer
CVPixelBuffer
形式は、フレームを生成し、iOS の CoreImage フレームワークを使用して処理するアプリに適しています。
CVPixelBuffer
形式は、次の実行モードに適しています。
画像: iOS の
CoreImage
フレームワークを使用して処理を行った後にCVPixelBuffer
画像を生成するアプリは、画像実行モードでジェスチャー認識ツールに送信できます。動画: 動画フレームは処理用に
CVPixelBuffer
形式に変換し、動画モードでジェスチャー認識ツールに送信できます。ライブ配信: iOS カメラを使用してフレームを生成するアプリは、処理のために
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 デベロッパー ドキュメントをご覧ください。
タスクを実行する
ジェスチャー認識ツールを実行するには、割り当てられた実行モードに固有の recognize()
メソッドを使用します。
- 静止画像:
recognize(image:)
- 動画:
recognize(videoFrame:timestampInMilliseconds:)
- ライブ配信:
recognizeAsync(image:timestampInMilliseconds:)
次のコードサンプルは、さまざまな実行モードでジェスチャー 認識ツールを実行する方法の基本的な例を示しています。
Swift
画像
let result = try gestureRecognizer.recognize(image: image)
動画
let result = try gestureRecognizer.recognize( videoFrame: image, timestampInMilliseconds: timestamp)
ライブ配信
try gestureRecognizer.recognizeAsync( image: image, timestampInMilliseconds: timestamp)
Objective-C
画像
MPPGestureRecognizerResult *result = [gestureRecognizer recognizeImage:mppImage error:nil];
動画
MPPGestureRecognizerResult *result = [gestureRecognizer recognizeVideoFrame:image timestampInMilliseconds:timestamp error:nil];
ライブ配信
BOOL success = [gestureRecognizer recognizeAsyncImage:image timestampInMilliseconds:timestamp error:nil];
サンプルコードでは、ユーザーが処理モードを切り替えることができますが、ユースケースで必要でない場合があります。
次の点にご留意ください。
動画モードまたはライブ配信モードで実行する場合は、入力フレームのタイムスタンプをジェスチャー認識タスクに指定する必要があります。
画像モードまたは動画モードで実行する場合、ジェスチャー認識タスクは、入力画像またはフレームの処理が完了するまで現在のスレッドをブロックします。現在のスレッドをブロックしないようにするには、iOS の Dispatch または NSOperation フレームワークを使用して、バックグラウンド スレッドで処理を実行します。
ライブ配信モードで実行すると、ジェスチャー認識タスクはすぐに返され、現在のスレッドはブロックされません。各入力フレームを処理した後、ジェスチャー認識結果を使用して
gestureRecognizer(_:didFinishRecognition:timestampInMilliseconds:error:)
メソッドを呼び出します。ジェスチャー認識ツールは、専用のシリアル ディスパッチ キューでこのメソッドを非同期的に呼び出します。結果をユーザー インターフェースに表示するには、結果を処理した後に結果をメインキューにディスパッチします。ジェスチャー認識タスクが別のフレームの処理でビジー状態になっているときにrecognizeAsync
関数が呼び出されると、ジェスチャー認識機能は新しい入力フレームを無視します。
結果を処理して表示する
推論を実行すると、ジェスチャー認識タスクは GestureRecognizerResult
を返します。この GestureRecognizerResult
には、画像座標のハンド ランドマーク、ワールド座標のハンド ランドマーク、利き手(左手/右手)、検出された手のハンド ジェスチャー カテゴリが含まれます。
このタスクの出力データの例を次に示します。
結果の GestureRecognizerResult
には 4 つのコンポーネントが含まれ、各コンポーネントは配列です。各要素には、検出された 1 つの手の検出結果が含まれます。
利き手
利き手は、検出された手が左手か右手かを表します。
ジェスチャー
検出された手の認識されたジェスチャー カテゴリ。
ランドマーク
21 個のハンド ランドマークがあり、それぞれ
x
、y
、z
座標で構成されています。x
座標とy
座標は、それぞれ画像の幅と高さで [0.0, 1.0] に正規化されます。z
座標はランドマークの深さを表し、手首の奥行きが原点になります。値が小さいほど、ランドマークはカメラに近くなります。z
の振幅は、x
とほぼ同じスケールを使用します。世界の名所
21 の針のランドマークも世界座標で示されています。各ランドマークは
x
、y
、z
で構成され、手形の幾何学的中心を原点として、メートル単位の現実世界の 3D 座標を表します。
GestureRecognizerResult:
Handedness:
Categories #0:
index : 0
score : 0.98396
categoryName : Left
Gestures:
Categories #0:
score : 0.76893
categoryName : Thumb_Up
Landmarks:
Landmark #0:
x : 0.638852
y : 0.671197
z : -3.41E-7
Landmark #1:
x : 0.634599
y : 0.536441
z : -0.06984
... (21 landmarks for a hand)
WorldLandmarks:
Landmark #0:
x : 0.067485
y : 0.031084
z : 0.055223
Landmark #1:
x : 0.063209
y : -0.00382
z : 0.020920
... (21 world landmarks for a hand)
次の画像は、タスク出力の可視化を示しています。