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

1. Einführung

Was ist MediaPipe?

Mit MediaPipe Solutions können Sie ML-Lösungen (Machine Learning) auf Ihre Apps anwenden. Es bietet ein Framework zum Konfigurieren vorgefertigter Verarbeitungspipelines, die Nutzern sofort ansprechende und nützliche Ergebnisse liefern. Viele dieser Lösungen lassen sich sogar mit 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 leeren Android-App und arbeiten sich dann durch mehrere Schritte, bis Sie neue Bilder direkt auf Ihrem Android-Gerät generieren können.

Lerninhalte

  • Implementieren der 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.
  • Grundlegende Kenntnisse der Android-Entwicklung und die Möglichkeit, ein vorgefertigtes Python-Skript auszuführen.

2. MediaPipe Tasks zur Android-App hinzufügen

Android-Start-App herunterladen

Dieses Codelab beginnt mit einem vorgefertigten Beispiel, das die UI für eine einfache Version der Bildgenerierung enthält. Sie finden die Start-App im offiziellen MediaPipe-Beispiel-Repository hier. Klonen Sie das Repository oder laden Sie die ZIP-Datei herunter, indem Sie auf „Code“ > „ZIP herunterladen“ klicken.

App in Android Studio importieren

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

a0b5b070b802e4ea.png

  1. Navigieren Sie zu dem Ort, an dem Sie das Repository geklont oder heruntergeladen haben, und öffnen Sie das codelabs/image_generation_basic/android/start directory.
  2. Zu diesem Zeitpunkt sollte die App nicht kompiliert werden , da Sie die MediaPipe Tasks-Abhängigkeit noch nicht hinzugefügt haben.

Sie können die App korrigieren und ausführen, indem Sie die Datei build.gradle öffnen und zu // Schritt 1 – Abhängigkeit hinzufügen scrollen. 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'

Nach Abschluss der Synchronisierung prüfen Sie, ob alles korrekt geöffnet und installiert wurde. Klicken Sie dazu oben rechts in Android Studio auf den grünen Pfeil Ausführen ( 7e15a9c9e1620fe7.png). Die App sollte auf einem Bildschirm mit zwei Optionsfeldern und einer Schaltfläche mit der Bezeichnung INITIALIZE geöffnet werden. Wenn Sie auf diese Schaltfläche klicken, sollten Sie sofort zu einer separaten UI weitergeleitet werden, die einen Text-Prompt und andere Optionen sowie eine Schaltfläche mit der Bezeichnung GENERATE enthält.

83c31de8e8a320ee.png 78b8765e832024e3.png

Das ist leider schon alles, was die Start-App zu bieten hat. Jetzt erfahren Sie, wie Sie diese App fertigstellen und neue Bilder auf Ihrem Gerät generieren können.

3. Bildgenerator einrichten

In diesem Beispiel findet der Großteil der Bildgenerierung in der Datei ImageGenerationHelper.kt statt. Wenn Sie diese Datei öffnen, sehen Sie oben in der Klasse eine Variable namens imageGenerator. Dies ist das Task-Objekt, das die Hauptarbeit in Ihrer Bildgenerierungs-App erledigt.

Direkt unter diesem Objekt sehen Sie eine Funktion namens initializeImageGenerator() mit dem folgenden Kommentar: // Schritt 2 – Bildgenerator initialisieren. Hier initialisieren Sie das ImageGenerator -Objekt. Ersetzen Sie den Funktionskörper durch den folgenden Code, um den Pfad des Bildgenerierungsmodells 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 akzeptiert drei Parameter: einen Prompt -String, der zum Definieren des generierten Bildes verwendet wird, die Anzahl der Wiederholungen , die die Aufgabe beim Generieren des neuen Bildes durchlaufen soll, und einen Seed -Wert, mit dem neue Versionen eines Bildes auf Grundlage desselben Prompts erstellt werden können, während bei Verwendung desselben Seeds das gleiche Bild generiert wird. Mit dieser Funktion werden diese Anfangsparameter für den Bildgenerator festgelegt, wenn Sie versuchen, ein Bild zu erstellen, bei dem Zwischenschritte angezeigt werden.

