Catch up on everything announced at Firebase Summit, and learn how Firebase can help you accelerate app development and run your app with confidence. Learn More

Etykietuj obrazy za pomocą modelu przeszkolonego w AutoML na platformach Apple

Zadbaj o dobrą organizację dzięki kolekcji Zapisuj i kategoryzuj treści zgodnie ze swoimi preferencjami.

Po wytrenowaniu własnego modelu przy użyciu AutoML Vision Edge możesz użyć go w swojej aplikacji do oznaczania obrazów.

Istnieją dwa sposoby integracji modeli wytrenowanych z AutoML Vision Edge. Model można połączyć w pakiet, kopiując pliki modelu do projektu Xcode lub dynamicznie pobrać go z Firebase.

Opcje łączenia modeli
Dołączone do Twojej aplikacji
  • Model jest częścią pakietu
  • Model jest dostępny od zaraz, nawet gdy urządzenie Apple jest w trybie offline
  • Nie potrzebujesz projektu Firebase
Hostowane w Firebase
  • Hostuj model, przesyłając go do systemów uczących się Firebase
  • Zmniejsza rozmiar pakietu aplikacji
  • Model pobierany na żądanie
  • Wysyłaj aktualizacje modeli bez ponownego publikowania aplikacji
  • Łatwe testowanie A/B dzięki zdalnej konfiguracji Firebase
  • Wymaga projektu Firebase

Zanim zaczniesz

  1. Dołącz biblioteki ML Kit do swojego pliku Podfile:

    Aby połączyć model z aplikacją:

    pod 'GoogleMLKit/ImageLabelingCustom'
    

    Aby dynamicznie pobierać model z Firebase, dodaj zależność LinkFirebase :

    pod 'GoogleMLKit/ImageLabelingCustom'
    pod 'GoogleMLKit/LinkFirebase'
    
  2. Po zainstalowaniu lub zaktualizowaniu podów projektu otwórz projekt Xcode przy użyciu jego .xcworkspace . ML Kit jest obsługiwany w Xcode w wersji 12.2 lub nowszej.

  3. Jeśli chcesz pobrać model , upewnij się, że dodałeś Firebase do swojego projektu na Androida , jeśli jeszcze tego nie zrobiłeś. Nie jest to wymagane w przypadku łączenia modelu w pakiet.

1. Załaduj model

Skonfiguruj lokalne źródło modelu

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.tflite
    

    Wszystkie trzy pliki muszą znajdować się w tym samym folderze. Zalecamy używanie pobranych plików bez modyfikacji (łącznie z nazwami plików).

  2. Skopiuj folder do projektu Xcode, uważając, aby wybrać opcję Utwórz odwołania do folderu , gdy to zrobisz. Plik modelu i metadane zostaną zawarte w pakiecie aplikacji i będą dostępne dla ML Kit.

  3. Utwórz obiekt LocalModel , określając ścieżkę do pliku manifestu modelu:

    Szybki

    guard let manifestPath = Bundle.main.path(
        forResource: "manifest",
        ofType: "json",
        inDirectory: "your_model_directory"
    ) else { return true }
    let localModel = LocalModel(manifestPath: manifestPath)
    

    Cel C

    NSString *manifestPath =
        [NSBundle.mainBundle pathForResource:@"manifest"
                                      ofType:@"json"
                                 inDirectory:@"your_model_directory"];
    MLKLocalModel *localModel =
        [[MLKLocalModel alloc] initWithManifestPath:manifestPath];
    

Skonfiguruj źródło modelu hostowane w Firebase

Aby użyć modelu hostowanego zdalnie, utwórz obiekt CustomRemoteModel , określając nazwę, którą przypisałeś modelowi podczas jego publikowania:

Szybki

// Initialize the model source with the name you assigned in
// the Firebase console.
let remoteModelSource = FirebaseModelSource(name: "your_remote_model")
let remoteModel = CustomRemoteModel(remoteModelSource: remoteModelSource)

Cel C

// Initialize the model source with the name you assigned in
// the Firebase console.
MLKFirebaseModelSource *firebaseModelSource =
    [[MLKFirebaseModelSource alloc] initWithName:@"your_remote_model"];
MLKCustomRemoteModel *remoteModel =
    [[MLKCustomRemoteModel alloc] initWithRemoteModelSource:firebaseModelSource];

