iOS 向け画像分類ガイド

画像分類タスクを使用すると、画像の分類を実行できます。このタスクを使用して、トレーニング時に定義された一連のカテゴリの中から画像が何を表しているかを特定できます。以下では、iOS アプリで画像分類器を使用する方法について説明します。この手順で説明するコードサンプルは GitHub で入手できます。

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

サンプルコード

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

このアプリは、独自の iOS アプリの出発点として使用することも、既存のアプリを変更するときに参照することもできます。画像分類器のサンプルコードは 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/image_classification/ios/
    

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

主要コンポーネント

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

セットアップ

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

依存関係

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

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

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

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

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

モデル

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

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

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

タスクを作成する

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

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

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

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

Swift

画像

import MediaPipeTasksVision

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

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

let imageClassifier = try ImageClassifier(options: options)
    

動画

import MediaPipeTasksVision

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

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

let imageClassifier = try ImageClassifier(options: options)
    

ライブ配信

import MediaPipeTasksVision

// Class that conforms to the `ImageClassifierLiveStreamDelegate` protocol and
// implements the method that the image classifier calls once it
// finishes performing classification on each input frame.
class ImageClassifierResultProcessor: NSObject, ImageClassifierLiveStreamDelegate {

   func imageClassifier(
    _ imageClassifier: ImageClassifier,
    didFinishClassification result: ImageClassifierResult?,
    timestampInMilliseconds: Int,
    error: Error?) {

    // Process the image classifier result or errors here.

  }
}

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

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

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

let imageClassifier = try ImageClassifier(options: options)
    

Objective-C

画像

@import MediaPipeTasksVision;

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

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

MPPImageClassifier *imageClassifier =
      [[MPPImageClassifier alloc] initWithOptions:options error:nil];
    

動画

@import MediaPipeTasksVision;

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

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

MPPImageClassifier *imageClassifier =
      [[MPPImageClassifier alloc] initWithOptions:options error:nil];
    

ライブ配信

@import MediaPipeTasksVision;

// Class that conforms to the `MPPImageClassifierLiveStreamDelegate` protocol
// and implements the method that the image classifier calls once it finishes
// performing classification on each input frame.

@interface APPImageClassifierResultProcessor : NSObject 

@end

@implementation APPImageClassifierResultProcessor

-   (void)imageClassifier:(MPPImageClassifier *)imageClassifier
    didFinishClassificationWithResult:(MPPImageClassifierResult *)imageClassifierResult
              timestampInMilliseconds:(NSInteger)timestampInMilliseconds
                                error:(NSError *)error {

    // Process the image classifier result or errors here.

}

@end

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

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

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

MPPImageClassifier *imageClassifier =
      [[MPPImageClassifier alloc] initWithOptions:options error:nil];
    

構成オプション

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

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

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

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

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

ライブ配信の設定

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

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

データの準備

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

ユースケースとアプリケーションに必要な実行モードに基づいて、iOS 画像形式を選択します。MPImage は、UIImageCVPixelBufferCMSampleBuffer の 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];
    

この例では、MPImage をデフォルトの UIImage.Orientation.Up の向きで初期化します。MPImage は、サポートされている UIImage.Orientation 値のいずれかで初期化できます。画像分類器は、.upMirrored.downMirrored.leftMirrored.rightMirrored などの画面の向きをサポートしていません。

UIImage の詳細については、UIImage Apple Developer Documentation をご覧ください。

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

タスクを実行する

画像分類器を実行するには、割り当てられた実行モードに固有の classify() メソッドを使用します。

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

画像分類器は、入力画像またはフレーム内のオブジェクトの可能なカテゴリを返します。

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

Swift

画像

let result = try imageClassifier.classify(image: image)
    

動画

let result = try imageClassifier.classify(
  videoFrame: image,
  timestampInMilliseconds: timestamp)
    

ライブ配信

try imageClassifier.classifyAsync(
  image: image,
  timestampInMilliseconds: timestamp)
    

Objective-C

画像

MPPImageClassifierResult *result = [imageClassifier classifyImage:image
                                                            error:nil];
    

動画

MPPImageClassifierResult *result = [imageClassifier classifyVideoFrame:image
                                               timestampInMilliseconds:timestamp
                                                                 error:nil];
    

ライブ配信

BOOL success = [imageClassifier classifyAsyncImage:image
                          timestampInMilliseconds:timestamp
                                            error:nil];
    

画像分類器のコード例では、これらの各モードの実装を、classify(image:)classify(videoFrame:timestampInMilliseconds:)classifyAsync(image:timestampInMilliseconds:) で詳しく示しています。このサンプルコードを使用すると、ユースケースでは不要な処理モードをユーザーが切り替えることができます。

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

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

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

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

結果の処理と表示

推論を実行すると、画像分類タスクは、入力画像またはフレーム内のオブジェクトの可能なカテゴリのリストを含む ImageClassifierResult オブジェクトを返します。

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

ImageClassifierResult:
 Classifications #0 (single classification head):
  head index: 0
  category #0:
   category name: "/m/01bwb9"
   display name: "Passer domesticus"
   score: 0.91406
   index: 671
  category #1:
   category name: "/m/01bwbt"
   display name: "Passer montanus"
   score: 0.00391
   index: 670

この結果は、以下に対して Bird Classifier を実行することで取得されました。

画像分類器のコード例は、タスクから返された分類結果を表示する方法を示しています。詳細については、コード例をご覧ください。