Po wytrenowaniu własnego modelu z użyciem AutoML Vision Edge możesz go używać w aplikacji do oznaczania obrazów etykietami.
Zanim zaczniesz
- Jeśli nie masz jeszcze dodanej usługi Firebase do swojej aplikacji, wykonaj czynności opisane we wprowadzeniu.
- Dodaj biblioteki ML Kit do pliku Podfile:
pod 'Firebase/MLVision', '6.25.0' pod 'Firebase/MLVisionAutoML', '6.25.0'
Po zainstalowaniu lub zaktualizowaniu podów projektu pamiętaj, aby otworzyć projekt Xcode za pomocą pliku.xcworkspace
. - W aplikacji zaimportuj Firebase:
Swift
import Firebase
Objective-C
@import Firebase;
1. Wczytaj model
ML Kit uruchamia modele wygenerowane przez AutoML na urządzeniu. Możesz jednak skonfigurować ML Kit, aby ładował model zdalnie z Firebase, z pamięci lokalnej lub z obu tych miejsc.
Hostując model w Firebase, możesz go aktualizować bez publikowania nowej wersji aplikacji. Dodatkowo możesz korzystać ze Zdalnej konfiguracji i Testów A/B do dynamicznego udostępniania różnych modeli różnym zbiorom użytkowników.
Jeśli zdecydujesz się udostępniać model tylko przez hosting w Firebase, a nie spakować go z aplikacją, możesz zmniejszyć początkowy rozmiar pobieranej aplikacji. Pamiętaj jednak, że jeśli model nie jest połączony z aplikacją, funkcje związane z modelem nie będą dostępne, dopóki aplikacja nie pobierze modelu po raz pierwszy.
Jeśli połączysz model z aplikacją, będziesz mieć pewność, że jej funkcje systemów uczących się będą nadal działać, gdy model hostowany w Firebase będzie niedostępny.
Skonfiguruj źródło modelu hostowanego w Firebase
Aby używać modelu hostowanego zdalnie, utwórz obiekt AutoMLRemoteModel
, podając nazwę przypisaną do niego podczas jego publikowania:
Swift
let remoteModel = AutoMLRemoteModel(
name: "your_remote_model" // The name you assigned in the Firebase console.
)
Objective-C
FIRAutoMLRemoteModel *remoteModel = [[FIRAutoMLRemoteModel 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 muszą zostać spełnione, aby można było pobierać dane. Jeśli modelu nie ma na urządzeniu lub jeśli jest dostępna jego nowsza wersja, zadanie pobierze go asynchronicznie z Firebase:
Swift
let downloadConditions = ModelDownloadConditions(
allowsCellularAccess: true,
allowsBackgroundDownloading: true
)
let downloadProgress = ModelManager.modelManager().download(
remoteModel,
conditions: downloadConditions
)
Objective-C
FIRModelDownloadConditions *downloadConditions =
[[FIRModelDownloadConditions alloc] initWithAllowsCellularAccess:YES
allowsBackgroundDownloading:YES];
NSProgress *downloadProgress =
[[FIRModelManager modelManager] downloadRemoteModel:remoteModel
conditions:downloadConditions];
Wiele aplikacji rozpoczyna zadanie pobierania w kodzie inicjowania, ale możesz to zrobić w dowolnym momencie, zanim trzeba będzie użyć modelu.
Skonfiguruj źródło modelu lokalnego
Aby połączyć model z aplikacją:
- Rozpakuj model i jego metadane z archiwum ZIP pobranego z konsoli Firebase do folderu:
your_model_directory |____dict.txt |____manifest.json |____model.tflite
Wszystkie 3 pliki muszą znajdować się w tym samym folderze. Zalecamy korzystanie z plików w takiej postaci, w jakiej zostały pobrane, bez modyfikacji (dotyczy to również nazw plików). - Skopiuj folder do projektu Xcode, zaznaczając opcję Utwórz odwołania do folderów. Plik modelu i metadane zostaną uwzględnione w pakiecie aplikacji i dostępne dla ML Kit.
- Utwórz obiekt
AutoMLLocalModel
, określając ścieżkę do pliku manifestu modelu:Swift
guard let manifestPath = Bundle.main.path( forResource: "manifest", ofType: "json", inDirectory: "your_model_directory" ) else { return true } let localModel = AutoMLLocalModel(manifestPath: manifestPath)
Objective-C
NSString *manifestPath = [NSBundle.mainBundle pathForResource:@"manifest" ofType:@"json" inDirectory:@"your_model_directory"]; FIRAutoMLLocalModel *localModel = [[FIRAutoMLLocalModel alloc] initWithManifestPath:manifestPath];
Tworzenie osoby oznaczającej obrazy na podstawie modelu
Po skonfigurowaniu źródeł modeli utwórz na ich podstawie obiekt VisionImageLabeler
.
Jeśli masz tylko model dołączony lokalnie, po prostu utwórz osobę oznaczającą etykietami na podstawie obiektu AutoMLLocalModel
i skonfiguruj próg wskaźnika ufności, którego chcesz wymagać (zobacz Ocena modelu):
Swift
let options = VisionOnDeviceAutoMLImageLabelerOptions(localModel: localModel)
options.confidenceThreshold = 0 // Evaluate your model in the Firebase console
// to determine an appropriate value.
let labeler = Vision.vision().onDeviceAutoMLImageLabeler(options: options)
Objective-C
FIRVisionOnDeviceAutoMLImageLabelerOptions *options =
[[FIRVisionOnDeviceAutoMLImageLabelerOptions alloc] initWithLocalModel:localModel];
options.confidenceThreshold = 0; // Evaluate your model in the Firebase console
// to determine an appropriate value.
FIRVisionImageLabeler *labeler =
[[FIRVision vision] onDeviceAutoMLImageLabelerWithOptions:options];
Jeśli masz model hostowany zdalnie, przed uruchomieniem musisz sprawdzić, czy został pobrany. Stan zadania pobierania modelu możesz sprawdzić za pomocą metody isModelDownloaded(remoteModel:)
menedżera modeli.
Chociaż musisz to potwierdzić przed uruchomieniem osoby oznaczającej etykietami, jeśli masz zarówno model hostowany zdalnie, jak i model umieszczony lokalnie, warto przeprowadzić tę kontrolę podczas tworzenia instancji VisionImageLabeler
: utwórz osobę oznaczającą etykietami na podstawie modelu zdalnego (jeśli został pobrany), a w przeciwnym razie z modelu lokalnego.
Swift
var options: VisionOnDeviceAutoMLImageLabelerOptions?
if (ModelManager.modelManager().isModelDownloaded(remoteModel)) {
options = VisionOnDeviceAutoMLImageLabelerOptions(remoteModel: remoteModel)
} else {
options = VisionOnDeviceAutoMLImageLabelerOptions(localModel: localModel)
}
options.confidenceThreshold = 0 // Evaluate your model in the Firebase console
// to determine an appropriate value.
let labeler = Vision.vision().onDeviceAutoMLImageLabeler(options: options)
Objective-C
VisionOnDeviceAutoMLImageLabelerOptions *options;
if ([[FIRModelManager modelManager] isModelDownloaded:remoteModel]) {
options = [[FIRVisionOnDeviceAutoMLImageLabelerOptions alloc] initWithRemoteModel:remoteModel];
} else {
options = [[FIRVisionOnDeviceAutoMLImageLabelerOptions alloc] initWithLocalModel:localModel];
}
options.confidenceThreshold = 0.0f; // Evaluate your model in the Firebase console
// to determine an appropriate value.
FIRVisionImageLabeler *labeler = [[FIRVision vision] onDeviceAutoMLImageLabelerWithOptions:options];
Jeśli masz tylko model hostowany zdalnie, wyłącz związane z nim funkcje – na przykład wyszarzanie lub ukrycie części interfejsu użytkownika – do czasu potwierdzenia pobrania modelu.
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ć uwolniony do zakończenia pobierania. Przykład:
Swift
NotificationCenter.default.addObserver( forName: .firebaseMLModelDownloadDidSucceed, 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: .firebaseMLModelDownloadDidFail, 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:FIRModelDownloadDidSucceedNotification object:nil queue:nil usingBlock:^(NSNotification *_Nonnull note) { if (weakSelf == nil | note.userInfo == nil) { return; } __strong typeof(self) strongSelf = weakSelf; FIRRemoteModel *model = note.userInfo[FIRModelDownloadUserInfoKeyRemoteModel]; if ([model.name isEqualToString:@"your_remote_model"]) { // The model was downloaded and is available on the device } }]; [NSNotificationCenter.defaultCenter addObserverForName:FIRModelDownloadDidFailNotification object:nil queue:nil usingBlock:^(NSNotification *_Nonnull note) { if (weakSelf == nil | note.userInfo == nil) { return; } __strong typeof(self) strongSelf = weakSelf; NSError *error = note.userInfo[FIRModelDownloadUserInfoKeyError]; }];
2. Przygotowywanie obrazu wejściowego
Następnie dla każdego obrazu, który chcesz oznaczyć etykietą, utwórz obiekt VisionImage
, korzystając z jednej z opcji opisanych w tej sekcji, i przekaż go do instancji VisionImageLabeler
(opisanej w następnej sekcji).
Utwórz obiekt VisionImage
za pomocą UIImage
lub CMSampleBufferRef
.
Aby użyć karty UIImage
:
- W razie potrzeby obróć obraz, by jego właściwość
imageOrientation
miała wartość.up
. - Utwórz obiekt
VisionImage
przy użyciu prawidłowo wykonanej rotacji wUIImage
. Nie określaj żadnych metadanych rotacji – należy użyć wartości domyślnej.topLeft
.Swift
let image = VisionImage(image: uiImage)
Objective-C
FIRVisionImage *image = [[FIRVisionImage alloc] initWithImage:uiImage];
Aby użyć karty CMSampleBufferRef
:
-
Utwórz obiekt
VisionImageMetadata
, który określa orientację danych obrazu zawartych w buforzeCMSampleBufferRef
.Aby sprawdzić orientację obrazu:
Swift
func imageOrientation( deviceOrientation: UIDeviceOrientation, cameraPosition: AVCaptureDevice.Position ) -> VisionDetectorImageOrientation { switch deviceOrientation { case .portrait: return cameraPosition == .front ? .leftTop : .rightTop case .landscapeLeft: return cameraPosition == .front ? .bottomLeft : .topLeft case .portraitUpsideDown: return cameraPosition == .front ? .rightBottom : .leftBottom case .landscapeRight: return cameraPosition == .front ? .topRight : .bottomRight case .faceDown, .faceUp, .unknown: return .leftTop } }
Objective-C
- (FIRVisionDetectorImageOrientation) imageOrientationFromDeviceOrientation:(UIDeviceOrientation)deviceOrientation cameraPosition:(AVCaptureDevicePosition)cameraPosition { switch (deviceOrientation) { case UIDeviceOrientationPortrait: if (cameraPosition == AVCaptureDevicePositionFront) { return FIRVisionDetectorImageOrientationLeftTop; } else { return FIRVisionDetectorImageOrientationRightTop; } case UIDeviceOrientationLandscapeLeft: if (cameraPosition == AVCaptureDevicePositionFront) { return FIRVisionDetectorImageOrientationBottomLeft; } else { return FIRVisionDetectorImageOrientationTopLeft; } case UIDeviceOrientationPortraitUpsideDown: if (cameraPosition == AVCaptureDevicePositionFront) { return FIRVisionDetectorImageOrientationRightBottom; } else { return FIRVisionDetectorImageOrientationLeftBottom; } case UIDeviceOrientationLandscapeRight: if (cameraPosition == AVCaptureDevicePositionFront) { return FIRVisionDetectorImageOrientationTopRight; } else { return FIRVisionDetectorImageOrientationBottomRight; } default: return FIRVisionDetectorImageOrientationTopLeft; } }
Następnie utwórz obiekt metadanych:
Swift
let cameraPosition = AVCaptureDevice.Position.back // Set to the capture device you used. let metadata = VisionImageMetadata() metadata.orientation = imageOrientation( deviceOrientation: UIDevice.current.orientation, cameraPosition: cameraPosition )
Objective-C
FIRVisionImageMetadata *metadata = [[FIRVisionImageMetadata alloc] init]; AVCaptureDevicePosition cameraPosition = AVCaptureDevicePositionBack; // Set to the capture device you used. metadata.orientation = [self imageOrientationFromDeviceOrientation:UIDevice.currentDevice.orientation cameraPosition:cameraPosition];
- Utwórz obiekt
VisionImage
, używając obiektuCMSampleBufferRef
i metadanych rotacji:Swift
let image = VisionImage(buffer: sampleBuffer) image.metadata = metadata
Objective-C
FIRVisionImage *image = [[FIRVisionImage alloc] initWithBuffer:sampleBuffer]; image.metadata = metadata;
3. Uruchamianie oznaczania obrazów
Aby oznaczyć etykietami obiekty na obrazie, przekaż obiekt VisionImage
do metody process()
interfejsu VisionImageLabeler
:
Swift
labeler.process(image) { labels, error in
guard error == nil, let labels = labels else { return }
// Task succeeded.
// ...
}
Objective-C
[labeler
processImage:image
completion:^(NSArray<FIRVisionImageLabel *> *_Nullable labels, NSError *_Nullable error) {
if (error != nil || labels == nil) {
return;
}
// Task succeeded.
// ...
}];
Jeśli oznaczenie obrazów zostanie oznaczone etykietami, do modułu obsługi uzupełniania zostanie przekazana tablica obiektów VisionImageLabel
. Możesz uzyskać o nim informacje
o obiekcie rozpoznanym na obrazie.
Przykład:
Swift
for label in labels {
let labelText = label.text
let confidence = label.confidence
}
Objective-C
for (FIRVisionImageLabel *label in labels) {
NSString *labelText = label.text;
NSNumber *confidence = label.confidence;
}
Wskazówki dotyczące poprawy skuteczności w czasie rzeczywistym
- Ogranicz wywołania do detektora. Jeśli podczas działania detektora dostępna będzie nowa klatka wideo, upuść ją.
- Jeśli używasz danych wyjściowych detektora do nakładania grafiki na obraz wejściowy, najpierw pobierz wynik z ML Kit, a potem wyrenderuj obraz i nakładkę w jednym kroku. Dzięki temu renderowanie na powierzchni wyświetlania będzie odbywać się tylko raz na każdą klatkę wejściową. Przykład znajdziesz w klasach previewOverlayView i FIRDetectionOverlayView w przykładowej aplikacji z funkcją prezentacji.