顔検出ガイド(iOS)

顔検出タスクを使用すると、画像または動画内の顔を検出できます。このタスクを使用して、フレーム内の顔と顔の特徴を見つけることができます。このタスクでは、単一の画像または連続した画像ストリームを処理する ML モデルを使用します。このタスクは、顔の位置と、左目、右目、鼻先、口、左目のトラゴン、右目のトラゴンの顔のキーポイントを出力します。

これらの手順で説明するコードサンプルは GitHub で入手できます。このタスクの動作を確認するには、こちらのウェブデモをご覧ください。このタスクの機能、モデル、構成オプションの詳細については、概要をご覧ください。

サンプルコード

MediaPipe Tasks のサンプルコードは、iOS 向けの顔検出アプリのシンプルな実装です。この例では、物理的な Android デバイスのカメラを使用して、連続した動画ストリーム内の顔を検出します。デバイスのギャラリーにある画像や動画の顔も検出できます。

このアプリは、独自の iOS アプリの開始点として使用できます。また、既存のアプリを変更する際にも参照できます。フェイス検出器のサンプルコードは GitHub でホストされています。

コードをダウンロードする

次の手順では、git コマンドライン ツールを使用してサンプルコードのローカルコピーを作成する方法について説明します。

サンプルコードをダウンロードするには:

  1. 次のコマンドを使用して、Git リポジトリのクローンを作成します。

    git clone https://github.com/google-ai-edge/mediapipe-samples
    
  2. 必要に応じて、スパース チェックアウトを使用するように Git インスタンスを構成し、Face Detector サンプルアプリのファイルのみを取得します。

    cd mediapipe
    git sparse-checkout init --cone
    git sparse-checkout set examples/face_detector/ios/
    

ローカル バージョンのサンプルコードを作成したら、MediaPipe タスク ライブラリをインストールし、Xcode を使用してプロジェクトを開いてアプリを実行できます。手順については、iOS 用セットアップガイドをご覧ください。

主要コンポーネント

次のファイルには、Face Detector サンプル アプリケーションの重要なコードが含まれています。

  • FaceDetectorService.swift: 検出機能を初期化し、モデル選択を処理して、入力データに対する推論を実行します。
  • CameraViewController: ライブカメラフィード入力モードの UI を実装し、検出結果を可視化します。
  • MediaLibraryViewController.swift: 静止画像と動画ファイルの入力モードの UI を実装し、検出結果を可視化します。

セットアップ

このセクションでは、Face Detector を使用するための開発環境とコード プロジェクトを設定するための主な手順について説明します。プラットフォーム バージョンの要件など、MediaPipe タスクを使用する開発環境の設定に関する一般的な情報については、iOS 用セットアップ ガイドをご覧ください。

依存関係

顔検出機能は、MediaPipeTasksVision ライブラリを使用します。このライブラリは、CocoaPods を使用してインストールする必要があります。このライブラリは Swift アプリと Objective-C アプリの両方に対応しており、言語固有の追加設定は必要ありません。

macOS に CocoaPods をインストールする手順については、CocoaPods インストール ガイドをご覧ください。アプリに必要な Pod を使用して Podfile を作成する方法については、CocoaPods の使用をご覧ください。

次のコードを使用して、Podfile に MediaPipeTasksVision Pod を追加します。

target 'MyFaceDetectorApp' do
  use_frameworks!
  pod 'MediaPipeTasksVision'
end

アプリに単体テスト ターゲットが含まれている場合は、Podfile の設定について詳しくは、iOS 用セットアップ ガイドをご覧ください。

モデル

MediaPipe フェイス検出タスクには、このタスクに対応したトレーニング済みモデルが必要です。顔検出機能で使用可能なトレーニング済みモデルの詳細については、タスクの概要のモデル セクションをご覧ください。

モデルを選択してダウンロードし、Xcode を使用してプロジェクト ディレクトリに追加します。Xcode プロジェクトにファイルを追加する方法については、Xcode プロジェクト内のファイルとフォルダの管理をご覧ください。

BaseOptions.modelAssetPath プロパティを使用して、アプリバンドルのモデルのパスを指定します。コード例については、次のセクションをご覧ください。

