می توانید از کیت ML برای تشخیص چهره در تصاویر و ویدیو استفاده کنید.
ویژگی | تفکیک شده | همراه |
---|---|---|
پیاده سازی | مدل به صورت پویا از طریق خدمات Google Play دانلود می شود. | مدل به طور ایستا به برنامه شما در زمان ساخت پیوند داده می شود. |
اندازه برنامه | حدود 800 کیلوبایت افزایش حجم. | حدود 6.9 مگابایت افزایش حجم. |
زمان اولیه سازی | ممکن است قبل از اولین استفاده باید منتظر بمانید تا مدل دانلود شود. | مدل فورا موجود است |
آن را امتحان کنید
- با برنامه نمونه بازی کنید تا نمونه استفاده از این API را ببینید.
- کد را خودتان با Codelab امتحان کنید.
قبل از شروع
در فایل
build.gradle
در سطح پروژه خود، مطمئن شوید که مخزن Maven Google را در هر دو بخشbuildscript
وallprojects
خود قرار دهید.وابستگی های کتابخانه های اندروید ML Kit را به فایل 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 استفاده کنید ، میتوانید برنامه خود را طوری پیکربندی کنید که پس از نصب برنامه از فروشگاه 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>
همچنین میتوانید صریحاً در دسترس بودن مدل را بررسی کنید و از طریق سرویسهای Google Play ModuleInstallClient API درخواست دانلود کنید.
اگر دانلودهای مدل در زمان نصب را فعال نکنید یا درخواست دانلود صریح نداشته باشید، اولین باری که آشکارساز را اجرا می کنید، مدل دانلود می شود. درخواستهایی که قبل از تکمیل دانلود ارائه میکنید، نتیجهای ندارند.
دستورالعمل های تصویر ورودی
برای تشخیص چهره، باید از تصویری با ابعاد حداقل 480x360 پیکسل استفاده کنید. برای اینکه کیت ML بتواند چهرهها را بهطور دقیق تشخیص دهد، تصاویر ورودی باید دارای چهرههایی باشند که با دادههای پیکسلی کافی نشان داده شوند. به طور کلی، هر چهره ای که می خواهید در یک تصویر تشخیص دهید باید حداقل 100x100 پیکسل باشد. اگر میخواهید خطوط چهرهها را تشخیص دهید، کیت ML به ورودی وضوح بالاتری نیاز دارد: هر چهره باید حداقل 200x200 پیکسل باشد.
اگر چهرهها را در یک برنامه بلادرنگ شناسایی میکنید، ممکن است بخواهید ابعاد کلی تصاویر ورودی را نیز در نظر بگیرید. تصاویر کوچکتر را میتوان سریعتر پردازش کرد، بنابراین برای کاهش تأخیر، تصاویر را با وضوح پایینتر ثبت کنید، اما الزامات دقت بالا را در نظر داشته باشید و اطمینان حاصل کنید که صورت سوژه تا حد امکان تصویر را اشغال میکند. همچنین نکاتی را برای بهبود عملکرد در زمان واقعی مشاهده کنید.
فوکوس ضعیف تصویر نیز می تواند بر دقت تأثیر بگذارد. اگر نتایج قابل قبولی دریافت نکردید، از کاربر بخواهید که تصویر را دوباره بگیرد.
جهت گیری چهره نسبت به دوربین نیز می تواند بر ویژگی های صورت که کیت ML تشخیص می دهد تأثیر بگذارد. به مفاهیم تشخیص چهره مراجعه کنید.
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 اینکه آیا به چهره ها یک شناسه اختصاص داده شود یا خیر، که می تواند برای ردیابی چهره ها در تصاویر استفاده شود. توجه داشته باشید که وقتی تشخیص کانتور فعال است، فقط یک چهره شناسایی میشود، بنابراین ردیابی چهره نتایج مفیدی ایجاد نمیکند. به همین دلیل و برای بهبود سرعت تشخیص، هم تشخیص کانتور و هم ردیابی چهره را فعال نکنید. |
به عنوان مثال:
کاتلین
// 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()
جاوا
// 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
منتقل کنید.برای تشخیص چهره، باید از تصویری با ابعاد حداقل 480x360 پیکسل استفاده کنید. اگر چهرهها را در زمان واقعی شناسایی میکنید، گرفتن فریمها با این حداقل وضوح میتواند به کاهش تأخیر کمک کند.
می توانید یک شی InputImage
از منابع مختلف ایجاد کنید که هر کدام در زیر توضیح داده شده است.
استفاده از یک media.Image
برای ایجاد یک شیء InputImage
از یک شیء media.Image
، مانند زمانی که تصویری را از دوربین دستگاه میگیرید، شیء media.Image
Image و چرخش تصویر را به InputImage.fromMediaImage()
منتقل کنید.
اگر از کتابخانه CameraX استفاده می کنید، کلاس های OnImageCapturedListener
و ImageAnalysis.Analyzer
مقدار چرخش را برای شما محاسبه می کنند.
کاتلین
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 // ... } } }
جاوا
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 // ... } } }
اگر از کتابخانه دوربینی که درجه چرخش تصویر را به شما می دهد استفاده نمی کنید، می توانید آن را از روی درجه چرخش دستگاه و جهت سنسور دوربین در دستگاه محاسبه کنید:
کاتلین
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 }
جاوا
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()
منتقل کنید:
کاتلین
val image = InputImage.fromMediaImage(mediaImage, rotation)
Java
InputImage image = InputImage.fromMediaImage(mediaImage, rotation);
استفاده از URI فایل
برای ایجاد یک شی InputImage
از URI فایل، زمینه برنامه و فایل URI را به InputImage.fromFilePath()
ارسال کنید. این زمانی مفید است که از یک هدف ACTION_GET_CONTENT
استفاده می کنید تا از کاربر بخواهید تصویری را از برنامه گالری خود انتخاب کند.
کاتلین
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
با بافر یا آرایه به همراه ارتفاع، عرض، فرمت کدگذاری رنگ و درجه چرخش تصویر ایجاد کنید:
کاتلین
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 )
جاوا
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
، اعلان زیر را انجام دهید:
کاتلین
val image = InputImage.fromBitmap(bitmap, 0)
Java
InputImage image = InputImage.fromBitmap(bitmap, rotationDegree);
تصویر با یک شی Bitmap
همراه با درجه چرخش نمایش داده می شود.
3. یک نمونه از FaceDetector را دریافت کنید
کاتلین
val detector = FaceDetection.getClient(options) // Or, to use the default option: // val detector = FaceDetection.getClient();
جاوا
FaceDetector detector = FaceDetection.getClient(options); // Or use the default options: // FaceDetector detector = FaceDetection.getClient();
4. تصویر را پردازش کنید
ارسال تصویر به روشprocess
: کاتلین
val result = detector.process(image) .addOnSuccessListener { faces -> // Task completed successfully // ... } .addOnFailureListener { e -> // Task failed with an exception // ... }
جاوا
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
نشان دهنده چهره ای است که در تصویر شناسایی شده است. برای هر چهره، میتوانید مختصات مرزی آن را در تصویر ورودی و همچنین اطلاعات دیگری را که آشکارساز چهره پیکربندی کردهاید، دریافت کنید. به عنوان مثال: کاتلین
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 } }
جاوا
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
API استفاده می کنید، دریچه گاز با آشکارساز تماس می گیرد. اگر یک قاب ویدیویی جدید در حین کار کردن آشکارساز در دسترس قرار گرفت، قاب را رها کنید. برای مثال، کلاس VisionProcessorBase
را در برنامه نمونه سریع شروع کنید.CameraX
API استفاده میکنید، مطمئن شوید که استراتژی فشار برگشتی روی مقدار پیشفرض ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST
تنظیم شده است.STRATEGY_KEEP_ONLY_LATEST. این تضمین می کند که هر بار فقط یک تصویر برای تجزیه و تحلیل تحویل داده می شود. اگر در زمانی که آنالایزر مشغول است، تصاویر بیشتری تولید شود، به طور خودکار حذف می شوند و برای تحویل در صف قرار نمی گیرند. هنگامی که تصویر مورد تجزیه و تحلیل با فراخوانی ImageProxy.close بسته شد، آخرین تصویر بعدی تحویل داده می شود.CameraSourcePreview
و GraphicOverlay
را در برنامه نمونه شروع سریع ببینید.ImageFormat.YUV_420_888
بگیرید. اگر از دوربین API قدیمی استفاده می کنید، تصاویر را با فرمت ImageFormat.NV21
بگیرید.