画像解析

画像解析ユースケースは、CPU からアクセスできる画像をアプリに提供し、それらの画像に対して画像処理、コンピュータ ビジョン、機械学習推論を実行できるようにします。アプリには、各フレームで実行する analyze() メソッドを実装します。

実装

画像を処理するには、画像解析が行われるエグゼキュータと ImageAnalysis.Analyzer パラメータを setAnalyzer() メソッドに渡します。登録できるアナライザは常に 1 つのみです。新しいアナライザを登録すると、既存のアナライザが置き換えられます。

このトピックのコードサンプルは、これを行う方法に加えて、画像解析ユースケースとプレビュー ユースケースを LifecycleOwner にバインドする方法を示しています。プレビュー ユースケースの作成方法については、プレビューを実装するをご覧ください。

画像解析は、ブロッキング モードと非ブロッキング モードの 2 つのモードで動作します。ブロッキング モードを有効にするには、STRATEGY_BLOCK_PRODUCERsetBackpressureStrategy() を呼び出します。このモードでは、エグゼキュータはカメラから逐次的にフレームを受け取ります。つまり、analyze() メソッドの処理に現在のフレームレートでの 1 フレームのレイテンシより長い時間がかかる場合、メソッドが結果を返すまで新しいフレームのパイプラインへの入力がブロックされるので、フレームが最新でなくなる可能性があります。

非ブロッキング モードを有効にするには、STRATEGY_KEEP_ONLY_LATESTsetBackpressureStrategy() を呼び出します。 このモードでは、エグゼキュータは、カメラから analyze() メソッドが呼び出された時点における最新の使用可能なフレームを受け取ります。メソッドの処理に現在のフレームレートでの 1 フレームのレイテンシより長い時間がかかる場合、一部のフレームをスキップすることにより、analyze() は次にデータを受け取ったときにカメラ パイプラインから最新の使用可能なフレームを取得します。

analyze() から戻る前に、image.close() を呼び出して画像参照を閉じます。これにより、それ以上画像の生成がブロックされる(それによりプレビューが遅くなる)ことを防ぎ、画像がドロップされる可能性を少なくします。メソッドは、解析メソッドの終了後は画像参照を渡さず、解析を完了するかコピーを作成する必要があります。

Kotlin

val imageAnalysis = ImageAnalysis.Builder()
    .setTargetResolution(Size(1280, 720))
    .setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST)
    .setOutputImageFormat(ImageAnalysis.OUTPUT_IMAGE_FORMAT_RGBA_8888)
    .build()

imageAnalysis.setAnalyzer(executor, ImageAnalysis.Analyzer { image ->
    val rotationDegrees = image.imageInfo.rotationDegrees
    // insert your code here.
})

cameraProvider.bindToLifecycle(this as LifecycleOwner, cameraSelector, imageAnalysis, preview)

Java

ImageAnalysis imageAnalysis =
    new ImageAnalysis.Builder()
        .setTargetResolution(new Size(1280, 720))
        .setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST)
        .setOutputImageFormat(ImageAnalysis.OUTPUT_IMAGE_FORMAT_RGBA_8888)
        .build();

imageAnalysis.setAnalyzer(executor, new ImageAnalysis.Analyzer() {
    @Override
    public void analyze(@NonNull ImageProxy image) {
        int rotationDegrees = image.getImageInfo().getRotationDegrees();
            // insert your code here.
        }
    });

cameraProvider.bindToLifecycle((LifecycleOwner) this, cameraSelector, imageAnalysis, preview);

デフォルトでは、CameraX は画像を OUTPUT_IMAGE_FORMAT_YUV_420_888 形式で設定します。

アプリは ImageProxy::getFormat() 関数を使用して、CameraX から渡された ImageProxy の色空間を確認できます。ImageFormat.YUV_420_888 が返された場合、画像は YUV 色空間です。PixelFormat.RGBA_8888 が返された場合、画像は RGBA 色空間です。

YUV 出力形式は、すべての camera-core バージョンで使用できます。RGBA 出力形式は、camera-core:1.1.0-alpha09 以降のバージョンで、画像解析ユースケースでのみ利用できます。

RGBA 出力形式を設定すると、CameraX は内部で画像を YUV 色空間から RGBA 色空間に変換し、ImageProxy の最初のプレーン(他のプレーンは不使用)の ByteBuffer に、次の順序で画像ビットを格納します。

ImageProxy::planes[0].buffer[0]: alpha
ImageProxy::planes[1].buffer[1]: red
ImageProxy::planes[2].buffer[2]: green
ImageProxy::planes[3].buffer[3]: blue
...

色変換は YUV 出力形式のアドオン ステップであり、変換時間は画像分析時間全体の一部です。アプリでリアルタイム解析を行うとき、フレームごとの処理時間が短縮されます。アプリで RGBA 出力が必要な場合に使用します。

参考情報

CameraX について詳しくは、以下の参考情報をご確認ください。

Codelab

  • CameraX のスタートガイド
  • コードサンプル

  • CameraX の公式サンプルアプリ