Detecta objetos y hazles seguimiento con ML Kit en iOS

Puedes usar ML Kit para detectar objetos y hacerles seguimiento en fotogramas sucesivos de video.

Cuando pasas una imagen al Kit de AA, este detecta hasta cinco objetos junto con la posición de cada objeto en la imagen. Al detectar objetos en transmisiones de video por Internet, cada objeto tiene un ID único que puedes usar para seguir el objeto de un fotograma a otro. También tienes la opción de habilitar objetos de clasificación, que etiqueta objetos con descripciones de categorías amplias.

Probar

Antes de comenzar

  1. Incluye los siguientes pods del ML Kit en tu Podfile:
    pod 'GoogleMLKit/ObjectDetection', '3.2.0'
    
  2. Después de instalar o actualizar los Pods de tu proyecto, abre el proyecto de Xcode a través de 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 crea una instancia de ObjectDetector y, de manera opcional, especifica cualquier configuración del detector que quieras cambian de la configuración predeterminada.

  1. Configura el detector de objetos para tu caso de uso con un ObjectDetectorOptions. Puedes cambiar las siguientes opciones 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 un puede generar resultados incompletos (como los cuadros delimitadores o categorías) en las primeras invocaciones del el detector. Además, en el modo de transmisión, el detector asigna el seguimiento IDs de objetos, que puedes usar para hacer un seguimiento de objetos en los fotogramas. Usa este modo cuando quieras hacer un seguimiento de objetos o cuando haya latencia baja es importante, como cuando se procesan transmisiones de video tiempo.

    En el modo de imagen única, el detector de objetos muestra el resultado luego de determinar el cuadro delimitador del objeto. Si también habilitas clasificación, devuelve el resultado después del cuadro delimitador y están disponibles las dos etiquetas de categoría. Como consecuencia, la detección la latencia es potencialmente mayor. Además, en el modo de imagen única, el seguimiento No se asignaron los IDs. Usa este modo si la latencia no es crítica no debes ocuparte de resultados parciales.

    Detecta varios objetos y hazles un seguimiento false (predeterminado) | true

    Ya sea para detectar y rastrear hasta cinco objetos o solo los más objeto destacado (predeterminado).

    Clasifica objetos false (predeterminado) | true

    Indica si se deben clasificar o no los objetos detectados en categorías generales. Cuando se habilita, el detector de objetos clasifica los objetos 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 estos dos usos principales casos:

    • Detección y seguimiento en vivo del objeto más prominente de la cámara visor.
    • Es la detección de varios objetos en una imagen estática.

    Si deseas configurar la API para estos casos de uso, 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;
  1. 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 objeto UIImage o CMSampleBuffer

Si usas un UIImage, sigue estos pasos:

  • Crea un objeto VisionImage con UIImage. 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:

  • Especificar la orientación de los datos de imagen que se incluyen en la 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 elemento Objeto CMSampleBuffer y 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 el VisionImage a uno de los procesamientos de imágenes del detector de objetos. . Puedes usar el método process(image:) asíncrono o método síncrono results().

Para detectar objetos de manera 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 de Object al controlador de finalización o muestra la lista, según lo siguiente: sin importar si llama al método asíncrono o síncrono.

Cada Object contiene las siguientes propiedades:

frame Un CGRect que indica la posición del objeto en el imagen.
trackingID Un número entero que identifica el objeto en las imágenes, o "nil" en modo de imagen única.
labels Un array de etiquetas que describen el objeto que muestra el detector. La propiedad está 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];
    ...
  }
}

Mejora 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. En ser detectados, los objetos con un número reducido de características visuales podrían necesitar ocupe una parte más grande de la imagen. Debes brindar orientación a los usuarios sobre y capturar entradas que funcionen bien con el tipo de objetos que quieres detectar.
  • Cuando usas la clasificación, si deseas detectar objetos que no caen de forma clara en las categorías admitidas, implementa un manejo especial para los objetos.

Consulta también el Material Design Colección de patrones para atributos con tecnología de aprendizaje automático.

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 múltiples objetos en el modo de transmisión, ya que la mayoría de los dispositivos no lo hace. producir una velocidad de fotogramas adecuada.
  • Inhabilita la clasificación si no la necesitas.
  • Para procesar fotogramas de video, usa la API síncrona results(in:) del detector. Llamada este método desde De AVCaptureVideoDataOutputSampleBufferDelegate La función captureOutput(_, didOutput:from:) para obtener resultados de un video determinado de forma síncrona marco. Mantener de AVCaptureVideoDataOutput alwaysDiscardsLateVideoFrames como true para limitar las llamadas al detector Si un nuevo cliente El fotograma estará disponible mientras se ejecute el detector, que se descartará.
  • Si usas la salida del detector para superponer gráficos la imagen de entrada, primero obtén el resultado del ML Kit y, luego, renderiza la imagen y superponerla en un solo paso. De esta manera, renderizas en la superficie de visualización. solo una vez por cada trama de entrada procesada. Consulta updatePreviewOverlayViewWithLastFrame. en la muestra de inicio rápido del Kit de AA para ver un ejemplo.