Leitfaden zum Generieren von Bildern für Android

Mit der Aufgabe „MediaPipe-Bild-Generator“ können Sie Bilder basierend auf einem Text-Prompt generieren. Bei dieser Aufgabe wird ein Text-zu-Bild-Modell verwendet, um Bilder mithilfe von Diffusionstechniken zu generieren.

Die Aufgabe akzeptiert eine Text-Prompts sowie ein optionales Bedingungsbild, das das Modell erweitern und als Referenz für die Generierung verwenden kann. Image Generator kann auch Bilder basierend auf bestimmten Konzepten generieren, die dem Modell während des Trainings oder des erneuten Trainings zur Verfügung gestellt werden. Weitere Informationen findest du unter Mit LoRA anpassen.

Das in dieser Anleitung beschriebene Codebeispiel ist auf GitHub verfügbar. Weitere Informationen zu den Funktionen, Modellen und Konfigurationsoptionen dieser Aufgabe finden Sie in der Übersicht.

Codebeispiel

Der Beispielcode von MediaPipe Tasks ist eine grundlegende Implementierung einer Image Generator-App für Android. Sie können die App als Ausgangspunkt für Ihre eigene Android-App verwenden oder beim Ändern einer vorhandenen App darauf zurückgreifen. Der Beispielcode für den Image-Generator wird auf GitHub gehostet.

Code herunterladen

In der folgenden Anleitung erfahren Sie, wie Sie mit dem git-Befehlszeilentool eine lokale Kopie des Beispielcodes erstellen.

So laden Sie den Beispielcode herunter:

  1. Klonen Sie das Git-Repository mit dem folgenden Befehl:
    git clone https://github.com/google-ai-edge/mediapipe-samples
    
  2. Konfigurieren Sie optional Ihre Git-Instanz für die Verwendung von Sparse Checkout, sodass Sie nur die Dateien für die Beispiel-App „Image Generator“ haben:
    cd mediapipe
    git sparse-checkout init --cone
    git sparse-checkout set examples/image_generator/android
    

Nachdem Sie eine lokale Version des Beispielcodes erstellt haben, können Sie das Projekt in Android Studio importieren und die App ausführen. Eine Anleitung finden Sie im Einrichtungsleitfaden für Android.

Schlüsselkomponenten

Die folgenden Dateien enthalten den wichtigen Code für diese Beispielanwendung zur Bildgenerierung:

  • ImageGenerationHelper.kt: Initialisiert die Aufgabe und übernimmt die Bildgenerierung.
  • DiffusionActivity.kt: Generiert Bilder, wenn Plug-ins oder LoRA-Gewichtungen nicht aktiviert sind.
  • PluginActivity.kt: Implementiert die Plug-in-Modelle, mit denen Nutzer ein Zustandsbild als Eingabe angeben können.
  • LoRAWeightActivity.kt: Ruft die LoRA-Gewichtungen auf und verarbeitet sie. Damit werden Foundation Models angepasst und Bilder bestimmter Konzepte generiert.

Einrichtung

In diesem Abschnitt werden die wichtigsten Schritte zum Einrichten Ihrer Entwicklungsumgebung und Codeprojekte speziell für die Verwendung von Image Generator beschrieben. Allgemeine Informationen zum Einrichten der Entwicklungsumgebung für die Verwendung von MediaPipe-Aufgaben, einschließlich der Anforderungen an die Plattformversion, finden Sie im Einrichtungsleitfaden für Android.

Abhängigkeiten

Die Image Generator-Aufgabe verwendet die com.google.mediapipe:tasks-vision-image-generator-Bibliothek. Fügen Sie diese Abhängigkeit in die Datei build.gradle Ihrer Android-App ein:

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

Fügen Sie für Geräte mit Android 12 (API 31) oder höher die native OpenCL-Bibliotheksabhängigkeit zu AndroidManifest.xml hinzu. Weitere Informationen finden Sie in der Dokumentation zum uses-native-library-Tag.

