Android による物体検出

このチュートリアルでは、TensorFlow Lite を使用して、デバイスのカメラでキャプチャされたフレーム内のオブジェクトを継続的に検出する Android アプリを構築する方法を説明します。このアプリケーションは、物理的な Android デバイス用に設計されています。既存のプロジェクトを更新する場合は、コード サンプルを参照として使用し、プロジェクトを変更する手順に進んでください。

物体検出のアニメーションデモ

物体検出の概要

物体検出は、画像内の複数のクラスの物体の存在と位置を識別する機械学習タスクです。物体検出モデルは、既知の物体のセットを含むデータセットでトレーニングされます。

トレーニングされたモデルは画像フレームを入力として受け取り、認識するようにトレーニングされた既知のクラスのセットから画像内の項目を分類しようとします。画像フレームごとに、物体検出モデルは、検出した物体のリスト、各物体の境界ボックスの位置、および物体が正しく分類されている信頼度を示すスコアを出力します。

モデルとデータセット

このチュートリアルでは、 COCO データセットを使用してトレーニングされたモデルを使用します。 COCO は、330,000 の画像、150 万のオブジェクト インスタンス、80 のオブジェクト カテゴリを含む大規模なオブジェクト検出データセットです。

次の事前トレーニングされたモデルのいずれかを使用するオプションがあります。

  • EfficientDet-Lite0 [推奨] - BiFPN 特徴抽出器、共有ボックス予測器、および焦点損失を備えた軽量の物体検出モデル。 COCO 2017 検証データセットの mAP (平均平均精度) は 25.69% です。

  • EfficientDet-Lite1 - 中型の EfficientDet オブジェクト検出モデル。 COCO 2017 検証データセットの mAP は 30.55% です。

  • EfficientDet-Lite2 - より大きな EfficientDet オブジェクト検出モデル。 COCO 2017 検証データセットの mAP は 33.97% です。

  • MobileNetV1-SSD - 物体検出のために TensorFlow Lite と連携するように最適化された非常に軽量なモデル。 COCO 2017 検証データセットの mAP は 21% です。

このチュートリアルでは、 EfficientDet-Lite0モデルはサイズと精度のバランスが取れています。

モデルのダウンロード、抽出、およびアセット フォルダーへの配置は、ビルド時に実行されるdownload.gradleファイルによって自動的に管理されます。 TFLite モデルをプロジェクトに手動でダウンロードする必要はありません。

セットアップと実行の例

物体検出アプリをセットアップするには、 GitHubからサンプルをダウンロードし、 Android Studioを使用して実行します。このチュートリアルの次のセクションでは、コード例の関連セクションを検討して、独自の Android アプリに適用できるようにします。

システム要求

  • Android Studioバージョン 2021.1.1 (Bumblebee) 以降。
  • Android SDK バージョン 31 以降
  • 開発者モードが有効になっている、SDK 24 (Android 7.0 - Nougat) の最小 OS バージョンを搭載した Android デバイス。

サンプルコードを入手する

サンプル コードのローカル コピーを作成します。このコードを使用して Android Studio でプロジェクトを作成し、サンプル アプリケーションを実行します。

サンプルコードを複製してセットアップするには、次のようにします。

  1. git リポジトリ
    git clone https://github.com/tensorflow/examples.git
    
    のクローンを作成します
  2. 必要に応じて、スパース チェックアウトを使用するように Git インスタンスを構成して、オブジェクト検出サンプル アプリのファイルのみを用意します:
    cd examples
    git sparse-checkout init --cone
    git sparse-checkout set lite/examples/object_detection/android
    

プロジェクトをインポートして実行する

ダウンロードしたサンプル コードからプロジェクトを作成し、プロジェクトをビルドして実行します。

サンプル コード プロジェクトをインポートしてビルドするには:

  1. Android Studioを起動します。
  2. Android Studio から、 [ファイル] > [新規作成] > [プロジェクトのインポート]を選択します。
  3. build.gradle ファイルを含むサンプル コード ディレクトリ ( .../examples/lite/examples/object_detection/android/build.gradle ) に移動し、そのディレクトリを選択します。
  4. Android Studio が Gradle Sync を要求する場合は、[OK] を選択します。
  5. Android デバイスがコンピュータに接続されており、開発者モードが有効になっていることを確認してください。緑色のRun矢印をクリックします。

正しいディレクトリを選択すると、Android Studio は新しいプロジェクトを作成してビルドします。コンピューターの速度や、他のプロジェクトで Android Studio を使用しているかどうかによっては、このプロセスに数分かかる場合があります。ビルドが完了すると、Android Studio の[ビルド出力ステータス] パネルにBUILD SUCCESSFULメッセージが表示されます。

