برای شناسایی و رمزگشایی بارکدها می توانید از کیت ML استفاده کنید.
- اگر قبلاً این کار را نکردهاید، 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-barcode-model:16.0.1' } 
- برای اینکه کیت ML بتواند بارکدها را به طور دقیق بخواند، تصاویر ورودی باید حاوی بارکدهایی باشند که با داده های پیکسلی کافی نشان داده شوند. - نیازهای خاص داده پیکسلی هم به نوع بارکد و هم به مقدار داده ای که در آن کدگذاری می شود بستگی دارد (زیرا اکثر بارکدها از یک بار با طول متغیر پشتیبانی می کنند). به طور کلی، کوچکترین واحد معنی دار بارکد باید حداقل 2 پیکسل عرض داشته باشد (و برای کدهای 2 بعدی، 2 پیکسل بلند باشد). - برای مثال، بارکدهای EAN-13 از میلهها و فضاهایی با عرض 1، 2، 3 یا 4 واحد تشکیل شدهاند، بنابراین تصویر بارکد EAN-13 در حالت ایدهآل دارای نوارها و فضاهایی است که حداقل 2، 4، 6 و عرض 8 پیکسل از آنجایی که یک بارکد EAN-13 در مجموع 95 واحد عرض دارد، بارکد باید حداقل 190 پیکسل باشد. - فرمتهای متراکمتر، مانند PDF417، برای خواندن قابل اطمینان ML Kit به ابعاد پیکسل بیشتری نیاز دارند. به عنوان مثال، یک کد PDF417 می تواند حداکثر 34 کلمه 17 واحدی در یک ردیف داشته باشد که در حالت ایده آل حداقل 1156 پیکسل عرض دارد. 
- فوکوس ضعیف تصویر می تواند به دقت اسکن آسیب برساند. اگر نتایج قابل قبولی دریافت نکردید، از کاربر بخواهید که تصویر را دوباره بگیرد. 
- برای کاربردهای معمولی، ارائه تصویری با وضوح بالاتر (مانند 1280x720 یا 1920x1080) توصیه میشود که باعث میشود بارکدها از فاصلهای دورتر از دوربین قابل تشخیص باشند. - با این حال، در برنامههایی که تأخیر حیاتی است، میتوانید با گرفتن تصاویر با وضوح پایینتر، عملکرد را بهبود ببخشید، اما نیاز دارید که بارکد بیشتر تصویر ورودی را تشکیل دهد. همچنین به نکاتی برای بهبود عملکرد در زمان واقعی مراجعه کنید. 
 به عنوان مثال، برای شناسایی فقط کدهای آزتک و کدهای QR، یک شی FirebaseVisionBarcodeDetectorOptions را مانند مثال زیر بسازید: 
FirebaseVisionBarcodeDetectorOptions options = new FirebaseVisionBarcodeDetectorOptions.Builder() .setBarcodeFormats( FirebaseVisionBarcode.FORMAT_QR_CODE, FirebaseVisionBarcode.FORMAT_AZTEC) .build();
val options = FirebaseVisionBarcodeDetectorOptions.Builder() .setBarcodeFormats( FirebaseVisionBarcode.FORMAT_QR_CODE, FirebaseVisionBarcode.FORMAT_AZTEC) .build()
فرمت های زیر پشتیبانی می شوند:
-  کد 128 ( FORMAT_CODE_128)
-  کد 39 ( FORMAT_CODE_39)
-  کد 93 ( FORMAT_CODE_93)
-  کدابار ( FORMAT_CODABAR)
-  EAN-13 ( FORMAT_EAN_13)
-  EAN-8 ( FORMAT_EAN_8)
-  ITF ( FORMAT_ITF)
-  UPC-A ( FORMAT_UPC_A)
-  UPC-E ( FORMAT_UPC_E)
-  کد QR ( FORMAT_QR_CODE)
-  PDF417 ( FORMAT_PDF417)
-  آزتک ( FORMAT_AZTEC)
-  ماتریس داده ( FORMAT_DATA_MATRIX)
FirebaseVisionImage از Bitmap ، media.Image ، ByteBuffer ، آرایه بایت یا یک فایل روی دستگاه ایجاد کنید. سپس، شی FirebaseVisionImage را به متد detectInImage FirebaseVisionBarcodeDetector ارسال کنید.- یک شی - FirebaseVisionImageاز تصویر خود ایجاد کنید.- برای ایجاد یک شی - 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 - 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 - 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 - 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 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 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 val image = FirebaseVisionImage.fromByteBuffer(buffer, metadata) // Or: val image = FirebaseVisionImage.fromByteArray(byteArray, metadata) 
-  برای ایجاد یک شی FirebaseVisionImageاز یک شیBitmap:تصویر نمایش داده شده توسط شیJava FirebaseVisionImage image = FirebaseVisionImage.fromBitmap(bitmap); Kotlin val image = FirebaseVisionImage.fromBitmap(bitmap) Bitmapباید عمودی باشد، بدون نیاز به چرخش اضافی.
 
