Ajouter des libellés à des images avec un modèle entraîné automatiquement sur iOS

Une fois que vous avez entraîné votre propre modèle à l'aide d'AutoML Vision Edge, vous pouvez l'utiliser dans votre application pour ajouter des libellés aux images.

Il existe deux façons d'intégrer des modèles entraînés à partir d'AutoML Vision Edge. Vous pouvez regrouper le modèle en copiant ses fichiers dans votre projet Xcode ou le télécharger de manière dynamique à partir de Firebase.

Options de regroupement de modèles
Regroupé dans votre application
  • Le modèle fait partie du bundle
  • Le modèle est disponible immédiatement, même lorsque l'appareil iOS est hors connexion
  • Aucun projet Firebase n'est nécessaire
Hébergé avec Firebase
  • Hébergez le modèle en l'important dans Firebase Machine Learning
  • Réduit la taille du bundle d'application
  • Le modèle est téléchargé à la demande
  • Envoyez des mises à jour du modèle sans republier votre application
  • Tests A/B faciles avec Firebase Remote Config
  • Nécessite un projet Firebase

Essayer

Avant de commencer

1. Incluez les bibliothèques ML Kit dans votre Podfile :

Pour regrouper un modèle avec votre application :
    pod 'GoogleMLKit/ImageLabelingAutoML'
    
Pour télécharger un modèle de manière dynamique à partir de Firebase, ajoutez la LinkFirebase dépendance :
    pod 'GoogleMLKit/ImageLabelingAutoML'
    pod 'GoogleMLKit/LinkFirebase'
    
2. Après avoir installé ou mis à jour les pods de votre projet, ouvrez votre projet Xcode à l'aide de son .xcworkspacecode>. ML Kit est compatible avec Xcode version 13.2.1 ou ultérieure. 3. Si vous souhaitez télécharger un modèle, assurez-vous d' ajouter Firebase à votre projet iOS, si ce n'est pas déjà fait. Cela n'est pas nécessaire lorsque vous regroupez le modèle.

1. Charger le modèle

Configurer une source de modèle local

Pour regrouper le modèle avec votre application :

1. Extrayez le modèle et ses métadonnées de l'archive ZIP que vous avez téléchargée depuis la console Firebase dans un dossier :
    your_model_directory
      |____dict.txt
      |____manifest.json
      |____model.tflite
    
Les trois fichiers doivent se trouver dans le même dossier. Nous vous recommandons d'utiliser les fichiers tels que vous les avez téléchargés, sans les modifier (y compris les noms de fichiers).

2. Copiez le dossier dans votre projet Xcode en veillant à sélectionner Create folder references (Créer des références de dossier). Le fichier de modèle et les métadonnées seront inclus dans le bundle d'application et disponibles pour ML Kit.

3. Créez un objet AutoMLImageLabelerLocalModel en spécifiant le chemin d'accès au fichier manifeste du modèle :

Swift

guard let manifestPath = Bundle.main.path(
    forResource: "manifest",
    ofType: "json",
    inDirectory: "your_model_directory"
) else { return }
let localModel = AutoMLImageLabelerLocalModel(manifestPath: manifestPath)

Objective-C

NSString *manifestPath =
    [NSBundle.mainBundle pathForResource:@"manifest"
                                  ofType:@"json"
                             inDirectory:@"your_model_directory"];
MLKAutoMLImageLabelerLocalModel *localModel =
    [[MLKAutoMLImageLabelerLocalModel alloc] initWithManifestPath:manifestPath];

Configurer une source de modèle hébergé par Firebase

Pour utiliser le modèle hébergé à distance, créez un objet AutoMLImageLabelerRemoteModel en spécifiant le nom que vous avez attribué au modèle lors de sa publication :

Swift

let remoteModel = AutoMLImageLabelerRemoteModel(
    name: "your_remote_model"  // The name you assigned in
                               // the Firebase console.
)

Objective-C

MLKAutoMLImageLabelerRemoteModel *remoteModel =
    [[MLKAutoMLImageLabelerRemoteModel alloc]
        initWithName:@"your_remote_model"];  // The name you assigned in
                                             // the Firebase console.

