Etichetta le immagini con un modello con addestramento AutoML su iOS

Dopo aver addestrato il tuo modello utilizzando AutoML Vision Edge , puoi utilizzarlo nella tua app per etichettare le immagini.

Prima di iniziare

  1. Se non hai già aggiunto Firebase alla tua app, fallo seguendo i passaggi nella guida introduttiva .
  2. Includi le librerie ML Kit nel tuo Podfile:
    pod 'Firebase/MLVision', '6.25.0'
    pod 'Firebase/MLVisionAutoML', '6.25.0'
    
    Dopo aver installato o aggiornato i Pod del tuo progetto, assicurati di aprire il tuo progetto Xcode utilizzando il relativo .xcworkspace .
  3. Nella tua app, importa Firebase:

    Veloce

    import Firebase

    Obiettivo-C

    @import Firebase;

1. Caricare il modello

ML Kit esegue i modelli generati da AutoML sul dispositivo. Tuttavia, puoi configurare ML Kit per caricare il tuo modello in remoto da Firebase, dall'archivio locale o da entrambi.

Ospitando il modello su Firebase, puoi aggiornare il modello senza rilasciare una nuova versione dell'app e puoi utilizzare Remote Config e A/B Testing per servire dinamicamente modelli diversi a diversi gruppi di utenti.

Se scegli di fornire il modello solo ospitandolo con Firebase e non raggruppandolo con la tua app, puoi ridurre le dimensioni di download iniziali della tua app. Tieni presente, tuttavia, che se il modello non è incluso nella tua app, qualsiasi funzionalità relativa al modello non sarà disponibile finché l'app non scaricherà il modello per la prima volta.

Raggruppando il tuo modello con la tua app, puoi assicurarti che le funzionalità ML della tua app continuino a funzionare quando il modello ospitato da Firebase non è disponibile.

Configura un'origine del modello ospitato da Firebase

Per utilizzare il modello ospitato in remoto, crea un oggetto AutoMLRemoteModel , specificando il nome che hai assegnato al modello quando lo hai pubblicato:

Veloce

let remoteModel = AutoMLRemoteModel(
    name: "your_remote_model"  // The name you assigned in the Firebase console.
)

Obiettivo-C

FIRAutoMLRemoteModel *remoteModel = [[FIRAutoMLRemoteModel alloc]
    initWithName:@"your_remote_model"];  // The name you assigned in the Firebase console.

Avvia quindi l'attività di download del modello, specificando le condizioni alle quali desideri consentire il download. Se il modello non è presente sul dispositivo o se è disponibile una versione più recente del modello, l'attività scaricherà in modo asincrono il modello da Firebase:

Veloce

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

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

Obiettivo-C

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

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

Molte app avviano l'attività di download nel codice di inizializzazione, ma puoi farlo in qualsiasi momento prima di dover utilizzare il modello.

Configurare un'origine del modello locale

Per raggruppare il modello con la tua app:

  1. Estrai il modello e i relativi metadati dall'archivio zip scaricato dalla console Firebase in una cartella:
    your_model_directory
      |____dict.txt
      |____manifest.json
      |____model.tflite
    
    Tutti e tre i file devono trovarsi nella stessa cartella. Ti consigliamo di utilizzare i file così come li hai scaricati, senza modifiche (inclusi i nomi dei file).
  2. Copia la cartella nel tuo progetto Xcode, avendo cura di selezionare Crea riferimenti a cartelle quando lo fai. Il file del modello e i metadati verranno inclusi nel pacchetto dell'app e saranno disponibili per ML Kit.
  3. Crea un oggetto AutoMLLocalModel , specificando il percorso del file manifest del modello:

    Veloce

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

    Obiettivo-C

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

Crea un'etichettatrice di immagini dal tuo modello

Dopo aver configurato le origini del modello, crea un oggetto VisionImageLabeler da uno di essi.

Se disponi solo di un modello raggruppato localmente, crea semplicemente un'etichettatrice dal tuo oggetto AutoMLLocalModel e configura la soglia del punteggio di confidenza che desideri richiedere (vedi Valuta il tuo modello ):

Veloce

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)

Obiettivo-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];

Se disponi di un modello ospitato in remoto, dovrai verificare che sia stato scaricato prima di eseguirlo. È possibile verificare lo stato dell'attività di download del modello utilizzando il metodo isModelDownloaded(remoteModel:) del gestore modelli.

