1. はじめに
MediaPipe とは何ですか?
MediaPipe Solutions を使用すると、アプリに機械学習(ML)ソリューションを適用できます。このソリューションが提供するフレームワークでは、事前構築の処理パイプラインを構成して、ユーザーに有益で魅力のある出力を迅速に配信できます。これらのソリューションの多くは、MediaPipe Model Maker でカスタマイズして、デフォルトのモデルを更新することもできます。
テキストから画像を生成する ML タスクは、MediaPipe Solutions が提供する数々の ML タスクの一つです。
この Codelab では、ほとんど空の Android アプリから始め、Android デバイスで直接新しい画像を生成できるようになるまで、複数のステップを進めていきます。
学習内容
- MediaPipe Tasks を使用して、Android アプリでローカルに実行されるテキストから画像への生成を実装する方法。
必要なもの
- インストール済みの Android Studio のバージョン(この Codelab は Android Studio Giraffe で作成、テストされています)。
- 8 GB 以上の RAM を搭載した Android デバイス。
- Android 開発に関する基本的な知識と、事前に作成された Python スクリプトを実行する能力。
2. Android アプリに MediaPipe Tasks を追加する
Android スターター アプリをダウンロードする
この Codelab では、基本的なバージョンの画像生成に使用する UI で構成された、事前作成されたサンプルから始めます。開始アプリは、公式の MediaPipe サンプル リポジトリ(こちら)にあります。[Code] > [Download ZIP] をクリックして、リポジトリのクローンを作成するか、zip ファイルをダウンロードします。
アプリを Android Studio にインポートする
- Android Studio を開きます。
- [Welcome to Android Studio] 画面で、右上の [Open] を選択します。
- リポジトリのクローンを作成またはダウンロードした場所に移動し、codelabs/image_generation_basic/android/start ディレクトリを開きます。
- この段階では、MediaPipe Tasks の依存関係はまだ含まれていないため、アプリはコンパイルされません。
アプリを修正して実行するには、build.gradle ファイルに移動し、// ステップ 1 - 依存関係を追加までスクロールします。そこから、次の行を追加し、Android Studio の上部にあるバナーに表示される [Sync Now] ボタンをクリックします。
// Step 1 - Add dependency
implementation 'com.google.mediapipe:tasks-vision-image-generator:latest.release'
同期が完了したら、Android Studio の右上にある緑色の実行矢印()をクリックして、すべてが正しく開いてインストールされていることを確認します。アプリが開き、2 つのラジオボタンと [初期化] というボタンが表示されます。このボタンをクリックすると、テキスト プロンプトとその他のオプション、[生成] というラベルの付いたボタンを含む別の UI にすぐに移動します。
残念ながら、ここまでがスターターアプリの範囲です。このアプリを完成させて、デバイスで新しい画像を生成する方法を学びましょう。
3. 画像生成ツールの設定
この例では、画像生成の大部分は ImageGenerationHelper.kt ファイルで行われます。このファイルを開くと、クラスの上部に imageGenerator という変数があります。これは、画像生成アプリで重い処理を行う Task オブジェクトです。
そのオブジェクトのすぐ下に、initializeImageGenerator() という関数があり、次のようなコメントが付いています。// ステップ 2 - 画像生成ツールを初期化します。ご想像のとおり、ここで ImageGenerator オブジェクトを初期化します。その関数の本文を次のコードに置き換えて、画像生成モデルのパスを設定し、ImageGenerator オブジェクトを初期化します。
// Step 2 - initialize the image generator
val options = ImageGeneratorOptions.builder()
.setImageGeneratorModelDirectory(modelPath)
.build()
imageGenerator = ImageGenerator.createFromOptions(context, options)
その下には、setInput() という別の関数があります。この関数は、生成された画像の定義に使用されるプロンプト文字列、新しい画像の生成中にタスクが行う反復処理の数、同じシードが使用されている場合に同じ画像を生成しながら、同じプロンプトに基づいて画像の新しいバージョンを作成するために使用できるシード値の 3 つのパラメータを受け取ります。この関数の目的は、中間ステップを表示する画像を作成しようとするときに、画像生成ツールにこれらの初期パラメータを設定することです。
setInput() の本文(// ステップ 3 - 入力を受け入れます というコメントがある部分)を次の行に置き換えます。
// Step 3 - accept inputs
imageGenerator.setInputs(prompt, iteration, seed)
次の 2 つのステップで生成が行われます。generate() 関数は setInput と同じ入力を受け付けますが、中間ステップの画像を返さないワンショット呼び出しとして画像を作成します。この関数の本文(コメント // ステップ 4 - 反復処理を表示せずに生成を含む)は、次のように置き換えることができます。
// Step 4 - generate without showing iterations
val result = imageGenerator.generate(prompt, iteration, seed)
val bitmap = BitmapExtractor.extract(result?.generatedImage())
return bitmap
このタスクは同期的に実行されるため、バックグラウンド スレッドから関数を呼び出す必要があります。これについては、この Codelab の後半で詳しく説明します。
このファイルで行う最後のステップは、execute() 関数に記入することです(ステップ 5 とラベル付けされています)。これは、ImageGenerator execute() 関数で実行される生成の単一ステップで中間画像を返すかどうかを指定するパラメータを受け取ります。関数の本文を次のコードに置き換えます。
// Step 5 - generate with iterations
val result = imageGenerator.execute(showResult)
if (result == null || result.generatedImage() == null) {
return Bitmap.createBitmap(512, 512, Bitmap.Config.ARGB_8888)
.apply {
val canvas = Canvas(this)
val paint = Paint()
paint.color = Color.WHITE
canvas.drawPaint(paint)
}
}
val bitmap =
BitmapExtractor.extract(result.generatedImage())
return bitmap
これでヘルパー ファイルの作成は完了です。次のセクションでは、この例のロジックを処理する ViewModel ファイルを作成します。
4. アプリをまとめる
MainViewModel ファイルは、このサンプルアプリに関連する UI の状態やその他のロジックを処理します。このファイルを開きましょう。
ファイルの上部に、// ステップ 6 - モデルパスを設定するというコメントがあります。ここで、画像生成に必要なモデルファイルをアプリが見つけられる場所を指定します。この例では、値を /data/local/tmp/image_generator/bins/ に設定します。
// Step 6 - set model path
private val MODEL_PATH = "/data/local/tmp/image_generator/bins/"
そこから、generateImage() 関数まで下にスクロールします。この関数の下部には、ステップ 7 とステップ 8 の両方があります。これらは、返された反復処理ありまたはなしで画像を生成するために使用されます。これらのオペレーションはどちらも同期的に行われるため、コルーチンでラップされています。まず、// ステップ 7 - 反復処理を表示せずに生成するを、次のコードブロックに置き換えて、ImageGenerationHelper ファイルから generate() を呼び出し、UI の状態を更新します。
// Step 7 - Generate without showing iterations
val result = helper?.generate(prompt, iteration, seed)
_uiState.update {
it.copy(outputBitmap = result)
}
ステップ 8 は少し複雑です。execute() 関数は、画像生成のすべてのステップではなく、1 つのステップのみを実行するため、ループで各ステップを個別に呼び出す必要があります。また、現在のステップをユーザーに表示するかどうかも判断する必要があります。最後に、現在の反復処理を表示する必要がある場合は UI の状態を更新します。これらの操作はすべて今すぐ行えます。
// Step 8 - Generate with showing iterations
helper?.setInput(prompt, iteration, seed)
for (step in 0 until iteration) {
isDisplayStep =
(displayIteration > 0 && ((step + 1) % displayIteration == 0))
val result = helper?.execute(isDisplayStep)
if (isDisplayStep) {
_uiState.update {
it.copy(
outputBitmap = result,
generatingMessage = "Generating... (${step + 1}/$iteration)",
)
}
}
}
この時点で、アプリをインストールし、画像生成ツールを初期化して、テキスト プロンプトに基づいて新しい画像を作成できるはずです。
ただし、画像生成ツールを初期化しようとするとアプリがクラッシュします。これは、モデルファイルをデバイスにコピーする必要があるためです。動作が確認されているサードパーティ モデル、この MediaPipe タスク用にモデルを変換する方法、デバイスにモデルをコピーする方法については、公式ドキュメントのこのセクションをご覧ください。
ファイルを開発デバイスに直接コピーするだけでなく、必要なファイルを実行時にユーザーのデバイスに直接ダウンロードするように Firebase Storage を設定することもできます。
5. アプリをデプロイしてテストする
ここまでの手順を完了すると、テキスト プロンプトを受け取って、完全にオンデバイスで新しい画像を生成するアプリが完成します。アプリを物理的な Android デバイスにデプロイしてテストします。ただし、メモリが 8 GB 以上のデバイスでテストすることをおすすめします。
- Android Studio のツールバーで実行アイコン(
)をクリックして、アプリを実行します。
- 生成ステップのタイプ(最終ステップまたは反復あり)を選択し、[初期化] ボタンを押します。
- 次の画面で必要なプロパティを設定し、[生成] ボタンをクリックしてツールが生成した結果を確認します。
6. 完了
やりました!この Codelab では、デバイス上のテキストから画像の生成を Android アプリに追加する方法について学習しました。
次のステップ
画像生成タスクでは、次のようなこともできます。
- ベース画像を使用して生成された画像をプラグインで構造化したり、Vertex AI で独自の追加 LoRA 重みをトレーニングしたりできます。
- Firebase Storage を使用して、ADB ツールを使用せずにデバイス上のモデルファイルを取得します。
この試験運用版タスクで作成されるクールな作品を楽しみにしています。MediaPipe チームの今後の Codelab とコンテンツにもご注目ください。