Rilevamento oggetti con Android

Questo tutorial mostra come creare un'app Android utilizzando TensorFlow Lite per rilevare continuamente oggetti nei fotogrammi catturati dalla fotocamera di un dispositivo. Questa applicazione è progettata per un dispositivo Android fisico. Se stai aggiornando un progetto esistente, puoi utilizzare l'esempio di codice come riferimento e passare alle istruzioni per modificare il progetto .

Demo animata di rilevamento oggetti

Panoramica sul rilevamento degli oggetti

Il rilevamento degli oggetti è l'attività di machine learning che consiste nell'identificare la presenza e la posizione di più classi di oggetti all'interno di un'immagine. Un modello di rilevamento degli oggetti viene addestrato su un set di dati che contiene un insieme di oggetti conosciuti.

Il modello addestrato riceve fotogrammi di immagine come input e tenta di classificare gli elementi nelle immagini dall'insieme di classi note che è stato addestrato a riconoscere. Per ogni fotogramma dell'immagine, il modello di rilevamento degli oggetti restituisce un elenco degli oggetti rilevati, la posizione di un riquadro di delimitazione per ciascun oggetto e un punteggio che indica la confidenza con cui l'oggetto è stato classificato correttamente.

Modelli e set di dati

Questo tutorial utilizza modelli addestrati utilizzando il set di dati COCO . COCO è un set di dati di rilevamento di oggetti su larga scala che contiene 330.000 immagini, 1,5 milioni di istanze di oggetti e 80 categorie di oggetti.

Hai la possibilità di utilizzare uno dei seguenti modelli pre-addestrati:

  • EfficientDet-Lite0 [Consigliato] : un modello leggero di rilevamento di oggetti con un estrattore di funzionalità BiFPN, un predittore di box condiviso e una perdita focale. Il mAP (precisione media media) per il set di dati di convalida COCO 2017 è 25,69%.

  • EfficientDet-Lite1 : un modello di rilevamento di oggetti EfficientDet di medie dimensioni. La mappa per il set di dati di convalida COCO 2017 è del 30,55%.

  • EfficientDet-Lite2 : un modello di rilevamento oggetti EfficientDet più ampio. La mappa per il set di dati di convalida COCO 2017 è del 33,97%.

  • MobileNetV1-SSD : un modello estremamente leggero ottimizzato per funzionare con TensorFlow Lite per il rilevamento di oggetti. La mappa per il set di dati di convalida COCO 2017 è del 21%.

Per questo tutorial, il modello EfficientDet-Lite0 raggiunge un buon equilibrio tra dimensioni e precisione.

Il download, l'estrazione e l'inserimento dei modelli nella cartella delle risorse è gestito automaticamente dal file download.gradle , che viene eseguito in fase di creazione. Non è necessario scaricare manualmente i modelli TFLite nel progetto.

Esempio di configurazione ed esecuzione

Per configurare l'app di rilevamento oggetti, scarica l'esempio da GitHub ed eseguilo utilizzando Android Studio . Le sezioni seguenti di questo tutorial esplorano le sezioni pertinenti dell'esempio di codice, in modo da poterle applicare alle tue app Android.

Requisiti di sistema

  • Android Studio versione 2021.1.1 (Bumblebee) o successiva.
  • Android SDK versione 31 o successiva
  • Dispositivo Android con una versione del sistema operativo minima SDK 24 (Android 7.0 - Nougat) con modalità sviluppatore abilitata.

Ottieni il codice di esempio

Crea una copia locale del codice di esempio. Utilizzerai questo codice per creare un progetto in Android Studio ed eseguire l'applicazione di esempio.

Per clonare e configurare il codice di esempio:

  1. Clona il repository git
    git clone https://github.com/tensorflow/examples.git
    
  2. Facoltativamente, configura la tua istanza git per utilizzare il checkout sparse, in modo da avere solo i file per l'app di esempio di rilevamento oggetti:
    cd examples
    git sparse-checkout init --cone
    git sparse-checkout set lite/examples/object_detection/android
    

Importare ed eseguire il progetto

Crea un progetto dal codice di esempio scaricato, crea il progetto e quindi eseguilo.

