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

La tarea de MediaPipe Image Segmenter te permite dividir las imágenes en regiones según categorías predefinidas para aplicar efectos visuales, como desenfoque de fondo. En estas instrucciones, se muestra cómo usar el Segmentador de imágenes con apps para Android. El ejemplo de código que se describe en estas instrucciones está disponible en GitHub. Para obtener más información sobre las funciones, los modelos y las opciones de configuración de esta tarea, consulta la descripción general.

Ejemplo de código

El ejemplo de código de MediaPipe Tasks contiene dos implementaciones simples de una app de Image Segmenter para Android:

En los ejemplos, se usa la cámara de un dispositivo Android físico para realizar la segmentación de imágenes en un feed de cámara en vivo, o bien puedes elegir imágenes y videos de la galería del dispositivo. Puedes usar las apps como punto de partida para tu propia app para Android o consultarlas cuando modifiques una app existente. El código de ejemplo de Image Segmenter se aloja en GitHub.

En las siguientes secciones, se hace referencia a la app Image Segmenter with a category mask.

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, sigue estos pasos:

  1. Clona el repositorio de git con el siguiente comando:
    git clone https://github.com/google-ai-edge/mediapipe-samples
    
  2. De manera opcional, configura tu instancia de git para usar el control de revisión disperso, de modo que solo tengas los archivos de la app de ejemplo de Image Segmenter:
    cd mediapipe
    git sparse-checkout init --cone
    git sparse-checkout set examples/image_segmentation/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 para Android.

Componentes clave

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

  • ImageSegmenterHelper.kt: Inicializa la tarea de Image Segmenter y controla el modelo y la selección del delegado.
  • CameraFragment.kt: Proporciona la interfaz de usuario y el código de control de una cámara.
  • GalleryFragment.kt: Proporciona la interfaz de usuario y el código de control para seleccionar archivos de imagen y video.
  • OverlayView.kt: Controla y da formato a los resultados de la segmentación.

Configuración

En esta sección, se describen los pasos clave para configurar tu entorno de desarrollo y proyectos de código para usar Image Segmenter. Si deseas 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

Image Segmenter usa la biblioteca com.google.mediapipe:tasks-vision. Agrega esta dependencia al archivo build.gradle de tu proyecto de desarrollo de apps para Android. Importa las dependencias requeridas con el siguiente código:

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

Modelo

La tarea de MediaPipe Image Segmenter requiere un modelo entrenado que sea compatible con esta tarea. Para obtener más información sobre los modelos entrenados disponibles para Image Segmenter, consulta la sección Modelos de la descripción general de la tarea.

Selecciona y descarga el modelo, y guárdalo en el directorio de tu proyecto:

<dev-project-root>/src/main/assets

Usa el método BaseOptions.Builder.setModelAssetPath() para especificar la ruta que usa el modelo. En el ejemplo de código de la siguiente sección, se hace referencia a este método.

En el código de ejemplo del segmentador de imágenes, el modelo se define en la clase ImageSegmenterHelper.kt de la función setupImageSegmenter().

Crea la tarea

Puedes usar la función createFromOptions para crear la tarea. La función createFromOptions acepta opciones de configuración, incluidos los tipos de salida de la máscara. Para obtener más información sobre la configuración de tareas, consulta Opciones de configuración.

La tarea de Segmentador de imágenes admite los siguientes tipos de datos de entrada: imágenes fijas, archivos de video y transmisiones de video en vivo. Cuando crees la tarea, debes especificar el modo de ejecución correspondiente al tipo de datos de entrada. Elige la pestaña de tu tipo de datos de entrada para ver cómo crear esa tarea.

Imagen

ImageSegmenterOptions options =
  ImageSegmenterOptions.builder()
    .setBaseOptions(
      BaseOptions.builder().setModelAssetPath("model.tflite").build())
    .setRunningMode(RunningMode.IMAGE)
    .setOutputCategoryMask(true)
    .setOutputConfidenceMasks(false)
    .build();
imagesegmenter = ImageSegmenter.createFromOptions(context, options);
    

Video

ImageSegmenterOptions options =
  ImageSegmenterOptions.builder()
    .setBaseOptions(
      BaseOptions.builder().setModelAssetPath("model.tflite").build())
    .setRunningMode(RunningMode.VIDEO)
    .setOutputCategoryMask(true)
    .setOutputConfidenceMasks(false)
    .build();
