Detectar caras con ML Kit en iOS

Puede utilizar ML Kit para detectar rostros en imágenes y videos.

Antes de que empieces

  1. Si aún no has agregado Firebase a tu aplicación, hazlo siguiendo los pasos de la guía de introducción .
  2. Incluya las bibliotecas del kit ML en su Podfile:
    pod 'Firebase/MLVision', '6.25.0'
    # If you want to detect face contours (landmark detection and classification
    # don't require this additional model):
    pod 'Firebase/MLVisionFaceModel', '6.25.0'
    
    Después de instalar o actualizar los Pods de su proyecto, asegúrese de abrir su proyecto Xcode usando su .xcworkspace .
  3. En tu aplicación, importa Firebase:

    Rápido

    import Firebase

    C objetivo

    @import Firebase;

Pautas de imagen de entrada

Para que ML Kit detecte rostros con precisión, las imágenes de entrada deben contener rostros representados por suficientes datos de píxeles. En general, cada rostro que quieras detectar en una imagen debe tener al menos 100x100 píxeles. Si desea detectar los contornos de las caras, ML Kit requiere una entrada de mayor resolución: cada cara debe tener al menos 200 x 200 píxeles.

Si está detectando rostros en una aplicación en tiempo real, es posible que también desee considerar 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, capture imágenes con resoluciones más bajas (teniendo en cuenta los requisitos de precisión anteriores) y asegúrese de que la cara del sujeto ocupe la mayor parte posible de la imagen. Consulte también Sugerencias para mejorar el rendimiento en tiempo real .

Un mal enfoque de la imagen puede perjudicar la precisión. Si no obtiene resultados aceptables, intente pedirle 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 los rasgos faciales que detecta ML Kit. Consulte Conceptos de detección de rostros .

1. Configurar el detector de rostros

Antes de aplicar la detección de rostros a una imagen, si desea cambiar alguna de las configuraciones predeterminadas del detector de rostros, especifique esas configuraciones con un objeto VisionFaceDetectorOptions . Puede cambiar las siguientes configuraciones:

Ajustes
performanceMode fast (predeterminado) | accurate

Favorece la velocidad o la precisión a la hora de detectar rostros.

landmarkMode none (predeterminado) | all

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

contourMode none (predeterminado) | all

Ya sea para detectar los contornos de los rasgos faciales. Los contornos se detectan sólo para el rostro más prominente de una imagen.

classificationMode none (predeterminado) | all

Si clasificar o no los rostros en categorías como "sonriente" y "ojos abiertos".

minFaceSize CGFloat (predeterminado: 0.1 )

El tamaño mínimo, relativo a la imagen, de caras a detectar.

isTrackingEnabled false (predeterminado) | true

Si se asigna o no una identificación a las caras, que se puede utilizar para rastrear caras en las imágenes.

Tenga en cuenta que cuando la detección de contorno está habilitada, solo se detecta una cara, por lo que el seguimiento de caras no produce resultados útiles. Por este motivo, y para mejorar la velocidad de detección, no habilite tanto la detección de contornos como el seguimiento de rostros.

Por ejemplo, cree un objeto VisionFaceDetectorOptions como uno de los siguientes ejemplos:

Rápido

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

// Real-time contour detection of multiple faces
let options = VisionFaceDetectorOptions()
options.contourMode = .all

C objetivo

// High-accuracy landmark detection and face classification
FIRVisionFaceDetectorOptions *options = [[FIRVisionFaceDetectorOptions alloc] init];
options.performanceMode = FIRVisionFaceDetectorPerformanceModeAccurate;
options.landmarkMode = FIRVisionFaceDetectorLandmarkModeAll;
options.classificationMode = FIRVisionFaceDetectorClassificationModeAll;

// Real-time contour detection of multiple faces
FIRVisionFaceDetectorOptions *options = [[FIRVisionFaceDetectorOptions alloc] init];
options.contourMode = FIRVisionFaceDetectorContourModeAll;

2. Ejecute el detector de rostros

Para detectar rostros en una imagen, pase la imagen como UIImage o CMSampleBufferRef al método detect(in:) de VisionFaceDetector :

  1. Obtenga una instancia de VisionFaceDetector :

    Rápido

    lazy var vision = Vision.vision()
    
    let faceDetector = vision.faceDetector(options: options)
    

    C objetivo

    FIRVision *vision = [FIRVision vision];
    FIRVisionFaceDetector *faceDetector = [vision faceDetector];
    // Or, to change the default settings:
    // FIRVisionFaceDetector *faceDetector =
    //     [vision faceDetectorWithOptions:options];
    
  2. Cree un objeto VisionImage utilizando UIImage o CMSampleBufferRef .

    Para usar una UIImage :

    1. Si es necesario, gire la imagen para que su propiedad imageOrientation sea .up .
    2. Cree un objeto VisionImage utilizando UIImage girado correctamente. No especifique ningún metadato de rotación; se debe utilizar el valor predeterminado, .topLeft .

      Rápido

      let image = VisionImage(image: uiImage)

      C objetivo

      FIRVisionImage *image = [[FIRVisionImage alloc] initWithImage:uiImage];

    Para utilizar CMSampleBufferRef :

    1. Cree un objeto VisionImageMetadata que especifique la orientación de los datos de la imagen contenidos en el búfer CMSampleBufferRef .

      Para obtener la orientación de la imagen:

      Rápido

      func imageOrientation(
          deviceOrientation: UIDeviceOrientation,
          cameraPosition: AVCaptureDevice.Position
          ) -> VisionDetectorImageOrientation {
          switch deviceOrientation {
          case .portrait:
              return cameraPosition == .front ? .leftTop : .rightTop
          case .landscapeLeft:
              return cameraPosition == .front ? .bottomLeft : .topLeft
          case .portraitUpsideDown:
              return cameraPosition == .front ? .rightBottom : .leftBottom
          case .landscapeRight:
              return cameraPosition == .front ? .topRight : .bottomRight
          case .faceDown, .faceUp, .unknown:
              return .leftTop
          }
      }

      C objetivo

      - (FIRVisionDetectorImageOrientation)
          imageOrientationFromDeviceOrientation:(UIDeviceOrientation)deviceOrientation
                                 cameraPosition:(AVCaptureDevicePosition)cameraPosition {
        switch (deviceOrientation) {
          case UIDeviceOrientationPortrait:
            if (cameraPosition == AVCaptureDevicePositionFront) {
              return FIRVisionDetectorImageOrientationLeftTop;
            } else {
              return FIRVisionDetectorImageOrientationRightTop;
            }
          case UIDeviceOrientationLandscapeLeft:
            if (cameraPosition == AVCaptureDevicePositionFront) {
              return FIRVisionDetectorImageOrientationBottomLeft;
            } else {
              return FIRVisionDetectorImageOrientationTopLeft;
            }
          case UIDeviceOrientationPortraitUpsideDown:
            if (cameraPosition == AVCaptureDevicePositionFront) {
              return FIRVisionDetectorImageOrientationRightBottom;
            } else {
              return FIRVisionDetectorImageOrientationLeftBottom;
            }
          case UIDeviceOrientationLandscapeRight:
            if (cameraPosition == AVCaptureDevicePositionFront) {
              return FIRVisionDetectorImageOrientationTopRight;
            } else {
              return FIRVisionDetectorImageOrientationBottomRight;
            }
          default:
            return FIRVisionDetectorImageOrientationTopLeft;
        }
      }

      Luego, crea el objeto de metadatos:

      Rápido

      let cameraPosition = AVCaptureDevice.Position.back  // Set to the capture device you used.
      let metadata = VisionImageMetadata()
      metadata.orientation = imageOrientation(
          deviceOrientation: UIDevice.current.orientation,
          cameraPosition: cameraPosition
      )

      C objetivo

      FIRVisionImageMetadata *metadata = [[FIRVisionImageMetadata alloc] init];
      AVCaptureDevicePosition cameraPosition =
          AVCaptureDevicePositionBack;  // Set to the capture device you used.
      metadata.orientation =
          [self imageOrientationFromDeviceOrientation:UIDevice.currentDevice.orientation
                                       cameraPosition:cameraPosition];
    2. Cree un objeto VisionImage utilizando el objeto CMSampleBufferRef y los metadatos de rotación:

      Rápido

      let image = VisionImage(buffer: sampleBuffer)
      image.metadata = metadata

      C objetivo

      FIRVisionImage *image = [[FIRVisionImage alloc] initWithBuffer:sampleBuffer];
      image.metadata = metadata;
  3. Luego, pasa la imagen al método detect(in:) :

    Rápido

    faceDetector.process(visionImage) { faces, error in
      guard error == nil, let faces = faces, !faces.isEmpty else {
        // ...
        return
      }
    
      // Faces detected
      // ...
    }
    

    C objetivo

    [faceDetector detectInImage:image
                     completion:^(NSArray<FIRVisionFace *> *faces,
                                  NSError *error) {
      if (error != nil) {
        return;
      } else if (faces != nil) {
        // Recognized faces
      }
    }];
    

3. Obtener información sobre rostros detectados

Si la operación de detección de rostros tiene éxito, el detector de rostros pasa una serie de objetos VisionFace al controlador de finalización. Cada objeto VisionFace representa una cara que se detectó en la imagen. Para cada cara, puede obtener sus coordenadas delimitadoras en la imagen de entrada, así como cualquier otra información que haya configurado para que encuentre el detector de caras. Por ejemplo:

Rápido

for face in faces {
  let frame = face.frame
  if face.hasHeadEulerAngleY {
    let rotY = face.headEulerAngleY  // Head is rotated to the right rotY degrees
  }
  if face.hasHeadEulerAngleZ {
    let rotZ = face.headEulerAngleZ  // Head is rotated upward 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
  }
}

C objetivo

for (FIRVisionFace *face in faces) {
  // Boundaries of face in image
  CGRect frame = face.frame;

  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):
  FIRVisionFaceLandmark *leftEar = [face landmarkOfType:FIRFaceLandmarkTypeLeftEar];
  if (leftEar != nil) {
    FIRVisionPoint *leftEarPosition = leftEar.position;
  }

  // If contour detection was enabled:
  FIRVisionFaceContour *upperLipBottomContour = [face contourOfType:FIRFaceContourTypeUpperLipBottom];
  if (upperLipBottomContour != nil) {
    NSArray<FIRVisionPoint *> *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 cara.

Cuando tiene habilitada la detección del contorno del rostro, obtiene una lista de puntos para cada rasgo facial que se detectó. Estos puntos representan la forma de la característica. Consulte la descripción general de conceptos de detección de rostros para obtener detalles sobre cómo se representan los contornos.

La siguiente imagen ilustra cómo estos puntos se asignan a una cara (haga clic en la imagen para ampliarla):

Detección de rostros en tiempo real

Si desea utilizar la detección de rostros en una aplicación en tiempo real, siga estas pautas para lograr las mejores velocidades de fotogramas:

  • Configure el detector de rostros para utilizar la detección del contorno del rostro o la clasificación y detección de puntos de referencia, pero no ambas:

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

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

  • Considere capturar imágenes a una resolución más baja. Sin embargo, también tenga en cuenta los requisitos de dimensión de imagen de esta API.

  • Llamadas del acelerador al detector. Si hay un nuevo cuadro de video disponible mientras el detector está en ejecución, suelte el cuadro.
  • Si está utilizando la salida del detector para superponer gráficos en la imagen de entrada, primero obtenga el resultado del ML Kit, luego renderice la imagen y superpóngala en un solo paso. Al hacerlo, renderiza en la superficie de visualización solo una vez por cada cuadro de entrada. Consulte las clases previaOverlayView y FIRDetectionOverlayView en la aplicación de muestra de presentación para ver un ejemplo.