يمكنك استخدام هذه الأدوات لرصد الوجوه في الصور والفيديوهات.
إبراز | غير مجمّعة | مُجمَّعة |
---|---|---|
التنفيذ | يتم تنزيل النموذج ديناميكيًا من خلال "خدمات Google Play". | النموذج مرتبط بشكلٍ ثابت بتطبيقك في وقت الإصدار. |
حجم التطبيق | يزيد الحجم بحوالي 800 كيلوبايت. | زيادة في الحجم بمقدار 6.9 ميغابايت تقريبًا |
وقت الإعداد | قد تضطر إلى الانتظار حتى يتم تنزيل النموذج قبل الاستخدام الأول. | يتوفّر الطراز على الفور. |
التجربة الآن
- جرّب نموذج التطبيق للاطّلاع على مثال لاستخدام واجهة برمجة التطبيقات هذه.
- جرِّب الترميز بنفسك باستخدام الدرس التطبيقي حول الترميز.
قبل البدء
في ملف
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.6' }
لاستخدام النموذج في "خدمات 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"، يمكنك ضبط تطبيقك على تنزيل النموذج تلقائيًا على الجهاز بعد تثبيت التطبيق من "متجر 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×360 بكسل. لكي ترصد أدوات تعلّم الآلة الوجوه بدقة، يجب أن تحتوي صور الإدخال على وجوه يمثّلها بيانات بكسل كافية. وبشكل عام، يجب ألا يقل حجم كل وجه تريد اكتشافه في الصورة عن 100×100 بكسل. إذا أردت رصد خطوط الوجوه، تتطلّب أدوات تعلّم الآلة إدخال درجة دقة أعلى، ويجب ألّا يقل حجم كل وجه عن 200×200 بكسل.
في حال اكتشاف وجوه في تطبيق في الوقت الفعلي، قد تحتاج أيضًا إلى مراعاة الأبعاد العامة للصور المدخلة. يمكن معالجة الصور الأصغر حجمًا بشكل أسرع، ولذلك احرص على التقاط الصور بدرجات دقة أقل لتقليل وقت الاستجابة، ولكن يُرجى مراعاة متطلبات الدقة المذكورة أعلاه والتأكّد من أنّ وجه الشخص المعني يشغل أكبر قدر ممكن من الصورة. ويمكنك أيضًا الاطّلاع على نصائح لتحسين الأداء في الوقت الفعلي.
ويمكن أن يؤثّر التركيز الضعيف في الصورة أيضًا في الدقة. وإذا لم تحصل على نتائج مقبولة، اطلب من المستخدم إعادة التقاط الصورة.
يمكن أن يؤثر اتجاه الوجه بالنسبة إلى الكاميرا أيضًا في الميزات التي ترصدها أدوات تعلُّم الآلة. يمكنك الاطّلاع على مفاهيم التعرّف على الوجوه.
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×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- الحصول على مثيل لميزة "التعرّف على الوجه"
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
(يتم تفعيله تلقائيًا)ننصحك بالتقاط الصور بدرجة دقة أقل. ومع ذلك، يُرجى أيضًا تذكُّر متطلبات أبعاد الصورة في واجهة برمجة التطبيقات هذه
Camera
أو camera2
، يمكنك التحكُّم في طلبات البيانات لأداة الرصد. في حال توفُّر إطار فيديو جديد أثناء تشغيل أداة الرصد، أفلِت الإطار. يمكنك الاطّلاع على صف
VisionProcessorBase
في نموذج التطبيق السريع للبدء من أجل الحصول على مثال.
CameraX
،
تأكّد من ضبط استراتيجية إعادة ضغط البيانات على قيمتها التلقائية
ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST
.
ويضمن ذلك تسليم صورة واحدة فقط لتحليلها في كل مرة. في حال إنشاء المزيد من الصور
عندما تكون أداة التحليل مشغولة، سيتم حذفها تلقائيًا ولن يتم وضعها في قائمة الانتظار
للتسليم. بعد إغلاق الصورة التي يتم تحليلها من خلال استدعاء ImageProxy.CLOSE() ، سيتم عرض أحدث صورة تالية.
CameraSourcePreview
و
GraphicOverlay
في نموذج التطبيق السريع للبدء للحصول على مثال.
ImageFormat.YUV_420_888
. إذا كنت تستخدم واجهة برمجة تطبيقات الكاميرا القديمة، التقِط الصور بتنسيق ImageFormat.NV21
.