imagesegmenter = ImageSegmenter.createFromOptions(context, options);
    

Transmisión en vivo

ImageSegmenterOptions options =
  ImageSegmenterOptions.builder()
    .setBaseOptions(
      BaseOptions.builder().setModelAssetPath("model.tflite").build())
    .setRunningMode(RunningMode.LIVE_STREAM)
    .setOutputCategoryMask(true)
    .setOutputConfidenceMasks(false)
    .setResultListener((result, inputImage) -> {
         // Process the segmentation result here.
    })
    .setErrorListener((result, inputImage) -> {
         // Process the segmentation errors here.
    })
    .build()
imagesegmenter = ImageSegmenter.createFromOptions(context, options)
    

La implementación del código de ejemplo de Image Segmenter permite al usuario cambiar entre los modos de procesamiento. El enfoque hace que el código de creación de tareas sea más complicado y es posible que no sea adecuado para tu caso de uso. Puedes ver este código en la clase ImageSegmenterHelper a través de la función setupImageSegmenter().

Opciones de configuración

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

Nombre de la opción Descripción Rango de valores Valor predeterminado
runningMode Establece el modo de ejecución de la tarea. Existen tres modos:

IMAGE: Es el modo para entradas de una sola imagen.

VIDEO: Es el modo para los fotogramas decodificados de un video.

LIVE_STREAM: Es el modo de transmisión en vivo de datos de entrada, como los de una cámara. En este modo, se debe llamar a resultListener para configurar un objeto de escucha que reciba resultados de forma asíncrona.
{IMAGE, VIDEO, LIVE_STREAM} IMAGE
outputCategoryMask Si se establece en True, el resultado incluye una máscara de segmentación como una imagen uint8, en la que cada valor de píxel indica el valor de la categoría ganadora. {True, False} False
outputConfidenceMasks Si se establece en True, el resultado incluye una máscara de segmentación como una imagen de valor de punto flotante, en la que cada valor de punto flotante representa el mapa de puntuación de confianza de la categoría. {True, False} True
displayNamesLocale Establece el idioma de las etiquetas que se usarán para los nombres visibles proporcionados en los metadatos del modelo de la tarea, si están disponibles. El valor predeterminado es en para el inglés. Puedes agregar etiquetas localizadas a los metadatos de un modelo personalizado con la API de Metadata Writer de TensorFlow Lite. Código de configuración regional en
resultListener Establece el objeto de escucha de resultados para que reciba los resultados de la segmentación de forma asíncrona cuando el segmentador de imágenes esté en el modo LIVE_STREAM. Solo se puede usar cuando el modo de ejecución está configurado como LIVE_STREAM. N/A N/A
errorListener Establece un objeto de escucha de errores opcional. N/A Sin establecer

Preparar los datos

El Segmentador de imágenes funciona con imágenes, archivos de video y videos de transmisiones en vivo. La tarea controla el procesamiento previo de la entrada de datos, incluido el cambio de tamaño, la rotación y la normalización de valores.

Debes convertir la imagen o el fotograma de entrada en un objeto com.google.mediapipe.framework.image.MPImage antes de pasarlo al segmentador de imágenes.

Imagen

import com.google.mediapipe.framework.image.BitmapImageBuilder;
import com.google.mediapipe.framework.image.MPImage;

// Load an image on the users device as a Bitmap object using BitmapFactory.

// Convert an Androids Bitmap object to a MediaPipes Image object.
Image mpImage = new BitmapImageBuilder(bitmap).build();
    

Video

import com.google.mediapipe.framework.image.BitmapImageBuilder;
import com.google.mediapipe.framework.image.MPImage;

// Load a video file on the user's device using MediaMetadataRetriever

// From the videos metadata, load the METADATA_KEY_DURATION and
// METADATA_KEY_VIDEO_FRAME_COUNT value. Youll need them
// to calculate the timestamp of each frame later.

// Loop through the video and load each frame as a Bitmap object.

// Convert the Androids Bitmap object to a MediaPipes Image object.
Image mpImage = new BitmapImageBuilder(frame).build();
    

Transmisión en vivo