Per importare e creare il progetto di codice di esempio:

  1. Avvia Android Studio .
  2. Da Android Studio, seleziona File > Nuovo > Importa progetto .
  3. Passare alla directory del codice di esempio contenente il file build.gradle ( .../examples/lite/examples/object_detection/android/build.gradle ) e selezionare quella directory.
  4. Se Android Studio richiede una sincronizzazione Gradle, scegli OK.
  5. Assicurati che il tuo dispositivo Android sia collegato al computer e che la modalità sviluppatore sia abilitata. Fare clic sulla freccia verde Run .

Se selezioni la directory corretta, Android Studio crea un nuovo progetto e lo crea. Questo processo può richiedere alcuni minuti, a seconda della velocità del tuo computer e se hai utilizzato Android Studio per altri progetti. Una volta completata la build, Android Studio visualizza un messaggio BUILD SUCCESSFUL nel pannello di stato dell'output della build .

Facoltativo: per correggere gli errori di creazione aggiornando la versione del plug-in Android:

  1. Apri il file build.gradle nella directory del progetto.
  2. Modificare la versione degli strumenti Android come segue:

    // from: classpath
    'com.android.tools.build:gradle:4.2.2'
    // to: classpath
    'com.android.tools.build:gradle:4.1.2'
    
  3. Sincronizza il progetto selezionando: File > Sincronizza progetto con file Gradle .

Per eseguire il progetto:

  1. Da Android Studio, esegui il progetto selezionando Esegui > Esegui… .
  2. Seleziona un dispositivo Android collegato con una fotocamera per testare l'app.

Le sezioni successive mostrano le modifiche che devi apportare al tuo progetto esistente per aggiungere questa funzionalità alla tua app, utilizzando questa app di esempio come punto di riferimento.

Aggiungi dipendenze del progetto

Nella tua applicazione, devi aggiungere dipendenze di progetto specifiche per eseguire modelli di machine learning TensorFlow Lite e accedere a funzioni di utilità che convertono dati come immagini in un formato dati tensore che può essere elaborato dal modello che stai utilizzando.

L'app di esempio utilizza la libreria TensorFlow Lite Task for Vision per abilitare l'esecuzione del modello di machine learning di rilevamento oggetti. Le seguenti istruzioni spiegano come aggiungere le dipendenze della libreria richieste al tuo progetto di app Android.

Le seguenti istruzioni spiegano come aggiungere il progetto richiesto e le dipendenze del modulo al tuo progetto di app Android.

Per aggiungere dipendenze del modulo:

  1. Nel modulo che utilizza TensorFlow Lite, aggiorna il file build.gradle del modulo per includere le seguenti dipendenze. Nel codice di esempio, questo file si trova qui: ...examples/lite/examples/object_detection/android/app/build.gradle ( riferimento codice )

    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'
    }
    

    Il progetto deve includere la libreria di attività Vision ( tensorflow-lite-task-vision ). La libreria dell'unità di elaborazione grafica (GPU) ( tensorflow-lite-gpu-delegate-plugin ) fornisce l'infrastruttura per eseguire l'app su GPU e Delegate ( tensorflow-lite-gpu ) fornisce l'elenco di compatibilità.

  2. In Android Studio, sincronizza le dipendenze del progetto selezionando: File > Sincronizza progetto con file Gradle .

Inizializza il modello ML

Nella tua app Android, devi inizializzare il modello di machine learning TensorFlow Lite con i parametri prima di eseguire previsioni con il modello. Questi parametri di inizializzazione sono coerenti tra i modelli di rilevamento degli oggetti e possono includere impostazioni come soglie di precisione minime per le previsioni.

Un modello TensorFlow Lite include un file .tflite contenente il codice del modello e spesso include un file di etichette contenente i nomi delle classi previste dal modello. Nel caso del rilevamento di oggetti, le classi sono oggetti come una persona, un cane, un gatto o un'auto.

In questo esempio vengono scaricati diversi modelli specificati in download_models.gradle e la classe ObjectDetectorHelper fornisce un selettore per i modelli:

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

Per inizializzare il modello nella tua app:

  1. Aggiungi un file modello .tflite alla directory src/main/assets del tuo progetto di sviluppo, ad esempio: EfficientDet-Lite0 .
  2. Imposta una variabile statica per il nome del file del tuo modello. Nell'app di esempio imposti la variabile modelName su MODEL_EFFICIENTDETV0 per utilizzare il modello di rilevamento EfficientDet-Lite0.
  3. Imposta le opzioni per il modello, ad esempio la soglia di previsione, la dimensione del set di risultati e, facoltativamente, i delegati dell'accelerazione hardware:

    val optionsBuilder =
      ObjectDetector.ObjectDetectorOptions.builder()
        .setScoreThreshold(threshold)
        .setMaxResults(maxResults)
    
  4. Utilizza le impostazioni di questo oggetto per costruire un oggetto TensorFlow Lite ObjectDetector che contiene il modello:

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

Il setupObjectDetector imposta i seguenti parametri del modello:

  • Soglia di rilevamento
  • Numero massimo di risultati di rilevamento
  • Numero di thread di elaborazione da utilizzare ( BaseOptions.builder().setNumThreads(numThreads) )
  • Modello attuale ( modelName )
  • Oggetto ObjectDetector ( objectDetector )

Configura l'acceleratore hardware

Quando inizializzi un modello TensorFlow Lite nella tua applicazione, puoi utilizzare le funzionalità di accelerazione hardware per accelerare i calcoli di previsione del modello.

I delegati TensorFlow Lite sono moduli software che accelerano l'esecuzione di modelli di machine learning utilizzando hardware di elaborazione specializzato su un dispositivo mobile, come unità di elaborazione grafica (GPU), unità di elaborazione tensore (TPU) e processori di segnali digitali (DSP). L'utilizzo dei delegati per l'esecuzione dei modelli TensorFlow Lite è consigliato, ma non obbligatorio.

Il rilevatore di oggetti viene inizializzato utilizzando le impostazioni correnti sul thread che lo sta utilizzando. È possibile utilizzare i delegati CPU e NNAPI con rilevatori creati sul thread principale e utilizzati su un thread in background, ma il thread che ha inizializzato il rilevatore deve utilizzare il delegato GPU.

I delegati vengono impostati all'interno della funzione 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()
    }
}

Per ulteriori informazioni sull'utilizzo dei delegati di accelerazione hardware con TensorFlow Lite, consulta Delegati TensorFlow Lite .

Preparare i dati per il modello

Nella tua app Android, il tuo codice fornisce dati al modello per l'interpretazione trasformando i dati esistenti come i fotogrammi di immagine in un formato dati Tensor che può essere elaborato dal tuo modello. I dati in un tensore che passi a un modello devono avere dimensioni o forma specifiche che corrispondano al formato dei dati utilizzati per addestrare il modello.

Il modello EfficientDet-Lite0 utilizzato in questo esempio di codice accetta tensori che rappresentano immagini con una dimensione di 320 x 320, con tre canali (rosso, blu e verde) per pixel. Ogni valore nel tensore è un singolo byte compreso tra 0 e 255. Pertanto, per eseguire previsioni su nuove immagini, l'app deve trasformare i dati dell'immagine in oggetti dati tensore di tale dimensione e forma. L'API Vision della libreria attività TensorFlow Lite gestisce la trasformazione dei dati per te.

L'app usa un oggetto ImageAnalysis per estrarre immagini dalla fotocamera. Questo oggetto chiama la funzione detectObject con bitmap dalla fotocamera. I dati vengono ridimensionati e ruotati automaticamente da ImageProcessor in modo da soddisfare i requisiti dei dati di immagine del modello. L'immagine viene quindi tradotta in un oggetto TensorImage .

Per preparare i dati dal sottosistema della fotocamera affinché vengano elaborati dal modello ML:

  1. Crea un oggetto ImageAnalysis per estrarre le immagini nel formato richiesto:

    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. Collegare l'analizzatore al sottosistema della fotocamera e creare un buffer bitmap per contenere i dati ricevuti dalla fotocamera:

    .also {
      it.setAnalyzer(cameraExecutor) {
        image -> if (!::bitmapBuffer.isInitialized)
        { bitmapBuffer = Bitmap.createBitmap( image.width, image.height,
        Bitmap.Config.ARGB_8888 ) } detectObjects(image)
        }
      }
    
  3. Estrai i dati dell'immagine specifici necessari al modello e trasmetti le informazioni sulla rotazione dell'immagine:

    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. Completa eventuali trasformazioni finali dei dati e aggiungi i dati dell'immagine a un oggetto TensorImage , come mostrato nel metodo ObjectDetectorHelper.detect() dell'app di esempio:

    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))
    

Esegui previsioni

Nella tua app Android, una volta creato un oggetto TensorImage con dati di immagine nel formato corretto, puoi eseguire il modello rispetto a tali dati per produrre una previsione o un'inferenza .

Nella classe fragments/CameraFragment.kt dell'app di esempio, l'oggetto imageAnalyzer all'interno della funzione bindCameraUseCases passa automaticamente i dati al modello per le previsioni quando l'app è connessa alla fotocamera.

L'app usa il metodo cameraProvider.bindToLifecycle() per gestire il selettore della fotocamera, la finestra di anteprima e l'elaborazione del modello ML. La classe ObjectDetectorHelper.kt gestisce il passaggio dei dati dell'immagine nel modello. Per eseguire il modello e generare previsioni dai dati dell'immagine:

  • Esegui la previsione passando i dati dell'immagine alla funzione di previsione:

    val results = objectDetector?.detect(tensorImage)
    

L'oggetto Interprete TensorFlow Lite riceve questi dati, li esegue rispetto al modello e produce un elenco di previsioni. Per l'elaborazione continua dei dati da parte del modello, utilizzare il metodo runForMultipleInputsOutputs() in modo che gli oggetti Interpreter non vengano creati e quindi rimossi dal sistema per ogni esecuzione della previsione.

Gestire l'output del modello

Nella tua app Android, dopo aver eseguito i dati dell'immagine rispetto al modello di rilevamento degli oggetti, viene prodotto un elenco di previsioni che il codice dell'app deve gestire eseguendo logica aziendale aggiuntiva, visualizzando i risultati all'utente o eseguendo altre azioni.

L'output di qualsiasi modello TensorFlow Lite varia in termini di numero di previsioni prodotte (una o più) e di informazioni descrittive per ciascuna previsione. Nel caso di un modello di rilevamento di oggetti, le previsioni in genere includono dati per un riquadro di delimitazione che indica dove viene rilevato un oggetto nell'immagine. Nel codice di esempio, i risultati vengono passati alla funzione onResults in CameraFragment.kt , che funge da DetectorListener nel processo di rilevamento degli oggetti.

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

Per il modello utilizzato in questo esempio, ogni previsione include una posizione del riquadro di delimitazione per l'oggetto, un'etichetta per l'oggetto e un punteggio di previsione compreso tra 0 e 1 come Float che rappresenta la confidenza della previsione, dove 1 rappresenta il punteggio di confidenza più alto . In generale, i pronostici con un punteggio inferiore al 50% (0,5) sono considerati inconcludenti. Tuttavia, il modo in cui gestisci i risultati della previsione di basso valore dipende da te e dalle esigenze della tua applicazione.

Per gestire i risultati della previsione del modello:

  1. Utilizza un pattern listener per passare i risultati al codice dell'app o agli oggetti dell'interfaccia utente. L'app di esempio utilizza questo modello per passare i risultati del rilevamento dall'oggetto ObjectDetectorHelper all'oggetto CameraFragment :

    objectDetectorListener.onResults(
    // instance of CameraFragment
        results,
        inferenceTime,
        tensorImage.height,
        tensorImage.width)
    
  2. Agire sui risultati, ad esempio mostrando la previsione all'utente. L'esempio disegna una sovrapposizione sull'oggetto CameraPreview per mostrare il risultato:

    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 volta che il modello ha restituito un risultato di previsione, l'applicazione può agire in base a tale previsione presentando il risultato all'utente o eseguendo logica aggiuntiva. Nel caso del codice di esempio, l'applicazione disegna un riquadro attorno all'oggetto identificato e visualizza il nome della classe sullo schermo.

Prossimi passi

  • Esplora i vari usi di TensorFlow Lite negli esempi .
  • Scopri di più sull'utilizzo dei modelli di machine learning con TensorFlow Lite nella sezione Modelli .
  • Scopri di più sull'implementazione del machine learning nella tua applicazione mobile nella Guida per sviluppatori TensorFlow Lite .