Detectar rostos com o Kit de ML no iOS

Você pode usar o Kit de ML para detectar rostos em imagens e vídeos.

Faça um teste

Antes de começar

  1. Inclua os seguintes pods do kit de ML no seu Podfile:
    pod 'GoogleMLKit/FaceDetection', '3.2.0'
    
  2. Depois de instalar ou atualizar os pods do seu projeto, abra o projeto Xcode usando o .xcworkspace: O Kit de ML é compatível com a versão 12.4 ou mais recente do Xcode.

Diretrizes de imagens de entrada

Para reconhecimento facial, você deve usar uma imagem com dimensões de pelo menos 480 x 360 pixels. Para que o Kit de ML detecte rostos com precisão, as imagens de entrada precisam conter rostos representados por dados de pixel suficientes. Em geral, cada rosto que você quer para detectar em uma imagem deve ter pelo menos 100 x 100 pixels. Se você quiser detectar os contornos dos rostos, o kit de ML exige uma entrada de resolução mais alta: cada rosto deve ter pelo menos 200 x 200 pixels.

Se você detectar rostos em um aplicativo em tempo real, também pode querer considere as dimensões gerais das imagens de entrada. Imagens menores podem ser processados mais rapidamente, por isso, para reduzir a latência, capture imagens em resoluções mais baixas, mas os requisitos de precisão acima e garantir que os o rosto da pessoa ocupa o máximo possível da imagem. Consulte também dicas para melhorar o desempenho em tempo real.

Uma imagem com foco inadequado também pode afetar a precisão. Caso o conteúdo não seja aceito peça para o usuário recapturar a imagem.

A orientação de um rosto em relação à câmera também pode afetar características de atributos que o kit de ML detecta. Consulte Conceitos de detecção facial.

1. Configurar o detector facial

Antes de aplicar a detecção facial a uma imagem, se você quiser alterar padrão do detector facial, especifique essas configurações com uma Objeto FaceDetectorOptions. É possível mudar as seguintes configurações:

Configurações
performanceMode fast (padrão) | accurate

Favoreça a velocidade ou a precisão ao detectar rostos.

landmarkMode none (padrão) | all

Para tentar detectar os "pontos de referência" faciais, como olhos, orelhas, nariz, bochechas, boca — de todos os rostos detectados.

contourMode none (padrão) | all

Para detectar os contornos das características faciais. Os contornos são detectado apenas no rosto mais proeminente da imagem.

classificationMode none (padrão) | all

Se é necessário classificar rostos em categorias como "sorrindo" e "de olhos abertos".

minFaceSize CGFloat (padrão: 0.1)

Define o menor tamanho facial desejado, expresso como a proporção do largura da cabeça com a largura da imagem.

isTrackingEnabled false (padrão) | true

Se é necessário atribuir um ID aos rostos, que pode ser usado para rastrear rostos nas imagens.

Quando a detecção de contorno está ativada, apenas um rosto detectado. Por isso, o rastreamento facial não produz resultados úteis. Para isso e, para melhorar a velocidade de detecção, não ative as duas opções detecção e rastreamento facial.

Por exemplo, crie um objeto FaceDetectorOptions como um dos seguintes exemplos:

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. Preparar a imagem de entrada

Para detectar rostos em uma imagem, transmita a imagem como UIImage ou CMSampleBufferRef para FaceDetector usando o Método process(_:completion:) ou results(in:):

Crie um objeto VisionImage usando um UIImage ou um CMSampleBuffer.

Se você usa um UIImage, siga estas etapas:

  • Crie um objeto VisionImage com o UIImage. Especifique o .orientation correto.

    Swift

    let image = VisionImage(image: UIImage)
    visionImage.orientation = image.imageOrientation

    Objective-C

    MLKVisionImage *visionImage = [[MLKVisionImage alloc] initWithImage:image];
    visionImage.orientation = image.imageOrientation;

Se você usa um CMSampleBuffer, siga estas etapas:

  • Especifique a orientação dos dados da imagem contidos no CMSampleBuffer:

    Para saber qual é a orientação da imagem:

    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;
      }
    }
          
  • Crie um objeto VisionImage usando o Objeto e orientação CMSampleBuffer:

    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. Receber uma instância do FaceDetector

Receba uma instância de FaceDetector:

Swift

let faceDetector = FaceDetector.faceDetector(options: options)

Objective-C

MLKFaceDetector *faceDetector = [MLKFaceDetector faceDetectorWithOptions:options];
      

4. Processar a imagem

Em seguida, transmita a imagem para o 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. Receber informações sobre rostos detectados

Se a operação de detecção facial for bem-sucedida, o detector vai transmitir uma matriz. de objetos Face para o gerenciador de conclusão. Cada O objeto Face representa um rosto que foi detectado na imagem. Para cada rosto, é possível obter as coordenadas delimitadoras na imagem de entrada, bem como qualquer outra informação configurada para ser encontrada pelo detector facial. Exemplo:

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;
  }
}

Exemplo de contornos faciais

Quando a detecção de contorno facial está ativada, você recebe uma lista de pontos para cada característica facial que foi detectada. Esses pontos representam a forma . Ver Rosto de detecção para detalhes sobre como os contornos representados.

A imagem a seguir ilustra como esses pontos mapeiam um rosto. Clique no imagem para ampliá-la:

exemplo de malha de contorno facial detectado

Detecção facial em tempo real

Se você quiser usar a detecção facial em um aplicativo em tempo real, siga estas diretrizes para obter as melhores taxas de quadros:

  • Configure o detector facial para usar detecção de contorno facial ou classificação e detecção de pontos de referência, mas não os dois:

    Detecção de contorno
    Detecção de pontos de referência
    Classificação
    Detecção e classificação de pontos de referência
    Detecção de contorno e detecção de pontos de referência
    Detecção e classificação de contorno
    Detecção de contorno, detecção de pontos de referência e classificação

  • Ative o modo fast (ativado por padrão).

  • Capture imagens em uma resolução mais baixa. No entanto, também tenha em mente os requisitos de dimensão de imagem dessa API.

  • Para processar frames de vídeo, use a API síncrona results(in:) do detector. Ligação esse método da AVCaptureVideoDataOutputSampleBufferDelegate captureOutput(_, didOutput:from:) para receber resultados do vídeo fornecido de forma síncrona frame. Manter de AVCaptureVideoDataOutput alwaysDiscardsLateVideoFrames como true para limitar as chamadas ao detector. Se uma nova frame de vídeo ficar disponível enquanto o detector estiver em execução, ele será descartado.
  • Se você usar a saída do detector para sobrepor elementos gráficos a imagem de entrada, primeiro acesse o resultado do Kit de ML e, em seguida, renderize a imagem e sobreposição em uma única etapa. Ao fazer isso, você renderiza a superfície de exibição apenas uma vez para cada frame de entrada processado. Veja a classe updatePreviewOverlayViewWithLastFrame na amostra do guia de início rápido do Kit de ML.