میتوانید از ML Kit برای برچسبگذاری اشیای شناساییشده در تصویر استفاده کنید. مدل پیشفرضی که با ML Kit ارائه میشود از بیشاز ۴۰۰ برچسب مختلف پشتیبانی میکند.
| ویژگی | بستهبندینشده | موجود در بستهبندی |
|---|---|---|
| پیادهسازی | مدل بهطور پویا ازطریق «خدمات Google Play» بارگیری میشود. | مدل در زمان ساخت بهطور ایستا به شما پیوند داده میشود. |
| حجم برنامه | حدود ۲۰۰ کیلوبایت افزایش اندازه. | حدود ۵٫۷ مگابایت افزایش اندازه. |
| زمان مقداردهی اولیه | ممکن است لازم باشد قبلاز اولین استفاده، منتظر بمانید تا مدل بارگیری شود. | مدل بلافاصله دردسترس است |
امتحان کنید
- با برنامه نمونه کار کنید تا نمونهای از کاربرد این API را ببینید.
قبلاز شروع
در فایل
build.gradleسطح پروژه، حتماً مخزن Maven مربوط به Google را در هر دو بخشbuildscriptوallprojectsاضافه کنید.وابستگیهای کتابخانههای Android «کیت یادگیری ماشین» را به فایل gradle سطح برنامه ماژولتان اضافه کنید. این فایل معمولاً
app/build.gradleاست. یکی از وابستگیهای زیر را براساس نیازهایتان انتخاب کنید:برای بستهبندی مدل با برنامهتان:
dependencies { // ... // Use this dependency to bundle the model with your app implementation 'com.google.mlkit:image-labeling:17.0.9' }برای استفاده از مدل در «خدمات Google Play»:
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' }اگر تصمیم بگیرید از مدل در «خدمات Google Play» استفاده کنید، میتوانید برنامهتان را پیکربندی کنید تا پساز نصب برنامهتان از «فروشگاه Play»، مدل را بهطور خودکار در دستگاه بارگیری کند. برای انجام این کار، اظهارنامه زیر را به فایل
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>همچنین میتوانید بهطور صریح دردسترس بودن مدل را بررسی کنید و ازطریق ModuleInstallClient API در خدمات Google Play درخواست بارگیری کنید.
اگر بارگیری مدل در زمان نصب را فعال نکنید یا درخواست بارگیری صریح نکنید، مدل اولین باری که برچسبزن را اجرا میکنید بارگیری میشود. درخواستهایی که قبلاز تکمیل بارگیری ارسال میکنید نتیجهای دربر نخواهد داشت.
اکنون آماده برچسبگذاری تصاویر هستید.
۱. آماده کردن تصویر ورودی
از تصویرتان شیءInputImage بسازید.
برچسبزن تصویر زمانی سریعترین عملکرد را دارد که از Bitmap یا، درصورت استفاده از
camera2 API، از YUV_420_888 media.Image استفاده کنید که درصورت امکان
توصیه میشود.
میتوانید شیء InputImage را از منابع مختلف ایجاد کنید، هرکدام در زیر توضیح داده شده است.
استفاده از media.Image
برای ایجاد شیء InputImage
از شیء media.Image، مثلاً وقتی تصویری را از
دوربین دستگاه ضبط میکنید، شیء media.Image و چرخش تصویر را به
InputImage.fromMediaImage() ارسال کنید.
اگر از کتابخانه
CameraX استفاده میکنید، کلاسهای OnImageCapturedListener و
ImageAnalysis.Analyzer مقدار چرخش را برای شما
محاسبه میکنند.
Kotlin
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 // ... } } }
اگر از کتابخانه دوربینی استفاده نمیکنید که درجه چرخش تصویر را به شما بدهد، میتوانید آن را از درجه چرخش دستگاه و جهت حسگر دوربین در دستگاه محاسبه کنید:
Kotlin
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() ارسال کنید:
Kotlin
val image = InputImage.fromMediaImage(mediaImage, rotation)
Java
InputImage image = InputImage.fromMediaImage(mediaImage, rotation);
استفاده از URI فایل
برای ایجاد شیء InputImage
از URI فایل، بافت برنامه و URI فایل را به
InputImage.fromFilePath() ارسال کنید. این کار زمانی مفید است که
از ACTION_GET_CONTENT intent برای درخواست از کاربر برای انتخاب
تصویری از برنامه گالریاش استفاده میکنید.
Kotlin
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 را با میانگیر یا آرایه، بههمراه ارتفاع، عرض، قالب کدبندی رنگ، و درجه چرخش تصویر ایجاد کنید:
Kotlin
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، اعلان زیر را انجام دهید:
Kotlin
val image = InputImage.fromBitmap(bitmap, 0)
Java
InputImage image = InputImage.fromBitmap(bitmap, rotationDegree);
تصویر با شیء Bitmap بههمراه درجه چرخش نشان داده میشود.
۲. پیکربندی و اجرای برچسبزن تصویر
برای برچسبگذاری اشیاء در تصویر، شیءInputImage را به
روش process ImageLabeler ارسال کنید.
ابتدا، نمونهای از
ImageLabelerرا دریافت کنید.اگر میخواهید از برچسبزن تصویر دروندستگاهی استفاده کنید، اظهارنامه زیر را ارائه دهید:
Kotlin
// 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()ارسال کنید:
Kotlin
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 نشاندهنده چیزی است که در تصویر برچسبگذاری شده است. مدل پایه از بیشاز ۴۰۰ برچسب مختلف پشتیبانی میکند.
میتوانید شرح نوشتاری هر برچسب، نمایه در میان همه برچسبهای پشتیبانیشده توسط
مدل، و امتیاز اطمینان مطابقت را دریافت کنید. برای مثال:
Kotlin
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(); }
نکاتی برای بهبود عملکرد همزمان
اگر میخواهید تصاویر را در یک برنامه همزمان برچسبگذاری کنید، این دستورالعملها را دنبال کنید تا به بهترین نرخ فریم دست یابید:
- اگر از میانای برنامهسازی کاربردی
Cameraیاcamera2استفاده میکنید، فراخوانیهای برچسبزن تصویر را محدود کنید. اگر فریم ویدیو جدیدی در حین اجرای برچسبزن تصویر دردسترس قرار گرفت، فریم را رها کنید. برای دیدن نمونه، کلاسVisionProcessorBaseرا در برنامه نمونه شروع سریع ببینید. - اگر از
CameraXAPI استفاده میکنید، مطمئن شوید که استراتژی فشار برگشتی روی مقدار پیشفرض آنImageAnalysis.STRATEGY_KEEP_ONLY_LATESTتنظیم شده باشد. این کار تضمین میکند که در هر بار فقط یک تصویر برای تجزیهوتحلیل ارسال شود. اگر وقتی تحلیلگر مشغول است تصاویر بیشتری تولید شود، این تصاویر بهطور خودکار حذف میشوند و برای تحویل در صف قرار نمیگیرند. وقتی تصویری که درحال تجزیهوتحلیل است با فراخوانی ImageProxy.close() بسته شود، تصویر جدید بعدی ارائه خواهد شد. - اگر از خروجی برچسبزن تصویر برای همپوشانی گرافیک روی تصویر ورودی استفاده میکنید، ابتدا نتیجه را از ML Kit دریافت کنید، سپس تصویر و همپوشانی را در یک مرحله رندر کنید. این مورد فقط یکبار برای هر فریم ورودی
در سطح نمایشگر پرداز میشود. برای دیدن نمونه، کلاسهای
CameraSourcePreviewوGraphicOverlayرا در برنامه نمونه شروع سریع ببینید. - اگر از Camera2 API استفاده میکنید، تصاویر را در قالب
ImageFormat.YUV_420_888ضبط کنید. اگر از Camera API قدیمیتر استفاده میکنید، تصاویر را در قالبImageFormat.NV21ضبط کنید.