Detecta rostros con ML Kit en iOS

Puedes usar ML Kit para detectar rostros en imágenes y videos.

Probar

Antes de comenzar

  1. Incluye los siguientes pods del ML Kit en tu Podfile:
    pod 'GoogleMLKit/FaceDetection', '3.2.0'
    
  2. 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.

Lineamientos para imágenes de entrada

Para el reconocimiento facial, debes usar una imagen con una dimensión de al menos 480 × 360 píxeles. Para que el Kit de AA detecte rostros con precisión, las imágenes de entrada deben contener rostros representados con datos de píxeles suficientes. En general, cada rostro que quieras detectar en una imagen debe tener al menos 100 x 100 píxeles. Si quieres detectar el contorno de los rostros, el ML Kit requiere una entrada de mayor resolución: cada rostro debe tener al menos 200 x 200 píxeles.

Si detectas rostros en una aplicación en tiempo real, te recomendamos que también consideres las dimensiones generales de las imágenes de entrada. Las imágenes más pequeñas se pueden procesar más rápido. Por lo tanto, para reducir la latencia, captura imágenes con resoluciones más bajas, pero ten en cuenta los requisitos de precisión que se mencionaron antes y asegúrate de que el rostro del sujeto ocupe la mayor parte de la imagen posible. Consulta también las sugerencias para mejorar el rendimiento en tiempo real.

Un enfoque de imagen deficiente también puede afectar la exactitud. Si no obtienes resultados aceptables, pídele al usuario que vuelva a capturar la imagen.

La orientación de un rostro en relación con la cámara también puede afectar las características que detecta el ML Kit. Consulta Conceptos de detección de rostro.

1. Configura el detector de rostros

Antes de aplicar la detección de rostro a una imagen, especifica la configuración con un objeto FaceDetectorOptions si quieres modificar la configuración predeterminada del detector de rostros. Puedes cambiar las siguientes opciones de configuración:

Configuración
performanceMode fast (predeterminado) | accurate

Da prioridad a la velocidad o a la precisión en la detección de rostros.

landmarkMode none (predeterminado) | all

Indica si se debe intentar detectar "puntos de referencia" faciales (ojos, orejas, nariz, mejillas, boca) de todos los rostros detectados.

contourMode none (predeterminado) | all

Indica si se deben detectar los contornos de los rasgos faciales. Solo se detectan los contornos de los rostros más destacados de una imagen.

classificationMode none (predeterminado) | all

Indica si se deben clasificar los rostros en categorías como "sonriente" y "ojos abiertos".

minFaceSize CGFloat (predeterminado: 0.1)

Configura el tamaño de rostro más pequeño que desees, expresado como la proporción entre el ancho de la cabeza y el ancho de la imagen.

isTrackingEnabled false (predeterminado) | true

Indica si se deben asignar ID a los rostros, que se pueden usar para hacer un seguimiento de los rostros en distintas imágenes.

Ten en cuenta que, cuando la detección de contorno está habilitada, solo se detectará un rostro, por lo que el seguimiento de rostros no producirá resultados útiles. Por este motivo, y para mejorar la velocidad de detección, no habilites la detección de contorno y el seguimiento de rostros a la vez.

Por ejemplo, compila un objeto FaceDetectorOptions como uno de los ejemplos siguientes:

Swift

// High-accuracy landmark detection and face classification
let options = FaceDetectorOptions()
options.performanceMode = .accurate
options.landmarkMode = .all
options.classificationMode = .all

// Real-time contour detection of multiple faces
// options.contourMode = .all

Objective‑C

// High-accuracy landmark detection and face classification
MLKFaceDetectorOptions *options = [[MLKFaceDetectorOptions alloc] init];
options.performanceMode = MLKFaceDetectorPerformanceModeAccurate;
options.landmarkMode = MLKFaceDetectorLandmarkModeAll;
options.classificationMode = MLKFaceDetectorClassificationModeAll;

// Real-time contour detection of multiple faces
// options.contourMode = MLKFaceDetectorContourModeAll;

2. Prepara la imagen de entrada

Para detectar rostros en una imagen, pasa la imagen como UIImage o CMSampleBufferRef a FaceDetector usando el método process(_:completion:) o results(in:):

Crea un objeto VisionImage mediante una UIImage o CMSampleBuffer.

Si usas un UIImage, sigue estos pasos:

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

  • 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 objeto CMSampleBuffer 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. Obtén una instancia de FaceDetector

Obtén una instancia de FaceDetector:

Swift

let faceDetector = FaceDetector.faceDetector(options: options)

Objective‑C

MLKFaceDetector *faceDetector = [MLKFaceDetector faceDetectorWithOptions:options];
      

4. Procesa la imagen

Por último, pasa la imagen al método process():

Swift

weak var weakSelf = self
faceDetector.process(visionImage) { faces, error in
  guard let strongSelf = weakSelf else {
    print("Self is nil!")
    return
  }
  guard error == nil, let faces = faces, !faces.isEmpty else {
    // ...
    return
  }

  // Faces detected
  // ...
}

Objective‑C

[faceDetector processImage:image
                completion:^(NSArray<MLKFace *> *faces,
                             NSError *error) {
  if (error != nil) {
    return;
  }
  if (faces.count > 0) {
    // Recognized faces
  }
}];

