Rileva, monitora e classifica gli oggetti con un modello di classificazione personalizzato su iOS

Puoi usare ML Kit per rilevare e tracciare oggetti in fotogrammi video successivi.

Quando passi un'immagine a ML Kit, quest'ultimo rileva fino a cinque oggetti al suo interno insieme alla posizione di ogni oggetto nell'immagine. Durante il rilevamento di oggetti in nei video stream, ogni oggetto ha un ID univoco che puoi utilizzare per monitorarlo da un frame all'altro.

Puoi utilizzare un modello di classificazione delle immagini personalizzato per classificare gli oggetti che sono rilevato. Fai riferimento alla sezione Modelli personalizzati con ML Kit per indicazioni sui requisiti di compatibilità dei modelli, dove trovare i modelli preaddestrati, e su come addestrare i tuoi modelli.

Esistono due modi per integrare un modello personalizzato. Puoi raggruppare il modello inserendolo nella cartella degli asset dell'app oppure scaricandolo in modo dinamico da Firebase. La tabella seguente mette a confronto le due opzioni.

Modello in bundle Modello ospitato
Il modello fa parte del file .ipa dell'app, che ne aumenta le dimensioni. Il modello non fa parte del file .ipa dell'app. È ospitato tramite caricamento Firebase Machine Learning
Il modello è disponibile immediatamente, anche quando il dispositivo Android è offline Il modello viene scaricato on demand
Non è necessario un progetto Firebase Richiede un progetto Firebase
Devi pubblicare nuovamente l'app per aggiornare il modello Esegui il push degli aggiornamenti del modello senza ripubblicare l'app
Nessun test A/B integrato Test A/B semplici con Firebase Remote Config

Prova

Prima di iniziare

  1. Includi le librerie del kit ML nel tuo podfile:

    Per raggruppare un modello con la tua app:

    pod 'GoogleMLKit/ObjectDetectionCustom', '15.5.0'
    

    Per scaricare dinamicamente un modello da Firebase, aggiungi LinkFirebase :

    pod 'GoogleMLKit/ObjectDetectionCustom', '15.5.0'
    pod 'GoogleMLKit/LinkFirebase', '15.5.0'
    
  2. Dopo aver installato o aggiornato i pod del progetto, apri il progetto Xcode utilizzando .xcworkspace. ML Kit è supportato in Xcode versione 13.2.1 o superiore.

  3. Se vuoi scaricare un modello, assicurati di aggiungi Firebase al tuo progetto iOS, se non l'hai già fatto. Questa operazione non è necessaria se includi un modello di machine learning.

1. Carica il modello

Configura un'origine del modello locale

Per raggruppare il modello con la tua app:

  1. Copia il file del modello (che di solito termina con .tflite o .lite) nel tuo Xcode progetto, assicurandoti di selezionare Copy bundle resources quando lo fai. La del modello sarà incluso nell'app bundle e sarà disponibile per ML Kit.

  2. Crea l'oggetto LocalModel, specificando il percorso del file del modello:

    Swift

    let localModel = LocalModel(path: localModelFilePath)

    Objective-C

    MLKLocalModel *localModel =
        [[MLKLocalModel alloc] initWithPath:localModelFilePath];
di Gemini Advanced.

Configura l'origine di un modello ospitata da Firebase

Per utilizzare il modello ospitato in remoto, crea un oggetto CustomRemoteModel, specificando il nome assegnato al modello al momento della pubblicazione:

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

Poi, avvia l'attività di download del modello, specificando le condizioni in cui vuoi consentire il download. Se il modello non è presente sul dispositivo o se una versione più recente del modello, l'attività scaricherà in modo asincrono modello di 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];

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

2. configura il rilevatore di oggetti

Dopo aver configurato le origini del modello, configura il rilevatore di oggetti per con un oggetto CustomObjectDetectorOptions. Puoi modificare le seguenti impostazioni:

Impostazioni del rilevatore di oggetti
Modalità di rilevamento STREAM_MODE (predefinito) | SINGLE_IMAGE_MODE