Démarrez ensuite la tâche de téléchargement du modèle en spécifiant les conditions dans lesquelles vous souhaitez autoriser le téléchargement. Si le modèle ne se trouve pas sur l'appareil ou si une version plus récente est disponible, la tâche télécharge le modèle de manière asynchrone à partir de Firebase :

Swift

let downloadConditions = ModelDownloadConditions(
  allowsCellularAccess: true,
  allowsBackgroundDownloading: true
)

let downloadProgress = ModelManager.modelManager().download(
  remoteModel,
  conditions: downloadConditions
)

Objective-C

MLKModelDownloadConditions *downloadConditions =
    [[MLKModelDownloadConditions alloc] initWithAllowsCellularAccess:YES
                                         allowsBackgroundDownloading:YES];

NSProgress *downloadProgress =
    [[MLKModelManager modelManager] downloadModel:remoteModel
                                       conditions:downloadConditions];

De nombreuses applications démarrent la tâche de téléchargement dans leur code d'initialisation, mais vous pouvez le faire à tout moment avant d'avoir besoin d'utiliser le modèle.

Créer un outil de libellisation d'images à partir de votre modèle

Une fois que vous avez configuré vos sources de modèle, créez un objet ImageLabeler à partir de l'une d'elles.

Si vous ne disposez que d'un modèle regroupé localement, créez simplement un outil de libellisation à partir de votre AutoMLImageLabelerLocalModel objet et configurez le seuil de score de confiance que vous souhaitez exiger (voir Évaluer votre mode) :

Swift

let options = AutoMLImageLabelerOptions(localModel: localModel)
options.confidenceThreshold = NSNumber(value: 0.0)  // Evaluate your model in the Firebase console
                                                    // to determine an appropriate value.
let imageLabeler = ImageLabeler.imageLabeler(options: options)

Objective-C

MLKAutoMLImageLabelerOptions *options =
    [[MLKAutoMLImageLabelerOptions alloc] initWithLocalModel:localModel];
options.confidenceThreshold = @(0.0);  // Evaluate your model in the Firebase console
                                       // to determine an appropriate value.
MLKImageLabeler *imageLabeler =
    [MLKImageLabeler imageLabelerWithOptions:options];

Si vous disposez d'un modèle hébergé à distance, vous devrez vérifier qu'il a été téléchargé avant de l'exécuter. Vous pouvez vérifier l'état de la tâche de téléchargement du modèle à l'aide de la méthode isModelDownloaded(remoteModel:) du gestionnaire de modèles.

Bien que vous n'ayez à confirmer cela qu'avant d'exécuter l'outil de libellisation, si vous disposez à la fois d'un modèle hébergé à distance et d'un modèle regroupé localement, il peut être judicieux d'effectuer cette vérification lors de l'instanciation de l'ImageLabeler : créez un outil de libellisation à partir du modèle distant s'il a été téléchargé, et à partir du modèle local dans le cas contraire.

Swift

var options: AutoMLImageLabelerOptions!
if (ModelManager.modelManager().isModelDownloaded(remoteModel)) {
  options = AutoMLImageLabelerOptions(remoteModel: remoteModel)
} else {
  options = AutoMLImageLabelerOptions(localModel: localModel)
}
options.confidenceThreshold = NSNumber(value: 0.0)  // Evaluate your model in the Firebase console
                                                    // to determine an appropriate value.
let imageLabeler = ImageLabeler.imageLabeler(options: options)

Objective-C

MLKAutoMLImageLabelerOptions *options;
if ([[MLKModelManager modelManager] isModelDownloaded:remoteModel]) {
  options = [[MLKAutoMLImageLabelerOptions alloc] initWithRemoteModel:remoteModel];
} else {
  options = [[MLKAutoMLImageLabelerOptions alloc] initWithLocalModel:localModel];
}
options.confidenceThreshold = @(0.0);  // Evaluate your model in the Firebase console
                                       // to determine an appropriate value.
MLKImageLabeler *imageLabeler =
    [MLKImageLabeler imageLabelerWithOptions:options];

Si vous ne disposez que d'un modèle hébergé à distance, vous devez désactiver les fonctionnalités liées au modèle (par exemple, griser ou masquer une partie de votre interface utilisateur) jusqu'à ce que vous confirmiez que le modèle a été téléchargé.