Ersetzen Sie den setInput()-Körper (in dem Sie den Kommentar // Schritt 3 – Eingaben akzeptieren sehen) durch diese Zeile:

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

In den nächsten beiden Schritten findet die Generierung statt. Die Funktion generate() akzeptiert dieselben Eingaben wie setInput, erstellt aber ein Bild als einmaligen Aufruf, der keine Zwischenschrittbilder zurückgibt. Sie können den Hauptteil dieser Funktion (einschließlich des Kommentars // Schritt 4 – Generieren ohne Anzeige von Wiederholungen) 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 von einem Hintergrundthread aufrufen. Mehr dazu erfahren Sie später in diesem Codelab.

Im letzten Schritt in dieser Datei füllen Sie die Funktion execute() aus (Schritt 5). Diese akzeptiert einen Parameter, der angibt, ob für den einzelnen Schritt der Generierung, der mit der Funktion ImageGenerator execute() ausgeführt wird, ein Zwischenbild zurückgegeben werden soll oder nicht. Ersetzen Sie den Funktionskörper durch diesen 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's mit der Hilfsdatei. Im nächsten Abschnitt füllen Sie die ViewModel-Datei aus, die die Logik für dieses Beispiel verarbeitet.

4. App zusammenführen

Die Datei MainViewModel verarbeitet UI-Zustände und andere Logik im Zusammenhang mit dieser Beispiel-App. Öffnen Sie sie jetzt.

Oben in der Datei sehen Sie den Kommentar // Schritt 6 – Modellpfad festlegen. Hier geben Sie Ihrer App an, wo sie die Modelldateien findet, 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 zur Funktion generateImage(). Unten in dieser Funktion sehen Sie sowohl Schritt 7 als auch Schritt 8, mit denen Bilder mit bzw. ohne zurückgegebene Wiederholungen generiert werden. Da beide Vorgänge synchron ausgeführt werden, sind sie in einer Coroutine eingeschlossen. Ersetzen Sie zuerst // Schritt 7 – Generieren ohne Anzeige von Wiederholungen durch diesen Codeblock, um generate() aus der Datei ImageGenerationHelper aufzurufen, und aktualisieren Sie dann den UI-Zustand.

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

Schritt 8 ist etwas komplizierter. Da die Funktion execute() nur einen Schritt anstelle von allen Schritten 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-Zustand, wenn die aktuelle Wiederholung angezeigt werden soll. Sie können das jetzt tun.

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

An diesem Punkt sollten Sie Ihre App installieren, den Bildgenerator initialisieren und dann ein neues Bild auf Grundlage eines Text-Prompts erstellen können.

... außer dass die App jetzt abstürzt, wenn Sie versuchen, den Bildgenerator zu initialisieren. Das liegt daran, dass Sie Ihre Modelldateien auf Ihr Gerät kopieren müssen. Die neuesten Informationen zu bekannten Modellen von Drittanbietern, zum Konvertieren dieser Modelle 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 einrichten, um die erforderlichen Dateien zur Laufzeit direkt auf das Gerät des Nutzers herunterzuladen.

5. App bereitstellen und testen

Danach sollten Sie eine funktionierende App haben, die einen Text-Prompt akzeptieren und neue Bilder vollständig auf dem Gerät generieren kann. Stellen Sie die App auf einem physischen Android-Gerät bereit, um sie zu testen. Denken Sie jedoch daran, dass Sie dies mit einem Gerät mit mindestens 8 GB Arbeitsspeicher versuchen 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 Wiederholungen) und klicken Sie dann auf die Schaltfläche INITIALIZE.
  3. Legen Sie auf dem nächsten Bildschirm die gewünschten Eigenschaften fest und klicken Sie auf die Schaltfläche GENERATE , um zu sehen, was das Tool liefert.

e46cfaeb9d3fc235.gif

6. Glückwunsch!

Geschafft! In diesem Codelab haben Sie gelernt, wie Sie einer Android-App die Text-zu-Bild-Generierung auf dem Gerät hinzufügen.

Nächste Schritte

Mit der Bildgenerierungsaufgabe können Sie noch mehr tun, z. B.

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

Wir sind gespannt, was Sie mit dieser experimentellen Aufgabe alles anstellen, und freuen uns darauf, Ihnen noch mehr Codelabs und Inhalte vom MediaPipe-Team zu präsentieren.