Guide d'intégration d'images pour Android

La tâche de l'intégrateur d'images MediaPipe vous permet de convertir des données d'image en représentation numérique pour effectuer des tâches de traitement d'images liées au ML, comme comparer les la similitude de deux images. Ces instructions vous expliquent comment utiliser Outil d'intégration d'images avec des applications Android

Pour en savoir plus sur les fonctionnalités, les modèles et les options de configuration de cette tâche, consultez la section Présentation.

Exemple de code

L'exemple de code MediaPipe Tasks est une implémentation simple d'un intégrateur d'images pour Android. L'exemple utilise l'appareil photo d'un appareil Android physique pour d'intégrer des images en continu et d'exécuter l'outil d'intégration sur les fichiers image stockés sur l'appareil.

Vous pouvez utiliser l'application comme point de départ pour votre propre application Android ou vous y référer. lorsque vous modifiez une application existante. L'exemple de code de l'outil d'intégration d'images est hébergé GitHub

Télécharger le code

Les instructions suivantes vous expliquent comment créer une copie locale de l'exemple à l'aide de l'outil de ligne de commande git.

<ph type="x-smartling-placeholder">

Pour télécharger l'exemple de code:

  1. Clonez le dépôt Git à l'aide de la commande suivante:
    git clone https://github.com/google-ai-edge/mediapipe-samples
    
  2. Si vous le souhaitez, vous pouvez configurer votre instance Git pour utiliser le paiement creuse. Seuls les fichiers de l'application exemple de l'outil d'intégration d'images:
    cd mediapipe
    git sparse-checkout init --cone
    git sparse-checkout set examples/image_embedder/android
    

Après avoir créé une version locale de l'exemple de code, vous pouvez importer le projet dans Android Studio et exécuter l'application. Pour obtenir des instructions, consultez le Guide de configuration Android

Composants clés

Les fichiers suivants contiennent le code essentiel pour cet exemple d'outil d'intégration d'images application:

  • ImageEmbedderHelper.kt: initialise l'intégrateur d'images, et gère le modèle et la délégation de votre choix.
  • MainActivity.kt: implémente l'application et assemble les composants de l'interface utilisateur.

Configuration

Cette section décrit les étapes clés à suivre pour configurer votre environnement de développement pour utiliser l'outil d'intégration d'images. Pour obtenir des informations générales sur la configuration environnement de développement permettant d'utiliser des tâches MediaPipe, y compris la version de la plate-forme configuration requise, consultez le Guide de configuration Android

<ph type="x-smartling-placeholder">

Dépendances

L'outil d'intégration d'images utilise la bibliothèque com.google.mediapipe:tasks-vision. Ajouter au fichier build.gradle de votre projet de développement d'applications Android. Importez les dépendances requises avec le code suivant:

dependencies {
    ...
    implementation 'com.google.mediapipe:tasks-vision:latest.release'
}

Modèle

La tâche de l'intégrateur d'images MediaPipe nécessite un modèle entraîné compatible avec tâche. Pour en savoir plus sur les modèles entraînés disponibles pour l'intégrateur d'images, consultez la section Modèles de la présentation des tâches.

Sélectionnez et téléchargez le modèle, puis stockez-le dans le répertoire de votre projet:

<dev-project-root>/src/main/assets

Spécifiez le chemin d'accès du modèle dans le paramètre ModelAssetPath. Dans exemple de code, le modèle est défini dans la fonction setupImageEmbedder() ImageEmbedderHelper.kt :

Utiliser la méthode BaseOptions.Builder.setModelAssetPath() pour spécifier le chemin d'accès utilisées par le modèle. Cette méthode est mentionnée dans l'exemple de code de la .

Créer la tâche

Vous pouvez utiliser la fonction createFromOptions pour créer la tâche. La La fonction createFromOptions accepte les options de configuration pour définir l'intégrateur options. Pour plus d'informations sur les options de configuration, consultez la section Configuration Présentation.

La tâche de l'intégrateur d'images accepte trois types de données d'entrée: images fixes, fichiers vidéo, et les flux vidéo en direct. Vous devez spécifier le mode d'exécution correspondant votre type de données d'entrée lors de la création de la tâche. Choisissez l'onglet correspondant votre type de données d'entrée pour découvrir comment créer la tâche et exécuter l'inférence.

Image

ImageEmbedderOptions options =
  ImageEmbedderOptions.builder()
    .setBaseOptions(
      BaseOptions.builder().setModelAssetPath("model.tflite").build())
    .setQuantize(true)
    .setRunningMode(RunningMode.IMAGE)
    .build();
imageEmbedder = ImageEmbedder.createFromOptions(context, options);
    

Vidéo

ImageEmbedderOptions options =
  ImageEmbedderOptions.builder()
    .setBaseOptions(
      BaseOptions.builder().setModelAssetPath("model.tflite").build())
    .setQuantize(true)
    .setRunningMode(RunningMode.VIDEO)
    .build();
imageEmbedder = ImageEmbedder.createFromOptions(context, options);
    

Diffusion en direct

ImageEmbedderOptions options =
  ImageEmbedderOptions.builder()
    .setBaseOptions(
      BaseOptions.builder().setModelAssetPath("model.tflite").build())
    .setQuantize(true)
    .setRunningMode(RunningMode.LIVE_STREAM)
    .setResultListener((result, inputImage) -> {
         // Process the embedding result here.
    })
    .build();
imageEmbedder = ImageEmbedder.createFromOptions(context, options);
    

L'exemple d'implémentation de code permet à l'utilisateur de basculer entre les modes de traitement différents modes. L'approche rend le code de création de la tâche plus compliqué et peut ne pas être adapté à votre cas d'utilisation. Ce code figure dans la fonction setupImageEmbedder() dans ImageEmbedderHelper.kt .

Options de configuration

Cette tâche comporte les options de configuration suivantes pour les applications Android:

Nom de l'option Description Plage de valeurs Valeur par défaut
runningMode Définit le mode d'exécution de la tâche. Il y en a trois modes:

IMAGE: mode utilisé pour la saisie d'une seule image.

VIDEO: mode des images décodées d'une vidéo.

LIVE_STREAM: mode d'une diffusion en direct des entrées provenant d'un appareil photo, par exemple. Dans ce mode, resultListener doit être appelé pour configurer un écouteur afin de recevoir les résultats ; de manière asynchrone.
{IMAGE, VIDEO, LIVE_STREAM} IMAGE
l2_normalize Indique s'il faut normaliser le vecteur de caractéristiques renvoyé avec la norme L2. N'utilisez cette option que si le modèle ne contient pas encore d'élément natif L2_NORMALIZATION TFLite Op. Dans la plupart des cas, c'est déjà le cas et La normalisation L2 est ainsi obtenue via l'inférence TFLite sans avoir besoin pour cette option. Boolean False
quantize Indique si la représentation vectorielle continue renvoyée doit être quantifiée en octets via la quantification scalaire. Les représentations vectorielles continues sont implicitement considérées comme étant une norme unitaire Par conséquent, toute dimension aura une valeur comprise dans [-1.0, 1.0]. Utilisez l'option l2_normalize si ce n'est pas le cas. Boolean False
resultListener Définit l'écouteur des résultats pour qu'il reçoive les résultats de la représentation vectorielle continue. de manière asynchrone lorsque l'intégrateur d'images est dans la diffusion en direct . Ne peut être utilisé que lorsque le mode d'exécution est défini sur LIVE_STREAM N/A Non défini
errorListener Définit un écouteur d'erreurs facultatif. N/A Non défini

Préparer les données

L'outil d'intégration d'images fonctionne avec les images, les fichiers vidéo et les diffusions en direct. La tâche gère le prétraitement de l'entrée des données, y compris le redimensionnement, la rotation et la valeur. normalisation.

Vous devez convertir l'image ou le cadre d'entrée en com.google.mediapipe.framework.image.MPImage avant de le transmettre à Tâche d'intégration d'images.

Image

import com.google.mediapipe.framework.image.BitmapImageBuilder;
import com.google.mediapipe.framework.image.MPImage;

// Load an image on the user’s device as a Bitmap object using BitmapFactory.

// Convert an Android’s Bitmap object to a MediaPipe’s Image object.
Image mpImage = new BitmapImageBuilder(bitmap).build();
    

Vidéo

import com.google.mediapipe.framework.image.BitmapImageBuilder;
import com.google.mediapipe.framework.image.MPImage;

// Load a video file on the user's device using MediaMetadataRetriever

// From the video’s metadata, load the METADATA_KEY_DURATION and
// METADATA_KEY_VIDEO_FRAME_COUNT value. You’ll need them
// to calculate the timestamp of each frame later.

// Loop through the video and load each frame as a Bitmap object.

// Convert the Android’s Bitmap object to a MediaPipe’s Image object.
Image mpImage = new BitmapImageBuilder(frame).build();
    

Diffusion en direct

import com.google.mediapipe.framework.image.MediaImageBuilder;
import com.google.mediapipe.framework.image.MPImage;

// Create a CameraX’s ImageAnalysis to continuously receive frames
// from the device’s camera. Configure it to output frames in RGBA_8888
// format to match with what is required by the model.

// For each Android’s ImageProxy object received from the ImageAnalysis,
// extract the encapsulated Android’s Image object and convert it to
// a MediaPipe’s Image object.
android.media.Image mediaImage = imageProxy.getImage()
Image mpImage = new MediaImageBuilder(mediaImage).build();
    

Dans l'exemple de code, la préparation des données est gérée dans le ImageEmbedderHelper.kt .

Exécuter la tâche

Vous pouvez appeler la fonction embed correspondant à votre mode de course pour déclencher les inférences. L'API Image Embedder renvoie les vecteurs de représentation vectorielle continue de l'entrée comme une image ou un cadre.

Image

ImageEmbedderResult embedderResult = imageEmbedder.embed(image);
    

Vidéo

// Calculate the timestamp in milliseconds of the current frame.
long frame_timestamp_ms = 1000 * video_duration * frame_index / frame_count;

// Run inference on the frame.
ImageEmbedderResult embedderResult =
    imageEmbedder.embedForVideo(image, frameTimestampMs);
    

Diffusion en direct


// Run inference on the frame. The embedding results will be available
// via the `resultListener` provided in the `ImageEmbedderOptions` when
// the image embedder was created.
imageEmbedder.embedAsync(image, frameTimestampMs);
    

Veuillez noter les points suivants :

  • Lorsque vous êtes en mode vidéo ou flux en direct, vous devez également fournir le code temporel de la trame d'entrée à la tâche de l'intégrateur d'images.
  • Lors de l'exécution en mode image ou vidéo, la tâche "Outil d'intégration d'images" bloquer le thread actuel jusqu'à ce qu'il ait fini de traiter l'image d'entrée ou cadre. Pour éviter de bloquer le thread actuel, exécutez le traitement dans une thread d'arrière-plan.
  • Lors de l'exécution en mode de diffusion en direct, la tâche de l'intégrateur d'images ne bloque pas le thread actuel, mais renvoie immédiatement. Elle appellera son résultat avec le résultat de la détection chaque fois que le traitement d'une trame d'entrée. Si la fonction embedAsync est appelée lorsque l'intégrateur d'images est occupée à traiter une autre trame, la tâche ignore la nouvelle trame d'entrée.

Dans l'exemple de code, la fonction embed est définie dans ImageEmbedderHelper.kt .

Gérer et afficher les résultats

Lors de l'exécution de l'inférence, la tâche d'intégration d'images renvoie un ImageEmbedderResult contenant une liste de représentations vectorielles continues (à virgule flottante ou quantifiée scalaire) pour l'image d'entrée.

Voici un exemple de données de sortie de cette tâche:

ImageEmbedderResult:
  Embedding #0 (sole embedding head):
    float_embedding: {0.0, 0.0, ..., 0.0, 1.0, 0.0, 0.0, 2.0}
    head_index: 0

Ce résultat a été obtenu en intégrant l'image suivante:

Vous pouvez comparer la similarité de deux représentations vectorielles continues à l'aide de la fonction fonction ImageEmbedder.cosineSimilarity. Consultez le code suivant pour obtenir à titre d'exemple.

// Compute cosine similarity.
double similarity = ImageEmbedder.cosineSimilarity(
  result.embeddingResult().embeddings().get(0),
  otherResult.embeddingResult().embeddings().get(0));