Étiqueter des images avec un modèle entraîné par AutoML sur les plates-formes Apple

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 pour regrouper le modèle en copiant ses fichiers dans votre projet Xcode ; vous pouvez les télécharger dynamiquement à partir de Firebase.

Options de regroupement des modèles
Intégré à votre application
  • Le modèle fait partie du lot
  • Le modèle est disponible immédiatement, même si l'appareil Apple est hors connexion
  • Pas besoin d'un projet Firebase
Hébergé avec Firebase
  • Hébergez le modèle en l'important dans Firebase Machine Learning
  • Réduction de la taille de l'app bundle
  • Le modèle est téléchargé à la demande
  • Déployer les mises à jour du modèle sans publier à nouveau votre application
  • Tests A/B faciles avec Firebase Remote Config
  • Nécessite un projet Firebase

Avant de commencer

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

    Pour regrouper un modèle avec votre application:

    pod 'GoogleMLKit/ImageLabelingCustom'
    

    Pour télécharger un modèle de manière dynamique depuis Firebase, ajoutez le LinkFirebase la dépendance:

    pod 'GoogleMLKit/ImageLabelingCustom'
    pod 'GoogleMLKit/LinkFirebase'
    
  2. Après avoir installé ou mis à jour les pods de votre projet, ouvrez votre projet Xcode à l'aide de son .xcworkspace. ML Kit est compatible avec Xcode version 12.2 ou plus élevée.

  3. Si vous souhaitez télécharger un modèle, assurez-vous ajouter Firebase à votre projet Android ; si vous ne l'avez pas déjà fait. Cela n'est pas nécessaire lorsque vous regroupez les du modèle de ML.

1. Charger le modèle

Configurer la source d'un modèle local

Pour regrouper le modèle avec votre application :

  1. Extrayez le modèle et ses métadonnées à partir de l'archive ZIP que vous avez téléchargée. de 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 lorsque vous les avez téléchargés, sans les modifier (y compris les noms des fichiers).

  2. Copiez le dossier dans votre projet Xcode, en prenant soin de sélectionner Créez des références à des dossiers lorsque vous effectuez cette opération. Le fichier de modèle et les métadonnées seront inclus dans l'app bundle et disponibles pour ML Kit.

  3. Créez un objet LocalModel 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 true }
    let localModel = LocalModel(manifestPath: manifestPath)
    

    Objective-C

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

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

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

Swift

// Initialize the model source with the name you assigned in
// the Firebase console.
let remoteModelSource = FirebaseModelSource(name: "your_remote_model")
let remoteModel = CustomRemoteModel(remoteModelSource: remoteModelSource)

Objective-C

// Initialize the model source with the name you assigned in
// the Firebase console.
MLKFirebaseModelSource *firebaseModelSource =
    [[MLKFirebaseModelSource alloc] initWithName:@"your_remote_model"];
MLKCustomRemoteModel *remoteModel =
    [[MLKCustomRemoteModel alloc] initWithRemoteModelSource:firebaseModelSource];

Ensuite, démarrez la tâche de téléchargement du modèle, en spécifiant les conditions dans lesquelles que vous souhaitez autoriser le téléchargement. Si le modèle ne figure pas sur l'appareil, ou si un modèle plus récent du modèle est disponible, la tâche téléchargera de manière asynchrone depuis 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] downloadRemoteModel: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 étiqueteur d'images à partir de votre modèle

Après avoir configuré les sources de votre modèle, créez un objet ImageLabeler à partir de l'un parmi d'autres.

Si vous ne disposez que d'un modèle groupé localement, il vous suffit de créer un étiqueteur à partir de votre LocalModel et configurer le score de confiance le seuil souhaité (voir Évaluer votre modèle):

Swift

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

Objective-C

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

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

Même si vous n'avez qu'à le confirmer avant d'exécuter l'étiqueteur, un modèle hébergé à distance et un modèle groupé localement, cela peut rendre d'effectuer cette vérification lors de l'instanciation de ImageLabeler: créez une étiqueteur du modèle distant s'il a été téléchargé, et du modèle local sinon.

Swift

var options: CustomImageLabelerOptions
if (ModelManager.modelManager().isModelDownloaded(remoteModel)) {
  options = CustomImageLabelerOptions(remoteModel: remoteModel)
} else {
  options = CustomImageLabelerOptions(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

MLKCustomImageLabelerOptions *options;
if ([[MLKModelManager modelManager] isModelDownloaded:remoteModel]) {
  options = [[MLKCustomImageLabelerOptions alloc] initWithRemoteModel:remoteModel];
} else {
  options = [[MLKCustomImageLabelerOptions alloc] initWithLocalModel:localModel];
}
options.confidenceThreshold = @(0.0f);  // 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 paramètres (par exemple, griser ou masquer une partie de l'interface utilisateur), vous confirmez 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 modèle Centre de notifications. Veillez à utiliser une référence faible à self dans l'observateur , car les téléchargements peuvent prendre un certain temps et que l'objet d'origine peut être libérées une fois le téléchargement terminé. Exemple :

Swift

NotificationCenter.default.addObserver(
    forName: .mlkitMLModelDownloadDidSucceed,
    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: .mlkitMLModelDownloadDidFail,
    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 objet VisionImage à l'aide d'un UIImage ou d'un CMSampleBufferRef.

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

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

    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 CMSampleBufferRef, procédez comme suit:

  • Spécifiez l'orientation des données d'image contenues dans le Mémoire tampon CMSampleBufferRef.

    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 position == AVCaptureDevicePositionFront ? UIImageOrientationLeftMirrored
                                                          : UIImageOrientationRight;
    
        case UIDeviceOrientationLandscapeLeft:
          return position == AVCaptureDevicePositionFront ? UIImageOrientationDownMirrored
                                                          : UIImageOrientationUp;
        case UIDeviceOrientationPortraitUpsideDown:
          return position == AVCaptureDevicePositionFront ? UIImageOrientationRightMirrored
                                                          : UIImageOrientationLeft;
        case UIDeviceOrientationLandscapeRight:
          return position == AVCaptureDevicePositionFront ? UIImageOrientationUpMirrored
                                                          : UIImageOrientationDown;
        case UIDeviceOrientationUnknown:
        case UIDeviceOrientationFaceUp:
        case UIDeviceOrientationFaceDown:
          return UIImageOrientationUp;
      }
    }
          
  • Créez un objet VisionImage à l'aide de l'objet et de l'orientation CMSampleBufferRef :

    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 libellé d'image

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<MLKImageLabel *> *_Nullable labels,
                   NSError *_Nullable error) {
        if (label.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<MLKImageLabel *> *labels =
    [imageLabeler resultsInImage:image error:&error];
// Show results or handle the error.

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

Si l'opération d'ajout d'étiquettes à l'image réussit, elle renvoie un tableau de ImageLabel Chaque ImageLabel représente un élément étiquetées sur 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 étiqueter des images dans une application en temps réel, suivez ces pour obtenir des fréquences d'images optimales:

  • Limiter les appels au détecteur. Si une nouvelle image vidéo devient disponible pendant l'exécution du détecteur, supprimez la trame.
  • Si vous utilisez la sortie du détecteur pour superposer des images l'image d'entrée, d'abord d'obtenir le résultat, puis d'effectuer le rendu de l'image et les superposer en une seule étape. Cela vous permet d'afficher sur la surface d'affichage une seule fois pour chaque trame d'entrée. Consultez la vue previewOverlayView. et FIRDetectionOverlayView dans l'application exemple Showcase.