Oznaczaj obrazy etykietami z użyciem modelu wytrenowanego przez AutoML na urządzeniu z iOS
Po wytrenowaniu własnego modelu z użyciem AutoML Vision Edge możesz użyć go w aplikacji do oznaczania obrazów etykietami.
Istnieją 2 sposoby integracji modeli wytrenowanych w AutoML Vision Edge. Możesz połączyć model, kopiując jego pliki do projektu Xcode, lub dynamicznie pobierać go z Firebase.
Opcje grupowania modeli | |
---|---|
Grupowanie w Twojej aplikacji |
|
Hostowane w Firebase |
|
Wypróbuj
- Przetestuj przykładową aplikację, aby zobaczyć przykład użycia tego interfejsu API.
Zanim zaczniesz
1. Dodaj biblioteki ML Kit w pliku Podfile:Aby połączyć model w pakiet z aplikacją:
pod 'GoogleMLKit/ImageLabelingAutoML'Aby dynamicznie pobierać model z Firebase, dodaj zależność
LinkFirebase
:
pod 'GoogleMLKit/ImageLabelingAutoML' pod 'GoogleMLKit/LinkFirebase'2. Po zainstalowaniu lub zaktualizowaniu podów projektu otwórz projekt Xcode, używając jego
.xcworkspace
kodu>. Pakiet ML Kit jest obsługiwany w Xcode w wersji 13.2.1 lub nowszej.
3. Jeśli chcesz pobrać model, dodaj Firebase do projektu iOS, jeśli jeszcze nie zostało to zrobione. Nie jest to wymagane podczas pakowania modelu.
1. Wczytywanie modelu
Skonfiguruj źródło modelu lokalnego
Aby połączyć model z aplikacją:1. Wyodrębnij model i jego metadane z archiwum ZIP pobranego z konsoli Firebase do folderu:
your_model_directory |____dict.txt |____manifest.json |____model.tfliteWszystkie 3 pliki muszą znajdować się w tym samym folderze. Zalecamy używanie plików w takiej postaci, w jakiej zostały pobrane, bez modyfikacji (w tym nazw plików).
2. Skopiuj folder do projektu Xcode, zaznaczając przy tym opcję Utwórz odwołania do folderów. Plik modelu i metadane zostaną dołączone do pakietu aplikacji i będą dostępne dla ML Kit.
3. Utwórz obiekt
AutoMLImageLabelerLocalModel
, podając ścieżkę do pliku manifestu modelu:
Swift
guard let manifestPath = Bundle.main.path( forResource: "manifest", ofType: "json", inDirectory: "your_model_directory" ) else { return } let localModel = AutoMLImageLabelerLocalModel(manifestPath: manifestPath)
Objective-C
NSString *manifestPath = [NSBundle.mainBundle pathForResource:@"manifest" ofType:@"json" inDirectory:@"your_model_directory"]; MLKAutoMLImageLabelerLocalModel *localModel = [[MLKAutoMLImageLabelerLocalModel alloc] initWithManifestPath:manifestPath];
Skonfiguruj źródło modelu hostowane w Firebase
Aby użyć modelu hostowanego zdalnie, utwórz obiekt AutoMLImageLabelerRemoteModel
z nazwą przypisaną do modelu w momencie jego opublikowania:
Swift
let remoteModel = AutoMLImageLabelerRemoteModel( name: "your_remote_model" // The name you assigned in // the Firebase console. )
Objective-C
MLKAutoMLImageLabelerRemoteModel *remoteModel = [[MLKAutoMLImageLabelerRemoteModel alloc] initWithName:@"your_remote_model"]; // The name you assigned in // the Firebase console.
Następnie rozpocznij zadanie pobierania modelu, określając warunki, które mają mieć wpływ na pobieranie. Jeśli modelu nie ma na urządzeniu lub dostępna jest jego nowsza wersja, zadanie asynchronicznie pobierze model z Firebase:
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];
Wiele aplikacji rozpoczyna zadanie pobierania w kodzie inicjowania, ale możesz to zrobić w dowolnym momencie, zanim będzie można używać modelu.
Tworzenie osoby oznaczającej obrazy na podstawie modelu
Po skonfigurowaniu źródeł modelu utwórz na podstawie jednego z nich obiekt ImageLabeler
.
Jeśli masz tylko model dołączony lokalnie, po prostu utwórz osobę oznaczającą etykietami na podstawie obiektu AutoMLImageLabelerLocalModel
i skonfiguruj wymagany próg ufności (zobacz Ocena trybu:
Swift
let options = AutoMLImageLabelerOptions(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
MLKAutoMLImageLabelerOptions *options = [[MLKAutoMLImageLabelerOptions alloc] initWithLocalModel:localModel]; options.confidenceThreshold = @(0.0); // Evaluate your model in the Firebase console // to determine an appropriate value. MLKImageLabeler *imageLabeler = [MLKImageLabeler imageLabelerWithOptions:options];
Jeśli masz model hostowany zdalnie, przed jego uruchomieniem musisz sprawdzić, czy został on pobrany. Stan zadania pobierania modelu możesz sprawdzić za pomocą metody isModelDownloaded
(remoteModel:) menedżera modeli.
Chociaż musisz to potwierdzić przed uruchomieniem narzędzia do etykietowania, jeśli masz zarówno model hostowany zdalnie, jak i model połączony lokalnie, warto to sprawdzić podczas tworzenia wystąpienia obiektu ImageLabeler
: utwórz etykietę z modelu zdalnego (jeśli został on pobrany) lub z modelu lokalnego, w przeciwnym razie.
Swift
var options: AutoMLImageLabelerOptions! if (ModelManager.modelManager().isModelDownloaded(remoteModel)) { options = AutoMLImageLabelerOptions(remoteModel: remoteModel) } else { options = AutoMLImageLabelerOptions(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
MLKAutoMLImageLabelerOptions *options; if ([[MLKModelManager modelManager] isModelDownloaded:remoteModel]) { options = [[MLKAutoMLImageLabelerOptions alloc] initWithRemoteModel:remoteModel]; } else { options = [[MLKAutoMLImageLabelerOptions alloc] initWithLocalModel:localModel]; } options.confidenceThreshold = @(0.0); // Evaluate your model in the Firebase console // to determine an appropriate value. MLKImageLabeler *imageLabeler = [MLKImageLabeler imageLabelerWithOptions:options];
Jeśli masz tylko model hostowany zdalnie, wyłącz funkcje związane z nim – na przykład wyszarzanie lub ukrycie części interfejsu użytkownika do czasu potwierdzenia, że model został pobrany.
Stan pobierania modelu możesz uzyskać, dołączając obserwatorów do domyślnego Centrum powiadomień. Pamiętaj, aby w bloku obserwatora używać słabego odniesienia do self
, ponieważ pobieranie może trochę potrwać, a obiekt źródłowy może zostać zwolniony do czasu zakończenia pobierania. Na przykład:
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. Przygotowywanie obrazu wejściowego
Utwórz obiekt VisionImage
za pomocą UIImage
lub CMSampleBuffer
.
Jeśli używasz konta UIImage
, wykonaj te czynności:
- Utwórz obiekt
VisionImage
zUIImage
. Pamiętaj, aby podać prawidłowy atrybut.orientation
.Swift
let image = VisionImage(image: UIImage) visionImage.orientation = image.imageOrientation
Objective-C
MLKVisionImage *visionImage = [[MLKVisionImage alloc] initWithImage:image]; visionImage.orientation = image.imageOrientation;
Jeśli używasz konta CMSampleBuffer
, wykonaj te czynności:
-
Określ orientację danych obrazu zawartych w pliku
CMSampleBuffer
.Aby określić orientację zdjęcia:
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; } }
- Utwórz obiekt
VisionImage
, używając obiektuCMSampleBuffer
i orientacji: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. Uruchamianie narzędzia do oznaczania obrazów
Asynchronicznie:
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 (labels.count == 0) { // Handle the error. return; } // Show results. }];
Synchronizacja:
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. Uzyskaj informacje o obiektach z etykietami
Jeśli operacja oznaczania obrazów etykietami się powiedzie, zwróci tablicęImageLabel
. Każdy element ImageLabel
reprezentuje coś, co zostało oznaczone na obrazie. Możesz uzyskać opis tekstowy każdej etykiety (jeśli jest dostępny w metadanych pliku modelu TensorFlow Lite), wskaźnik ufności i indeks.
Na przykład:
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; }
Wskazówki dotyczące poprawy skuteczności w czasie rzeczywistym
Jeśli chcesz oznaczać etykietami obrazy w aplikacji czasu rzeczywistego, postępuj zgodnie z tymi wskazówkami, aby uzyskać najlepszą liczbę klatek:
- Do przetwarzania klatek wideo użyj synchronicznego interfejsu API
results(in:)
wzorca. Wywołaj tę metodę z funkcjicaptureOutput(_, didOutput:from:)
obiektuAVCaptureVideoDataOutputSampleBufferDelegate
, aby synchronicznie pobierać wyniki z danej klatki wideo. PozostawalwaysDiscardsLateVideoFrames
instancjiAVCaptureVideoDataOutput
jakotrue
, aby ograniczyć wywołania do wzorca. Jeśli podczas działania wykrywacza pojawi się nowa klatka wideo, zostanie usunięta. - Jeśli używasz danych wyjściowych detektora do nakładania grafiki na obraz wejściowy, najpierw pobierz wynik z ML Kit, a następnie wyrenderuj obraz i nakładkę w jednym kroku. Dzięki temu renderujesz na wyświetlaczu tylko raz dla każdej przetworzonej ramki wejściowej. Przykład znajdziesz w sekcji updatePreviewOverlayViewWithLastFrame w krótkim wprowadzeniu do ML Kit.