Você pode usar o Kit de ML para detectar rostos em imagens e vídeos.
Recurso | Desagrupado | Agrupadas |
---|---|---|
Implementação | O download do modelo é feito dinamicamente pelo Google Play Services. | O modelo é vinculado estaticamente ao app no tempo de build. |
Tamanho do app | Aumento de cerca de 800 KB. | Aumento de tamanho de aproximadamente 6,9 MB. |
Tempo de inicialização | Talvez seja necessário aguardar o download do modelo para usar o modelo pela primeira vez. | O modelo está disponível imediatamente |
Faça um teste
- Teste o app de exemplo para um exemplo de uso dessa API.
- Experimente o código com a codelab.
Antes de começar
No arquivo
build.gradle
no nível do projeto, inclua a propriedade repositório Maven nas seçõesbuildscript
eallprojects
.Adicione as dependências das bibliotecas do Android do Kit de ML ao arquivo arquivo do Gradle no nível do app, que geralmente é
app/build.gradle
. Escolha uma destas opções: as seguintes dependências com base nas suas necessidades:Para agrupar o modelo e 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 que o app faça o download automático do modelo no dispositivo após instalado pela Play Store. Para isso, adicione a seguinte declaração ao arquivo arquivo
AndroidManifest.xml
do seu 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 pelo API ModuleInstallClient do Google Play Services.
Se você não ativar os downloads do modelo de tempo de instalação ou solicitar o download explícito, o modelo é transferido por download na primeira vez que você executa o detector. Solicitações feitas por você antes da conclusão do download não produzem resultados.
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 ao usuário para 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 ObjetoFaceDetectorOptions
.
Você pode alterar as seguintes configurações:
Configurações | |
---|---|
setPerformanceMode
|
PERFORMANCE_MODE_FAST (padrão)
|
PERFORMANCE_MODE_ACCURATE
Favoreça a velocidade ou a precisão ao detectar rostos. |
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 das características faciais. Contornos são detectado apenas no rosto mais proeminente da imagem. |
setClassificationMode
|
CLASSIFICATION_MODE_NONE (padrão)
|
CLASSIFICATION_MODE_ALL
Se é necessário classificar rostos em categorias como "sorrindo", e "de olhos abertos". |
setMinFaceSize
|
float (padrão: 0.1f )
Define o menor tamanho facial desejado, expresso como a proporção do largura da cabeça com a largura da imagem. |
enableTracking
|
false (padrão) | true
Se deve ou não 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. |
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
de uma matriz de bytes Bitmap
, media.Image
, ByteBuffer
, ou um arquivo na
o dispositivo. Em seguida, transmita o objeto InputImage
para a
Método process
de FaceDetector
.
Para a detecção facial, você deve usar uma imagem com dimensões de pelo menos 480x360 pixels. Se você detectar rostos em tempo real, capturar frames nessa resolução mínima pode ajudar a reduzir a latência.
Você pode criar um InputImage
de diferentes origens, cada uma explicada abaixo.
Como usar um media.Image
Para criar um InputImage
de um objeto media.Image
, como quando você captura uma imagem de um
da câmera do dispositivo, transmita o objeto media.Image
e o
rotação para InputImage.fromMediaImage()
.
Se você usar o método
CameraX, os recursos OnImageCapturedListener
e
As classes ImageAnalysis.Analyzer
calculam o valor de rotação
para você.
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 informe o grau de rotação da imagem, pode calculá-lo usando o grau de rotação do dispositivo e a orientação da câmera no dispositivo:
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
grau de rotação para InputImage.fromMediaImage()
:
Kotlin
val image = InputImage.fromMediaImage(mediaImage, rotation)
Java
InputImage image = InputImage.fromMediaImage(mediaImage, rotation);
Usar um URI de arquivo
Para criar um InputImage
de um URI de arquivo, transmita o contexto do aplicativo e o URI do arquivo para
InputImage.fromFilePath()
. Isso é útil quando você
usar uma intent ACTION_GET_CONTENT
para solicitar que o usuário selecione
uma imagem do app Galeria.
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 ByteBuffer
ou ByteArray
Para criar um InputImage
objeto de uma ByteBuffer
ou ByteArray
, primeiro calcule a imagem
grau de rotação conforme descrito anteriormente para a entrada media.Image
.
Depois, crie o objeto InputImage
com o buffer ou a matriz, junto com o
altura, largura, formato de codificação de cores e grau de rotação:
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 InputImage
de 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. Receber 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, será exibida ObjetosFace
são transmitidos para a instância bem-sucedida
ouvinte. Cada objeto Face
representa um rosto detectado
na imagem. É possível receber as coordenadas delimitadoras de cada rosto na entrada
imagem, bem como qualquer outra informação para a qual você configurou o detector facial
encontrar. 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 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:
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çãoAtive 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.
Camera
ou
API camera2
,
limitar chamadas ao detector. Se um novo vídeo
fica disponível enquanto o detector está em execução, descarte esse frame. Consulte a
VisionProcessorBase
no app de amostra do guia de início rápido para conferir um exemplo.
CameraX
,
verificar se a estratégia de pressão de retorno está definida para o valor padrão
ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST
.
Isso garante que apenas uma imagem será 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
entrega. Depois que a imagem analisada é fechada, chamando
ImageProxy.close(), a próxima imagem mais recente será entregue.
CameraSourcePreview
e
GraphicOverlay
no app de amostra 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
ImageFormat.NV21
.