میتوانید از کیت ML برای تشخیص چهرهها در تصاویر و ویدیوهای سلفی مانند استفاده کنید.
API تشخیص مش چهره | |
---|---|
نام SDK | face-mesh-detection |
پیاده سازی | کد و دارایی ها به صورت ایستا به برنامه شما در زمان ساخت مرتبط هستند. |
تاثیر اندازه برنامه | ~ 6.4 مگابایت |
عملکرد | زمان واقعی در اکثر دستگاه ها. |
آن را امتحان کنید
- با برنامه نمونه بازی کنید تا نمونه استفاده از این API را ببینید.
قبل از شروع
در فایل
build.gradle
در سطح پروژه خود، مطمئن شوید که مخزن Maven Google را در هر دو بخش buildscript و allprojects خود قرار دهید.وابستگی کتابخانه تشخیص مش چهره کیت ML را به فایل gradle سطح برنامه ماژول خود اضافه کنید، که معمولا
app/build.gradle
است:dependencies { // ... implementation 'com.google.mlkit:face-mesh-detection:16.0.0-beta1' }
دستورالعمل های تصویر ورودی
تصاویر باید در فاصله ~2 متری (~7 فوت) از دوربین دستگاه گرفته شوند، به طوری که چهره ها به اندازه کافی بزرگ باشند تا بتوان بهینه مش چهره را تشخیص داد. به طور کلی، هرچه صورت بزرگتر باشد، تشخیص مش چهره بهتر است.
صورت باید رو به دوربین باشد و حداقل نیمی از صورت قابل مشاهده باشد. هر جسم بزرگی بین صورت و دوربین ممکن است باعث کاهش دقت شود.
اگر میخواهید چهرهها را در یک برنامه بلادرنگ شناسایی کنید، باید ابعاد کلی تصویر ورودی را نیز در نظر بگیرید. تصاویر کوچکتر را میتوان سریعتر پردازش کرد، بنابراین ثبت تصاویر با وضوح پایینتر، تأخیر را کاهش میدهد. با این حال، الزامات دقت بالا را در نظر داشته باشید و اطمینان حاصل کنید که صورت سوژه تا حد امکان تصویر را اشغال می کند.
آشکارساز مش چهره را پیکربندی کنید
اگر میخواهید هر یک از تنظیمات پیشفرض آشکارساز چهره مش را تغییر دهید، آن تنظیمات را با یک شی FaceMeshDetectorOptions مشخص کنید. می توانید تنظیمات زیر را تغییر دهید:
setUseCase
BOUNDING_BOX_ONLY
: فقط یک جعبه محدود کننده برای مش چهره شناسایی شده ارائه می دهد. این سریعترین آشکارساز چهره است، اما دارای محدودیت برد است (چهره ها باید در فاصله 2 متری یا ~ 7 فوتی دوربین باشند).FACE_MESH
(گزینه پیشفرض): یک کادر محدود و اطلاعات مش اضافی (468 نقطه سه بعدی و اطلاعات مثلث) را ارائه میکند. در مقایسه با موارد استفادهBOUNDING_BOX_ONLY
، تأخیر تا 15٪ افزایش مییابد که در Pixel 3 اندازهگیری میشود.
به عنوان مثال:
کاتلین
val defaultDetector = FaceMeshDetection.getClient( FaceMeshDetectorOptions.DEFAULT_OPTIONS) val boundingBoxDetector = FaceMeshDetection.getClient( FaceMeshDetectorOptions.Builder() .setUseCase(UseCase.BOUNDING_BOX_ONLY) .build() )
جاوا
FaceMeshDetector defaultDetector = FaceMeshDetection.getClient( FaceMeshDetectorOptions.DEFAULT_OPTIONS); FaceMeshDetector boundingBoxDetector = FaceMeshDetection.getClient( new FaceMeshDetectorOptions.Builder() .setUseCase(UseCase.BOUNDING_BOX_ONLY) .build() );
تصویر ورودی را آماده کنید
برای شناسایی چهرهها در یک تصویر، یک شی 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
همراه با درجه چرخش نمایش داده می شود.
تصویر را پردازش کنید
ارسال تصویر به روش process
:
کاتلین
val result = detector.process(image) .addOnSuccessListener { result -> // Task completed successfully // … } .addOnFailureListener { e -> // Task failed with an exception // … }
جاوا
Task<List<FaceMesh>> result = detector.process(image) .addOnSuccessListener( new OnSuccessListener<List<FaceMesh>>() { @Override public void onSuccess(List<FaceMesh> result) { // Task completed successfully // … } }) .addOnFailureListener( new OnFailureListener() { @Override Public void onFailure(Exception e) { // Task failed with an exception // … } });
اطلاعاتی در مورد مش چهره شناسایی شده دریافت کنید
اگر چهرهای در تصویر شناسایی شود، فهرستی از اشیاء FaceMesh
به شنونده موفق ارسال میشود. هر FaceMesh
نشان دهنده چهره ای است که در تصویر شناسایی شده است. برای هر فیس مش، می توانید مختصات مرزی آن را در تصویر ورودی و همچنین هر اطلاعات دیگری را که آشکارساز مش چهره را برای یافتن آن پیکربندی کرده اید، دریافت کنید.
کاتلین
for (faceMesh in faceMeshs) { val bounds: Rect = faceMesh.boundingBox() // Gets all points val faceMeshpoints = faceMesh.allPoints for (faceMeshpoint in faceMeshpoints) { val index: Int = faceMeshpoints.index() val position = faceMeshpoint.position } // Gets triangle info val triangles: List<Triangle<FaceMeshPoint>> = faceMesh.allTriangles for (triangle in triangles) { // 3 Points connecting to each other and representing a triangle area. val connectedPoints = triangle.allPoints() } }
جاوا
for (FaceMesh faceMesh : faceMeshs) { Rect bounds = faceMesh.getBoundingBox(); // Gets all points List<FaceMeshPoint> faceMeshpoints = faceMesh.getAllPoints(); for (FaceMeshPoint faceMeshpoint : faceMeshpoints) { int index = faceMeshpoints.getIndex(); PointF3D position = faceMeshpoint.getPosition(); } // Gets triangle info List<Triangle<FaceMeshPoint>> triangles = faceMesh.getAllTriangles(); for (Triangle<FaceMeshPoint> triangle : triangles) { // 3 Points connecting to each other and representing a triangle area. List<FaceMeshPoint> connectedPoints = triangle.getAllPoints(); } }
جز در مواردی که غیر از این ذکر شده باشد،محتوای این صفحه تحت مجوز Creative Commons Attribution 4.0 License است. نمونه کدها نیز دارای مجوز Apache 2.0 License است. برای اطلاع از جزئیات، به خطمشیهای سایت Google Developers مراجعه کنید. جاوا علامت تجاری ثبتشده Oracle و/یا شرکتهای وابسته به آن است.
تاریخ آخرین بهروزرسانی 2024-09-21 بهوقت ساعت هماهنگ جهانی.