شما می توانید از کیت ML برای شناسایی موجودیت ها در یک تصویر و برچسب گذاری آنها استفاده کنید. این API از طیف گسترده ای از مدل های طبقه بندی تصاویر سفارشی پشتیبانی می کند. لطفاً برای راهنمایی در مورد الزامات سازگاری مدل، مکان یافتن مدل های از پیش آموزش دیده و نحوه آموزش مدل های خود به مدل های سفارشی با کیت ML مراجعه کنید.
دو راه برای ادغام برچسبگذاری تصویر با مدلهای سفارشی وجود دارد: با بستهبندی خط لوله بهعنوان بخشی از برنامه خود، یا با استفاده از خط لوله جداشده که به خدمات Google Play بستگی دارد. اگر خط لوله جداشده را انتخاب کنید، برنامه شما کوچکتر خواهد شد. برای جزئیات به جدول زیر مراجعه کنید.
همراه | تفکیک شده | |
---|---|---|
نام کتابخانه | com.google.mlkit:image-labeling-custom | com.google.android.gms:play-services-mlkit-image-labeling-custom |
پیاده سازی | Pipeline به صورت ایستا به برنامه شما در زمان ساخت مرتبط است. | Pipeline به صورت پویا از طریق خدمات Google Play دانلود می شود. |
اندازه برنامه | حدود 3.8 مگابایت افزایش حجم. | افزایش حجم حدود 200 کیلوبایت |
زمان اولیه سازی | خط لوله بلافاصله در دسترس است. | ممکن است قبل از استفاده برای اولین بار منتظر بمانید تا خط لوله بارگیری شود. |
مرحله چرخه عمر API | در دسترس بودن عمومی (GA) | بتا |
دو راه برای ادغام یک مدل سفارشی وجود دارد: مدل را با قرار دادن آن در پوشه دارایی برنامه خود دسته بندی کنید یا به صورت پویا آن را از Firebase دانلود کنید. جدول زیر این دو گزینه را با هم مقایسه می کند.
مدل همراه | مدل میزبانی شده |
---|---|
این مدل بخشی از APK برنامه شما است که اندازه آن را افزایش می دهد. | مدل بخشی از APK شما نیست. با آپلود در Firebase Machine Learning میزبانی می شود. |
این مدل بلافاصله در دسترس است، حتی زمانی که دستگاه اندروید آفلاین است | مدل در صورت تقاضا دانلود می شود |
بدون نیاز به پروژه Firebase | به پروژه Firebase نیاز دارد |
برای بهروزرسانی مدل، باید برنامه خود را دوباره منتشر کنید | به روز رسانی مدل را بدون انتشار مجدد برنامه خود فشار دهید |
بدون تست A/B داخلی | تست آسان A/B با Firebase Remote Config |
آن را امتحان کنید
- برای مثالی از استفاده از مدل همراه، برنامه راه اندازی سریع چشم انداز و برای مثال استفاده از مدل میزبانی شده ، برنامه شروع سریع automl را ببینید.
قبل از شروع
در فایل
build.gradle
در سطح پروژه خود، مطمئن شوید که مخزن Maven Google را در هر دو بخشbuildscript
وallprojects
خود قرار دهید.وابستگی های کتابخانه های اندروید ML Kit را به فایل gradle سطح برنامه ماژول خود اضافه کنید، که معمولا
app/build.gradle
است. یکی از وابستگی های زیر را بر اساس نیاز خود انتخاب کنید:برای بسته بندی خط لوله با برنامه شما:
dependencies { // ... // Use this dependency to bundle the pipeline with your app implementation 'com.google.mlkit:image-labeling-custom:17.0.3' }
برای استفاده از خط لوله در خدمات Google Play:
dependencies { // ... // Use this dependency to use the dynamically downloaded pipeline in Google Play Services implementation 'com.google.android.gms:play-services-mlkit-image-labeling-custom:16.0.0-beta5' }
اگر انتخاب کردید از خط لوله در خدمات Google Play استفاده کنید ، میتوانید برنامه خود را طوری پیکربندی کنید که پس از نصب برنامه از فروشگاه Play، خط لوله را بهطور خودکار در دستگاه دانلود کنید. برای انجام این کار، اعلان زیر را به فایل
AndroidManifest.xml
برنامه خود اضافه کنید:<application ...> ... <meta-data android:name="com.google.mlkit.vision.DEPENDENCIES" android:value="custom_ica" /> <!-- To use multiple downloads: android:value="custom_ica,download2,download3" --> </application>
همچنین میتوانید صریحاً در دسترس بودن خط لوله را بررسی کنید و از طریق سرویسهای Google Play ModuleInstallClient API درخواست دانلود کنید.
اگر دانلودهای خط لوله زمان نصب را فعال نکنید یا دانلود صریح درخواست نکنید، اولین باری که برچسبزن را اجرا میکنید خط لوله دانلود میشود. درخواستهایی که قبل از تکمیل دانلود ارائه میکنید، نتیجهای ندارند.
اگر میخواهید مدلی را به صورت پویا از Firebase دانلود کنید، وابستگی
linkFirebase
را اضافه کنید:برای دانلود پویا یک مدل از Firebase، وابستگی
linkFirebase
را اضافه کنید:dependencies { // ... // Image labeling feature with model downloaded from Firebase implementation 'com.google.mlkit:image-labeling-custom:17.0.3' // Or use the dynamically downloaded pipeline in Google Play Services // implementation 'com.google.android.gms:play-services-mlkit-image-labeling-custom:16.0.0-beta5' implementation 'com.google.mlkit:linkfirebase:17.0.0' }
اگر می خواهید مدلی را دانلود کنید ، مطمئن شوید که Firebase را به پروژه اندروید خود اضافه کرده اید ، اگر قبلاً این کار را انجام نداده اید. هنگامی که مدل را بسته بندی می کنید، این مورد نیاز نیست.
1. مدل را بارگذاری کنید
یک منبع مدل محلی را پیکربندی کنید
برای بستهبندی مدل با برنامهتان:
فایل مدل (معمولاً به
.tflite
یا.lite
ختم می شود) درassets/
پوشه برنامه خود کپی کنید. (شاید لازم باشد ابتدا با کلیک راست بر رویapp/
پوشه، سپس روی New > Folder > Assets Folder، پوشه را ایجاد کنید.)سپس موارد زیر را به فایل
build.gradle
برنامه خود اضافه کنید تا مطمئن شوید که Gradle فایل مدل را هنگام ساخت برنامه فشرده نمی کند:android { // ... aaptOptions { noCompress "tflite" // or noCompress "lite" } }
فایل مدل در بسته برنامه گنجانده شده و به عنوان دارایی خام در اختیار ML Kit قرار خواهد گرفت.
شی
LocalModel
را ایجاد کنید، مسیر فایل مدل را مشخص کنید:کاتلین
val localModel = LocalModel.Builder() .setAssetFilePath("model.tflite") // or .setAbsoluteFilePath(absolute file path to model file) // or .setUri(URI to model file) .build()
جاوا
LocalModel localModel = new LocalModel.Builder() .setAssetFilePath("model.tflite") // or .setAbsoluteFilePath(absolute file path to model file) // or .setUri(URI to model file) .build();
یک منبع مدل میزبانی شده توسط Firebase را پیکربندی کنید
برای استفاده از مدل میزبانی از راه دور، یک شی RemoteModel
توسط FirebaseModelSource
ایجاد کنید و نامی را که به مدل اختصاص داده اید هنگام انتشار آن مشخص کنید:
کاتلین
// Specify the name you assigned in the Firebase console. val remoteModel = CustomRemoteModel .Builder(FirebaseModelSource.Builder("your_model_name").build()) .build()
جاوا
// Specify the name you assigned in the Firebase console. CustomRemoteModel remoteModel = new CustomRemoteModel .Builder(new FirebaseModelSource.Builder("your_model_name").build()) .build();
سپس، با مشخص کردن شرایطی که میخواهید اجازه دانلود را بدهید، کار دانلود مدل را شروع کنید. اگر مدل در دستگاه نباشد، یا اگر نسخه جدیدتری از مدل موجود باشد، این کار به صورت ناهمزمان مدل را از Firebase دانلود میکند:
کاتلین
val downloadConditions = DownloadConditions.Builder() .requireWifi() .build() RemoteModelManager.getInstance().download(remoteModel, downloadConditions) .addOnSuccessListener { // Success. }
جاوا
DownloadConditions downloadConditions = new DownloadConditions.Builder() .requireWifi() .build(); RemoteModelManager.getInstance().download(remoteModel, downloadConditions) .addOnSuccessListener(new OnSuccessListener() { @Override public void onSuccess(@NonNull Task task) { // Success. } });
بسیاری از برنامهها وظیفه دانلود را در کد اولیه خود شروع میکنند، اما شما میتوانید این کار را در هر زمانی قبل از نیاز به استفاده از مدل انجام دهید.
برچسبگذار تصویر را پیکربندی کنید
پس از پیکربندی منابع مدل خود، یک شی ImageLabeler
از یکی از آنها ایجاد کنید.
گزینه های زیر در دسترس هستند:
گزینه ها | |
---|---|
confidenceThreshold | حداقل امتیاز اطمینان برچسب های شناسایی شده اگر تنظیم نشود، از هر آستانه طبقهبندیکنندهای که توسط فراداده مدل مشخص شده است استفاده میشود. اگر مدل حاوی هیچ ابرداده ای نباشد یا ابرداده آستانه طبقه بندی کننده را مشخص نکرده باشد، از آستانه پیش فرض 0.0 استفاده می شود. |
maxResultCount | حداکثر تعداد برچسب برای بازگشت. اگر تنظیم نشود، مقدار پیش فرض 10 استفاده می شود. |
اگر فقط یک مدل باندل محلی دارید، فقط یک برچسب از شی LocalModel
خود ایجاد کنید:
کاتلین
val customImageLabelerOptions = CustomImageLabelerOptions.Builder(localModel) .setConfidenceThreshold(0.5f) .setMaxResultCount(5) .build() val labeler = ImageLabeling.getClient(customImageLabelerOptions)
جاوا
CustomImageLabelerOptions customImageLabelerOptions = new CustomImageLabelerOptions.Builder(localModel) .setConfidenceThreshold(0.5f) .setMaxResultCount(5) .build(); ImageLabeler labeler = ImageLabeling.getClient(customImageLabelerOptions);
اگر یک مدل با میزبانی از راه دور دارید، قبل از اجرای آن باید بررسی کنید که دانلود شده است. با استفاده از متد isModelDownloaded()
مدیر مدل می توانید وضعیت وظیفه دانلود مدل را بررسی کنید.
اگرچه شما فقط باید قبل از اجرای برچسبگذار این موضوع را تأیید کنید، اگر هم یک مدل با میزبانی از راه دور و هم یک مدل بستهبندی محلی دارید، ممکن است این بررسی را هنگام نمونهسازی برچسبکننده تصویر انجام دهید: یک برچسبگذار از مدل راه دور ایجاد کنید اگر دانلود شده است، و در غیر این صورت از مدل محلی.
کاتلین
RemoteModelManager.getInstance().isModelDownloaded(remoteModel) .addOnSuccessListener { isDownloaded -> val optionsBuilder = if (isDownloaded) { CustomImageLabelerOptions.Builder(remoteModel) } else { CustomImageLabelerOptions.Builder(localModel) } val options = optionsBuilder .setConfidenceThreshold(0.5f) .setMaxResultCount(5) .build() val labeler = ImageLabeling.getClient(options) }
جاوا
RemoteModelManager.getInstance().isModelDownloaded(remoteModel) .addOnSuccessListener(new OnSuccessListener() { @Override public void onSuccess(Boolean isDownloaded) { CustomImageLabelerOptions.Builder optionsBuilder; if (isDownloaded) { optionsBuilder = new CustomImageLabelerOptions.Builder(remoteModel); } else { optionsBuilder = new CustomImageLabelerOptions.Builder(localModel); } CustomImageLabelerOptions options = optionsBuilder .setConfidenceThreshold(0.5f) .setMaxResultCount(5) .build(); ImageLabeler labeler = ImageLabeling.getClient(options); } });
اگر فقط یک مدل با میزبانی از راه دور دارید، باید عملکردهای مربوط به مدل را غیرفعال کنید - به عنوان مثال، خاکستری کردن یا پنهان کردن بخشی از رابط کاربری خود - تا زمانی که تأیید کنید مدل دانلود شده است. می توانید این کار را با پیوست کردن شنونده به متد download()
مدیر مدل انجام دهید:
کاتلین
RemoteModelManager.getInstance().download(remoteModel, conditions) .addOnSuccessListener { // Download complete. Depending on your app, you could enable the ML // feature, or switch from the local model to the remote model, etc. }
جاوا
RemoteModelManager.getInstance().download(remoteModel, conditions) .addOnSuccessListener(new OnSuccessListener() { @Override public void onSuccess(Void v) { // Download complete. Depending on your app, you could enable // the ML feature, or switch from the local model to the remote // model, etc. } });
2. تصویر ورودی را آماده کنید
سپس، برای هر تصویری که می خواهید برچسب گذاری کنید، یک شیInputImage
از تصویر خود ایجاد کنید. وقتی از Bitmap
استفاده میکنید، برچسبگذار تصویر سریعترین کار را انجام میدهد، یا اگر از camera2 API استفاده میکنید، یک media.Image
YUV_420_888. Image، که در صورت امکان توصیه میشوند. شما می توانید یک شی 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. برچسب تصویر را اجرا کنید
برای برچسب گذاری اشیاء در یک تصویر، شی image
را به متد process()
ImageLabeler
ارسال کنید.
کاتلین
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 // ... } });
4. اطلاعاتی در مورد نهادهای دارای برچسب دریافت کنید
اگر عملیات برچسب گذاری تصویر با موفقیت انجام شود، لیستی از اشیاءImageLabel
به شنونده موفقیت ارسال می شود. هر شی ImageLabel
چیزی را نشان می دهد که در تصویر برچسب گذاری شده است. میتوانید توضیحات متنی هر برچسب (در صورت موجود بودن در فراداده فایل مدل TensorFlow Lite)، امتیاز اطمینان و فهرست را دریافت کنید. به عنوان مثال: کاتلین
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
API استفاده میکنید، دریچه گاز با برچسب تصویر تماس میگیرد. اگر در حالی که برچسبدهنده تصویر در حال اجرا است، فریم ویدیویی جدیدی در دسترس است، قاب را رها کنید. برای مثال، کلاسVisionProcessorBase
را در برنامه نمونه سریع شروع کنید. - اگر از
CameraX
API استفاده میکنید، مطمئن شوید که استراتژی فشار برگشتی روی مقدار پیشفرضImageAnalysis.STRATEGY_KEEP_ONLY_LATEST
تنظیم شده است.STRATEGY_KEEP_ONLY_LATEST. این تضمین می کند که هر بار فقط یک تصویر برای تجزیه و تحلیل تحویل داده می شود. اگر در زمانی که آنالایزر مشغول است، تصاویر بیشتری تولید شود، به طور خودکار حذف می شوند و برای تحویل در صف قرار نمی گیرند. هنگامی که تصویر مورد تجزیه و تحلیل با فراخوانی ImageProxy.close بسته شد، آخرین تصویر بعدی تحویل داده می شود. - اگر از خروجی برچسب تصویر برای همپوشانی گرافیک روی تصویر ورودی استفاده می کنید، ابتدا نتیجه را از کیت ML دریافت کنید، سپس تصویر را رندر کنید و در یک مرحله همپوشانی کنید. این تنها یک بار برای هر فریم ورودی به سطح نمایشگر نمایش داده می شود. برای مثال، کلاسهای
CameraSourcePreview
وGraphicOverlay
را در برنامه نمونه شروع سریع ببینید. - اگر از Camera2 API استفاده می کنید، تصاویر را با فرمت
ImageFormat.YUV_420_888
بگیرید. اگر از دوربین قدیمیتر API استفاده میکنید، تصاویر را با فرمتImageFormat.NV21
بگیرید.