Mit ML Kit können Sie Entitäten in einem Bild erkennen und mit Labels versehen. Diese API unterstützt eine Vielzahl benutzerdefinierter Bildklassifizierungsmodelle. Weitere Informationen zu den Anforderungen an die Modellkompatibilität, zur Suche nach vortrainierten Modellen und zum Trainieren Ihrer eigenen Modelle finden Sie unter Benutzerdefinierte Modelle mit ML Kit.
Es gibt zwei Möglichkeiten, ein benutzerdefiniertes Modell zu integrieren. Sie können das Modell bündeln, indem Sie es in den Asset-Ordner Ihrer App stellen, oder es dynamisch aus Firebase herunterladen. In der folgenden Tabelle werden die beiden Optionen verglichen.
Gebündeltes Modell | Gehostetes Modell |
---|---|
Das Modell ist Teil des APK Ihrer App, das seine Größe vergrößert. | Das Modell ist nicht Teil Ihres APK. Sie wird durch Hochladen in Firebase Machine Learning gehostet. |
Das Modell ist sofort verfügbar, auch wenn das Android-Gerät offline ist | Das Modell wird bei Bedarf heruntergeladen |
Kein Firebase-Projekt erforderlich | Firebase-Projekt erforderlich |
Du musst deine App noch einmal veröffentlichen, um das Modell zu aktualisieren | Modellaktualisierungen ohne erneute Veröffentlichung Ihrer App veröffentlichen |
Keine integrierten A/B-Tests | Einfache A/B-Tests mit Firebase Remote Config |
Testen
- Ein Beispiel für die Verwendung des gebündelten Modells finden Sie in der Vision-Kurzanleitungs-App. Die Verwendung des gehosteten Modells wird in der Kurzanleitung für AutoML ML veranschaulicht.
Hinweis
Fügen Sie die ML Kit-Bibliotheken in Ihre Podfile-Datei ein:
So bündeln Sie ein Modell mit Ihrer App:
pod 'GoogleMLKit/ImageLabelingCustom', '3.2.0'
Fügen Sie die Abhängigkeit
LinkFirebase
hinzu, um ein Modell dynamisch aus Firebase herunterzuladen:pod 'GoogleMLKit/ImageLabelingCustom', '3.2.0' pod 'GoogleMLKit/LinkFirebase', '3.2.0'
Nachdem Sie die Pods Ihres Projekts installiert oder aktualisiert haben, öffnen Sie das Xcode-Projekt mit dessen
.xcworkspace
. ML Kit wird ab Xcode Version 13.2.1 unterstützt.Wenn Sie ein Modell herunterladen möchten, achten Sie darauf, dass Sie Ihrem iOS-Projekt Firebase hinzufügen, falls Sie dies noch nicht getan haben. Dies 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 auf
.tflite
oder.lite
enden) in Ihr Xcode-Projekt und wählen Sie dabeiCopy bundle resources
aus. Die Modelldatei ist im App Bundle enthalten und für ML Kit verfügbar.Erstellen Sie das Objekt
LocalModel
und geben Sie den Pfad zur Modelldatei an:Swift
let localModel = LocalModel(path: localModelFilePath)
Objective-C
MLKLocalModel *localModel = [[MLKLocalModel alloc] initWithPath:localModelFilePath];
Von Firebase gehostete Modellquelle konfigurieren
Wenn Sie das remote gehostete Modell verwenden möchten, erstellen Sie ein RemoteModel
-Objekt und geben Sie den Namen an, den Sie dem Modell bei der Veröffentlichung zugewiesen haben:
Swift
let firebaseModelSource = FirebaseModelSource( name: "your_remote_model") // The name you assigned in // the Firebase console. let remoteModel = CustomRemoteModel(remoteModelSource: firebaseModelSource)
Objective-C
MLKFirebaseModelSource *firebaseModelSource = [[MLKFirebaseModelSource alloc] initWithName:@"your_remote_model"]; // The name you assigned in // the Firebase console. MLKCustomRemoteModel *remoteModel = [[MLKCustomRemoteModel alloc] initWithRemoteModelSource:firebaseModelSource];
Starten Sie dann die Aufgabe zum Modelldownload 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 aus Firebase herunter:
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] downloadModel:remoteModel conditions:downloadConditions];
Viele Anwendungen starten die Downloadaufgabe in ihrem Initialisierungscode. Sie können dies jedoch jederzeit tun, bevor Sie das Modell verwenden müssen.
Image-Labelersteller konfigurieren
Nachdem Sie die Modellquellen konfiguriert haben, erstellen Sie aus einer dieser Quellen ein ImageLabeler
-Objekt.
Folgende Optionen sind verfügbar:
Optionen | |
---|---|
confidenceThreshold
|
Minimaler Konfidenzwert der erkannten Labels. Wenn nichts anderes festgelegt ist, wird jeder Klassifikatorgrenzwert verwendet, der in den Metadaten des Modells angegeben ist. Wenn das Modell keine Metadaten enthält oder die Metadaten keinen Klassifikatorschwellenwert angeben, wird der Standardgrenzwert 0,0 verwendet. |
maxResultCount
|
Maximale Anzahl der Labels, die zurückgegeben werden sollen. Wenn nicht festgelegt, wird der Standardwert 10 verwendet. |
Wenn Sie nur ein lokal gebündeltes Modell haben, erstellen Sie einfach einen Labelersteller 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 remote gehostetes Modell haben, müssen Sie prüfen, ob es heruntergeladen wurde, bevor Sie es ausführen. Sie können den Status der Modelldownloadaufgabe mit der Methode isModelDownloaded(remoteModel:)
des Modellmanagers prüfen.
Sie müssen dies zwar nur vor dem Ausführen des Labelerstellers bestätigen, aber wenn Sie sowohl ein remote gehostetes Modell als auch ein lokal gebündeltes Modell haben, kann es sinnvoll sein, diese Prüfung bei der Instanziierung von ImageLabeler
durchzuführen: Erstellen Sie einen Labeler für das Remote-Modell, wenn es heruntergeladen wurde, und anschließend 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) 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.0); 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 ausblenden oder ausblenden, bis Sie bestätigt haben, dass das Modell heruntergeladen wurde.
Sie können den Downloadstatus des Modells abrufen, indem Sie Betrachter an das Standardbenachrichtigungscenter anhängen. Achten Sie darauf, einen schwachen Verweis auf self
im Beobachterblock zu verwenden, da Downloads einige Zeit in Anspruch nehmen können und das ursprüngliche Objekt freigegeben werden kann, wenn der Download abgeschlossen ist. Beispiel:
Swift
NotificationCenter.default.addObserver( forName: .mlkitModelDownloadDidSucceed, 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: .mlkitModelDownloadDidFail, 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 CMSampleBuffer
.
Wenn Sie UIImage
verwenden, gehen Sie so vor:
- Erstellen Sie ein
VisionImage
-Objekt mitUIImage
. Achten Sie darauf, die richtige.orientation
anzugeben.Swift
let image = VisionImage(image: UIImage) visionImage.orientation = image.imageOrientation
Objective-C
MLKVisionImage *visionImage = [[MLKVisionImage alloc] initWithImage:image]; visionImage.orientation = image.imageOrientation;
Wenn Sie CMSampleBuffer
verwenden, gehen Sie so vor:
-
Gib die Ausrichtung der Bilddaten an, die in
CMSampleBuffer
enthalten sind.So erhalten Sie die Bildausrichtung:
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 ObjektCMSampleBuffer
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. Image-Labelersteller ausführen
Übergeben Sie das Objekt image
an die Methode process()
von ImageLabeler
, um Objekte in einem Bild mit Labels zu versehen.
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 Elementen mit Labels abrufen
Wenn der Vorgang zur Labelerstellung für Bilder erfolgreich ist, wird ein Array vonImageLabel
zurückgegeben. Jeder ImageLabel
steht für etwas, das im Bild mit einem Label versehen wurde. Sie können die Textbeschreibung jedes Labels (sofern in den Metadaten der TensorFlow Lite-Modelldatei verfügbar), den Konfidenzwert und den Index 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 mit Labels versehen möchten, beachten Sie die folgenden Best Practices, um die besten Framerates zu erzielen:
- Verwenden Sie zur Verarbeitung von Videoframes die synchrone API des Detektors
results(in:)
. Rufen Sie diese Methode über diecaptureOutput(_, didOutput:from:)
-Funktion derAVCaptureVideoDataOutputSampleBufferDelegate
auf, um synchron Ergebnisse aus dem angegebenen Videoframe zu erhalten. Behalten SiealwaysDiscardsLateVideoFrames
vonAVCaptureVideoDataOutput
alstrue
bei, um Aufrufe an den Detektor zu drosseln. Wenn während der Ausführung des Detektors ein neuer Videoframe verfügbar ist, wird er verworfen. - Wenn Sie die Ausgabe des Detektors verwenden, um Grafiken auf dem Eingabebild einzublenden, rufen Sie zuerst das Ergebnis aus ML Kit ab und rendern dann das Bild und das Overlay in einem einzigen Schritt. Dadurch wird die Anzeige für jeden verarbeiteten Eingabeframe nur einmal auf der Anzeigeoberfläche gerendert. Ein Beispiel findest du in der Kurzanleitung zu updatePreviewOverlayViewWithLastFrame.