از کیت ML استفاده کنید تا به راحتی ویژگی های تقسیم بندی موضوع را به برنامه خود اضافه کنید.
ویژگی | جزئیات |
---|---|
نام Sdk | play-services-mlkit-subject-segmentation |
پیاده سازی | Unbundled: مدل به صورت پویا با استفاده از خدمات Google Play دانلود می شود. |
تاثیر اندازه برنامه | 200 کیلوبایت افزایش حجم |
زمان اولیه سازی | کاربران ممکن است قبل از اولین استفاده منتظر باشند تا مدل دانلود شود. |
آن را امتحان کنید
- با برنامه نمونه بازی کنید تا نمونه استفاده از این API را ببینید.
قبل از شروع
- در فایل
build.gradle
در سطح پروژه خود، مطمئن شوید که مخزن Maven Google را در هر دو بخشbuildscript
وallprojects
خود قرار دهید. - وابستگی را برای کتابخانه تقسیمبندی موضوع ML Kit به فایل gradle سطح برنامه ماژول خود اضافه کنید، که معمولا
app/build.gradle
است:
dependencies {
implementation 'com.google.android.gms:play-services-mlkit-subject-segmentation:16.0.0-beta1'
}
همانطور که در بالا ذکر شد این مدل توسط سرویس های Google Play ارائه می شود. می توانید برنامه خود را طوری پیکربندی کنید که پس از نصب برنامه از Play Store، مدل را به طور خودکار در دستگاه دانلود کند. برای انجام این کار، اعلان زیر را به فایل AndroidManifest.xml
برنامه خود اضافه کنید:
<application ...>
...
<meta-data
android:name="com.google.mlkit.vision.DEPENDENCIES"
android:value="subject_segment" >
<!-- To use multiple models: android:value="subject_segment,model2,model3" -->
</application>
همچنین میتوانید صراحتاً در دسترس بودن مدل را بررسی کنید و از طریق سرویسهای Google Play با ModuleInstallClient API درخواست دانلود کنید.
اگر دانلودهای مدل زمان نصب را فعال نکنید یا درخواست دانلود صریح نداشته باشید، اولین باری که قطعهساز را اجرا میکنید، مدل دانلود میشود. درخواستهایی که قبل از تکمیل دانلود ارائه میکنید، نتیجهای ندارند.
1. تصویر ورودی را آماده کنید
برای انجام بخش بندی روی یک تصویر، یک شی InputImage
از Bitmap
، media.Image
، ByteBuffer
، آرایه بایت یا یک فایل روی دستگاه ایجاد کنید.
می توانید یک شی 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
همراه با درجه چرخش نمایش داده می شود.
2. یک نمونه از SubjectSegmenter ایجاد کنید
گزینه های قطعه ساز را تعریف کنید
برای بخش بندی تصویر خود، ابتدا یک نمونه از SubjectSegmenterOptions
به صورت زیر ایجاد کنید:
کاتلین
val options = SubjectSegmenterOptions.Builder() // enable options .build()
جاوا
SubjectSegmenterOptions options = new SubjectSegmenterOptions.Builder() // enable options .build();
در اینجا جزئیات هر گزینه آورده شده است:
ماسک اعتماد به نفس پیش زمینه
ماسک اطمینان پیش زمینه به شما امکان می دهد سوژه پیش زمینه را از پس زمینه تشخیص دهید.
فراخوانی enableForegroundConfidenceMask()
در گزینهها به شما امکان میدهد بعداً با فراخوانی getForegroundMask()
در شیء SubjectSegmentationResult
که پس از پردازش تصویر برگردانده میشود، ماسک پیشزمینه را بازیابی کنید.
کاتلین
val options = SubjectSegmenterOptions.Builder() .enableForegroundConfidenceMask() .build()
جاوا
SubjectSegmenterOptions options = new SubjectSegmenterOptions.Builder() .enableForegroundConfidenceMask() .build();
نقشه بیت پیش زمینه
به طور مشابه، شما همچنین می توانید یک بیت مپ از موضوع پیش زمینه دریافت کنید.
فراخوانی enableForegroundBitmap()
در گزینه ها به شما این امکان را می دهد که بعداً با فراخوانی getForegroundBitmap()
در شیء SubjectSegmentationResult
که پس از پردازش تصویر برگردانده شده است، بیت مپ پیش زمینه را بازیابی کنید.
کاتلین
val options = SubjectSegmenterOptions.Builder() .enableForegroundBitmap() .build()
جاوا
SubjectSegmenterOptions options = new SubjectSegmenterOptions.Builder() .enableForegroundBitmap() .build();
ماسک اعتماد به نفس چند موضوعی
مانند گزینه های پیش زمینه، می توانید از SubjectResultOptions
برای فعال کردن ماسک اطمینان برای هر موضوع پیش زمینه به صورت زیر استفاده کنید:
کاتلین
val subjectResultOptions = SubjectSegmenterOptions.SubjectResultOptions.Builder() .enableConfidenceMask() .build() val options = SubjectSegmenterOptions.Builder() .enableMultipleSubjects(subjectResultOptions) .build()
جاوا
SubjectResultOptions subjectResultOptions = new SubjectSegmenterOptions.SubjectResultOptions.Builder() .enableConfidenceMask() .build() SubjectSegmenterOptions options = new SubjectSegmenterOptions.Builder() .enableMultipleSubjects(subjectResultOptions) .build()
بیت مپ چند موضوعی
و به طور مشابه، می توانید بیت مپ را برای هر موضوع فعال کنید:
کاتلین
val subjectResultOptions = SubjectSegmenterOptions.SubjectResultOptions.Builder() .enableSubjectBitmap() .build() val options = SubjectSegmenterOptions.Builder() .enableMultipleSubjects(subjectResultOptions) .build()
جاوا
SubjectResultOptions subjectResultOptions = new SubjectSegmenterOptions.SubjectResultOptions.Builder() .enableSubjectBitmap() .build() SubjectSegmenterOptions options = new SubjectSegmenterOptions.Builder() .enableMultipleSubjects(subjectResultOptions) .build()
قطعه ساز موضوع را ایجاد کنید
هنگامی که گزینه های SubjectSegmenterOptions
را مشخص کردید، یک نمونه SubjectSegmenter
ایجاد کنید که getClient()
فراخوانی می کند و گزینه ها را به عنوان پارامتر ارسال می کند:
کاتلین
val segmenter = SubjectSegmentation.getClient(options)
جاوا
SubjectSegmenter segmenter = SubjectSegmentation.getClient(options);
3. یک تصویر را پردازش کنید
آبجکت InputImage
آماده شده را به روش process
SubjectSegmenter
ارسال کنید:
کاتلین
segmenter.process(inputImage) .addOnSuccessListener { result -> // Task completed successfully // ... } .addOnFailureListener { e -> // Task failed with an exception // ... }
جاوا
segmenter.process(inputImage) .addOnSuccessListener(new OnSuccessListener() { @Override public void onSuccess(SubjectSegmentationResult result) { // Task completed successfully // ... } }) .addOnFailureListener(new OnFailureListener() { @Override public void onFailure(@NonNull Exception e) { // Task failed with an exception // ... } });
4. نتیجه بخش بندی موضوع را دریافت کنید
ماسک های پیش زمینه و بیت مپ ها را بازیابی کنید
پس از پردازش، می توانید ماسک پیش زمینه تصویر خود را با فراخوانی getForegroundConfidenceMask()
به صورت زیر بازیابی کنید:
کاتلین
val colors = IntArray(image.width * image.height) val foregroundMask = result.foregroundConfidenceMask for (i in 0 until image.width * image.height) { if (foregroundMask[i] > 0.5f) { colors[i] = Color.argb(128, 255, 0, 255) } } val bitmapMask = Bitmap.createBitmap( colors, image.width, image.height, Bitmap.Config.ARGB_8888 )
جاوا
int[] colors = new int[image.getWidth() * image.getHeight()]; FloatBuffer foregroundMask = result.getForegroundConfidenceMask(); for (int i = 0; i < image.getWidth() * image.getHeight(); i++) { if (foregroundMask.get() > 0.5f) { colors[i] = Color.argb(128, 255, 0, 255); } } Bitmap bitmapMask = Bitmap.createBitmap( colors, image.getWidth(), image.getHeight(), Bitmap.Config.ARGB_8888 );
همچنین می توانید یک بیت مپ از پیش زمینه تصویری که getForegroundBitmap()
را فراخوانی می کند، بازیابی کنید:
کاتلین
val foregroundBitmap = result.foregroundBitmap
جاوا
Bitmap foregroundBitmap = result.getForegroundBitmap();
ماسک ها و بیت مپ ها را برای هر موضوع بازیابی کنید
به طور مشابه، می توانید با فراخوانی getConfidenceMask()
در هر موضوع، ماسک را برای موضوعات تقسیم شده بازیابی کنید:
کاتلین
val subjects = result.subjects val colors = IntArray(image.width * image.height) for (subject in subjects) { val mask = subject.confidenceMask for (i in 0 until subject.width * subject.height) { val confidence = mask[i] if (confidence > 0.5f) { colors[image.width * (subject.startY - 1) + subject.startX] = Color.argb(128, 255, 0, 255) } } } val bitmapMask = Bitmap.createBitmap( colors, image.width, image.height, Bitmap.Config.ARGB_8888 )
جاوا
Listsubjects = result.getSubjects(); int[] colors = new int[image.getWidth() * image.getHeight()]; for (Subject subject : subjects) { FloatBuffer mask = subject.getConfidenceMask(); for (int i = 0; i < subject.getWidth() * subject.getHeight(); i++) { float confidence = mask.get(); if (confidence > 0.5f) { colors[width * (subject.getStartY() - 1) + subject.getStartX()] = Color.argb(128, 255, 0, 255); } } } Bitmap bitmapMask = Bitmap.createBitmap( colors, image.width, image.height, Bitmap.Config.ARGB_8888 );
همچنین می توانید به بیت مپ هر موضوع تقسیم شده به صورت زیر دسترسی داشته باشید:
کاتلین
val bitmaps = mutableListOf() for (subject in subjects) { bitmaps.add(subject.bitmap) }
جاوا
Listbitmaps = new ArrayList<>(); for (Subject subject : subjects) { bitmaps.add(subject.getBitmap()); }
نکاتی برای بهبود عملکرد
برای هر جلسه برنامه، استنتاج اول به دلیل مقداردهی اولیه مدل، اغلب کندتر از استنتاج های بعدی است. اگر تأخیر کم حیاتی است، پیش از موعد یک استنتاج «ساختگی» را فراخوانی کنید.
کیفیت نتایج شما به کیفیت تصویر ورودی بستگی دارد:
- برای اینکه ML Kit به یک نتیجه تقسیم بندی دقیق برسد، تصویر باید حداقل 512x512 پیکسل باشد.
- فوکوس ضعیف تصویر نیز می تواند بر دقت تأثیر بگذارد. اگر نتایج قابل قبولی دریافت نکردید، از کاربر بخواهید که تصویر را دوباره بگیرد.