Détection d'objets avec Android

Ce didacticiel vous montre comment créer une application Android à l'aide de TensorFlow Lite pour détecter en continu des objets dans les images capturées par la caméra d'un appareil. Cette application est conçue pour un appareil Android physique. Si vous mettez à jour un projet existant, vous pouvez utiliser l'exemple de code comme référence et passer directement aux instructions de modification de votre projet .

Démo animée de détection d'objets

Présentation de la détection d'objets

La détection d'objets est la tâche d'apprentissage automatique consistant à identifier la présence et l'emplacement de plusieurs classes d'objets dans une image. Un modèle de détection d'objets est formé sur un ensemble de données qui contient un ensemble d'objets connus.

Le modèle entraîné reçoit des images en entrée et tente de catégoriser les éléments des images à partir de l'ensemble des classes connues pour lesquelles il a été entraîné à reconnaître. Pour chaque image, le modèle de détection d'objet génère une liste des objets qu'il détecte, l'emplacement d'un cadre de délimitation pour chaque objet et un score qui indique le degré de confiance de l'objet étant correctement classé.

Modèles et ensemble de données

Ce didacticiel utilise des modèles qui ont été formés à l'aide de l' ensemble de données COCO . COCO est un ensemble de données de détection d'objets à grande échelle contenant 330 000 images, 1,5 million d'instances d'objets et 80 catégories d'objets.

Vous avez la possibilité d'utiliser l'un des modèles pré-entraînés suivants :

  • EfficientDet-Lite0 [Recommandé] - un modèle de détection d'objets léger avec un extracteur de fonctionnalités BiFPN, un prédicteur de boîte partagée et une perte focale. Le mAP (mean Average Precision) pour l’ensemble de données de validation COCO 2017 est de 25,69 %.

  • EfficientDet-Lite1 - un modèle de détection d'objets EfficientDet de taille moyenne. Le mAP pour l'ensemble de données de validation COCO 2017 est de 30,55 %.

  • EfficientDet-Lite2 - un modèle de détection d'objets EfficientDet plus grand. Le mAP pour l'ensemble de données de validation COCO 2017 est de 33,97 %.

  • MobileNetV1-SSD - un modèle extrêmement léger optimisé pour fonctionner avec TensorFlow Lite pour la détection d'objets. Le mAP pour l'ensemble de données de validation COCO 2017 est de 21 %.

Pour ce didacticiel, le modèle EfficientDet-Lite0 établit un bon équilibre entre taille et précision.

Le téléchargement, l'extraction et le placement des modèles dans le dossier des ressources sont gérés automatiquement par le fichier download.gradle , qui est exécuté au moment de la construction. Vous n'avez pas besoin de télécharger manuellement les modèles TFLite dans le projet.

Exemple d'installation et d'exécution

Pour configurer l'application de détection d'objets, téléchargez l'exemple depuis GitHub et exécutez-le à l'aide d' Android Studio . Les sections suivantes de ce didacticiel explorent les sections pertinentes de l'exemple de code afin que vous puissiez les appliquer à vos propres applications Android.

Configuration requise

  • Android Studio version 2021.1.1 (Bumblebee) ou supérieure.
  • SDK Android version 31 ou supérieure
  • Appareil Android avec une version minimale du système d'exploitation du SDK 24 (Android 7.0 - Nougat) avec le mode développeur activé.

Obtenez l'exemple de code

Créez une copie locale de l'exemple de code. Vous utiliserez ce code pour créer un projet dans Android Studio et exécuter l'exemple d'application.

Pour cloner et configurer l'exemple de code :

  1. Cloner le dépôt git
    git clone https://github.com/tensorflow/examples.git
    
  2. Vous pouvez éventuellement configurer votre instance git pour utiliser une extraction fragmentée, afin de disposer uniquement des fichiers pour l'exemple d'application de détection d'objets :
    cd examples
    git sparse-checkout init --cone
    git sparse-checkout set lite/examples/object_detection/android
    

Importer et exécuter le projet

Créez un projet à partir de l'exemple de code téléchargé, générez le projet, puis exécutez-le.

