Rileva e monitora gli oggetti con ML Kit 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. Facoltativamente, puoi abilitare l'oggetto approssimativo che etichetta gli oggetti con ampie descrizioni di categorie.

Prova

Prima di iniziare

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

1. configura il rilevatore di oggetti

Per rilevare e monitorare gli oggetti, devi prima creare un'istanza ObjectDetector e, facoltativamente, specificare le impostazioni del rilevatore che preferisci modificare quello predefinito.

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

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

    In modalità flusso (impostazione predefinita), il rilevatore di oggetti funziona con un ma potrebbe produrre risultati incompleti (ad esempio, riquadri di delimitazione o categorie) alle prime chiamate di il rilevatore. Inoltre, in modalità stream, il rilevatore assegna il monitoraggio ID agli oggetti, che puoi utilizzare per tenere traccia degli oggetti nei vari frame. Utilizza questa modalità quando vuoi monitorare gli oggetti o in caso di bassa latenza è importante, ad esempio durante l'elaborazione degli stream video nel tempo.

    In modalità immagine singola, il rilevatore di oggetti restituisce il risultato dopo aver determinato il riquadro di delimitazione dell'oggetto. Se attivi anche per la classificazione, restituisce il risultato dopo il riquadro di delimitazione sono entrambe disponibili. Di conseguenza, il rilevamento è potenzialmente più alta. Inoltre, in modalità immagine singola, ID non assegnati. Utilizza questa modalità se la latenza non è critica per evitare 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 in categorie approssimative. Se abilitato, il rilevatore di oggetti classifica gli oggetti nell'intervallo seguenti categorie: articoli di moda, cibo, casalinghi, luoghi e piante.

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

    • Rilevamento e tracciamento in tempo reale dell'oggetto più in evidenza nella videocamera mirino.
    • 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 tracciare oggetti, procedi nel seguente modo per ogni immagine o fotogramma del video. Se hai abilitato la modalità flusso di dati, devi creare VisionImage oggetti da CMSampleBuffer

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

3. Elabora l'immagine

Passa VisionImage a uno dei sistemi di elaborazione delle immagini del rilevatore di oggetti di machine learning. Puoi utilizzare il metodo process(image:) asincrono oppure metodo 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. Recuperare informazioni sugli oggetti rilevati

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 tra le immagini, o "nessuno" 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 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.

Dai un'occhiata anche al Material Design Raccolta di pattern per le funzionalità basate sul machine learning.

Quando utilizzi la modalità flusso di dati in un'applicazione in tempo reale, segui queste linee guida per ottenere le migliori frequenze fotogrammi:

  • Non utilizzare il rilevamento di più oggetti in modalità flusso di dati, perché la maggior parte dei dispositivi non essere in grado di produrre frequenze fotogrammi adeguate.
  • Disabilita la classificazione se non ti serve.
  • 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, visualizzi la pagina solo una volta per ogni frame di input elaborato. Vedi la pagina updatePreviewOverlayViewWithLastFrame. nell'esempio della guida rapida di ML Kit.