- یک نمونه از - FirebaseVisionBarcodeDetectorرا دریافت کنید:- Java - FirebaseVisionBarcodeDetector detector = FirebaseVision.getInstance() .getVisionBarcodeDetector(); // Or, to specify the formats to recognize: // FirebaseVisionBarcodeDetector detector = FirebaseVision.getInstance() // .getVisionBarcodeDetector(options); - Kotlin - val detector = FirebaseVision.getInstance() .visionBarcodeDetector // Or, to specify the formats to recognize: // val detector = FirebaseVision.getInstance() // .getVisionBarcodeDetector(options) 
- در نهایت تصویر را به متد - detectInImageمنتقل کنید:- Java - Task<List<FirebaseVisionBarcode>> result = detector.detectInImage(image) .addOnSuccessListener(new OnSuccessListener<List<FirebaseVisionBarcode>>() { @Override public void onSuccess(List<FirebaseVisionBarcode> barcodes) { // Task completed successfully // ... } }) .addOnFailureListener(new OnFailureListener() { @Override public void onFailure(@NonNull Exception e) { // Task failed with an exception // ... } }); - Kotlin - val result = detector.detectInImage(image) .addOnSuccessListener { barcodes -> // Task completed successfully // ... } .addOnFailureListener { // Task failed with an exception // ... } 
FirebaseVisionBarcode به شنونده موفقیت آمیز ارسال می شود. هر شی FirebaseVisionBarcode نشان دهنده بارکدی است که در تصویر شناسایی شده است. برای هر بارکد، می توانید مختصات مرزی آن را در تصویر ورودی و همچنین داده های خام کدگذاری شده توسط بارکد را دریافت کنید. همچنین، اگر آشکارساز بارکد قادر به تعیین نوع داده های کدگذاری شده توسط بارکد بود، می توانید یک شی حاوی داده های تجزیه شده را دریافت کنید.به عنوان مثال:
for (FirebaseVisionBarcode barcode: barcodes) { Rect bounds = barcode.getBoundingBox(); Point[] corners = barcode.getCornerPoints(); String rawValue = barcode.getRawValue(); int valueType = barcode.getValueType(); // See API reference for complete list of supported types switch (valueType) { case FirebaseVisionBarcode.TYPE_WIFI: String ssid = barcode.getWifi().getSsid(); String password = barcode.getWifi().getPassword(); int type = barcode.getWifi().getEncryptionType(); break; case FirebaseVisionBarcode.TYPE_URL: String title = barcode.getUrl().getTitle(); String url = barcode.getUrl().getUrl(); break; } }
for (barcode in barcodes) { val bounds = barcode.boundingBox val corners = barcode.cornerPoints val rawValue = barcode.rawValue val valueType = barcode.valueType // See API reference for complete list of supported types when (valueType) { FirebaseVisionBarcode.TYPE_WIFI -> { val ssid = barcode.wifi!!.ssid val password = barcode.wifi!!.password val type = barcode.wifi!!.encryptionType } FirebaseVisionBarcode.TYPE_URL -> { val title = barcode.url!!.title val url = barcode.url!!.url } } }
اگر می خواهید بارکدها را در یک برنامه بلادرنگ اسکن کنید، این دستورالعمل ها را برای دستیابی به بهترین نرخ فریم دنبال کنید:
- ورودی را با وضوح اصلی دوربین نگیرید. در برخی از دستگاهها، گرفتن ورودی با وضوح اصلی تصاویر بسیار بزرگ (10+ مگاپیکسل) تولید میکند که منجر به تأخیر بسیار ضعیف و بدون مزیتی برای دقت میشود. در عوض، فقط اندازه ای را از دوربین درخواست کنید که برای تشخیص بارکد لازم است: معمولاً بیش از 2 مگاپیکسل نیست. - اگر سرعت اسکن مهم است، می توانید وضوح تصویربرداری را بیشتر کاهش دهید. با این حال، حداقل الزامات اندازه بارکد که در بالا ذکر شد را در نظر داشته باشید. 
- دریچه گاز به آشکارساز زنگ می زند. اگر یک قاب ویدیویی جدید در حین کار کردن آشکارساز در دسترس قرار گرفت، قاب را رها کنید.
- اگر از خروجی آشکارساز برای همپوشانی گرافیک روی تصویر ورودی استفاده میکنید، ابتدا نتیجه را از کیت ML دریافت کنید، سپس تصویر را رندر کنید و در یک مرحله همپوشانی کنید. با انجام این کار، برای هر فریم ورودی فقط یک بار به سطح نمایشگر رندر می دهید.
- اگر از Camera2 API استفاده می کنید، تصاویر را با فرمت - ImageFormat.YUV_420_888بگیرید.- اگر از دوربین قدیمیتر API استفاده میکنید، تصاویر را با فرمت - ImageFormat.NV21بگیرید.