Für einige Android-Geräte sind möglicherweise auch zusätzliche Bibliotheken erforderlich:

<uses-native-library android:name="libOpenCL.so" android:required="false" />
<uses-native-library android:name="libOpenCL-car.so" android:required="false"/>
<uses-native-library android:name="libOpenCL-pixel.so" android:required="false" />

Modell

Die Aufgabe „MediaPipe Image Generator“ erfordert ein trainiertes Foundation Model, das mit dieser Aufgabe kompatibel ist. Installieren Sie nach dem Herunterladen eines Modells die erforderlichen Abhängigkeiten und konvertieren Sie das Modell in ein geeignetes Format. Übertragen Sie das konvertierte Modell dann auf das Android-Gerät.

Weitere Informationen zu verfügbaren trainierten Modellen für Image Generator finden Sie in der Aufgabenübersicht im Abschnitt „Modelle“.

Basismodell herunterladen

Für den Image Generator muss das Foundation Model dem Modellformat runwayml/stable-diffusion-v1-5 EMA-only entsprechen. Dies basiert auf dem folgenden Modell: runwayml/stable-diffusion-v1-5.

Abhängigkeiten installieren und Modell konvertieren

$ pip install torch typing_extensions numpy Pillow requests pytorch_lightning absl-py

Führen Sie das convert.py-Skript aus:

$ python3 convert.py --ckpt_path <ckpt_path> --output_path <output_path>

Konvertiertes Modell auf das Gerät übertragen

Übertragen Sie den Inhalt des Ordners <output_path> auf das Android-Gerät.

$ adb shell rm -r /data/local/tmp/image_generator/ # Remove any previously loaded weights
$ adb shell mkdir -p /data/local/tmp/image_generator/
$ adb push <output_path>/. /data/local/tmp/image_generator/bins

Plug-in-Modelle herunterladen und LoRA-Gewichtungen hinzufügen (optional)

Wenn Sie ein Plug-in-Modell verwenden möchten, prüfen Sie, ob das Modell heruntergeladen werden muss. Bei Plug-ins, die ein zusätzliches Modell erfordern, müssen die Plug-in-Modelle entweder im APK gebündelt oder bei Bedarf heruntergeladen werden. Plug-in-Modelle sind unkompliziert (ca. 23 MB) und können direkt im APK gebündelt werden. Wir empfehlen jedoch, Plug-in-Modelle on demand herunterzuladen.

Wenn Sie ein Modell mit LoRA angepasst haben, können Sie es bei Bedarf herunterladen. Weitere Informationen finden Sie unter Plug-in-Modell für LoRA-Gewichtungen.

Aufgabe erstellen

Die Aufgabe „MediaPipe Image Generator“ verwendet die Funktion createFromOptions(), um die Aufgabe einzurichten. Die Funktion createFromOptions() akzeptiert Werte für die Konfigurationsoptionen. Weitere Informationen zu Konfigurationsoptionen finden Sie unter Konfigurationsoptionen.

Konfigurationsoptionen

Diese Aufgabe umfasst die folgenden Konfigurationsoptionen für Android-Apps:

Option Beschreibung Wertebereich
imageGeneratorModelDirectory Im Modellverzeichnis des Bildgenerators, in dem die Modellgewichtungen gespeichert sind PATH
loraWeightsFilePath Legt den Pfad zur LoRA-Gewichtungsdatei fest. Optional und nur anwendbar, wenn das Modell mit LoRA angepasst wurde. PATH
errorListener Legt einen optionalen Fehler-Listener fest. N/A

Die Aufgabe unterstützt auch Plug-in-Modelle, mit denen Nutzer Bedingungsbilder in die Aufgabeneingabe einfügen können, die das Foundation Model erweitern und als Referenz für die Generierung verwenden kann. Diese Zustandsbilder können Gesichtsmerkmale, Kantenumrisse und Tiefenschätzungen sein, die das Modell als zusätzlichen Kontext und als zusätzliche Informationen zum Generieren von Bildern verwendet.