Następnie uruchom zadanie pobierania modelu, określając warunki, na jakich chcesz zezwolić na pobieranie. Jeśli modelu nie ma na urządzeniu lub jeśli dostępna jest nowsza wersja modelu, zadanie asynchronicznie pobierze model z Firebase:

Szybki

let downloadConditions = ModelDownloadConditions(
  allowsCellularAccess: true,
  allowsBackgroundDownloading: true
)

let downloadProgress = ModelManager.modelManager().download(
  remoteModel,
  conditions: downloadConditions
)

Cel C

MLKModelDownloadConditions *downloadConditions =
    [[MLKModelDownloadConditions alloc] initWithAllowsCellularAccess:YES
                                         allowsBackgroundDownloading:YES];

NSProgress *downloadProgress =
    [[MLKModelManager modelManager] downloadRemoteModel:remoteModel
                                             conditions:downloadConditions];

Wiele aplikacji rozpoczyna zadanie pobierania w swoim kodzie inicjującym, ale możesz to zrobić w dowolnym momencie, zanim będziesz musiał użyć modelu.

Stwórz etykietę obrazu ze swojego modelu

Po skonfigurowaniu źródeł modelu utwórz obiekt ImageLabeler z jednego z nich.

Jeśli masz tylko model powiązany lokalnie, po prostu utwórz etykietę z obiektu LocalModel i skonfiguruj wymagany próg wyniku ufności (zobacz Oceń model ):

Szybki

let options = CustomImageLabelerOptions(localModel: localModel)
options.confidenceThreshold = NSNumber(value: 0.0)  // Evaluate your model in the Cloud console
                                                    // to determine an appropriate value.
let imageLabeler = ImageLabeler.imageLabeler(options)

Cel C

CustomImageLabelerOptions *options =
    [[CustomImageLabelerOptions alloc] initWithLocalModel:localModel];
options.confidenceThreshold = @(0.0f);  // Evaluate your model in the Cloud console
                                        // to determine an appropriate value.
MLKImageLabeler *imageLabeler =
    [MLKImageLabeler imageLabelerWithOptions:options];

Jeśli masz model hostowany zdalnie, przed uruchomieniem musisz sprawdzić, czy został pobrany. Możesz sprawdzić status zadania pobierania modelu za pomocą metody isModelDownloaded(remoteModel:) menedżera modeli.

Chociaż musisz to tylko potwierdzić przed uruchomieniem programu do etykietowania, jeśli masz zarówno model hostowany zdalnie, jak i model wiązany lokalnie, sensowne może być wykonanie tego sprawdzenia podczas tworzenia wystąpienia ImageLabeler : utwórz etykietę z modelu zdalnego, jeśli jest zostały pobrane, a z modelu lokalnego w inny sposób.

Szybki

var options: CustomImageLabelerOptions
if (ModelManager.modelManager().isModelDownloaded(remoteModel)) {
  options = CustomImageLabelerOptions(remoteModel: remoteModel)
} else {
  options = CustomImageLabelerOptions(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)

Cel C

MLKCustomImageLabelerOptions *options;
if ([[MLKModelManager modelManager] isModelDownloaded:remoteModel]) {
  options = [[MLKCustomImageLabelerOptions alloc] initWithRemoteModel:remoteModel];
} else {
  options = [[MLKCustomImageLabelerOptions alloc] initWithLocalModel:localModel];
}
options.confidenceThreshold = @(0.0f);  // 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 — na przykład wyszarzanie lub ukrycie części interfejsu użytkownika — do momentu potwierdzenia, że ​​model został pobrany.

Stan pobierania modelu można uzyskać, dołączając obserwatorów do domyślnego centrum powiadomień. Upewnij się, że używasz słabego odniesienia do self w bloku obserwatora, ponieważ pobieranie może zająć trochę czasu, a obiekt źródłowy może zostać uwolniony przed zakończeniem pobierania. Na przykład:

Szybki

NotificationCenter.default.addObserver(
    forName: .mlkitMLModelDownloadDidSucceed,
    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: .mlkitMLModelDownloadDidFail,
    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]
    // ...
}

Cel 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 przy użyciu UIImage lub CMSampleBufferRef .

Jeśli używasz UIImage , wykonaj następujące kroki:

  • Utwórz obiekt VisionImage z UIImage . Upewnij się, że podałeś poprawny .orientation .

    Szybki

    let image = VisionImage(image: uiImage)
    visionImage.orientation = image.imageOrientation

    Cel C

    MLKVisionImage *visionImage = [[MLKVisionImage alloc] initWithImage:image];
    visionImage.orientation = image.imageOrientation;

