Detección de objetos con Android

Este tutorial le muestra cómo crear una aplicación de Android usando TensorFlow Lite para detectar continuamente objetos en fotogramas capturados por la cámara de un dispositivo. Esta aplicación está diseñada para un dispositivo Android físico. Si está actualizando un proyecto existente, puede utilizar el código de muestra como referencia y pasar a las instrucciones para modificar su proyecto .

Demostración animada de detección de objetos

Descripción general de la detección de objetos

La detección de objetos es la tarea de aprendizaje automático de identificar la presencia y ubicación de múltiples clases de objetos dentro de una imagen. Un modelo de detección de objetos se entrena en un conjunto de datos que contiene un conjunto de objetos conocidos.

El modelo entrenado recibe marcos de imágenes como entrada e intenta categorizar elementos en las imágenes del conjunto de clases conocidas para las que fue entrenado para reconocer. Para cada cuadro de imagen, el modelo de detección de objetos genera una lista de los objetos que detecta, la ubicación de un cuadro delimitador para cada objeto y una puntuación que indica la confianza de que el objeto se clasifique correctamente.

Modelos y conjunto de datos

Este tutorial utiliza modelos que se entrenaron utilizando el conjunto de datos COCO . COCO es un conjunto de datos de detección de objetos a gran escala que contiene 330.000 imágenes, 1,5 millones de instancias de objetos y 80 categorías de objetos.

Tiene la opción de utilizar uno de los siguientes modelos previamente entrenados:

  • EfficientDet-Lite0 [Recomendado] : un modelo de detección de objetos liviano con un extractor de características BiFPN, un predictor de cuadro compartido y pérdida focal. El mAP (precisión promedio media) para el conjunto de datos de validación COCO 2017 es del 25,69 %.

  • EfficientDet-Lite1 : un modelo de detección de objetos EfficientDet de tamaño mediano. El mAP para el conjunto de datos de validación de COCO 2017 es del 30,55%.

  • EfficientDet-Lite2 : un modelo de detección de objetos EfficientDet más grande. El mAP para el conjunto de datos de validación COCO 2017 es 33,97%.

  • MobileNetV1-SSD : un modelo extremadamente liviano optimizado para funcionar con TensorFlow Lite para la detección de objetos. El mAP para el conjunto de datos de validación COCO 2017 es del 21%.

Para este tutorial, el modelo EfficientDet-Lite0 logra un buen equilibrio entre tamaño y precisión.

La descarga, extracción y colocación de los modelos en la carpeta de activos se administra automáticamente mediante el archivo download.gradle , que se ejecuta en el momento de la compilación. No es necesario descargar manualmente los modelos TFLite en el proyecto.

Ejemplo de configuración y ejecución

Para configurar la aplicación de detección de objetos, descargue la muestra de GitHub y ejecútela con Android Studio . Las siguientes secciones de este tutorial exploran las secciones relevantes del ejemplo de código, para que pueda aplicarlas a sus propias aplicaciones de Android.

Requisitos del sistema

  • Android Studio versión 2021.1.1 (Bumblebee) o superior.
  • Android SDK versión 31 o superior
  • Dispositivo Android con una versión mínima del sistema operativo SDK 24 (Android 7.0 - Nougat) con el modo de desarrollador habilitado.

Obtenga el código de ejemplo

Cree una copia local del código de ejemplo. Utilizará este código para crear un proyecto en Android Studio y ejecutar la aplicación de muestra.

Para clonar y configurar el código de ejemplo:

  1. Clonar el repositorio git
    git clone https://github.com/tensorflow/examples.git
    
  2. Opcionalmente, configure su instancia de git para usar el pago disperso, de modo que solo tenga los archivos para la aplicación de ejemplo de detección de objetos:
    cd examples
    git sparse-checkout init --cone
    git sparse-checkout set lite/examples/object_detection/android
    

Importar y ejecutar el proyecto.

Cree un proyecto a partir del código de ejemplo descargado, compílelo y luego ejecútelo.