In STREAM_MODE (impostazione predefinita), il rilevatore di oggetti esegue con bassa latenza, ma potrebbe produrre risultati incompleti (come riquadri di delimitazione o etichette di categoria non specificati) sui primi delle chiamate al rilevatore. Inoltre, tra STREAM_MODE, il rilevatore assegna gli ID di monitoraggio agli oggetti, che puoi utilizzare per tenere traccia di oggetti tra i frame. Usa questa modalità per monitorare oggetti o quando è importante una bassa latenza, ad esempio durante l'elaborazione video stream in tempo reale.

In SINGLE_IMAGE_MODE, il rilevatore di oggetti restituisce il risultato dopo aver determinato il riquadro di delimitazione dell'oggetto. Se ad abilitare anche la classificazione, restituisce il risultato dopo il la casella e l'etichetta della categoria sono disponibili. Di conseguenza, di rilevamento è potenzialmente più elevata. Inoltre, nelle SINGLE_IMAGE_MODE, gli ID monitoraggio non sono assegnati. Utilizza le funzionalità di questa modalità se la latenza non è fondamentale e non vuoi gestire di risultati parziali.

Rilevamento e tracciamento di più oggetti false (predefinito) | true

Indica se rilevare e tracciare fino a cinque oggetti o solo il più ben visibile (impostazione predefinita).

Classificare gli oggetti false (predefinito) | true

Indica se classificare o meno gli oggetti rilevati utilizzando il metodo un modello di classificazione personalizzato. Per utilizzare la classificazione personalizzata devi impostarlo su true.

Soglia di confidenza della classificazione

Punteggio di confidenza minimo delle etichette rilevate. Se non viene configurato, qualsiasi valore verrà usata la soglia del classificatore specificata dai metadati del modello. Se il modello non contiene metadati o se i metadati non contengono specifica una soglia di classificazione, la soglia predefinita di 0,0 sarà in uso.

Numero massimo di etichette per oggetto

Numero massimo di etichette per oggetto che il rilevatore eseguirà per tornare indietro. Se non viene configurato, viene utilizzato il valore predefinito 10.

Se hai un modello in bundle locale, crea un rilevatore di oggetti il tuo oggetto LocalModel:

Swift

let options = CustomObjectDetectorOptions(localModel: localModel)
options.detectorMode = .singleImage
options.shouldEnableClassification = true
options.shouldEnableMultipleObjects = true
options.classificationConfidenceThreshold = NSNumber(value: 0.5)
options.maxPerObjectLabelCount = 3

Objective-C

MLKCustomObjectDetectorOptions *options =
    [[MLKCustomObjectDetectorOptions alloc] initWithLocalModel:localModel];
options.detectorMode = MLKObjectDetectorModeSingleImage;
options.shouldEnableClassification = YES;
options.shouldEnableMultipleObjects = YES;
options.classificationConfidenceThreshold = @(0.5);
options.maxPerObjectLabelCount = 3;

Se utilizzi un modello ospitato in remoto, dovrai verificare che sia stato scaricato prima di eseguirlo. Puoi controllare lo stato del download del modello utilizzando il metodo isModelDownloaded(remoteModel:) del gestore del modello.

Anche se devi solo confermarlo prima di eseguire il rilevatore di oggetti, se sia il modello ospitato in remoto sia il modello in bundle locale, potrebbero di eseguire questo controllo durante la creazione di un'istanza per ObjectDetector: rilevatore dal modello remoto, se è stato scaricato, e dal modello locale negli altri casi.

Swift

var options: CustomObjectDetectorOptions!
if (ModelManager.modelManager().isModelDownloaded(remoteModel)) {
  options = CustomObjectDetectorOptions(remoteModel: remoteModel)
} else {
  options = CustomObjectDetectorOptions(localModel: localModel)
}
options.detectorMode = .singleImage
options.shouldEnableClassification = true
options.shouldEnableMultipleObjects = true
options.classificationConfidenceThreshold = NSNumber(value: 0.5)
options.maxPerObjectLabelCount = 3

Objective-C

