Puoi utilizzare ML Kit per rilevare e tenere traccia degli oggetti in fotogrammi video successivi.
Quando passi un'immagine a ML Kit, questo rileva fino a cinque oggetti nell'immagine, insieme alla posizione di ciascuno di essi. Durante il rilevamento degli oggetti nei flussi video, ogni oggetto ha un ID univoco che consente di monitorare l'oggetto da un frame all'altro. Facoltativamente, puoi abilitare la classificazione di oggetti approssimativi, che etichettano gli oggetti con descrizioni generiche.
Prova
- Prova l'app di esempio per vedere un utilizzo di esempio di questa API.
- Consulta l'app Material Design Showcase per un'implementazione end-to-end di questa API.
Prima di iniziare
- Includi i seguenti pod ML Kit nel podfile:
pod 'GoogleMLKit/ObjectDetection', '3.2.0'
- Dopo aver installato o aggiornato i pod del progetto, apri il progetto Xcode utilizzando il relativo
.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 di
ObjectDetector
e, se vuoi, specificare le impostazioni del rilevatore che vuoi
modificare rispetto a quelle predefinite.
Configura il rilevatore di oggetti per il tuo caso d'uso con un oggetto
ObjectDetectorOptions
. Puoi modificare le seguenti impostazioni:Impostazioni rilevatore di oggetti Modalità di rilevamento .stream
(valore predefinito) |.singleImage
In modalità flusso (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) durante le prime chiamate del rilevatore. Inoltre, in modalità flusso, il rilevatore assegna ID di monitoraggio agli oggetti, che possono essere utilizzati per monitorare gli oggetti tra i frame. Utilizza questa modalità quando desideri monitorare gli oggetti o quando la bassa latenza è importante, ad esempio durante l'elaborazione di video stream in tempo reale.
In modalità a immagine singola, il rilevatore di oggetti restituisce il risultato dopo aver determinato il riquadro di delimitazione dell'oggetto. Se abiliti anche la classificazione, viene restituito il risultato dopo che il riquadro di delimitazione e l'etichetta della categoria sono entrambi disponibili. Di conseguenza, la latenza del rilevamento è potenzialmente più elevata. Inoltre, in modalità immagine singola, gli ID di monitoraggio non vengono assegnati. Utilizza questa modalità se la latenza non è critica e non vuoi avere a che fare con risultati parziali.
Rileva e monitora più oggetti false
(valore predefinito) |true
Indica se rilevare e tracciare fino a cinque oggetti o solo l'oggetto più in evidenza (impostazione predefinita).
Classificare gli oggetti false
(valore predefinito) |true
Indica se classificare o meno gli oggetti rilevati in categorie approssimative. Quando è abilitato, il rilevatore di oggetti classifica gli oggetti nelle seguenti categorie: articoli di moda, cibo, articoli per la casa, luoghi e piante.
L'API di rilevamento e monitoraggio degli oggetti è ottimizzata per questi due casi d'uso principali:
- Rilevamento e tracciamento in tempo reale 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;
- 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 frame video.
Se hai abilitato la modalità flusso, devi creare VisionImage
oggetti dagli CMSampleBuffer
.
Crea un oggetto VisionImage
utilizzando UIImage
o CMSampleBuffer
.
Se usi un UIImage
, segui questi passaggi:
- Crea un oggetto
VisionImage
con ilUIImage
. 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 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'oggettoCMSampleBuffer
e l'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
PassaVisionImage
a uno dei metodi di elaborazione delle immagini del rilevatore di oggetti. Puoi utilizzare il metodo process(image:)
asincrono o il
metodo sincrono results()
.
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. Visualizza informazioni sugli oggetti rilevati
Se la chiamata al processore di immagini ha esito positivo, passa un elenco diObject
al gestore di completamento oppure restituisce l'elenco, a seconda che tu abbia chiamato il metodo asincrono o sincrono.
Ogni Object
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 oppure "nil" in modalità a 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 corretto rilevamento degli oggetti dipende dalla complessità visiva dell'oggetto. Per essere rilevati, gli oggetti con un numero ridotto di caratteristiche visive potrebbero dover occupare una parte più ampia dell'immagine. 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 perfettamente nelle categorie supportate, implementa una gestione speciale per gli oggetti sconosciuti.
Inoltre, dai un'occhiata alla raccolta Pattern per funzionalità basate sul machine learning di Material Design.
Quando utilizzi la modalità di streaming in un'applicazione in tempo reale, segui queste linee guida per ottenere le frequenze fotogrammi migliori:
- Non utilizzare il rilevamento di più oggetti in modalità flusso, poiché la maggior parte dei dispositivi non sarà 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. Richiama questo metodo dalla funzionecaptureOutput(_, didOutput:from:)
diAVCaptureVideoDataOutputSampleBufferDelegate
per ottenere in modo sincrono i risultati dal frame video specificato. Mantieni il valoretrue
peralwaysDiscardsLateVideoFrames
diAVCaptureVideoDataOutput
per limitare le chiamate al rilevatore. Se un nuovo frame video diventa disponibile mentre il rilevatore è in esecuzione, questo verrà eliminato. - Se utilizzi l'output del rilevatore per sovrapporre gli elementi grafici all'immagine di input, recupera prima il risultato da ML Kit, quindi esegui il rendering dell'immagine e dell'overlay in un solo passaggio. In questo modo, esegui il rendering sulla piattaforma di visualizzazione solo una volta per ogni frame di input elaborato. Per un esempio, vedi updatePreviewOverlayViewWithLastFrame nell'esempio della guida rapida di ML Kit.