Beschriften Sie Bilder mit einem AutoML-trainierten Modell auf Apple-Plattformen

Nachdem Sie Ihr eigenes Modell mit AutoML Vision Edge trainiert haben, können Sie es in Ihrer App verwenden, um Bilder zu beschriften.

Es gibt zwei Möglichkeiten, Modelle zu integrieren, die von AutoML Vision Edge trainiert wurden. Sie können das Modell bündeln, indem Sie die Dateien des Modells in Ihr Xcode-Projekt kopieren, oder Sie können es dynamisch von Firebase herunterladen.

Modellbündelungsoptionen
Gebündelt in Ihrer App
  • Das Modell ist Bestandteil des Bundles
  • Das Modell ist sofort verfügbar, auch wenn das Apple-Gerät offline ist
  • Kein Firebase-Projekt erforderlich
Gehostet mit Firebase
  • Hosten Sie das Modell, indem Sie es in Firebase Machine Learning hochladen
  • Reduziert die Größe des App-Pakets
  • Das Modell wird bei Bedarf heruntergeladen
  • Pushen Sie Modellaktualisierungen, ohne Ihre App erneut zu veröffentlichen
  • Einfache A/B-Tests mit Firebase Remote Config
  • Erfordert ein Firebase-Projekt

Bevor Sie beginnen

  1. Fügen Sie die ML Kit-Bibliotheken in Ihre Poddatei ein:

    So bündeln Sie ein Modell mit Ihrer App:

    pod 'GoogleMLKit/ImageLabelingCustom'
    

    Um ein Modell dynamisch von Firebase herunterzuladen, fügen Sie die LinkFirebase Abhängigkeit hinzu:

    pod 'GoogleMLKit/ImageLabelingCustom'
    pod 'GoogleMLKit/LinkFirebase'
    
  2. Nachdem Sie die Pods Ihres Projekts installiert oder aktualisiert haben, öffnen Sie Ihr Xcode-Projekt mit seinem .xcworkspace . ML Kit wird in Xcode-Version 12.2 oder höher unterstützt.

  3. Wenn Sie ein Modell herunterladen möchten , stellen Sie sicher, dass Sie Firebase zu Ihrem Android-Projekt hinzufügen , falls Sie dies noch nicht getan haben. Dies ist nicht erforderlich, wenn Sie das Modell bündeln.

1. Laden Sie das Modell

Konfigurieren Sie eine lokale Modellquelle

So bündeln Sie das Modell mit Ihrer App:

  1. Extrahieren Sie das Modell und seine Metadaten aus dem ZIP-Archiv, das Sie von der Firebase-Konsole heruntergeladen haben, in einen Ordner:

    your_model_directory
      |____dict.txt
      |____manifest.json
      |____model.tflite
    

    Alle drei Dateien müssen sich im selben Ordner befinden. Wir empfehlen Ihnen, die Dateien so zu verwenden, wie Sie sie heruntergeladen haben, ohne Änderungen (einschließlich der Dateinamen).

  2. Kopieren Sie den Ordner in Ihr Xcode-Projekt und achten Sie darauf, dass Sie dabei Ordnerverweise erstellen auswählen. Die Modelldatei und die Metadaten werden in das App-Bundle aufgenommen und stehen ML Kit zur Verfügung.

  3. Erstellen Sie LocalModel Objekt und geben Sie den Pfad zur Modellmanifestdatei an:

    Schnell

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

    Ziel c

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

Konfigurieren Sie eine von Firebase gehostete Modellquelle

Um das remote gehostete Modell zu verwenden, erstellen Sie ein CustomRemoteModel -Objekt und geben Sie dabei den Namen an, den Sie dem Modell beim Veröffentlichen zugewiesen haben:

Schnell

// 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)

Ziel 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];

Starten Sie dann die Aufgabe zum Herunterladen des Modells und geben Sie die Bedingungen an, unter denen Sie das Herunterladen zulassen möchten. Wenn sich das Modell nicht auf dem Gerät befindet oder eine neuere Version des Modells verfügbar ist, lädt die Aufgabe das Modell asynchron von Firebase herunter:

Schnell

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

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

Ziel c

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

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

Viele Apps starten die Download-Aufgabe in ihrem Initialisierungscode, aber Sie können dies jederzeit tun, bevor Sie das Modell verwenden müssen.

Erstellen Sie einen Bildbezeichner aus Ihrem Modell