MLKCustomObjectDetectorOptions *options;
if ([[MLKModelManager modelManager] isModelDownloaded:remoteModel]) {
  options = [[MLKCustomObjectDetectorOptions alloc] initWithRemoteModel:remoteModel];
} else {
  options = [[MLKCustomObjectDetectorOptions alloc] initWithLocalModel:localModel];
}
options.detectorMode = MLKObjectDetectorModeSingleImage;
options.shouldEnableClassification = YES;
options.shouldEnableMultipleObjects = YES;
options.classificationConfidenceThreshold = @(0.5);
options.maxPerObjectLabelCount = 3;

Se disponi solo di un modello ospitato in remoto, devi disattivare le relative funzionalità, ad esempio rendere non selezionabile o nascondere parte dell'interfaccia utente, fino a quando confermi che il modello è stato scaricato.

Puoi ottenere lo stato di download del modello collegando gli osservatori all'impostazione predefinita Centro notifiche. Assicurati di utilizzare un riferimento debole a self nell'osservatore perché i download possono richiedere del tempo e l'oggetto di origine può essere verrà liberato al termine del download. Ad esempio:

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

L'API di rilevamento e monitoraggio degli oggetti è ottimizzata per questi due utilizzi principali casi:

  • Rilevamento e tracciamento in tempo reale dell'oggetto più in evidenza nella videocamera mirino.
  • Rilevamento di più oggetti da un'immagine statica.

Per configurare l'API per questi casi d'uso:

Swift

// Live detection and tracking
let options = CustomObjectDetectorOptions(localModel: localModel)
options.shouldEnableClassification = true
options.maxPerObjectLabelCount = 3

// Multiple object detection in static images
let options = CustomObjectDetectorOptions(localModel: localModel)
options.detectorMode = .singleImage
options.shouldEnableMultipleObjects = true
options.shouldEnableClassification = true
options.maxPerObjectLabelCount = 3

Objective-C

// Live detection and tracking
MLKCustomObjectDetectorOptions *options =
    [[MLKCustomObjectDetectorOptions alloc] initWithLocalModel:localModel];
options.shouldEnableClassification = YES;
options.maxPerObjectLabelCount = 3;

// Multiple object detection in static images
MLKCustomObjectDetectorOptions *options =
    [[MLKCustomObjectDetectorOptions alloc] initWithLocalModel:localModel];
options.detectorMode = MLKObjectDetectorModeSingleImage;
options.shouldEnableMultipleObjects = YES;
options.shouldEnableClassification = YES;
options.maxPerObjectLabelCount = 3;

3. Prepara l'immagine di input

Crea un oggetto VisionImage utilizzando un UIImage o un CMSampleBuffer.

Se usi un UIImage, segui questi passaggi:

  • Crea un oggetto VisionImage con UIImage. Assicurati di specificare il valore .orientation corretto.

    Swift

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

    Objective-C

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

Se usi un CMSampleBuffer, segui questi passaggi:

  • Specifica l'orientamento dei dati dell'immagine contenuti nei CMSampleBuffer.

    Per ottenere l'orientamento dell'immagine:

    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;
      }
    }
          
  • Crea un oggetto VisionImage utilizzando il metodo CMSampleBuffer oggetto e orientamento:

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

4. Crea ed esegui il rilevatore di oggetti

  1. Crea un nuovo rilevatore di oggetti:

    Swift

    let objectDetector = ObjectDetector.objectDetector(options: options)

    Objective-C

    MLKObjectDetector *objectDetector = [MLKObjectDetector objectDetectorWithOptions:options];
  2. Quindi, utilizza il rilevatore:

    In modo asincrono:

    Swift

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

    Objective-C

    [objectDetector
        processImage:image
          completion:^(NSArray *_Nullable objects,
                       NSError *_Nullable error) {
            if (objects.count == 0) {
                // Handle the error.
                return;
            }
            // Show results.
         }];

    In modo sincrono:

    Swift

    var objects: [Object]
    do {
        objects = try objectDetector.results(in: image)
    } catch let error {
        // Handle the error.
        return
    }
    // Show results.

    Objective-C

    NSError *error;
    NSArray *objects =
        [objectDetector resultsInImage:image error:&error];
    // Show results or handle the error.

