MediaPipe ジェスチャー認識タスクを使用すると、リアルタイムで手のジェスチャーを認識し、認識された手のジェスチャーの結果と検出された手のランドマークを提供します。ここでは、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 の使用をご覧ください。
次のコードを使用して、MediaPipeTasksVision Pod を Podfile
に追加します。
target 'MyGestureRecognizerApp' do
use_frameworks!
pod 'MediaPipeTasksVision'
end
アプリに単体テストのターゲットが含まれている場合は、iOS のセットアップ ガイドで Podfile
のセットアップの詳細をご確認ください。
モデル
MediaPipe ジェスチャー認識タスクには、このタスクと互換性のあるトレーニング済みモデルが必要です。ジェスチャー認識ツールで利用可能なトレーニング済みモデルについて詳しくは、タスクの概要のモデルのセクションをご覧ください。
モデルを選択してダウンロードし、Xcode を使用してプロジェクト ディレクトリに追加します。Xcode プロジェクトにファイルを追加する方法については、Xcode プロジェクト内のファイルとフォルダの管理をご覧ください。
BaseOptions.modelAssetPath
プロパティを使用して、App Bundle 内のモデルへのパスを指定します。コード例については、次のセクションをご覧ください。
タスクを作成する
イニシャライザの 1 つを呼び出して、ジェスチャー認識タスクを作成できます。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: 単一の画像入力のモード。 VIDEO: 動画のデコードされたフレームのモード。 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
形式は、次の実行モードに適しています。
画像:
UIImage
画像としてフォーマットされた App Bundle、ユーザー ギャラリー、ファイル システムの画像を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];
この例では、MPImage
をデフォルトの UIImage.Orientation.Up の向きで初期化しています。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
には 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)
次の図は、タスク出力を可視化したものです。