Para importar y construir el proyecto de código de ejemplo:

  1. Inicie Android Studio .
  2. Desde Android Studio, seleccione Archivo > Nuevo > Importar proyecto .
  3. Navegue hasta el directorio del código de ejemplo que contiene el archivo build.gradle ( .../examples/lite/examples/object_detection/android/build.gradle ) y seleccione ese directorio.
  4. Si Android Studio solicita Gradle Sync, elija Aceptar.
  5. Asegúrese de que su dispositivo Android esté conectado a su computadora y que el modo de desarrollador esté habilitado. Haga clic en la flecha verde Run .

Si selecciona el directorio correcto, Android Studio crea un nuevo proyecto y lo construye. Este proceso puede tardar unos minutos, dependiendo de la velocidad de tu computadora y si has usado Android Studio para otros proyectos. Cuando se completa la compilación, Android Studio muestra un mensaje BUILD SUCCESSFUL en el panel de estado de Salida de la compilación .

Opcional: para corregir errores de compilación actualizando la versión del complemento de Android:

  1. Abra el archivo build.gradle en el directorio del proyecto.
  2. Cambie la versión de las herramientas de Android de la siguiente manera:

    // from: classpath
    'com.android.tools.build:gradle:4.2.2'
    // to: classpath
    'com.android.tools.build:gradle:4.1.2'
    
  3. Sincronice el proyecto seleccionando: Archivo > Sincronizar proyecto con archivos Gradle .

Para ejecutar el proyecto:

  1. Desde Android Studio, ejecute el proyecto seleccionando Ejecutar > Ejecutar… .
  2. Seleccione un dispositivo Android conectado con una cámara para probar la aplicación.

Las siguientes secciones le muestran las modificaciones que necesita realizar en su proyecto existente para agregar esta funcionalidad a su propia aplicación, utilizando esta aplicación de ejemplo como punto de referencia.

Agregar dependencias del proyecto

En su propia aplicación, debe agregar dependencias de proyecto específicas para ejecutar modelos de aprendizaje automático de TensorFlow Lite y acceder a funciones de utilidad que convierten datos, como imágenes, en un formato de datos tensorial que puede ser procesado por el modelo que está utilizando.

La aplicación de ejemplo utiliza la biblioteca de tareas TensorFlow Lite para que la visión permita la ejecución del modelo de aprendizaje automático de detección de objetos. Las siguientes instrucciones explican cómo agregar las dependencias de biblioteca necesarias a su propio proyecto de aplicación de Android.

Las siguientes instrucciones explican cómo agregar las dependencias requeridas del proyecto y del módulo a su propio proyecto de aplicación de Android.

Para agregar dependencias de módulos:

  1. En el módulo que usa TensorFlow Lite, actualice el archivo build.gradle del módulo para incluir las siguientes dependencias. En el código de ejemplo, este archivo se encuentra aquí: ...examples/lite/examples/object_detection/android/app/build.gradle ( referencia del código )

    dependencies {
      ...
      implementation 'org.tensorflow:tensorflow-lite-task-vision:0.4.0'
      // Import the GPU delegate plugin Library for GPU inference
      implementation 'org.tensorflow:tensorflow-lite-gpu-delegate-plugin:0.4.0'
      implementation 'org.tensorflow:tensorflow-lite-gpu:2.9.0'
    }
    

    El proyecto debe incluir la biblioteca de tareas de Vision ( tensorflow-lite-task-vision ). La biblioteca de la unidad de procesamiento de gráficos (GPU) ( tensorflow-lite-gpu-delegate-plugin ) proporciona la infraestructura para ejecutar la aplicación en la GPU, y Delegate ( tensorflow-lite-gpu ) proporciona la lista de compatibilidad.

  2. En Android Studio, sincronice las dependencias del proyecto seleccionando: Archivo > Sincronizar proyecto con archivos Gradle .

Inicializar el modelo ML