5. Obtén información sobre los rostros detectados

Si la operación de detección de rostro se ejecuta correctamente, el detector de rostros pasará un arreglo de objetos Face al controlador de finalización. Cada objeto Face representa un rostro que se detectó en la imagen. Para cada rostro, puedes obtener las coordenadas de sus límites en la imagen de entrada, junto con cualquier otra información que encuentre el detector de rostros según la configuración que le asignaste. Por ejemplo:

Swift

for face in faces {
  let frame = face.frame
  if face.hasHeadEulerAngleX {
    let rotX = face.headEulerAngleX  // Head is rotated to the uptoward rotX degrees
  }
  if face.hasHeadEulerAngleY {
    let rotY = face.headEulerAngleY  // Head is rotated to the right rotY degrees
  }
  if face.hasHeadEulerAngleZ {
    let rotZ = face.headEulerAngleZ  // Head is tilted sideways rotZ degrees
  }

  // If landmark detection was enabled (mouth, ears, eyes, cheeks, and
  // nose available):
  if let leftEye = face.landmark(ofType: .leftEye) {
    let leftEyePosition = leftEye.position
  }

  // If contour detection was enabled:
  if let leftEyeContour = face.contour(ofType: .leftEye) {
    let leftEyePoints = leftEyeContour.points
  }
  if let upperLipBottomContour = face.contour(ofType: .upperLipBottom) {
    let upperLipBottomPoints = upperLipBottomContour.points
  }

  // If classification was enabled:
  if face.hasSmilingProbability {
    let smileProb = face.smilingProbability
  }
  if face.hasRightEyeOpenProbability {
    let rightEyeOpenProb = face.rightEyeOpenProbability
  }

  // If face tracking was enabled:
  if face.hasTrackingID {
    let trackingId = face.trackingID
  }
}

Objective‑C

for (MLKFace *face in faces) {
  // Boundaries of face in image
  CGRect frame = face.frame;
  if (face.hasHeadEulerAngleX) {
    CGFloat rotX = face.headEulerAngleX;  // Head is rotated to the upward rotX degrees
  }
  if (face.hasHeadEulerAngleY) {
    CGFloat rotY = face.headEulerAngleY;  // Head is rotated to the right rotY degrees
  }
  if (face.hasHeadEulerAngleZ) {
    CGFloat rotZ = face.headEulerAngleZ;  // Head is tilted sideways rotZ degrees
  }

  // If landmark detection was enabled (mouth, ears, eyes, cheeks, and
  // nose available):
  MLKFaceLandmark *leftEar = [face landmarkOfType:FIRFaceLandmarkTypeLeftEar];
  if (leftEar != nil) {
    MLKVisionPoint *leftEarPosition = leftEar.position;
  }

  // If contour detection was enabled:
  MLKFaceContour *upperLipBottomContour = [face contourOfType:FIRFaceContourTypeUpperLipBottom];
  if (upperLipBottomContour != nil) {
    NSArray<MLKVisionPoint *> *upperLipBottomPoints = upperLipBottomContour.points;
    if (upperLipBottomPoints.count > 0) {
      NSLog("Detected the bottom contour of the subject's upper lip.")
    }
  }

  // If classification was enabled:
  if (face.hasSmilingProbability) {
    CGFloat smileProb = face.smilingProbability;
  }
  if (face.hasRightEyeOpenProbability) {
    CGFloat rightEyeOpenProb = face.rightEyeOpenProbability;
  }

  // If face tracking was enabled:
  if (face.hasTrackingID) {
    NSInteger trackingID = face.trackingID;
  }
}

Ejemplo de contornos de rostro

Cuando la detección de contorno de rostro se encuentra habilitada, obtienes una lista de puntos por cada rasgo facial que se detectó. Estos puntos representan la forma del componente. Consulta Conceptos de detección de rostros para obtener más información sobre cómo se representan los contornos.

En la siguiente imagen, se ilustra cómo se asignan estos puntos a un rostro. Haz clic en la imagen para ampliarla:

ejemplo de malla de contorno de rostro detectado

Detección de rostro en tiempo real

Si quieres usar la detección de rostro en una aplicación en tiempo real, sigue estos lineamientos para lograr la mejor velocidad de fotogramas:

  • Configura el detector de rostros para usar la detección de contorno facial o la clasificación y detección de puntos de referencia, pero no ambos:

    Detección de contorno
    Detección de puntos de referencia
    Clasificación
    Detección y clasificación de puntos de referencia
    Detección de contorno y de puntos de referencia
    Detección y clasificación de contornos
    Detección de contorno y de puntos de referencia, y clasificación

  • Habilita el modo fast (habilitado de forma predeterminada).

  • Considera capturar imágenes con una resolución más baja. Sin embargo, también ten en cuenta los requisitos de dimensiones de imágenes de esta API.

  • Para procesar fotogramas de video, usa la API síncrona results(in:) del detector. Llama a este método desde la función captureOutput(_, didOutput:from:) de AVCaptureVideoDataOutputSampleBufferDelegate para obtener resultados de un fotograma de video determinado de manera síncrona. Mantén el alwaysDiscardsLateVideoFrames de AVCaptureVideoDataOutput como true 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.