タスクを作成する

顔検出タスクを作成するには、いずれかの初期化子を呼び出します。FaceDetector(options:) イニシャライザは、構成オプションの値を受け入れます。

カスタマイズされた構成オプションで初期化された顔検出器が不要な場合は、FaceDetector(modelPath:) イニシャライザを使用して、デフォルト オプションで顔検出器を作成できます。構成オプションの詳細については、構成の概要をご覧ください。

顔検出タスクは、静止画像、動画ファイル、ライブ動画ストリーミングの 3 種類の入力データ形式をサポートしています。デフォルトでは、FaceDetector(modelPath:) は静止画像のタスクを初期化します。動画ファイルまたはライブ動画ストリームを処理するようにタスクを初期化する場合は、FaceDetector(options:) を使用して動画またはライブ配信の実行モードを指定します。ライブ配信モードでは、Face Detector が顔検出結果をデリゲータに非同期で配信できるようにする faceDetectorLiveStreamDelegate 構成オプションも必要です。

実行モードに対応するタブを選択して、タスクを作成し推論を実行する方法を確認します。

Swift

画像

import MediaPipeTasksVision

let modelPath = Bundle.main.path(forResource: "model",
                                      ofType: "tflite")

let options = FaceDetectorOptions()
options.baseOptions.modelAssetPath = modelPath
options.runningMode = .image

let faceDetector = try FaceDetector(options: options)
    

動画

import MediaPipeTasksVision

let modelPath = Bundle.main.path(forResource: "model",
                                      ofType: "tflite")

let options = FaceDetectorOptions()
options.baseOptions.modelAssetPath = modelPath
options.runningMode = .video

let faceDetector = try FaceDetector(options: options)
    

ライブ配信

import MediaPipeTasksVision

// Class that conforms to the `FaceDetectorLiveStreamDelegate` protocol and
// implements the method that the face detector calls once it finishes
// detecting faces in each input frame.
class FaceDetectorResultProcessor: NSObject, FaceDetectorLiveStreamDelegate {

  func faceDetector(
    _ faceDetector: FaceDetector,
    didFinishDetection result: FaceDetectorResult?,
    timestampInMilliseconds: Int,
    error: Error?) {

    // Process the face detection result or errors here.

  }
}

let modelPath = Bundle.main.path(
  forResource: "model",
  ofType: "tflite")

let options = FaceDetectorOptions()
options.baseOptions.modelAssetPath = modelPath
options.runningMode = .liveStream

// Assign an object of the class to the `faceDetectorLiveStreamDelegate`
// property.
let processor = FaceDetectorResultProcessor()
options.faceDetectorLiveStreamDelegate = processor

let faceDetector = try FaceDetector(options: options)
    

Objective-C

画像

@import MediaPipeTasksVision;

NSString *modelPath = [[NSBundle mainBundle] pathForResource:@"model"
                                                      ofType:@"tflite"];

MPPFaceDetectorOptions *options = [[MPPFaceDetectorOptions alloc] init];
options.baseOptions.modelAssetPath = modelPath;
options.runningMode = MPPRunningModeImage;

MPPFaceDetector *faceDetector =
      [[MPPFaceDetector alloc] initWithOptions:options error:nil];
    

動画

@import MediaPipeTasksVision;

NSString *modelPath = [[NSBundle mainBundle] pathForResource:@"model"
                                                      ofType:@"tflite"];

MPPFaceDetectorOptions *options = [[MPPFaceDetectorOptions alloc] init];
options.baseOptions.modelAssetPath = modelPath;
options.runningMode = MPPRunningModeVideo;

MPPFaceDetector *faceDetector =
      [[MPPFaceDetector alloc] initWithOptions:options error:nil];
    

ライブ配信

@import MediaPipeTasksVision;

// Class that conforms to the `MPPFaceDetectorLiveStreamDelegate` protocol
// and implements the method that the face detector calls once it finishes
// detecting faces in each input frame.

@interface APPFaceDetectorResultProcessor : NSObject 

@end

@implementation APPFaceDetectorResultProcessor

-   (void)faceDetector:(MPPFaceDetector *)faceDetector
    didFinishDetectionWithResult:(MPPFaceDetectorResult *)faceDetectorResult
         timestampInMilliseconds:(NSInteger)timestampInMilliseconds
                           error:(NSError *)error {

    // Process the face detector result or errors here.

}

@end

NSString *modelPath = [[NSBundle mainBundle] pathForResource:@"model"
                                                      ofType:@"tflite"];

MPPFaceDetectorOptions *options = [[MPPFaceDetectorOptions alloc] init];
options.baseOptions.modelAssetPath = modelPath;
options.runningMode = MPPRunningModeLiveStream;

// Assign an object of the class to the `faceDetectorLiveStreamDelegate`
// property.
APPFaceDetectorResultProcessor *processor = [APPFaceDetectorResultProcessor new];
options.faceDetectorLiveStreamDelegate = processor;

MPPFaceDetector *faceDetector =
      [[MPPFaceDetector alloc] initWithOptions:options error:nil];
    

注: 動画モードまたはライブ配信モードを使用している場合、Face Detector はトラッキングを使用して、フレームごとに検出モデルをトリガーしないようにします。これにより、レイテンシを短縮できます。

設定オプション

このタスクには、iOS アプリ用の次の構成オプションがあります。

オプション名 説明 値の範囲 デフォルト値
runningMode タスクの実行モードを設定します。モードは次の 3 つです。

IMAGE: 単一画像入力のモード。

動画: 動画のデコードされたフレームのモード。

LIVE_STREAM: カメラなどの入力データのライブ ストリームのモード。このモードでは、resultListener を呼び出して、結果を非同期で受信するリスナーを設定する必要があります。
{RunningMode.image, RunningMode.video, RunningMode.liveStream} RunningMode.image
minDetectionConfidence 顔検出が成功とみなされるための最小信頼スコア。 Float [0,1] 0.5
minSuppressionThreshold 顔検出が重複と見なされる最小の非最大抑制しきい値。 Float [0,1] 0.3

ライブ配信の設定

実行モードがライブ配信に設定されている場合、顔検出器には faceDetectorLiveStreamDelegate 構成オプションが必要です。これにより、顔検出器は検出結果を非同期で提供できます。デリゲートには faceDetector(_:didFinishDetection:timestampInMilliseconds:error:) メソッドを実装します。このメソッドは、各フレームの顔検出結果を処理した後に顔検出器によって呼び出されます。

オプション名 説明 値の範囲 デフォルト値
faceDetectorLiveStreamDelegate ライブ配信モードで、顔検出が顔検出の結果を非同期で受信できるようにします。このプロパティにインスタンスが設定されているクラスは、faceDetector(_:didFinishDetection:timestampInMilliseconds:error:) メソッドを実装する必要があります。 該当なし 未設定

データの準備

入力画像またはフレームを Face Detector に渡す前に、MPImage オブジェクトに変換する必要があります。MPImage はさまざまな種類の iOS 画像形式をサポートしており、推論の実行モードで使用できます。MPImage の詳細については、MPImage API をご覧ください。

ユースケースと、アプリに必要な実行モードに基づいて iOS イメージ形式を選択します。MPImage は、UIImageCVPixelBufferCMSampleBuffer の 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 値のいずれかで初期化できます。顔検出機能は、.upMirrored.downMirrored.leftMirrored.rightMirrored などのミラーリングされた向きをサポートしていません。

UIImage の詳細については、UIImage Apple デベロッパー ドキュメントをご覧ください。

CVPixelBuffer

CVPixelBuffer 形式は、フレームを生成し、iOS の CoreImage フレームワークを使用して処理するアプリに適しています。

CVPixelBuffer 形式は、次の実行モードに適しています。

  • 画像: iOS の CoreImage フレームワークを使用してなんらかの処理を行った後に CVPixelBuffer 画像を生成するアプリは、画像実行モードで Face Detector に送信できます。

  • 動画: 動画フレームを CVPixelBuffer 形式に変換してから、動画モードで Face Detector に送信できます。

  • ライブ配信: 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 デベロッパー ドキュメントをご覧ください。

タスクを実行する

