Guía de generación de imágenes para Android

La tarea MediaPipe Image Generator te permite generar imágenes basadas en instrucciones de texto. En esta tarea, se usa un modelo de texto a imagen para generar imágenes mediante técnicas de difusión.

La tarea acepta una instrucción de texto como entrada, junto con una imagen de condición opcional que el modelo puede aumentar y usar como referencia para la generación. El generador de imágenes también puede generar imágenes basadas en conceptos específicos proporcionados al modelo durante el entrenamiento o el reentrenamiento. Para obtener más información, consulta Personaliza con LoRA.

La muestra de código que se describe en estas instrucciones está disponible en GitHub. Para obtener más información sobre las capacidades, los modelos y las opciones de configuración de esta tarea, consulta la Descripción general.

Ejemplo de código

El código de ejemplo de MediaPipe Tasks es una implementación básica de una app de generación de imágenes para Android. Puedes usar la app como punto de partida para tu propia app para Android o consultarla cuando modifiques una app existente. El código de ejemplo del generador de imágenes se aloja en GitHub.

Descarga el código

En las siguientes instrucciones, se muestra cómo crear una copia local del código de ejemplo con la herramienta de línea de comandos git.

Para descargar el código de ejemplo, haz lo siguiente:

  1. Usa el siguiente comando para clonar el repositorio de Git:
    git clone https://github.com/google-ai-edge/mediapipe-samples
    
  2. De manera opcional, configura tu instancia de Git para que use la confirmación de la compra dispersa, de modo que solo tengas los archivos para la app de ejemplo del generador de imágenes:
    cd mediapipe
    git sparse-checkout init --cone
    git sparse-checkout set examples/image_generator/android
    
    .

Después de crear una versión local del código de ejemplo, puedes importar el proyecto a Android Studio y ejecutar la app. Para obtener instrucciones, consulta la Guía de configuración de Android.

Componentes clave

Los siguientes archivos contienen el código fundamental para esta aplicación de ejemplo de generación de imágenes:

  • ImageGenerationHelper.kt: Inicializa la tarea y controla la generación de imágenes.
  • DiffusionActivity.kt: Genera imágenes cuando los complementos o los pesos de LoRA no están habilitados.
  • PluginActivity.kt: Implementa los modelos de complementos, que permiten a los usuarios proporcionar una imagen de condición como entrada.
  • LoRAWeightActivity.kt: Accede a los pesos de LoRA y los controla, que se usan para personalizar modelos de base y permitirles generar imágenes de conceptos específicos.

Configuración

En esta sección, se describen los pasos clave a fin de configurar el entorno de desarrollo y los proyectos de código específicamente para usar el generador de imágenes. Si quieres obtener información general sobre cómo configurar tu entorno de desarrollo para usar tareas de MediaPipe, incluidos los requisitos de la versión de la plataforma, consulta la Guía de configuración para Android.

Dependencias

La tarea Generador de imágenes usa la biblioteca com.google.mediapipe:tasks-vision-image-generator. Agrega esta dependencia al archivo build.gradle de tu app para Android:

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

Para dispositivos con Android 12 (nivel de API 31) o versiones posteriores, agrega la dependencia nativa de la biblioteca OpenCL a AndroidManifest.xml. Para obtener más información, consulta la documentación sobre la etiqueta uses-native-library.

Es posible que algunos dispositivos Android también requieran bibliotecas adicionales:

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

Modelo

La tarea Generador de imágenes de MediaPipe requiere un modelo de base entrenado que sea compatible con esta tarea. Después de descargar un modelo, instala las dependencias necesarias y convierte el modelo en un formato adecuado. Luego, envía el modelo convertido al dispositivo Android.

Si deseas obtener más información sobre los modelos entrenados disponibles para el generador de imágenes, consulta la descripción general de tareas de la sección Modelos.

Descargar el modelo de base

El generador de imágenes requiere que el modelo de base coincida con el formato del modelo runwayml/stable-diffusion-v1-5 EMA-only, según el siguiente modelo: runwayml/stable-diffusion-v1-5.

