Puedes usar ML Kit para detectar objetos en fotogramas de video sucesivos y hacerles seguimiento.
Cuando pasas una imagen al Kit de AA, este detecta hasta cinco objetos en la imagen, junto con la posición de cada uno de ellos. Cuando se detectan objetos en transmisiones de video por Internet, cada objeto tiene un ID único que puedes usar para seguirlo de fotograma a fotograma. De manera opcional, también puedes habilitar la clasificación aproximada de objetos, que etiqueta los objetos con descripciones de categorías amplias.
Probar
- Prueba la app de ejemplo para ver un ejemplo de uso de esta API.
- Consulta la app de muestra de material design para obtener una implementación de extremo a extremo de esta API.
Antes de comenzar
- Incluye los siguientes pods del ML Kit en tu Podfile:
pod 'GoogleMLKit/ObjectDetection', '3.2.0'
- Después de instalar o actualizar los Pods de tu proyecto, abre el proyecto de Xcode con su
.xcworkspace
. El ML Kit es compatible con Xcode 12.4 o versiones posteriores.
1. Configura el detector de objetos
Para detectar objetos y hacerles seguimiento, primero debes crear una instancia de ObjectDetector
y, de manera opcional, especifica cualquier configuración del detector que desees cambiar de la configuración predeterminada.
Configura el detector de objetos para tu caso de uso con un objeto
ObjectDetectorOptions
. Puedes cambiar las siguientes opciones de configuración:Configuración del detector de objetos Modo de detección .stream
(predeterminado) |.singleImage
En el modo de transmisión (predeterminado), el detector de objetos se ejecuta con una latencia muy baja, pero puede generar resultados incompletos (como cuadros de límite o categorías no especificados) en las primeras invocaciones del detector. Además, en el modo de transmisión, el detector asigna ID de seguimiento a los objetos, que puedes usar para hacer seguimiento de objetos en los marcos. Usa este modo cuando quieras hacer seguimiento de objetos o si la latencia baja es importante, como cuando procesas transmisiones de video por Internet en tiempo real.
En el modo de imagen única, el detector de objetos muestra el resultado una vez que se determina el cuadro de límite del objeto. Si también habilitas la clasificación, se muestra el resultado después de que el cuadro de límite y la etiqueta de categoría estén disponibles. En consecuencia, la latencia de detección es potencialmente más alta. Además, en el modo de imagen única, no se asignan ID de seguimiento. Usa este modo si la latencia no es crítica y no quieres lidiar con resultados parciales.
Detecta varios objetos y hazles seguimiento false
(predeterminado) |true
Ya sea para detectar y hacer seguimiento de hasta cinco objetos o solo al más prominente (predeterminado).
Clasificar objetos false
(predeterminado) |true
Indica si se deben clasificar o no los objetos detectados en categorías generales. Cuando está habilitado, el detector de objetos clasifica los objetos en las siguientes categorías: artículos de moda, comida, artículos para el hogar, lugares y plantas.
La API de detección y seguimiento de objetos está optimizada para los siguientes dos casos prácticos principales:
- Detección y seguimiento en vivo del objeto más prominente en el visor de la cámara
- La detección de múltiples objetos en una imagen estática.
Si deseas configurar la API para estos casos de uso, haz lo siguiente:
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;
- Obtén una instancia de
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 la imagen de entrada
Para detectar objetos y hacerles seguimiento, haz lo siguiente con cada imagen o fotograma de video.
Si habilitaste el modo de transmisión, debes crear objetos VisionImage
a partir de CMSampleBuffer
.
Crea un objeto VisionImage
mediante una UIImage
o CMSampleBuffer
.
Si usas un UIImage
, sigue estos pasos:
- Crea un objeto
VisionImage
con laUIImage
. Asegúrate de especificar el.orientation
correcto.Swift
let image = VisionImage(image: UIImage) visionImage.orientation = image.imageOrientation
Objective‑C
MLKVisionImage *visionImage = [[MLKVisionImage alloc] initWithImage:image]; visionImage.orientation = image.imageOrientation;
Si usas un CMSampleBuffer
, sigue estos pasos:
-
Especifica la orientación de los datos de imagen que contiene
CMSampleBuffer
.Para obtener la orientación de la imagen, haz lo siguiente:
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 objeto
VisionImage
con el objetoCMSampleBuffer
y la orientación: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. Procesa la imagen
Pasa elVisionImage
a uno de los métodos de procesamiento de imágenes del detector de objetos. Puedes usar el método asíncrono process(image:)
o el método síncrono results()
.
Para detectar objetos de forma asíncrona, haz lo siguiente:
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. }];
Para detectar objetos de forma síncrona, haz lo siguiente:
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. Obtén información sobre los objetos detectados
Si la llamada al procesador de imágenes se ejecuta correctamente, este pasa una lista deObject
al controlador de finalización o la muestra, dependiendo de si llamaste al método asíncrono o síncrono.
Cada Object
contiene las siguientes propiedades:
frame |
Es un CGRect que indica la posición del objeto en la imagen. |
trackingID |
Un número entero que identifica el objeto en las imágenes o "nil" en el modo de una sola imagen. |
labels |
Un arreglo de etiquetas que describen el objeto que muestra el detector.
La propiedad estará vacía si la opción del detector shouldEnableClassification se configura como 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]; ... } }
Cómo mejorar la usabilidad y el rendimiento
Para obtener la mejor experiencia del usuario, sigue estos lineamientos en tu app:
- La detección correcta de objetos depende de la complejidad visual del objeto. Para poder detectarse, es posible que los objetos con una pequeña cantidad de características visuales deban ocupar una parte más grande de la imagen. Debes proporcionar a los usuarios orientación sobre cómo capturar entradas que funcionen bien con el tipo de objetos que deseas detectar.
- Cuando usas la clasificación, si deseas detectar objetos que no se incluyen de forma clara en las categorías admitidas, implementa un manejo especial para objetos desconocidos.
Además, consulta la colección de patrones para las funciones con tecnología de aprendizaje automático de Material Design.
Cuando uses el modo de transmisión en una aplicación en tiempo real, sigue estos lineamientos para lograr la mejor velocidad de fotogramas:
- No uses la detección de varios objetos en el modo de transmisión, ya que la mayoría de los dispositivos no podrán producir fotogramas adecuados.
- Inhabilita la clasificación si no la necesitas.
- Para procesar fotogramas de video, usa la API síncrona
results(in:)
del detector. Llama a este método desde la funcióncaptureOutput(_, didOutput:from:)
deAVCaptureVideoDataOutputSampleBufferDelegate
para obtener resultados de un fotograma de video determinado de manera síncrona. Mantén elalwaysDiscardsLateVideoFrames
deAVCaptureVideoDataOutput
comotrue
para limitar las llamadas al detector. Si hay un fotograma de video nuevo disponible mientras se ejecuta el detector, se descartará. - Si usas la salida del detector para superponer gráficos en la imagen de entrada, primero obtén el resultado del ML Kit y, luego, procesa la imagen y la superposición en un solo paso. De esta manera, renderizas en la superficie de visualización solo una vez por cada fotograma de entrada procesado. Consulta updatePreviewOverlayViewWithLastFrame en la muestra de inicio rápido del Kit de AA para ver un ejemplo.