AutoML でトレーニングされたモデルを使用して画像内のオブジェクトを検出する(Android)

AutoML Vision Edge を使用して独自のモデルをトレーニングした後、そのモデルをアプリで使用して画像内のオブジェクトを検出することができます。

AutoML Vision Edge からトレーニングされたモデルを統合するには、アプリのアセット フォルダにモデルをバンドルする方法と、Firebase から動的にダウンロードする方法の 2 つがあります。

モデルのバンドル オプション
アプリにバンドルする
  • モデルはアプリの APK の一部である
  • このモデルは、Android デバイスがオフラインのときでもすぐに利用可能
  • Firebase プロジェクトは不要
Firebase でホストする
  • モデルを Firebase Machine Learning にアップロードしてホストする
  • APK のサイズを小さくする
  • モデルがオンデマンドでダウンロードされる
  • アプリを再公開することなくモデルの更新を push できる
  • Firebase Remote Config による簡単な A/B テスト
  • Firebase プロジェクトが必要

始める前に

  1. モデルをダウンロードする場合は、Firebase を Android プロジェクトに追加します(まだ行っていない場合)。これは、モデルをバンドルする場合には必要ありません。

  2. TensorFlow Lite タスク ライブラリの依存関係をモジュールのアプリレベルの Gradle ファイル(通常は app/build.gradle)に追加します。

    モデルをアプリにバンドルする場合:

    dependencies {
      // ...
      // Object detection with a bundled Auto ML model
      implementation 'org.tensorflow:tensorflow-lite-task-vision:0.0.0-nightly-SNAPSHOT'
    }
    

    Firebase からモデルを動的にダウンロードする場合は、Firebase ML の依存関係も追加します。

    dependencies {
      // ...
      // Object detection with an Auto ML model deployed to Firebase
      implementation platform('com.google.firebase:firebase-bom:26.1.1')
      implementation 'com.google.firebase:firebase-ml-model-interpreter'
    
      implementation 'org.tensorflow:tensorflow-lite-task-vision:0.0.0-nightly'
    }
    

1. モデルを読み込む

ローカル モデルソースを構成する

モデルをアプリにバンドルするには:

  1. Google Cloud コンソール からダウンロードした zip アーカイブからモデルを抽出します。
  2. モデルをアプリ パッケージに含めます。
    1. プロジェクトにアセット フォルダがない場合は、app/ フォルダを右クリックし、次に [新規] > [フォルダ] > [Assets フォルダ]の順にクリックして作成します。
    2. メタデータが埋め込まれた tflite モデルファイルをアセット フォルダにコピーします。
  3. アプリのビルド時に Gradle がモデルファイルを圧縮しないように、アプリの build.gradle ファイルに以下を追加します。

    android {
        // ...
        aaptOptions {
            noCompress "tflite"
        }
    }
    

    モデルファイルはアプリ パッケージに含められ、生のアセットとして使用できます。

Firebase によってホストされるモデルソースを構成する

リモートでホストされるモデルを使用するには、RemoteModel オブジェクトを作成します。その際に、モデルを公開したときに割り当てた名前を指定します。

Java

// Specify the name you assigned when you deployed the model.
FirebaseCustomRemoteModel remoteModel =
        new FirebaseCustomRemoteModel.Builder("your_model").build();

Kotlin

// Specify the name you assigned when you deployed the model.
val remoteModel =
    FirebaseCustomRemoteModel.Builder("your_model_name").build()

次に、ダウンロードを許可する条件を指定してモデルのダウンロード タスクを開始します。モデルがデバイスにない場合、または新しいバージョンのモデルが使用可能な場合、このタスクは Firebase から非同期でモデルをダウンロードします。

Java

DownloadConditions downloadConditions = new DownloadConditions.Builder()
        .requireWifi()
        .build();
RemoteModelManager.getInstance().download(remoteModel, downloadConditions)
        .addOnSuccessListener(new OnSuccessListener<Void>() {
            @Override
            public void onSuccess(@NonNull Task<Void> task) {
                // Success.
            }
        });

Kotlin

val downloadConditions = DownloadConditions.Builder()
    .requireWifi()
    .build()
RemoteModelManager.getInstance().download(remoteModel, downloadConditions)
    .addOnSuccessListener {
        // Success.
    }

多くのアプリは、初期化コードでモデルのダウンロード タスクを開始しますが、モデルを使用する前に開始することもできます。

モデルからオブジェクト検出器を作成する

モデルソースを構成した後、そのソースのいずれか 1 つから ObjectDetector オブジェクトを作成します。

ローカル バンドル モデルのみを使用する場合は、モデルファイルからオブジェクト検出器を作成し、必要な信頼スコアしきい値を構成するだけで済みます(モデルを評価するを参照)。

Java

// Initialization
ObjectDetectorOptions options = ObjectDetectorOptions.builder()
    .setScoreThreshold(0)  // Evaluate your model in the Google Cloud console
                           // to determine an appropriate value.
    .build();
ObjectDetector objectDetector = ObjectDetector.createFromFileAndOptions(context, modelFile, options);

Kotlin