Instala dependencias y convierte el modelo

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

Ejecuta la secuencia de comandos convert.py:

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

Enviar el modelo convertido al dispositivo

Envía el contenido de la carpeta <output_path> al dispositivo Android.

$ 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

Descarga modelos de complementos y agrega las ponderaciones de LoRA (opcional)

Si deseas usar un modelo de complemento, verifica si se debe descargar el modelo. Para los complementos que requieren un modelo adicional, estos deben empaquetarse en el APK o descargarse a pedido. Los modelos de complementos son ligeros (aproximadamente 23 MB) y se pueden incluir directamente en el APK. Sin embargo, recomendamos descargar modelos de complementos a pedido.

Si personalizaste un modelo con LoRA, descárgalo a pedido. Para obtener más información, consulta el modelo del complemento de las ponderaciones de LoRA.

Crea la tarea

En la tarea Generador de imágenes de MediaPipe, se usa la función createFromOptions() para configurar la tarea. La función createFromOptions() acepta valores para las opciones de configuración. Si deseas obtener más información sobre las opciones de configuración, consulta Opciones de configuración.

Opciones de configuración

Esta tarea incluye las siguientes opciones de configuración para apps para Android:

Nombre de la opción Descripción Rango de valores
imageGeneratorModelDirectory El directorio del modelo generador de imágenes en el que se almacenan los pesos del modelo. PATH
loraWeightsFilePath Establece la ruta de acceso al archivo de ponderaciones de LoRA. Opcional y solo aplicable si el modelo se personalizó con LoRA. PATH
errorListener Establece un objeto de escucha de errores opcional. N/A

La tarea también admite modelos de complementos, que permiten a los usuarios incluir imágenes de condición en la entrada de la tarea, que el modelo de base puede aumentar y usar como referencia para la generación. Estas imágenes de condición pueden ser puntos de referencia de rostros, contornos de bordes y estimaciones de profundidad, que el modelo usa como información y contexto adicionales para generar imágenes.

Cuando agregues un modelo de complemento al modelo de base, también configura las opciones del complemento. El complemento de punto de referencia de Face usa faceConditionOptions, el de Canny Edge usa edgeConditionOptions y el complemento de Depth usa depthConditionOptions.

Opciones de Canny Edge

Configura las siguientes opciones en edgeConditionOptions.

Nombre de la opción Descripción Rango de valores Valor predeterminado
threshold1 Primer umbral para el procedimiento de histéresis. Float 100
threshold2 Segundo umbral para el procedimiento de histéresis. Float 200
apertureSize Tamaño de apertura para el operador Sobel. El rango habitual es de 3 a 7. Integer 3
l2Gradient Indica si se usa la norma L2 para calcular la magnitud del gradiente de la imagen, en lugar de la norma L1 predeterminada. BOOLEAN False
EdgePluginModelBaseOptions El objeto BaseOptions que establece la ruta de acceso para el modelo del complemento Objeto BaseOptions N/A

Para obtener más información sobre cómo funcionan estas opciones de configuración, consulta el detector de perímetro Canny.

Opciones de puntos de referencia facial

Configura las siguientes opciones en faceConditionOptions.

Nombre de la opción Descripción Rango de valores Valor predeterminado
minFaceDetectionConfidence Puntuación de confianza mínima para que se considere correcta la detección de rostro. Float [0.0,1.0] 0.5
minFacePresenceConfidence Puntuación de confianza mínima de la puntuación de presencia facial en la detección de puntos de referencia facial. Float [0.0,1.0] 0.5
faceModelBaseOptions El objeto BaseOptions que establece la ruta de acceso para el modelo que crea la imagen de condición. Objeto BaseOptions N/A
FacePluginModelBaseOptions El objeto BaseOptions que establece la ruta de acceso para el modelo del complemento Objeto BaseOptions N/A

Para obtener más información sobre cómo funcionan estas opciones de configuración, consulta la tarea de marcador de rostro.

Opciones de profundidad

Configura las siguientes opciones en depthConditionOptions.