5. Ottieni informazioni sugli oggetti etichettati

Se la chiamata al processore di immagini ha esito positivo, passa un elenco di Object al gestore del completamento o restituisce l'elenco, a seconda del a seconda che tu abbia chiamato il metodo asincrono o sincrono.

Ogni Object contiene le seguenti proprietà:

frame Un elemento CGRect che indica la posizione dell'oggetto nell'intervallo dell'immagine.
trackingID Un numero intero che identifica l'oggetto attraverso le immagini, o "nullo" in MODALITÀ_IMMAGINE_SINGLE.
labels
label.text La descrizione testuale dell'etichetta. Restituisce solo se TensorFlow I metadati del modello Lite contengono descrizioni delle etichette.
label.index L'indice dell'etichetta tra tutte le etichette supportate dal classificatore.
label.confidence Il valore di confidenza della classificazione dell'oggetto.

Swift

// objects contains one item if multiple object detection wasn't enabled.
for object in objects {
  let frame = object.frame
  let trackingID = object.trackingID
  let description = object.labels.enumerated().map { (index, label) in
    "Label \(index): \(label.text), \(label.confidence), \(label.index)"
  }.joined(separator: "\n")
}

Objective-C

// The list of detected objects contains one item if multiple object detection
// wasn't enabled.
for (MLKObject *object in objects) {
  CGRect frame = object.frame;
  NSNumber *trackingID = object.trackingID;
  for (MLKObjectLabel *label in object.labels) {
    NSString *labelString =
        [NSString stringWithFormat:@"%@, %f, %lu",
                                   label.text,
                                   label.confidence,
                                   (unsigned long)label.index];
  }
}

Garantire un'esperienza utente ottimale

Per una migliore esperienza utente, segui queste linee guida nella tua app:

  • Il successo del rilevamento degli oggetti dipende dalla complessità visiva dell'oggetto. Nella per essere rilevati, gli oggetti con un numero ridotto di caratteristiche visive potrebbero richiedere in modo da occupare una parte più grande dell'immagine. Devi fornire agli utenti indicazioni acquisire input che funzionano bene con il tipo di oggetti che si vuole rilevare.
  • Quando usi la classificazione, se vuoi rilevare gli oggetti che non cadono nelle categorie supportate, implementare una gestione speciale per di oggetti strutturati.

Consulta anche [App vetrina ML Kit Material Design][showcase-link]{: .external } e i Material design Raccolta di pattern per le funzionalità basate sul machine learning.

Ottimizzazione del rendimento

Se vuoi utilizzare il rilevamento degli oggetti in un'applicazione in tempo reale, segui questi linee guida per ottenere le migliori frequenze fotogrammi:

  • Quando utilizzi la modalità flusso di dati in un'applicazione in tempo reale, non utilizzare più di oggetti Kubernetes, poiché la maggior parte dei dispositivi non è in grado di produrre frequenze fotogrammi adeguate.

  • Per elaborare i fotogrammi video, utilizza l'API sincrona results(in:) del rilevatore. Chiama questo metodo dal di AVCaptureVideoDataOutputSampleBufferDelegate captureOutput(_, didOutput:from:) per ottenere in modo sincrono i risultati dal video specificato frame. Mantieni di AVCaptureVideoDataOutput alwaysDiscardsLateVideoFrames come true per limitare le chiamate al rilevatore. Se un nuovo il fotogramma video diventa disponibile mentre il rilevatore è in esecuzione, quindi verrà eliminato.
  • Se utilizzi l'output del rilevatore per sovrapporre elementi grafici l'immagine di input, occorre prima ottenere il risultato da ML Kit, quindi eseguire il rendering dell'immagine e la sovrapposizione in un solo passaggio. In questo modo, puoi visualizzare i contenuti solo una volta per ogni frame di input elaborato. Vedi la pagina updatePreviewOverlayViewWithLastFrame. nell'esempio della guida rapida di ML Kit.