1. Avant de commencer
Taper du code est un excellent moyen de développer votre mémoire musculaire et d'approfondir votre compréhension du contenu. Bien que le copier-coller puisse vous faire gagner du temps, investir dans cette pratique peut vous permettre de gagner en efficacité et d'améliorer vos compétences en programmation à long terme.
Dans cet atelier de programmation, vous allez apprendre à créer une application Android qui effectue une segmentation d'image en temps réel sur un flux vidéo en direct à l'aide du nouveau runtime de Google pour TensorFlow Lite, LiteRT. Vous allez prendre une application Android de démarrage et y ajouter des fonctionnalités de segmentation d'images. Nous aborderons également les étapes de prétraitement, d'inférence et de post-traitement. Vous découvrirez comment :
- Créer une application Android qui segmente les images en temps réel.
- Intégrez un modèle de segmentation d'images LiteRT pré-entraîné.
- Prétraitez l'image d'entrée pour le modèle.
- Utilisez l'environnement d'exécution LiteRT pour l'accélération du processeur et du GPU.
- Comprendre comment traiter la sortie du modèle pour afficher le masque de segmentation.
- Découvrez comment ajuster la caméra avant.
Au final, vous obtiendrez un résultat semblable à l'image ci-dessous :

Prérequis
Cet atelier de programmation s'adresse aux développeurs mobiles expérimentés qui souhaitent acquérir de l'expérience dans le domaine du machine learning. Vous devez maîtriser les éléments suivants :
- Développement Android avec Kotlin et Android Studio
- Concepts de base du traitement des images
Points abordés
- Comment intégrer et utiliser le runtime LiteRT dans une application Android.
- Comment effectuer la segmentation d'images à l'aide d'un modèle LiteRT pré-entraîné.
- Comment prétraiter l'image d'entrée pour le modèle.
- Comment exécuter l'inférence pour le modèle.
- Comment traiter la sortie d'un modèle de segmentation pour visualiser les résultats.
- Utiliser CameraX pour le traitement du flux de caméra en temps réel
Prérequis
- Une version récente d'Android Studio (testée sur la version 2025.1.1).
- Un appareil Android physique. Il est préférable de le tester sur des appareils Galaxy et Pixel.
- Exemple de code (depuis GitHub).
- Connaissances de base du développement Android en Kotlin.
2. Segmentation d'image
La segmentation d'images est une tâche de vision par ordinateur qui consiste à partitionner une image en plusieurs segments ou régions. Contrairement à la détection d'objets, qui dessine un cadre de délimitation autour d'un objet, la segmentation d'image attribue une classe ou une étiquette spécifique à chaque pixel de l'image. Vous obtenez ainsi une compréhension beaucoup plus détaillée et précise du contenu de l'image, ce qui vous permet de connaître la forme et les limites exactes de chaque objet.
Par exemple, au lieu de simplement savoir qu'une personne se trouve dans une boîte, vous pouvez savoir exactement quels pixels lui appartiennent. Ce tutoriel explique comment effectuer une segmentation d'image en temps réel sur un appareil Android à l'aide d'un modèle de machine learning pré-entraîné.

LiteRT : repousser les limites du ML sur l'appareil
LiteRT est une technologie clé qui permet une segmentation haute fidélité en temps réel sur les appareils mobiles. LiteRT est l'environnement d'exécution hautes performances de nouvelle génération de Google pour TensorFlow Lite. Il est conçu pour obtenir les meilleures performances possibles du matériel sous-jacent.
Pour ce faire, il utilise de manière intelligente et optimisée des accélérateurs matériels tels que le GPU (Graphics Processing Unit) et le NPU (Neural Processing Unit). En déchargeant la charge de travail de calcul intense du modèle de segmentation du CPU à usage général vers ces processeurs spécialisés, LiteRT réduit considérablement le temps d'inférence. Cette accélération permet d'exécuter des modèles complexes de manière fluide sur un flux vidéo en direct, ce qui repousse les limites de ce que nous pouvons accomplir avec le machine learning directement sur votre téléphone. Sans ce niveau de performances, la segmentation en temps réel serait trop lente et saccadée pour offrir une bonne expérience utilisateur.
3. Configuration
Cloner le dépôt
Commencez par cloner le dépôt pour LiteRT :
git clone https://github.com/google-ai-edge/litert-samples.git
litert-samples/v2/image_segmentation est le répertoire contenant toutes les ressources dont vous aurez besoin. Pour cet atelier de programmation, vous n'aurez besoin que du projet kotlin_cpu_gpu/android_starter. Si vous êtes bloqué, vous pouvez consulter le projet finalisé : kotlin_cpu_gpu/android
Remarque sur les chemins d'accès aux fichiers
Ce tutoriel spécifie les chemins d'accès aux fichiers au format Linux/macOS. Si vous utilisez Windows, vous devrez ajuster les chemins d'accès en conséquence.
Il est également important de noter la distinction entre la vue du projet Android Studio et une vue standard du système de fichiers. La vue du projet Android Studio est une représentation structurée des fichiers de votre projet, organisée pour le développement Android. Les chemins d'accès aux fichiers de ce tutoriel font référence aux chemins d'accès au système de fichiers, et non à ceux de la vue du projet Android Studio.
Importer l'application de départ
Commençons par importer l'application de démarrage dans Android Studio.
- Ouvrez Android Studio et sélectionnez Open (Ouvrir).

- Accédez au répertoire
kotlin_cpu_gpu/android_starteret ouvrez-le.

Pour vous assurer que toutes les dépendances sont disponibles pour votre application, vous devez synchroniser votre projet avec les fichiers Gradle une fois le processus d'importation terminé.
- Sélectionnez Sync Project with Gradle Files (Synchroniser le projet avec les fichiers Gradle) dans la barre d'outils Android Studio.

- Veuillez ne pas ignorer cette étape. Si elle ne fonctionne pas, le reste du tutoriel n'aura aucun sens.
Exécuter l'application de départ
Maintenant que vous avez importé le projet dans Android Studio, vous êtes prêt à exécuter l'application pour la première fois.
Connectez votre appareil Android à votre ordinateur via USB, puis cliquez sur Run (Exécuter) dans la barre d'outils Android Studio.

L'application doit se lancer sur votre appareil. Un flux vidéo en direct s'affiche, mais aucune segmentation n'est encore effectuée. Toutes les modifications de fichiers que vous effectuerez dans ce tutoriel se trouveront dans le répertoire litert-samples/v2/image_segmentation/kotlin_cpu_gpu/android_starter/app/src/main/java/com/google/ai/edge/examples/image_segmentation (vous savez maintenant pourquoi Android Studio le restructure 😃).

Vous verrez également des commentaires TODO dans les fichiers ImageSegmentationHelper.kt, MainViewModel.kt et view/SegmentationOverlay.kt. Dans les étapes suivantes, vous allez implémenter la fonctionnalité de segmentation d'image en remplissant ces TODO.
4. Comprendre l'application de démarrage
L'application de démarrage possède déjà une UI de base et une logique de gestion de la caméra. Voici un aperçu rapide des fichiers clés :
app/src/main/java/com/google/ai/edge/examples/image_segmentation/MainActivity.kt: il s'agit du point d'entrée principal de l'application. Il configure l'UI à l'aide de Jetpack Compose et gère les autorisations de l'appareil photo.app/src/main/java/com/google/ai/edge/examples/image_segmentation/MainViewModel.kt: ce ViewModel gère l'état de l'UI et orchestre le processus de segmentation d'image.app/src/main/java/com/google/ai/edge/examples/image_segmentation/ImageSegmentationHelper.kt: c'est ici que nous ajouterons la logique de base pour la segmentation d'image. Il gérera le chargement du modèle, le traitement des images de la caméra et l'exécution de l'inférence.app/src/main/java/com/google/ai/edge/examples/image_segmentation/view/CameraScreen.kt: cette fonction composable affiche l'aperçu de la caméra et la superposition de segmentation.app/download_model.gradle: ce script téléchargeselfie_multiclass.tflite. Il s'agit du modèle de segmentation d'images TensorFlow Lite pré-entraîné que nous allons utiliser.
5. Comprendre LiteRT et ajouter des dépendances
Ajoutons maintenant la fonctionnalité de segmentation d'image à l'application de démarrage.
1. Ajouter la dépendance LiteRT
Vous devez d'abord ajouter la bibliothèque LiteRT à votre projet. Il s'agit de la première étape cruciale pour activer le machine learning sur l'appareil avec le runtime optimisé de Google.
Ouvrez le fichier app/build.gradle.kts et ajoutez la ligne suivante au bloc dependencies :
// LiteRT for on-device ML
implementation(libs.litert)
Après avoir ajouté la dépendance, synchronisez votre projet avec les fichiers Gradle en cliquant sur le bouton Sync Now (Synchroniser maintenant) qui s'affiche en haut à droite d'Android Studio.

2. Comprendre les principales API LiteRT
OuvrirImageSegmentationHelper.kt
Avant d'écrire le code d'implémentation, il est important de comprendre les composants principaux de l'API LiteRT que vous allez utiliser. Assurez-vous d'importer à partir du package com.google.ai.edge.litert, puis ajoutez les importations suivantes en haut de ImageSegmentationHelper.kt :
import com.google.ai.edge.litert.Accelerator
import com.google.ai.edge.litert.CompiledModel
CompiledModel: classe centrale pour interagir avec votre modèle TFLite. Il s'agit d'un modèle précompilé et optimisé pour un accélérateur matériel spécifique (comme le processeur ou le GPU). Cette précompilation est une fonctionnalité clé de LiteRT qui permet une inférence plus rapide et plus efficace.CompiledModel.Options: vous utilisez cette classe de compilateur pour configurerCompiledModel. Le paramètre le plus important consiste à spécifier l'accélérateur matériel que vous souhaitez utiliser pour exécuter votre modèle.Accelerator: cette énumération vous permet de choisir le matériel pour l'inférence. Le projet de démarrage est déjà configuré pour gérer ces options :Accelerator.CPU: pour exécuter le modèle sur le processeur de l'appareil. Il s'agit de l'option la plus universellement compatible.Accelerator.GPU: pour exécuter le modèle sur le GPU de l'appareil. C'est souvent beaucoup plus rapide que le processeur pour les modèles basés sur des images.
- Tampons d'entrée et de sortie (
TensorBuffer) : LiteRT utiliseTensorBufferpour les entrées et sorties du modèle. Cela vous permet de contrôler précisément la mémoire et d'éviter les copies de données inutiles. Vous obtiendrez ces tampons directement à partir de votre instanceCompiledModelà l'aide demodel.createInputBuffers()etmodel.createOutputBuffers(), puis vous y écrirez vos données d'entrée et y lirez les résultats. model.run(): fonction qui exécute l'inférence. Vous lui transmettez les tampons d'entrée et de sortie, et LiteRT gère la tâche complexe d'exécution du modèle sur l'accélérateur matériel sélectionné.
6. Terminer l'implémentation initiale d'ImageSegmentationHelper
Il est maintenant temps d'écrire du code. Vous allez effectuer l'implémentation initiale de ImageSegmentationHelper.kt. Cela implique de configurer la classe privée Segmenter pour contenir le modèle LiteRT et d'implémenter la fonction cleanup() pour le libérer correctement.
- Terminez la classe
Segmenteret la fonctioncleanup(): dans le fichierImageSegmentationHelper.kt, vous trouverez le squelette d'une classe privée nomméeSegmenteret d'une fonction nomméecleanup(). Tout d'abord, complétez la classeSegmenteren définissant son constructeur pour contenir le modèle, en créant des propriétés pour les tampons d'entrée/sortie et en ajoutant une méthodeclose()pour libérer le modèle. Implémentez ensuite la fonctioncleanup()pour appeler cette nouvelle méthodeclose().Remplacez la classeSegmenteret la fonctioncleanup()existantes par les éléments suivants (ligne 83 environ) :private class Segmenter( // Add this argument private val model: CompiledModel, private val coloredLabels: List<ColoredLabel>, ) { // Add these private vals private val inputBuffers = model.createInputBuffers() private val outputBuffers = model.createOutputBuffers() fun cleanup() { // cleanup buffers inputBuffers.forEach { it.close() } outputBuffers.forEach { it.close() } // cleanup model model.close() } } - Définissez la méthode toAccelerator : cette méthode mappe les énumérations d'accélérateur définies à partir du menu d'accélérateur aux énumérations d'accélérateur spécifiques aux modules LiteRT importés (ligne 225 environ) :
fun toAccelerator(acceleratorEnum: AcceleratorEnum): Accelerator { return when (acceleratorEnum) { AcceleratorEnum.CPU -> Accelerator.CPU AcceleratorEnum.GPU -> Accelerator.GPU } } - Initialisez
CompiledModel: recherchez maintenant la fonctioninitSegmenter. C'est là que vous allez créer l'instanceCompiledModelet l'utiliser pour instancier votre classeSegmenterdésormais définie. Ce code configure le modèle avec l'accélérateur spécifié (CPU ou GPU) et le prépare pour l'inférence. RemplacezTODOdansinitSegmenterpar l'implémentation suivante (Cmd/Ctrl+f "initSegmenter" ou ligne 62) :cleanup() try { withContext(singleThreadDispatcher) { val model = CompiledModel.create( context.assets, "selfie_multiclass.tflite", CompiledModel.Options(toAccelerator(acceleratorEnum)), null, ) segmenter = Segmenter(model, coloredLabels) Log.d(TAG, "Created an image segmenter") } } catch (e: Exception) { Log.i(TAG, "Create LiteRT from selfie_multiclass is failed: ${e.message}") _error.emit(e) }
7. Démarrer la segmentation et le prétraitement
Maintenant que nous avons un modèle, nous devons déclencher le processus de segmentation et préparer les données d'entrée pour le modèle.
Segmentation des déclencheurs
Le processus de segmentation commence dans MainViewModel.kt, qui reçoit les frames de la caméra.
OuvrirMainViewModel.kt
- Déclencher la segmentation à partir des images de la caméra : les fonctions
segmentdansMainViewModelsont le point d'entrée de notre tâche de segmentation. Elles sont appelées chaque fois qu'une nouvelle image est disponible depuis l'appareil photo ou sélectionnée dans la galerie. Ces fonctions appellent ensuite la méthodesegmentdans notreImageSegmentationHelper. Remplacez lesTODOdans les deux fonctionssegmentpar ce qui suit (ligne 107 environ) :// For ImageProxy (from CameraX) fun segment(imageProxy: ImageProxy) { segmentJob = viewModelScope.launch { imageSegmentationHelper.segment(imageProxy.toBitmap(), imageProxy.imageInfo.rotationDegrees) imageProxy.close() } } // For Bitmaps (from gallery) fun segment(bitmap: Bitmap, rotationDegrees: Int) { segmentJob = viewModelScope.launch { val argbBitmap = bitmap.copy(Bitmap.Config.ARGB_8888, true) imageSegmentationHelper.segment(argbBitmap, rotationDegrees) } }
Prétraiter l'image
Revenons maintenant à ImageSegmentationHelper.kt pour gérer le prétraitement des images.
OuvrirImageSegmentationHelper.kt
- Implémenter la fonction publique
segment: cette fonction sert de wrapper qui appelle la fonction privéesegmentdans la classeSegmenter. RemplacezTODOpar (~ligne 95) :try { withContext(singleThreadDispatcher) { segmenter?.segment(bitmap, rotationDegrees)?.let { if (isActive) _segmentation.emit(it) } } } catch (e: Exception) { Log.i(TAG, "Image segment error occurred: ${e.message}") _error.emit(e) } - Implémenter le prétraitement : la fonction privée
segmentà l'intérieur de la classeSegmenterest l'endroit où nous effectuerons les transformations nécessaires sur l'image d'entrée pour la préparer au modèle. Cela inclut la mise à l'échelle, la rotation et la normalisation de l'image. Cette fonction appellera ensuite une autre fonction privéesegmentpour effectuer l'inférence. RemplacezTODOdans la fonctionsegment(bitmap: Bitmap, ...)par ce qui suit (ligne 121 environ) :val totalStartTime = SystemClock.uptimeMillis() val rotation = -rotationDegrees / 90 val (h, w) = Pair(256, 256) // Preprocessing val preprocessStartTime = SystemClock.uptimeMillis() var image = bitmap.scale(w, h, true) image = rot90Clockwise(image, rotation) val inputFloatArray = normalize(image, 127.5f, 127.5f) Log.d(TAG, "Preprocessing time: ${SystemClock.uptimeMillis() - preprocessStartTime} ms") // Inference val inferenceStartTime = SystemClock.uptimeMillis() val segmentResult = segment(inputFloatArray) Log.d(TAG, "Inference time: ${SystemClock.uptimeMillis() - inferenceStartTime} ms") Log.d(TAG, "Total segmentation time: ${SystemClock.uptimeMillis() - totalStartTime} ms") return SegmentationResult(segmentResult, SystemClock.uptimeMillis() - inferenceStartTime)
8. Inférence primaire avec LiteRT
Maintenant que les données d'entrée sont prétraitées, nous pouvons exécuter l'inférence principale à l'aide de LiteRT.
OuvrirImageSegmentationHelper.kt
- Implémenter l'exécution du modèle : la fonction privée
segment(inputFloatArray: FloatArray)est l'endroit où nous interagissons directement avec la méthoderun()de LiteRT. Nous écrivons nos données prétraitées dans le tampon d'entrée, exécutons le modèle et lisons les résultats du tampon de sortie. RemplacezTODOdans cette fonction par (~ligne 188) :val (h, w, c) = Triple(256, 256, 6) // MODEL EXECUTION PHASE val modelExecStartTime = SystemClock.uptimeMillis() // Write input data - measure time val bufferWriteStartTime = SystemClock.uptimeMillis() inputBuffers[0].writeFloat(inputFloatArray) val bufferWriteTime = SystemClock.uptimeMillis() - bufferWriteStartTime Log.d(TAG, "Buffer write time: $bufferWriteTime ms") // Optional tensor inspection logTensorStats("Input tensor", inputFloatArray) // Run model inference - measure time val modelRunStartTime = SystemClock.uptimeMillis() model.run(inputBuffers, outputBuffers) val modelRunTime = SystemClock.uptimeMillis() - modelRunStartTime Log.d(TAG, "Model.run() time: $modelRunTime ms") // Read output data - measure time val bufferReadStartTime = SystemClock.uptimeMillis() val outputFloatArray = outputBuffers[0].readFloat() val outputBuffer = FloatBuffer.wrap(outputFloatArray) val bufferReadTime = SystemClock.uptimeMillis() - bufferReadStartTime Log.d(TAG, "Buffer read time: $bufferReadTime ms") val modelExecTime = SystemClock.uptimeMillis() - modelExecStartTime Log.d(TAG, "Total model execution time: $modelExecTime ms") // Optional tensor inspection logTensorStats("Output tensor", outputFloatArray) // POSTPROCESSING PHASE val postprocessStartTime = SystemClock.uptimeMillis() // Process mask from model output val inferenceData = InferenceData(width = w, height = h, channels = c, buffer = outputBuffer) val mask = processImage(inferenceData) val postprocessTime = SystemClock.uptimeMillis() - postprocessStartTime Log.d(TAG, "Postprocessing time (mask creation): $postprocessTime ms") return Segmentation( listOf(Mask(mask, inferenceData.width, inferenceData.height)), coloredLabels, )
9. Post-traitement et affichage de la superposition
Après l'exécution de l'inférence, nous obtenons une sortie brute du modèle. Nous devons traiter cette sortie pour créer un masque de segmentation visuelle, puis l'afficher à l'écran.
OuvrirImageSegmentationHelper.kt
- Implémenter le traitement des sorties : la fonction
processImageconvertit la sortie brute à virgule flottante du modèle enByteBufferqui représente le masque de segmentation. Pour ce faire, il recherche la classe ayant la probabilité la plus élevée pour chaque pixel. Remplacez sonTODOpar (~ligne 238) :val mask = ByteBuffer.allocateDirect(inferenceData.width * inferenceData.height) for (i in 0 until inferenceData.height) { for (j in 0 until inferenceData.width) { val offset = inferenceData.channels * (i * inferenceData.width + j) var maxIndex = 0 var maxValue = inferenceData.buffer.get(offset) for (index in 1 until inferenceData.channels) { if (inferenceData.buffer.get(offset + index) > maxValue) { maxValue = inferenceData.buffer.get(offset + index) maxIndex = index } } mask.put(i * inferenceData.width + j, maxIndex.toByte()) } } return mask
OuvrirMainViewModel.kt
- Collecter et traiter les résultats de la segmentation : revenons maintenant à
MainViewModelpour traiter les résultats de la segmentation deImageSegmentationHelper. LesegmentationUiShareFlowcollecte leSegmentationResult, convertit le masque enBitmapcoloré et le fournit à l'UI. RemplacezTODOdans la propriétésegmentationUiShareFlowpar (~ligne 63). Ne remplacez pas le code déjà présent, remplissez simplement le corps :viewModelScope.launch { imageSegmentationHelper.segmentation .filter { it.segmentation.masks.isNotEmpty() } .map { val segmentation = it.segmentation val mask = segmentation.masks[0] val maskArray = mask.data val width = mask.width val height = mask.height val pixelSize = width * height val pixels = IntArray(pixelSize) val colorLabels = segmentation.coloredLabels.mapIndexed { index, coloredLabel -> ColorLabel(index, coloredLabel.label, coloredLabel.argb) } // Set color for pixels for (i in 0 until pixelSize) { val colorLabel = colorLabels[maskArray[i].toInt()] val color = colorLabel.getColor() pixels[i] = color } // Get image info val overlayInfo = OverlayInfo(pixels = pixels, width = width, height = height) val inferenceTime = it.inferenceTime Pair(overlayInfo, inferenceTime) } .collect { flow.emit(it) } }
Ouvrirview/SegmentationOverlay.kt
La dernière étape consiste à orienter correctement la superposition de segmentation lorsque l'utilisateur passe à la caméra frontale. Le flux de la caméra avant est naturellement mis en miroir. Nous devons donc appliquer la même inversion horizontale à notre superposition Bitmap pour nous assurer qu'elle s'aligne correctement sur l'aperçu de la caméra.
- Gérer l'orientation de la superposition : recherchez
TODOdans le fichierSegmentationOverlay.ktet remplacez-le par le code suivant. Ce code vérifie si la caméra frontale est active et, si c'est le cas, applique une inversion horizontale à la superpositionBitmapavant qu'elle ne soit dessinée surCanvas. (~ligne 42) :val orientedBitmap = if (lensFacing == CameraSelector.LENS_FACING_FRONT) { // Create a matrix for horizontal flipping val matrix = Matrix().apply { preScale(-1f, 1f) } Bitmap.createBitmap(image, 0, 0, image.width, image.height, matrix, false).also { image.recycle() } } else { image }
10. Exécuter et utiliser l'application finale
Vous avez maintenant terminé toutes les modifications de code nécessaires. Il est temps d'exécuter l'application et de voir le résultat de votre travail.
- Exécuter l'application : connectez votre appareil Android et cliquez sur Exécuter dans la barre d'outils Android Studio.

- Testez les fonctionnalités : une fois l'application lancée, vous devriez voir le flux vidéo en direct de la caméra avec une superposition de segmentation colorée.
- Changer de caméra : appuyez sur l'icône de changement de caméra en haut de l'écran pour basculer entre la caméra avant et la caméra arrière. Notez comment la superposition s'oriente correctement.
- Changer d'accélérateur : appuyez sur le bouton "CPU" ou "GPU" en bas de l'écran pour changer d'accélérateur matériel. Observez la modification du temps d'inférence affiché en bas de l'écran. Le GPU devrait être beaucoup plus rapide.
- Utiliser une image de la galerie : appuyez sur l'onglet "Galerie" en haut de l'écran pour sélectionner une image dans la galerie de photos de votre appareil. L'application exécutera la segmentation sur l'image statique sélectionnée.

Vous disposez désormais d'une application de segmentation d'images en temps réel entièrement fonctionnelle, optimisée par LiteRT.
11. Avancé (facultatif) : Utiliser la NPU
Ce dépôt contient également une version de l'application optimisée pour les unités de traitement neuronal (NPU). La version NPU peut améliorer considérablement les performances sur les appareils dotés d'un NPU compatible.
Pour essayer la version NPU, ouvrez le projet kotlin_npu/android dans Android Studio. Le code est très semblable à la version CPU/GPU et est configuré pour utiliser le délégué NPU.
Pour utiliser le délégué NPU, vous devez vous inscrire au programme d'accès anticipé.
12. Félicitations !
Vous avez créé une application Android qui effectue une segmentation d'images en temps réel à l'aide de LiteRT. Vous avez appris à effectuer les tâches suivantes :
- Intégrez le runtime LiteRT à une application Android.
- Chargez et exécutez un modèle TFLite de segmentation d'images.
- Prétraitez l'entrée du modèle.
- Traitez la sortie du modèle pour créer un masque de segmentation.
- Utilisez CameraX pour une application d'appareil photo en temps réel.
Étapes suivantes
- Essayez un autre modèle de segmentation d'images.
- Testez différents délégués LiteRT (CPU, GPU, NPU).