Bilder auf Apple-Plattformen mit einem AutoML-trainierten Modell mit Labels versehen

Nachdem Sie Ihr eigenes Modell mit AutoML Vision Edge trainiert haben, können Sie es in Ihrer App zum Labeln von Bildern verwenden.

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

Optionen für die Kombination von Modellen
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
Mit Firebase gehostet
  • Das Modell hosten, indem Sie es in Firebase Machine Learning hochladen
  • App-Bundle-Größe reduzieren
  • Das Modell wird bei Bedarf heruntergeladen
  • Modellaktualisierungen per Push übertragen, ohne Ihre App neu zu veröffentlichen
  • Einfaches A/B‑Testing mit Firebase Remote Config
  • Firebase-Projekt erforderlich

Hinweis

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

    So binden Sie ein Modell in Ihre App ein:

    pod 'GoogleMLKit/ImageLabelingCustom'
    

    Wenn Sie ein Modell dynamisch aus Firebase herunterladen möchten, 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 der Datei .xcworkspace. ML Kit wird in Xcode-Version 12.2 oder höher unterstützt.

  3. Wenn Sie ein Modell herunterladen möchten, müssen Sie Firebase Ihrem Android-Projekt hinzufügen, falls Sie das noch nicht getan haben. Das ist nicht erforderlich, wenn Sie das Modell bündeln.

1. Modell laden

Lokale Modellquelle konfigurieren

So bündeln Sie das Modell mit Ihrer App:

  1. Extrahieren Sie das Modell und seine Metadaten aus dem ZIP-Archiv, das Sie aus 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, die Dateien so zu verwenden, wie Sie sie heruntergeladen haben, ohne Änderungen vorzunehmen (einschließlich der Dateinamen).

  2. Kopieren Sie den Ordner in Ihr Xcode-Projekt und achten Sie darauf, dass Sie dabei Create folder references (Ordnerreferenzen erstellen) auswählen. Die Modelldatei und die Metadaten werden in das App-Bundle aufgenommen und sind für ML Kit verfügbar.

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

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

Von Firebase gehostete Modellquelle konfigurieren

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

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

Starten Sie dann den Modell-Download und geben Sie die Bedingungen an, unter denen Sie das Herunterladen zulassen möchten. Wenn das Modell nicht auf dem Gerät vorhanden ist oder eine neuere Version des Modells verfügbar ist, wird das Modell asynchron von Firebase heruntergeladen:

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

Viele Apps starten den Downloadvorgang in ihrem Initialisierungscode, aber Sie können dies jederzeit tun, bevor Sie das Modell verwenden müssen.

Image-Labeler aus Ihrem Modell erstellen

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

Wenn Sie nur ein lokal gebündeltes Modell haben, erstellen Sie einfach einen Labeler aus Ihrem LocalModel-Objekt und konfigurieren Sie den erforderlichen Konfidenzwertschwellenwert (siehe Modell bewerten):

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

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

Sie müssen dies zwar nur vor dem Ausführen des Labelers bestätigen, aber wenn Sie sowohl ein remote gehostetes als auch ein lokal gebündeltes Modell haben, kann es sinnvoll sein, diese Prüfung beim Instanziieren von ImageLabeler durchzuführen: Erstellen Sie einen Labeler aus dem Remote-Modell, wenn es heruntergeladen wurde, und andernfalls aus dem lokalen Modell.

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

Wenn Sie nur ein Remote-Modell haben, sollten Sie modellbezogene Funktionen deaktivieren, z. B. einen Teil der 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 Standard-Notification Center anhängen. Verwenden Sie im Observer-Block unbedingt einen schwachen Verweis auf self, da Downloads einige Zeit dauern können und das ursprüngliche Objekt möglicherweise freigegeben wird, bevor der Download abgeschlossen ist. Beispiel:

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. Eingabebild vorbereiten

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

Wenn Sie ein UIImage verwenden, gehen Sie so vor:

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

    Swift

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

    Objective-C

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

Wenn Sie ein CMSampleBufferRef verwenden, gehen Sie so vor:

  • Gibt die Ausrichtung der Bilddaten im CMSampleBufferRef-Puffer an.

    So rufen Sie die Bildausrichtung ab:

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

    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. Bildlabeler ausführen

Asynchron:

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

Synchron:

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. Informationen zu gekennzeichneten Objekten abrufen

Wenn die Bildkennzeichnung erfolgreich ist, wird ein Array von ImageLabel zurückgegeben. Jedes ImageLabel steht für etwas, das auf dem Bild gekennzeichnet wurde. Sie können die Textbeschreibung (falls in den Metadaten der TensorFlow Lite-Modelldatei verfügbar), den Konfidenzwert und den Index für jedes Label abrufen. Beispiel:

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

Tipps zur Verbesserung der Echtzeitleistung

Wenn Sie Bilder in einer Echtzeitanwendung labeln möchten, sollten Sie die folgenden Richtlinien beachten, um die besten Framerates zu erzielen:

  • Drosseln Sie die Aufrufe des Detektors. Wenn ein neuer Videoframes verfügbar wird, während der Detektor ausgeführt wird, verwerfen Sie den Frame.
  • Wenn Sie die Ausgabe des Detektors verwenden, um Grafiken auf das Eingabebild zu legen, rufen Sie zuerst das Ergebnis ab und rendern Sie dann das Bild und das Overlay in einem einzigen Schritt. Dadurch wird für jeden Eingabe-Frame nur einmal auf die Displayoberfläche gerendert. Ein Beispiel finden Sie in den Klassen previewOverlayView und FIRDetectionOverlayView in der Showcase-Beispiel-App.