Wenn Sie dem Foundation Model ein Plug-in-Modell hinzufügen, müssen Sie auch die Plug-in-Optionen konfigurieren. Für das Plug-in für Gesichtermarkierungen wird faceConditionOptions verwendet, für das Canny-Edge-Plug-in edgeConditionOptions und für das Tiefen-Plug-in depthConditionOptions.

Canny Edge-Optionen

Konfigurieren Sie die folgenden Optionen in edgeConditionOptions.

Option Beschreibung Wertebereich Standardwert
threshold1 Erster Schwellenwert für das Hystereseverfahren. Float 100
threshold2 Zweiter Schwellenwert für das Hystereseverfahren. Float 200
apertureSize Blende für den Sobel-Operator Der typische Bereich liegt zwischen 3 und 7. Integer 3
l2Gradient Gibt an, ob die L2-Norm verwendet wird, um die Größe des Farbverlaufs zu berechnen, und nicht die Standard-L1-Norm. BOOLEAN False
EdgePluginModelBaseOptions Das BaseOptions-Objekt, das den Pfad für das Plug-in-Modell festlegt. BaseOptions Objekt N/A

Weitere Informationen zu diesen Konfigurationsoptionen finden Sie unter Canny Edge Detector.

Optionen für Gesichtsmarkierungen

Konfigurieren Sie die folgenden Optionen in faceConditionOptions.

Option Beschreibung Wertebereich Standardwert
minFaceDetectionConfidence Der minimale Konfidenzwert, damit die Gesichtserkennung als erfolgreich gilt. Float [0.0,1.0] 0.5
minFacePresenceConfidence Der minimale Konfidenzwert für die Gesichtserkennung bei der Erkennung von Sehenswürdigkeiten. Float [0.0,1.0] 0.5
faceModelBaseOptions Das BaseOptions-Objekt, das den Pfad für das Modell festlegt, das das Bedingungsbild erstellt. BaseOptions Objekt N/A
FacePluginModelBaseOptions Das BaseOptions-Objekt, das den Pfad für das Plug-in-Modell festlegt. BaseOptions Objekt N/A

Weitere Informationen zur Funktionsweise dieser Konfigurationsoptionen finden Sie unter Gesichtererkennung.

Tiefenoptionen

Konfigurieren Sie die folgenden Optionen in depthConditionOptions.

Option Beschreibung Wertebereich Standardwert
depthModelBaseOptions Das BaseOptions-Objekt, das den Pfad für das Modell festlegt, das das Bedingungsbild erstellt. BaseOptions Objekt N/A
depthPluginModelBaseOptions Das BaseOptions-Objekt, das den Pfad für das Plug-in-Modell festlegt. BaseOptions Objekt N/A

Nur mit dem Foundation Model erstellen

val options = ImageGeneratorOptions.builder()
    .setImageGeneratorModelDirectory(modelPath)
    .build()

imageGenerator = ImageGenerator.createFromOptions(context, options)

Mit Plug-ins erstellen

Wenn Sie ein optionales Plug-in-Modell anwenden, legen Sie die Basisoptionen für das Plug-in-Modell mit setPluginModelBaseOptions fest. Wenn für das Plug-in-Modell ein zusätzliches heruntergeladenes Modell zum Erstellen des Bedingungsbilds erforderlich ist, geben Sie den Pfad in BaseOptions an.

Gesichts-Markierung

val options = ImageGeneratorOptions.builder()
    .setImageGeneratorModelDirectory(modelPath)
    .build()

val faceModelBaseOptions = BaseOptions.builder()
    .setModelAssetPath("face_landmarker.task")
    .build()

val facePluginModelBaseOptions = BaseOptions.builder()
    .setModelAssetPath("face_landmark_plugin.tflite")
    .build()

val faceConditionOptions = FaceConditionOptions.builder()
    .setFaceModelBaseOptions(faceModelBaseOptions)
    .setPluginModelBaseOptions(facePluginModelBaseOptions)
    .setMinFaceDetectionConfidence(0.3f)
    .setMinFacePresenceConfidence(0.3f)
    .build()