Nombre de la opción Descripción Rango de valores Valor predeterminado
depthModelBaseOptions El objeto BaseOptions que establece la ruta de acceso para el modelo que crea la imagen de condición. Objeto BaseOptions N/A
depthPluginModelBaseOptions El objeto BaseOptions que establece la ruta de acceso para el modelo del complemento Objeto BaseOptions N/A

Crea solo con el modelo de base

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

imageGenerator = ImageGenerator.createFromOptions(context, options)

Crear con complementos

Si aplicas un modelo de complemento opcional, configura las opciones base para el modelo de complemento con setPluginModelBaseOptions. Si el modelo del complemento requiere un modelo descargado adicional para crear la imagen de condición, especifica la ruta de acceso en BaseOptions.

Punto de referencia facial

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 Edge

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)
    

Profundidad

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)
    

Cómo crear con ponderaciones de LoRA

Si incluyes ponderaciones de LoRA, usa el parámetro loraWeightsFilePath para señalar la ubicación de la ruta.

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

imageGenerator = ImageGenerator.createFromOptions(context, options)

Preparar los datos

El generador de imágenes acepta las siguientes entradas:

  • prompt (obligatorio): Es la instrucción de texto que describe la imagen que se generará.
  • iterations (obligatorio): El total de las iteraciones para generar la imagen. Un buen punto de partida es 20.
  • seed (obligatorio): Es el valor inicial aleatorio que se usa durante la generación de la imagen.
  • condition image (opcional): Es la imagen que el modelo usa como referencia para la generación. Solo se aplica cuando se usa un modelo de complemento.
  • condition type (opcional): Es el tipo de modelo de complemento que se usa con la tarea. Solo se aplica cuando se usa un modelo de complemento.

Entradas solo con el modelo de base

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

Entradas con complementos

Si aplicas un modelo de complemento opcional, usa también el parámetro conditionType para elegir el modelo del complemento y el parámetro sourceConditionImage para generar la imagen de condición.

Nombre de la opción Descripción Valor
conditionType El modelo del complemento aplicado al modelo de base. {"FACE", "EDGE", "DEPTH"}
sourceConditionImage La imagen de origen que se usa para crear la imagen de condición. Objeto MPImage

Si usas un modelo de complemento, utiliza createConditionImage para crear la imagen de condición:

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

Después de crear la imagen de condición, inclúyela como una entrada junto con el mensaje, el origen y la cantidad de iteraciones.

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

Entradas con ponderaciones de LoRA

Si usas ponderaciones de LoRA, asegúrate de que el token esté en el mensaje de texto si quieres generar una imagen con el concepto específico representado por las ponderaciones.

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

Ejecuta la tarea

Usa el método generate() para generar una imagen con las entradas proporcionadas en la sección anterior. Esto produce una única imagen generada.

Genera solo con el modelo de base

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

Genera con complementos

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
}

Cómo generar con ponderaciones de LoRA

El proceso de generación de imágenes con un modelo personalizado con ponderaciones de LoRA es similar al proceso con un modelo de base estándar. Asegúrate de que el token esté incluido en el mensaje y ejecuta el mismo código.

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

Generación iterativa

El generador de imágenes también puede generar las imágenes intermedias generadas durante cada iteración, como se define en el parámetro de entrada iterations. Para ver estos resultados intermedios, llama al método setInputs y, luego, a execute() para ejecutar cada paso. Establece el parámetro showResult en true para mostrar los resultados intermedios.

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

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

    return bitmap
}

Cómo controlar y mostrar los resultados

El generador de imágenes muestra un ImageGeneratorResult, que incluye la imagen generada, una marca de tiempo de la hora de finalización y la imagen condicional si se proporcionó una como entrada.

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

La siguiente imagen se generó a partir de las siguientes entradas, con solo un modelo de base.

Entradas:

  • Consigna: "Una caricatura colorida de un mapache con un sombrero de ala ancha que sostiene un palo y camina por el bosque. Vista animada de tres cuartos y pintura".
  • Valor inicial: 312687592
  • Iteraciones: 20

Imagen generada: