Rileva e monitora gli oggetti con ML Kit su iOS

Puoi utilizzare ML Kit per rilevare e monitorare gli oggetti nei frame video successivi.

Quando passi un'immagine a ML Kit, rileva fino a cinque oggetti nell'immagine insieme alla posizione di ciascun oggetto nell'immagine. Quando vengono rilevati oggetti nei flussi video, ogni oggetto ha un ID univoco che puoi utilizzare per monitorare l'oggetto da un frame all'altro. Facoltativamente, puoi abilitare la classificazione approssimativa degli oggetti, che etichetta gli oggetti con descrizioni di categorie ampie.

Prova subito

Prima di iniziare

  1. Includi i seguenti pod di ML Kit nel tuo podfile:
    pod 'GoogleMLKit/ObjectDetection', '3.2.0'
    
  2. Dopo aver installato o aggiornato i pod del progetto, apri il progetto Xcode utilizzando .xcworkspace. ML Kit è supportato in Xcode versione 12.4 o successiva.

1. Configura il rilevatore di oggetti

Per rilevare e monitorare gli oggetti, crea prima un'istanza di ObjectDetector e, facoltativamente, specifica le impostazioni del rilevatore che vuoi modificare rispetto all'impostazione predefinita.

  1. Configura il rilevatore di oggetti per il tuo caso d'uso con un oggetto ObjectDetectorOptions. Puoi modificare le seguenti impostazioni:

    Impostazioni del rilevatore di oggetti
    Modalità di rilevamento .stream (valore predefinito) | .singleImage

    In modalità flusso (impostazione predefinita), il rilevatore di oggetti viene eseguito con una latenza molto bassa, ma potrebbe produrre risultati incompleti (ad esempio categorie o riquadri di delimitazione non specificati) sulle prime chiamate del rilevatore. Inoltre, in modalità flusso, il rilevatore assegna gli ID monitoraggio agli oggetti, che puoi utilizzare per monitorare gli oggetti nei frame. Usa questa modalità quando vuoi monitorare gli oggetti o quando è importante una bassa latenza, ad esempio durante l'elaborazione in tempo reale dei flussi video.

    In modalità immagine singola, il rilevatore di oggetti restituisce il risultato dopo aver stabilito il riquadro di delimitazione dell'oggetto. Se abiliti anche la classificazione, restituisce il risultato dopo che il riquadro di delimitazione e l'etichetta della categoria sono entrambi disponibili. Di conseguenza, la latenza di rilevamento è potenzialmente più elevata. Inoltre, in modalità immagine singola non vengono assegnati gli ID monitoraggio. Usa questa modalità se la latenza non è critica e non vuoi gestire risultati parziali.

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

    Indica se rilevare e monitorare fino a cinque oggetti o solo l'oggetto più in evidenza (impostazione predefinita).

    Classifica oggetti false (valore predefinito) | true

    Indica se classificare o meno gli oggetti rilevati in categorie approssimative. Se abilitato, il rilevatore di oggetti classifica gli oggetti nelle seguenti categorie: articoli di moda, cibo, prodotti per la casa, luoghi e piante.

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

    • Rilevamento in tempo reale e monitoraggio dell'oggetto più in evidenza nel mirino della fotocamera.
    • Il rilevamento di più oggetti in un'immagine statica.

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

Swift

// Live detection and tracking
let options = ObjectDetectorOptions()
options.shouldEnableClassification = true

// Multiple object detection in static images
let options = ObjectDetectorOptions()
options.detectorMode = .singleImage
options.shouldEnableMultipleObjects = true
options.shouldEnableClassification = true

Objective-C

// Live detection and tracking
MLKObjectDetectorOptions *options = [[MLKObjectDetectorOptions alloc] init];
options.shouldEnableClassification = YES;

// Multiple object detection in static images
MLKObjectDetectorOptions *options = [[MLKOptions alloc] init];
options.detectorMode = MLKObjectDetectorModeSingleImage;
options.shouldEnableMultipleObjects = YES;
options.shouldEnableClassification = YES;
  1. Ottieni un'istanza di ObjectDetector:

Swift

let objectDetector = ObjectDetector.objectDetector()

// Or, to change the default settings:
let objectDetector = ObjectDetector.objectDetector(options: options)

Objective-C

MLKObjectDetector *objectDetector = [MLKObjectDetector objectDetector];

// Or, to change the default settings:
MLKObjectDetector *objectDetector = [MLKObjectDetector objectDetectorWithOptions:options];

2. Prepara l'immagine di input

Per rilevare e monitorare gli oggetti, procedi nel seguente modo per ogni immagine o frame del video. Se hai abilitato la modalità flusso, devi creare oggetti VisionImage da CMSampleBuffer s.

Crea un oggetto VisionImage utilizzando un UIImage o un CMSampleBuffer.

Se utilizzi un UIImage, segui questi passaggi:

  • Crea un oggetto VisionImage con il UIImage. Assicurati di specificare il .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 utilizzi un CMSampleBuffer, segui questi passaggi:

  • Specifica l'orientamento dei dati dell'immagine contenuti in 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 l'oggetto e l'orientamento CMSampleBuffer:

    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. Elabora immagine

Passa VisionImage a uno dei metodi di elaborazione delle immagini del rilevatore di oggetti. Puoi usare il metodo asincrono process(image:) o results() sincrono.

Per rilevare gli oggetti in modo asincrono:

Swift

objectDetector.process(image) { objects, error in
  guard error == nil else {
    // Error.
    return
  }
  guard !objects.isEmpty else {
    // No objects detected.
    return
  }

  // Success. Get object info here.
  // ...
}

Objective-C

[objectDetector processImage:image
                  completion:^(NSArray * _Nullable objects,
                               NSError * _Nullable error) {
                    if (error == nil) {
                      return;
                    }
                    if (objects.count == 0) {
                      // No objects detected.
                      return;
                    }

                    // Success. Get object info here.
                  }];

Per rilevare gli oggetti in modo sincrono:

Swift

var objects: [Object]
do {
  objects = try objectDetector.results(in: image)
} catch let error {
  print("Failed to detect object with error: \(error.localizedDescription).")
  return
}
guard !objects.isEmpty else {
  print("Object detector returned no results.")
  return
}

// Success. Get object info here.

Objective-C

NSError *error;
NSArray *objects = [objectDetector resultsInImage:image error:&error];
if (error == nil) {
  return;
}
if (objects.count == 0) {
  // No objects detected.
  return;
}

// Success. Get object info here.

4. Ottieni informazioni sugli oggetti rilevati

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

Ogni Object contiene le seguenti proprietà:

frame CGRect che indica la posizione dell'oggetto nell'immagine.
trackingID Un numero intero che identifica l'oggetto tra le immagini o "nil" in modalità immagine singola.
labels Un array di etichette che descrivono l'oggetto restituito dal rilevatore. La proprietà è vuota se l'opzione del rilevatore shouldEnableClassification è impostata su false.

Swift

// objects contains one item if multiple object detection wasn't enabled.
for object in objects {
  let frame = object.frame
  let trackingID = object.trackingID

  // If classification was enabled:
  let description = object.labels.enumerated().map { (index, label) in
    "Label \(index): \(label.text), \(label.confidence)"
    }.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];
    ...
  }
}

Migliorare l'usabilità e le prestazioni

Per un'esperienza utente ottimale, segui queste linee guida nella tua app:

  • Il rilevamento riuscito degli oggetti dipende dalla complessità visiva dell'oggetto. Per poter essere rilevati, gli oggetti con un numero ridotto di funzionalità visive potrebbero occupare una parte più grande dell'immagine. Devi fornire agli utenti indicazioni sull'acquisizione degli input che funzionino bene con il tipo di oggetti che vuoi rilevare.
  • Se utilizzi la classificazione, se vuoi rilevare oggetti che non rientrano nelle categorie supportate, implementa la gestione speciale degli oggetti sconosciuti.

Dai anche un'occhiata alla raccolta di pattern di Material Design per il machine learning di Material Design.

Quando utilizzi la modalità streaming in un'applicazione in tempo reale, segui queste linee guida per ottenere la migliore frequenza fotogrammi:

  • Non utilizzare il rilevamento di più oggetti in modalità flusso, poiché la maggior parte dei dispositivi non sarà in grado di produrre frequenze di fotogrammi adeguate.
  • Disattiva la classificazione se non ti serve.
  • Per l'elaborazione dei frame video, utilizza l'API sincrona results(in:) del rilevatore. Richiama questo metodo dalla funzione captureOutput(_, didOutput:from:) di AVCaptureVideoDataOutputSampleBufferDelegate per ottenere in modo sincrono i risultati dal frame video specificato. Mantieni alwaysDiscardsLateVideoFrames di AVCaptureVideoDataOutput come true per limitare le chiamate al rilevatore. Se un nuovo video diventa disponibile mentre il rilevatore è in esecuzione, viene eliminato.
  • Se utilizzi l'output del rilevatore per sovrapporre la grafica all'immagine di input, prima ottieni il risultato da ML Kit, quindi visualizza l'immagine e l'overlay in un solo passaggio. In questo modo, visualizzerai nella piattaforma display solo una volta per ogni frame di input elaborato. Guarda un esempio di updateAnteprimaOverlayViewWithLastFrame nell'esempio della guida rapida di ML Kit.