val conditionOptions = ConditionOptions.builder()
    .setFaceConditionOptions(faceConditionOptions)
    .build()

imageGenerator =
    ImageGenerator.createFromOptions(context, options, conditionOptions)
    

Canny Kante

val options = ImageGeneratorOptions.builder()
    .setImageGeneratorModelDirectory(modelPath)
    .build()

val edgePluginModelBaseOptions = BaseOptions.builder()
    .setModelAssetPath("canny_edge_plugin.tflite")
    .build()

val edgeConditionOptions = EdgeConditionOptions.builder()
    .setThreshold1(100.0f)
    .setThreshold2(100.0f)
    .setApertureSize(3)
    .setL2Gradient(false)
    .setPluginModelBaseOptions(edgePluginModelBaseOptions)
    .build()

val conditionOptions = ConditionOptions.builder()
    .setEdgeConditionOptions(edgeConditionOptions)
    .build()

imageGenerator =
    ImageGenerator.createFromOptions(context, options, conditionOptions)
    

Tiefe

val options = ImageGeneratorOptions.builder()
    .setImageGeneratorModelDirectory(modelPath)
    .build()

val depthModelBaseOptions = BaseOptions.builder()
    .setModelAssetPath("depth_model.tflite")
    .build()

val depthPluginModelBaseOptions = BaseOptions.builder()
    .setModelAssetPath("depth_plugin.tflite")
    .build()

val depthConditionOptions =
    ConditionOptions.DepthConditionOptions.builder()
        .setDepthModelBaseOptions(depthModelBaseOptions)
        .setPluginModelBaseOptions(depthPluginModelBaseOptions)
        .build()

val conditionOptions = ConditionOptions.builder()
    .setDepthConditionOptions(depthConditionOptions)
    .build()

imageGenerator =
    ImageGenerator.createFromOptions(context, options, conditionOptions)
    

Mit LoRA-Gewichtungen erstellen

Wenn Sie LoRA-Gewichtungen einschließen, verweisen Sie mit dem Parameter loraWeightsFilePath auf die Pfadposition.

val options = ImageGeneratorOptions.builder()
    .setLoraWeightsFilePath(weightsPath)
    .setImageGeneratorModelDirectory(modelPath)
    .build()

imageGenerator = ImageGenerator.createFromOptions(context, options)

Daten vorbereiten

Der Image Generator akzeptiert die folgenden Eingaben:

  • prompt (erforderlich): der Text-Prompt, der das zu generierende Bild beschreibt.
  • iterations (erforderlich): Die Gesamtzahl der Iterationen zur Bildgenerierung. Ein guter Ausgangspunkt ist 20.
  • seed (erforderlich): Der bei der Bildgenerierung verwendete zufällig ausgewählte Seed-Wert.
  • condition image (optional): Das Bild, das das Modell als Referenz zur Generierung verwendet. Gilt nur bei Verwendung eines Plug-in-Modells.
  • condition type (optional): Der Typ des Plug-in-Modells, das für die Aufgabe verwendet wird. Gilt nur bei Verwendung eines Plug-in-Modells.

Eingaben nur mit dem Foundation Model

fun setInput(prompt: String, iteration: Int, seed: Int) {
    imageGenerator.setInputs(prompt, iteration, seed)
}

Eingaben mit Plug-ins

Wenn Sie ein optionales Plug-in-Modell anwenden, verwenden Sie auch den Parameter conditionType, um das Plug-in-Modell auszuwählen, und den Parameter sourceConditionImage, um das Bedingungsbild zu generieren.

Option Beschreibung Wert
conditionType Das auf das Foundation Model angewendete Plug-in-Modell. {"FACE", "EDGE", "DEPTH"}
sourceConditionImage Das Quellbild, das zum Erstellen des Zustandsbilds verwendet wurde. MPImage Objekt

