Puedes usar el Kit de AA para detectar objetos y hacerles seguimiento en marcos de video sucesivos.
Cuando pasas una imagen al Kit de AA, se detectan hasta cinco objetos en ella, junto con la posición de cada uno. Cuando se detectan objetos en transmisiones de video por Internet, cada uno de ellos tiene un ID único que puedes usar para seguirlo de fotograma a fotograma. De manera opcional, puedes habilitar la clasificación general de objetos, que etiqueta objetos con descripciones de categorías amplias.
Probarlo
- Juega con la app de muestra para ver un ejemplo de uso de esta API.
- Consulta la app de muestra de material design para ver una implementación de extremo a extremo de esta API.
Antes de comenzar
- Incluye los siguientes pods de 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 Kit de AA 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, especificar cualquier configuración del detector que quieras cambiar de la configuración predeterminada.
Configura el detector de objetos para tu caso práctico 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 producir resultados incompletos (como categorías o cuadros de límite 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 realizar un seguimiento de objetos o cuando la latencia baja sea 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 después de 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 estén disponibles el cuadro de límite y la etiqueta de categoría. Como consecuencia de esto, 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 haz un seguimiento de ellos false
(predeterminado) |true
Ya sea para detectar y hacer seguimiento de hasta cinco objetos o solo al más destacado (predeterminado).
Clasifica objetos false
(predeterminado) |true
Ya sea para clasificar objetos detectados en categorías generales. Cuando se habilita, el detector de objetos clasifica los objetos en las siguientes categorías: productos de moda, comida, artículos para el hogar, lugares y plantas.
La API de detección y seguimiento de objetos está optimizada para estos dos casos prácticos principales:
- Detección en tiempo real y seguimiento del objeto más prominente en el visor de la cámara.
- La detección de varios objetos en una imagen estática.
A fin de configurar la API para estos casos prácticos, sigue estos pasos:
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
con un UIImage
o CMSampleBuffer
.
Si usas un UIImage
, sigue estos pasos:
- Crea un objeto
VisionImage
con elUIImage
. Asegúrate de especificar la.orientation
correcta.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 se encuentran en
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 objeto y la orientaciónCMSampleBuffer
: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 manera 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 a un método asíncrono o a uno síncrono.
Cada Object
contiene las siguientes propiedades:
frame |
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 imagen única. |
labels |
Un arreglo de etiquetas que describen el objeto que muestra el detector.
La propiedad está vacía si la opción de detector shouldEnableClassification se configura en 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]; ... } }
Mejora de la usabilidad y el rendimiento
Para obtener la mejor experiencia del usuario, sigue estos lineamientos en tu aplicación:
- La detección correcta de objetos depende de la complejidad visual del objeto. Para que se puedan detectar, 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 la captura de entradas que funcione bien con el tipo de objetos que deseas detectar.
- Cuando uses la clasificación, si deseas detectar objetos que no se incluyen de forma clara en las categorías admitidas, implementa un control especial para objetos desconocidos.
Además, consulta la colección Patrones para 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 los mejores 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 manera síncrona desde el marco de video determinado. Mantén elalwaysDiscardsLateVideoFrames
deAVCaptureVideoDataOutput
comotrue
para regular 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 Kit de AA y, luego, procesa la imagen y la superposición en un solo paso. De esta manera, procesas en la superficie de visualización solo una vez por cada fotograma de entrada procesado. Consulta la updatePreviewOverlayViewWithLastFrame en la muestra de inicio rápido del Kit de AA para ver un ejemplo.