Jeśli używasz CMSampleBufferRef , wykonaj następujące kroki:

  • Określ orientację danych obrazu zawartych w buforze CMSampleBufferRef .

    Aby uzyskać orientację obrazu:

    Szybki

    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
      }
    }
          

    Cel C

    - (UIImageOrientation)
      imageOrientationFromDeviceOrientation:(UIDeviceOrientation)deviceOrientation
                             cameraPosition:(AVCaptureDevicePosition)cameraPosition {
      switch (deviceOrientation) {
        case UIDeviceOrientationPortrait:
          return position == AVCaptureDevicePositionFront ? UIImageOrientationLeftMirrored
                                                          : UIImageOrientationRight;
    
        case UIDeviceOrientationLandscapeLeft:
          return position == AVCaptureDevicePositionFront ? UIImageOrientationDownMirrored
                                                          : UIImageOrientationUp;
        case UIDeviceOrientationPortraitUpsideDown:
          return position == AVCaptureDevicePositionFront ? UIImageOrientationRightMirrored
                                                          : UIImageOrientationLeft;
        case UIDeviceOrientationLandscapeRight:
          return position == AVCaptureDevicePositionFront ? UIImageOrientationUpMirrored
                                                          : UIImageOrientationDown;
        case UIDeviceOrientationUnknown:
        case UIDeviceOrientationFaceUp:
        case UIDeviceOrientationFaceDown:
          return UIImageOrientationUp;
      }
    }
          
  • Utwórz obiekt VisionImage przy użyciu obiektu i orientacji CMSampleBufferRef :

    Szybki

    let image = VisionImage(buffer: sampleBuffer)
    image.orientation = imageOrientation(
      deviceOrientation: UIDevice.current.orientation,
      cameraPosition: cameraPosition)

    Cel C

     MLKVisionImage *image = [[MLKVisionImage alloc] initWithBuffer:sampleBuffer];
     image.orientation =
       [self imageOrientationFromDeviceOrientation:UIDevice.currentDevice.orientation
                                    cameraPosition:cameraPosition];

3. Uruchom etykietę obrazu

Asynchronicznie:

Szybki

imageLabeler.process(image) { labels, error in
    guard error == nil, let labels = labels, !labels.isEmpty else {
        // Handle the error.
        return
    }
    // Show results.
}

Cel C

[imageLabeler
    processImage:image
      completion:^(NSArray<MLKImageLabel *> *_Nullable labels,
                   NSError *_Nullable error) {
        if (label.count == 0) {
            // Handle the error.
            return;
        }
        // Show results.
     }];

Synchronicznie:

Szybki

var labels: [ImageLabel]
do {
    labels = try imageLabeler.results(in: image)
} catch let error {
    // Handle the error.
    return
}
// Show results.

Cel C

NSError *error;
NSArray<MLKImageLabel *> *labels =
    [imageLabeler resultsInImage:image error:&error];
// Show results or handle the error.

4. Uzyskaj informacje o oznaczonych obiektach

Jeśli operacja oznaczania obrazu zakończy się pomyślnie, zwraca tablicę ImageLabel . Każda 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), ocenę ufności i indeks. Na przykład:

Szybki

for label in labels {
  let labelText = label.text
  let confidence = label.confidence
  let index = label.index
}

Cel C

for (MLKImageLabel *label in labels) {
  NSString *labelText = label.text;
  float confidence = label.confidence;
  NSInteger index = label.index;
}

Wskazówki dotyczące poprawy wydajności w czasie rzeczywistym

Jeśli chcesz opisywać obrazy w aplikacji działającej w czasie rzeczywistym, postępuj zgodnie z poniższymi wskazówkami, aby uzyskać najlepszą liczbę klatek na sekundę:

  • Przepustnica wzywa do detektora. Jeśli nowa ramka wideo stanie się dostępna podczas działania detektora, upuść ramkę.
  • Jeśli używasz wyjścia detektora do nakładania grafiki na obraz wejściowy, najpierw uzyskaj wynik, a następnie wyrenderuj obraz i nakładkę w jednym kroku. W ten sposób renderujesz na powierzchnię wyświetlania tylko raz dla każdej klatki wejściowej. Zobacz na przykład klasy previewOverlayView i FIRDetectionOverlayView w przykładowej aplikacji prezentacji.