iOS 向けオブジェクト検出ガイド

オブジェクト検出タスクを使用すると、複数のクラスのオブジェクトの存在と位置を検出できます。たとえば、オブジェクト検出ツールは画像内の犬を検出できます。ここでは、iOS でオブジェクト検出タスクを使用する方法について説明します。この手順で説明されているコードサンプルは、GitHub で入手できます。

このタスクの動作を確認するには、こちらのウェブデモをご覧ください。このタスクの機能、モデル、構成オプションの詳細については、概要をご覧ください。

サンプルコード

MediaPipe Tasks のサンプルコードは、iOS 用オブジェクト検出アプリの基本的な実装です。この例では、物理 iOS デバイスのカメラを使用してオブジェクトを継続的に検出します。また、デバイス ギャラリーの画像や動画を使用してオブジェクトを静的に検出することもできます。

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

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

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

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

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

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

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

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

主要コンポーネント

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

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

セットアップ

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

依存関係

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

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

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

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

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

モデル

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

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

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

タスクを作成する

オブジェクト検出タスクを作成するには、いずれかのイニシャライザを呼び出します。ObjectDetector(options:) イニシャライザは、実行モード、表示名のロケール、結果の最大数、信頼度のしきい値、カテゴリの許可リスト、拒否リストなどの構成オプションの値を設定します。

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

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

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

Swift

画像

import MediaPipeTasksVision

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

let options = ObjectDetectorOptions()
options.baseOptions.modelAssetPath = modelPath
options.runningMode = .image
options.maxResults = 5

let objectDetector = try ObjectDetector(options: options)
    

動画

import MediaPipeTasksVision

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

let options = ObjectDetectorOptions()
options.baseOptions.modelAssetPath = modelPath
options.runningMode = .video
options.maxResults = 5

let objectDetector = try ObjectDetector(options: options)
    

ライブ配信

import MediaPipeTasksVision

// Class that conforms to the `ObjectDetectorLiveStreamDelegate` protocol and
// implements the method that the object detector calls once it
// finishes performing detection on each input frame.
class ObjectDetectorResultProcessor: NSObject, ObjectDetectorLiveStreamDelegate {

  func objectDetector(
    _ objectDetector: ObjectDetector,
    didFinishDetection objectDetectionResult: ObjectDetectorResult?,
    timestampInMilliseconds: Int,
    error: Error?) {
    // Process the detection result or errors here.
  }
}

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

let options = ObjectDetectorOptions()
options.baseOptions.modelAssetPath = modelPath
options.runningMode = .liveStream
options.maxResults = 5

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

let objectDetector = try ObjectDetector(options: options)
    

Objective-C

画像

@import MediaPipeTasksVision;

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

MPPObjectDetectorOptions *options = [[MPPObjectDetectorOptions alloc] init];
options.baseOptions.modelAssetPath = modelPath;
options.runningMode = MPPRunningModeImage;
options.maxResults = 5;

MPPObjectDetector *objectDetector =
      [[MPPObjectDetector alloc] initWithOptions:options error:nil];
    

動画

@import MediaPipeTasksVision;

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

MPPObjectDetectorOptions *options = [[MPPObjectDetectorOptions alloc] init];
options.baseOptions.modelAssetPath = modelPath;
options.runningMode = MPPRunningModeVideo;
options.maxResults = 5;

MPPObjectDetector *objectDetector =
      [[MPPObjectDetector alloc] initWithOptions:options error:nil];
    

ライブ配信

@import MediaPipeTasksVision;

// Class that conforms to the `ObjectDetectorLiveStreamDelegate` protocol and
// implements the method that the object detector calls once it
// finishes performing detection on each input frame.

@interface APPObjectDetectorResultProcessor : NSObject 

@end

@implementation MPPObjectDetectorResultProcessor

-   (void)objectDetector:(MPPObjectDetector *)objectDetector
    didFinishDetectionWithResult:(MPPObjectDetectorResult *)ObjectDetectorResult
         timestampInMilliseconds:(NSInteger)timestampInMilliseconds
                           error:(NSError *)error {

    // Process the detection result or errors here.

}

@end

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

MPPObjectDetectorOptions *options = [[MPPObjectDetectorOptions alloc] init];
options.baseOptions.modelAssetPath = modelPath;
options.runningMode = MPPRunningModeLiveStream;
options.maxResults = 5;

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