// Initialization
val options = ObjectDetectorOptions.builder()
    .setScoreThreshold(0)  // Evaluate your model in the Google Cloud console
                           // to determine an appropriate value.
    .build()
val objectDetector = ObjectDetector.createFromFileAndOptions(context, modelFile, options)

リモートでホストされるモデルがある場合は、そのモデルを実行する前にダウンロード済みであることを確認する必要があります。モデルのダウンロード タスクのステータスは、モデル マネージャーの isModelDownloaded() メソッドを使用して確認できます。

ダウンロードのステータスの確認はオブジェクト検出器を実行する前に行いますが、リモートでホストされるモデルとローカル バンドル モデルの両方を使用する場合は、オブジェクト検出器をインスタンス化するときにこの確認を行うという選択肢があります。この方法では、リモートモデルがダウンロードされている場合はリモートモデルから検出器を作成し、リモートモデルがダウンロードされていない場合はローカルモデルから検出器を作成するということが可能です。

Java

FirebaseModelManager.getInstance().isModelDownloaded(remoteModel)
        .addOnSuccessListener(new OnSuccessListener<Boolean>() {
            @Override
            public void onSuccess(Boolean isDownloaded) {
            }
        });

Kotlin

FirebaseModelManager.getInstance().isModelDownloaded(remoteModel)
        .addOnSuccessListener { success ->

        }

リモートでホストされるモデルのみがある場合は、モデルがダウンロード済みであることを確認するまで、モデルに関連する機能を無効にする必要があります(UI の一部をグレー表示または非表示にするなど)。確認はモデル マネージャーの download() メソッドにリスナーを接続して行います。

モデルがダウンロードされていることを確認したら、そのモデルファイルからオブジェクト検出器を作成します。

Java

FirebaseModelManager.getInstance().getLatestModelFile(remoteModel)
        .addOnCompleteListener(new OnCompleteListener<File>() {
            @Override
            public void onComplete(@NonNull Task<File> task) {
                File modelFile = task.getResult();
                if (modelFile != null) {
                    ObjectDetectorOptions options = ObjectDetectorOptions.builder()
                            .setScoreThreshold(0)
                            .build();
                    objectDetector = ObjectDetector.createFromFileAndOptions(
                            getApplicationContext(), modelFile.getPath(), options);
                }
            }
        });

Kotlin

FirebaseModelManager.getInstance().getLatestModelFile(remoteModel)
        .addOnSuccessListener { modelFile ->
            val options = ObjectDetectorOptions.builder()
                    .setScoreThreshold(0f)
                    .build()
            objectDetector = ObjectDetector.createFromFileAndOptions(
                    applicationContext, modelFile.path, options)
        }

2. 入力画像を準備する

次に、ラベルを付ける画像ごとに、画像から TensorImage オブジェクトを作成します。fromBitmap メソッドを使用すると、Bitmap から TensorImage オブジェクトを作成できます。

Java

TensorImage image = TensorImage.fromBitmap(bitmap);

Kotlin

val image = TensorImage.fromBitmap(bitmap)

画像データが Bitmap でない場合は、TensorFlow Lite のドキュメントに記載されている方法でピクセル配列を読み込むことができます。

3. オブジェクト検出器を実行する

画像内のオブジェクトを検出するには、TensorImage オブジェクトを ObjectDetectordetect() メソッドに渡します。

Java

List<Detection> results = objectDetector.detect(image);

Kotlin

val results = objectDetector.detect(image)

4. ラベル付きオブジェクトに関する情報を取得する

オブジェクト検出オペレーションが成功すると、Detection オブジェクトのリストが返されます。それぞれの Detection オブジェクトは画像内で検出されたものを表します。各オブジェクトの境界ボックスとラベルを取得できます。

次に例を示します。

Java

for (Detection result : results) {
    RectF bounds = result.getBoundingBox();
    List<Category> labels = result.getCategories();
}

Kotlin

for (result in results) {
    val bounds = result.getBoundingBox()
    val labels = result.getCategories()
}

リアルタイムのパフォーマンスを改善するためのヒント

リアルタイムのアプリケーションで画像にラベルを付ける場合は、適切なフレームレートを得るために次のガイドラインに沿ってください。

  • 画像ラベラーの呼び出しをスロットリングします。画像ラベラーの実行中に新しい動画フレームが使用可能になった場合は、そのフレームをドロップします。例については、クイックスタート サンプルアプリの VisionProcessorBase クラスをご覧ください。
  • 画像ラベラーの出力を使用して入力画像の上にグラフィックスをオーバーレイする場合は、まず検出結果を取得し、画像とオーバーレイを 1 つのステップでレンダリングします。これにより、ディスプレイ サーフェスへのレンダリングは入力フレームごとに 1 回で済みます。例については、クイックスタート サンプルアプリの CameraSourcePreview クラスと GraphicOverlay クラスをご覧ください。
  • Camera2 API を使用する場合は、ImageFormat.YUV_420_888 形式で画像をキャプチャします。

    古い Camera API を使用する場合は、ImageFormat.NV21 形式で画像をキャプチャします。