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 zum Beschriften von Bildern verwenden.

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

Optionen zur Modellbündelung
In Ihrer App gebündelt
  • Das Modell ist Teil 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 auf Firebase Machine Learning hochladen
  • Reduziert die Größe des App-Bundles
  • Das Modell wird bei Bedarf heruntergeladen
  • Pushen Sie Modellaktualisierungen, ohne Ihre App erneut zu veröffentlichen
  • Einfaches A/B-Testen mit Firebase Remote Config
  • Erfordert ein Firebase-Projekt

Bevor Sie beginnen

  1. Fügen Sie die ML-Kit-Bibliotheken in Ihr Podfile 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 seiner .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 , sofern 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 dabei darauf, Ordnerverweise erstellen auszuwählen. Die Modelldatei und die Metadaten werden im App-Bundle enthalten und für ML Kit verfügbar sein.

  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 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 den Download 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, Sie können dies jedoch jederzeit tun, bevor Sie das Modell verwenden müssen.

Erstellen Sie aus Ihrem Modell einen Bildbeschrifter

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

Wenn Sie nur über ein lokal gebündeltes Modell verfügen, erstellen Sie einfach einen Labeler aus Ihrem LocalModel Objekt und konfigurieren Sie den Schwellenwert für die Konfidenzbewertung, den Sie benötigen möchten (siehe Bewerten Sie Ihr Modell ):

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 über ein remote gehostetes Modell verfügen, müssen Sie überprüfen, ob es heruntergeladen wurde, bevor Sie es ausführen. Sie können den Status der Modell-Download-Aufgabe mithilfe der Methode isModelDownloaded(remoteModel:) des Modellmanagers überprüfen.

Obwohl Sie dies nur bestätigen müssen, bevor Sie den Labeler ausführen, kann es sinnvoll sein, diese Prüfung bei der Instanziierung des ImageLabeler durchzuführen, wenn Sie sowohl über ein remote gehostetes Modell als auch über ein lokal gebündeltes Modell verfügen: Erstellen Sie ggf. einen Labeler aus dem Remote-Modell heruntergeladen wurden, andernfalls 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. einen Teil Ihrer Benutzeroberfläche ausgrauen oder ausblenden), bis Sie bestätigen, dass das Modell heruntergeladen wurde.

Sie können den Modell-Download-Status abrufen, indem Sie Beobachter an das Standard-Benachrichtigungscenter anhängen. Stellen Sie sicher, dass Sie im Beobachterblock einen schwachen Verweis auf self verwenden, da Downloads einige Zeit dauern können und das ursprüngliche Objekt bis zum Abschluss des Downloads freigegeben werden kann. Zum Beispiel:

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 . Stellen Sie sicher, dass Sie die richtige .orientation angeben.

    Schnell

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

    Ziel c

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

Wenn Sie CMSampleBufferRef verwenden, führen Sie die folgenden Schritte aus:

  • 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 Bildbeschrifter 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 gekennzeichnete Objekte

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

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:

  • Gasrufe an den Detektor. Wenn ein neues Videobild verfügbar wird, während der Detektor läuft, löschen Sie das Bild.
  • Wenn Sie die Ausgabe des Detektors verwenden, um Grafiken auf dem Eingabebild zu überlagern, rufen Sie zuerst das Ergebnis ab, rendern Sie dann das Bild und überlagern Sie es in einem einzigen Schritt. Auf diese Weise rendern Sie für jeden Eingaberahmen nur einmal auf der Anzeigeoberfläche. Ein Beispiel finden Sie in den Klassen „previewOverlayView“ und „FIRDetectionOverlayView“ in der Showcase-Beispiel-App.