Etykietowanie obrazów za pomocą wytrenowanego za pomocą AutoML modelu na iOS
Po wytrenowaniu własnego modelu za pomocą AutoML Vision Edge możesz go używać w aplikacji do etykietowania obrazów.
Modele wytrenowane za pomocą AutoML Vision Edge można integrować na 2 sposoby. Możesz zgrupować model, kopiując jego pliki do projektu Xcode, lub pobrać go dynamicznie z Firebase.
Opcje grupowania modeli | |
---|---|
W pakiecie w aplikacji |
|
Hostowany w Firebase |
|
Wypróbuj
- Aby zobaczyć przykład użycia tego interfejsu API, wypróbuj przykładową aplikację.
Zanim zaczniesz
1. Uwzględnij biblioteki ML Kit w pliku Podfile:Aby z aplikacją połączyć model:
pod 'GoogleMLKit/ImageLabelingAutoML'
LinkFirebase
:
pod 'GoogleMLKit/ImageLabelingAutoML' pod 'GoogleMLKit/LinkFirebase'
.xcworkspace
kodu>. ML Kit jest obsługiwany w Xcode w wersji 13.2.1 lub nowszej.
3. Jeśli chcesz pobrać model, dodaj Firebase do projektu na iOS, jeśli jeszcze tego nie zrobiono. Nie jest to wymagane, gdy model jest w pakiecie.
1. Wczytaj model
Konfigurowanie źródła lokalnego modelu
Aby połączyć model z aplikacją:1. Wyodrębnij model i jego metadane z pobranego z konsoli Firebase archiwum ZIP do folderu:
your_model_directory |____dict.txt |____manifest.json |____model.tflite
2. Skopiuj folder do projektu Xcode, pamiętając o zaznaczeniu opcji Utwórz odwołania do folderu. Plik modelu i metadane zostaną uwzględnione w pakiecie aplikacji i będą dostępne dla ML Kit.
3. Utwórz obiekt
AutoMLImageLabelerLocalModel
, podając ścieżkę do pliku manifestu modelu:
guard let manifestPath = Bundle.main.path( forResource: "manifest", ofType: "json", inDirectory: "your_model_directory" ) else { return } let localModel = AutoMLImageLabelerLocalModel(manifestPath: manifestPath)
NSString *manifestPath = [NSBundle.mainBundle pathForResource:@"manifest" ofType:@"json" inDirectory:@"your_model_directory"]; MLKAutoMLImageLabelerLocalModel *localModel = [[MLKAutoMLImageLabelerLocalModel alloc] initWithManifestPath:manifestPath];
Konfigurowanie źródła modelu hostowanego w Firebase
Aby użyć modelu hostowanego zdalnie, utwórz obiekt AutoMLImageLabelerRemoteModel
, podając nazwę przypisaną do modelu podczas jego publikowania:
let remoteModel = AutoMLImageLabelerRemoteModel( name: "your_remote_model" // The name you assigned in // the Firebase console. )
MLKAutoMLImageLabelerRemoteModel *remoteModel = [[MLKAutoMLImageLabelerRemoteModel alloc] initWithName:@"your_remote_model"]; // The name you assigned in // the Firebase console.
Następnie uruchom zadanie pobierania modelu, określając warunki, na jakich chcesz zezwolić na pobieranie. Jeśli model nie jest dostępny na urządzeniu lub jeśli dostępna jest nowsza wersja modelu, zadanie asynchronicznie pobierze model z Firebase:
let downloadConditions = ModelDownloadConditions( allowsCellularAccess: true, allowsBackgroundDownloading: true ) let downloadProgress = ModelManager.modelManager().download( remoteModel, conditions: downloadConditions )
MLKModelDownloadConditions *downloadConditions = [[MLKModelDownloadConditions alloc] initWithAllowsCellularAccess:YES allowsBackgroundDownloading:YES]; NSProgress *downloadProgress = [[MLKModelManager modelManager] downloadModel:remoteModel conditions:downloadConditions];
Wiele aplikacji inicjuje zadanie pobierania w kodzie inicjującym, ale możesz to zrobić w dowolnym momencie, zanim zaczniesz używać modelu.
Tworzenie etykiet obrazów na podstawie modelu
Po skonfigurowaniu źródeł modelu utwórz obiekt ImageLabeler
na podstawie jednego z nich.
Jeśli masz tylko model w pakiecie lokalnym, utwórz etykietownik na podstawie obiektu AutoMLImageLabelerLocalModel
i skonfiguruj próg poziomu ufności, którego wymagasz (patrz Ocena modelu:
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)
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 model jest hostowany zdalnie, przed jego uruchomieniem musisz sprawdzić, czy został pobrany. Stan zadania pobierania modelu możesz sprawdzić, korzystając z metody isModelDownloaded
(remoteModel:) menedżera modeli.
Musisz to potwierdzić tylko przed uruchomieniem etykietowania, ale jeśli masz model hostowany zdalnie i model w pakiecie lokalnym, warto wykonać tę weryfikację podczas tworzenia instancji ImageLabeler
: utwórz etykietowanie z modelu zdalnego, jeśli został pobrany, a w przeciwnym razie z modelu lokalnego.
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)
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 modelem (np. wygaszaj lub ukryj część interfejsu użytkownika), dopóki nie potwierdzisz, że model został pobrany.
Stan pobierania modelu możesz uzyskać, dołączając obserwatorów do domyślnego Centrum powiadomień. W bloku obserwatora używaj słabego odwołania do self
, ponieważ pobieranie może zająć trochę czasu, a do czasu jego zakończenia obiekt źródłowy może zostać zwolniony. Na przykład:
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] // ... }
__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. Przygotuj obraz wejściowy
Utwórz obiekt VisionImage
za pomocą obiektu UIImage
lub CMSampleBuffer
.
Jeśli używasz UIImage
, wykonaj te czynności:
- Utwórz obiekt
VisionImage
za pomocą funkcjiUIImage
. Pamiętaj, aby podać prawidłowy adres.orientation
.let image = VisionImage(image: UIImage) visionImage.orientation = image.imageOrientation
MLKVisionImage *visionImage = [[MLKVisionImage alloc] initWithImage:image]; visionImage.orientation = image.imageOrientation;
Jeśli używasz CMSampleBuffer
, wykonaj te czynności:
-
Określ orientację danych obrazu zawartych w elemencie
CMSampleBuffer
.Aby uzyskać orientację obrazu:
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 } }
- (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 jego orientacji:let image = VisionImage(buffer: sampleBuffer) image.orientation = imageOrientation( deviceOrientation: UIDevice.current.orientation, cameraPosition: cameraPosition)
MLKVisionImage *image = [[MLKVisionImage alloc] initWithBuffer:sampleBuffer]; image.orientation = [self imageOrientationFromDeviceOrientation:UIDevice.currentDevice.orientation cameraPosition:cameraPosition];
3. Uruchamianie narzędzia do etykietowania obrazów
Asynchronicznie:
imageLabeler.process(image) { labels, error in guard error == nil, let labels = labels, !labels.isEmpty else { // Handle the error. return } // Show results. }
[imageLabeler processImage:image completion:^(NSArray*_Nullable labels, NSError *_Nullable error) { if (labels.count == 0) { // Handle the error. return; } // Show results. }];
Synchronicznie:
var labels: [ImageLabel] do { labels = try imageLabeler.results(in: image) } catch let error { // Handle the error. return } // Show results.
NSError *error; NSArray*labels = [imageLabeler resultsInImage:image error:&error]; // Show results or handle the error.
4. Uzyskiwanie informacji o oznaczonych obiektach
Jeśli operacja etykietowania obrazu się powiedzie, zwróci tablicęImageLabel
. Każdy element ImageLabel
reprezentuje coś, co zostało opisane na obrazie. Możesz uzyskać tekstowy opis każdej etykiety (jeśli jest dostępny w metadanych pliku modelu TensorFlow Lite), wskaźnik ufności i indeks.
Na przykład:
for label in labels { let labelText = label.text let confidence = label.confidence let index = label.index }
for (MLKImageLabel *label in labels) { NSString *labelText = label.text; float confidence = label.confidence; NSInteger index = label.index; }
Wskazówki dotyczące zwiększania skuteczności w czasie rzeczywistym
Jeśli chcesz oznaczać obrazy w aplikacji w czasie rzeczywistym, postępuj zgodnie z tymi wskazówkami, aby uzyskać najlepszą liczbę klatek na sekundę:
- Do przetwarzania klatek wideo użyj synchronicznego interfejsu API
results(in:)
do wykrywania. Aby synchronicznie uzyskać wyniki z danego kadru wideo, wywołaj tę metodę zAVCaptureVideoDataOutputSampleBufferDelegate
captureOutput(_, didOutput:from:)
. Aby ograniczyć liczbę połączeń z detektorem, zachowajAVCaptureVideoDataOutput
alwaysDiscardsLateVideoFrames
jakotrue
. Jeśli podczas działania detektora pojawi się nowa klatka wideo, zostanie ona odrzucona. - Jeśli używasz danych wyjściowych z detektora do nakładania grafiki na obraz wejściowy, najpierw uzyskaj wynik z ML Kit, a potem wyrenderuj obraz i nałóż go w jednym kroku. Dzięki temu renderujesz na powierzchni wyświetlacza tylko raz dla każdego przetworzonego kadru wejściowego. Przykładowy kod updatePreviewOverlayViewWithLastFrame znajdziesz w pliku sample_mlkit_quick_start.cpp.