顔検出ガイド(iOS)

顔検出タスクを使用すると、画像や動画内の顔を検出できます。このタスクを使用して、フレーム内の顔や顔の特徴を特定できます。このタスクでは、単一の画像または画像の連続ストリームを操作する機械学習(ML)モデルを使用します。このタスクは、顔の位置と、顔のキーポイント(左目、右目、鼻先、口、左目による悲惨、右目による傷)を出力します。

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

サンプルコード

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

このアプリは、独自の iOS アプリの出発点として使用できます。また、既存のアプリを変更するときに参照することもできます。Face Detector のサンプルコードは 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 の設定ガイドをご覧ください。

依存関係

Face Detector は MediaPipeTasksVision ライブラリを使用します。このライブラリは、CocoaPods を使用してインストールする必要があります。このライブラリは、Swift アプリと Objective-C アプリの両方と互換性があり、言語固有の追加設定は必要ありません。

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

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

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

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

モデル

MediaPipe Face Detector タスクには、このタスクと互換性のあるトレーニング済みモデルが必要です。顔検出で利用可能なトレーニング済みモデルの詳細については、タスクの概要のモデルのセクションをご覧ください。

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

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

タスクを作成する

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

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

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

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

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: 単一の画像入力のモード。

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

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:) メソッドを実装します。このメソッドは、各フレームの顔検出結果を処理した後に Face Detector が呼び出します。

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

データの準備

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

ユースケースとアプリケーションに必要な実行モードに基づいて、iOS 画像形式を選択します。MPImage では、UIImageCVPixelBufferCMSampleBuffer の 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 形式に変換して処理した後、動画モードで顔検出器に送信できます。

  • livestream: iOS カメラを使用してフレームを生成するアプリは、ライブ配信モードで Face Detector に送信される前に処理のために 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:) で示しています。サンプルコードを使用すると、ユースケースでは不要な処理モードを切り替えることができます。

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

  • 動画モードまたはライブストリーム モードで実行する場合は、顔検出タスクに入力フレームのタイムスタンプも指定する必要があります。

  • 画像モードまたは動画モードで実行する場合、顔検出タスクは入力画像またはフレームの処理を完了するまで現在のスレッドをブロックします。現在のスレッドのブロックを回避するには、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)

次の図は、タスク出力を可視化したものです。

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

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