En su aplicación de Android, debe inicializar el modelo de aprendizaje automático de TensorFlow Lite con parámetros antes de ejecutar predicciones con el modelo. Estos parámetros de inicialización son consistentes en todos los modelos de detección de objetos y pueden incluir configuraciones como umbrales mínimos de precisión para las predicciones.

Un modelo de TensorFlow Lite incluye un archivo .tflite que contiene el código del modelo y, con frecuencia, incluye un archivo de etiquetas que contiene los nombres de las clases predichas por el modelo. En el caso de la detección de objetos, las clases son objetos como una persona, un perro, un gato o un automóvil.

Este ejemplo descarga varios modelos que se especifican en download_models.gradle y la clase ObjectDetectorHelper proporciona un selector para los modelos:

val modelName =
  when (currentModel) {
    MODEL_MOBILENETV1 -> "mobilenetv1.tflite"
    MODEL_EFFICIENTDETV0 -> "efficientdet-lite0.tflite"
    MODEL_EFFICIENTDETV1 -> "efficientdet-lite1.tflite"
    MODEL_EFFICIENTDETV2 -> "efficientdet-lite2.tflite"
    else -> "mobilenetv1.tflite"
  }

Para inicializar el modelo en su aplicación:

  1. Agregue un archivo de modelo .tflite al directorio src/main/assets de su proyecto de desarrollo, como por ejemplo: EfficientDet-Lite0 .
  2. Establezca una variable estática para el nombre de archivo de su modelo. En la aplicación de ejemplo, configura la variable modelName en MODEL_EFFICIENTDETV0 para usar el modelo de detección EfficientDet-Lite0.
  3. Configure las opciones para el modelo, como el umbral de predicción, el tamaño del conjunto de resultados y, opcionalmente, los delegados de aceleración de hardware:

    val optionsBuilder =
      ObjectDetector.ObjectDetectorOptions.builder()
        .setScoreThreshold(threshold)
        .setMaxResults(maxResults)
    
  4. Utilice la configuración de este objeto para construir un objeto ObjectDetector de TensorFlow Lite que contenga el modelo:

    objectDetector =
      ObjectDetector.createFromFileAndOptions(
        context, modelName, optionsBuilder.build())
    

setupObjectDetector configura los siguientes parámetros del modelo:

  • Umbral de detección
  • Número máximo de resultados de detección
  • Número de subprocesos de procesamiento a utilizar ( BaseOptions.builder().setNumThreads(numThreads) )
  • Modelo real ( modelName )
  • Objeto detector de objetos ( objectDetector )

Configurar el acelerador de hardware

Al inicializar un modelo de TensorFlow Lite en su aplicación, puede usar funciones de aceleración de hardware para acelerar los cálculos de predicción del modelo.

Los delegados de TensorFlow Lite son módulos de software que aceleran la ejecución de modelos de aprendizaje automático utilizando hardware de procesamiento especializado en un dispositivo móvil, como unidades de procesamiento de gráficos (GPU), unidades de procesamiento tensorial (TPU) y procesadores de señales digitales (DSP). Se recomienda utilizar delegados para ejecutar modelos de TensorFlow Lite, pero no es obligatorio.

El detector de objetos se inicializa usando la configuración actual en el hilo que lo está usando. Puede usar delegados de CPU y NNAPI con detectores que se crean en el subproceso principal y se usan en un subproceso en segundo plano, pero el subproceso que inicializó el detector debe usar el delegado de GPU.

Los delegados se configuran dentro de la función ObjectDetectionHelper.setupObjectDetector() :

when (currentDelegate) {
    DELEGATE_CPU -> {
        // Default
    }
    DELEGATE_GPU -> {
        if (CompatibilityList().isDelegateSupportedOnThisDevice) {
            baseOptionsBuilder.useGpu()
        } else {
            objectDetectorListener?.onError("GPU is not supported on this device")
        }
    }
    DELEGATE_NNAPI -> {
        baseOptionsBuilder.useNnapi()
    }
}

