Rileva e monitora gli oggetti con ML Kit su iOS

Puoi utilizzare ML Kit per rilevare e monitorare gli oggetti nei fotogrammi di un video.

Quando passi le immagini di ML Kit, ML Kit restituisce, per ogni immagine, un elenco di fino a cinque oggetti rilevati e la loro posizione nell'immagine. Durante il rilevamento nei video stream, ogni oggetto ha un ID che puoi utilizzare per tracciare tra le immagini. Facoltativamente, puoi abilitare l'oggetto approssimativo che etichetta gli oggetti con ampie descrizioni di categorie.

Prima di iniziare

  1. Se non hai già aggiunto Firebase alla tua app, puoi farlo seguendo le istruzioni riportate in passaggi nella Guida introduttiva.
  2. Includi le librerie ML Kit nel tuo Podfile:
    pod 'Firebase/MLVision', '6.25.0'
    pod 'Firebase/MLVisionObjectDetection', '6.25.0'
    
    Dopo aver installato o aggiornato i pod del progetto, assicurati di aprire il progetto Xcode utilizzando il relativo .xcworkspace.
  3. Nell'app, importa Firebase:

    Swift

    import Firebase

    Objective-C

    @import Firebase;

1. configura il rilevatore di oggetti

Per iniziare a rilevare e monitorare gli oggetti, crea prima un'istanza di VisionObjectDetector, specificando facoltativamente le impostazioni del rilevatore da cambiare rispetto a quelle predefinite.

  1. Configura il rilevatore di oggetti per il tuo caso d'uso con un oggetto VisionObjectDetectorOptions. Puoi modificare le seguenti 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 categoria) 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 attende che venga rilevato riquadro di delimitazione dell'oggetto e (se hai abilitato la classificazione) disponibili prima di restituire un risultato. Di conseguenza, la latenza del rilevamento è potenzialmente più elevata. Inoltre, in un'immagine singola , gli ID monitoraggio non vengono assegnati. Utilizza questa modalità se la latenza non è fondamentale e non vuoi gestire risultati parziali.

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

    Indica se rilevare e monitorare fino a cinque oggetti o solo l'oggetto più prominente (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 nelle seguenti categorie: abbigliamento, cibo, articoli per la casa, luoghi, piante e sconosciuto.

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

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

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

    Swift

    // Live detection and tracking
    let options = VisionObjectDetectorOptions()
    options.detectorMode = .stream
    options.shouldEnableMultipleObjects = false
    options.shouldEnableClassification = true  // Optional
    
    // Multiple object detection in static images
    let options = VisionObjectDetectorOptions()
    options.detectorMode = .singleImage
    options.shouldEnableMultipleObjects = true
    options.shouldEnableClassification = true  // Optional
    

    Objective-C

    // Live detection and tracking
    FIRVisionObjectDetectorOptions *options = [[FIRVisionObjectDetectorOptions alloc] init];
    options.detectorMode = FIRVisionObjectDetectorModeStream;
    options.shouldEnableMultipleObjects = NO;
    options.shouldEnableClassification = YES;  // Optional
    
    // Multiple object detection in static images
    FIRVisionObjectDetectorOptions *options = [[FIRVisionObjectDetectorOptions alloc] init];
    options.detectorMode = FIRVisionObjectDetectorModeSingleImage;
    options.shouldEnableMultipleObjects = YES;
    options.shouldEnableClassification = YES;  // Optional
    
  2. Recupera un'istanza di FirebaseVisionObjectDetector:

    Swift

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

    Objective-C

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

2. Esegui il rilevatore di oggetti

Per rilevare e monitorare gli oggetti, svolgi i seguenti passaggi per ogni immagine o fotogramma del video. Se hai abilitato la modalità flusso di dati, devi creare VisionImage oggetti da CMSampleBufferRef

  1. Crea un oggetto VisionImage utilizzando un UIImage o un CMSampleBufferRef.

    Per utilizzare un UIImage:

    1. Se necessario, ruota l'immagine in modo che imageOrientation è .up.
    2. Crea un oggetto VisionImage utilizzando il UIImage ruotato correttamente. Non specificare alcun metadato di rotazione (l'impostazione predefinita) è necessario utilizzare il valore .topLeft.

      Swift

      let image = VisionImage(image: uiImage)

      Objective-C

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

    Per usare un CMSampleBufferRef:

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

      Per ottenere l'orientamento dell'immagine:

      Swift

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

      Objective-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 dei metadati:

      Swift

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

      Objective-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 Oggetto CMSampleBufferRef e metadati di rotazione:

      Swift

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

      Objective-C

      FIRVisionImage *image = [[FIRVisionImage alloc] initWithBuffer:sampleBuffer];
      image.metadata = metadata;
  2. 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) { detectedObjects, error in
      guard error == nil else {
        // Error.
        return
      }
      guard let detectedObjects = detectedObjects, !detectedObjects.isEmpty else {
        // No objects detected.
        return
      }
    
      // Success. Get object info here.
      // ...
    }
    

    Objective-C

    [objectDetector processImage:image
                      completion:^(NSArray<FIRVisionObject *> * _Nullable objects,
                                   NSError * _Nullable error) {
                        if (error == nil) {
                          return;
                        }
                        if (objects == nil | objects.count == 0) {
                          // No objects detected.
                          return;
                        }
    
                        // Success. Get object info here.
                        // ...
                      }];
    

    Per rilevare gli oggetti in modo sincrono:

    Swift

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

    Objective-C

    NSError *error;
    NSArray<FIRVisionObject *> *objects = [objectDetector resultsInImage:image
                                                                   error:&error];
    if (error == nil) {
      return;
    }
    if (objects == nil | objects.count == 0) {
      // No objects detected.
      return;
    }
    
    // Success. Get object info here.
    // ...
    
  3. Se la chiamata all'elaboratore di immagini va a buon fine, passa un elenco di VisionObject al gestore del completamento o lo restituisce, a seconda che tu abbia chiamato il metodo asincrono o sincrono.

    Ogni VisionObject contiene le seguenti proprietà:

    frame Un CGRect che indica la posizione dell'oggetto nell'immagine.
    trackingID Un numero intero che identifica l'oggetto nelle immagini. Nil in modalità di immagine singola.
    classificationCategory La categoria approssimativa dell'oggetto. Se il rilevatore di oggetti non ha attivato la classificazione, questo valore è sempre .unknown.
    confidence Il valore di confidenza della classificazione dell'oggetto. Se l'oggetto nel rilevatore non è abilitata la classificazione oppure l'oggetto è classificato come sconosciuto, questo è nil.

    Swift

    // detectedObjects contains one item if multiple object detection wasn't enabled.
    for obj in detectedObjects {
      let bounds = obj.frame
      let id = obj.trackingID
    
      // If classification was enabled:
      let category = obj.classificationCategory
      let confidence = obj.confidence
    }
    

    Objective-C

    // The list of detected objects contains one item if multiple
    // object detection wasn't enabled.
    for (FIRVisionObject *obj in objects) {
      CGRect bounds = obj.frame;
      if (obj.trackingID) {
        NSInteger id = obj.trackingID.integerValue;
      }
    
      // If classification was enabled:
      FIRVisionObjectCategory category = obj.classificationCategory;
      float confidence = obj.confidence.floatValue;
    }
    

Miglioramento dell'usabilità e delle prestazioni

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

  • Il rilevamento degli oggetti dipende dalla complessità visiva dell'oggetto. Oggetti con un numero ridotto di caratteristiche visive, potrebbe dover occupare una parte dell'immagine da rilevare. Fornisci agli utenti indicazioni su come acquisire input che funzionino bene con il tipo di oggetti che vuoi rilevare.
  • Quando utilizzi la classificazione, se vuoi rilevare oggetti che non rientrano chiaramente nelle categorie supportate, implementa un'elaborazione speciale per gli oggetti sconosciuti.

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.

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

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

  • Limita le chiamate al rilevatore. Se un nuovo frame video diventa disponibile mentre il rilevatore è in esecuzione, inseriscilo.
  • Se utilizzi l'output del rilevatore per sovrapporre la grafica all'immagine di input, ottieni prima il risultato da ML Kit, poi esegui il rendering dell'immagine e la sovrapposizione in un unico passaggio. In questo modo, esegui il rendering sulla superficie di visualizzazione solo una volta per ogni frame di input. Guarda previewOverlayView. e FIRDetectionOverlayView nell'app di esempio Showcase.