Pour importer et créer l'exemple de projet de code :

  1. Démarrez Android Studio .
  2. Depuis Android Studio, sélectionnez Fichier > Nouveau > Importer un projet .
  3. Accédez au répertoire de code d'exemple contenant le fichier build.gradle ( .../examples/lite/examples/object_detection/android/build.gradle ) et sélectionnez ce répertoire.
  4. Si Android Studio demande une synchronisation Gradle, choisissez OK.
  5. Assurez-vous que votre appareil Android est connecté à votre ordinateur et que le mode développeur est activé. Cliquez sur la flèche verte Run .

Si vous sélectionnez le bon répertoire, Android Studio crée un nouveau projet et le construit. Ce processus peut prendre quelques minutes, selon la vitesse de votre ordinateur et si vous avez utilisé Android Studio pour d'autres projets. Une fois la construction terminée, Android Studio affiche un message BUILD SUCCESSFUL dans le panneau d'état de sortie de construction .

Facultatif : Pour corriger les erreurs de build en mettant à jour la version du plugin Android :

  1. Ouvrez le fichier build.gradle dans le répertoire du projet.
  2. Modifiez la version des outils Android comme suit :

    // from: classpath
    'com.android.tools.build:gradle:4.2.2'
    // to: classpath
    'com.android.tools.build:gradle:4.1.2'
    
  3. Synchronisez le projet en sélectionnant : Fichier > Synchroniser le projet avec les fichiers Gradle .

Pour exécuter le projet :

  1. Depuis Android Studio, exécutez le projet en sélectionnant Exécuter > Exécuter… .
  2. Sélectionnez un appareil Android connecté avec une caméra pour tester l'application.

Les sections suivantes vous montrent les modifications que vous devez apporter à votre projet existant pour ajouter cette fonctionnalité à votre propre application, en utilisant cet exemple d'application comme point de référence.

Ajouter des dépendances de projet

Dans votre propre application, vous devez ajouter des dépendances de projet spécifiques pour exécuter des modèles d'apprentissage automatique TensorFlow Lite et accéder aux fonctions utilitaires qui convertissent des données telles que des images dans un format de données tensoriel pouvant être traité par le modèle que vous utilisez.

L'exemple d'application utilise la bibliothèque de tâches TensorFlow Lite pour la vision afin de permettre l'exécution du modèle d'apprentissage automatique de détection d'objets. Les instructions suivantes expliquent comment ajouter les dépendances de bibliothèque requises à votre propre projet d'application Android.

Les instructions suivantes expliquent comment ajouter les dépendances de projet et de module requises à votre propre projet d'application Android.

Pour ajouter des dépendances de module :

  1. Dans le module qui utilise TensorFlow Lite, mettez à jour le fichier build.gradle du module pour inclure les dépendances suivantes. Dans l'exemple de code, ce fichier se trouve ici : ...examples/lite/examples/object_detection/android/app/build.gradle ( référence du code )

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

    Le projet doit inclure la bibliothèque de tâches Vision ( tensorflow-lite-task-vision ). La bibliothèque d'unité de traitement graphique (GPU) ( tensorflow-lite-gpu-delegate-plugin ) fournit l'infrastructure permettant d'exécuter l'application sur GPU, et Delegate ( tensorflow-lite-gpu ) fournit la liste de compatibilité.

  2. Dans Android Studio, synchronisez les dépendances du projet en sélectionnant : Fichier > Synchroniser le projet avec les fichiers Gradle .

Initialiser le modèle ML

Dans votre application Android, vous devez initialiser le modèle de machine learning TensorFlow Lite avec des paramètres avant d'exécuter des prédictions avec le modèle. Ces paramètres d'initialisation sont cohérents dans tous les modèles de détection d'objets et peuvent inclure des paramètres tels que des seuils de précision minimaux pour les prédictions.

Un modèle TensorFlow Lite comprend un fichier .tflite contenant le code du modèle et inclut fréquemment un fichier d'étiquettes contenant les noms des classes prédites par le modèle. Dans le cas de la détection d'objets, les classes sont des objets tels qu'une personne, un chien, un chat ou une voiture.

Cet exemple télécharge plusieurs modèles spécifiés dans download_models.gradle , et la classe ObjectDetectorHelper fournit un sélecteur pour les modèles :

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

