Bạn có thể dùng Bộ công cụ máy học để phát hiện khuôn mặt trong hình ảnh và video.
Tính năng | Không nhóm | Gộp chung |
---|---|---|
Triển khai | Mô hình được tải xuống động thông qua Dịch vụ Google Play. | Mô hình được liên kết tĩnh với ứng dụng tại thời điểm xây dựng. |
Kích thước ứng dụng | Mức tăng kích thước khoảng 800 KB. | Dung lượng tăng khoảng 6,9 MB. |
Thời gian khởi chạy | Có thể phải đợi mô hình tải xuống trước khi sử dụng lần đầu. | Mô hình có sẵn ngay lập tức |
Dùng thử
- Hãy dùng thử ứng dụng mẫu để xem ví dụ về cách sử dụng API này.
- Hãy thử tự tạo mã bằng lớp học lập trình.
Trước khi bắt đầu
Trong tệp
build.gradle
cấp dự án, hãy nhớ đưa kho lưu trữ Maven của Google vào cả hai phầnbuildscript
vàallprojects
.Thêm các phần phụ thuộc cho thư viện Android ML Kit vào tệp gradle cấp ứng dụng của mô-đun, thường là
app/build.gradle
. Chọn một trong các phần phụ thuộc sau đây dựa trên nhu cầu của bạn:Để nhóm mô hình với ứng dụng:
dependencies { // ... // Use this dependency to bundle the model with your app implementation 'com.google.mlkit:face-detection:16.1.5' }
Để sử dụng mô hình trong Dịch vụ 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' }
Nếu chọn sử dụng mô hình trong Dịch vụ Google Play, bạn có thể định cấu hình để ứng dụng tự động tải mô hình xuống thiết bị sau khi ứng dụng được cài đặt từ Cửa hàng Play. Để thực hiện việc này, hãy thêm nội dung khai báo sau vào tệp
AndroidManifest.xml
của ứng dụng:<application ...> ... <meta-data android:name="com.google.mlkit.vision.DEPENDENCIES" android:value="face" > <!-- To use multiple models: android:value="face,model2,model3" --> </application>
Bạn cũng có thể kiểm tra tính khả dụng của mô hình một cách rõ ràng và yêu cầu tải xuống thông qua API ModuleInstallClient của Dịch vụ Google Play.
Nếu bạn không bật tính năng tải xuống mô hình tại thời điểm cài đặt hoặc không yêu cầu tải xuống một cách rõ ràng, mô hình sẽ được tải xuống trong lần đầu tiên bạn chạy trình phát hiện. Các yêu cầu bạn đưa ra trước khi tải xuống không tạo ra kết quả.
Nhập nguyên tắc về hình ảnh
Để nhận dạng khuôn mặt, bạn nên sử dụng hình ảnh có kích thước tối thiểu là 480x360 pixel. Để Bộ công cụ máy học phát hiện chính xác các khuôn mặt, hình ảnh đầu vào phải chứa các khuôn mặt được biểu thị bằng dữ liệu pixel đầy đủ. Nhìn chung, kích thước tối thiểu của mỗi khuôn mặt mà bạn muốn phát hiện trong một hình ảnh là 100x100 pixel. Nếu bạn muốn phát hiện các đường viền của khuôn mặt, thì Bộ công cụ học máy sẽ yêu cầu dữ liệu đầu vào có độ phân giải cao hơn: mỗi khuôn mặt phải có kích thước ít nhất là 200x200 pixel.
Nếu phát hiện khuôn mặt trong một ứng dụng theo thời gian thực, bạn cũng nên xem xét kích thước tổng thể của hình ảnh nhập vào. Ảnh nhỏ có thể được xử lý nhanh hơn. Vì vậy, để giảm độ trễ, hãy chụp ảnh ở độ phân giải thấp hơn, nhưng hãy lưu ý các yêu cầu về độ chính xác ở trên và đảm bảo rằng khuôn mặt của đối tượng chiếm càng nhiều hình ảnh càng tốt. Ngoài ra, hãy xem các mẹo cải thiện hiệu suất theo thời gian thực.
Tiêu điểm ảnh kém cũng có thể ảnh hưởng đến độ chính xác. Nếu bạn không nhận được kết quả chấp nhận được, hãy yêu cầu người dùng chụp lại hình ảnh.
Hướng của khuôn mặt so với máy ảnh cũng có thể ảnh hưởng tới các đặc điểm của Bộ công cụ máy học. Hãy xem phần Khái niệm phát hiện khuôn mặt.
1. Định cấu hình trình phát hiện khuôn mặt
Trước khi áp dụng tính năng phát hiện khuôn mặt cho một hình ảnh, nếu bạn muốn thay đổi chế độ cài đặt mặc định của trình phát hiện khuôn mặt, hãy chỉ định những chế độ cài đặt đó bằng một đối tượngFaceDetectorOptions
.
Bạn có thể thay đổi các cài đặt sau đây:
Cài đặt | |
---|---|
setPerformanceMode
|
PERFORMANCE_MODE_FAST (mặc định)
PERFORMANCE_MODE_ACCURATE
Ưu tiên tốc độ hoặc độ chính xác khi phát hiện khuôn mặt. |
setLandmarkMode
|
LANDMARK_MODE_NONE (mặc định)
LANDMARK_MODE_ALL
Liệu có cố gắng xác định "các đặc điểm" trên khuôn mặt: mắt, tai, mũi, má, miệng, v.v. hay không. |
setContourMode
|
CONTOUR_MODE_NONE (mặc định)
CONTOUR_MODE_ALL
Liệu có phát hiện các đường nét của đặc điểm khuôn mặt hay không. Chúng tôi chỉ phát hiện đường viền cho khuôn mặt nổi bật nhất trong hình ảnh. |
setClassificationMode
|
CLASSIFICATION_MODE_NONE (mặc định)
CLASSIFICATION_MODE_ALL
Liệu có phân loại khuôn mặt thành các danh mục như "mắt cười" và "mở mắt" không. |
setMinFaceSize
|
float (mặc định: 0.1f )
Đặt kích thước khuôn mặt mong muốn nhỏ nhất, được biểu thị bằng tỷ lệ chiều rộng của đầu với chiều rộng của hình ảnh. |
enableTracking
|
false (mặc định) | true
Có chỉ định ID khuôn mặt hay không. Bạn có thể sử dụng mã này để theo dõi các khuôn mặt trên các hình ảnh. Xin lưu ý rằng khi bạn bật tính năng phát hiện đường viền, chỉ có một khuôn mặt được phát hiện nên tính năng theo dõi khuôn mặt không cho kết quả hữu ích. Vì lý do này, để cải thiện tốc độ phát hiện, bạn không nên bật cả tính năng phát hiện đường viền và theo dõi khuôn mặt. |
Ví dụ:
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. Chuẩn bị hình ảnh nhập vào
Để phát hiện khuôn mặt trong một hình ảnh, hãy tạo một đối tượngInputImage
từ Bitmap
, media.Image
, ByteBuffer
, mảng byte hoặc một tệp trên thiết bị. Sau đó, hãy truyền đối tượng InputImage
đến phương thức process
của FaceDetector
.
Để phát hiện khuôn mặt, bạn nên sử dụng hình ảnh có kích thước tối thiểu là 480x360 pixel. Nếu bạn phát hiện khuôn mặt theo thời gian thực, việc chụp khung hình ở độ phân giải tối thiểu này có thể giúp giảm độ trễ.
Bạn có thể tạo một đối tượng InputImage
từ nhiều nguồn, mỗi nguồn được giải thích ở bên dưới.
Sử dụng media.Image
Để tạo một đối tượng InputImage
từ đối tượng media.Image
, chẳng hạn như khi bạn chụp ảnh từ máy ảnh của thiết bị, hãy truyền đối tượng media.Image
và độ xoay của hình ảnh đến InputImage.fromMediaImage()
.
Nếu bạn sử dụng thư viện
CameraX, các lớp OnImageCapturedListener
và
ImageAnalysis.Analyzer
sẽ tính toán giá trị xoay vòng
cho bạn.
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 // ... } } }
Nếu không sử dụng thư viện máy ảnh cung cấp cho bạn độ xoay của hình ảnh, bạn có thể tính toán độ này từ độ xoay của thiết bị và hướng của cảm biến máy ảnh trong thiết bị:
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; }
Sau đó, hãy truyền đối tượng media.Image
và giá trị độ xoay vòng đến InputImage.fromMediaImage()
:
Kotlin
val image = InputImage.fromMediaImage(mediaImage, rotation)
Java
InputImage image = InputImage.fromMediaImage(mediaImage, rotation);
Sử dụng URI tệp
Để tạo một đối tượng InputImage
từ URI tệp, hãy truyền ngữ cảnh ứng dụng và URI tệp cho InputImage.fromFilePath()
. Điều này sẽ hữu ích khi bạn sử dụng ý định ACTION_GET_CONTENT
để nhắc người dùng chọn một hình ảnh từ ứng dụng thư viện.
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(); }
Sử dụng ByteBuffer
hoặc ByteArray
Để tạo một đối tượng InputImage
từ ByteBuffer
hoặc ByteArray
, trước tiên, hãy tính độ xoay hình ảnh như mô tả trước đó cho phương thức nhập media.Image
.
Sau đó, hãy tạo đối tượng InputImage
kèm theo vùng đệm hoặc mảng cùng với chiều cao, chiều rộng, định dạng mã hoá màu và độ xoay:
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 );
Sử dụng Bitmap
Để tạo một đối tượng InputImage
từ đối tượng Bitmap
, hãy khai báo như sau:
Kotlin
val image = InputImage.fromBitmap(bitmap, 0)
Java
InputImage image = InputImage.fromBitmap(bitmap, rotationDegree);
Hình ảnh này được biểu thị bằng một đối tượng Bitmap
cùng với độ xoay.
3. Nhận một phiên bản của 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. Xử lý hình ảnh
Truyền hình ảnh đến phương thứcprocess
:
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. Nhận thông tin về các khuôn mặt được phát hiện
Nếu thao tác phát hiện khuôn mặt thành công, một danh sách các đối tượngFace
sẽ được truyền đến trình nghe thành công. Mỗi đối tượng Face
biểu thị một khuôn mặt đã được phát hiện trong hình ảnh. Đối với mỗi khuôn mặt, bạn có thể lấy các toạ độ giới hạn của hình ảnh đó trong hình ảnh đầu vào, cũng như mọi thông tin khác mà bạn đã định cấu hình trình phát hiện khuôn mặt để tìm. Ví dụ:
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(); } }
Ví dụ về đường nét khuôn mặt
Khi bật tính năng phát hiện đường nét khuôn mặt, bạn sẽ nhận được một danh sách các điểm cho mỗi đặc điểm trên khuôn mặt đã được phát hiện. Các điểm này thể hiện hình dạng của tính năng. Hãy xem Khái niệm phát hiện khuôn mặt để biết thông tin chi tiết về cách trình bày đường viền.
Hình ảnh sau đây minh hoạ cách các điểm này tương ứng với một khuôn mặt, hãy nhấp vào hình ảnh đó để phóng to:
Phát hiện khuôn mặt theo thời gian thực
Nếu bạn muốn sử dụng tính năng phát hiện khuôn mặt trong một ứng dụng theo thời gian thực, hãy làm theo các nguyên tắc sau để đạt được tốc độ khung hình tốt nhất:
Định cấu hình trình phát hiện khuôn mặt để sử dụng tính năng phát hiện hoặc phân loại đường viền khuôn mặt và phát hiện mốc, nhưng không phải cả hai:
Phát hiện đường viền
Phát hiện mốc
Phân loại
Phát hiện và phân loại mốc
Phát hiện và phát hiện đường viền
Phát hiện và phân loại đường viền
Phát hiện và phát hiện đường viềnBật chế độ
FAST
(được bật theo mặc định).Hãy cân nhắc chụp ảnh ở độ phân giải thấp hơn. Tuy nhiên, bạn cũng cần lưu ý đến các yêu cầu về kích thước hình ảnh của API này.
Camera
hoặc API camera2
, hãy điều chỉnh các lệnh gọi đến trình phát hiện. Nếu khung video mới
hoạt động trong khi trình phát hiện đang chạy, hãy thả khung hình đó. Hãy xem lớp
VisionProcessorBase
trong ứng dụng mẫu khởi động nhanh để biết ví dụ.
CameraX
, hãy đảm bảo rằng chiến lược áp lực ngược được đặt thành giá trị mặc định
ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST
.
Việc này đảm bảo mỗi lần bạn chỉ gửi được một hình ảnh để phân tích. Nếu hệ thống phân tích nhiều hình ảnh hơn khi trình phân tích đang bận, chúng sẽ tự động được thả và không được đưa vào hàng đợi để phân phối. Sau khi hình ảnh đang được phân tích được đóng bằng cách gọi ImageProxy.close(), hình ảnh mới nhất tiếp theo sẽ được phân phối.
CameraSourcePreview
và
GraphicOverlay
trong ứng dụng mẫu bắt đầu nhanh.
ImageFormat.YUV_420_888
. Nếu bạn sử dụng API Máy ảnh cũ hơn, hãy chụp ảnh ở định dạng ImageFormat.NV21
.