1. Introduzione
Che cos'è MediaPipe?
MediaPipe Solutions ti consente di applicare soluzioni di machine learning (ML) alle tue app. Fornisce un framework per la configurazione di pipeline di elaborazione predefinite che offrono agli utenti un output immediato, coinvolgente e utile. Puoi anche personalizzare molte di queste soluzioni con MediaPipe Model Maker per aggiornare i modelli predefiniti.
La generazione di immagini a partire da testo è una delle diverse attività di ML offerte da MediaPipe Solutions.
In questo codelab, inizierai con un'app per Android quasi vuota, poi passerai attraverso diversi passaggi fino a quando non potrai generare nuove immagini direttamente sul tuo dispositivo Android.
Obiettivi didattici
- Come implementare la generazione di testo in immagine in esecuzione localmente in un'app per Android con MediaPipe Tasks.
Che cosa ti serve
- Una versione installata di Android Studio (questo codelab è stato scritto e testato con Android Studio Giraffe).
- Un dispositivo Android con almeno 8 GB di RAM.
- Conoscenza di base dello sviluppo Android e capacità di eseguire uno script Python precompilato.
2. Aggiungere MediaPipe Tasks all'app per Android
Scaricare l'app iniziale per Android
Questo codelab inizierà con un esempio predefinito costituito dall'interfaccia utente che verrà utilizzata per una versione di base della generazione di immagini. Puoi trovare l'app di avvio nel repository ufficiale di MediaPipe Samples qui. Clona il repository o scarica il file ZIP facendo clic su Codice > Scarica ZIP.
Importa l'app in Android Studio
- Apri Android Studio.
- Nella schermata Ti diamo il benvenuto in Android Studio, seleziona Apri nell'angolo in alto a destra.
- Vai alla posizione in cui hai clonato o scaricato il repository e apri la directory codelabs/image_generation_basic/android/start.
- A questo punto l'app non deve compilarsi perché non hai ancora incluso la dipendenza da MediaPipe Tasks.
Per correggere l'app e avviarla, vai al file build.gradle e scorri verso il basso fino a // Passaggio 1: aggiungi dipendenza. Da qui, includi la riga seguente e fai clic sul pulsante Sincronizza ora visualizzato nel banner nella parte superiore di Android Studio.
// Step 1 - Add dependency
implementation 'com.google.mediapipe:tasks-vision-image-generator:latest.release'
Al termine della sincronizzazione, verifica che tutto sia stato aperto e installato correttamente facendo clic sulla freccia verde Esegui ( ) in alto a destra in Android Studio. L'app dovrebbe aprirsi su una schermata con due pulsanti di opzione e un pulsante denominato INIZIALIZZA. Se fai clic su questo pulsante, dovresti essere reindirizzato immediatamente a un'interfaccia utente separata composta da un prompt di testo e altre opzioni, oltre a un pulsante denominato GENERA.
Purtroppo, questo è più o meno il limite dell'app di avvio, quindi è il momento di scoprire come completare questa app e iniziare a generare nuove immagini sul tuo dispositivo.
3. Configurazione del Generatore di immagini
Per questo esempio, la maggior parte del lavoro di generazione delle immagini verrà eseguita nel file ImageGenerationHelper.kt. Quando apri questo file, noterai una variabile nella parte superiore della classe chiamata imageGenerator. Questo è l'oggetto Task che eseguirà la parte più complessa del lavoro nell'app di generazione di immagini.
Appena sotto questo oggetto vedrai una funzione chiamata initializeImageGenerator() con il seguente commento: // Passaggio 2: inizializza il generatore di immagini. Come puoi immaginare, è qui che devi inizializzare l'oggetto ImageGenerator. Sostituisci il corpo della funzione con il seguente codice per impostare il percorso del modello di generazione di immagini e inizializzare l'oggetto ImageGenerator:
// Step 2 - initialize the image generator
val options = ImageGeneratorOptions.builder()
.setImageGeneratorModelDirectory(modelPath)
.build()
imageGenerator = ImageGenerator.createFromOptions(context, options)
Sotto vedrai un'altra funzione denominata setInput(). Questa accetta tre parametri: una stringa prompt che verrà utilizzata per definire l'immagine generata, il numero di iterazioni che l'attività deve eseguire durante la generazione della nuova immagine e un valore seed che può essere utilizzato per creare nuove versioni di un'immagine in base allo stesso prompt, generando al contempo la stessa immagine quando viene utilizzato lo stesso seed. Lo scopo di questa funzione è impostare questi parametri iniziali per il generatore di immagini quando si tenta di creare un'immagine che mostri i passaggi intermedi.
Sostituisci il corpo di setInput() (dove vedrai il commento // Passaggio 3: accetta gli input) con questa riga:
// Step 3 - accept inputs
imageGenerator.setInputs(prompt, iteration, seed)
I due passaggi successivi sono quelli in cui avviene la generazione. La funzione generate() accetta gli stessi input di setInput, ma crea un'immagine come chiamata una tantum che non restituisce immagini intermedie. Puoi sostituire il corpo di questa funzione (che include il commento // Passaggio 4: genera senza mostrare le iterazioni) con quanto segue:
// Step 4 - generate without showing iterations
val result = imageGenerator.generate(prompt, iteration, seed)
val bitmap = BitmapExtractor.extract(result?.generatedImage())
return bitmap
È importante sapere che questa attività viene eseguita in modo sincrono, quindi dovrai chiamare la funzione da un thread in background. Scoprirai di più su questo argomento più avanti in questo codelab.
L'ultimo passaggio da eseguire in questo file è compilare la funzione execute() (etichettata come Passaggio 5). Accetta un parametro che indica se deve restituire o meno un'immagine intermedia per il singolo passaggio di generazione che verrà eseguito con la funzione execute() di ImageGenerator. Sostituisci il corpo della funzione con questo codice:
// 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
Questo è tutto per il file di supporto. Nella sezione successiva compilerai il file ViewModel che gestisce la logica di questo esempio.
4. Combinare l'app
Il file MainViewModel gestirà gli stati dell'interfaccia utente e altra logica relativa a questa app di esempio. Aprilo subito.
Nella parte superiore del file dovresti vedere il commento // Passaggio 6: imposta il percorso del modello. Qui dovrai indicare all'app dove può trovare i file del modello necessari per la generazione di immagini. Per questo esempio, imposta il valore su /data/local/tmp/image_generator/bins/.
// Step 6 - set model path
private val MODEL_PATH = "/data/local/tmp/image_generator/bins/"
Da qui, scorri verso il basso fino alla funzione generateImage(). Verso la fine di questa funzione vedrai i passaggi 7 e 8, che verranno utilizzati per generare immagini con o senza iterazioni restituite, rispettivamente. Poiché entrambe le operazioni vengono eseguite in modo sincrono, noterai che sono racchiuse in una coroutine. Puoi iniziare sostituendo // Passaggio 7: genera senza mostrare le iterazioni con questo blocco di codice per chiamare generate() dal file ImageGenerationHelper, quindi aggiornare lo stato dell'interfaccia utente.
// Step 7 - Generate without showing iterations
val result = helper?.generate(prompt, iteration, seed)
_uiState.update {
it.copy(outputBitmap = result)
}
Il passaggio 8 è un po' più complicato. Poiché la funzione execute() esegue solo un passaggio anziché tutti i passaggi per la generazione di immagini, dovrai chiamare ogni passaggio singolarmente tramite un ciclo. Dovrai anche stabilire se il passaggio corrente deve essere visualizzato per l'utente. Infine, aggiornerai lo stato dell'interfaccia utente se deve essere visualizzata l'iterazione corrente. Puoi fare tutto questo ora.
// 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)",
)
}
}
}
A questo punto dovresti essere in grado di installare l'app, inizializzare il generatore di immagini e creare una nuova immagine in base a un prompt di testo
... ma ora l'app si arresta in modo anomalo quando provi a inizializzare il generatore di immagini. Il motivo è che devi copiare i file del modello sul dispositivo. Per ottenere le informazioni più aggiornate sui modelli di terze parti che funzionano, convertirli per questa attività MediaPipe e copiarli sul tuo dispositivo, puoi consultare questa sezione della documentazione ufficiale.
Oltre a copiare i file direttamente sul dispositivo di sviluppo, è anche possibile configurare Firebase Storage in modo che scarichi i file necessari direttamente sul dispositivo dell'utente in fase di esecuzione.
5. Esegui il deployment e il test dell'app
Al termine, dovresti avere un'app funzionante che può accettare un prompt di testo e generare nuove immagini interamente sul dispositivo. Vai avanti e implementa l'app su un dispositivo Android fisico per testarla, ma ricordati di provare questa operazione con un dispositivo con almeno 8 GB di memoria.
- Fai clic su Esegui (
) nella barra degli strumenti di Android Studio per eseguire l'app.
- Seleziona il tipo di passaggi di generazione (finali o con iterazioni) e poi premi il pulsante INIZIALIZZA.
- Nella schermata successiva, imposta le proprietà che preferisci e fai clic sul pulsante GENERA per vedere cosa suggerisce lo strumento.
6. Complimenti!
Ce l'hai fatta! In questo codelab hai imparato ad aggiungere la generazione di testo in immagine sul dispositivo a un'app per Android.
Passaggi successivi
Puoi fare molto di più con l'attività di generazione di immagini, ad esempio
- utilizzando un'immagine di base per strutturare le immagini generate tramite plug-in oppure addestrando i tuoi pesi LoRA aggiuntivi tramite Vertex AI.
- Utilizza Firebase Storage per recuperare i file del modello sul tuo dispositivo senza dover utilizzare lo strumento ADB.
Non vediamo l'ora di vedere tutte le cose fantastiche che realizzerai con questo compito sperimentale e ti invitiamo a tenere d'occhio altri codelab e contenuti del team di MediaPipe.