Bilder mit einem benutzerdefinierten Modell unter iOS mit Labels versehen

Mit ML Kit können Sie Objekte in einem Bild erkennen und mit Labels versehen. Diese API unterstützt eine Vielzahl von benutzerdefinierten Bildklassifizierungsmodellen. Weitere Informationen zu den Anforderungen an die Modellkompatibilität, dazu, wo Sie vortrainierte Modelle finden und wie Sie eigene Modelle trainieren, finden Sie unter Benutzerdefinierte Modelle mit ML Kit.

Es gibt zwei Möglichkeiten, ein benutzerdefiniertes Modell einzubinden. Sie können das Modell bündeln, indem Sie es in den Asset-Ordner Ihrer App einfügen, oder es dynamisch aus Cloud Storage herunterladen. In der folgenden Tabelle werden die beiden Optionen verglichen.

Gebündeltes Modell Gehostetes Modell
Das Modell ist Teil des APKs Ihrer App, was die Größe erhöht. Das Modell ist nicht Teil Ihres APKs. Es wird gehostet, indem es in Cloud Storage hochgeladen wird. Wir empfehlen die Verwendung von Cloud Storage for Firebase.
Das Modell ist sofort verfügbar, auch wenn das Android-Gerät offline ist. Ihre App muss Code enthalten, mit dem das Modell bei Bedarf heruntergeladen wird.
Kein Firebase-Projekt erforderlich Erfordert ein Firebase-Projekt (bei Verwendung von Cloud Storage for Firebase).
Sie müssen Ihre App neu veröffentlichen, um das Modell zu aktualisieren Modellupdates per Push übertragen, ohne die App neu zu veröffentlichen
Keine integrierten A/B-Tests A/B-Tests mit Firebase Remote Config

Jetzt ausprobieren

Hinweis

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

    pod 'GoogleMLKit/ImageLabelingCustom', '8.0.0'
    
  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 13.2.1 oder höher unterstützt.

  3. Wenn Sie ein Modell mit Cloud Storage for Firebase herunterladen möchten, müssen Sie Firebase zu Ihrem iOS-Projekt hinzufügen, sofern 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. Kopieren Sie die Modelldatei (normalerweise mit der Endung .tflite oder .lite) in Ihr Xcode-Projekt und achten Sie darauf, dass Sie dabei Copy bundle resources auswählen. Die Modelldatei wird in das App-Bundle aufgenommen und ist für ML Kit verfügbar.

  2. Erstellen Sie ein LocalModel-Objekt und geben Sie den Pfad zur Modelldatei an:

    Swift

    let localModel = LocalModel(path: localModelFilePath)

    Objective-C

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

Remote gehostete Modellquelle konfigurieren

Wenn Sie das remote gehostete Modell verwenden möchten, müssen Sie die Modelldatei mit Ihrer eigenen App-Logik in den lokalen Speicher des Geräts herunterladen und dann als lokales Modell laden. Wir empfehlen, Cloud Storage for Firebase zum Hosten eines Modells zu verwenden. Implementierungsdetails finden Sie im Migrationsleitfaden für Firebase ML zu Cloud Storage.

Bildlabeler konfigurieren

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

Folgende Optionen sind verfügbar:

Optionen
confidenceThreshold

Mindestkonfidenzwert für erkannte Labels. Wenn nicht festgelegt, wird ein beliebiger Klassifikatorschwellenwert verwendet, der in den Metadaten des Modells angegeben ist. Wenn das Modell keine Metadaten enthält oder in den Metadaten kein Klassifikatorschwellenwert angegeben ist, wird der Standardschwellenwert 0,0 verwendet.

maxResultCount

Maximale Anzahl der zurückzugebenden Labels. Wenn nicht festgelegt, wird der Standardwert 10 verwendet.

Wenn Sie nur ein lokal gebündeltes Modell haben, erstellen Sie einfach einen Labeler aus Ihrem LocalModel-Objekt:

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

Wenn Sie ein Modell haben, das auf einem Remote-Server gehostet wird, müssen Sie prüfen, ob es heruntergeladen wurde, bevor Sie es ausführen.

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

// Path where your download logic saves the model
let documentDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
let localModelURL = documentDirectory.appendingPathComponent("my_remote_model.tflite")

let model: LocalModel
if FileManager.default.fileExists(atPath: localModelURL.path) {
  // Use the downloaded model
  model = LocalModel(path: localModelURL.path)
} else {
  // Fall back to bundled model
  guard let bundledModelPath = Bundle.main.path(forResource: "model", ofType: "tflite") else { return }
  model = LocalModel(path: bundledModelPath)
}