Nachdem Sie Ihre Modellquellen konfiguriert haben, erstellen Sie ein ImageLabeler -Objekt aus einer davon.

Wenn Sie nur ein lokal gebündeltes Modell haben, erstellen Sie einfach einen Labeler aus Ihrem LocalModel Objekt und konfigurieren Sie den gewünschten Konfidenzwert-Schwellenwert (siehe Evaluieren Ihres Modells ):

Schnell

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)

Ziel 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];

Wenn Sie ein remote gehostetes Modell haben, müssen Sie überprüfen, ob es heruntergeladen wurde, bevor Sie es ausführen. Sie können den Status der Modell-Download-Aufgabe mit der isModelDownloaded(remoteModel:) Methode des Modellmanagers überprüfen.

Obwohl Sie dies nur bestätigen müssen, bevor Sie den Labeler ausführen, kann es sinnvoll sein, wenn Sie sowohl ein remote gehostetes als auch ein lokal gebündeltes Modell haben, diese Überprüfung beim Instanziieren von ImageLabeler : Erstellen Sie einen Labeler aus dem Remote-Modell, falls dies der Fall ist heruntergeladen wurden, und ansonsten vom lokalen Modell.

Schnell

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)

Ziel 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];

Wenn Sie nur über ein remote gehostetes Modell verfügen, sollten Sie modellbezogene Funktionen deaktivieren, z. B. Teile Ihrer Benutzeroberfläche ausgrauen oder ausblenden, bis Sie bestätigen, dass das Modell heruntergeladen wurde.

Sie können den Downloadstatus des Modells abrufen, indem Sie Beobachter an das standardmäßige Benachrichtigungscenter anhängen. Stellen Sie sicher, dass Sie im Beobachterblock einen schwachen Verweis auf sich self verwenden, da Downloads einige Zeit dauern können und das Ursprungsobjekt bis zum Abschluss des Downloads freigegeben werden kann. Beispielsweise:

Schnell

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]
    // ...
}

Ziel 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. Bereiten Sie das Eingabebild vor

Erstellen Sie ein VisionImage Objekt mit einem UIImage oder einem CMSampleBufferRef .

Wenn Sie ein UIImage verwenden, gehen Sie folgendermaßen vor:

  • Erstellen Sie ein VisionImage Objekt mit dem UIImage . Achten Sie darauf, die richtige .orientation .

    Schnell

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

    Ziel c

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

Wenn Sie eine CMSampleBufferRef verwenden, gehen Sie folgendermaßen vor:

  • Geben Sie die Ausrichtung der im CMSampleBufferRef Puffer enthaltenen Bilddaten an.

    So erhalten Sie die Bildausrichtung:

    Schnell

    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
      }
    }
          

    Ziel 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;
      }
    }
          
  • Erstellen Sie ein VisionImage Objekt mit dem CMSampleBufferRef Objekt und der Ausrichtung:

    Schnell

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

    Ziel c

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

3. Führen Sie den Image-Labeler aus

Asynchron:

Schnell

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

Ziel c

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

Synchron:

Schnell

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

Ziel c

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

4. Informieren Sie sich über beschriftete Objekte

Wenn der Bildkennzeichnungsvorgang erfolgreich ist, wird ein Array von ImageLabel . Jedes ImageLabel stellt etwas dar, das im Bild beschriftet wurde. Sie können die Textbeschreibung jedes Labels (falls in den Metadaten der TensorFlow Lite-Modelldatei verfügbar), den Konfidenzwert und den Index abrufen. Beispielsweise:

Schnell

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

Ziel c

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

Tipps zur Verbesserung der Echtzeitleistung

Wenn Sie Bilder in einer Echtzeitanwendung beschriften möchten, befolgen Sie diese Richtlinien, um die besten Frameraten zu erzielen:

  • Drosselrufe an den Detektor. Wenn ein neuer Videoframe verfügbar wird, während der Detektor läuft, löschen Sie den Frame.
  • Wenn Sie die Ausgabe des Detektors verwenden, um Grafiken über das Eingabebild zu legen, erhalten Sie zuerst das Ergebnis, rendern dann das Bild und überlagern es in einem einzigen Schritt. Dadurch rendern Sie für jeden Eingabeframe nur einmal auf der Anzeigeoberfläche. Ein Beispiel finden Sie in den Klassen previewOverlayView und FIRDetectionOverlayView in der Showcase-Beispiel-App.