می توانید از کیت ML برای تشخیص چهره در تصاویر و ویدیو استفاده کنید.
قبل از شروع
- اگر قبلاً این کار را نکردهاید، Firebase را به پروژه Android خود اضافه کنید .
- وابستگیهای کتابخانههای اندروید ML Kit را به فایل Gradle ماژول (سطح برنامه) خود اضافه کنید (معمولا
app/build.gradle
):apply plugin: 'com.android.application' apply plugin: 'com.google.gms.google-services' dependencies { // ... implementation 'com.google.firebase:firebase-ml-vision:24.0.3' // If you want to detect face contours (landmark detection and classification // don't require this additional model): implementation 'com.google.firebase:firebase-ml-vision-face-model:20.0.1' }
- اختیاری اما توصیه می شود : برنامه خود را طوری پیکربندی کنید که پس از نصب برنامه از فروشگاه Play، مدل ML را به طور خودکار در دستگاه دانلود کند.
برای انجام این کار، اعلان زیر را به فایل
AndroidManifest.xml
برنامه خود اضافه کنید: اگر دانلودهای مدل زمان نصب را فعال نکنید، اولین باری که آشکارساز را اجرا می کنید، مدل دانلود می شود. درخواستهایی که قبل از تکمیل دانلود ارائه میکنید، نتیجهای ندارند.<application ...> ... <meta-data android:name="com.google.firebase.ml.vision.DEPENDENCIES" android:value="face" /> <!-- To use multiple models: android:value="face,model2,model3" --> </application>
دستورالعمل های تصویر ورودی
برای اینکه کیت ML بتواند چهرهها را بهطور دقیق تشخیص دهد، تصاویر ورودی باید دارای چهرههایی باشند که با دادههای پیکسلی کافی نشان داده شوند. به طور کلی، هر چهره ای که می خواهید در یک تصویر تشخیص دهید باید حداقل 100x100 پیکسل باشد. اگر میخواهید خطوط چهرهها را تشخیص دهید، کیت ML به ورودی وضوح بالاتری نیاز دارد: هر چهره باید حداقل 200x200 پیکسل باشد.
اگر چهرهها را در یک برنامه بلادرنگ شناسایی میکنید، ممکن است بخواهید ابعاد کلی تصاویر ورودی را نیز در نظر بگیرید. تصاویر کوچکتر را میتوان سریعتر پردازش کرد، بنابراین برای کاهش تأخیر، تصاویر را با وضوح پایینتر (با در نظر گرفتن الزامات دقت بالا) ثبت کنید و اطمینان حاصل کنید که صورت سوژه تا حد امکان تصویر را اشغال میکند. همچنین به نکاتی برای بهبود عملکرد در زمان واقعی مراجعه کنید.
فوکوس ضعیف تصویر می تواند به دقت آسیب برساند. اگر نتایج قابل قبولی دریافت نکردید، از کاربر بخواهید که تصویر را دوباره بگیرد.
جهت گیری چهره نسبت به دوربین نیز می تواند بر ویژگی های صورت که کیت ML تشخیص می دهد تأثیر بگذارد. به مفاهیم تشخیص چهره مراجعه کنید.
1. آشکارساز چهره را پیکربندی کنید
قبل از اعمال تشخیص چهره بر روی یک تصویر، اگر میخواهید هر یک از تنظیمات پیشفرض آشکارساز چهره را تغییر دهید، آن تنظیمات را با یک شیFirebaseVisionFaceDetectorOptions
مشخص کنید. می توانید تنظیمات زیر را تغییر دهید:تنظیمات | |
---|---|
حالت عملکرد | FAST (پیش فرض) | ACCURATE هنگام تشخیص چهره، سرعت یا دقت را ترجیح دهید. |
شناسایی نقاط دیدنی | NO_LANDMARKS (پیشفرض) | ALL_LANDMARKS آیا تلاش برای شناسایی "نقاط برجسته" صورت: چشم ها، گوش ها، بینی، گونه ها، دهان، و غیره. |
تشخیص خطوط | NO_CONTOURS (پیشفرض) | ALL_CONTOURS آیا برای تشخیص خطوط خطوط صورت. خطوط تنها برای برجسته ترین چهره در یک تصویر شناسایی می شوند. |
طبقه بندی چهره ها | NO_CLASSIFICATIONS (پیشفرض) | ALL_CLASSIFICATIONS اینکه آیا باید چهره ها را به دسته هایی مانند "خندان" و "چشمان باز" طبقه بندی کرد یا خیر. |
حداقل اندازه صورت | float (پیشفرض: 0.1f )حداقل اندازه، نسبت به تصویر، برای تشخیص چهره ها. |
فعال کردن ردیابی چهره | false (پیش فرض) | true اینکه آیا به چهره ها یک شناسه اختصاص داده شود یا خیر، که می تواند برای ردیابی چهره ها در تصاویر استفاده شود. توجه داشته باشید که وقتی تشخیص کانتور فعال است، فقط یک چهره شناسایی میشود، بنابراین ردیابی چهره نتایج مفیدی ایجاد نمیکند. به همین دلیل و برای بهبود سرعت تشخیص، هم تشخیص کانتور و هم ردیابی چهره را فعال نکنید. |
به عنوان مثال:
Java
// High-accuracy landmark detection and face classification FirebaseVisionFaceDetectorOptions highAccuracyOpts = new FirebaseVisionFaceDetectorOptions.Builder() .setPerformanceMode(FirebaseVisionFaceDetectorOptions.ACCURATE) .setLandmarkMode(FirebaseVisionFaceDetectorOptions.ALL_LANDMARKS) .setClassificationMode(FirebaseVisionFaceDetectorOptions.ALL_CLASSIFICATIONS) .build(); // Real-time contour detection of multiple faces FirebaseVisionFaceDetectorOptions realTimeOpts = new FirebaseVisionFaceDetectorOptions.Builder() .setContourMode(FirebaseVisionFaceDetectorOptions.ALL_CONTOURS) .build();
Kotlin
// High-accuracy landmark detection and face classification val highAccuracyOpts = FirebaseVisionFaceDetectorOptions.Builder() .setPerformanceMode(FirebaseVisionFaceDetectorOptions.ACCURATE) .setLandmarkMode(FirebaseVisionFaceDetectorOptions.ALL_LANDMARKS) .setClassificationMode(FirebaseVisionFaceDetectorOptions.ALL_CLASSIFICATIONS) .build() // Real-time contour detection of multiple faces val realTimeOpts = FirebaseVisionFaceDetectorOptions.Builder() .setContourMode(FirebaseVisionFaceDetectorOptions.ALL_CONTOURS) .build()
2. آشکارساز چهره را اجرا کنید
برای شناسایی چهرهها در یک تصویر، یک شیFirebaseVisionImage
از Bitmap
، media.Image
، ByteBuffer
، آرایه بایت یا یک فایل روی دستگاه ایجاد کنید. سپس، شی FirebaseVisionImage
را به متد detectInImage
FirebaseVisionFaceDetector
ارسال کنید.برای تشخیص چهره، باید از تصویری با ابعاد حداقل 480x360 پیکسل استفاده کنید. اگر چهرهها را در زمان واقعی تشخیص میدهید، گرفتن فریمها با این حداقل وضوح میتواند به کاهش تأخیر کمک کند.
یک شی
FirebaseVisionImage
از تصویر خود ایجاد کنید.برای ایجاد یک شی
FirebaseVisionImage
از یک شیmedia.Image
، مانند هنگام گرفتن تصویر از دوربین دستگاه، شیmedia.Image
.Image و چرخش تصویر را بهFirebaseVisionImage.fromMediaImage()
منتقل کنید.اگر از کتابخانه CameraX ، کلاسهای
OnImageCapturedListener
وImageAnalysis.Analyzer
استفاده میکنید، مقدار چرخش را برای شما محاسبه میکنند، بنابراین فقط باید قبل از فراخوانیFirebaseVisionImage.fromMediaImage()
چرخش را به یکی از ثابتهایROTATION_
ML Kit تبدیل کنید:Java
private class YourAnalyzer implements ImageAnalysis.Analyzer { private int degreesToFirebaseRotation(int degrees) { switch (degrees) { case 0: return FirebaseVisionImageMetadata.ROTATION_0; case 90: return FirebaseVisionImageMetadata.ROTATION_90; case 180: return FirebaseVisionImageMetadata.ROTATION_180; case 270: return FirebaseVisionImageMetadata.ROTATION_270; default: throw new IllegalArgumentException( "Rotation must be 0, 90, 180, or 270."); } } @Override public void analyze(ImageProxy imageProxy, int degrees) { if (imageProxy == null || imageProxy.getImage() == null) { return; } Image mediaImage = imageProxy.getImage(); int rotation = degreesToFirebaseRotation(degrees); FirebaseVisionImage image = FirebaseVisionImage.fromMediaImage(mediaImage, rotation); // Pass image to an ML Kit Vision API // ... } }
Kotlin
private class YourImageAnalyzer : ImageAnalysis.Analyzer { private fun degreesToFirebaseRotation(degrees: Int): Int = when(degrees) { 0 -> FirebaseVisionImageMetadata.ROTATION_0 90 -> FirebaseVisionImageMetadata.ROTATION_90 180 -> FirebaseVisionImageMetadata.ROTATION_180 270 -> FirebaseVisionImageMetadata.ROTATION_270 else -> throw Exception("Rotation must be 0, 90, 180, or 270.") } override fun analyze(imageProxy: ImageProxy?, degrees: Int) { val mediaImage = imageProxy?.image val imageRotation = degreesToFirebaseRotation(degrees) if (mediaImage != null) { val image = FirebaseVisionImage.fromMediaImage(mediaImage, imageRotation) // Pass image to an ML Kit Vision API // ... } } }
اگر از کتابخانه دوربینی که چرخش تصویر را به شما می دهد استفاده نمی کنید، می توانید آن را از روی چرخش دستگاه و جهت سنسور دوربین در دستگاه محاسبه کنید:
Java
private static final SparseIntArray ORIENTATIONS = new SparseIntArray(); static { ORIENTATIONS.append(Surface.ROTATION_0, 90); ORIENTATIONS.append(Surface.ROTATION_90, 0); ORIENTATIONS.append(Surface.ROTATION_180, 270); ORIENTATIONS.append(Surface.ROTATION_270, 180); } /** * 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, Context context) 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); // On most devices, the sensor orientation is 90 degrees, but for some // devices it is 270 degrees. For devices with a sensor orientation of // 270, rotate the image an additional 180 ((270 + 270) % 360) degrees. CameraManager cameraManager = (CameraManager) context.getSystemService(CAMERA_SERVICE); int sensorOrientation = cameraManager .getCameraCharacteristics(cameraId) .get(CameraCharacteristics.SENSOR_ORIENTATION); rotationCompensation = (rotationCompensation + sensorOrientation + 270) % 360; // Return the corresponding FirebaseVisionImageMetadata rotation value. int result; switch (rotationCompensation) { case 0: result = FirebaseVisionImageMetadata.ROTATION_0; break; case 90: result = FirebaseVisionImageMetadata.ROTATION_90; break; case 180: result = FirebaseVisionImageMetadata.ROTATION_180; break; case 270: result = FirebaseVisionImageMetadata.ROTATION_270; break; default: result = FirebaseVisionImageMetadata.ROTATION_0; Log.e(TAG, "Bad rotation value: " + rotationCompensation); } return result; }
Kotlin
private val ORIENTATIONS = SparseIntArray() init { ORIENTATIONS.append(Surface.ROTATION_0, 90) ORIENTATIONS.append(Surface.ROTATION_90, 0) ORIENTATIONS.append(Surface.ROTATION_180, 270) ORIENTATIONS.append(Surface.ROTATION_270, 180) } /** * 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, context: Context): 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) // On most devices, the sensor orientation is 90 degrees, but for some // devices it is 270 degrees. For devices with a sensor orientation of // 270, rotate the image an additional 180 ((270 + 270) % 360) degrees. val cameraManager = context.getSystemService(CAMERA_SERVICE) as CameraManager val sensorOrientation = cameraManager .getCameraCharacteristics(cameraId) .get(CameraCharacteristics.SENSOR_ORIENTATION)!! rotationCompensation = (rotationCompensation + sensorOrientation + 270) % 360 // Return the corresponding FirebaseVisionImageMetadata rotation value. val result: Int when (rotationCompensation) { 0 -> result = FirebaseVisionImageMetadata.ROTATION_0 90 -> result = FirebaseVisionImageMetadata.ROTATION_90 180 -> result = FirebaseVisionImageMetadata.ROTATION_180 270 -> result = FirebaseVisionImageMetadata.ROTATION_270 else -> { result = FirebaseVisionImageMetadata.ROTATION_0 Log.e(TAG, "Bad rotation value: $rotationCompensation") } } return result }
سپس، شی
media.Image
و مقدار چرخش را بهFirebaseVisionImage.fromMediaImage()
ارسال کنید:Java
FirebaseVisionImage image = FirebaseVisionImage.fromMediaImage(mediaImage, rotation);
Kotlin
val image = FirebaseVisionImage.fromMediaImage(mediaImage, rotation)
- برای ایجاد یک شی
FirebaseVisionImage
از URI فایل، زمینه برنامه و فایل URI را بهFirebaseVisionImage.fromFilePath()
ارسال کنید. این زمانی مفید است که از یک هدفACTION_GET_CONTENT
استفاده می کنید تا از کاربر بخواهید تصویری را از برنامه گالری خود انتخاب کند.Java
FirebaseVisionImage image; try { image = FirebaseVisionImage.fromFilePath(context, uri); } catch (IOException e) { e.printStackTrace(); }
Kotlin
val image: FirebaseVisionImage try { image = FirebaseVisionImage.fromFilePath(context, uri) } catch (e: IOException) { e.printStackTrace() }
- برای ایجاد یک شی
FirebaseVisionImage
از یکByteBuffer
یا یک آرایه بایت، ابتدا چرخش تصویر را همانطور که در بالا برای ورودیmedia.Image
توضیح داده شد محاسبه کنید.سپس، یک شی
FirebaseVisionImageMetadata
ایجاد کنید که شامل ارتفاع، عرض، فرمت کدگذاری رنگ و چرخش تصویر باشد:Java
FirebaseVisionImageMetadata metadata = new FirebaseVisionImageMetadata.Builder() .setWidth(480) // 480x360 is typically sufficient for .setHeight(360) // image recognition .setFormat(FirebaseVisionImageMetadata.IMAGE_FORMAT_NV21) .setRotation(rotation) .build();
Kotlin
val metadata = FirebaseVisionImageMetadata.Builder() .setWidth(480) // 480x360 is typically sufficient for .setHeight(360) // image recognition .setFormat(FirebaseVisionImageMetadata.IMAGE_FORMAT_NV21) .setRotation(rotation) .build()
برای ایجاد یک شی
FirebaseVisionImage
از بافر یا آرایه و شیء فراداده استفاده کنید:Java
FirebaseVisionImage image = FirebaseVisionImage.fromByteBuffer(buffer, metadata); // Or: FirebaseVisionImage image = FirebaseVisionImage.fromByteArray(byteArray, metadata);
Kotlin
val image = FirebaseVisionImage.fromByteBuffer(buffer, metadata) // Or: val image = FirebaseVisionImage.fromByteArray(byteArray, metadata)
- برای ایجاد یک شی
FirebaseVisionImage
از یک شیBitmap
:تصویر نمایش داده شده توسط شیJava
FirebaseVisionImage image = FirebaseVisionImage.fromBitmap(bitmap);
Kotlin
val image = FirebaseVisionImage.fromBitmap(bitmap)
Bitmap
باید عمودی باشد، بدون نیاز به چرخش اضافی.
نمونه ای از
FirebaseVisionFaceDetector
را دریافت کنید:Java
FirebaseVisionFaceDetector detector = FirebaseVision.getInstance() .getVisionFaceDetector(options);
Kotlin
val detector = FirebaseVision.getInstance() .getVisionFaceDetector(options)
در نهایت تصویر را به متد
detectInImage
منتقل کنید:Java
Task<List<FirebaseVisionFace>> result = detector.detectInImage(image) .addOnSuccessListener( new OnSuccessListener<List<FirebaseVisionFace>>() { @Override public void onSuccess(List<FirebaseVisionFace> faces) { // Task completed successfully // ... } }) .addOnFailureListener( new OnFailureListener() { @Override public void onFailure(@NonNull Exception e) { // Task failed with an exception // ... } });
Kotlin
val result = detector.detectInImage(image) .addOnSuccessListener { faces -> // Task completed successfully // ... } .addOnFailureListener { e -> // Task failed with an exception // ... }
3. اطلاعاتی در مورد چهره های شناسایی شده دریافت کنید
اگر عملیات تشخیص چهره با موفقیت انجام شود، لیستی از اشیاءFirebaseVisionFace
به شنونده موفقیت آمیز ارسال می شود. هر شی FirebaseVisionFace
نمایانگر چهره ای است که در تصویر شناسایی شده است. برای هر چهره، میتوانید مختصات مرزی آن را در تصویر ورودی و همچنین اطلاعات دیگری را که آشکارساز چهره پیکربندی کردهاید، دریافت کنید. به عنوان مثال: Java
for (FirebaseVisionFace 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): FirebaseVisionFaceLandmark leftEar = face.getLandmark(FirebaseVisionFaceLandmark.LEFT_EAR); if (leftEar != null) { FirebaseVisionPoint leftEarPos = leftEar.getPosition(); } // If contour detection was enabled: List<FirebaseVisionPoint> leftEyeContour = face.getContour(FirebaseVisionFaceContour.LEFT_EYE).getPoints(); List<FirebaseVisionPoint> upperLipBottomContour = face.getContour(FirebaseVisionFaceContour.UPPER_LIP_BOTTOM).getPoints(); // If classification was enabled: if (face.getSmilingProbability() != FirebaseVisionFace.UNCOMPUTED_PROBABILITY) { float smileProb = face.getSmilingProbability(); } if (face.getRightEyeOpenProbability() != FirebaseVisionFace.UNCOMPUTED_PROBABILITY) { float rightEyeOpenProb = face.getRightEyeOpenProbability(); } // If face tracking was enabled: if (face.getTrackingId() != FirebaseVisionFace.INVALID_ID) { int id = face.getTrackingId(); } }
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(FirebaseVisionFaceLandmark.LEFT_EAR) leftEar?.let { val leftEarPos = leftEar.position } // If contour detection was enabled: val leftEyeContour = face.getContour(FirebaseVisionFaceContour.LEFT_EYE).points val upperLipBottomContour = face.getContour(FirebaseVisionFaceContour.UPPER_LIP_BOTTOM).points // If classification was enabled: if (face.smilingProbability != FirebaseVisionFace.UNCOMPUTED_PROBABILITY) { val smileProb = face.smilingProbability } if (face.rightEyeOpenProbability != FirebaseVisionFace.UNCOMPUTED_PROBABILITY) { val rightEyeOpenProb = face.rightEyeOpenProbability } // If face tracking was enabled: if (face.trackingId != FirebaseVisionFace.INVALID_ID) { val id = face.trackingId } }
نمونه ای از خطوط صورت
هنگامی که تشخیص کانتور صورت را فعال کنید، لیستی از نقاط برای هر ویژگی صورت شناسایی شده دریافت می کنید. این نقاط نمایانگر شکل ویژگی هستند. برای جزئیات بیشتر در مورد نحوه نمایش خطوط به نمای کلی مفاهیم تشخیص چهره مراجعه کنید.
تصویر زیر نشان میدهد که چگونه این نقاط به صورت نگاشت میشوند (برای بزرگنمایی روی تصویر کلیک کنید):
تشخیص چهره در زمان واقعی
اگر میخواهید از تشخیص چهره در یک برنامه بلادرنگ استفاده کنید، این دستورالعملها را برای دستیابی به بهترین نرخ فریم دنبال کنید:
آشکارساز چهره را طوری پیکربندی کنید که از تشخیص کانتور صورت یا طبقه بندی و تشخیص نقطه عطف استفاده کند، اما نه از هر دو:
تشخیص کانتور
تشخیص نقطه عطف
طبقه بندی
تشخیص و طبقه بندی نقاط عطف
تشخیص کانتور و تشخیص نقطه عطف
تشخیص و طبقه بندی کانتور
تشخیص کانتور، تشخیص نقطه عطف و طبقه بندیحالت
FAST
را فعال کنید (به طور پیش فرض فعال است).گرفتن تصاویر با وضوح کمتر را در نظر بگیرید. با این حال، الزامات ابعاد تصویر این API را نیز در نظر داشته باشید.
- دریچه گاز به آشکارساز زنگ می زند. اگر یک قاب ویدیویی جدید در حین کار کردن آشکارساز در دسترس قرار گرفت، قاب را رها کنید.
- اگر از خروجی آشکارساز برای همپوشانی گرافیک روی تصویر ورودی استفاده میکنید، ابتدا نتیجه را از کیت ML دریافت کنید، سپس تصویر را رندر کنید و در یک مرحله همپوشانی کنید. با انجام این کار، برای هر فریم ورودی فقط یک بار به سطح نمایشگر رندر می دهید.
اگر از Camera2 API استفاده می کنید، تصاویر را با فرمت
ImageFormat.YUV_420_888
بگیرید.اگر از دوربین API قدیمی استفاده می کنید، تصاویر را با فرمت
ImageFormat.NV21
بگیرید.