Pour initialiser le modèle dans votre application :

  1. Ajoutez un fichier modèle .tflite au répertoire src/main/assets de votre projet de développement, tel que : EfficientDet-Lite0 .
  2. Définissez une variable statique pour le nom de fichier de votre modèle. Dans l'exemple d'application, vous définissez la variable modelName sur MODEL_EFFICIENTDETV0 pour utiliser le modèle de détection EfficientDet-Lite0.
  3. Définissez les options du modèle, telles que le seuil de prédiction, la taille de l'ensemble de résultats et éventuellement les délégués de l'accélération matérielle :

    val optionsBuilder =
      ObjectDetector.ObjectDetectorOptions.builder()
        .setScoreThreshold(threshold)
        .setMaxResults(maxResults)
    
  4. Utilisez les paramètres de cet objet pour créer un objet TensorFlow Lite ObjectDetector contenant le modèle :

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

Le setupObjectDetector configure les paramètres de modèle suivants :

  • Seuil de détection
  • Nombre maximum de résultats de détection
  • Nombre de threads de traitement à utiliser ( BaseOptions.builder().setNumThreads(numThreads) )
  • Modèle réel ( modelName )
  • Objet ObjectDetector ( objectDetector )

Configurer l'accélérateur matériel

Lors de l'initialisation d'un modèle TensorFlow Lite dans votre application, vous pouvez utiliser les fonctionnalités d'accélération matérielle pour accélérer les calculs de prédiction du modèle.

Les délégués TensorFlow Lite sont des modules logiciels qui accélèrent l'exécution de modèles d'apprentissage automatique à l'aide de matériel de traitement spécialisé sur un appareil mobile, tels que des unités de traitement graphique (GPU), des unités de traitement tensoriel (TPU) et des processeurs de signal numérique (DSP). L'utilisation de délégués pour exécuter des modèles TensorFlow Lite est recommandée, mais pas obligatoire.

Le détecteur d'objets est initialisé en utilisant les paramètres actuels du thread qui l'utilise. Vous pouvez utiliser des délégués CPU et NNAPI avec des détecteurs créés sur le thread principal et utilisés sur un thread d'arrière-plan, mais le thread qui a initialisé le détecteur doit utiliser le délégué GPU.

Les délégués sont définis dans la fonction 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()
    }
}

Pour plus d'informations sur l'utilisation de délégués d'accélération matérielle avec TensorFlow Lite, consultez Délégués TensorFlow Lite .

Préparer les données pour le modèle

Dans votre application Android, votre code fournit des données au modèle à des fins d'interprétation en transformant les données existantes telles que les cadres d'image en un format de données Tensor pouvant être traité par votre modèle. Les données d'un Tensor que vous transmettez à un modèle doivent avoir des dimensions ou une forme spécifiques qui correspondent au format des données utilisées pour entraîner le modèle.

Le modèle EfficientDet-Lite0 utilisé dans cet exemple de code accepte des Tensors représentant des images d'une dimension de 320 x 320, avec trois canaux (rouge, bleu et vert) par pixel. Chaque valeur du tenseur est un seul octet compris entre 0 et 255. Ainsi, pour exécuter des prédictions sur de nouvelles images, votre application doit transformer ces données d'image en objets de données Tensor de cette taille et de cette forme. L'API TensorFlow Lite Task Library Vision gère la transformation des données pour vous.

L'application utilise un objet ImageAnalysis pour extraire des images de la caméra. Cet objet appelle la fonction detectObject avec le bitmap de la caméra. Les données sont automatiquement redimensionnées et pivotées par ImageProcessor afin qu'elles répondent aux exigences en matière de données d'image du modèle. L'image est ensuite traduite en un objet TensorImage .

Pour préparer les données du sous-système de caméra à traiter par le modèle ML :

  1. Créez un objet ImageAnalysis pour extraire les images au format requis :

    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. Connectez l'analyseur au sous-système de la caméra et créez un tampon bitmap pour contenir les données reçues de la caméra :

    .also {
      it.setAnalyzer(cameraExecutor) {
        image -> if (!::bitmapBuffer.isInitialized)
        { bitmapBuffer = Bitmap.createBitmap( image.width, image.height,
        Bitmap.Config.ARGB_8888 ) } detectObjects(image)
        }
      }
    
  3. Extrayez les données d'image spécifiques nécessaires au modèle et transmettez les informations de rotation de l'image :

    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. Effectuez toutes les transformations de données finales et ajoutez les données d'image à un objet TensorImage , comme indiqué dans la méthode ObjectDetectorHelper.detect() de l'exemple d'application :

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