Para obtener más información sobre el uso de delegados de aceleración de hardware con TensorFlow Lite, consulte Delegados de TensorFlow Lite .

Preparar datos para el modelo.

En su aplicación de Android, su código proporciona datos al modelo para su interpretación transformando datos existentes, como marcos de imágenes, en un formato de datos Tensor que puede ser procesado por su modelo. Los datos de un tensor que pasa a un modelo deben tener dimensiones o formas específicas que coincidan con el formato de los datos utilizados para entrenar el modelo.

El modelo EfficientDet-Lite0 utilizado en este ejemplo de código acepta tensores que representan imágenes con una dimensión de 320 x 320, con tres canales (rojo, azul y verde) por píxel. Cada valor en el tensor es un solo byte entre 0 y 255. Por lo tanto, para ejecutar predicciones en nuevas imágenes, su aplicación debe transformar los datos de esa imagen en objetos de datos de tensor de ese tamaño y forma. La API Vision de la biblioteca de tareas de TensorFlow Lite maneja la transformación de datos por usted.

La aplicación utiliza un objeto ImageAnalysis para extraer imágenes de la cámara. Este objeto llama a la función detectObject con mapa de bits de la cámara. ImageProcessor cambia el tamaño y rota automáticamente los datos para que cumplan con los requisitos de datos de imagen del modelo. Luego, la imagen se traduce a un objeto TensorImage .

Para preparar datos del subsistema de cámara para que los procese el modelo ML:

  1. Cree un objeto ImageAnalysis para extraer imágenes en el formato requerido:

    imageAnalyzer =
        ImageAnalysis.Builder()
            .setTargetAspectRatio(AspectRatio.RATIO_4_3)
            .setTargetRotation(fragmentCameraBinding.viewFinder.display.rotation)
            .setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST)
            .setOutputImageFormat(OUTPUT_IMAGE_FORMAT_RGBA_8888)
            .build()
            ...
    
  2. Conecte el analizador al subsistema de la cámara y cree un búfer de mapa de bits para contener los datos recibidos de la cámara:

    .also {
      it.setAnalyzer(cameraExecutor) {
        image -> if (!::bitmapBuffer.isInitialized)
        { bitmapBuffer = Bitmap.createBitmap( image.width, image.height,
        Bitmap.Config.ARGB_8888 ) } detectObjects(image)
        }
      }
    
  3. Extraiga los datos de imagen específicos que necesita el modelo y pase la información de rotación de la imagen:

    private fun detectObjects(image: ImageProxy) {
      //Copy out RGB bits to the shared bitmap buffer
      image.use {bitmapBuffer.copyPixelsFromBuffer(image.planes[0].buffer) }
        val imageRotation = image.imageInfo.rotationDegrees
        objectDetectorHelper.detect(bitmapBuffer, imageRotation)
      }
    
  4. Complete cualquier transformación de datos final y agregue los datos de la imagen a un objeto TensorImage , como se muestra en el método ObjectDetectorHelper.detect() de la aplicación de ejemplo:

    val imageProcessor = ImageProcessor.Builder().add(Rot90Op(-imageRotation / 90)).build()
    // Preprocess the image and convert it into a TensorImage for detection.
    val tensorImage = imageProcessor.process(TensorImage.fromBitmap(image))
    

Ejecutar predicciones

En su aplicación de Android, una vez que crea un objeto TensorImage con datos de imagen en el formato correcto, puede ejecutar el modelo con esos datos para producir una predicción o inferencia .

En la clase fragments/CameraFragment.kt de la aplicación de ejemplo, el objeto imageAnalyzer dentro de la función bindCameraUseCases pasa automáticamente datos al modelo para realizar predicciones cuando la aplicación está conectada a la cámara.

La aplicación utiliza el método cameraProvider.bindToLifecycle() para manejar el selector de cámara, la ventana de vista previa y el procesamiento del modelo ML. La clase ObjectDetectorHelper.kt se encarga de pasar los datos de la imagen al modelo. Para ejecutar el modelo y generar predicciones a partir de datos de imágenes:

  • Ejecute la predicción pasando los datos de la imagen a su función de predicción:

    val results = objectDetector?.detect(tensorImage)
    

