Ajouter un libellé aux images avec un modèle personnalisé sur iOS

Vous pouvez utiliser ML Kit pour reconnaître des entités dans une image et les étiqueter. Cette API est compatible avec un large éventail de modèles personnalisés de classification d'images. Veuillez consultez Modèles personnalisés avec ML Kit pour obtenir des conseils les exigences de compatibilité des modèles, où trouver des modèles pré-entraînés, et comment entraîner vos propres modèles.

Il existe deux façons d'intégrer un modèle personnalisé. Vous pouvez grouper le modèle en le plaçant dans le dossier de composants de votre application, ou vous pouvez le télécharger depuis Firebase. Le tableau suivant compare les deux options.

Modèle groupé Modèle hébergé
Le modèle fait partie de l'APK de votre application, ce qui augmente sa taille. Le modèle ne fait pas partie de votre APK. Il est hébergé par l'importation dans Firebase Machine Learning.
Le modèle est disponible immédiatement, même lorsque l'appareil Android est hors connexion Le modèle est téléchargé à la demande
Pas besoin d'un projet Firebase Nécessite un projet Firebase
Vous devez publier à nouveau votre application pour mettre à jour le modèle Déployer les mises à jour du modèle sans publier à nouveau votre application
Pas de tests A/B intégrés Tests A/B faciles avec Firebase Remote Config

Essayer

Avant de commencer

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

    Pour regrouper un modèle avec votre application:

    pod 'GoogleMLKit/ImageLabelingCustom', '3.2.0'
    

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

    pod 'GoogleMLKit/ImageLabelingCustom', '3.2.0'
    pod 'GoogleMLKit/LinkFirebase', '3.2.0'
    
  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 13.2.1 ou supérieur.

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

1. Charger le modèle

Configurer une source de modèle locale

Pour empaqueter le modèle avec votre application:

  1. Copiez le fichier de modèle (se terminant généralement par .tflite ou .lite) dans votre Xcode. projet, en prenant soin de sélectionner Copy bundle resources lorsque vous le faites. La sera inclus dans l'app bundle et disponible pour ML Kit.

  2. Créez l'objet LocalModel en spécifiant le chemin d'accès au fichier de modèle:

    Swift

    let localModel = LocalModel(path: localModelFilePath)

    Objective-C

    MLKLocalModel *localModel =
        [[MLKLocalModel alloc] initWithPath:localModelFilePath];

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

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

Swift

let firebaseModelSource = FirebaseModelSource(
    name: "your_remote_model") // The name you assigned in
                               // the Firebase console.
let remoteModel = CustomRemoteModel(remoteModelSource: firebaseModelSource)

Objective-C

MLKFirebaseModelSource *firebaseModelSource =
    [[MLKFirebaseModelSource alloc]
        initWithName:@"your_remote_model"]; // The name you assigned in
                                            // the Firebase console.
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] downloadModel:remoteModel
                                       conditions:downloadConditions];

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

Configurer l'étiqueteur d'images

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

Les options suivantes sont disponibles :

Options
confidenceThreshold

Score de confiance minimal des étiquettes détectées. Si ce champ n'est pas défini, spécifié par les métadonnées du modèle sera utilisé. Si le modèle ne contient pas de métadonnées spécifiez un seuil de classificateur, un seuil par défaut de 0.0 utilisé.

maxResultCount

Nombre maximal d'étiquettes à renvoyer. Si ce champ n'est pas défini, la valeur par défaut de 10 seront utilisés.

Si vous ne disposez que d'un modèle groupé localement, il vous suffit de créer un étiqueteur à partir de votre Objet LocalModel:

Swift

let options = CustomImageLabelerOptions(localModel: localModel)
options.confidenceThreshold = NSNumber(value: 0.0)
let imageLabeler = ImageLabeler.imageLabeler(options: options)

Objective-C

MLKCustomImageLabelerOptions *options =
    [[MLKCustomImageLabelerOptions alloc] initWithLocalModel:localModel];
options.confidenceThreshold = @(0.0);
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ée 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)
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.0);
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: .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 objet VisionImage à l'aide d'un UIImage ou d'un CMSampleBuffer

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 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 la classe Objet CMSampleBuffer et 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'étiqueteur d'images

Pour ajouter un libellé aux objets d'une image, transmettez l'objet image aux classes ImageLabeler. process().

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 (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 *labels =
    [imageLabeler resultsInImage:image error:&error];
// Show results or handle the error.

4. Obtenir des informations sur les entités avec libellé

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:

  • Pour traiter les images vidéo, utilisez l'API synchrone results(in:) du détecteur. Appeler cette méthode à partir de AVCaptureVideoDataOutputSampleBufferDelegate <ph type="x-smartling-placeholder"></ph> captureOutput(_, didOutput:from:) pour obtenir les résultats d'une vidéo donnée de manière synchrone. cadre. Conserver <ph type="x-smartling-placeholder"></ph> de AVCaptureVideoDataOutput alwaysDiscardsLateVideoFrames en tant que true afin de limiter les appels au détecteur. Si un nouveau l'image vidéo devient disponible pendant l'exécution du détecteur, elle est ignorée.
  • Si vous utilisez la sortie du détecteur pour superposer des graphiques sur 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. Cela vous permet d'afficher sur la surface d'affichage une seule fois pour chaque trame d'entrée traitée. Consultez la classe updatePreviewOverlayViewWithLastFrame. dans l'exemple de démarrage rapide de ML Kit.