Étiqueter des images avec ML Kit sur Android

Vous pouvez utiliser ML Kit pour étiqueter les objets reconnus dans une image. Le modèle par défaut fourni avec ML Kit accepte plus de 400 étiquettes différentes.

FonctionnalitéSans catégorieGroupée
ImplémentationLe modèle est téléchargé de manière dynamique via les services Google Play.Le modèle est lié de manière statique à votre au moment de la compilation.
Taille de l'applicationAugmentation de la taille d'environ 200 Ko.Augmentation de la taille d'environ 5,7 Mo.
Délai d'initialisationVous devrez peut-être attendre que le modèle soit téléchargé avant de l'utiliser pour la première fois.Le modèle est disponible immédiatement

Essayer

Avant de commencer

  1. Dans le fichier build.gradle au niveau du projet, veillez à inclure l'adresse e-mail de Google Dépôt Maven dans les sections buildscript et allprojects.

  2. Ajoutez les dépendances des bibliothèques Android ML Kit au fichier fichier Gradle au niveau de l'application, généralement app/build.gradle. Choisissez l'une des options les dépendances suivantes en fonction de vos besoins:

    Pour regrouper le modèle avec votre application:

    dependencies {
      // ...
      // Use this dependency to bundle the model with your app
      implementation 'com.google.mlkit:image-labeling:17.0.8'
    }
    

    Pour utiliser le modèle dans les services Google Play:

    dependencies {
      // ...
      // Use this dependency to use the dynamically downloaded model in Google Play Services
      implementation 'com.google.android.gms:play-services-mlkit-image-labeling:16.0.8'
    }
    
  3. Si vous choisissez d'utiliser le modèle dans les services Google Play, vous pouvez configurer votre application pour télécharger automatiquement le modèle sur l'appareil une fois l'application installé depuis le Play Store. Pour ce faire, ajoutez la déclaration suivante au fichier le fichier AndroidManifest.xml de votre application:

    <application ...>
          ...
          <meta-data
              android:name="com.google.mlkit.vision.DEPENDENCIES"
              android:value="ica" >
          <!-- To use multiple models: android:value="ica,model2,model3" -->
    </application>
    

    Vous pouvez aussi vérifier explicitement la disponibilité du modèle et demander un téléchargement via API ModuleInstallClient des services Google Play.

    Si vous n'activez pas le téléchargement du modèle au moment de l'installation ou le modèle est téléchargé la première fois que vous exécutez l'étiqueteur. Demandes que vous effectuez avant la fin du téléchargement ne produit aucun résultat.

Vous êtes maintenant prêt à étiqueter des images.

1. Préparer l'image d'entrée

Créez un objet InputImage à partir de votre image. L'étiqueteur d'images s'exécute plus rapidement lorsque vous utilisez un Bitmap ou, si vous utilisez le l'API camera2 et une media.Image YUV_420_888, recommandées lorsque possible.

Vous pouvez créer un InputImage de différentes sources. Chacune d'elles est expliquée ci-dessous.

Utiliser un media.Image

Pour créer un InputImage à partir d'un objet media.Image, par exemple lorsque vous capturez une image à partir d'un l'appareil photo de l'appareil, transmettez l'objet media.Image et l'image la rotation sur InputImage.fromMediaImage().

Si vous utilisez les la bibliothèque CameraX, les OnImageCapturedListener et Les classes ImageAnalysis.Analyzer calculent la valeur de rotation pour vous.

Kotlin

private class YourImageAnalyzer : ImageAnalysis.Analyzer {

    override fun analyze(imageProxy: ImageProxy) {
        val mediaImage = imageProxy.image
        if (mediaImage != null) {
            val image = InputImage.fromMediaImage(mediaImage, imageProxy.imageInfo.rotationDegrees)
            // Pass image to an ML Kit Vision API
            // ...
        }
    }
}

Java

private class YourAnalyzer implements ImageAnalysis.Analyzer {

    @Override
    public void analyze(ImageProxy imageProxy) {
        Image mediaImage = imageProxy.getImage();
        if (mediaImage != null) {
          InputImage image =
                InputImage.fromMediaImage(mediaImage, imageProxy.getImageInfo().getRotationDegrees());
          // Pass image to an ML Kit Vision API
          // ...
        }
    }
}

Si vous n'utilisez pas de bibliothèque d'appareils photo qui indique le degré de rotation de l'image, le calcul à partir du degré de rotation de l'appareil et de l'orientation de la caméra capteur de l'appareil:

Kotlin

private val ORIENTATIONS = SparseIntArray()

init {
    ORIENTATIONS.append(Surface.ROTATION_0, 0)
    ORIENTATIONS.append(Surface.ROTATION_90, 90)
    ORIENTATIONS.append(Surface.ROTATION_180, 180)
    ORIENTATIONS.append(Surface.ROTATION_270, 270)
}

/**
 * Get the angle by which an image must be rotated given the device's current
 * orientation.
 */
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
@Throws(CameraAccessException::class)
private fun getRotationCompensation(cameraId: String, activity: Activity, isFrontFacing: Boolean): Int {
    // Get the device's current rotation relative to its "native" orientation.
    // Then, from the ORIENTATIONS table, look up the angle the image must be
    // rotated to compensate for the device's rotation.
    val deviceRotation = activity.windowManager.defaultDisplay.rotation
    var rotationCompensation = ORIENTATIONS.get(deviceRotation)

    // Get the device's sensor orientation.
    val cameraManager = activity.getSystemService(CAMERA_SERVICE) as CameraManager
    val sensorOrientation = cameraManager
            .getCameraCharacteristics(cameraId)
            .get(CameraCharacteristics.SENSOR_ORIENTATION)!!

    if (isFrontFacing) {
        rotationCompensation = (sensorOrientation + rotationCompensation) % 360
    } else { // back-facing
        rotationCompensation = (sensorOrientation - rotationCompensation + 360) % 360
    }
    return rotationCompensation
}

Java

private static final SparseIntArray ORIENTATIONS = new SparseIntArray();
static {
    ORIENTATIONS.append(Surface.ROTATION_0, 0);
    ORIENTATIONS.append(Surface.ROTATION_90, 90);
    ORIENTATIONS.append(Surface.ROTATION_180, 180);
    ORIENTATIONS.append(Surface.ROTATION_270, 270);
}

/**
 * Get the angle by which an image must be rotated given the device's current
 * orientation.
 */
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
private int getRotationCompensation(String cameraId, Activity activity, boolean isFrontFacing)
        throws CameraAccessException {
    // Get the device's current rotation relative to its "native" orientation.
    // Then, from the ORIENTATIONS table, look up the angle the image must be
    // rotated to compensate for the device's rotation.
    int deviceRotation = activity.getWindowManager().getDefaultDisplay().getRotation();
    int rotationCompensation = ORIENTATIONS.get(deviceRotation);

    // Get the device's sensor orientation.
    CameraManager cameraManager = (CameraManager) activity.getSystemService(CAMERA_SERVICE);
    int sensorOrientation = cameraManager
            .getCameraCharacteristics(cameraId)
            .get(CameraCharacteristics.SENSOR_ORIENTATION);

    if (isFrontFacing) {
        rotationCompensation = (sensorOrientation + rotationCompensation) % 360;
    } else { // back-facing
        rotationCompensation = (sensorOrientation - rotationCompensation + 360) % 360;
    }
    return rotationCompensation;
}

Ensuite, transmettez l'objet media.Image et valeur du degré de rotation sur InputImage.fromMediaImage():

Kotlin

val image = InputImage.fromMediaImage(mediaImage, rotation)

Java

InputImage image = InputImage.fromMediaImage(mediaImage, rotation);

Utiliser un URI de fichier

Pour créer un InputImage à partir d'un URI de fichier, transmettez le contexte de l'application et l'URI du fichier à InputImage.fromFilePath() Cela est utile lorsque vous Utiliser un intent ACTION_GET_CONTENT pour inviter l'utilisateur à sélectionner une image de son application Galerie.

Kotlin

val image: InputImage
try {
    image = InputImage.fromFilePath(context, uri)
} catch (e: IOException) {
    e.printStackTrace()
}

Java

InputImage image;
try {
    image = InputImage.fromFilePath(context, uri);
} catch (IOException e) {
    e.printStackTrace();
}

Utiliser un ByteBuffer ou un ByteArray

Pour créer un InputImage d'un objet ByteBuffer ou ByteArray, calculez d'abord l'image degré de rotation décrit précédemment pour l'entrée media.Image. Créez ensuite l'objet InputImage avec le tampon ou le tableau, ainsi que l'objet image la hauteur, la largeur, le format d'encodage des couleurs et le degré de rotation:

Kotlin

val image = InputImage.fromByteBuffer(
        byteBuffer,
        /* image width */ 480,
        /* image height */ 360,
        rotationDegrees,
        InputImage.IMAGE_FORMAT_NV21 // or IMAGE_FORMAT_YV12
)
// Or:
val image = InputImage.fromByteArray(
        byteArray,
        /* image width */ 480,
        /* image height */ 360,
        rotationDegrees,
        InputImage.IMAGE_FORMAT_NV21 // or IMAGE_FORMAT_YV12
)

Java

InputImage image = InputImage.fromByteBuffer(byteBuffer,
        /* image width */ 480,
        /* image height */ 360,
        rotationDegrees,
        InputImage.IMAGE_FORMAT_NV21 // or IMAGE_FORMAT_YV12
);
// Or:
InputImage image = InputImage.fromByteArray(
        byteArray,
        /* image width */480,
        /* image height */360,
        rotation,
        InputImage.IMAGE_FORMAT_NV21 // or IMAGE_FORMAT_YV12
);

Utiliser un Bitmap

Pour créer un InputImage à partir d'un objet Bitmap, effectuez la déclaration suivante:

Kotlin

val image = InputImage.fromBitmap(bitmap, 0)

Java

InputImage image = InputImage.fromBitmap(bitmap, rotationDegree);

L'image est représentée par un objet Bitmap associé à des degrés de rotation.

2. Configurer et exécuter l'étiqueteur d'images

Pour étiqueter des objets dans une image, transmettez l'objet InputImage à la La méthode process de ImageLabeler.

  1. Tout d'abord, obtenez une instance de ImageLabeler

    Si vous souhaitez utiliser l'étiqueteur d'images sur l'appareil, effectuez les opérations suivantes : déclaration:

Kotlin

// To use default options:
val labeler = ImageLabeling.getClient(ImageLabelerOptions.DEFAULT_OPTIONS)

// Or, to set the minimum confidence required:
// val options = ImageLabelerOptions.Builder()
//     .setConfidenceThreshold(0.7f)
//     .build()
// val labeler = ImageLabeling.getClient(options)

Java

// To use default options:
ImageLabeler labeler = ImageLabeling.getClient(ImageLabelerOptions.DEFAULT_OPTIONS);

// Or, to set the minimum confidence required:
// ImageLabelerOptions options =
//     new ImageLabelerOptions.Builder()
//         .setConfidenceThreshold(0.7f)
//         .build();
// ImageLabeler labeler = ImageLabeling.getClient(options);
  1. Transmettez ensuite l'image à la méthode process():

Kotlin

labeler.process(image)
        .addOnSuccessListener { labels ->
            // Task completed successfully
            // ...
        }
        .addOnFailureListener { e ->
            // Task failed with an exception
            // ...
        }

Java

labeler.process(image)
        .addOnSuccessListener(new OnSuccessListener<List<ImageLabel>>() {
            @Override
            public void onSuccess(List<ImageLabel> labels) {
                // Task completed successfully
                // ...
            }
        })
        .addOnFailureListener(new OnFailureListener() {
            @Override
            public void onFailure(@NonNull Exception e) {
                // Task failed with an exception
                // ...
            }
        });

3. Obtenir des informations sur les objets étiquetés

Si l'opération d'ajout d'étiquettes à l'image réussit, une liste des Les objets ImageLabel sont transmis à l'écouteur de réussite. Chaque L'objet ImageLabel représente un élément étiqueté dans l'image. Base accepte plus de 400 étiquettes différentes. Vous pouvez obtenir la description et l'index de chaque libellé, parmi tous ceux compatibles avec le modèle et le score de confiance de la correspondance. Exemple :

Kotlin

for (label in labels) {
    val text = label.text
    val confidence = label.confidence
    val index = label.index
}

Java

for (ImageLabel label : labels) {
    String text = label.getText();
    float confidence = label.getConfidence();
    int index = label.getIndex();
}

Conseils pour améliorer les performances en temps réel

Si vous souhaitez étiqueter des images dans une application en temps réel, suivez ces pour obtenir des fréquences d'images optimales:

  • Si vous utilisez les Camera ou API camera2 limiter les appels à l'étiqueteur d'images. Si une nouvelle vidéo image devient disponible pendant que l'étiqueteur d'image est en cours d'exécution, supprimez le cadre. Consultez le VisionProcessorBase de l'application exemple de démarrage rapide.
  • Si vous utilisez l'API CameraX, Assurez-vous que la stratégie de contre-pression est définie sur sa valeur par défaut ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST Cela garantit qu'une seule image à la fois sera envoyée pour analyse. Si davantage d'images sont générées lorsque l'analyseur est occupé, elles sont automatiquement abandonnées et ne sont pas mises en file d'attente la livraison. Une fois que l'image en cours d'analyse est fermée en appelant ImageProxy.close(), l'image suivante la plus récente sera diffusée.
  • Si vous utilisez la sortie de l'étiqueteur d'images pour superposer des images l'image d'entrée, récupérez d'abord le résultat à partir de ML Kit, puis effectuez le rendu de l'image. et les superposer en une seule étape. Le rendu à la surface d'affichage une seule fois pour chaque trame d'entrée. Consultez le CameraSourcePreview et GraphicOverlay de l'application exemple de démarrage rapide.
  • Si vous utilisez l'API Camera2, capturez des images Format ImageFormat.YUV_420_888. Si vous utilisez l'ancienne API Camera, capturez les images Format ImageFormat.NV21.