Wenn Sie ein Plug-in-Modell verwenden, nutzen Sie createConditionImage, um das Bedingungsbild zu erstellen:

fun createConditionImage(
    inputImage: MPImage,
    conditionType: ConditionType
): Bitmap {
    val result =
        imageGenerator.createConditionImage(inputImage, conditionType)
    return BitmapExtractor.extract(result)
}

Nachdem Sie das Bedingungsbild erstellt haben, fügen Sie es zusammen mit dem Prompt, dem Seed und der Anzahl der Iterationen als Eingabe ein.

imageGenerator.setInputs(
    prompt,
    conditionalImage,
    conditionType,
    iteration,
    seed
)

Eingaben mit LoRA-Gewichtungen

Wenn Sie LoRA-Gewichtungen verwenden, muss sich das Token in der Text-Eingabeaufforderung befinden, wenn Sie ein Bild mit dem spezifischen Konzept generieren möchten, das durch die Gewichtungen dargestellt wird.

fun setInput(prompt: String, iteration: Int, seed: Int) {
    imageGenerator.setInputs(prompt, iteration, seed)
}

Task ausführen

Verwenden Sie die Methode generate(), um mit den im vorherigen Abschnitt angegebenen Eingaben ein Bild zu generieren. Dadurch wird ein einzelnes Bild generiert.

Nur mit dem Basismodell generieren

fun generate(prompt: String, iteration: Int, seed: Int): Bitmap {
    val result = imageGenerator.generate(prompt, iteration, seed)
    val bitmap = BitmapExtractor.extract(result?.generatedImage())
    return bitmap
}

Mit Plug-ins generieren

fun generate(
    prompt: String,
    inputImage: MPImage,
    conditionType: ConditionType,
    iteration: Int,
    seed: Int
): Bitmap {
    val result = imageGenerator.generate(
        prompt,
        inputImage,
        conditionType,
        iteration,
        seed
    )
    val bitmap = BitmapExtractor.extract(result?.generatedImage())
    return bitmap
}

Mit LoRA-Gewichtungen generieren

Der Prozess zum Generieren von Bildern mit einem Modell, das mit LoRA-Gewichtungen angepasst ist, ähnelt dem Verfahren mit einem Standard-Grundlagenmodell. Prüfen Sie, ob das Token in der Eingabeaufforderung enthalten ist, und führen Sie denselben Code aus.

fun generate(prompt: String, iteration: Int, seed: Int): Bitmap {
    val result = imageGenerator.generate(prompt, iteration, seed)
    val bitmap = BitmapExtractor.extract(result?.generatedImage())
    return bitmap
}

Iterative Generierung

Der Bildgenerator kann bei jedem Durchlauf auch die generierten Zwischenbilder ausgeben, wie im Eingabeparameter iterations definiert. Wenn Sie diese Zwischenergebnisse sehen möchten, rufen Sie die Methode setInputs und dann execute() auf, um jeden Schritt auszuführen. Legen Sie den Parameter showResult auf true fest, um die Zwischenergebnisse anzeigen zu lassen.

fun execute(showResult: Boolean): Bitmap {
    val result = imageGenerator.execute(showResult)

    val bitmap =
        BitmapExtractor.extract(result.generatedImage())

    return bitmap
}

Ergebnisse verarbeiten und anzeigen

Der Bildgenerator gibt ein ImageGeneratorResult zurück, das das generierte Bild, einen Zeitstempel für den Abschluss und das bedingte Bild, falls vorhanden, als Eingabe enthält.

val bitmap = BitmapExtractor.extract(result.generatedImage())

Das folgende Bild wurde aus den folgenden Eingaben nur mit einem Fundamentmodell generiert.

Eingaben:

  • Prompt: „Ein bunter Cartoon-Waschbär mit einem schlappen Stock mit breiter Krempe und einem Stock geht durch den Wald, animierte Dreiviertelansicht, Gemälde“
  • Seed: 312687592
  • Iterationen: 20

Generiertes Bild: