Android 向け画像埋め込みガイド

MediaPipe Image Embedder タスクを使用すると、画像データを数値表現に変換して、2 つの画像の類似度の比較などの ML 関連の画像処理タスクを実行できます。ここでは、Android アプリで画像埋め込みを使用する方法について説明します。

このタスクの機能、モデル、構成オプションの詳細については、概要をご覧ください。

サンプルコード

MediaPipe Tasks のサンプルコードは、Android 用 Image Embedder アプリの簡単な実装です。この例では、物理 Android デバイスのカメラを使用して、画像を継続的に埋め込みます。また、デバイスに保存されている画像ファイルに対してエンベダーを実行することもできます。

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

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

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

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

  1. 次のコマンドを使用して、git リポジトリのクローンを作成します。
    git clone https://github.com/google-ai-edge/mediapipe-samples
    
  2. 必要に応じて、スパース チェックアウトを使用するように Git インスタンスを構成し、Image Embedder サンプルアプリのファイルのみが含まれるようにします。
    cd mediapipe
    git sparse-checkout init --cone
    git sparse-checkout set examples/image_embedder/android
    

サンプルコードのローカル バージョンを作成したら、Android Studio にプロジェクトをインポートしてアプリを実行できます。手順については、Android の設定ガイドをご覧ください。

主要コンポーネント

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

  • ImageEmbedderHelper.kt: 画像埋め込みを初期化し、モデルを処理して選択を委任します。
  • MainActivity.kt: アプリを実装し、ユーザー インターフェース コンポーネントを組み立てます。

セットアップ

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

依存関係

画像埋め込みは、com.google.mediapipe:tasks-vision ライブラリを使用します。この依存関係を Android アプリ開発プロジェクトの build.gradle ファイルに追加します。以下のコードを使用して、必要な依存関係をインポートします。

dependencies {
    ...
    implementation 'com.google.mediapipe:tasks-vision:latest.release'
}

モデル

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

モデルを選択してダウンロードし、プロジェクト ディレクトリに保存します。

<dev-project-root>/src/main/assets

ModelAssetPath パラメータ内にモデルのパスを指定します。このサンプルコードでは、ImageEmbedderHelper.kt ファイルの setupImageEmbedder() 関数でモデルが定義されています。

BaseOptions.Builder.setModelAssetPath() メソッドを使用して、モデルで使用するパスを指定します。このメソッドは、次のセクションのコードサンプルで参照しています。

タスクを作成する

createFromOptions 関数を使用してタスクを作成できます。createFromOptions 関数は、埋め込みオプションを設定する構成オプションを受け入れます。構成オプションの詳細については、構成の概要をご覧ください。

画像埋め込みタスクは、静止画像、動画ファイル、ライブ動画ストリームの 3 つの入力データ型をサポートしています。タスクの作成時に、入力データ型に対応する実行モードを指定する必要があります。入力データ型に対応するタブを選択して、タスクを作成して推論を実行する方法をご覧ください。

画像

ImageEmbedderOptions options =
  ImageEmbedderOptions.builder()
    .setBaseOptions(
      BaseOptions.builder().setModelAssetPath("model.tflite").build())
    .setQuantize(true)
    .setRunningMode(RunningMode.IMAGE)
    .build();
imageEmbedder = ImageEmbedder.createFromOptions(context, options);
    

動画

ImageEmbedderOptions options =
  ImageEmbedderOptions.builder()
    .setBaseOptions(
      BaseOptions.builder().setModelAssetPath("model.tflite").build())
    .setQuantize(true)
    .setRunningMode(RunningMode.VIDEO)
    .build();
imageEmbedder = ImageEmbedder.createFromOptions(context, options);
    

ライブ配信

ImageEmbedderOptions options =
  ImageEmbedderOptions.builder()
    .setBaseOptions(
      BaseOptions.builder().setModelAssetPath("model.tflite").build())
    .setQuantize(true)
    .setRunningMode(RunningMode.LIVE_STREAM)
    .setResultListener((result, inputImage) -> {
         // Process the embedding result here.
    })
    .build();
imageEmbedder = ImageEmbedder.createFromOptions(context, options);
    

サンプルコードの実装では、ユーザーが処理モードを切り替えることができます。このアプローチでは、タスク作成コードが複雑になり、実際のユースケースに適さない場合があります。このコードは、ImageEmbedderHelper.kt ファイルの setupImageEmbedder() 関数で確認できます。

構成オプション

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

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

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

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

LIVE_STREAM: カメラからのデータなど、入力データのライブストリームのモード。このモードでは、resultListener を呼び出して、結果を非同期で受け取るリスナーをセットアップする必要があります。
{IMAGE, VIDEO, LIVE_STREAM} IMAGE
l2_normalize 返された特徴ベクトルを L2 ノルムで正規化するかどうか。このオプションは、モデルにネイティブの L2_NORMALIZATION TFLite Op がまだ含まれていない場合にのみ使用してください。ほとんどの場合、これはすでに当てはまるため、L2 正規化は TFLite 推論によって行われるため、このオプションは必要ありません。 Boolean False
quantize 返されたエンベディングを、スカラー量子化によってバイトに量子化するかどうかを指定します。エンベディングは暗黙的に単位ノルムであると想定されるため、どのディメンションも [-1.0, 1.0] の値を持つことが保証されます。そうでない場合は、l2_normalize オプションを使用します。 Boolean False
resultListener Image Embedder がライブ ストリーム モードのときに埋め込み結果を非同期で受け取るように結果リスナーを設定します。実行モードが LIVE_STREAM に設定されている場合にのみ使用できます なし 未設定
errorListener オプションのエラーリスナーを設定します。 なし 未設定

