À propos de cet atelier de programmation
1. Introduction
Qu'est-ce que MediaPipe ?
MediaPipe Solutions vous permet d'appliquer des solutions de machine learning (ML) à vos applications. Il fournit un framework permettant de configurer des pipelines de traitement prédéfinis qui fournissent des résultats immédiats, attrayants et utiles aux utilisateurs. Vous pouvez même personnaliser un grand nombre de ces solutions avec MediaPipe Model Maker afin de mettre à jour les modèles par défaut.
La génération de texte en image est l'une des nombreuses tâches de ML proposées par MediaPipe Solutions.
Dans cet atelier de programmation, vous allez commencer avec une application Android épurée, puis réaliser plusieurs étapes jusqu'à ce que vous puissiez générer de nouvelles images directement sur votre appareil Android.
Points abordés
- Découvrez comment implémenter la génération d'images à partir de texte en local dans une application Android avec MediaPipe Tasks.
Prérequis
- Une version installée d'Android Studio (cet atelier de programmation a été écrit et testé avec Android Studio Giraffe)
- Un appareil Android avec au moins 8 Go de RAM.
- Connaissances de base du développement Android et capacité à exécuter un script Python pré-écrit
2. Ajouter MediaPipe Tasks à l'application Android
Télécharger l'application de démarrage Android
Cet atelier de programmation démarrera avec un exemple prédéfini composé de l'UI qui sera utilisée pour une version de base de la génération d'images. Vous trouverez cette application de démarrage dans le dépôt officiel MediaPipe Samples, sur cette page. Clonez le dépôt ou téléchargez le fichier ZIP en cliquant sur Code > Télécharger le fichier ZIP
Importer l'application dans Android Studio
- Ouvrez Android Studio.
- Sur l'écran Welcome to Android Studio (Bienvenue dans Android Studio), sélectionnez Open (Ouvrir) en haut à droite.
- Accédez à l'emplacement où vous avez cloné ou téléchargé le dépôt, puis ouvrez le répertoire codelabs/image_generation_basic/android/start.
- À ce stade, l'application ne doit pas se compiler, car vous n'avez pas encore inclus la dépendance MediaPipe Tasks.
Pour corriger l'application et l'exécuter, accédez au fichier build.gradle, puis faites défiler la page vers le bas jusqu'à // Étape 1 : Ajouter une dépendance. Ensuite, incluez la ligne suivante, puis appuyez sur le bouton Sync Now (Synchroniser) qui s'affiche dans la bannière en haut d'Android Studio.
// Step 1 - Add dependency
implementation 'com.google.mediapipe:tasks-vision-image-generator:latest.release'
Une fois la synchronisation terminée, vérifiez que tout est ouvert et installé correctement en cliquant sur la flèche verte Run ( Exécuter) en haut à droite d'Android Studio. L'application doit s'ouvrir sur un écran avec deux cases d'option et un bouton intitulé INITIALIZE (INITIALISER). Si vous cliquez sur ce bouton, vous êtes immédiatement redirigé vers une interface utilisateur distincte, composée d'une requête textuelle et d'autres options à côté d'un bouton intitulé GÉNÉRER.
Malheureusement, cela représente à peu près toute l'étendue de l'application de démarrage. Il est temps pour vous d'apprendre comment la terminer et commencer à générer de nouvelles images sur votre appareil.
3. Configurer le générateur d'images
Dans cet exemple, la majeure partie du travail de génération d'images est effectuée dans le fichier ImageGenerationHelper.kt. Lorsque vous ouvrirez ce fichier, vous remarquerez une variable appelée "imageGenerator" dans la partie supérieure de la classe. Il s'agit de l'objet Task qui effectuera le plus gros du travail dans votre application de génération d'images.
Juste en dessous de cet objet, vous verrez une fonction appelée InitializeImageGenerator() avec le commentaire suivant: // Étape 2 - Initialiser le générateur d'images. Comme vous pouvez le deviner, c'est ici que vous allez initialiser l'objet ImageGenerator. Remplacez le corps de cette fonction par le code suivant pour définir le chemin d'accès au modèle de génération d'image et initialiser l'objet ImageGenerator:
// Step 2 - initialize the image generator
val options = ImageGeneratorOptions.builder()
.setImageGeneratorModelDirectory(modelPath)
.build()
imageGenerator = ImageGenerator.createFromOptions(context, options)
En dessous, vous pouvez voir une autre fonction nommée setInput(). Ce code accepte trois paramètres: une chaîne de requête qui sera utilisée pour définir l'image générée, le nombre d'itérations que la tâche doit effectuer lors de la génération de la nouvelle image et une valeur seed qui peut être utilisée pour créer de nouvelles versions d'une image basée sur la même requête tout en générant la même image lorsque la même graine est utilisée. L'objectif de cette fonction est de définir ces paramètres initiaux pour le générateur d'images lorsque vous tentez de créer une image qui affiche des étapes intermédiaires.
Remplacez le corps de setInput() (où vous verrez le commentaire // Étape 3 - acceptez les entrées) par cette ligne:
// Step 3 - accept inputs
imageGenerator.setInputs(prompt, iteration, seed)
Les deux prochaines étapes sont le moment de la génération. La fonction generate() accepte les mêmes entrées que setInput, mais crée une image sous la forme d'un appel unique qui ne renvoie aucune image d'étape intermédiaire. Vous pouvez remplacer le corps de cette fonction (qui inclut le commentaire // Étape 4 - Générer sans afficher les itérations) par ce qui suit:
// Step 4 - generate without showing iterations
val result = imageGenerator.generate(prompt, iteration, seed)
val bitmap = BitmapExtractor.extract(result?.generatedImage())
return bitmap
Il est important de savoir que cette tâche se déroule de manière synchrone. Vous devrez donc appeler la fonction à partir d'un thread d'arrière-plan. Vous en apprendrez davantage à ce sujet un peu plus tard dans cet atelier de programmation.
La dernière étape que vous ferez dans ce fichier consiste à remplir la fonction execute() (intitulée Étape 5). Cette commande accepte un paramètre qui indique si une image intermédiaire doit être renvoyée ou non pour la seule étape de génération qui sera effectuée avec la fonction execute() de ImageGenerator. Remplacez le corps de la fonction par le code suivant:
// 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
Et c'est tout pour le fichier d'assistance. Dans la section suivante, vous allez remplir le fichier ViewModel qui gère la logique de cet exemple.
4. Rassembler l'application
Le fichier MainViewModel gérera les états de l'interface utilisateur et d'autres logiques liées à cet exemple d'application. Ouvrez-le maintenant.
Vers le haut du fichier, vous devriez voir le commentaire. // Étape 6 - Définir le chemin d'accès au modèle. C'est là que vous indiquerez à votre application où elle peut trouver les fichiers de modèle nécessaires à la génération d'images. Pour cet exemple, vous allez définir la valeur sur /data/local/tmp/image_generator/bins/.
// Step 6 - set model path
private val MODEL_PATH = "/data/local/tmp/image_generator/bins/"
De là, faites défiler vers le bas jusqu’à la fonction generateImage(). Vers le bas de cette fonction se trouvent les étapes 7 et 8, qui serviront à générer des images avec des itérations renvoyées ou aucune, respectivement. Comme ces deux opérations se produisent de manière synchrone, vous remarquerez qu'elles sont encapsulées dans une coroutine. Vous pouvez commencer par remplacer // Étape 7 : Générer sans afficher les itérations avec ce bloc de code pour appeler generate() à partir du fichier ImageGenerationHelper, puis mettre à jour l'état de l'interface utilisateur.
// Step 7 - Generate without showing iterations
val result = helper?.generate(prompt, iteration, seed)
_uiState.update {
it.copy(outputBitmap = result)
}
L'étape 8 devient un peu plus délicate. Étant donné que la fonction "execute()" n'effectue qu'une étape au lieu de toutes pour la génération d'images, vous devrez appeler chaque étape individuellement via une boucle. Vous devez également déterminer si l'étape actuelle doit être présentée à l'utilisateur. Enfin, vous mettrez à jour l'état de l'interface utilisateur si l'itération en cours doit être affichée. Vous pouvez effectuer toutes ces opérations dès maintenant.
// 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)",
)
}
}
}
À ce stade, vous devriez être en mesure d'installer votre application, d'initialiser le générateur d'images, puis de créer une image à partir d'une requête textuelle.
... sauf que maintenant l'application plante lorsque vous essayez d'initialiser le générateur d'images. En effet, vous devez copier les fichiers de modèle sur votre appareil. Pour obtenir les informations les plus récentes sur les modèles tiers connus, les convertir pour cette tâche MediaPipe et les copier sur votre appareil, vous pouvez consulter cette section de la documentation officielle.
En plus de copier les fichiers directement sur votre appareil de développement, vous pouvez également configurer Firebase Storage pour qu'il télécharge les fichiers nécessaires directement sur l'appareil de l'utilisateur au moment de l'exécution.
5. Déployer et tester l'application
Après tout cela, vous devriez avoir une application fonctionnelle capable d'accepter une requête textuelle et de générer de nouvelles images entièrement sur l'appareil. Vous pouvez maintenant déployer l'application sur un appareil Android physique afin de la tester. Toutefois, n'oubliez pas qu'il est préférable de l'essayer sur un appareil disposant d'au moins 8 Go de mémoire.
- Cliquez sur Exécuter (
) dans la barre d'outils d'Android Studio pour exécuter l'application.
- Sélectionnez le type d'étapes de génération (finales ou avec itérations), puis appuyez sur le bouton INITIALIZE (INITIALISER).
- Sur l'écran suivant, définissez les propriétés de votre choix, puis cliquez sur le bouton GÉNÉRER pour découvrir les résultats de l'outil.
6. Félicitations !
Bravo ! Dans cet atelier de programmation, vous avez appris à ajouter la génération de texte sur l'appareil à une application Android.
Étapes suivantes
La tâche de génération d'images offre d'autres possibilités, y compris
- utiliser une image de base pour structurer les images générées par le biais de plug-ins, ou entraîner vos propres pondérations LoRA supplémentaires via Vertex AI.
- Utilisez Firebase Storage pour récupérer les fichiers de modèle sur votre appareil sans avoir besoin de l'outil ADB.
Nous avons hâte de découvrir tout ce que vous allez créer avec cette tâche expérimentale. Nous vous proposerons bientôt d'autres ateliers de programmation et contenus de l'équipe MediaPipe !