El objeto TensorFlow Lite Interpreter recibe estos datos, los ejecuta con el modelo y produce una lista de predicciones. Para el procesamiento continuo de datos por parte del modelo, utilice el método runForMultipleInputsOutputs() para que el sistema no cree objetos de intérprete y luego los elimine para cada ejecución de predicción.

Manejar la salida del modelo

En su aplicación de Android, después de ejecutar datos de imágenes en el modelo de detección de objetos, se produce una lista de predicciones que el código de su aplicación debe manejar ejecutando lógica empresarial adicional, mostrando resultados al usuario o realizando otras acciones.

El resultado de cualquier modelo de TensorFlow Lite varía en términos de la cantidad de predicciones que produce (una o muchas) y la información descriptiva de cada predicción. En el caso de un modelo de detección de objetos, las predicciones normalmente incluyen datos para un cuadro delimitador que indica dónde se detecta un objeto en la imagen. En el código de ejemplo, los resultados se pasan a la función onResults en CameraFragment.kt , que actúa como DetectorListener en el proceso de detección de objetos.

interface DetectorListener {
  fun onError(error: String)
  fun onResults(
    results: MutableList<Detection>?,
    inferenceTime: Long,
    imageHeight: Int,
    imageWidth: Int
  )
}

Para el modelo utilizado en este ejemplo, cada predicción incluye una ubicación del cuadro delimitador para el objeto, una etiqueta para el objeto y una puntuación de predicción entre 0 y 1 como flotante que representa la confianza de la predicción, siendo 1 la calificación de confianza más alta. . En general, las predicciones con una puntuación inferior al 50% (0,5) se consideran no concluyentes. Sin embargo, la forma en que maneja los resultados de predicción de bajo valor depende de usted y de las necesidades de su aplicación.

Para manejar los resultados de la predicción del modelo:

  1. Utilice un patrón de escucha para pasar resultados al código de su aplicación o a los objetos de la interfaz de usuario. La aplicación de ejemplo usa este patrón para pasar los resultados de la detección del objeto ObjectDetectorHelper al objeto CameraFragment :

    objectDetectorListener.onResults(
    // instance of CameraFragment
        results,
        inferenceTime,
        tensorImage.height,
        tensorImage.width)
    
  2. Actuar sobre los resultados, como mostrar la predicción al usuario. El ejemplo dibuja una superposición en el objeto CameraPreview para mostrar el resultado:

    override fun onResults(
      results: MutableList<Detection>?,
      inferenceTime: Long,
      imageHeight: Int,
      imageWidth: Int
    ) {
        activity?.runOnUiThread {
            fragmentCameraBinding.bottomSheetLayout.inferenceTimeVal.text =
                String.format("%d ms", inferenceTime)
    
            // Pass necessary information to OverlayView for drawing on the canvas
            fragmentCameraBinding.overlay.setResults(
                results ?: LinkedList<Detection>(),
                imageHeight,
                imageWidth
            )
    
            // Force a redraw
            fragmentCameraBinding.overlay.invalidate()
        }
    }
    

Una vez que el modelo ha devuelto un resultado de predicción, su aplicación puede actuar según esa predicción presentando el resultado a su usuario o ejecutando lógica adicional. En el caso del código de ejemplo, la aplicación dibuja un cuadro delimitador alrededor del objeto identificado y muestra el nombre de la clase en la pantalla.

Próximos pasos

  • Explore varios usos de TensorFlow Lite en los ejemplos .
  • Obtenga más información sobre el uso de modelos de aprendizaje automático con TensorFlow Lite en la sección Modelos .
  • Obtenga más información sobre cómo implementar el aprendizaje automático en su aplicación móvil en la Guía para desarrolladores de TensorFlow Lite .