Detecta objetos en imágenes con un modelo entrenado por AutoML en Android

Después de entrenar tu propio modelo con AutoML Vision Edge, puedes usarlo en tu app para detectar objetos en imágenes.

Hay dos formas de integrar los modelos entrenados desde AutoML Vision Edge: puedes agrupar el modelo colocándolo dentro de la carpeta de elementos de tu app o puedes descargarlo de forma dinámica desde Firebase.

Opciones de agrupación de modelos
Agrupados en tu app
  • El modelo es parte del APK de la app
  • El modelo está disponible de inmediato, incluso cuando el dispositivo Android está sin conexión
  • No se necesita un proyecto de Firebase
Alojado en Firebase

Antes de comenzar

  1. Si quieres descargar un modelo, asegúrate de agregar Firebase a tu proyecto de Android, en caso de que aún no lo hayas hecho. Esto no es obligatorio cuando se agrupa un modelo.

  2. Agrega las dependencias para la biblioteca de tareas de TensorFlow Lite al archivo Gradle de nivel de la app del módulo, que generalmente es app/build.gradle:

    Para empaquetar un modelo con tu app, sigue estos pasos:

    dependencies {
      // ...
      // Object detection with a bundled Auto ML model
      implementation 'org.tensorflow:tensorflow-lite-task-vision:0.0.0-nightly-SNAPSHOT'
    }
    

    Si quieres descargar un modelo de Firebase de forma dinámica, agrega también la dependencia del AA de Firebase:

    dependencies {
      // ...
      // Object detection with an Auto ML model deployed to Firebase
      implementation platform('com.google.firebase:firebase-bom:26.1.1')
      implementation 'com.google.firebase:firebase-ml-model-interpreter'
    
      implementation 'org.tensorflow:tensorflow-lite-task-vision:0.0.0-nightly'
    }
    

1. Carga el modelo

Configura una fuente de modelo local

Sigue estos pasos para empaquetar el modelo con tu app:

  1. Extrae el modelo del archivo ZIP que descargaste de la consola de Google Cloud.
  2. Incluye tu modelo en el paquete de tu app:
    1. Si no tienes una carpeta de elementos en tu proyecto, debes crear una. Para ello, haz clic con el botón derecho en la carpeta app/ y, luego, haz clic en Nuevo > Carpeta > Carpeta de elementos.
    2. Copia el archivo del modelo tflite con metadatos incorporados a la carpeta de elementos.
  3. Agrega lo siguiente al archivo build.gradle de tu app para asegurarte de que Gradle no comprima el archivo del modelo cuando se compile la app:

    android {
        // ...
        aaptOptions {
            noCompress "tflite"
        }
    }
    

    El archivo del modelo se incluirá en el paquete de la app y estará disponible como elemento sin procesar.

Configura una fuente de modelo alojada en Firebase

Para usar el modelo alojado de forma remota, crea un objeto RemoteModel y especifica el nombre que le asignaste al modelo cuando lo publicaste:

Java

// Specify the name you assigned when you deployed the model.
FirebaseCustomRemoteModel remoteModel =
        new FirebaseCustomRemoteModel.Builder("your_model").build();

Kotlin

// Specify the name you assigned when you deployed the model.
val remoteModel =
    FirebaseCustomRemoteModel.Builder("your_model_name").build()

Luego, inicia la tarea de descarga del modelo y especifica las condiciones en las que deseas permitir la descarga. Si el modelo no está en el dispositivo o si hay una versión más reciente de este, la tarea descargará el modelo de Firebase de forma asíncrona:

Java

DownloadConditions downloadConditions = new DownloadConditions.Builder()
        .requireWifi()
        .build();
RemoteModelManager.getInstance().download(remoteModel, downloadConditions)
        .addOnSuccessListener(new OnSuccessListener<Void>() {
            @Override
            public void onSuccess(@NonNull Task<Void> task) {
                // Success.
            }
        });

Kotlin

val downloadConditions = DownloadConditions.Builder()
    .requireWifi()
    .build()
RemoteModelManager.getInstance().download(remoteModel, downloadConditions)
    .addOnSuccessListener {
        // Success.
    }

Muchas apps comienzan la tarea de descarga en su código de inicialización, pero puedes hacerlo en cualquier momento antes de usar el modelo.

Crea un detector de objetos a partir de tu modelo

Después de configurar las fuentes de tu modelo, crea un objeto ObjectDetector a partir de una de ellas.

Si solo tienes un modelo empaquetado a nivel local, crea un detector de objetos a partir del archivo de modelo y configura el umbral de puntuación de confianza que deseas solicitar (consulta Evalúa tu modelo):

Java

// Initialization
ObjectDetectorOptions options = ObjectDetectorOptions.builder()
    .setScoreThreshold(0)  // Evaluate your model in the Google Cloud Console
                           // to determine an appropriate value.
    .build();
ObjectDetector objectDetector = ObjectDetector.createFromFileAndOptions(context, modelFile, options);

Kotlin