顔検出機能を実行するには、割り当てられた実行モードに固有の detect() メソッドを使用します。

  • 静止画像: detect(image:)
  • 動画: detect(videoFrame:timestampInMilliseconds:)
  • ライブ配信: detectAsync(image:timestampInMilliseconds:)

顔検出機能は、入力画像またはフレーム内で検出された顔を返します。

次のコードサンプルは、これらのさまざまな実行モードでフェイス検出を実行する方法の簡単な例を示しています。

Swift

画像

let result = try faceDetector.detect(image: image)
    

動画

let result = try faceDetector.detect(
  videoFrame: image,
  timestampInMilliseconds: timestamp)
    

ライブ配信

try faceDetector.detectAsync(
  image: image,
  timestampInMilliseconds: timestamp)
    

Objective-C

画像

MPPFaceDetectorResult *result = [faceDetector detectInImage:image
                                                      error:nil];
    

動画

MPPFaceDetectorResult *result = [faceDetector detectInVideoFrame:image
                                         timestampInMilliseconds:timestamp
                                                           error:nil];
    

ライブ配信

BOOL success = [faceDetector detectAsyncInImage:image
                        timestampInMilliseconds:timestamp
                                          error:nil];
    

顔検出器のコード例では、これらの各モードの実装について、detect(image:)detect(videoFrame:timestampInMilliseconds:)detectAsync(image:timestampInMilliseconds:) について詳しく説明します。サンプルコードでは、ユーザーが処理モードを切り替えることができますが、ユースケースで必要でない場合があります。

次の点にご留意ください。

  • 動画モードまたはライブ配信モードで実行する場合は、入力フレームのタイムスタンプを Face Detector タスクに指定する必要があります。

  • 画像モードまたは動画モードで実行している場合、顔検出タスクは、入力画像またはフレームの処理が完了するまで現在のスレッドをブロックします。現在のスレッドをブロックしないようにするには、iOS の Dispatch または NSOperation フレームワークを使用して、バックグラウンド スレッドで処理を実行します。

  • ライブ配信モードで実行すると、顔検出タスクはすぐに返され、現在のスレッドはブロックされません。各入力フレームを処理した後、顔検出結果を指定して faceDetector(_:didFinishDetection:timestampInMilliseconds:error:) メソッドを呼び出します。顔検出器は、専用のシリアル ディスパッチ キューで、このメソッドを非同期で呼び出します。結果をユーザー インターフェースに表示するには、結果を処理した後に結果をメインキューにディスパッチします。顔検出タスクが別のフレームの処理でビジー状態になっているときに detectAsync 関数が呼び出された場合、顔検出器は新しい入力フレームを無視します。

結果の処理と表示

推論を実行すると、顔検出タスクは、検出された顔の境界ボックスと検出された各顔の信頼スコアを含む FaceDetectorResult オブジェクトを返します。

このタスクからの出力データの例を次に示します。

FaceDetectionResult:
  Detections:
    Detection #0:
      BoundingBox:
        origin_x: 126
        origin_y: 100
        width: 463
        height: 463
      Categories:
        Category #0:
          index: 0
          score: 0.9729152917861938
      NormalizedKeypoints:
        NormalizedKeypoint #0:
          x: 0.18298381567001343
          y: 0.2961040139198303
        NormalizedKeypoint #1:
          x: 0.3302789330482483
          y: 0.29289937019348145
        ... (6 keypoints for each face)
    Detection #1:
      BoundingBox:
        origin_x: 616
        origin_y: 193
        width: 430
        height: 430
      Categories:
        Category #0:
          index: 0
          score: 0.9251380562782288
      NormalizedKeypoints:
        NormalizedKeypoint #0:
          x: 0.6151331663131714
          y: 0.3713381886482239
        NormalizedKeypoint #1:
          x: 0.7460576295852661
          y: 0.38825345039367676
        ... (6 keypoints for each face)

次の画像は、タスク出力の可視化を示しています。

境界ボックスのない画像については、元の画像をご覧ください。

顔検出器のサンプルコードでは、結果を表示する方法を示しています。詳しくは、コードサンプルをご覧ください。