オプション: Android プラグインのバージョンを更新してビルド エラーを修正するには、次の手順を実行します。

  1. プロジェクト ディレクトリ内の build.gradle ファイルを開きます。
  2. Android ツールのバージョンを次のように変更します。

    // from: classpath
    'com.android.tools.build:gradle:4.2.2'
    // to: classpath
    'com.android.tools.build:gradle:4.1.2'
    
  3. [ファイル] > [プロジェクトを Gradle ファイルと同期]を選択して、プロジェクトを同期します。

プロジェクトを実行するには:

  1. Android Studio から、 [実行] > [実行…]を選択してプロジェクトを実行します。
  2. アプリをテストするには、カメラが接続されている Android デバイスを選択します。

次のセクションでは、このサンプル アプリを参照ポイントとして使用して、この機能を独自のアプリに追加するために既存のプロジェクトに加える必要がある変更を示します。

プロジェクトの依存関係を追加する

独自のアプリケーションでは、TensorFlow Lite 機械学習モデルを実行し、画像などのデータを、使用しているモデルで処理できるテンソル データ形式に変換するユーティリティ関数にアクセスするには、特定のプロジェクトの依存関係を追加する必要があります。

サンプル アプリでは、ビジョン用の TensorFlow Lite タスク ライブラリを使用して、物体検出機械学習モデルの実行を可能にします。次の手順では、必要なライブラリの依存関係を独自の Android アプリ プロジェクトに追加する方法について説明します。

次の手順では、必要なプロジェクトとモジュールの依存関係を独自の Android アプリ プロジェクトに追加する方法について説明します。

モジュールの依存関係を追加するには:

  1. TensorFlow Lite を使用するモジュールで、モジュールのbuild.gradleファイルを更新して、次の依存関係を含めます。コード例では、このファイルは次の場所にあります: ...examples/lite/examples/object_detection/android/app/build.gradle (コード リファレンス)

    dependencies {
      ...
      implementation 'org.tensorflow:tensorflow-lite-task-vision:0.4.0'
      // Import the GPU delegate plugin Library for GPU inference
      implementation 'org.tensorflow:tensorflow-lite-gpu-delegate-plugin:0.4.0'
      implementation 'org.tensorflow:tensorflow-lite-gpu:2.9.0'
    }
    

    プロジェクトには、Vision タスク ライブラリ ( tensorflow-lite-task-vision ) が含まれている必要があります。グラフィックス プロセッシング ユニット (GPU) ライブラリ ( tensorflow-lite-gpu-delegate-plugin ) は、GPU 上でアプリを実行するためのインフラストラクチャを提供し、Delegate ( tensorflow-lite-gpu ) は互換性リストを提供します。

  2. Android Studio で、 [ファイル] > [プロジェクトを Gradle ファイルと同期]を選択して、プロジェクトの依存関係を同期します。

ML モデルを初期化する

Android アプリでは、モデルで予測を実行する前に、パラメーターを使用して TensorFlow Lite 機械学習モデルを初期化する必要があります。これらの初期化パラメーターは物体検出モデル全体で一貫しており、予測の最小精度しきい値などの設定を含めることができます。

TensorFlow Lite モデルには、モデル コードを含む.tfliteファイルが含まれており、多くの場合、モデルによって予測されたクラスの名前を含むラベル ファイルが含まれています。オブジェクト検出の場合、クラスは人、犬、猫、車などのオブジェクトです。

この例では、 download_models.gradleで指定されたいくつかのモデルをダウンロードし、 ObjectDetectorHelperクラスがモデルのセレクターを提供します。

val modelName =
  when (currentModel) {
    MODEL_MOBILENETV1 -> "mobilenetv1.tflite"
    MODEL_EFFICIENTDETV0 -> "efficientdet-lite0.tflite"
    MODEL_EFFICIENTDETV1 -> "efficientdet-lite1.tflite"
    MODEL_EFFICIENTDETV2 -> "efficientdet-lite2.tflite"
    else -> "mobilenetv1.tflite"
  }

アプリでモデルを初期化するには:

  1. 開発プロジェクトのsrc/main/assetsディレクトリに.tfliteモデル ファイル ( EfficientDet-Lite0など) を追加します。
  2. モデルのファイル名に静的変数を設定します。サンプル アプリでは、EfficientDet-Lite0 検出モデルを使用するために、 modelName変数をMODEL_EFFICIENTDETV0に設定します。
  3. 予測しきい値、結果セットのサイズ、およびオプションでハードウェア アクセラレーション デリゲートなどのモデルのオプションを設定します。

    val optionsBuilder =
      ObjectDetector.ObjectDetectorOptions.builder()
        .setScoreThreshold(threshold)
        .setMaxResults(maxResults)
    
  4. このオブジェクトの設定を使用して、モデルを含む TensorFlow Lite ObjectDetectorオブジェクトを構築します。

    objectDetector =
      ObjectDetector.createFromFileAndOptions(
        context, modelName, optionsBuilder.build())
    

