شما میتوانید از ML Kit برای برچسبگذاری اشیاء شناساییشده در یک تصویر استفاده کنید. مدل پیشفرض ارائهشده با ML Kit از بیش از ۴۰۰ برچسب مختلف پشتیبانی میکند.
| ویژگی | بدون دسته بندی | بستهبندی شده |
|---|---|---|
| پیادهسازی | مدل به صورت پویا از طریق سرویسهای گوگل پلی دانلود میشود. | مدل به صورت ایستا در زمان ساخت به مدل شما متصل است. |
| اندازه برنامه | حدود ۲۰۰ کیلوبایت افزایش حجم. | حدود ۵.۷ مگابایت افزایش حجم. |
| زمان اولیه سازی | ممکن است لازم باشد قبل از اولین استفاده، منتظر دانلود مدل باشید. | مدل فوراً موجود است |
امتحانش کن.
- برای مشاهدهی نحوهی استفاده از این API، با برنامهی نمونه کار کنید.
قبل از اینکه شروع کنی
در فایل
build.gradleسطح پروژه خود، مطمئن شوید که مخزن Maven گوگل را هم در بخشهایbuildscriptو همallprojectsخود وارد کردهاید.وابستگیهای کتابخانههای اندروید ML Kit را به فایل gradle سطح برنامه ماژول خود که معمولاً
app/build.gradleاست، اضافه کنید. بر اساس نیاز خود، یکی از وابستگیهای زیر را انتخاب کنید:برای باندل کردن مدل با اپلیکیشن خود:
dependencies { // ... // Use this dependency to bundle the model with your app implementation 'com.google.mlkit:image-labeling:17.0.9' }برای استفاده از مدل در سرویسهای گوگل پلی:
dependencies { // ... // Use this dependency to use the dynamically downloaded model in Google Play Services implementation 'com.google.android.gms:play-services-mlkit-image-labeling:16.0.8' }اگر تصمیم دارید از مدل در سرویسهای گوگل پلی استفاده کنید ، میتوانید برنامه خود را طوری پیکربندی کنید که پس از نصب برنامه از فروشگاه پلی استور، مدل را به طور خودکار روی دستگاه دانلود کند. برای انجام این کار، اعلان زیر را به فایل
AndroidManifest.xmlبرنامه خود اضافه کنید:<application ...> ... <meta-data android:name="com.google.mlkit.vision.DEPENDENCIES" android:value="ica" > <!-- To use multiple models: android:value="ica,model2,model3" --> </application>همچنین میتوانید به صراحت در دسترس بودن مدل را بررسی کرده و از طریق API ModuleInstallClient سرویسهای گوگل پلی درخواست دانلود دهید.
اگر دانلود مدل در زمان نصب را فعال نکنید یا درخواست دانلود صریح ندهید، مدل در اولین باری که برچسبگذار را اجرا میکنید دانلود میشود. درخواستهایی که قبل از اتمام دانلود انجام میدهید، نتیجهای ندارند.
حالا آمادهاید تا تصاویر را برچسبگذاری کنید.
۱. تصویر ورودی را آماده کنید
یک شیءInputImage از تصویر خود ایجاد کنید. برچسبگذار تصویر زمانی که از Bitmap یا اگر از camera2 API استفاده میکنید، از YUV_420_888 media.Image استفاده میکنید، سریعتر اجرا میشود، که در صورت امکان توصیه میشوند. شما میتوانید یک شیء InputImage را از منابع مختلفی ایجاد کنید که هر کدام در زیر توضیح داده شدهاند.
استفاده از یک media.Image
برای ایجاد یک شیء InputImage از یک شیء media.Image ، مانند زمانی که از دوربین یک دستگاه تصویر میگیرید، شیء media.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 به همراه درجه چرخش نمایش داده میشود.
۲. پیکربندی و اجرای برچسبگذار تصویر
برای برچسبگذاری اشیاء در یک تصویر، شیءInputImage را به متد process در ImageLabeler ارسال کنید.ابتدا، یک نمونه از
ImageLabelerدریافت کنید.اگر میخواهید از برچسبگذار تصویر روی دستگاه استفاده کنید، عبارت زیر را وارد کنید:
کاتلین
// To use default options: val labeler = ImageLabeling.getClient(ImageLabelerOptions.DEFAULT_OPTIONS) // Or, to set the minimum confidence required: // val options = ImageLabelerOptions.Builder() // .setConfidenceThreshold(0.7f) // .build() // val labeler = ImageLabeling.getClient(options)
جاوا
// To use default options: ImageLabeler labeler = ImageLabeling.getClient(ImageLabelerOptions.DEFAULT_OPTIONS); // Or, to set the minimum confidence required: // ImageLabelerOptions options = // new ImageLabelerOptions.Builder() // .setConfidenceThreshold(0.7f) // .build(); // ImageLabeler labeler = ImageLabeling.getClient(options);
- سپس، تصویر را به متد
process()ارسال کنید:
کاتلین
labeler.process(image) .addOnSuccessListener { labels -> // Task completed successfully // ... } .addOnFailureListener { e -> // Task failed with an exception // ... }
جاوا
labeler.process(image) .addOnSuccessListener(new OnSuccessListener<List<ImageLabel>>() { @Override public void onSuccess(List<ImageLabel> labels) { // Task completed successfully // ... } }) .addOnFailureListener(new OnFailureListener() { @Override public void onFailure(@NonNull Exception e) { // Task failed with an exception // ... } });
۳. اطلاعات مربوط به اشیاء برچسبگذاری شده را دریافت کنید
اگر عملیات برچسبگذاری تصویر با موفقیت انجام شود، فهرستی از اشیاءImageLabel به شنونده موفقیت ارسال میشود. هر شیء ImageLabel نشان دهنده چیزی است که در تصویر برچسبگذاری شده است. مدل پایه از بیش از ۴۰۰ برچسب مختلف پشتیبانی میکند. میتوانید توضیحات متنی هر برچسب، فهرستبندی بین تمام برچسبهای پشتیبانی شده توسط مدل و امتیاز اطمینان تطابق را دریافت کنید. به عنوان مثال: کاتلین
for (label in labels) { val text = label.text val confidence = label.confidence val index = label.index }
جاوا
for (ImageLabel label : labels) { String text = label.getText(); float confidence = label.getConfidence(); int index = label.getIndex(); }
نکاتی برای بهبود عملکرد در زمان واقعی
اگر میخواهید تصاویر را در یک برنامهی بلادرنگ برچسبگذاری کنید، برای دستیابی به بهترین نرخ فریم، این دستورالعملها را دنبال کنید:
- اگر از API
Cameraیاcamera2استفاده میکنید، فراخوانیهای throttle به برچسبگذار تصویر را متوقف کنید. اگر در حین اجرای برچسبگذار تصویر، یک فریم ویدیویی جدید در دسترس قرار گرفت، فریم را رها کنید. برای مثال، به کلاسVisionProcessorBaseدر برنامه نمونه شروع سریع مراجعه کنید. - اگر از API
CameraXاستفاده میکنید، مطمئن شوید که استراتژی فشار معکوس (backpressure strategy) روی مقدار پیشفرض خودImageAnalysis.STRATEGY_KEEP_ONLY_LATESTتنظیم شده است. این تضمین میکند که فقط یک تصویر در هر زمان برای تجزیه و تحلیل تحویل داده میشود. اگر تصاویر بیشتری هنگام مشغول بودن تحلیلگر تولید شوند، به طور خودکار حذف میشوند و برای تحویل در صف قرار نمیگیرند. پس از بسته شدن تصویر در حال تجزیه و تحلیل با فراخوانی ImageProxy.close()، آخرین تصویر بعدی تحویل داده میشود. - اگر از خروجی برچسبگذار تصویر برای همپوشانی گرافیکها روی تصویر ورودی استفاده میکنید، ابتدا نتیجه را از ML Kit دریافت کنید، سپس تصویر و همپوشانی را در یک مرحله رندر کنید. این کار فقط یک بار برای هر فریم ورودی روی سطح نمایشگر رندر میشود. برای مثال به کلاسهای
CameraSourcePreviewوGraphicOverlayدر برنامه نمونه شروع سریع مراجعه کنید. - اگر از API دوربین ۲ استفاده میکنید، تصاویر را با فرمت
ImageFormat.YUV_420_888ضبط کنید. اگر از API دوربین قدیمیتر استفاده میکنید، تصاویر را با فرمتImageFormat.NV21ضبط کنید.