Use o Kit de ML para detectar rostos em imagens e vídeos.
Recurso | Não agrupado | Agrupadas |
---|---|---|
Implementação | O modelo é baixado dinamicamente pelo Google Play Services. | O modelo é vinculado de forma estática ao app no momento da criação. |
Tamanho do app | Aumento de cerca de 800 KB. | Aumento de cerca de 6,9 MB. |
Tempo de inicialização | Talvez seja necessário esperar o download do modelo antes do primeiro uso. | O modelo está disponível imediatamente |
Faça um teste
- Teste o app de exemplo para conferir um exemplo de uso dessa API.
- Teste o código com o codelab.
Antes de começar
No arquivo
build.gradle
no nível do projeto, inclua o repositório Maven do Google nas seçõesbuildscript
eallprojects
.Adicione as dependências das bibliotecas do Android do Kit de ML ao arquivo Gradle no nível do app do módulo, que geralmente é
app/build.gradle
. Escolha uma das dependências a seguir com base nas suas necessidades:Para agrupar o modelo com o app:
dependencies { // ... // Use this dependency to bundle the model with your app implementation 'com.google.mlkit:face-detection:16.1.7' }
Para usar o modelo no Google Play Services:
dependencies { // ... // Use this dependency to use the dynamically downloaded model in Google Play Services implementation 'com.google.android.gms:play-services-mlkit-face-detection:17.1.0' }
Se você optar por usar o modelo no Google Play Services, poderá configurar seu app para fazer o download automático do modelo no dispositivo depois que ele for instalado na Play Store. Para fazer isso, adicione a declaração abaixo ao arquivo
AndroidManifest.xml
do app:<application ...> ... <meta-data android:name="com.google.mlkit.vision.DEPENDENCIES" android:value="face" > <!-- To use multiple models: android:value="face,model2,model3" --> </application>
Também é possível verificar explicitamente a disponibilidade do modelo e solicitar o download pela API ModuleInstallClient do Google Play Services.
Se você não ativar os downloads do modelo no momento da instalação ou solicitar um download explícito, o modelo será transferido na primeira vez em que você executar o detector. As solicitações feitas antes da conclusão do download não produzem resultados.
Diretrizes de imagens de entrada
Para reconhecimento facial, use 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ê quiser detectar em uma imagem precisa ter pelo menos 100x100 pixels. Se você quiser detectar os contornos dos rostos, o Kit de ML precisará de uma entrada de resolução mais alta: cada rosto deverá ter pelo menos 200x200 pixels.
Se você detectar rostos em um aplicativo em tempo real, considere as dimensões gerais das imagens de entrada. Já que as imagens menores podem ser processadas mais rapidamente, reduza a latência capturando imagens em resoluções menores, mas lembre-se dos requisitos de precisão acima e faça o rosto da pessoa ocupar 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. Se os resultados não forem aceitáveis, peça para o usuário recapturar a imagem.
A orientação de um rosto em relação à câmera também pode afetar os atributos faciais 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 quiser mudar as configurações padrão do detector, especifique essas configurações com um objetoFaceDetectorOptions
.
É possível mudar as seguintes configurações:
Configurações | |
---|---|
setPerformanceMode
|
PERFORMANCE_MODE_FAST (padrão)
|
PERFORMANCE_MODE_ACCURATE
Favoreça a velocidade ou a precisão durante a detecção facial. |
setLandmarkMode
|
LANDMARK_MODE_NONE (padrão)
|
LANDMARK_MODE_ALL
Para tentar identificar "pontos de referência" faciais: olhos, orelhas, nariz, bochechas, boca e assim por diante. |
setContourMode
|
CONTOUR_MODE_NONE (padrão)
|
CONTOUR_MODE_ALL
Para detectar os contornos dos atributos faciais. São detectados apenas os contornos do rosto mais proeminente de uma imagem. |
setClassificationMode
|
CLASSIFICATION_MODE_NONE (padrão)
|
CLASSIFICATION_MODE_ALL
Se é necessário classificar faces em categorias como "sorrindo" e "olhos abertos". |
setMinFaceSize
|
float (padrão: 0.1f )
Define o menor tamanho de rosto desejado, expresso como a proporção da largura da cabeça em relação à largura da imagem. |
enableTracking
|
false (padrão) | true
Atribuir ou não IDs, que podem ser usados para rastrear rostos em imagens. Quando a detecção de contorno está ativada, apenas um rosto é detectado, portanto, o rastreamento facial não produz resultados úteis. Por esse motivo, e para melhorar a velocidade de detecção, não ative a detecção de contorno simultaneamente com o rastreamento facial. |
Exemplo:
Kotlin
// High-accuracy landmark detection and face classification val highAccuracyOpts = FaceDetectorOptions.Builder() .setPerformanceMode(FaceDetectorOptions.PERFORMANCE_MODE_ACCURATE) .setLandmarkMode(FaceDetectorOptions.LANDMARK_MODE_ALL) .setClassificationMode(FaceDetectorOptions.CLASSIFICATION_MODE_ALL) .build() // Real-time contour detection val realTimeOpts = FaceDetectorOptions.Builder() .setContourMode(FaceDetectorOptions.CONTOUR_MODE_ALL) .build()
Java
// High-accuracy landmark detection and face classification FaceDetectorOptions highAccuracyOpts = new FaceDetectorOptions.Builder() .setPerformanceMode(FaceDetectorOptions.PERFORMANCE_MODE_ACCURATE) .setLandmarkMode(FaceDetectorOptions.LANDMARK_MODE_ALL) .setClassificationMode(FaceDetectorOptions.CLASSIFICATION_MODE_ALL) .build(); // Real-time contour detection FaceDetectorOptions realTimeOpts = new FaceDetectorOptions.Builder() .setContourMode(FaceDetectorOptions.CONTOUR_MODE_ALL) .build();
2. Preparar a imagem de entrada
Para detectar rostos em uma imagem, crie um objetoInputImage
usando Bitmap
, media.Image
, ByteBuffer
, matriz de bytes ou um arquivo no
dispositivo. Em seguida, transmita o objeto InputImage
para o
método process
do FaceDetector
.
Para detecção facial, use uma imagem com dimensões de pelo menos 480x360 pixels. Se você estiver detectando rostos em tempo real, a captura de frames com essa resolução mínima poderá ajudar a reduzir a latência.
É possível criar um objeto InputImage
de diferentes origens. Cada uma é explicada abaixo.
Como usar um media.Image
Para criar um objeto InputImage
usando um objeto media.Image
, como quando você captura uma imagem da
câmera de um dispositivo, transmita o objeto media.Image
e a rotação
da imagem para InputImage.fromMediaImage()
.
Se você usar a biblioteca
CameraX, as classes OnImageCapturedListener
e
ImageAnalysis.Analyzer
vão calcular o valor de rotação
automaticamente.
Kotlin
private class YourImageAnalyzer : ImageAnalysis.Analyzer { override fun analyze(imageProxy: ImageProxy) { val mediaImage = imageProxy.image if (mediaImage != null) { val image = InputImage.fromMediaImage(mediaImage, imageProxy.imageInfo.rotationDegrees) // Pass image to an ML Kit Vision API // ... } } }
Java
private class YourAnalyzer implements ImageAnalysis.Analyzer { @Override public void analyze(ImageProxy imageProxy) { Image mediaImage = imageProxy.getImage(); if (mediaImage != null) { InputImage image = InputImage.fromMediaImage(mediaImage, imageProxy.getImageInfo().getRotationDegrees()); // Pass image to an ML Kit Vision API // ... } } }
Se você não usar uma biblioteca de câmera que ofereça o grau de rotação da imagem, será possível calcular usando o grau de rotação do dispositivo e a orientação do sensor da câmera:
Kotlin
private val ORIENTATIONS = SparseIntArray() init { ORIENTATIONS.append(Surface.ROTATION_0, 0) ORIENTATIONS.append(Surface.ROTATION_90, 90) ORIENTATIONS.append(Surface.ROTATION_180, 180) ORIENTATIONS.append(Surface.ROTATION_270, 270) } /** * Get the angle by which an image must be rotated given the device's current * orientation. */ @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) @Throws(CameraAccessException::class) private fun getRotationCompensation(cameraId: String, activity: Activity, isFrontFacing: Boolean): Int { // Get the device's current rotation relative to its "native" orientation. // Then, from the ORIENTATIONS table, look up the angle the image must be // rotated to compensate for the device's rotation. val deviceRotation = activity.windowManager.defaultDisplay.rotation var rotationCompensation = ORIENTATIONS.get(deviceRotation) // Get the device's sensor orientation. val cameraManager = activity.getSystemService(CAMERA_SERVICE) as CameraManager val sensorOrientation = cameraManager .getCameraCharacteristics(cameraId) .get(CameraCharacteristics.SENSOR_ORIENTATION)!! if (isFrontFacing) { rotationCompensation = (sensorOrientation + rotationCompensation) % 360 } else { // back-facing rotationCompensation = (sensorOrientation - rotationCompensation + 360) % 360 } return rotationCompensation }
Java
private static final SparseIntArray ORIENTATIONS = new SparseIntArray(); static { ORIENTATIONS.append(Surface.ROTATION_0, 0); ORIENTATIONS.append(Surface.ROTATION_90, 90); ORIENTATIONS.append(Surface.ROTATION_180, 180); ORIENTATIONS.append(Surface.ROTATION_270, 270); } /** * Get the angle by which an image must be rotated given the device's current * orientation. */ @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) private int getRotationCompensation(String cameraId, Activity activity, boolean isFrontFacing) throws CameraAccessException { // Get the device's current rotation relative to its "native" orientation. // Then, from the ORIENTATIONS table, look up the angle the image must be // rotated to compensate for the device's rotation. int deviceRotation = activity.getWindowManager().getDefaultDisplay().getRotation(); int rotationCompensation = ORIENTATIONS.get(deviceRotation); // Get the device's sensor orientation. CameraManager cameraManager = (CameraManager) activity.getSystemService(CAMERA_SERVICE); int sensorOrientation = cameraManager .getCameraCharacteristics(cameraId) .get(CameraCharacteristics.SENSOR_ORIENTATION); if (isFrontFacing) { rotationCompensation = (sensorOrientation + rotationCompensation) % 360; } else { // back-facing rotationCompensation = (sensorOrientation - rotationCompensation + 360) % 360; } return rotationCompensation; }
Em seguida, transmita o objeto media.Image
e o
valor do grau de rotação para InputImage.fromMediaImage()
:
Kotlin
val image = InputImage.fromMediaImage(mediaImage, rotation)
Java
InputImage image = InputImage.fromMediaImage(mediaImage, rotation);
Como usar um URI de arquivo
Para criar um objeto InputImage
usando o URI de um arquivo, transmita o contexto do app e o URI do arquivo para
InputImage.fromFilePath()
. Isso é útil ao usar
uma intent ACTION_GET_CONTENT
para solicitar que o usuário selecione
uma imagem no app de galeria dele.
Kotlin
val image: InputImage try { image = InputImage.fromFilePath(context, uri) } catch (e: IOException) { e.printStackTrace() }
Java
InputImage image; try { image = InputImage.fromFilePath(context, uri); } catch (IOException e) { e.printStackTrace(); }
Como usar um ByteBuffer
ou ByteArray
Para criar um objeto InputImage
usando um ByteBuffer
ou um ByteArray
, primeiro calcule o grau de rotação da imagem
conforme descrito anteriormente para a entrada de media.Image
.
Em seguida, crie o objeto InputImage
com o buffer ou a matriz, com a altura,
a largura, o formato de codificação de cores e o grau de rotação da imagem:
Kotlin
val image = InputImage.fromByteBuffer( byteBuffer, /* image width */ 480, /* image height */ 360, rotationDegrees, InputImage.IMAGE_FORMAT_NV21 // or IMAGE_FORMAT_YV12 ) // Or: val image = InputImage.fromByteArray( byteArray, /* image width */ 480, /* image height */ 360, rotationDegrees, InputImage.IMAGE_FORMAT_NV21 // or IMAGE_FORMAT_YV12 )
Java
InputImage image = InputImage.fromByteBuffer(byteBuffer, /* image width */ 480, /* image height */ 360, rotationDegrees, InputImage.IMAGE_FORMAT_NV21 // or IMAGE_FORMAT_YV12 ); // Or: InputImage image = InputImage.fromByteArray( byteArray, /* image width */480, /* image height */360, rotation, InputImage.IMAGE_FORMAT_NV21 // or IMAGE_FORMAT_YV12 );
Como usar um Bitmap
Para criar um objeto InputImage
usando um objeto Bitmap
, faça a seguinte declaração:
Kotlin
val image = InputImage.fromBitmap(bitmap, 0)
Java
InputImage image = InputImage.fromBitmap(bitmap, rotationDegree);
A imagem é representada por um objeto Bitmap
com os graus de rotação.
3. Crie uma instância do FaceDetector
Kotlin
val detector = FaceDetection.getClient(options) // Or, to use the default option: // val detector = FaceDetection.getClient();
Java
FaceDetector detector = FaceDetection.getClient(options); // Or use the default options: // FaceDetector detector = FaceDetection.getClient();
4. Processar a imagem
Transmita a imagem para o métodoprocess
:
Kotlin
val result = detector.process(image) .addOnSuccessListener { faces -> // Task completed successfully // ... } .addOnFailureListener { e -> // Task failed with an exception // ... }
Java
Task<List<Face>> result = detector.process(image) .addOnSuccessListener( new OnSuccessListener<List<Face>>() { @Override public void onSuccess(List<Face> faces) { // Task completed successfully // ... } }) .addOnFailureListener( new OnFailureListener() { @Override public void onFailure(@NonNull Exception e) { // Task failed with an exception // ... } });
5. Receber informações sobre rostos detectados
Se a operação de detecção facial for bem-sucedida, uma lista de objetosFace
será transmitida para o listener de
êxito. Cada objeto Face
representa um rosto detectado
na imagem. Para cada rosto, é possível receber as coordenadas delimitadoras na imagem de
entrada, além de qualquer outra informação que você tenha configurado para detecção. Exemplo:
Kotlin
for (face in faces) { val bounds = face.boundingBox val rotY = face.headEulerAngleY // Head is rotated to the right rotY degrees val rotZ = face.headEulerAngleZ // Head is tilted sideways rotZ degrees // If landmark detection was enabled (mouth, ears, eyes, cheeks, and // nose available): val leftEar = face.getLandmark(FaceLandmark.LEFT_EAR) leftEar?.let { val leftEarPos = leftEar.position } // If contour detection was enabled: val leftEyeContour = face.getContour(FaceContour.LEFT_EYE)?.points val upperLipBottomContour = face.getContour(FaceContour.UPPER_LIP_BOTTOM)?.points // If classification was enabled: if (face.smilingProbability != null) { val smileProb = face.smilingProbability } if (face.rightEyeOpenProbability != null) { val rightEyeOpenProb = face.rightEyeOpenProbability } // If face tracking was enabled: if (face.trackingId != null) { val id = face.trackingId } }
Java
for (Face face : faces) { Rect bounds = face.getBoundingBox(); float rotY = face.getHeadEulerAngleY(); // Head is rotated to the right rotY degrees float rotZ = face.getHeadEulerAngleZ(); // Head is tilted sideways rotZ degrees // If landmark detection was enabled (mouth, ears, eyes, cheeks, and // nose available): FaceLandmark leftEar = face.getLandmark(FaceLandmark.LEFT_EAR); if (leftEar != null) { PointF leftEarPos = leftEar.getPosition(); } // If contour detection was enabled: List<PointF> leftEyeContour = face.getContour(FaceContour.LEFT_EYE).getPoints(); List<PointF> upperLipBottomContour = face.getContour(FaceContour.UPPER_LIP_BOTTOM).getPoints(); // If classification was enabled: if (face.getSmilingProbability() != null) { float smileProb = face.getSmilingProbability(); } if (face.getRightEyeOpenProbability() != null) { float rightEyeOpenProb = face.getRightEyeOpenProbability(); } // If face tracking was enabled: if (face.getTrackingId() != null) { int id = face.getTrackingId(); } }
Exemplo de contornos faciais
Quando a detecção de contorno facial está ativada, você recebe uma lista de pontos para cada traço facial detectado. Esses pontos representam a forma do elemento. Consulte Conceitos de detecção facial para saber como os contornos são representados.
A imagem a seguir ilustra como esses pontos mapeiam um rosto. Clique na imagem para ampliar:
Detecção facial em tempo real
Se você quiser usar a detecção facial em um aplicativo em tempo real, siga estas diretrizes para conseguir as melhores taxas de frames:
Configure o detector facial para usar a detecção de contorno facial ou a classificação e a 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 contornos e detecção de pontos de referência
Detecção e classificação de contornos
Detecção de contornos, detecção de pontos de referência e classificaçãoAtive o modo
FAST
(ativado por padrão).Capture imagens em uma resolução menor. No entanto, lembre-se também dos requisitos de dimensão de imagem da API.
Camera
ou
camera2
,
limite as chamadas para o detector. Se um novo frame de vídeo
ficar disponível durante a execução do detector, descarte esse frame. Consulte a classe
VisionProcessorBase
no app de exemplo do guia de início rápido para conferir um exemplo.
CameraX
,
verifique se a estratégia de backpressure está definida como o valor padrão
ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST
.
Isso garante que apenas uma imagem seja enviada para análise por vez. Se mais imagens forem
produzidas quando o analisador estiver ocupado, elas serão descartadas automaticamente e não serão enfileiradas para
envio. Quando a imagem que está sendo analisada é fechada chamando
ImageProxy.close(), a próxima imagem mais recente é entregue.
CameraSourcePreview
e
GraphicOverlay
no app de exemplo do guia de início rápido para conferir um exemplo.
ImageFormat.YUV_420_888
. Se você usar a API Camera mais antiga, capture imagens no
formato ImageFormat.NV21
.