import com.google.mediapipe.framework.image.MediaImageBuilder;
import com.google.mediapipe.framework.image.MPImage;

// Create a CameraXs ImageAnalysis to continuously receive frames
// from the devices camera. Configure it to output frames in RGBA_8888
// format to match with what is required by the model.

// For each Androids ImageProxy object received from the ImageAnalysis,
// extract the encapsulated Androids Image object and convert it to
// a MediaPipes Image object.
android.media.Image mediaImage = imageProxy.getImage()
Image mpImage = new MediaImageBuilder(mediaImage).build();
    

En el código de ejemplo de Image Segmenter, la función segmentLiveStreamFrame() controla la preparación de los datos en la clase ImageSegmenterHelper.

Ejecuta la tarea

Llamas a una función segment diferente según el modo de ejecución que uses. La función Image Segmenter muestra las regiones de segmentos identificadas dentro de la imagen o el fotograma de entrada.

Imagen

ImageSegmenterResult segmenterResult = imagesegmenter.segment(image);
    

Video

// Calculate the timestamp in milliseconds of the current frame.
long frame_timestamp_ms = 1000 * video_duration * frame_index / frame_count;

// Run inference on the frame.
ImageSegmenterResult segmenterResult =
    imagesegmenter.segmentForVideo(image, frameTimestampMs);
    

Transmisión en vivo

// Run inference on the frame. The segmentations results will be available via
// the `resultListener` provided in the `ImageSegmenterOptions` when the image
// segmenter was created.
imagesegmenter.segmentAsync(image, frameTimestampMs);
    

Ten en cuenta lo siguiente:

  • Cuando se ejecuta en el modo de video o en el modo de transmisión en vivo, también debes proporcionar la marca de tiempo del fotograma de entrada a la tarea del segmentador de imágenes.
  • Cuando se ejecuta en el modo de imagen o de video, la tarea del segmentador de imágenes bloquea el subproceso actual hasta que termina de procesar la imagen o el fotograma de entrada. Para evitar bloquear la interfaz de usuario, ejecuta el procesamiento en un subproceso en segundo plano.
  • Cuando se ejecuta en el modo de transmisión en vivo, la tarea del segmentador de imágenes no bloquea el subproceso actual, sino que se muestra de inmediato. Invocará su objeto de escucha de resultados con el resultado de la detección cada vez que termine de procesar un fotograma de entrada. Si se llama a la función segmentAsync cuando la tarea del segmentador de imágenes está ocupada procesando otro fotograma, la tarea ignora el nuevo fotograma de entrada.

En el código de ejemplo de Image Segmenter, las funciones segment se definen en el archivo ImageSegmenterHelper.kt.

Cómo controlar y mostrar los resultados

Cuando se ejecuta la inferencia, la tarea del segmentador de imágenes muestra un objeto ImageSegmenterResult que contiene los resultados de la tarea de segmentación. El contenido del resultado depende del outputType que estableciste cuando configuraste la tarea.

En las siguientes secciones, se muestran ejemplos de los datos de resultado de esta tarea:

Confianza de la categoría

En las siguientes imágenes, se muestra una visualización del resultado de la tarea para una máscara de confianza de categoría. El resultado de la máscara de confianza contiene valores de números de punto flotante entre [0, 1].

Dos niñas a caballo y una caminando junto al caballo La máscara de imagen que define la forma de las niñas y el caballo de la fotografía anterior. Se captura la mitad izquierda del contorno de la imagen, pero no la mitad derecha.

Imagen original y resultado de la máscara de confianza de la categoría. Imagen de origen del conjunto de datos Pascal VOC 2012.

Valor de la categoría

En las siguientes imágenes, se muestra una visualización del resultado de la tarea para una máscara de valor de categoría. El rango de la máscara de categorías es [0, 255] y cada valor de píxel representa el índice de categoría ganador del resultado del modelo. El índice de categoría ganador tiene la puntuación más alta entre las categorías que el modelo puede reconocer.

Dos niñas a caballo y una caminando junto al caballo La máscara de imagen que define la forma de las niñas y el caballo de la imagen anterior. La forma de las tres niñas y el caballo está enmascarada con precisión.

Imagen original y resultado de la máscara de categoría. Imagen de origen del conjunto de datos Pascal VOC 2012.