Vous pouvez obtenir l'état du téléchargement du modèle en associant des observateurs au centre de notifications par défaut. Veillez à utiliser une référence faible à self dans le bloc d'observateur, car les téléchargements peuvent prendre un certain temps et l'objet d'origine peut être libéré une fois le téléchargement terminé. Exemple :

Swift

NotificationCenter.default.addObserver(
    forName: .mlkitModelDownloadDidSucceed,
    object: nil,
    queue: nil
) { [weak self] notification in
    guard let strongSelf = self,
        let userInfo = notification.userInfo,
        let model = userInfo[ModelDownloadUserInfoKey.remoteModel.rawValue]
            as? RemoteModel,
        model.name == "your_remote_model"
        else { return }
    // The model was downloaded and is available on the device
}

NotificationCenter.default.addObserver(
    forName: .mlkitModelDownloadDidFail,
    object: nil,
    queue: nil
) { [weak self] notification in
    guard let strongSelf = self,
        let userInfo = notification.userInfo,
        let model = userInfo[ModelDownloadUserInfoKey.remoteModel.rawValue]
            as? RemoteModel
        else { return }
    let error = userInfo[ModelDownloadUserInfoKey.error.rawValue]
    // ...
}

Objective-C

__weak typeof(self) weakSelf = self;

[NSNotificationCenter.defaultCenter
    addObserverForName:MLKModelDownloadDidSucceedNotification
                object:nil
                 queue:nil
            usingBlock:^(NSNotification *_Nonnull note) {
              if (weakSelf == nil | note.userInfo == nil) {
                return;
              }
              __strong typeof(self) strongSelf = weakSelf;

              MLKRemoteModel *model = note.userInfo[MLKModelDownloadUserInfoKeyRemoteModel];
              if ([model.name isEqualToString:@"your_remote_model"]) {
                // The model was downloaded and is available on the device
              }
            }];

[NSNotificationCenter.defaultCenter
    addObserverForName:MLKModelDownloadDidFailNotification
                object:nil
                 queue:nil
            usingBlock:^(NSNotification *_Nonnull note) {
              if (weakSelf == nil | note.userInfo == nil) {
                return;
              }
              __strong typeof(self) strongSelf = weakSelf;

              NSError *error = note.userInfo[MLKModelDownloadUserInfoKeyError];
            }];

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

Créez un VisionImage objet à l'aide d'un UIImage ou d'un CMSampleBuffer.

Si vous utilisez un UIImage, procédez comme suit :

  • Créez un VisionImage objet avec le UIImage. Veillez à spécifier le .orientation correct.

    Swift

    let image = VisionImage(image: UIImage)
    visionImage.orientation = image.imageOrientation

    Objective-C

    MLKVisionImage *visionImage = [[MLKVisionImage alloc] initWithImage:image];
    visionImage.orientation = image.imageOrientation;

Si vous utilisez un CMSampleBuffer, procédez comme suit :

  • Spécifiez l'orientation des données d'image contenues dans le CMSampleBuffer.

    Pour obtenir l'orientation de l'image :

    Swift

    func imageOrientation(
      deviceOrientation: UIDeviceOrientation,
      cameraPosition: AVCaptureDevice.Position
    ) -> UIImage.Orientation {
      switch deviceOrientation {
      case .portrait:
        return cameraPosition == .front ? .leftMirrored : .right
      case .landscapeLeft:
        return cameraPosition == .front ? .downMirrored : .up
      case .portraitUpsideDown:
        return cameraPosition == .front ? .rightMirrored : .left
      case .landscapeRight:
        return cameraPosition == .front ? .upMirrored : .down
      case .faceDown, .faceUp, .unknown:
        return .up
      }
    }
          

    Objective-C

    - (UIImageOrientation)
      imageOrientationFromDeviceOrientation:(UIDeviceOrientation)deviceOrientation
                             cameraPosition:(AVCaptureDevicePosition)cameraPosition {
      switch (deviceOrientation) {
        case UIDeviceOrientationPortrait:
          return cameraPosition == AVCaptureDevicePositionFront ? UIImageOrientationLeftMirrored
                                                                : UIImageOrientationRight;
    
        case UIDeviceOrientationLandscapeLeft:
          return cameraPosition == AVCaptureDevicePositionFront ? UIImageOrientationDownMirrored
                                                                : UIImageOrientationUp;
        case UIDeviceOrientationPortraitUpsideDown:
          return cameraPosition == AVCaptureDevicePositionFront ? UIImageOrientationRightMirrored
                                                                : UIImageOrientationLeft;
        case UIDeviceOrientationLandscapeRight:
          return cameraPosition == AVCaptureDevicePositionFront ? UIImageOrientationUpMirrored
                                                                : UIImageOrientationDown;
        case UIDeviceOrientationUnknown:
        case UIDeviceOrientationFaceUp:
        case UIDeviceOrientationFaceDown:
          return UIImageOrientationUp;
      }
    }
          
  • Créez un objet VisionImage à l'aide de l' CMSampleBuffer objet et de l'orientation :

    Swift

    let image = VisionImage(buffer: sampleBuffer)
    image.orientation = imageOrientation(
      deviceOrientation: UIDevice.current.orientation,
      cameraPosition: cameraPosition)

    Objective-C

     MLKVisionImage *image = [[MLKVisionImage alloc] initWithBuffer:sampleBuffer];
     image.orientation =
       [self imageOrientationFromDeviceOrientation:UIDevice.currentDevice.orientation
                                    cameraPosition:cameraPosition];

3. Exécuter l'outil de libellisation d'images

De manière asynchrone :

Swift

imageLabeler.process(image) { labels, error in
    guard error == nil, let labels = labels, !labels.isEmpty else {
        // Handle the error.
        return
    }
    // Show results.
}

Objective-C

[imageLabeler
    processImage:image
      completion:^(NSArray *_Nullable labels,
                   NSError *_Nullable error) {
        if (labels.count == 0) {
            // Handle the error.
            return;
        }
        // Show results.
     }];

De manière synchrone :

Swift

var labels: [ImageLabel]
do {
    labels = try imageLabeler.results(in: image)
} catch let error {
    // Handle the error.
    return
}
// Show results.

Objective-C

NSError *error;
NSArray *labels =
    [imageLabeler resultsInImage:image error:&error];
// Show results or handle the error.

4. Obtenir des informations sur les objets libellisés

Si l'opération de libellisation d'images réussit, elle renvoie un tableau de ImageLabel. Chaque ImageLabel représente un élément libellisé dans l'image. Vous pouvez obtenir la description textuelle de chaque libellé (si elle est disponible dans les métadonnées du fichier de modèle TensorFlow Lite), le score de confiance et l'index. Exemple :

Swift

for label in labels {
  let labelText = label.text
  let confidence = label.confidence
  let index = label.index
}

Objective-C

for (MLKImageLabel *label in labels) {
  NSString *labelText = label.text;
  float confidence = label.confidence;
  NSInteger index = label.index;
}

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

Si vous souhaitez libelliser des images dans une application en temps réel, suivez ces consignes pour obtenir les meilleures fréquences d'images :

  • Pour traiter les images vidéo, utilisez l'API synchrone results(in:) du détecteur. Appelez cette méthode à partir de la AVCaptureVideoDataOutputSampleBufferDelegate captureOutput(_, didOutput:from:) fonction pour obtenir de manière synchrone les résultats de l'image vidéo donnée. Conservez AVCaptureVideoDataOutput de alwaysDiscardsLateVideoFrames comme true pour limiter les appels au détecteur. Si une nouvelle image vidéo devient disponible pendant l'exécution du détecteur, elle sera supprimée.
  • Si vous utilisez la sortie du détecteur pour superposer des graphiques sur l'image d'entrée, obtenez d'abord le résultat de ML Kit, puis effectuez le rendu de l'image et la superposition en une seule étape. Ce faisant, vous n'effectuez le rendu sur la surface d'affichage qu'une seule fois pour chaque image d'entrée traitée. Pour obtenir un exemple, consultez updatePreviewOverlayViewWithLastFrame dans l'exemple de démarrage rapide de ML Kit.