On-Device-Bildgenerierung auf Android-Geräten mit MediaPipe

On-Device-Bildergenerierung auf Android-Geräten mit MediaPipe

Informationen zu diesem Codelab

subjectZuletzt aktualisiert: Okt. 24, 2023
account_circleVerfasst von Paul Ruiz

1. Einführung

Was ist MediaPipe?

Mit MediaPipe Solutions können Sie Lösungen für maschinelles Lernen (ML) auf Ihre Apps anwenden. Sie bietet ein Framework zum Konfigurieren vordefinierter Verarbeitungspipelines, die Nutzern sofortige, ansprechende und nützliche Ergebnisse liefern. Viele dieser Lösungen lassen sich sogar mit dem MediaPipe Model Maker anpassen, um die Standardmodelle zu aktualisieren.

Die Text-zu-Bild-Generierung ist eine von mehreren ML-Aufgaben, die MediaPipe Solutions bietet.

In diesem Codelab beginnen Sie mit einer weitgehend nackten Android-App und führen dann mehrere Schritte aus, bis Sie neue Bilder direkt auf Ihrem Android-Gerät generieren können.

Lerninhalte

  • So implementieren Sie die Text-zu-Bild-Generierung, die lokal in einer Android-App mit MediaPipe Tasks ausgeführt wird.

Voraussetzungen

  • Eine installierte Version von Android Studio (dieses Codelab wurde mit Android Studio Giraffe geschrieben und getestet).
  • Ein Android-Gerät mit mindestens 8 GB RAM
  • Grundkenntnisse in der Android-Entwicklung und die Fähigkeit, ein vorgefertigtes Python-Script auszuführen.

2. MediaPipe Tasks zur Android-App hinzufügen

Android-Start-App herunterladen

Dieses Codelab beginnt mit einem vorgefertigten Beispiel, das aus der Benutzeroberfläche besteht, die für eine einfache Version der Bildgenerierung verwendet wird. Sie finden diese Start-App im offiziellen MediaPipe-Samples-Repository. Klone das Repository oder lade die ZIP-Datei herunter, indem du auf „Code“ > „ZIP herunterladen“ klickst.

App in Android Studio importieren

  1. Öffnen Sie Android Studio.
  2. Wählen Sie auf dem Bildschirm Willkommen bei Android Studio rechts oben die Option Öffnen aus.

a0b5b070b802e4ea.png

  1. Rufen Sie den Speicherort auf, an dem Sie das Repository geklont oder heruntergeladen haben, und öffnen Sie das Verzeichnis codelabs/image_generation_basic/android/start.
  2. In dieser Phase sollte die App nicht kompiliert werden, da Sie die Abhängigkeit von MediaPipe Tasks noch nicht hinzugefügt haben.

Öffnen Sie die Datei build.gradle und scrollen Sie nach unten zu // Schritt 1 – Abhängigkeit hinzufügen. Fügen Sie dort die folgende Zeile ein und klicken Sie dann auf die Schaltfläche Jetzt synchronisieren, die im Banner oben in Android Studio angezeigt wird.

// Step 1 - Add dependency
implementation
'com.google.mediapipe:tasks-vision-image-generator:latest.release'

Wenn die Synchronisierung abgeschlossen ist, klicken Sie rechts oben in Android Studio auf den grünen Pfeil Ausführen ( 7e15a9c9e1620fe7.png), um zu prüfen, ob alles richtig geöffnet und installiert wurde. Die App sollte mit einem Bildschirm mit zwei Optionsschaltflächen und der Schaltfläche INITIALISIEREN geöffnet werden. Wenn Sie auf diese Schaltfläche klicken, sollten Sie sofort zu einer separaten Benutzeroberfläche mit einem Textprompt und anderen Optionen sowie einer Schaltfläche mit der Bezeichnung GENERIER weitergeleitet werden.

83c31de8e8a320ee.png 78b8765e832024e3.png

Das ist leider schon alles, was Sie über die Starter App wissen müssen. Jetzt ist es an der Zeit, zu lernen, wie Sie diese App fertigstellen und neue Bilder auf Ihrem Gerät generieren.