MPPObjectDetector *objectDetector =
      [[MPPObjectDetector alloc] initWithOptions:options error:nil];
    

構成オプション

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

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

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

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

LIVE_STREAM: カメラからのデータなど、入力データのライブストリームのモード。このモードでは、resultListener を呼び出して、結果を非同期で受け取るリスナーをセットアップする必要があります。
{RunningMode.image, RunningMode.video, RunningMode.liveStream} RunningMode.image
displayNamesLocales タスクのモデルのメタデータで提供される表示名に使用するラベルの言語を設定します(利用可能な場合)。英語の場合、デフォルトは en です。TensorFlow Lite Metadata Writer API を使用して、カスタムモデルのメタデータにローカライズされたラベルを追加できます。 言語 / 地域コード en
maxResults 返されるトップスコアの検出結果の最大数を設定します(省略可)。 任意の正の数 -1(すべての結果が返されます)
scoreThreshold モデル メタデータ(存在する場合)で指定された値をオーバーライドする予測スコアのしきい値を設定します。この値を下回る結果は拒否されます。 任意の浮動小数点数 未設定
categoryAllowlist 許可されるカテゴリ名のオプション リストを設定します。空でない場合、カテゴリ名がこのセットにない検出結果は除外されます。重複するカテゴリ名や不明なカテゴリ名は無視されます。 このオプションは categoryDenylist と相互に排他的であり、両方を使用するとエラーが発生します。 任意の文字列 未設定
categoryDenylist 使用できないカテゴリ名のオプション リストを設定します。空でない場合、カテゴリ名がこのセットに含まれる検出結果は除外されます。重複するカテゴリ名や不明なカテゴリ名は無視されます。このオプションは categoryAllowlist と相互に排他的であり、両方を使用するとエラーになります。 任意の文字列 未設定

ライブ配信の設定

実行モードがライブストリームに設定されている場合、オブジェクト検出機能には追加の objectDetectorLiveStreamDelegate 構成オプションが必要です。これにより、検出機能は非同期で検出結果を配信できます。このデリゲートは objectDetector(_objectDetector:didFinishDetection:timestampInMilliseconds:error:) メソッドを実装します。このメソッドは、各フレームの検出結果を処理した後に Object Detector が呼び出します。

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

データの準備

入力の画像またはフレームを MPImage オブジェクトに変換してから、Object Detector に渡す必要があります。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 値で初期化できます。Object Detector では、.upMirrored.downMirrored.leftMirrored.rightMirrored などのミラーリングされた向きはサポートされていません。

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

CVPixelBuffer

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

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

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

  • 動画: 動画フレームは CVPixelBuffer 形式に変換されて処理され、動画モードで Object Detector に送信できます。

  • livestream: 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:)

次のコードサンプルは、さまざまな実行モードで Object Detector を実行する基本的な例を示しています。

Swift

画像

let objectDetector.detect(image:image)
    

動画

let objectDetector.detect(videoFrame:image)
    

ライブ配信

let objectDetector.detectAsync(image:image)
    

Objective-C

画像

MPPObjectDetectorResult *result = [objectDetector detectInImage:image error:nil];
    

動画

MPPObjectDetectorResult *result = [objectDetector detectInVideoFrame:image          timestampInMilliseconds:timestamp error:nil];
    

ライブ配信

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

オブジェクト検出機能のコード例は、これらの各モードの実装を detect(image:)detect(videoFrame:)detectAsync(image:) でより詳細に示しています。サンプルコードを使用すると、ユースケースでは不要な処理モードを切り替えることができます。

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

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

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

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

結果を処理して表示する

推論を実行すると、オブジェクト検出タスクは、入力画像で検出されたオブジェクトを記述する ObjectDetectorResult オブジェクトを返します。

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

ObjectDetectorResult:
 Detection #0:
  Box: (x: 355, y: 133, w: 190, h: 206)
  Categories:
   index       : 17
   score       : 0.73828
   class name  : dog
 Detection #1:
  Box: (x: 103, y: 15, w: 138, h: 369)
  Categories:
   index       : 17
   score       : 0.73047
   class name  : dog

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

オブジェクト検出サンプルコードは、タスクから返された検出結果を表示する方法を示しています。詳細については、コードサンプルをご覧ください。