let options = CustomImageLabelerOptions(localModel: model)
let imageLabeler = ImageLabeler.imageLabeler(options: options)

Objective-C

NSString *documentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject];
NSString *localModelPath = [documentsDirectory stringByAppendingPathComponent:@"my_remote_model.tflite"];

MLKLocalModel *model;
if ([NSFileManager.defaultManager fileExistsAtPath:localModelPath]) {
  // Use the downloaded model
  model = [[MLKLocalModel alloc] initWithPath:localModelPath];
} else {
  // Fall back to bundled model
  NSString *bundledModelPath = [NSBundle.mainBundle pathForResource:@"model" ofType:@"tflite"];
  model = [[MLKLocalModel alloc] initWithPath:bundledModelPath];
}

MLKCustomImageLabelerOptions *options = [[MLKCustomImageLabelerOptions alloc] initWithLocalModel:model];
MLKImageLabeler *imageLabeler = [MLKImageLabeler imageLabelerWithOptions:options];

Wenn Sie nur ein remote gehostetes 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.

Swift

let documentDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
let localModelURL = documentDirectory.appendingPathComponent("my_remote_model.tflite")
if FileManager.default.fileExists(atPath: localModelURL.path) {
  // Model is already cached, initialize immediately
  self.initializeLabeler(with: localModelURL)
} else {
  // Model is not yet available, show loading UI and start download
  self.showLoadingUI()
  let storage = Storage.storage()
  let modelRef = storage.reference(forURL: "gs://YOUR_BUCKET/path/to/model.tflite")
  modelRef.write(toFile: localModelURL) { url, error in
    self.hideLoadingUI()
    if let error = error {
      // Handle download error
      self.showErrorUI()
    } else if let modelURL = url {
      // Download success, initialize labeler
      self.initializeLabeler(with: modelURL)
    }
  }
}

func initializeLabeler(with modelURL: URL) {
  let localModel = LocalModel(path: modelURL.path)
  let options = CustomImageLabelerOptions(localModel: localModel)
  self.imageLabeler = ImageLabeler.imageLabeler(options: options)
  // Enable ML-related UI features here
  self.enableMLFeatures()
}

Objective-C

NSString *documentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject];
NSString *localModelPath = [documentsDirectory stringByAppendingPathComponent:@"my_remote_model.tflite"];
NSURL *localModelURL = [NSURL fileURLWithPath:localModelPath];

if ([NSFileManager.defaultManager fileExistsAtPath:localModelPath]) {
  // Model is already cached, initialize immediately
  [self initializeLabelerWithURL:localModelURL];
} else {
  // Model is not yet available, show loading UI and start download
  [self showLoadingUI];

  FIRStorage *storage = [FIRStorage storage];
  FIRStorageReference *modelRef = [storage referenceForURL:@"gs://YOUR_BUCKET/path/to/model.tflite"];

  [modelRef writeToFile:localModelURL
             completion:^(NSURL * _Nullable URL, NSError * _Nullable error) {
               [self hideLoadingUI];
               if (error != nil) {
                 // Handle download error
                 [self showErrorUI];
               } else {
                 // Download success, initialize labeler
                 [self initializeLabelerWithURL:URL];
               }
             }];
}

- (void)initializeLabelerWithURL:(NSURL *)modelURL {
  MLKLocalModel *localModel = [[MLKLocalModel alloc] initWithPath:modelURL.path];
  MLKCustomImageLabelerOptions *options = [[MLKCustomImageLabelerOptions alloc] initWithLocalModel:localModel];
  self.imageLabeler = [MLKImageLabeler imageLabelerWithOptions:options];

  // Enable ML-related UI features here
  [self enableMLFeatures];
}

2. Eingabebild vorbereiten

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

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 CMSampleBuffer verwenden, gehen Sie so vor:

  • Geben Sie die Ausrichtung der Bilddaten an, die in CMSampleBuffer enthalten sind.

    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 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;
      }
    }
          
  • Erstellen Sie ein VisionImage-Objekt mit dem CMSampleBuffer-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

Wenn Sie Objekte in einem Bild mit Labels versehen möchten, übergeben Sie das image-Objekt an die process()-Methode von ImageLabeler.

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

4. Informationen zu gelabelten Entitäten 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 LiteRT-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: