Catch up on everything announced at Firebase Summit, and learn how Firebase can help you accelerate app development and run your app with confidence. Learn More

Detectar rostos com o kit de ML no iOS

Mantenha tudo organizado com as coleções Salve e categorize o conteúdo com base nas suas preferências.

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

Antes de você começar

  1. Se você ainda não adicionou o Firebase ao seu aplicativo, faça isso seguindo as etapas do guia de primeiros passos .
  2. Inclua as bibliotecas do ML Kit em seu 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'
    
    Depois de instalar ou atualizar os Pods do seu projeto, certifique-se de abrir seu projeto Xcode usando seu .xcworkspace .
  3. No seu aplicativo, importe o Firebase:

    Rápido

    import Firebase

    Objetivo-C

    @import Firebase;

Diretrizes de imagem de entrada

Para que o ML Kit detecte rostos com precisão, as imagens de entrada devem conter rostos representados por dados de pixel suficientes. Em geral, cada rosto que você deseja detectar em uma imagem deve ter pelo menos 100x100 pixels. Se você deseja detectar os contornos dos rostos, o ML Kit requer uma entrada de resolução mais alta: cada rosto deve ter pelo menos 200x200 pixels.

Se você estiver detectando rostos em um aplicativo em tempo real, também poderá considerar as dimensões gerais das imagens de entrada. Imagens menores podem ser processadas mais rapidamente, portanto, para reduzir a latência, capture imagens em resoluções mais baixas (tendo em mente os requisitos de precisão acima) e assegure-se de que o rosto do sujeito ocupe o máximo possível da imagem. Consulte também Dicas para melhorar o desempenho em tempo real .

O foco de imagem ruim pode prejudicar a precisão. Se você não estiver obtendo resultados aceitáveis, tente pedir ao usuário para recapturar a imagem.

A orientação de um rosto em relação à câmera também pode afetar quais recursos faciais o ML Kit detecta. Consulte Conceitos de detecção de rosto .

1. Configure o detector de rosto

Antes de aplicar a detecção de rosto a uma imagem, se quiser alterar qualquer uma das configurações padrão do detector de rosto, especifique essas configurações com um objeto VisionFaceDetectorOptions . Você pode alterar as seguintes configurações:

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

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

landmarkMode none (padrão) | all

Se deve tentar detectar os "pontos de referência" faciais - olhos, ouvidos, nariz, bochechas, boca - de todos os rostos detectados.

contourMode none (padrão) | all

Seja para detectar os contornos das características faciais. Os contornos são detectados apenas para o rosto mais proeminente em uma imagem.

classificationMode none (padrão) | all

Se deve ou não classificar os rostos em categorias como "sorrindo" e "olhos abertos".

minFaceSize CGFloat (padrão: 0.1 )

O tamanho mínimo, em relação à imagem, dos rostos a serem detectados.

isTrackingEnabled false (padrão) | true

Se deve ou não atribuir um ID aos rostos, que pode ser usado para rastrear rostos em imagens.

Observe que quando a detecção de contorno está habilitada, apenas um rosto é detectado, portanto, o rastreamento de rosto não produz resultados úteis. Por esse motivo, e para melhorar a velocidade de detecção, não ative a detecção de contorno e o rastreamento de rosto.

Por exemplo, crie um objeto VisionFaceDetectorOptions como um dos exemplos a seguir:

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

Objetivo-C

// 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. Execute o detector de rosto

Para detectar rostos em uma imagem, passe a imagem como UIImage ou CMSampleBufferRef para o método detect(in:) do VisionFaceDetector :

  1. Obtenha uma instância de VisionFaceDetector :

    Rápido

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

    Objetivo-C

    FIRVision *vision = [FIRVision vision];
    FIRVisionFaceDetector *faceDetector = [vision faceDetector];
    // Or, to change the default settings:
    // FIRVisionFaceDetector *faceDetector =
    //     [vision faceDetectorWithOptions:options];
    
  2. Crie um objeto VisionImage usando um UIImage ou um CMSampleBufferRef .

    Para usar uma UIImage :

    1. Se necessário, gire a imagem para que sua propriedade imageOrientation seja .up .
    2. Crie um objeto VisionImage usando o UIImage girado corretamente. Não especifique nenhum metadados de rotação — o valor padrão, .topLeft , deve ser usado.

      Rápido

      let image = VisionImage(image: uiImage)

      Objetivo-C

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

    Para usar um CMSampleBufferRef :

    1. Crie um objeto VisionImageMetadata que especifica a orientação dos dados de imagem contidos no buffer CMSampleBufferRef .

      Para obter a orientação da imagem:

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

      Objetivo-C

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

      Em seguida, crie o objeto de metadados:

      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
      )

      Objetivo-C

      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. Crie um objeto VisionImage usando o objeto CMSampleBufferRef e os metadados de rotação:

      Rápido

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

      Objetivo-C

      FIRVisionImage *image = [[FIRVisionImage alloc] initWithBuffer:sampleBuffer];
      image.metadata = metadata;
  3. Em seguida, passe a imagem para o método detect(in:) :

    Rápido

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

    Objetivo-C

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

3. Obtenha informações sobre rostos detectados

Se a operação de detecção de rosto for bem-sucedida, o detector de rosto passará uma matriz de objetos VisionFace para o manipulador de conclusão. Cada objeto VisionFace representa um rosto que foi detectado na imagem. Para cada face, você pode obter suas coordenadas delimitadoras na imagem de entrada, bem como qualquer outra informação que você configurou para encontrar o detector de face. Por exemplo:

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

Objetivo-C

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

Exemplo de contornos de rosto

Quando a detecção de contorno facial está ativada, você obtém uma lista de pontos para cada recurso facial detectado. Esses pontos representam a forma do recurso. Consulte a Visão geral dos conceitos de detecção de rosto para obter detalhes sobre como os contornos são representados.

A imagem a seguir ilustra como esses pontos são mapeados para um rosto (clique na imagem para ampliar):

Detecção de rosto em tempo real

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

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

    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).

  • Considere capturar imagens em uma resolução mais baixa. No entanto, lembre-se também dos requisitos de dimensão de imagem desta API.

  • Acelere as chamadas para o detector. Se um novo quadro de vídeo ficar disponível enquanto o detector estiver em execução, descarte o quadro.
  • Se você estiver usando a saída do detector para sobrepor gráficos na imagem de entrada, primeiro obtenha o resultado do ML Kit e, em seguida, renderize a imagem e a sobreposição em uma única etapa. Ao fazer isso, você renderiza para a superfície de exibição apenas uma vez para cada quadro de entrada. Consulte as classes previewOverlayView e FIRDetectionOverlayView no aplicativo de amostra de demonstração para obter um exemplo.