Вы можете использовать ML Kit для обнаружения лиц на изображениях и видео.
| Функция | Без пакета | Пакетный |
|---|---|---|
| Реализация | Модель динамически скачивается через сервисы Google Play. | Модель статически связана с приложением во время сборки. |
| Размер приложения | Размер увеличивается примерно на 800 КБ. | Размер увеличится примерно на 6,9 МБ. |
| Время инициализации | Перед первым использованием может потребоваться дождаться скачивания модели. | Модель доступна сразу |
Попробовать
- Попробуйте поработать с примером приложения, чтобы понять, как использовать этот API.
- Попробуйте написать код самостоятельно, используя практическую работу.
Подготовка
В файле
build.gradleна уровне проекта добавьте репозиторий Maven от Google в разделыbuildscriptиallprojects.Добавьте зависимости для библиотек ML Kit для Android в файл Gradle на уровне приложения, который обычно называется
app/build.gradle. Выберите одну из следующих зависимостей в соответствии со своими потребностями:Если вы хотите встроить модель в приложение:
dependencies { // ... // Use this dependency to bundle the model with your app implementation 'com.google.mlkit:face-detection:16.1.7' }Для использования модели в сервисах Google Play:
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' }Если вы решите использовать модель в сервисах Google Play, то можете настроить приложение так, чтобы оно автоматически скачивало модель на устройство после установки из Google Play. Для этого добавьте в файл
AndroidManifest.xmlприложения следующую декларацию:<application ...> ... <meta-data android:name="com.google.mlkit.vision.DEPENDENCIES" android:value="face" > <!-- To use multiple models: android:value="face,model2,model3" --> </application>Вы также можете проверить доступность модели и запросить ее скачивание через ModuleInstallClient API сервисов Google Play.
Если вы не включите скачивание модели во время установки или не запросите явное скачивание, модель будет скачана при первом запуске детектора. Запросы, сделанные до завершения скачивания, не принесут результатов.
Требования к исходным изображениям
Для распознавания лиц используйте изображение размером не менее 480 x 360 пикселей. Чтобы ML Kit мог точно обнаруживать лица, входные изображения должны содержать лица, представленные достаточным количеством пиксельных данных. В целом, каждое лицо, которое вы хотите обнаружить на изображении, должно быть не менее 100x100 пикселей. Если вы хотите распознавать контуры лиц, ML Kit требуется более высокое разрешение: каждое лицо должно быть не менее 200x200 пикселей.
Если вы распознаете лица в приложении, работающем в реальном времени, вам также может потребоваться учитывать общие размеры входных изображений. Изображения меньшего размера обрабатываются быстрее, поэтому для уменьшения задержки делайте снимки с более низким разрешением, но помните о приведенных выше требованиях к точности и следите за тем, чтобы лицо объекта занимало как можно большую часть изображения. Также ознакомьтесь с советами по повышению эффективности в реальном времени.
Плохая фокусировка изображения также может повлиять на точность. Если вы не получите приемлемых результатов, попросите пользователя сделать снимок заново.
Ориентация лица относительно камеры также может повлиять на то, какие черты лица обнаруживает ML Kit. Подробнее о распознавании лиц…
1. Настройте детектор лиц.
Если вы хотите изменить настройки распознавания лиц по умолчанию, задайте их с помощью объектаFaceDetectorOptions.
Укажите следующие параметры:
| Настройки | |
|---|---|
setPerformanceMode
|
PERFORMANCE_MODE_FAST (по умолчанию)
|
PERFORMANCE_MODE_ACCURATE
Выберите, что важнее при распознавании лиц: скорость или точность. |
setLandmarkMode
|
LANDMARK_MODE_NONE (по умолчанию)
|
LANDMARK_MODE_ALL
Определяет, нужно ли пытаться распознать "ориентиры" на лице: глаза, уши, нос, щеки, рот и т. д. |
setContourMode
|
CONTOUR_MODE_NONE (по умолчанию)
|
CONTOUR_MODE_ALL
Определять ли контуры черт лица. Контуры определяются только для самого заметного лица на изображении. |
setClassificationMode
|
CLASSIFICATION_MODE_NONE (по умолчанию)
|
CLASSIFICATION_MODE_ALL
Определяет, нужно ли классифицировать лица по категориям, например "улыбается" и "глаза открыты". |
setMinFaceSize
|
float (по умолчанию: 0.1f)
Задает наименьший желаемый размер лица, выраженный как отношение ширины головы к ширине изображения. |
enableTracking
|
false (по умолчанию) | true
Нужно ли присваивать лицам идентификаторы, которые можно использовать для отслеживания лиц на изображениях. Обратите внимание, что при включенном распознавании контуров обнаруживается только одно лицо, поэтому отслеживание лиц не дает полезных результатов. По этой причине, а также для повышения скорости обнаружения не включайте одновременно обнаружение контуров и отслеживание лиц. |
Пример:
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. Подготовьте входное изображение
Чтобы распознать лица на изображении, создайте объектInputImage из Bitmap, media.Image, ByteBuffer, массива байтов или файла на устройстве. Затем передайте объект InputImage методу process объекта FaceDetector.
Для распознавания лиц следует использовать изображение размером не менее 480 x 360 пикселей. Если вы распознаете лица в реальном времени, захват кадров с таким минимальным разрешением поможет уменьшить задержку.
Объект InputImage можно создать из разных источников, каждый из которых описан ниже.
Использование media.Image
Чтобы создать объект InputImage из объекта media.Image, например при съемке изображения с помощью камеры устройства, передайте объект media.Image и поворот изображения в InputImage.fromMediaImage().
Если вы используете библиотеку
CameraX, классы OnImageCapturedListener и ImageAnalysis.Analyzer рассчитают значение поворота за вас.
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 // ... } } }
Если вы не используете библиотеку камеры, которая предоставляет угол поворота изображения, вы можете рассчитать его на основе угла поворота устройства и ориентации датчика камеры в устройстве:
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; }
Затем передайте объект media.Image и значение угла поворота в InputImage.fromMediaImage():
Kotlin
val image = InputImage.fromMediaImage(mediaImage, rotation)
Java
InputImage image = InputImage.fromMediaImage(mediaImage, rotation);
Использование URI файла
Чтобы создать объект InputImage из URI файла, передайте контекст приложения и URI файла в InputImage.fromFilePath(). Это полезно, когда вы используете намерение ACTION_GET_CONTENT, чтобы предложить пользователю выбрать изображение из галереи.
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(); }
Использование ByteBuffer или ByteArray
Чтобы создать объект InputImage из ByteBuffer или ByteArray, сначала рассчитайте угол поворота изображения, как описано выше для входных данных media.Image.
Затем создайте объект InputImage с буфером или массивом, а также высотой, шириной, форматом кодирования цвета и углом поворота изображения:
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 );
Использование Bitmap
Чтобы создать объект InputImage из объекта Bitmap, добавьте следующий код:
Kotlin
val image = InputImage.fromBitmap(bitmap, 0)
Java
InputImage image = InputImage.fromBitmap(bitmap, rotationDegree);
Изображение представлено объектом Bitmap и углом поворота.
3. Получите экземпляр 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. Обработка изображения
Передайте изображение в методprocess:
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. Получение информации о распознанных лицах
Если распознавание лиц выполнено успешно, список объектовFace передается в прослушиватель успешного выполнения. Каждый объект Face представляет лицо, обнаруженное на изображении. Для каждого лица вы можете получить его ограничивающие координаты на входном изображении, а также любую другую информацию, которую вы настроили для детектора лиц. Пример:
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(); } }
Пример контуров лица
Если включено распознавание контуров лица, вы получите список точек для каждой обнаруженной черты лица. Эти точки определяют форму объекта. Подробные сведения о том, как представлены контуры, можно найти в статье Основные понятия, связанные с распознаванием лиц.
На изображении ниже показано, как эти точки соотносятся с лицом. Нажмите на изображение, чтобы увеличить его.
Распознавание лиц в реальном времени
Если вы хотите использовать распознавание лиц в приложении, работающем в реальном времени, следуйте этим рекомендациям, чтобы добиться наилучшей частоты кадров:
Настройте детектор лиц на использование либо обнаружения контуров лица, либо классификации и обнаружения ориентиров, но не того и другого:
Распознавание контуров
Распознавание ориентиров
Классификация
Распознавание ориентиров и классификация
Распознавание контуров и ориентиров
Распознавание контуров и классификация
Распознавание контуров и ориентиров, а также классификацияВключите режим
FAST(включен по умолчанию).Попробуйте сделать снимки с более низким разрешением. Однако также учитывайте требования этого API к размерам изображений.
Camera или camera2, ограничьте вызовы детектора. Если во время работы детектора становится доступен новый кадр видео, отбросьте его. Пример можно найти в классе
VisionProcessorBase в примере приложения из краткого руководства.
CameraX, убедитесь, что для стратегии противодавления задано значение по умолчанию
ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST.
Это гарантирует, что для анализа будет отправляться только одно изображение за раз. Если во время работы анализатора будут созданы дополнительные изображения, они будут автоматически удалены и не будут поставлены в очередь на доставку. После того как анализируемое изображение будет закрыто вызовом ImageProxy.close(), будет доставлено следующее последнее изображение.
CameraSourcePreview и
GraphicOverlay в примере приложения из краткого руководства.
ImageFormat.YUV_420_888. Если вы используете старый Camera API, делайте снимки в формате ImageFormat.NV21.