Anche se devi solo confermarlo prima di eseguire l'etichettatore, se disponi sia di un modello ospitato in remoto che di un modello raggruppato localmente, potrebbe avere senso eseguire questo controllo quando istanzia VisionImageLabeler : crea un'etichettatrice dal modello remoto se è stato scaricato e altrimenti dal modello locale.

Veloce

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)

Obiettivo-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];

Se disponi solo di un modello ospitato in remoto, dovresti disabilitare le funzionalità relative al modello, ad esempio disattivare o nascondere parte della tua interfaccia utente, finché non confermi che il modello è stato scaricato.

È possibile ottenere lo stato di download del modello collegando gli osservatori al Centro notifiche predefinito. Assicurati di utilizzare un riferimento debole a self nel blocco dell'osservatore, poiché i download possono richiedere del tempo e l'oggetto di origine può essere liberato al termine del download. Per esempio:

Veloce

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]
    // ...
}

Obiettivo-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. Preparare l'immagine di input

Quindi, per ogni immagine che desideri etichettare, crea un oggetto VisionImage utilizzando una delle opzioni descritte in questa sezione e passalo a un'istanza di VisionImageLabeler (descritta nella sezione successiva).

Crea un oggetto VisionImage utilizzando UIImage o CMSampleBufferRef .

Per utilizzare un'immagine UIImage :

  1. Se necessario, ruotare l'immagine in modo che la relativa proprietà imageOrientation sia .up .
  2. Crea un oggetto VisionImage utilizzando UIImage ruotato correttamente. Non specificare alcun metadato di rotazione: è necessario utilizzare il valore predefinito, .topLeft .

    Veloce

    let image = VisionImage(image: uiImage)

    Obiettivo-C

    FIRVisionImage *image = [[FIRVisionImage alloc] initWithImage:uiImage];

Per utilizzare un CMSampleBufferRef :

  1. Crea un oggetto VisionImageMetadata che specifica l'orientamento dei dati dell'immagine contenuti nel buffer CMSampleBufferRef .

    Per ottenere l'orientamento dell'immagine:

    Veloce

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

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

    Quindi, crea l'oggetto metadati:

    Veloce

    let cameraPosition = AVCaptureDevice.Position.back  // Set to the capture device you used.
    let metadata = VisionImageMetadata()
    metadata.orientation = imageOrientation(
        deviceOrientation: UIDevice.current.orientation,
        cameraPosition: cameraPosition
    )

    Obiettivo-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];
  2. Crea un oggetto VisionImage utilizzando l'oggetto CMSampleBufferRef e i metadati di rotazione:

    Veloce

    let image = VisionImage(buffer: sampleBuffer)
    image.metadata = metadata

    Obiettivo-C

    FIRVisionImage *image = [[FIRVisionImage alloc] initWithBuffer:sampleBuffer];
    image.metadata = metadata;

3. Eseguire l'etichettatrice delle immagini

Per etichettare gli oggetti in un'immagine, passa l'oggetto VisionImage al metodo process() di VisionImageLabeler :

Veloce

labeler.process(image) { labels, error in
    guard error == nil, let labels = labels else { return }

    // Task succeeded.
    // ...
}

Obiettivo-C

[labeler
    processImage:image
      completion:^(NSArray<FIRVisionImageLabel *> *_Nullable labels, NSError *_Nullable error) {
        if (error != nil || labels == nil) {
          return;
        }

        // Task succeeded.
        // ...
      }];

Se l'etichettatura dell'immagine ha esito positivo, una serie di oggetti VisionImageLabel verrà passata al gestore di completamento. Da ciascun oggetto è possibile ottenere informazioni su una caratteristica riconosciuta nell'immagine.

Per esempio:

Veloce

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

Obiettivo-C

for (FIRVisionImageLabel *label in labels) {
  NSString *labelText = label.text;
  NSNumber *confidence = label.confidence;
}

Suggerimenti per migliorare le prestazioni in tempo reale

  • Limita le chiamate al rilevatore. Se un nuovo fotogramma video diventa disponibile mentre il rilevatore è in funzione, rilasciare il fotogramma.
  • Se si utilizza l'output del rilevatore per sovrapporre la grafica all'immagine in input, ottenere prima il risultato da ML Kit, quindi eseguire il rendering dell'immagine e sovrapporre in un unico passaggio. In questo modo, viene eseguito il rendering sulla superficie di visualizzazione solo una volta per ciascun fotogramma di input. Per un esempio, vedi le classi PreviewOverlayView e FIRDetectionOverlayView nell'app di esempio vetrina.