// Initialization
val options = ObjectDetectorOptions.builder()
    .setScoreThreshold(0)  // Evaluate your model in the Google Cloud Console
                           // to determine an appropriate value.
    .build()
val objectDetector = ObjectDetector.createFromFileAndOptions(context, modelFile, options)

Si tienes un modelo alojado de forma remota, comprueba si se descargó antes de ejecutarlo. Puedes verificar el estado de la tarea de descarga del modelo con el método isModelDownloaded() del administrador del modelo.

Aunque solo debes confirmarlo antes de ejecutar el detector de objetos, si tienes un modelo alojado de forma remota y uno empaquetado localmente, sería acertado realizar esta verificación cuando se crea una instancia de detector de objetos: crea un intérprete desde el modelo remoto si se descargó o, en su defecto, desde el modelo local.

Java

FirebaseModelManager.getInstance().isModelDownloaded(remoteModel)
        .addOnSuccessListener(new OnSuccessListener<Boolean>() {
            @Override
            public void onSuccess(Boolean isDownloaded) {
            }
        });

Kotlin

FirebaseModelManager.getInstance().isModelDownloaded(remoteModel)
        .addOnSuccessListener { success ->

        }

Si solo tienes un modelo alojado de forma remota, debes inhabilitar la funcionalidad relacionada con el modelo, por ejemplo, ocultar o inhabilitar parte de tu IU, hasta que confirmes que el modelo se descargó. Puedes hacerlo si adjuntas un objeto de escucha al método download() del administrador de modelos.

Una vez que confirmes que se descargó el modelo, crea un detector de objetos a partir del archivo de modelo:

Java

FirebaseModelManager.getInstance().getLatestModelFile(remoteModel)
        .addOnCompleteListener(new OnCompleteListener<File>() {
            @Override
            public void onComplete(@NonNull Task<File> task) {
                File modelFile = task.getResult();
                if (modelFile != null) {
                    ObjectDetectorOptions options = ObjectDetectorOptions.builder()
                            .setScoreThreshold(0)
                            .build();
                    objectDetector = ObjectDetector.createFromFileAndOptions(
                            getApplicationContext(), modelFile.getPath(), options);
                }
            }
        });

Kotlin

FirebaseModelManager.getInstance().getLatestModelFile(remoteModel)
        .addOnSuccessListener { modelFile ->
            val options = ObjectDetectorOptions.builder()
                    .setScoreThreshold(0f)
                    .build()
            objectDetector = ObjectDetector.createFromFileAndOptions(
                    applicationContext, modelFile.path, options)
        }

2. Prepara la imagen de entrada

Luego, deberás crear un objeto TensorImage a partir de tu imagen por cada imagen que quieras etiquetar. Puedes crear un objeto TensorImage a partir de un Bitmap con el método fromBitmap:

Java

TensorImage image = TensorImage.fromBitmap(bitmap);

Kotlin

val image = TensorImage.fromBitmap(bitmap)

Si los datos de tus imágenes no están en un Bitmap, puedes cargar un arreglo de píxeles como se muestra en la documentación de TensorFlow Lite.

3. Ejecuta el detector de objetos

Para detectar los objetos de una imagen, pasa el objeto TensorImage al método detect() de ObjectDetector.

Java

List<Detection> results = objectDetector.detect(image);

Kotlin

val results = objectDetector.detect(image)

4. Obtén información sobre los objetos etiquetados

Si la operación de detección de objetos se ejecuta correctamente, se mostrará una lista de objetos Detection. Cada objeto Detection representa un elemento detectado en la imagen. Puedes obtener el cuadro de límite de cada objeto y sus etiquetas.

Por ejemplo:

Java

for (Detection result : results) {
    RectF bounds = result.getBoundingBox();
    List<Category> labels = result.getCategories();
}

Kotlin

for (result in results) {
    val bounds = result.getBoundingBox()
    val labels = result.getCategories()
}

Sugerencias para mejorar el rendimiento en tiempo real

Si quieres etiquetar imágenes en una aplicación en tiempo real, sigue estos lineamientos para lograr la mejor velocidad de fotogramas:

  • Limita las llamadas al etiquetador de imágenes. Si surge un fotograma de video nuevo mientras se ejecuta el etiquetador de imágenes, ignora ese fotograma. Consulta la clase VisionProcessorBase de la app de ejemplo de la guía de inicio rápido para ver un ejemplo.
  • Si usas la salida del etiquetador de imágenes para superponer gráficos en la imagen de entrada, primero obtén el resultado y, luego, renderiza la imagen y la superposición en un solo paso. De esta manera, renderizas en la superficie de visualización solo una vez por cada fotograma de entrada. Consulta las clases CameraSourcePreview y GraphicOverlay en la app de ejemplo de la guía de inicio rápido para ver un ejemplo.
  • Si usas la API de Camera2, captura imágenes en formato ImageFormat.YUV_420_888.

    Si usas la API de Camera más antigua, captura imágenes en formato ImageFormat.NV21.