Za pomocą ML Kit możesz rozpoznawać encje na obrazach i oznaczać je etykietami. Ten interfejs API obsługuje szeroką gamę niestandardowych modeli klasyfikacji obrazów. W artykule Modele niestandardowe z użyciem ML Kit dowiesz się, jakie są wymagania dotyczące zgodności modeli, gdzie znaleźć wytrenowane modele i jak trenować własne modele.
Model niestandardowy można zintegrować na 2 sposoby. Możesz połączyć model, umieszczając go w folderze zasobów aplikacji lub pobrać dynamicznie z Firebase. Tabela poniżej zawiera porównanie obu opcji.
Model w pakiecie | Model hostowany |
---|---|
Model jest częścią pliku APK aplikacji, co zwiększa swój rozmiar. | Ten model nie jest częścią Twojego pliku APK. Jest on hostowany przez przesłanie go do systemów uczących się Firebase. |
Model jest dostępny natychmiast, nawet jeśli urządzenie z Androidem jest offline. | Model jest pobierany na żądanie |
Nie potrzebujesz projektu Firebase | Wymaga projektu Firebase |
Aby zaktualizować model, musisz ponownie opublikować aplikację | Przesyłaj aktualizacje modelu bez ponownego publikowania aplikacji |
Brak wbudowanych testów A/B | łatwe testy A/B dzięki Zdalnej konfiguracji Firebase. |
Wypróbuj
- W krótkim wprowadzeniu do aplikacji Vision znajdziesz przykład użycia modelu w pakiecie, a w aplikacji z krótkim wprowadzeniem do Automl – przykład użycia hostowanego modelu.
Zanim zaczniesz
Dodaj biblioteki ML Kit do pliku Podfile:
Aby dodać model do pakietu z aplikacją:
pod 'GoogleMLKit/ImageLabelingCustom', '3.2.0'
Aby dynamicznie pobierać model z Firebase, dodaj zależność
LinkFirebase
:pod 'GoogleMLKit/ImageLabelingCustom', '3.2.0' pod 'GoogleMLKit/LinkFirebase', '3.2.0'
Po zainstalowaniu lub zaktualizowaniu podów w projekcie otwórz projekt Xcode, korzystając z
.xcworkspace
. ML Kit obsługuje Xcode w wersji 13.2.1 lub nowszej.Jeśli chcesz pobrać model, dodaj Firebase do swojego projektu iOS, jeśli jeszcze tego nie zrobiłeś. Nie jest to wymagane podczas pakowania modelu.
1. Wczytywanie modelu
Skonfiguruj źródło modelu lokalnego
Aby połączyć model z aplikacją:
Skopiuj do projektu Xcode plik modelu (zwykle kończący się na
.tflite
lub.lite
), wybierając przy tymCopy bundle resources
. Plik modelu zostanie dołączony do pakietu aplikacji i będzie dostępny dla ML Kit.Utwórz obiekt
LocalModel
, podając ścieżkę do pliku modelu:Swift
let localModel = LocalModel(path: localModelFilePath)
Objective-C
MLKLocalModel *localModel = [[MLKLocalModel alloc] initWithPath:localModelFilePath];
Skonfiguruj źródło modelu hostowane w Firebase
Aby użyć modelu hostowanego zdalnie, utwórz obiekt RemoteModel
z nazwą przypisaną do modelu w chwili jego opublikowania:
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];
Następnie rozpocznij zadanie pobierania modelu, określając warunki, które mają mieć możliwość pobierania. Jeśli modelu nie ma na urządzeniu lub dostępna jest jego nowsza wersja, zadanie pobierze asynchronicznie 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 zajdzie potrzeba używania modelu.
Konfigurowanie oznaczania obrazów etykietami
Po skonfigurowaniu źródeł modelu utwórz na podstawie jednego z nich obiekt ImageLabeler
.
Dostępne są te ustawienia:
Opcje | |
---|---|
confidenceThreshold
|
Minimalny wskaźnik ufności wykrytych etykiet. Jeśli nie skonfigurujesz tej zasady, zostanie użyty dowolny próg klasyfikatora określony przez metadane modelu. Jeśli model nie zawiera żadnych metadanych lub metadane nie określają progu klasyfikatora, zostanie użyty domyślny próg równy 0,0. |
maxResultCount
|
Maksymalna liczba etykiet do zwrócenia. Jeśli zasada nie jest skonfigurowana, używana jest wartość domyślna, czyli 10. |
Jeśli masz tylko model dołączony do pakietu lokalnie, po prostu utwórz etykietę na podstawie obiektu LocalModel
:
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];
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.
Musisz to potwierdzić przed uruchomieniem osoby oznaczającej etykietami, ale jeśli używasz zarówno modelu hostowanego zdalnie, jak i modelu dołączonego lokalnie, podczas tworzenia wystąpienia obiektu ImageLabeler
warto wykonać tę procedurę sprawdzania: utwórz etykietę z modelu zdalnego (jeśli został on pobrany, a w przeciwnym razie z modelu lokalnego).
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];
Jeśli masz tylko model hostowany zdalnie, wyłącz funkcje związane z modelem – 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 obserwacyjnym używać słabego odniesienia do self
, ponieważ pobieranie może trochę potrwać, a obiekt źródłowy może zostać uwolniony do momentu 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. Przygotuj obraz wejściowy
Utwórz obiekt VisionImage
za pomocą UIImage
lub CMSampleBuffer
.
Jeśli używasz urządzenia UIImage
, wykonaj te czynności:
- Utwórz obiekt
VisionImage
za pomocąUIImage
. Pamiętaj, aby podać prawidłową wartość.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 urządzenia CMSampleBuffer
, wykonaj te czynności:
-
Określ orientację danych obrazu w elemencie
CMSampleBuffer
.Aby pobrać orientację:
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 obiektu i orientacjiCMSampleBuffer
: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 etykietowania obrazów
Aby oznaczyć etykietami obiekty na obrazie, przekaż obiekt image
do metody process()
metody ImageLabeler
.
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 (label.count == 0) { // Handle the error. return; } // Show results. }];
Synchronicznie:
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 elementach oznaczonych etykietami
Jeśli operacja oznaczania obrazów zakończy się powodzeniem, 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 przesyłającej dane w czasie rzeczywistym, postępuj zgodnie z tymi wytycznymi, aby uzyskać najlepszą liczbę klatek na sekundę:
- 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
obiektuAVCaptureVideoDataOutput
jakotrue
, aby ograniczać wywołania do wzorca. Jeśli podczas działania wzorca pojawi się nowa ramka wideo, zostanie ona usunięta. - Jeśli używasz danych wyjściowych wzorca 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 na każdą przetworzoną klatkę wejściową renderujesz się tylko raz. Przykład znajdziesz w sekcji updatePreviewOverlayViewWithLastFrame w przykładowym krótkim wprowadzeniu do ML Kit.