Exécuter des prédictions

Dans votre application Android, une fois que vous avez créé un objet TensorImage avec des données d'image au format correct, vous pouvez exécuter le modèle sur ces données pour produire une prédiction ou une inférence .

Dans la classe fragments/CameraFragment.kt de l'exemple d'application, l'objet imageAnalyzer dans la fonction bindCameraUseCases transmet automatiquement les données au modèle pour les prédictions lorsque l'application est connectée à la caméra.

L'application utilise la méthode cameraProvider.bindToLifecycle() pour gérer le sélecteur de caméra, la fenêtre d'aperçu et le traitement du modèle ML. La classe ObjectDetectorHelper.kt gère la transmission des données d'image dans le modèle. Pour exécuter le modèle et générer des prédictions à partir des données d'image :

  • Exécutez la prédiction en transmettant les données d'image à votre fonction de prédiction :

    val results = objectDetector?.detect(tensorImage)
    

L'objet TensorFlow Lite Interpreter reçoit ces données, les exécute sur le modèle et produit une liste de prédictions. Pour un traitement continu des données par le modèle, utilisez la méthode runForMultipleInputsOutputs() afin que les objets Interpreter ne soient pas créés puis supprimés par le système pour chaque exécution de prédiction.

Gérer la sortie du modèle

Dans votre application Android, après avoir exécuté des données d'image sur le modèle de détection d'objets, celle-ci produit une liste de prédictions que le code de votre application doit gérer en exécutant une logique métier supplémentaire, en affichant les résultats à l'utilisateur ou en effectuant d'autres actions.

Le résultat d'un modèle TensorFlow Lite donné varie en termes du nombre de prédictions qu'il produit (une ou plusieurs) et des informations descriptives pour chaque prédiction. Dans le cas d'un modèle de détection d'objets, les prédictions incluent généralement des données pour un cadre de délimitation qui indique où un objet est détecté dans l'image. Dans l'exemple de code, les résultats sont transmis à la fonction onResults dans CameraFragment.kt , qui agit comme DetectorListener sur le processus de détection d'objet.

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

Pour le modèle utilisé dans cet exemple, chaque prédiction comprend un emplacement de cadre englobant pour l'objet, une étiquette pour l'objet et un score de prédiction compris entre 0 et 1 sous forme de flotteur représentant la confiance de la prédiction, 1 étant l'indice de confiance le plus élevé. . En général, les prédictions avec un score inférieur à 50 % (0,5) sont considérées comme non concluantes. Toutefois, la manière dont vous gérez les résultats de prédiction de faible valeur dépend de vous et des besoins de votre application.

Pour gérer les résultats de prédiction du modèle :

  1. Utilisez un modèle d'écoute pour transmettre les résultats au code de votre application ou aux objets de l'interface utilisateur. L'exemple d'application utilise ce modèle pour transmettre les résultats de détection de l'objet ObjectDetectorHelper à l'objet CameraFragment :

    objectDetectorListener.onResults(
    // instance of CameraFragment
        results,
        inferenceTime,
        tensorImage.height,
        tensorImage.width)
    
  2. Agissez sur les résultats, par exemple en affichant la prédiction à l'utilisateur. L'exemple dessine une superposition sur l'objet CameraPreview pour afficher le résultat :

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

Une fois que le modèle a renvoyé un résultat de prédiction, votre application peut agir sur cette prédiction en présentant le résultat à votre utilisateur ou en exécutant une logique supplémentaire. Dans le cas de l'exemple de code, l'application dessine un cadre de délimitation autour de l'objet identifié et affiche le nom de la classe à l'écran.

Prochaines étapes

  • Découvrez diverses utilisations de TensorFlow Lite dans les exemples .
  • Apprenez-en davantage sur l'utilisation de modèles de machine learning avec TensorFlow Lite dans la section Modèles .
  • Apprenez-en davantage sur la mise en œuvre du machine learning dans votre application mobile dans le Guide du développeur TensorFlow Lite .