データの準備

画像埋め込みは、画像、動画ファイル、ライブ配信動画に対して機能します。このタスクは、サイズ変更、回転、値の正規化などのデータ入力の前処理を処理します。

入力の画像またはフレームを com.google.mediapipe.framework.image.MPImage オブジェクトに変換してから、画像埋め込みタスクに渡す必要があります。

画像

import com.google.mediapipe.framework.image.BitmapImageBuilder;
import com.google.mediapipe.framework.image.MPImage;

// Load an image on the user’s device as a Bitmap object using BitmapFactory.

// Convert an Android’s Bitmap object to a MediaPipe’s Image object.
Image mpImage = new BitmapImageBuilder(bitmap).build();
    

動画

import com.google.mediapipe.framework.image.BitmapImageBuilder;
import com.google.mediapipe.framework.image.MPImage;

// Load a video file on the user's device using MediaMetadataRetriever

// From the video’s metadata, load the METADATA_KEY_DURATION and
// METADATA_KEY_VIDEO_FRAME_COUNT value. You’ll need them
// to calculate the timestamp of each frame later.

// Loop through the video and load each frame as a Bitmap object.

// Convert the Android’s Bitmap object to a MediaPipe’s Image object.
Image mpImage = new BitmapImageBuilder(frame).build();
    

ライブ配信

import com.google.mediapipe.framework.image.MediaImageBuilder;
import com.google.mediapipe.framework.image.MPImage;

// Create a CameraX’s ImageAnalysis to continuously receive frames
// from the device’s camera. Configure it to output frames in RGBA_8888
// format to match with what is required by the model.

// For each Android’s ImageProxy object received from the ImageAnalysis,
// extract the encapsulated Android’s Image object and convert it to
// a MediaPipe’s Image object.
android.media.Image mediaImage = imageProxy.getImage()
Image mpImage = new MediaImageBuilder(mediaImage).build();
    

このサンプルコードでは、データの準備は ImageEmbedderHelper.kt ファイルで処理されます。

タスクを実行する

実行モードに対応する embed 関数を呼び出して、推論をトリガーできます。Image Embedder API は、入力画像またはフレームのエンベディング ベクトルを返します。

画像

ImageEmbedderResult embedderResult = imageEmbedder.embed(image);
    

動画

// Calculate the timestamp in milliseconds of the current frame.
long frame_timestamp_ms = 1000 * video_duration * frame_index / frame_count;

// Run inference on the frame.
ImageEmbedderResult embedderResult =
    imageEmbedder.embedForVideo(image, frameTimestampMs);
    

ライブ配信


// Run inference on the frame. The embedding results will be available
// via the `resultListener` provided in the `ImageEmbedderOptions` when
// the image embedder was created.
imageEmbedder.embedAsync(image, frameTimestampMs);
    

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

  • 動画モードまたはライブ ストリーム モードで実行する場合は、入力フレームのタイムスタンプも画像埋め込みタスクに渡す必要があります。
  • 画像モードまたは動画モードで実行されている場合、画像埋め込みタスクは入力画像またはフレームの処理を完了するまで、現在のスレッドをブロックします。現在のスレッドがブロックされないように、処理はバックグラウンド スレッドで実行します。
  • ライブ ストリーム モードで実行されている場合、画像埋め込みタスクは現在のスレッドをブロックせず、すぐに結果を返します。入力フレームの処理が完了するたびに、検出結果とともに結果リスナーを呼び出します。Image Embedder タスクが別のフレームの処理でビジー状態のときに embedAsync 関数が呼び出されると、このタスクは新しい入力フレームを無視します。

このサンプルコードでは、embed 関数が ImageEmbedderHelper.kt ファイルで定義されています。

結果を処理して表示する

推論を実行すると、画像エンベディング タスクは、入力画像のエンベディング(浮動小数点またはスカラー量子化)のリストを含む ImageEmbedderResult オブジェクトを返します。

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

ImageEmbedderResult:
  Embedding #0 (sole embedding head):
    float_embedding: {0.0, 0.0, ..., 0.0, 1.0, 0.0, 0.0, 2.0}
    head_index: 0

この結果は、次の画像を埋め込むことで取得されました。

ImageEmbedder.cosineSimilarity 関数を使用して、2 つのエンベディングの類似性を比較できます。例として、次のコードをご覧ください。

// Compute cosine similarity.
double similarity = ImageEmbedder.cosineSimilarity(
  result.embeddingResult().embeddings().get(0),
  otherResult.embeddingResult().embeddings().get(0));