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
- Ein Beispiel für die Verwendung des gebündelten Modells finden Sie in der Vision-Schnellstart-App und ein Beispiel für die Verwendung des gehosteten Modells in der AutoML-Schnellstart-App.
Hinweis
Fügen Sie die ML Kit-Bibliotheken in Ihre Podfile-Datei ein:
pod 'GoogleMLKit/ImageLabelingCustom', '8.0.0'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.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:
Kopieren Sie die Modelldatei (normalerweise mit der Endung
.tfliteoder.lite) in Ihr Xcode-Projekt und achten Sie darauf, dass Sie dabeiCopy bundle resourcesauswählen. Die Modelldatei wird in das App-Bundle aufgenommen und ist für ML Kit verfügbar.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 demUIImage. Achten Sie darauf, dass Sie die richtige.orientationangeben.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
CMSampleBufferenthalten 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 demCMSampleBuffer-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 vonImageLabel 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:
-
Verwenden Sie für die Verarbeitung von Videoframes die synchrone API
results(in:)des Detektors. Rufen Sie diese Methode über die FunktioncaptureOutput(_, didOutput:from:)desAVCaptureVideoDataOutputSampleBufferDelegateauf, um synchron Ergebnisse für den angegebenen Videoframes zu erhalten. Behalten SieAVCaptureVideoDataOutputalstruebei, um Aufrufe an den Detektor zu drosseln. Wenn ein neuer Videoframes verfügbar wird, während der Detektor ausgeführt wird, wird er verworfen.alwaysDiscardsLateVideoFrames - Wenn Sie die Ausgabe des Detektors verwenden, um Grafiken auf das Eingabebild zu legen, rufen Sie zuerst das Ergebnis von ML Kit ab und rendern Sie dann das Bild und das Overlay in einem einzigen Schritt. Dadurch wird für jeden verarbeiteten Eingabe-Frame nur einmal auf die Displayoberfläche gerendert. Ein Beispiel finden Sie in der updatePreviewOverlayViewWithLastFrame-Funktion im ML Kit-Schnellstartbeispiel.