3. Bildgenerator einrichten

In diesem Beispiel wird der Großteil der Bildgenerierung in der Datei ImageGenerationHelper.kt ausgeführt. Wenn Sie diese Datei öffnen, sehen Sie oben in der Klasse die Variable „imageGenerator“. Dieses Task-Objekt übernimmt die Hauptarbeit in Ihrer App zur Bildgenerierung.

Unterhalb dieses Objekts sehen Sie die Funktion „initializeImageGenerator()“ mit dem folgenden Kommentar: // Schritt 2 – Image-Generator initialisieren. Wie Sie sich vorstellen können, wird hier das ImageGenerator-Objekt initialisiert. Ersetzen Sie den Funktionskörper durch den folgenden Code, um den Pfad zum Modell für die Bildgenerierung festzulegen und das ImageGenerator-Objekt zu initialisieren:

// Step 2 - initialize the image generator
val options
= ImageGeneratorOptions.builder()
   
.setImageGeneratorModelDirectory(modelPath)
   
.build()

imageGenerator
= ImageGenerator.createFromOptions(context, options)

Darunter sehen Sie eine weitere Funktion namens „setInput()“. Diese nimmt drei Parameter an: einen Prompt-String, der zum Definieren des generierten Bildes verwendet wird, die Anzahl der Iterationen, die die Aufgabe beim Generieren des neuen Bildes durchlaufen soll, und einen Zufallszahlen-Seed, mit dem neue Versionen eines Bildes basierend auf demselben Prompt erstellt werden können, während mit demselben Seed das gleiche Bild generiert wird. Mit dieser Funktion können Sie diese anfänglichen Parameter für den Bildgenerator festlegen, wenn Sie ein Bild erstellen möchten, in dem Zwischenschritte angezeigt werden.

Ersetzen Sie den Body von setInput(), in dem sich der Kommentar // Schritt 3 – Eingaben akzeptieren befindet, durch diese Zeile:

// Step 3 - accept inputs
imageGenerator
.setInputs(prompt, iteration, seed)

In den nächsten beiden Schritten erfolgt die Generierung. Die Funktion „generate()“ akzeptiert dieselben Eingaben wie „setInput“, erstellt aber ein Bild als einmaligen Aufruf, der keine Bilder der Zwischenschritte zurückgibt. Sie können den Body dieser Funktion (einschließlich des Kommentars // Schritt 4 – ohne Iterationen generieren) durch Folgendes ersetzen:

// Step 4 - generate without showing iterations
val result
= imageGenerator.generate(prompt, iteration, seed)
val bitmap
= BitmapExtractor.extract(result?.generatedImage())
return bitmap

Diese Aufgabe wird synchron ausgeführt. Sie müssen die Funktion also über einen Hintergrund-Thread aufrufen. Dazu erfahren Sie später in diesem Codelab mehr.

Der letzte Schritt in dieser Datei besteht darin, die Funktion „execute()“ auszufüllen (als Schritt 5 gekennzeichnet). Hier wird ein Parameter angegeben, der angibt, ob für den einzelnen Schritt der Generierung, der mit der execute()-Funktion von ImageGenerator ausgeführt wird, ein Zwischenbild zurückgegeben werden soll oder nicht. Ersetzen Sie den Funktionskörper durch folgenden Code:

// 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

Das war es mit der Hilfsdatei. Im nächsten Abschnitt füllen Sie die ViewModel-Datei aus, die die Logik für dieses Beispiel verwaltet.

4. App zusammenstellen

In der Datei MainViewModel werden die UI-Status und andere Logik für diese Beispiel-App verwaltet. Öffnen Sie sie jetzt.

Oben in der Datei sollte der Kommentar // Schritt 6 – Modellpfad festlegen zu sehen sein. Hier geben Sie an, wo Ihre App die Modelldateien finden kann, die für die Bildgenerierung erforderlich sind. In diesem Beispiel legen Sie den Wert auf /data/local/tmp/image_generator/bins/ fest.

// Step 6 - set model path
private val MODEL_PATH = "/data/local/tmp/image_generator/bins/"

Scrollen Sie dann nach unten zur Funktion „generateImage()“. Unten in dieser Funktion sehen Sie sowohl Schritt 7 als auch Schritt 8, mit denen Bilder mit bzw. ohne zurückgegebene Iterationen generiert werden. Da beide Vorgänge synchron ablaufen, sind sie in einer Coroutine verpackt. Ersetzen Sie zuerst // Schritt 7 – Generieren, ohne Iterationen anzuzeigen durch diesen Codeblock, um generate() aus der Datei ImageGenerationHelper aufzurufen, und aktualisieren Sie dann den UI-Status.

// Step 7 - Generate without showing iterations
val result
= helper?.generate(prompt, iteration, seed)
_uiState
.update {
    it
.copy(outputBitmap = result)
}

Schritt 8 ist etwas schwieriger. Da die Funktion „execute()“ nur einen Schritt statt alle Schritte für die Bildgenerierung ausführt, müssen Sie jeden Schritt einzeln über eine Schleife aufrufen. Sie müssen auch festlegen, ob der aktuelle Schritt für den Nutzer angezeigt werden soll. Schließlich aktualisieren Sie den UI-Status, wenn die aktuelle Iteration angezeigt werden soll. All das ist jetzt möglich.

// 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)",
           
)
       
}
   
}
}

Jetzt sollten Sie Ihre App installieren, den Bildgenerator initialisieren und dann ein neues Bild anhand eines Text-Prompts erstellen können.

… nur jetzt stürzt die App ab, wenn Sie versuchen, den Bildgenerator zu initialisieren. Das liegt daran, dass Sie Ihre Modelldateien auf Ihr Gerät kopieren müssen. Aktuelle Informationen zu funktionierenden Drittanbietermodellen, zur Konvertierung für diese MediaPipe-Aufgabe und zum Kopieren auf Ihr Gerät finden Sie in diesem Abschnitt der offiziellen Dokumentation.

Sie können Dateien nicht nur direkt auf Ihr Entwicklungsgerät kopieren, sondern auch Firebase Storage so einrichten, dass die erforderlichen Dateien zur Laufzeit direkt auf das Gerät des Nutzers heruntergeladen werden.

5. App bereitstellen und testen

Danach sollten Sie eine funktionierende App haben, die einen Textprompt akzeptieren und neue Bilder vollständig auf dem Gerät generieren kann. Sie können die App jetzt auf einem physischen Android-Gerät bereitstellen, um sie zu testen. Denken Sie aber daran, dass Sie dies mit einem Gerät mit mindestens 8 GB Arbeitsspeicher tun sollten.

  1. Klicken Sie in der Android Studio-Symbolleiste auf „Ausführen“ (7e15a9c9e1620fe7.png), um die App auszuführen.
  2. Wählen Sie die Art der Generierungsschritte aus (final oder mit Iterationen) und drücken Sie dann die Schaltfläche INITIALISIEREN.
  3. Legen Sie auf dem nächsten Bildschirm die gewünschten Eigenschaften fest und klicken Sie auf die Schaltfläche GENERIERUNG STARTEN, um sich die Ergebnisse anzusehen.

e46cfaeb9d3fc235.gif

6. Glückwunsch!

Geschafft! In diesem Codelab haben Sie gelernt, wie Sie einer Android-App die On-Device-Text-zu-Bild-Generierung hinzufügen.

Nächste Schritte

Mit der Aufgabe „Bilder erstellen“ können Sie noch mehr tun, z. B.

  • Sie können ein Basisbild verwenden, um generierte Bilder über Plug-ins zu strukturieren, oder eigene zusätzliche LoRA-Gewichte über Vertex AI trainieren.
  • Mit Firebase Storage können Sie Modelldateien auf Ihrem Gerät abrufen, ohne das ADB-Tool verwenden zu müssen.

Wir sind gespannt auf die coolen Dinge, die ihr mit dieser experimentellen Aufgabe kreiert. Haltet Ausschau nach weiteren Codelabs und Inhalten vom MediaPipe-Team.