setupObjectDetector次のモデル パラメーターを設定します。

  • 検出閾値
  • 検出結果の最大数
  • 使用する処理スレッドの数 ( BaseOptions.builder().setNumThreads(numThreads) )
  • 実際のモデル ( modelName )
  • ObjectDetector オブジェクト ( objectDetector )

ハードウェア アクセラレータを構成する

アプリケーションで TensorFlow Lite モデルを初期化するときに、ハードウェア アクセラレーション機能を使用してモデルの予測計算を高速化できます。

TensorFlow Liteデリゲートは、グラフィックス プロセッシング ユニット (GPU)、テンソル プロセッシング ユニット (TPU)、デジタル シグナル プロセッサ (DSP) など、モバイル デバイス上の特殊な処理ハードウェアを使用して機械学習モデルの実行を高速化するソフトウェア モジュールです。 TensorFlow Lite モデルの実行にはデリゲートを使用することが推奨されますが、必須ではありません。

オブジェクト検出器は、それを使用しているスレッドの現在の設定を使用して初期化されます。メイン スレッドで作成され、バックグラウンド スレッドで使用される検出器で CPU およびNNAPIデリゲートを使用できますが、検出器を初期化したスレッドは GPU デリゲートを使用する必要があります。

デリゲートはObjectDetectionHelper.setupObjectDetector()関数内で設定されます。

when (currentDelegate) {
    DELEGATE_CPU -> {
        // Default
    }
    DELEGATE_GPU -> {
        if (CompatibilityList().isDelegateSupportedOnThisDevice) {
            baseOptionsBuilder.useGpu()
        } else {
            objectDetectorListener?.onError("GPU is not supported on this device")
        }
    }
    DELEGATE_NNAPI -> {
        baseOptionsBuilder.useNnapi()
    }
}

TensorFlow Lite でのハードウェア アクセラレーション デリゲートの使用の詳細については、 「 TensorFlow Lite デリゲート 」を参照してください。

モデルのデータを準備する

Android アプリでは、コードは画像フレームなどの既存のデータをモデルで処理できる Tensor データ形式に変換することで、解釈用のデータをモデルに提供します。モデルに渡す Tensor 内のデータは、モデルのトレーニングに使用されるデータの形式と一致する特定の次元または形状を持っている必要があります。

このコード例で使用されているEfficientDet-Lite0モデルは、ピクセルごとに 3 つのチャネル (赤、青、緑) を持つ 320 x 320 の寸法の画像を表す Tensor を受け入れます。テンソルの各値は 0 ~ 255 の単一バイトです。したがって、新しい画像に対して予測を実行するには、アプリでその画像データをそのサイズと形状の Tensor データ オブジェクトに変換する必要があります。 TensorFlow Lite タスク ライブラリ Vision API がデータ変換を処理します。

アプリはImageAnalysisオブジェクトを使用してカメラから画像を取得します。このオブジェクトは、カメラからのビットマップを使用してdetectObject関数を呼び出します。データは、モデルの画像データ要件を満たすように、 ImageProcessorによって自動的にサイズ変更および回転されます。次に、画像はTensorImageオブジェクトに変換されます。

ML モデルによって処理されるようにカメラ サブシステムからのデータを準備するには:

  1. ImageAnalysisオブジェクトを構築して、必要な形式で画像を抽出します。

    imageAnalyzer =
        ImageAnalysis.Builder()
            .setTargetAspectRatio(AspectRatio.RATIO_4_3)
            .setTargetRotation(fragmentCameraBinding.viewFinder.display.rotation)
            .setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST)
            .setOutputImageFormat(OUTPUT_IMAGE_FORMAT_RGBA_8888)
            .build()
            ...
    
  2. アナライザーをカメラ サブシステムに接続し、カメラから受信したデータを含むビットマップ バッファーを作成します。

    .also {
      it.setAnalyzer(cameraExecutor) {
        image -> if (!::bitmapBuffer.isInitialized)
        { bitmapBuffer = Bitmap.createBitmap( image.width, image.height,
        Bitmap.Config.ARGB_8888 ) } detectObjects(image)
        }
      }
    
  3. モデルに必要な特定の画像データを抽出し、画像の回転情報を渡します。

    private fun detectObjects(image: ImageProxy) {
      //Copy out RGB bits to the shared bitmap buffer
      image.use {bitmapBuffer.copyPixelsFromBuffer(image.planes[0].buffer) }
        val imageRotation = image.imageInfo.rotationDegrees
        objectDetectorHelper.detect(bitmapBuffer, imageRotation)
      }
    
  4. サンプル アプリのObjectDetectorHelper.detect()メソッドに示すように、最終的なデータ変換を完了し、画像データをTensorImageオブジェクトに追加します。

    val imageProcessor = ImageProcessor.Builder().add(Rot90Op(-imageRotation / 90)).build()
    // Preprocess the image and convert it into a TensorImage for detection.
    val tensorImage = imageProcessor.process(TensorImage.fromBitmap(image))
    

予測を実行する

Android アプリで、正しい形式の画像データを含む TensorImage オブジェクトを作成したら、そのデータに対してモデルを実行して、予測または推論を生成できます。

サンプル アプリのfragments/CameraFragment.ktクラスでは、アプリがカメラに接続されているときに、 bindCameraUseCases関数内のimageAnalyzerオブジェクトが予測用のモデルにデータを自動的に渡します。

アプリは、 cameraProvider.bindToLifecycle()メソッドを使用して、カメラ セレクター、プレビュー ウィンドウ、および ML モデルの処理を処理します。 ObjectDetectorHelper.ktクラスは、画像データをモデルに渡す処理を処理します。モデルを実行して画像データから予測を生成するには:

  • 画像データを予測関数に渡して予測を実行します。

    val results = objectDetector?.detect(tensorImage)
    

TensorFlow Lite インタープリター オブジェクトはこのデータを受け取り、モデルに対して実行し、予測のリストを生成します。モデルによるデータの継続的な処理には、 runForMultipleInputsOutputs()メソッドを使用して、Interpreter オブジェクトが予測実行ごとにシステムによって作成され、削除されないようにしてください。

モデル出力を処理します

Android アプリでは、オブジェクト検出モデルに対して画像データを実行した後、追加のビジネス ロジックの実行、ユーザーへの結果の表示、またはその他のアクションの実行によってアプリ コードが処理する必要がある予測のリストが生成されます。

特定の TensorFlow Lite モデルの出力は、生成される予測の数 (1 つまたは複数)、および各予測の説明情報によって異なります。物体検出モデルの場合、予測には通常、画像内で物体が検出される場所を示す境界ボックスのデータが含まれます。コード例では、結果はCameraFragment.ktonResults関数に渡され、オブジェクト検出プロセスで DetectorListener として機能します。

interface DetectorListener {
  fun onError(error: String)
  fun onResults(
    results: MutableList<Detection>?,
    inferenceTime: Long,
    imageHeight: Int,
    imageWidth: Int
  )
}

この例で使用されるモデルの場合、各予測には、オブジェクトの境界ボックスの位置、オブジェクトのラベル、および予測の信頼度を表す浮動小数点数として 0 から 1 までの予測スコアが含まれます (1 が最も高い信頼度評価です)。 。一般に、スコアが 50% (0.5) を下回る予測は決定的ではないと考えられます。ただし、値の低い予測結果をどのように処理するかは、アプリケーションのニーズとユーザー次第です。

モデルの予測結果を処理するには:

  1. リスナー パターンを使用して、結果をアプリ コードまたはユーザー インターフェイス オブジェクトに渡します。サンプル アプリは、このパターンを使用して、検出結果をObjectDetectorHelperオブジェクトからCameraFragmentオブジェクトに渡します。

    objectDetectorListener.onResults(
    // instance of CameraFragment
        results,
        inferenceTime,
        tensorImage.height,
        tensorImage.width)
    
  2. ユーザーに予測を表示するなど、結果に基づいて行動します。この例では、CameraPreview オブジェクトにオーバーレイを描画して結果を表示します。

    override fun onResults(
      results: MutableList<Detection>?,
      inferenceTime: Long,
      imageHeight: Int,
      imageWidth: Int
    ) {
        activity?.runOnUiThread {
            fragmentCameraBinding.bottomSheetLayout.inferenceTimeVal.text =
                String.format("%d ms", inferenceTime)
    
            // Pass necessary information to OverlayView for drawing on the canvas
            fragmentCameraBinding.overlay.setResults(
                results ?: LinkedList<Detection>(),
                imageHeight,
                imageWidth
            )
    
            // Force a redraw
            fragmentCameraBinding.overlay.invalidate()
        }
    }
    

モデルが予測結果を返したら、アプリケーションはユーザーに結果を提示するか、追加のロジックを実行することで、その予測に基づいて動作できます。コード例の場合、アプリケーションは識別されたオブジェクトの周囲に境界ボックスを描画し、画面上にクラス名を表示します。

次のステップ

  • で TensorFlow Lite のさまざまな使用法を調べてください。
  • TensorFlow Lite での機械学習モデルの使用について詳しくは、 「モデル」セクションをご覧ください。
  • モバイル アプリケーションでの機械学習の実装について詳しくは、 「TensorFlow Lite 開発者ガイド」をご覧ください。