بعد از اینکه مدل خود را با استفاده از AutoML Vision Edge آموزش دادید ، میتوانید از آن در برنامه خود برای برچسبگذاری تصاویر استفاده کنید.
قبل از شروع
- اگر قبلاً این کار را نکردهاید، Firebase را به پروژه Android خود اضافه کنید .
- وابستگی های کتابخانه های اندروید ML Kit را به فایل Gradle ماژول (سطح برنامه) خود اضافه کنید (معمولا
app/build.gradle
):apply plugin: 'com.android.application' apply plugin: 'com.google.gms.google-services' dependencies { // ... implementation 'com.google.firebase:firebase-ml-vision:24.0.3' implementation 'com.google.firebase:firebase-ml-vision-automl:18.0.5' }
1. مدل را بارگذاری کنید
ML Kit مدل های تولید شده توسط AutoML شما را روی دستگاه اجرا می کند. با این حال، میتوانید ML Kit را برای بارگیری مدل خود از راه دور از Firebase، از ذخیرهسازی محلی یا هر دو پیکربندی کنید.
با میزبانی مدل در Firebase، میتوانید مدل را بدون انتشار نسخه جدید برنامه بهروزرسانی کنید و میتوانید از Remote Config و A/B Testing برای ارائه پویا مدلهای مختلف به مجموعههای مختلف کاربران استفاده کنید.
اگر ترجیح میدهید مدل را فقط با میزبانی آن در Firebase ارائه دهید، و آن را با برنامه خود همراه نکنید، میتوانید حجم دانلود اولیه برنامه خود را کاهش دهید. البته به خاطر داشته باشید که اگر مدل با برنامه شما همراه نباشد، تا زمانی که برنامه شما برای اولین بار مدل را دانلود نکند، هیچ عملکرد مرتبط با مدل در دسترس نخواهد بود.
با بستهبندی مدل خود با برنامهتان، میتوانید مطمئن شوید که ویژگیهای ML برنامهتان همچنان در زمانی که مدل میزبانی شده توسط Firebase در دسترس نیست، کار میکنند.
یک منبع مدل میزبانی شده توسط Firebase را پیکربندی کنید
برای استفاده از مدل میزبانی از راه دور، یک شی FirebaseAutoMLRemoteModel
ایجاد کنید و نامی را که به مدل اختصاص داده اید در هنگام انتشار آن مشخص کنید:
Java
// Specify the name you assigned in the Firebase console.
FirebaseAutoMLRemoteModel remoteModel =
new FirebaseAutoMLRemoteModel.Builder("your_remote_model").build();
Kotlin+KTX
// Specify the name you assigned in the Firebase console.
val remoteModel = FirebaseAutoMLRemoteModel.Builder("your_remote_model").build()
سپس، با مشخص کردن شرایطی که میخواهید اجازه دانلود را بدهید، کار دانلود مدل را شروع کنید. اگر مدل در دستگاه نباشد، یا اگر نسخه جدیدتری از مدل موجود باشد، این کار به صورت ناهمزمان مدل را از Firebase دانلود میکند:
Java
FirebaseModelDownloadConditions conditions = new FirebaseModelDownloadConditions.Builder()
.requireWifi()
.build();
FirebaseModelManager.getInstance().download(remoteModel, conditions)
.addOnCompleteListener(new OnCompleteListener<Void>() {
@Override
public void onComplete(@NonNull Task<Void> task) {
// Success.
}
});
Kotlin+KTX
val conditions = FirebaseModelDownloadConditions.Builder()
.requireWifi()
.build()
FirebaseModelManager.getInstance().download(remoteModel, conditions)
.addOnCompleteListener {
// Success.
}
بسیاری از برنامهها وظیفه دانلود را در کد اولیه خود شروع میکنند، اما شما میتوانید این کار را در هر زمانی قبل از نیاز به استفاده از مدل انجام دهید.
یک منبع مدل محلی را پیکربندی کنید
برای بستهبندی مدل با برنامهتان:
- مدل و ابرداده آن را از آرشیو فشرده ای که از کنسول Firebase دانلود کرده اید استخراج کنید. توصیه میکنیم از فایلها در حین دانلود، بدون تغییر (از جمله نام فایل) استفاده کنید.
مدل خود و فایل های فراداده آن را در بسته برنامه خود قرار دهید:
- اگر در پروژه خود پوشه دارایی ندارید، با کلیک راست روی پوشه
app/
، سپس روی New > Folder > Assets Folder کلیک کنید. - یک پوشه فرعی در زیر پوشه assets ایجاد کنید تا حاوی فایل های مدل باشد.
- فایلهای
model.tflite
،dict.txt
وmanifest.json
را در پوشه فرعی کپی کنید (هر سه فایل باید در یک پوشه باشند).
- اگر در پروژه خود پوشه دارایی ندارید، با کلیک راست روی پوشه
- موارد زیر را به فایل
build.gradle
برنامه خود اضافه کنید تا مطمئن شوید که Gradle فایل مدل را هنگام ساخت برنامه فشرده نمی کند:android { // ... aaptOptions { noCompress "tflite" } }
فایل مدل در بسته برنامه گنجانده شده و به عنوان دارایی خام در اختیار ML Kit قرار خواهد گرفت. - یک شی
FirebaseAutoMLLocalModel
ایجاد کنید و مسیر فایل مانیفست مدل را مشخص کنید:Java
FirebaseAutoMLLocalModel localModel = new FirebaseAutoMLLocalModel.Builder() .setAssetFilePath("manifest.json") .build();
Kotlin+KTX
val localModel = FirebaseAutoMLLocalModel.Builder() .setAssetFilePath("manifest.json") .build()
یک برچسب تصویر از مدل خود ایجاد کنید
پس از پیکربندی منابع مدل خود، یک شی FirebaseVisionImageLabeler
از یکی از آنها ایجاد کنید.
اگر فقط یک مدل به صورت محلی دارید، فقط یک برچسب از شی FirebaseAutoMLLocalModel
خود ایجاد کنید و آستانه امتیاز اطمینان مورد نیاز خود را پیکربندی کنید ( به ارزیابی مدل خود مراجعه کنید):
Java
FirebaseVisionImageLabeler labeler;
try {
FirebaseVisionOnDeviceAutoMLImageLabelerOptions options =
new FirebaseVisionOnDeviceAutoMLImageLabelerOptions.Builder(localModel)
.setConfidenceThreshold(0.0f) // Evaluate your model in the Firebase console
// to determine an appropriate value.
.build();
labeler = FirebaseVision.getInstance().getOnDeviceAutoMLImageLabeler(options);
} catch (FirebaseMLException e) {
// ...
}
Kotlin+KTX
val options = FirebaseVisionOnDeviceAutoMLImageLabelerOptions.Builder(localModel)
.setConfidenceThreshold(0) // Evaluate your model in the Firebase console
// to determine an appropriate value.
.build()
val labeler = FirebaseVision.getInstance().getOnDeviceAutoMLImageLabeler(options)
اگر یک مدل با میزبانی از راه دور دارید، قبل از اجرای آن باید بررسی کنید که دانلود شده است. با استفاده از متد isModelDownloaded()
مدیر مدل می توانید وضعیت وظیفه دانلود مدل را بررسی کنید.
اگرچه شما فقط باید قبل از اجرای برچسبگذار این موضوع را تأیید کنید، اگر هم یک مدل با میزبانی از راه دور و هم یک مدل بستهبندی محلی دارید، ممکن است این بررسی را هنگام نمونهسازی برچسبکننده تصویر انجام دهید: یک برچسبگذار از مدل راه دور ایجاد کنید اگر دانلود شده است، و در غیر این صورت از مدل محلی.
Java
FirebaseModelManager.getInstance().isModelDownloaded(remoteModel)
.addOnSuccessListener(new OnSuccessListener<Boolean>() {
@Override
public void onSuccess(Boolean isDownloaded) {
FirebaseVisionOnDeviceAutoMLImageLabelerOptions.Builder optionsBuilder;
if (isDownloaded) {
optionsBuilder = new FirebaseVisionOnDeviceAutoMLImageLabelerOptions.Builder(remoteModel);
} else {
optionsBuilder = new FirebaseVisionOnDeviceAutoMLImageLabelerOptions.Builder(localModel);
}
FirebaseVisionOnDeviceAutoMLImageLabelerOptions options = optionsBuilder
.setConfidenceThreshold(0.0f) // Evaluate your model in the Firebase console
// to determine an appropriate threshold.
.build();
FirebaseVisionImageLabeler labeler;
try {
labeler = FirebaseVision.getInstance().getOnDeviceAutoMLImageLabeler(options);
} catch (FirebaseMLException e) {
// Error.
}
}
});
Kotlin+KTX
FirebaseModelManager.getInstance().isModelDownloaded(remoteModel)
.addOnSuccessListener { isDownloaded ->
val optionsBuilder =
if (isDownloaded) {
FirebaseVisionOnDeviceAutoMLImageLabelerOptions.Builder(remoteModel)
} else {
FirebaseVisionOnDeviceAutoMLImageLabelerOptions.Builder(localModel)
}
// Evaluate your model in the Firebase console to determine an appropriate threshold.
val options = optionsBuilder.setConfidenceThreshold(0.0f).build()
val labeler = FirebaseVision.getInstance().getOnDeviceAutoMLImageLabeler(options)
}
اگر فقط یک مدل با میزبانی از راه دور دارید، باید عملکردهای مربوط به مدل را غیرفعال کنید - به عنوان مثال، خاکستری کردن یا پنهان کردن بخشی از رابط کاربری خود - تا زمانی که تأیید کنید مدل دانلود شده است. می توانید این کار را با پیوست کردن شنونده به متد download()
مدیر مدل انجام دهید:
Java
FirebaseModelManager.getInstance().download(remoteModel, conditions)
.addOnSuccessListener(new OnSuccessListener<Void>() {
@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.
}
});
Kotlin+KTX
FirebaseModelManager.getInstance().download(remoteModel, conditions)
.addOnCompleteListener {
// Download complete. Depending on your app, you could enable the ML
// feature, or switch from the local model to the remote model, etc.
}
2. تصویر ورودی را آماده کنید
سپس، برای هر تصویری که می خواهید برچسب گذاری کنید، با استفاده از یکی از گزینه های توضیح داده شده در این بخش، یک شی FirebaseVisionImage
ایجاد کنید و آن را به نمونه ای از FirebaseVisionImageLabeler
(شرح داده شده در بخش بعدی) ارسال کنید.
میتوانید یک شی FirebaseVisionImage
از یک شی media.Image
، یک فایل روی دستگاه، یک آرایه بایت یا یک شی Bitmap
ایجاد کنید:
برای ایجاد یک شی
FirebaseVisionImage
از یک شیmedia.Image
، مانند هنگام گرفتن تصویر از دوربین دستگاه، شیmedia.Image
.Image و چرخش تصویر را بهFirebaseVisionImage.fromMediaImage()
منتقل کنید.اگر از کتابخانه CameraX ، کلاسهای
OnImageCapturedListener
وImageAnalysis.Analyzer
استفاده میکنید، مقدار چرخش را برای شما محاسبه میکنند، بنابراین فقط باید قبل از فراخوانیFirebaseVisionImage.fromMediaImage()
چرخش را به یکی از ثابتهایROTATION_
ML Kit تبدیل کنید:Java
private class YourAnalyzer implements ImageAnalysis.Analyzer { private int degreesToFirebaseRotation(int degrees) { switch (degrees) { case 0: return FirebaseVisionImageMetadata.ROTATION_0; case 90: return FirebaseVisionImageMetadata.ROTATION_90; case 180: return FirebaseVisionImageMetadata.ROTATION_180; case 270: return FirebaseVisionImageMetadata.ROTATION_270; default: throw new IllegalArgumentException( "Rotation must be 0, 90, 180, or 270."); } } @Override public void analyze(ImageProxy imageProxy, int degrees) { if (imageProxy == null || imageProxy.getImage() == null) { return; } Image mediaImage = imageProxy.getImage(); int rotation = degreesToFirebaseRotation(degrees); FirebaseVisionImage image = FirebaseVisionImage.fromMediaImage(mediaImage, rotation); // Pass image to an ML Kit Vision API // ... } }
Kotlin+KTX
private class YourImageAnalyzer : ImageAnalysis.Analyzer { private fun degreesToFirebaseRotation(degrees: Int): Int = when(degrees) { 0 -> FirebaseVisionImageMetadata.ROTATION_0 90 -> FirebaseVisionImageMetadata.ROTATION_90 180 -> FirebaseVisionImageMetadata.ROTATION_180 270 -> FirebaseVisionImageMetadata.ROTATION_270 else -> throw Exception("Rotation must be 0, 90, 180, or 270.") } override fun analyze(imageProxy: ImageProxy?, degrees: Int) { val mediaImage = imageProxy?.image val imageRotation = degreesToFirebaseRotation(degrees) if (mediaImage != null) { val image = FirebaseVisionImage.fromMediaImage(mediaImage, imageRotation) // Pass image to an ML Kit Vision API // ... } } }
اگر از کتابخانه دوربینی که چرخش تصویر را به شما می دهد استفاده نمی کنید، می توانید آن را از روی چرخش دستگاه و جهت سنسور دوربین در دستگاه محاسبه کنید:
Java
private static final SparseIntArray ORIENTATIONS = new SparseIntArray(); static { ORIENTATIONS.append(Surface.ROTATION_0, 90); ORIENTATIONS.append(Surface.ROTATION_90, 0); ORIENTATIONS.append(Surface.ROTATION_180, 270); ORIENTATIONS.append(Surface.ROTATION_270, 180); } /** * 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, Context context) 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); // On most devices, the sensor orientation is 90 degrees, but for some // devices it is 270 degrees. For devices with a sensor orientation of // 270, rotate the image an additional 180 ((270 + 270) % 360) degrees. CameraManager cameraManager = (CameraManager) context.getSystemService(CAMERA_SERVICE); int sensorOrientation = cameraManager .getCameraCharacteristics(cameraId) .get(CameraCharacteristics.SENSOR_ORIENTATION); rotationCompensation = (rotationCompensation + sensorOrientation + 270) % 360; // Return the corresponding FirebaseVisionImageMetadata rotation value. int result; switch (rotationCompensation) { case 0: result = FirebaseVisionImageMetadata.ROTATION_0; break; case 90: result = FirebaseVisionImageMetadata.ROTATION_90; break; case 180: result = FirebaseVisionImageMetadata.ROTATION_180; break; case 270: result = FirebaseVisionImageMetadata.ROTATION_270; break; default: result = FirebaseVisionImageMetadata.ROTATION_0; Log.e(TAG, "Bad rotation value: " + rotationCompensation); } return result; }
Kotlin+KTX
private val ORIENTATIONS = SparseIntArray() init { ORIENTATIONS.append(Surface.ROTATION_0, 90) ORIENTATIONS.append(Surface.ROTATION_90, 0) ORIENTATIONS.append(Surface.ROTATION_180, 270) ORIENTATIONS.append(Surface.ROTATION_270, 180) } /** * 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, context: Context): 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) // On most devices, the sensor orientation is 90 degrees, but for some // devices it is 270 degrees. For devices with a sensor orientation of // 270, rotate the image an additional 180 ((270 + 270) % 360) degrees. val cameraManager = context.getSystemService(CAMERA_SERVICE) as CameraManager val sensorOrientation = cameraManager .getCameraCharacteristics(cameraId) .get(CameraCharacteristics.SENSOR_ORIENTATION)!! rotationCompensation = (rotationCompensation + sensorOrientation + 270) % 360 // Return the corresponding FirebaseVisionImageMetadata rotation value. val result: Int when (rotationCompensation) { 0 -> result = FirebaseVisionImageMetadata.ROTATION_0 90 -> result = FirebaseVisionImageMetadata.ROTATION_90 180 -> result = FirebaseVisionImageMetadata.ROTATION_180 270 -> result = FirebaseVisionImageMetadata.ROTATION_270 else -> { result = FirebaseVisionImageMetadata.ROTATION_0 Log.e(TAG, "Bad rotation value: $rotationCompensation") } } return result }
سپس، شی
media.Image
و مقدار چرخش را بهFirebaseVisionImage.fromMediaImage()
ارسال کنید:Java
FirebaseVisionImage image = FirebaseVisionImage.fromMediaImage(mediaImage, rotation);
Kotlin+KTX
val image = FirebaseVisionImage.fromMediaImage(mediaImage, rotation)
- برای ایجاد یک شی
FirebaseVisionImage
از URI فایل، زمینه برنامه و فایل URI را بهFirebaseVisionImage.fromFilePath()
ارسال کنید. این زمانی مفید است که از یک هدفACTION_GET_CONTENT
استفاده می کنید تا از کاربر بخواهید تصویری را از برنامه گالری خود انتخاب کند.Java
FirebaseVisionImage image; try { image = FirebaseVisionImage.fromFilePath(context, uri); } catch (IOException e) { e.printStackTrace(); }
Kotlin+KTX
val image: FirebaseVisionImage try { image = FirebaseVisionImage.fromFilePath(context, uri) } catch (e: IOException) { e.printStackTrace() }
- برای ایجاد یک شی
FirebaseVisionImage
از یکByteBuffer
یا یک آرایه بایت، ابتدا چرخش تصویر را همانطور که در بالا برای ورودیmedia.Image
توضیح داده شد محاسبه کنید.سپس، یک شی
FirebaseVisionImageMetadata
ایجاد کنید که شامل ارتفاع، عرض، فرمت کدگذاری رنگ و چرخش تصویر باشد:Java
FirebaseVisionImageMetadata metadata = new FirebaseVisionImageMetadata.Builder() .setWidth(480) // 480x360 is typically sufficient for .setHeight(360) // image recognition .setFormat(FirebaseVisionImageMetadata.IMAGE_FORMAT_NV21) .setRotation(rotation) .build();
Kotlin+KTX
val metadata = FirebaseVisionImageMetadata.Builder() .setWidth(480) // 480x360 is typically sufficient for .setHeight(360) // image recognition .setFormat(FirebaseVisionImageMetadata.IMAGE_FORMAT_NV21) .setRotation(rotation) .build()
برای ایجاد یک شی
FirebaseVisionImage
از بافر یا آرایه و شیء فراداده استفاده کنید:Java
FirebaseVisionImage image = FirebaseVisionImage.fromByteBuffer(buffer, metadata); // Or: FirebaseVisionImage image = FirebaseVisionImage.fromByteArray(byteArray, metadata);
Kotlin+KTX
val image = FirebaseVisionImage.fromByteBuffer(buffer, metadata) // Or: val image = FirebaseVisionImage.fromByteArray(byteArray, metadata)
- برای ایجاد یک شی
FirebaseVisionImage
از یک شیBitmap
:تصویر نمایش داده شده توسط شیJava
FirebaseVisionImage image = FirebaseVisionImage.fromBitmap(bitmap);
Kotlin+KTX
val image = FirebaseVisionImage.fromBitmap(bitmap)
Bitmap
باید عمودی باشد، بدون نیاز به چرخش اضافی.
3. برچسب تصویر را اجرا کنید
برای برچسب گذاری اشیاء در یک تصویر، شی FirebaseVisionImage
را به متد processImage()
FirebaseVisionImageLabeler
ارسال کنید.
Java
labeler.processImage(image)
.addOnSuccessListener(new OnSuccessListener<List<FirebaseVisionImageLabel>>() {
@Override
public void onSuccess(List<FirebaseVisionImageLabel> labels) {
// Task completed successfully
// ...
}
})
.addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(@NonNull Exception e) {
// Task failed with an exception
// ...
}
});
Kotlin+KTX
labeler.processImage(image)
.addOnSuccessListener { labels ->
// Task completed successfully
// ...
}
.addOnFailureListener { e ->
// Task failed with an exception
// ...
}
اگر برچسبگذاری تصویر با موفقیت انجام شود، آرایهای از اشیاء FirebaseVisionImageLabel
به شنونده موفقیت ارسال میشود. از هر شی، می توانید اطلاعاتی در مورد ویژگی شناسایی شده در تصویر دریافت کنید.
به عنوان مثال:
Java
for (FirebaseVisionImageLabel label: labels) {
String text = label.getText();
float confidence = label.getConfidence();
}
Kotlin+KTX
for (label in labels) {
val text = label.text
val confidence = label.confidence
}
نکاتی برای بهبود عملکرد در زمان واقعی
- دریچه گاز به آشکارساز زنگ می زند. اگر یک قاب ویدیویی جدید در حین کار کردن آشکارساز در دسترس قرار گرفت، قاب را رها کنید.
- اگر از خروجی آشکارساز برای همپوشانی گرافیک روی تصویر ورودی استفاده میکنید، ابتدا نتیجه را از کیت ML دریافت کنید، سپس تصویر را رندر کنید و در یک مرحله همپوشانی کنید. با انجام این کار، برای هر فریم ورودی فقط یک بار به سطح نمایشگر رندر می دهید.
اگر از Camera2 API استفاده می کنید، تصاویر را با فرمت
ImageFormat.YUV_420_888
بگیرید.اگر از دوربین قدیمیتر API استفاده میکنید، تصاویر را با فرمت
ImageFormat.NV21
بگیرید.
بعد از اینکه مدل خود را با استفاده از AutoML Vision Edge آموزش دادید ، میتوانید از آن در برنامه خود برای برچسبگذاری تصاویر استفاده کنید.
قبل از شروع
- اگر قبلاً این کار را نکردهاید، Firebase را به پروژه Android خود اضافه کنید .
- وابستگی های کتابخانه های اندروید ML Kit را به فایل Gradle ماژول (سطح برنامه) خود اضافه کنید (معمولا
app/build.gradle
):apply plugin: 'com.android.application' apply plugin: 'com.google.gms.google-services' dependencies { // ... implementation 'com.google.firebase:firebase-ml-vision:24.0.3' implementation 'com.google.firebase:firebase-ml-vision-automl:18.0.5' }
1. مدل را بارگذاری کنید
ML Kit مدل های تولید شده توسط AutoML شما را روی دستگاه اجرا می کند. با این حال، میتوانید ML Kit را برای بارگیری مدل خود از راه دور از Firebase، از ذخیرهسازی محلی یا هر دو پیکربندی کنید.
با میزبانی مدل در Firebase، میتوانید مدل را بدون انتشار نسخه جدید برنامه بهروزرسانی کنید و میتوانید از Remote Config و A/B Testing برای ارائه پویا مدلهای مختلف به مجموعههای مختلف کاربران استفاده کنید.
اگر ترجیح میدهید مدل را فقط با میزبانی آن در Firebase ارائه دهید، و آن را با برنامه خود همراه نکنید، میتوانید حجم دانلود اولیه برنامه خود را کاهش دهید. البته به خاطر داشته باشید که اگر مدل با برنامه شما همراه نباشد، تا زمانی که برنامه شما برای اولین بار مدل را دانلود نکند، هیچ عملکرد مرتبط با مدل در دسترس نخواهد بود.
با بستهبندی مدل خود با برنامهتان، میتوانید مطمئن شوید که ویژگیهای ML برنامهتان همچنان در زمانی که مدل میزبانی شده توسط Firebase در دسترس نیست، کار میکنند.
یک منبع مدل میزبانی شده توسط Firebase را پیکربندی کنید
برای استفاده از مدل میزبانی از راه دور، یک شی FirebaseAutoMLRemoteModel
ایجاد کنید و نامی را که به مدل اختصاص داده اید در هنگام انتشار آن مشخص کنید:
Java
// Specify the name you assigned in the Firebase console.
FirebaseAutoMLRemoteModel remoteModel =
new FirebaseAutoMLRemoteModel.Builder("your_remote_model").build();
Kotlin+KTX
// Specify the name you assigned in the Firebase console.
val remoteModel = FirebaseAutoMLRemoteModel.Builder("your_remote_model").build()
سپس، با مشخص کردن شرایطی که میخواهید اجازه دانلود را بدهید، کار دانلود مدل را شروع کنید. اگر مدل در دستگاه نباشد، یا اگر نسخه جدیدتری از مدل موجود باشد، این کار به صورت ناهمزمان مدل را از Firebase دانلود میکند:
Java
FirebaseModelDownloadConditions conditions = new FirebaseModelDownloadConditions.Builder()
.requireWifi()
.build();
FirebaseModelManager.getInstance().download(remoteModel, conditions)
.addOnCompleteListener(new OnCompleteListener<Void>() {
@Override
public void onComplete(@NonNull Task<Void> task) {
// Success.
}
});
Kotlin+KTX
val conditions = FirebaseModelDownloadConditions.Builder()
.requireWifi()
.build()
FirebaseModelManager.getInstance().download(remoteModel, conditions)
.addOnCompleteListener {
// Success.
}
بسیاری از برنامهها وظیفه دانلود را در کد اولیه خود شروع میکنند، اما شما میتوانید این کار را در هر زمانی قبل از نیاز به استفاده از مدل انجام دهید.
یک منبع مدل محلی را پیکربندی کنید
برای بستهبندی مدل با برنامهتان:
- مدل و ابرداده آن را از آرشیو فشرده ای که از کنسول Firebase دانلود کرده اید استخراج کنید. توصیه میکنیم از فایلها در حین دانلود، بدون تغییر (از جمله نام فایل) استفاده کنید.
مدل خود و فایل های فراداده آن را در بسته برنامه خود قرار دهید:
- اگر در پروژه خود پوشه دارایی ندارید، با کلیک راست روی پوشه
app/
، سپس روی New > Folder > Assets Folder کلیک کنید. - یک پوشه فرعی در زیر پوشه assets ایجاد کنید تا حاوی فایل های مدل باشد.
- فایلهای
model.tflite
،dict.txt
وmanifest.json
را در پوشه فرعی کپی کنید (هر سه فایل باید در یک پوشه باشند).
- اگر در پروژه خود پوشه دارایی ندارید، با کلیک راست روی پوشه
- موارد زیر را به فایل
build.gradle
برنامه خود اضافه کنید تا مطمئن شوید که Gradle فایل مدل را هنگام ساخت برنامه فشرده نمی کند:android { // ... aaptOptions { noCompress "tflite" } }
فایل مدل در بسته برنامه گنجانده شده و به عنوان دارایی خام در اختیار ML Kit قرار خواهد گرفت. - یک شی
FirebaseAutoMLLocalModel
ایجاد کنید و مسیر فایل مانیفست مدل را مشخص کنید:Java
FirebaseAutoMLLocalModel localModel = new FirebaseAutoMLLocalModel.Builder() .setAssetFilePath("manifest.json") .build();
Kotlin+KTX
val localModel = FirebaseAutoMLLocalModel.Builder() .setAssetFilePath("manifest.json") .build()
یک برچسب تصویر از مدل خود ایجاد کنید
پس از پیکربندی منابع مدل خود، یک شی FirebaseVisionImageLabeler
از یکی از آنها ایجاد کنید.
اگر فقط یک مدل به صورت محلی دارید، فقط یک برچسب از شی FirebaseAutoMLLocalModel
خود ایجاد کنید و آستانه امتیاز اطمینان مورد نیاز خود را پیکربندی کنید ( به ارزیابی مدل خود مراجعه کنید):
Java
FirebaseVisionImageLabeler labeler;
try {
FirebaseVisionOnDeviceAutoMLImageLabelerOptions options =
new FirebaseVisionOnDeviceAutoMLImageLabelerOptions.Builder(localModel)
.setConfidenceThreshold(0.0f) // Evaluate your model in the Firebase console
// to determine an appropriate value.
.build();
labeler = FirebaseVision.getInstance().getOnDeviceAutoMLImageLabeler(options);
} catch (FirebaseMLException e) {
// ...
}
Kotlin+KTX
val options = FirebaseVisionOnDeviceAutoMLImageLabelerOptions.Builder(localModel)
.setConfidenceThreshold(0) // Evaluate your model in the Firebase console
// to determine an appropriate value.
.build()
val labeler = FirebaseVision.getInstance().getOnDeviceAutoMLImageLabeler(options)
اگر یک مدل با میزبانی از راه دور دارید، قبل از اجرای آن باید بررسی کنید که دانلود شده است. با استفاده از متد isModelDownloaded()
مدیر مدل می توانید وضعیت وظیفه دانلود مدل را بررسی کنید.
اگرچه شما فقط باید قبل از اجرای برچسبگذار این موضوع را تأیید کنید، اگر هم یک مدل با میزبانی از راه دور و هم یک مدل بستهبندی محلی دارید، ممکن است این بررسی را هنگام نمونهسازی برچسبکننده تصویر انجام دهید: یک برچسبگذار از مدل راه دور ایجاد کنید اگر دانلود شده است، و در غیر این صورت از مدل محلی.
Java
FirebaseModelManager.getInstance().isModelDownloaded(remoteModel)
.addOnSuccessListener(new OnSuccessListener<Boolean>() {
@Override
public void onSuccess(Boolean isDownloaded) {
FirebaseVisionOnDeviceAutoMLImageLabelerOptions.Builder optionsBuilder;
if (isDownloaded) {
optionsBuilder = new FirebaseVisionOnDeviceAutoMLImageLabelerOptions.Builder(remoteModel);
} else {
optionsBuilder = new FirebaseVisionOnDeviceAutoMLImageLabelerOptions.Builder(localModel);
}
FirebaseVisionOnDeviceAutoMLImageLabelerOptions options = optionsBuilder
.setConfidenceThreshold(0.0f) // Evaluate your model in the Firebase console
// to determine an appropriate threshold.
.build();
FirebaseVisionImageLabeler labeler;
try {
labeler = FirebaseVision.getInstance().getOnDeviceAutoMLImageLabeler(options);
} catch (FirebaseMLException e) {
// Error.
}
}
});
Kotlin+KTX
FirebaseModelManager.getInstance().isModelDownloaded(remoteModel)
.addOnSuccessListener { isDownloaded ->
val optionsBuilder =
if (isDownloaded) {
FirebaseVisionOnDeviceAutoMLImageLabelerOptions.Builder(remoteModel)
} else {
FirebaseVisionOnDeviceAutoMLImageLabelerOptions.Builder(localModel)
}
// Evaluate your model in the Firebase console to determine an appropriate threshold.
val options = optionsBuilder.setConfidenceThreshold(0.0f).build()
val labeler = FirebaseVision.getInstance().getOnDeviceAutoMLImageLabeler(options)
}
اگر فقط یک مدل با میزبانی از راه دور دارید، باید عملکردهای مربوط به مدل را غیرفعال کنید - به عنوان مثال، خاکستری کردن یا پنهان کردن بخشی از رابط کاربری خود - تا زمانی که تأیید کنید مدل دانلود شده است. می توانید این کار را با پیوست کردن شنونده به متد download()
مدیر مدل انجام دهید:
Java
FirebaseModelManager.getInstance().download(remoteModel, conditions)
.addOnSuccessListener(new OnSuccessListener<Void>() {
@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.
}
});
Kotlin+KTX
FirebaseModelManager.getInstance().download(remoteModel, conditions)
.addOnCompleteListener {
// Download complete. Depending on your app, you could enable the ML
// feature, or switch from the local model to the remote model, etc.
}
2. تصویر ورودی را آماده کنید
سپس، برای هر تصویری که می خواهید برچسب گذاری کنید، با استفاده از یکی از گزینه های توضیح داده شده در این بخش، یک شی FirebaseVisionImage
ایجاد کنید و آن را به نمونه ای از FirebaseVisionImageLabeler
(شرح داده شده در بخش بعدی) ارسال کنید.
میتوانید یک شی FirebaseVisionImage
از یک شی media.Image
، یک فایل روی دستگاه، یک آرایه بایت یا یک شی Bitmap
ایجاد کنید:
برای ایجاد یک شی
FirebaseVisionImage
از یک شیmedia.Image
، مانند هنگام گرفتن تصویر از دوربین دستگاه، شیmedia.Image
.Image و چرخش تصویر را بهFirebaseVisionImage.fromMediaImage()
منتقل کنید.اگر از کتابخانه CameraX ، کلاسهای
OnImageCapturedListener
وImageAnalysis.Analyzer
استفاده میکنید، مقدار چرخش را برای شما محاسبه میکنند، بنابراین فقط باید قبل از فراخوانیFirebaseVisionImage.fromMediaImage()
چرخش را به یکی از ثابتهایROTATION_
ML Kit تبدیل کنید:Java
private class YourAnalyzer implements ImageAnalysis.Analyzer { private int degreesToFirebaseRotation(int degrees) { switch (degrees) { case 0: return FirebaseVisionImageMetadata.ROTATION_0; case 90: return FirebaseVisionImageMetadata.ROTATION_90; case 180: return FirebaseVisionImageMetadata.ROTATION_180; case 270: return FirebaseVisionImageMetadata.ROTATION_270; default: throw new IllegalArgumentException( "Rotation must be 0, 90, 180, or 270."); } } @Override public void analyze(ImageProxy imageProxy, int degrees) { if (imageProxy == null || imageProxy.getImage() == null) { return; } Image mediaImage = imageProxy.getImage(); int rotation = degreesToFirebaseRotation(degrees); FirebaseVisionImage image = FirebaseVisionImage.fromMediaImage(mediaImage, rotation); // Pass image to an ML Kit Vision API // ... } }
Kotlin+KTX
private class YourImageAnalyzer : ImageAnalysis.Analyzer { private fun degreesToFirebaseRotation(degrees: Int): Int = when(degrees) { 0 -> FirebaseVisionImageMetadata.ROTATION_0 90 -> FirebaseVisionImageMetadata.ROTATION_90 180 -> FirebaseVisionImageMetadata.ROTATION_180 270 -> FirebaseVisionImageMetadata.ROTATION_270 else -> throw Exception("Rotation must be 0, 90, 180, or 270.") } override fun analyze(imageProxy: ImageProxy?, degrees: Int) { val mediaImage = imageProxy?.image val imageRotation = degreesToFirebaseRotation(degrees) if (mediaImage != null) { val image = FirebaseVisionImage.fromMediaImage(mediaImage, imageRotation) // Pass image to an ML Kit Vision API // ... } } }
اگر از کتابخانه دوربینی که چرخش تصویر را به شما می دهد استفاده نمی کنید، می توانید آن را از روی چرخش دستگاه و جهت سنسور دوربین در دستگاه محاسبه کنید:
Java
private static final SparseIntArray ORIENTATIONS = new SparseIntArray(); static { ORIENTATIONS.append(Surface.ROTATION_0, 90); ORIENTATIONS.append(Surface.ROTATION_90, 0); ORIENTATIONS.append(Surface.ROTATION_180, 270); ORIENTATIONS.append(Surface.ROTATION_270, 180); } /** * 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, Context context) 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); // On most devices, the sensor orientation is 90 degrees, but for some // devices it is 270 degrees. For devices with a sensor orientation of // 270, rotate the image an additional 180 ((270 + 270) % 360) degrees. CameraManager cameraManager = (CameraManager) context.getSystemService(CAMERA_SERVICE); int sensorOrientation = cameraManager .getCameraCharacteristics(cameraId) .get(CameraCharacteristics.SENSOR_ORIENTATION); rotationCompensation = (rotationCompensation + sensorOrientation + 270) % 360; // Return the corresponding FirebaseVisionImageMetadata rotation value. int result; switch (rotationCompensation) { case 0: result = FirebaseVisionImageMetadata.ROTATION_0; break; case 90: result = FirebaseVisionImageMetadata.ROTATION_90; break; case 180: result = FirebaseVisionImageMetadata.ROTATION_180; break; case 270: result = FirebaseVisionImageMetadata.ROTATION_270; break; default: result = FirebaseVisionImageMetadata.ROTATION_0; Log.e(TAG, "Bad rotation value: " + rotationCompensation); } return result; }
Kotlin+KTX
private val ORIENTATIONS = SparseIntArray() init { ORIENTATIONS.append(Surface.ROTATION_0, 90) ORIENTATIONS.append(Surface.ROTATION_90, 0) ORIENTATIONS.append(Surface.ROTATION_180, 270) ORIENTATIONS.append(Surface.ROTATION_270, 180) } /** * 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, context: Context): 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) // On most devices, the sensor orientation is 90 degrees, but for some // devices it is 270 degrees. For devices with a sensor orientation of // 270, rotate the image an additional 180 ((270 + 270) % 360) degrees. val cameraManager = context.getSystemService(CAMERA_SERVICE) as CameraManager val sensorOrientation = cameraManager .getCameraCharacteristics(cameraId) .get(CameraCharacteristics.SENSOR_ORIENTATION)!! rotationCompensation = (rotationCompensation + sensorOrientation + 270) % 360 // Return the corresponding FirebaseVisionImageMetadata rotation value. val result: Int when (rotationCompensation) { 0 -> result = FirebaseVisionImageMetadata.ROTATION_0 90 -> result = FirebaseVisionImageMetadata.ROTATION_90 180 -> result = FirebaseVisionImageMetadata.ROTATION_180 270 -> result = FirebaseVisionImageMetadata.ROTATION_270 else -> { result = FirebaseVisionImageMetadata.ROTATION_0 Log.e(TAG, "Bad rotation value: $rotationCompensation") } } return result }
سپس، شی
media.Image
و مقدار چرخش را بهFirebaseVisionImage.fromMediaImage()
ارسال کنید:Java
FirebaseVisionImage image = FirebaseVisionImage.fromMediaImage(mediaImage, rotation);
Kotlin+KTX
val image = FirebaseVisionImage.fromMediaImage(mediaImage, rotation)
- برای ایجاد یک شی
FirebaseVisionImage
از URI فایل، زمینه برنامه و فایل URI را بهFirebaseVisionImage.fromFilePath()
ارسال کنید. این زمانی مفید است که از یک هدفACTION_GET_CONTENT
استفاده می کنید تا از کاربر بخواهید تصویری را از برنامه گالری خود انتخاب کند.Java
FirebaseVisionImage image; try { image = FirebaseVisionImage.fromFilePath(context, uri); } catch (IOException e) { e.printStackTrace(); }
Kotlin+KTX
val image: FirebaseVisionImage try { image = FirebaseVisionImage.fromFilePath(context, uri) } catch (e: IOException) { e.printStackTrace() }
- برای ایجاد یک شی
FirebaseVisionImage
از یکByteBuffer
یا یک آرایه بایت، ابتدا چرخش تصویر را همانطور که در بالا برای ورودیmedia.Image
توضیح داده شد محاسبه کنید.سپس، یک شی
FirebaseVisionImageMetadata
ایجاد کنید که شامل ارتفاع، عرض، فرمت کدگذاری رنگ و چرخش تصویر باشد:Java
FirebaseVisionImageMetadata metadata = new FirebaseVisionImageMetadata.Builder() .setWidth(480) // 480x360 is typically sufficient for .setHeight(360) // image recognition .setFormat(FirebaseVisionImageMetadata.IMAGE_FORMAT_NV21) .setRotation(rotation) .build();
Kotlin+KTX
val metadata = FirebaseVisionImageMetadata.Builder() .setWidth(480) // 480x360 is typically sufficient for .setHeight(360) // image recognition .setFormat(FirebaseVisionImageMetadata.IMAGE_FORMAT_NV21) .setRotation(rotation) .build()
برای ایجاد یک شی
FirebaseVisionImage
از بافر یا آرایه و شیء فراداده استفاده کنید:Java
FirebaseVisionImage image = FirebaseVisionImage.fromByteBuffer(buffer, metadata); // Or: FirebaseVisionImage image = FirebaseVisionImage.fromByteArray(byteArray, metadata);
Kotlin+KTX
val image = FirebaseVisionImage.fromByteBuffer(buffer, metadata) // Or: val image = FirebaseVisionImage.fromByteArray(byteArray, metadata)
- برای ایجاد یک شی
FirebaseVisionImage
از یک شیBitmap
:تصویر نمایش داده شده توسط شیJava
FirebaseVisionImage image = FirebaseVisionImage.fromBitmap(bitmap);
Kotlin+KTX
val image = FirebaseVisionImage.fromBitmap(bitmap)
Bitmap
باید عمودی باشد، بدون نیاز به چرخش اضافی.
3. برچسب تصویر را اجرا کنید
برای برچسب گذاری اشیاء در یک تصویر، شی FirebaseVisionImage
را به متد processImage()
FirebaseVisionImageLabeler
ارسال کنید.
Java
labeler.processImage(image)
.addOnSuccessListener(new OnSuccessListener<List<FirebaseVisionImageLabel>>() {
@Override
public void onSuccess(List<FirebaseVisionImageLabel> labels) {
// Task completed successfully
// ...
}
})
.addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(@NonNull Exception e) {
// Task failed with an exception
// ...
}
});
Kotlin+KTX
labeler.processImage(image)
.addOnSuccessListener { labels ->
// Task completed successfully
// ...
}
.addOnFailureListener { e ->
// Task failed with an exception
// ...
}
اگر برچسبگذاری تصویر با موفقیت انجام شود، آرایهای از اشیاء FirebaseVisionImageLabel
به شنونده موفقیت ارسال میشود. از هر شی، می توانید اطلاعاتی در مورد ویژگی شناسایی شده در تصویر دریافت کنید.
به عنوان مثال:
Java
for (FirebaseVisionImageLabel label: labels) {
String text = label.getText();
float confidence = label.getConfidence();
}
Kotlin+KTX
for (label in labels) {
val text = label.text
val confidence = label.confidence
}
نکاتی برای بهبود عملکرد در زمان واقعی
- دریچه گاز به آشکارساز زنگ می زند. اگر یک قاب ویدیویی جدید در حین کار کردن آشکارساز در دسترس قرار گرفت، قاب را رها کنید.
- اگر از خروجی آشکارساز برای همپوشانی گرافیک روی تصویر ورودی استفاده میکنید، ابتدا نتیجه را از کیت ML دریافت کنید، سپس تصویر را رندر کنید و در یک مرحله همپوشانی کنید. با انجام این کار، برای هر فریم ورودی فقط یک بار به سطح نمایشگر رندر می دهید.
اگر از Camera2 API استفاده می کنید، تصاویر را با فرمت
ImageFormat.YUV_420_888
بگیرید.اگر از دوربین قدیمیتر API استفاده میکنید، تصاویر را با فرمت
ImageFormat.NV21
بگیرید.
بعد از اینکه مدل خود را با استفاده از AutoML Vision Edge آموزش دادید ، میتوانید از آن در برنامه خود برای برچسبگذاری تصاویر استفاده کنید.
قبل از شروع
- اگر قبلاً این کار را نکردهاید، Firebase را به پروژه Android خود اضافه کنید .
- وابستگیهای کتابخانههای اندروید ML Kit را به فایل Gradle ماژول (سطح برنامه) خود اضافه کنید (معمولا
app/build.gradle
):apply plugin: 'com.android.application' apply plugin: 'com.google.gms.google-services' dependencies { // ... implementation 'com.google.firebase:firebase-ml-vision:24.0.3' implementation 'com.google.firebase:firebase-ml-vision-automl:18.0.5' }
1. مدل را بارگذاری کنید
ML Kit مدل های تولید شده توسط AutoML شما را روی دستگاه اجرا می کند. با این حال، میتوانید ML Kit را برای بارگیری مدل خود از راه دور از Firebase، از ذخیرهسازی محلی یا هر دو پیکربندی کنید.
با میزبانی مدل در Firebase، میتوانید مدل را بدون انتشار نسخه جدید برنامه بهروزرسانی کنید و میتوانید از Remote Config و A/B Testing برای ارائه پویا مدلهای مختلف به مجموعههای مختلف کاربران استفاده کنید.
اگر ترجیح میدهید مدل را فقط با میزبانی آن در Firebase ارائه دهید، و آن را با برنامه خود همراه نکنید، میتوانید حجم دانلود اولیه برنامه خود را کاهش دهید. البته به خاطر داشته باشید که اگر مدل با برنامه شما همراه نباشد، تا زمانی که برنامه شما برای اولین بار مدل را دانلود نکند، هیچ عملکرد مرتبط با مدل در دسترس نخواهد بود.
با بستهبندی مدل خود با برنامهتان، میتوانید مطمئن شوید که ویژگیهای ML برنامهتان همچنان در زمانی که مدل میزبانی شده توسط Firebase در دسترس نیست، کار میکنند.
یک منبع مدل میزبانی شده توسط Firebase را پیکربندی کنید
برای استفاده از مدل میزبانی از راه دور، یک شی FirebaseAutoMLRemoteModel
ایجاد کنید و نامی را که به مدل اختصاص داده اید در هنگام انتشار آن مشخص کنید:
Java
// Specify the name you assigned in the Firebase console.
FirebaseAutoMLRemoteModel remoteModel =
new FirebaseAutoMLRemoteModel.Builder("your_remote_model").build();
Kotlin+KTX
// Specify the name you assigned in the Firebase console.
val remoteModel = FirebaseAutoMLRemoteModel.Builder("your_remote_model").build()
سپس، با مشخص کردن شرایطی که میخواهید اجازه دانلود را بدهید، کار دانلود مدل را شروع کنید. اگر مدل در دستگاه نباشد، یا اگر نسخه جدیدتری از مدل موجود باشد، این کار به صورت ناهمزمان مدل را از Firebase دانلود میکند:
Java
FirebaseModelDownloadConditions conditions = new FirebaseModelDownloadConditions.Builder()
.requireWifi()
.build();
FirebaseModelManager.getInstance().download(remoteModel, conditions)
.addOnCompleteListener(new OnCompleteListener<Void>() {
@Override
public void onComplete(@NonNull Task<Void> task) {
// Success.
}
});
Kotlin+KTX
val conditions = FirebaseModelDownloadConditions.Builder()
.requireWifi()
.build()
FirebaseModelManager.getInstance().download(remoteModel, conditions)
.addOnCompleteListener {
// Success.
}
بسیاری از برنامهها وظیفه دانلود را در کد اولیه خود شروع میکنند، اما شما میتوانید این کار را در هر زمانی قبل از نیاز به استفاده از مدل انجام دهید.
یک منبع مدل محلی را پیکربندی کنید
برای بستهبندی مدل با برنامهتان:
- مدل و ابرداده آن را از آرشیو فشرده ای که از کنسول Firebase دانلود کرده اید استخراج کنید. توصیه میکنیم از فایلها در حین دانلود، بدون تغییر (از جمله نام فایل) استفاده کنید.
مدل خود و فایل های فراداده آن را در بسته برنامه خود قرار دهید:
- اگر در پروژه خود پوشه دارایی ندارید، با کلیک راست روی پوشه
app/
، سپس روی New > Folder > Assets Folder کلیک کنید. - یک پوشه فرعی در زیر پوشه assets ایجاد کنید تا حاوی فایل های مدل باشد.
- فایلهای
model.tflite
،dict.txt
وmanifest.json
را در پوشه فرعی کپی کنید (هر سه فایل باید در یک پوشه باشند).
- اگر در پروژه خود پوشه دارایی ندارید، با کلیک راست روی پوشه
- موارد زیر را به فایل
build.gradle
برنامه خود اضافه کنید تا مطمئن شوید که Gradle فایل مدل را هنگام ساخت برنامه فشرده نمی کند:android { // ... aaptOptions { noCompress "tflite" } }
فایل مدل در بسته برنامه گنجانده شده و به عنوان دارایی خام در اختیار ML Kit قرار خواهد گرفت. - یک شی
FirebaseAutoMLLocalModel
ایجاد کنید و مسیر فایل مانیفست مدل را مشخص کنید:Java
FirebaseAutoMLLocalModel localModel = new FirebaseAutoMLLocalModel.Builder() .setAssetFilePath("manifest.json") .build();
Kotlin+KTX
val localModel = FirebaseAutoMLLocalModel.Builder() .setAssetFilePath("manifest.json") .build()
یک برچسب تصویر از مدل خود ایجاد کنید
پس از پیکربندی منابع مدل خود، یک شی FirebaseVisionImageLabeler
از یکی از آنها ایجاد کنید.
اگر فقط یک مدل به صورت محلی دارید، فقط یک برچسب از شی FirebaseAutoMLLocalModel
خود ایجاد کنید و آستانه امتیاز اطمینان مورد نیاز خود را پیکربندی کنید ( به ارزیابی مدل خود مراجعه کنید):
Java
FirebaseVisionImageLabeler labeler;
try {
FirebaseVisionOnDeviceAutoMLImageLabelerOptions options =
new FirebaseVisionOnDeviceAutoMLImageLabelerOptions.Builder(localModel)
.setConfidenceThreshold(0.0f) // Evaluate your model in the Firebase console
// to determine an appropriate value.
.build();
labeler = FirebaseVision.getInstance().getOnDeviceAutoMLImageLabeler(options);
} catch (FirebaseMLException e) {
// ...
}
Kotlin+KTX
val options = FirebaseVisionOnDeviceAutoMLImageLabelerOptions.Builder(localModel)
.setConfidenceThreshold(0) // Evaluate your model in the Firebase console
// to determine an appropriate value.
.build()
val labeler = FirebaseVision.getInstance().getOnDeviceAutoMLImageLabeler(options)
اگر یک مدل با میزبانی از راه دور دارید، قبل از اجرای آن باید بررسی کنید که دانلود شده است. با استفاده از متد isModelDownloaded()
مدیر مدل می توانید وضعیت وظیفه دانلود مدل را بررسی کنید.
اگرچه شما فقط باید قبل از اجرای برچسبگذار این موضوع را تأیید کنید، اگر هم یک مدل با میزبانی از راه دور و هم یک مدل بستهبندی محلی دارید، ممکن است این بررسی را هنگام نمونهسازی برچسبکننده تصویر انجام دهید: یک برچسبگذار از مدل راه دور ایجاد کنید اگر دانلود شده است، و در غیر این صورت از مدل محلی.
Java
FirebaseModelManager.getInstance().isModelDownloaded(remoteModel)
.addOnSuccessListener(new OnSuccessListener<Boolean>() {
@Override
public void onSuccess(Boolean isDownloaded) {
FirebaseVisionOnDeviceAutoMLImageLabelerOptions.Builder optionsBuilder;
if (isDownloaded) {
optionsBuilder = new FirebaseVisionOnDeviceAutoMLImageLabelerOptions.Builder(remoteModel);
} else {
optionsBuilder = new FirebaseVisionOnDeviceAutoMLImageLabelerOptions.Builder(localModel);
}
FirebaseVisionOnDeviceAutoMLImageLabelerOptions options = optionsBuilder
.setConfidenceThreshold(0.0f) // Evaluate your model in the Firebase console
// to determine an appropriate threshold.
.build();
FirebaseVisionImageLabeler labeler;
try {
labeler = FirebaseVision.getInstance().getOnDeviceAutoMLImageLabeler(options);
} catch (FirebaseMLException e) {
// Error.
}
}
});
Kotlin+KTX
FirebaseModelManager.getInstance().isModelDownloaded(remoteModel)
.addOnSuccessListener { isDownloaded ->
val optionsBuilder =
if (isDownloaded) {
FirebaseVisionOnDeviceAutoMLImageLabelerOptions.Builder(remoteModel)
} else {
FirebaseVisionOnDeviceAutoMLImageLabelerOptions.Builder(localModel)
}
// Evaluate your model in the Firebase console to determine an appropriate threshold.
val options = optionsBuilder.setConfidenceThreshold(0.0f).build()
val labeler = FirebaseVision.getInstance().getOnDeviceAutoMLImageLabeler(options)
}
اگر فقط یک مدل با میزبانی از راه دور دارید، باید عملکردهای مربوط به مدل را غیرفعال کنید - به عنوان مثال، خاکستری کردن یا پنهان کردن بخشی از رابط کاربری خود - تا زمانی که تأیید کنید مدل دانلود شده است. می توانید این کار را با پیوست کردن شنونده به متد download()
مدیر مدل انجام دهید:
Java
FirebaseModelManager.getInstance().download(remoteModel, conditions)
.addOnSuccessListener(new OnSuccessListener<Void>() {
@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.
}
});
Kotlin+KTX
FirebaseModelManager.getInstance().download(remoteModel, conditions)
.addOnCompleteListener {
// Download complete. Depending on your app, you could enable the ML
// feature, or switch from the local model to the remote model, etc.
}
2. تصویر ورودی را آماده کنید
سپس، برای هر تصویری که می خواهید برچسب گذاری کنید، با استفاده از یکی از گزینه های توضیح داده شده در این بخش، یک شی FirebaseVisionImage
ایجاد کنید و آن را به نمونه ای از FirebaseVisionImageLabeler
(شرح داده شده در بخش بعدی) ارسال کنید.
میتوانید یک شی FirebaseVisionImage
از یک شی media.Image
، یک فایل روی دستگاه، یک آرایه بایت یا یک شی Bitmap
ایجاد کنید:
برای ایجاد یک شی
FirebaseVisionImage
از یک شیmedia.Image
، مانند هنگام گرفتن تصویر از دوربین دستگاه، شیmedia.Image
.Image و چرخش تصویر را بهFirebaseVisionImage.fromMediaImage()
منتقل کنید.اگر از کتابخانه CameraX ، کلاسهای
OnImageCapturedListener
وImageAnalysis.Analyzer
استفاده میکنید، مقدار چرخش را برای شما محاسبه میکنند، بنابراین فقط باید قبل از فراخوانیFirebaseVisionImage.fromMediaImage()
چرخش را به یکی از ثابتهایROTATION_
ML Kit تبدیل کنید:Java
private class YourAnalyzer implements ImageAnalysis.Analyzer { private int degreesToFirebaseRotation(int degrees) { switch (degrees) { case 0: return FirebaseVisionImageMetadata.ROTATION_0; case 90: return FirebaseVisionImageMetadata.ROTATION_90; case 180: return FirebaseVisionImageMetadata.ROTATION_180; case 270: return FirebaseVisionImageMetadata.ROTATION_270; default: throw new IllegalArgumentException( "Rotation must be 0, 90, 180, or 270."); } } @Override public void analyze(ImageProxy imageProxy, int degrees) { if (imageProxy == null || imageProxy.getImage() == null) { return; } Image mediaImage = imageProxy.getImage(); int rotation = degreesToFirebaseRotation(degrees); FirebaseVisionImage image = FirebaseVisionImage.fromMediaImage(mediaImage, rotation); // Pass image to an ML Kit Vision API // ... } }
Kotlin+KTX
private class YourImageAnalyzer : ImageAnalysis.Analyzer { private fun degreesToFirebaseRotation(degrees: Int): Int = when(degrees) { 0 -> FirebaseVisionImageMetadata.ROTATION_0 90 -> FirebaseVisionImageMetadata.ROTATION_90 180 -> FirebaseVisionImageMetadata.ROTATION_180 270 -> FirebaseVisionImageMetadata.ROTATION_270 else -> throw Exception("Rotation must be 0, 90, 180, or 270.") } override fun analyze(imageProxy: ImageProxy?, degrees: Int) { val mediaImage = imageProxy?.image val imageRotation = degreesToFirebaseRotation(degrees) if (mediaImage != null) { val image = FirebaseVisionImage.fromMediaImage(mediaImage, imageRotation) // Pass image to an ML Kit Vision API // ... } } }
اگر از کتابخانه دوربینی که چرخش تصویر را به شما می دهد استفاده نمی کنید، می توانید آن را از روی چرخش دستگاه و جهت سنسور دوربین در دستگاه محاسبه کنید:
Java
private static final SparseIntArray ORIENTATIONS = new SparseIntArray(); static { ORIENTATIONS.append(Surface.ROTATION_0, 90); ORIENTATIONS.append(Surface.ROTATION_90, 0); ORIENTATIONS.append(Surface.ROTATION_180, 270); ORIENTATIONS.append(Surface.ROTATION_270, 180); } /** * 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, Context context) 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); // On most devices, the sensor orientation is 90 degrees, but for some // devices it is 270 degrees. For devices with a sensor orientation of // 270, rotate the image an additional 180 ((270 + 270) % 360) degrees. CameraManager cameraManager = (CameraManager) context.getSystemService(CAMERA_SERVICE); int sensorOrientation = cameraManager .getCameraCharacteristics(cameraId) .get(CameraCharacteristics.SENSOR_ORIENTATION); rotationCompensation = (rotationCompensation + sensorOrientation + 270) % 360; // Return the corresponding FirebaseVisionImageMetadata rotation value. int result; switch (rotationCompensation) { case 0: result = FirebaseVisionImageMetadata.ROTATION_0; break; case 90: result = FirebaseVisionImageMetadata.ROTATION_90; break; case 180: result = FirebaseVisionImageMetadata.ROTATION_180; break; case 270: result = FirebaseVisionImageMetadata.ROTATION_270; break; default: result = FirebaseVisionImageMetadata.ROTATION_0; Log.e(TAG, "Bad rotation value: " + rotationCompensation); } return result; }
Kotlin+KTX
private val ORIENTATIONS = SparseIntArray() init { ORIENTATIONS.append(Surface.ROTATION_0, 90) ORIENTATIONS.append(Surface.ROTATION_90, 0) ORIENTATIONS.append(Surface.ROTATION_180, 270) ORIENTATIONS.append(Surface.ROTATION_270, 180) } /** * 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, context: Context): 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) // On most devices, the sensor orientation is 90 degrees, but for some // devices it is 270 degrees. For devices with a sensor orientation of // 270, rotate the image an additional 180 ((270 + 270) % 360) degrees. val cameraManager = context.getSystemService(CAMERA_SERVICE) as CameraManager val sensorOrientation = cameraManager .getCameraCharacteristics(cameraId) .get(CameraCharacteristics.SENSOR_ORIENTATION)!! rotationCompensation = (rotationCompensation + sensorOrientation + 270) % 360 // Return the corresponding FirebaseVisionImageMetadata rotation value. val result: Int when (rotationCompensation) { 0 -> result = FirebaseVisionImageMetadata.ROTATION_0 90 -> result = FirebaseVisionImageMetadata.ROTATION_90 180 -> result = FirebaseVisionImageMetadata.ROTATION_180 270 -> result = FirebaseVisionImageMetadata.ROTATION_270 else -> { result = FirebaseVisionImageMetadata.ROTATION_0 Log.e(TAG, "Bad rotation value: $rotationCompensation") } } return result }
سپس، شی
media.Image
و مقدار چرخش را بهFirebaseVisionImage.fromMediaImage()
ارسال کنید:Java
FirebaseVisionImage image = FirebaseVisionImage.fromMediaImage(mediaImage, rotation);
Kotlin+KTX
val image = FirebaseVisionImage.fromMediaImage(mediaImage, rotation)
- برای ایجاد یک شی
FirebaseVisionImage
از URI فایل، زمینه برنامه و فایل URI را بهFirebaseVisionImage.fromFilePath()
ارسال کنید. این زمانی مفید است که از یک هدفACTION_GET_CONTENT
استفاده می کنید تا از کاربر بخواهید تصویری را از برنامه گالری خود انتخاب کند.Java
FirebaseVisionImage image; try { image = FirebaseVisionImage.fromFilePath(context, uri); } catch (IOException e) { e.printStackTrace(); }
Kotlin+KTX
val image: FirebaseVisionImage try { image = FirebaseVisionImage.fromFilePath(context, uri) } catch (e: IOException) { e.printStackTrace() }
- برای ایجاد یک شی
FirebaseVisionImage
از یکByteBuffer
یا یک آرایه بایت، ابتدا چرخش تصویر را همانطور که در بالا برای ورودیmedia.Image
توضیح داده شد محاسبه کنید.سپس، یک شی
FirebaseVisionImageMetadata
ایجاد کنید که شامل ارتفاع، عرض، فرمت کدگذاری رنگ و چرخش تصویر باشد:Java
FirebaseVisionImageMetadata metadata = new FirebaseVisionImageMetadata.Builder() .setWidth(480) // 480x360 is typically sufficient for .setHeight(360) // image recognition .setFormat(FirebaseVisionImageMetadata.IMAGE_FORMAT_NV21) .setRotation(rotation) .build();
Kotlin+KTX
val metadata = FirebaseVisionImageMetadata.Builder() .setWidth(480) // 480x360 is typically sufficient for .setHeight(360) // image recognition .setFormat(FirebaseVisionImageMetadata.IMAGE_FORMAT_NV21) .setRotation(rotation) .build()
برای ایجاد یک شی
FirebaseVisionImage
از بافر یا آرایه و شیء فراداده استفاده کنید:Java
FirebaseVisionImage image = FirebaseVisionImage.fromByteBuffer(buffer, metadata); // Or: FirebaseVisionImage image = FirebaseVisionImage.fromByteArray(byteArray, metadata);
Kotlin+KTX
val image = FirebaseVisionImage.fromByteBuffer(buffer, metadata) // Or: val image = FirebaseVisionImage.fromByteArray(byteArray, metadata)
- برای ایجاد یک شی
FirebaseVisionImage
از یک شیBitmap
:تصویر نمایش داده شده توسط شیJava
FirebaseVisionImage image = FirebaseVisionImage.fromBitmap(bitmap);
Kotlin+KTX
val image = FirebaseVisionImage.fromBitmap(bitmap)
Bitmap
باید عمودی باشد، بدون نیاز به چرخش اضافی.
3. برچسب تصویر را اجرا کنید
برای برچسب گذاری اشیاء در یک تصویر، شی FirebaseVisionImage
را به متد processImage()
FirebaseVisionImageLabeler
ارسال کنید.
Java
labeler.processImage(image)
.addOnSuccessListener(new OnSuccessListener<List<FirebaseVisionImageLabel>>() {
@Override
public void onSuccess(List<FirebaseVisionImageLabel> labels) {
// Task completed successfully
// ...
}
})
.addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(@NonNull Exception e) {
// Task failed with an exception
// ...
}
});
Kotlin+KTX
labeler.processImage(image)
.addOnSuccessListener { labels ->
// Task completed successfully
// ...
}
.addOnFailureListener { e ->
// Task failed with an exception
// ...
}
اگر برچسبگذاری تصویر با موفقیت انجام شود، آرایهای از اشیاء FirebaseVisionImageLabel
به شنونده موفقیت ارسال میشود. از هر شی، می توانید اطلاعاتی در مورد ویژگی شناسایی شده در تصویر دریافت کنید.
به عنوان مثال:
Java
for (FirebaseVisionImageLabel label: labels) {
String text = label.getText();
float confidence = label.getConfidence();
}
Kotlin+KTX
for (label in labels) {
val text = label.text
val confidence = label.confidence
}
نکاتی برای بهبود عملکرد در زمان واقعی
- دریچه گاز به آشکارساز زنگ می زند. اگر یک قاب ویدیویی جدید در حین کار کردن آشکارساز در دسترس قرار گرفت، قاب را رها کنید.
- اگر از خروجی آشکارساز برای همپوشانی گرافیک روی تصویر ورودی استفاده میکنید، ابتدا نتیجه را از کیت ML دریافت کنید، سپس تصویر را رندر کنید و در یک مرحله همپوشانی کنید. با انجام این کار، برای هر فریم ورودی فقط یک بار به سطح نمایشگر رندر می دهید.
اگر از Camera2 API استفاده می کنید، تصاویر را با فرمت
ImageFormat.YUV_420_888
بگیرید.اگر از دوربین قدیمیتر API استفاده میکنید، تصاویر را با فرمت
ImageFormat.NV21
بگیرید.
بعد از اینکه مدل خود را با استفاده از AutoML Vision Edge آموزش دادید ، میتوانید از آن در برنامه خود برای برچسبگذاری تصاویر استفاده کنید.
قبل از شروع
- اگر قبلاً این کار را نکردهاید، Firebase را به پروژه Android خود اضافه کنید .
- وابستگی های کتابخانه های اندروید ML Kit را به فایل Gradle ماژول (سطح برنامه) خود اضافه کنید (معمولا
app/build.gradle
):apply plugin: 'com.android.application' apply plugin: 'com.google.gms.google-services' dependencies { // ... implementation 'com.google.firebase:firebase-ml-vision:24.0.3' implementation 'com.google.firebase:firebase-ml-vision-automl:18.0.5' }
1. مدل را بارگذاری کنید
ML Kit مدل های تولید شده توسط AutoML شما را روی دستگاه اجرا می کند. با این حال، میتوانید ML Kit را برای بارگیری مدل خود از راه دور از Firebase، از ذخیرهسازی محلی یا هر دو پیکربندی کنید.
با میزبانی مدل در Firebase، میتوانید مدل را بدون انتشار نسخه جدید برنامه بهروزرسانی کنید و میتوانید از Remote Config و A/B Testing برای ارائه پویا مدلهای مختلف به مجموعههای مختلف کاربران استفاده کنید.
اگر ترجیح میدهید مدل را فقط با میزبانی آن در Firebase ارائه دهید، و آن را با برنامه خود همراه نکنید، میتوانید حجم دانلود اولیه برنامه خود را کاهش دهید. البته به خاطر داشته باشید که اگر مدل با برنامه شما همراه نباشد، تا زمانی که برنامه شما برای اولین بار مدل را دانلود نکند، هیچ عملکرد مرتبط با مدل در دسترس نخواهد بود.
با بستهبندی مدل خود با برنامهتان، میتوانید مطمئن شوید که ویژگیهای ML برنامهتان همچنان در زمانی که مدل میزبانی شده توسط Firebase در دسترس نیست، کار میکنند.
یک منبع مدل میزبانی شده توسط Firebase را پیکربندی کنید
برای استفاده از مدل میزبانی از راه دور، یک شی FirebaseAutoMLRemoteModel
ایجاد کنید و نامی را که به مدل اختصاص داده اید در هنگام انتشار آن مشخص کنید:
Java
// Specify the name you assigned in the Firebase console.
FirebaseAutoMLRemoteModel remoteModel =
new FirebaseAutoMLRemoteModel.Builder("your_remote_model").build();
Kotlin+KTX
// Specify the name you assigned in the Firebase console.
val remoteModel = FirebaseAutoMLRemoteModel.Builder("your_remote_model").build()
سپس، با مشخص کردن شرایطی که میخواهید اجازه دانلود را بدهید، کار دانلود مدل را شروع کنید. اگر مدل در دستگاه نباشد، یا اگر نسخه جدیدتری از مدل موجود باشد، این کار به صورت ناهمزمان مدل را از Firebase دانلود میکند:
Java
FirebaseModelDownloadConditions conditions = new FirebaseModelDownloadConditions.Builder()
.requireWifi()
.build();
FirebaseModelManager.getInstance().download(remoteModel, conditions)
.addOnCompleteListener(new OnCompleteListener<Void>() {
@Override
public void onComplete(@NonNull Task<Void> task) {
// Success.
}
});
Kotlin+KTX
val conditions = FirebaseModelDownloadConditions.Builder()
.requireWifi()
.build()
FirebaseModelManager.getInstance().download(remoteModel, conditions)
.addOnCompleteListener {
// Success.
}
بسیاری از برنامهها وظیفه دانلود را در کد اولیه خود شروع میکنند، اما شما میتوانید این کار را در هر زمانی قبل از نیاز به استفاده از مدل انجام دهید.
یک منبع مدل محلی را پیکربندی کنید
برای بستهبندی مدل با برنامهتان:
- مدل و ابرداده آن را از آرشیو فشرده ای که از کنسول Firebase دانلود کرده اید استخراج کنید. توصیه میکنیم از فایلها در حین دانلود، بدون تغییر (از جمله نام فایل) استفاده کنید.
مدل خود و فایل های فراداده آن را در بسته برنامه خود قرار دهید:
- اگر در پروژه خود پوشه دارایی ندارید، با کلیک راست روی پوشه
app/
، سپس روی New > Folder > Assets Folder کلیک کنید. - یک پوشه فرعی در زیر پوشه assets ایجاد کنید تا حاوی فایل های مدل باشد.
- فایلهای
model.tflite
،dict.txt
وmanifest.json
را در پوشه فرعی کپی کنید (هر سه فایل باید در یک پوشه باشند).
- اگر در پروژه خود پوشه دارایی ندارید، با کلیک راست روی پوشه
- موارد زیر را به فایل
build.gradle
برنامه خود اضافه کنید تا مطمئن شوید که Gradle فایل مدل را هنگام ساخت برنامه فشرده نمی کند:android { // ... aaptOptions { noCompress "tflite" } }
فایل مدل در بسته برنامه گنجانده شده و به عنوان دارایی خام در اختیار ML Kit قرار خواهد گرفت. - یک شی
FirebaseAutoMLLocalModel
ایجاد کنید و مسیر فایل مانیفست مدل را مشخص کنید:Java
FirebaseAutoMLLocalModel localModel = new FirebaseAutoMLLocalModel.Builder() .setAssetFilePath("manifest.json") .build();
Kotlin+KTX
val localModel = FirebaseAutoMLLocalModel.Builder() .setAssetFilePath("manifest.json") .build()
یک برچسب تصویر از مدل خود ایجاد کنید
پس از پیکربندی منابع مدل خود، یک شی FirebaseVisionImageLabeler
از یکی از آنها ایجاد کنید.
اگر فقط یک مدل به صورت محلی دارید، فقط یک برچسب از شی FirebaseAutoMLLocalModel
خود ایجاد کنید و آستانه امتیاز اطمینان مورد نیاز خود را پیکربندی کنید ( به ارزیابی مدل خود مراجعه کنید):
Java
FirebaseVisionImageLabeler labeler;
try {
FirebaseVisionOnDeviceAutoMLImageLabelerOptions options =
new FirebaseVisionOnDeviceAutoMLImageLabelerOptions.Builder(localModel)
.setConfidenceThreshold(0.0f) // Evaluate your model in the Firebase console
// to determine an appropriate value.
.build();
labeler = FirebaseVision.getInstance().getOnDeviceAutoMLImageLabeler(options);
} catch (FirebaseMLException e) {
// ...
}
Kotlin+KTX
val options = FirebaseVisionOnDeviceAutoMLImageLabelerOptions.Builder(localModel)
.setConfidenceThreshold(0) // Evaluate your model in the Firebase console
// to determine an appropriate value.
.build()
val labeler = FirebaseVision.getInstance().getOnDeviceAutoMLImageLabeler(options)
اگر یک مدل با میزبانی از راه دور دارید، قبل از اجرای آن باید بررسی کنید که دانلود شده است. با استفاده از متد isModelDownloaded()
مدیر مدل می توانید وضعیت وظیفه دانلود مدل را بررسی کنید.
اگرچه شما فقط باید قبل از اجرای برچسبگذار این موضوع را تأیید کنید، اگر هم یک مدل با میزبانی از راه دور و هم یک مدل بستهبندی محلی دارید، ممکن است این بررسی را هنگام نمونهسازی برچسبکننده تصویر انجام دهید: یک برچسبگذار از مدل راه دور ایجاد کنید اگر دانلود شده است، و در غیر این صورت از مدل محلی.
Java
FirebaseModelManager.getInstance().isModelDownloaded(remoteModel)
.addOnSuccessListener(new OnSuccessListener<Boolean>() {
@Override
public void onSuccess(Boolean isDownloaded) {
FirebaseVisionOnDeviceAutoMLImageLabelerOptions.Builder optionsBuilder;
if (isDownloaded) {
optionsBuilder = new FirebaseVisionOnDeviceAutoMLImageLabelerOptions.Builder(remoteModel);
} else {
optionsBuilder = new FirebaseVisionOnDeviceAutoMLImageLabelerOptions.Builder(localModel);
}
FirebaseVisionOnDeviceAutoMLImageLabelerOptions options = optionsBuilder
.setConfidenceThreshold(0.0f) // Evaluate your model in the Firebase console
// to determine an appropriate threshold.
.build();
FirebaseVisionImageLabeler labeler;
try {
labeler = FirebaseVision.getInstance().getOnDeviceAutoMLImageLabeler(options);
} catch (FirebaseMLException e) {
// Error.
}
}
});
Kotlin+KTX
FirebaseModelManager.getInstance().isModelDownloaded(remoteModel)
.addOnSuccessListener { isDownloaded ->
val optionsBuilder =
if (isDownloaded) {
FirebaseVisionOnDeviceAutoMLImageLabelerOptions.Builder(remoteModel)
} else {
FirebaseVisionOnDeviceAutoMLImageLabelerOptions.Builder(localModel)
}
// Evaluate your model in the Firebase console to determine an appropriate threshold.
val options = optionsBuilder.setConfidenceThreshold(0.0f).build()
val labeler = FirebaseVision.getInstance().getOnDeviceAutoMLImageLabeler(options)
}
اگر فقط یک مدل با میزبانی از راه دور دارید، باید عملکردهای مربوط به مدل را غیرفعال کنید - به عنوان مثال، خاکستری کردن یا پنهان کردن بخشی از رابط کاربری خود - تا زمانی که تأیید کنید مدل دانلود شده است. می توانید این کار را با پیوست کردن شنونده به متد download()
مدیر مدل انجام دهید:
Java
FirebaseModelManager.getInstance().download(remoteModel, conditions)
.addOnSuccessListener(new OnSuccessListener<Void>() {
@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.
}
});
Kotlin+KTX
FirebaseModelManager.getInstance().download(remoteModel, conditions)
.addOnCompleteListener {
// Download complete. Depending on your app, you could enable the ML
// feature, or switch from the local model to the remote model, etc.
}
2. تصویر ورودی را آماده کنید
سپس، برای هر تصویری که می خواهید برچسب گذاری کنید، با استفاده از یکی از گزینه های توضیح داده شده در این بخش، یک شی FirebaseVisionImage
ایجاد کنید و آن را به نمونه ای از FirebaseVisionImageLabeler
(شرح داده شده در بخش بعدی) ارسال کنید.
میتوانید یک شی FirebaseVisionImage
از یک شی media.Image
، یک فایل روی دستگاه، یک آرایه بایت یا یک شی Bitmap
ایجاد کنید:
برای ایجاد یک شی
FirebaseVisionImage
از یک شیmedia.Image
، مانند هنگام گرفتن تصویر از دوربین دستگاه، شیmedia.Image
.Image و چرخش تصویر را بهFirebaseVisionImage.fromMediaImage()
منتقل کنید.اگر از کتابخانه CameraX ، کلاسهای
OnImageCapturedListener
وImageAnalysis.Analyzer
استفاده میکنید، مقدار چرخش را برای شما محاسبه میکنند، بنابراین فقط باید قبل از فراخوانیFirebaseVisionImage.fromMediaImage()
چرخش را به یکی از ثابتهایROTATION_
ML Kit تبدیل کنید:Java
private class YourAnalyzer implements ImageAnalysis.Analyzer { private int degreesToFirebaseRotation(int degrees) { switch (degrees) { case 0: return FirebaseVisionImageMetadata.ROTATION_0; case 90: return FirebaseVisionImageMetadata.ROTATION_90; case 180: return FirebaseVisionImageMetadata.ROTATION_180; case 270: return FirebaseVisionImageMetadata.ROTATION_270; default: throw new IllegalArgumentException( "Rotation must be 0, 90, 180, or 270."); } } @Override public void analyze(ImageProxy imageProxy, int degrees) { if (imageProxy == null || imageProxy.getImage() == null) { return; } Image mediaImage = imageProxy.getImage(); int rotation = degreesToFirebaseRotation(degrees); FirebaseVisionImage image = FirebaseVisionImage.fromMediaImage(mediaImage, rotation); // Pass image to an ML Kit Vision API // ... } }
Kotlin+KTX
private class YourImageAnalyzer : ImageAnalysis.Analyzer { private fun degreesToFirebaseRotation(degrees: Int): Int = when(degrees) { 0 -> FirebaseVisionImageMetadata.ROTATION_0 90 -> FirebaseVisionImageMetadata.ROTATION_90 180 -> FirebaseVisionImageMetadata.ROTATION_180 270 -> FirebaseVisionImageMetadata.ROTATION_270 else -> throw Exception("Rotation must be 0, 90, 180, or 270.") } override fun analyze(imageProxy: ImageProxy?, degrees: Int) { val mediaImage = imageProxy?.image val imageRotation = degreesToFirebaseRotation(degrees) if (mediaImage != null) { val image = FirebaseVisionImage.fromMediaImage(mediaImage, imageRotation) // Pass image to an ML Kit Vision API // ... } } }
اگر از کتابخانه دوربینی که چرخش تصویر را به شما می دهد استفاده نمی کنید، می توانید آن را از روی چرخش دستگاه و جهت سنسور دوربین در دستگاه محاسبه کنید:
Java
private static final SparseIntArray ORIENTATIONS = new SparseIntArray(); static { ORIENTATIONS.append(Surface.ROTATION_0, 90); ORIENTATIONS.append(Surface.ROTATION_90, 0); ORIENTATIONS.append(Surface.ROTATION_180, 270); ORIENTATIONS.append(Surface.ROTATION_270, 180); } /** * 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, Context context) 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); // On most devices, the sensor orientation is 90 degrees, but for some // devices it is 270 degrees. For devices with a sensor orientation of // 270, rotate the image an additional 180 ((270 + 270) % 360) degrees. CameraManager cameraManager = (CameraManager) context.getSystemService(CAMERA_SERVICE); int sensorOrientation = cameraManager .getCameraCharacteristics(cameraId) .get(CameraCharacteristics.SENSOR_ORIENTATION); rotationCompensation = (rotationCompensation + sensorOrientation + 270) % 360; // Return the corresponding FirebaseVisionImageMetadata rotation value. int result; switch (rotationCompensation) { case 0: result = FirebaseVisionImageMetadata.ROTATION_0; break; case 90: result = FirebaseVisionImageMetadata.ROTATION_90; break; case 180: result = FirebaseVisionImageMetadata.ROTATION_180; break; case 270: result = FirebaseVisionImageMetadata.ROTATION_270; break; default: result = FirebaseVisionImageMetadata.ROTATION_0; Log.e(TAG, "Bad rotation value: " + rotationCompensation); } return result; }
Kotlin+KTX
private val ORIENTATIONS = SparseIntArray() init { ORIENTATIONS.append(Surface.ROTATION_0, 90) ORIENTATIONS.append(Surface.ROTATION_90, 0) ORIENTATIONS.append(Surface.ROTATION_180, 270) ORIENTATIONS.append(Surface.ROTATION_270, 180) } /** * 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, context: Context): 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) // On most devices, the sensor orientation is 90 degrees, but for some // devices it is 270 degrees. For devices with a sensor orientation of // 270, rotate the image an additional 180 ((270 + 270) % 360) degrees. val cameraManager = context.getSystemService(CAMERA_SERVICE) as CameraManager val sensorOrientation = cameraManager .getCameraCharacteristics(cameraId) .get(CameraCharacteristics.SENSOR_ORIENTATION)!! rotationCompensation = (rotationCompensation + sensorOrientation + 270) % 360 // Return the corresponding FirebaseVisionImageMetadata rotation value. val result: Int when (rotationCompensation) { 0 -> result = FirebaseVisionImageMetadata.ROTATION_0 90 -> result = FirebaseVisionImageMetadata.ROTATION_90 180 -> result = FirebaseVisionImageMetadata.ROTATION_180 270 -> result = FirebaseVisionImageMetadata.ROTATION_270 else -> { result = FirebaseVisionImageMetadata.ROTATION_0 Log.e(TAG, "Bad rotation value: $rotationCompensation") } } return result }
سپس، شی
media.Image
و مقدار چرخش را بهFirebaseVisionImage.fromMediaImage()
ارسال کنید:Java
FirebaseVisionImage image = FirebaseVisionImage.fromMediaImage(mediaImage, rotation);
Kotlin+KTX
val image = FirebaseVisionImage.fromMediaImage(mediaImage, rotation)
- برای ایجاد یک شی
FirebaseVisionImage
از URI فایل، زمینه برنامه و فایل URI را بهFirebaseVisionImage.fromFilePath()
ارسال کنید. این زمانی مفید است که از یک هدفACTION_GET_CONTENT
استفاده می کنید تا از کاربر بخواهید تصویری را از برنامه گالری خود انتخاب کند.Java
FirebaseVisionImage image; try { image = FirebaseVisionImage.fromFilePath(context, uri); } catch (IOException e) { e.printStackTrace(); }
Kotlin+KTX
val image: FirebaseVisionImage try { image = FirebaseVisionImage.fromFilePath(context, uri) } catch (e: IOException) { e.printStackTrace() }
- برای ایجاد یک شی
FirebaseVisionImage
از یکByteBuffer
یا یک آرایه بایت، ابتدا چرخش تصویر را همانطور که در بالا برای ورودیmedia.Image
توضیح داده شد محاسبه کنید.سپس، یک شی
FirebaseVisionImageMetadata
ایجاد کنید که شامل ارتفاع، عرض، فرمت کدگذاری رنگ و چرخش تصویر باشد:Java
FirebaseVisionImageMetadata metadata = new FirebaseVisionImageMetadata.Builder() .setWidth(480) // 480x360 is typically sufficient for .setHeight(360) // image recognition .setFormat(FirebaseVisionImageMetadata.IMAGE_FORMAT_NV21) .setRotation(rotation) .build();
Kotlin+KTX
val metadata = FirebaseVisionImageMetadata.Builder() .setWidth(480) // 480x360 is typically sufficient for .setHeight(360) // image recognition .setFormat(FirebaseVisionImageMetadata.IMAGE_FORMAT_NV21) .setRotation(rotation) .build()
برای ایجاد یک شی
FirebaseVisionImage
از بافر یا آرایه و شیء فراداده استفاده کنید:Java
FirebaseVisionImage image = FirebaseVisionImage.fromByteBuffer(buffer, metadata); // Or: FirebaseVisionImage image = FirebaseVisionImage.fromByteArray(byteArray, metadata);
Kotlin+KTX
val image = FirebaseVisionImage.fromByteBuffer(buffer, metadata) // Or: val image = FirebaseVisionImage.fromByteArray(byteArray, metadata)
- برای ایجاد یک شی
FirebaseVisionImage
از یک شیBitmap
:تصویر نمایش داده شده توسط شیJava
FirebaseVisionImage image = FirebaseVisionImage.fromBitmap(bitmap);
Kotlin+KTX
val image = FirebaseVisionImage.fromBitmap(bitmap)
Bitmap
باید عمودی باشد، بدون نیاز به چرخش اضافی.
3. برچسب تصویر را اجرا کنید
برای برچسب گذاری اشیاء در یک تصویر، شی FirebaseVisionImage
را به متد processImage()
FirebaseVisionImageLabeler
ارسال کنید.
Java
labeler.processImage(image)
.addOnSuccessListener(new OnSuccessListener<List<FirebaseVisionImageLabel>>() {
@Override
public void onSuccess(List<FirebaseVisionImageLabel> labels) {
// Task completed successfully
// ...
}
})
.addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(@NonNull Exception e) {
// Task failed with an exception
// ...
}
});
Kotlin+KTX
labeler.processImage(image)
.addOnSuccessListener { labels ->
// Task completed successfully
// ...
}
.addOnFailureListener { e ->
// Task failed with an exception
// ...
}
اگر برچسبگذاری تصویر با موفقیت انجام شود، آرایهای از اشیاء FirebaseVisionImageLabel
به شنونده موفقیت ارسال میشود. از هر شی، می توانید اطلاعاتی در مورد ویژگی شناسایی شده در تصویر دریافت کنید.
به عنوان مثال:
Java
for (FirebaseVisionImageLabel label: labels) {
String text = label.getText();
float confidence = label.getConfidence();
}
Kotlin+KTX
for (label in labels) {
val text = label.text
val confidence = label.confidence
}
نکاتی برای بهبود عملکرد در زمان واقعی
- دریچه گاز به آشکارساز زنگ می زند. اگر یک قاب ویدیویی جدید در حین کار کردن آشکارساز در دسترس قرار گرفت، قاب را رها کنید.
- اگر از خروجی آشکارساز برای همپوشانی گرافیک روی تصویر ورودی استفاده میکنید، ابتدا نتیجه را از کیت ML دریافت کنید، سپس تصویر را رندر کنید و در یک مرحله همپوشانی کنید. با انجام این کار، برای هر فریم ورودی فقط یک بار به سطح نمایشگر رندر می دهید.
اگر از Camera2 API استفاده می کنید، تصاویر را با فرمت
ImageFormat.YUV_420_888
بگیرید.اگر از دوربین API قدیمی استفاده می کنید، تصاویر را با فرمت
ImageFormat.NV21
بگیرید.