Barkodları tanımak ve kodunu çözmek için ML Kit'i kullanabilirsiniz.
Özellik | Paket halinde sunulmayan | Gruplandırılanlar |
---|---|---|
Uygulama | Model, Google Play Hizmetleri aracılığıyla dinamik olarak indirilir. | Model, derleme zamanında uygulamanıza statik olarak bağlanır. |
Uygulama boyutu | Boyut yaklaşık 200 KB artar. | Boyut yaklaşık 2,4 MB artar. |
Başlatma süresi | İlk kullanımdan önce modelin indirilmesini beklemeniz gerekebilir. | Model hemen kullanılabilir. |
Deneyin
- Bu API'nin kullanımına dair bir örnek görmek için örnek uygulamayı inceleyin.
- Bu API'nin uçtan uca uygulanması için Material Design Showcase uygulamasını inceleyin.
Başlamadan önce
Proje düzeyindeki
build.gradle
dosyanızda, Google'ın Maven deposunu hembuildscript
hem deallprojects
bölümüne eklediğinizden emin olun.ML Kit Android kitaplıklarına ait bağımlılıkları, modülünüzün uygulama düzeyindeki Gradle dosyasına (genellikle
app/build.gradle
) ekleyin. İhtiyaçlarınıza göre aşağıdaki bağımlılıklardan birini seçin:Modeli uygulamanızla paketlemek için:
dependencies { // ... // Use this dependency to bundle the model with your app implementation 'com.google.mlkit:barcode-scanning:17.3.0' }
Modeli Google Play Hizmetleri'nde kullanmak için:
dependencies { // ... // Use this dependency to use the dynamically downloaded model in Google Play Services implementation 'com.google.android.gms:play-services-mlkit-barcode-scanning:18.3.1' }
Google Play Hizmetleri'ndeki modeli kullanmayı tercih ederseniz uygulamanız Play Store'dan yüklendikten sonra modeli otomatik olarak cihaza indirecek şekilde yapılandırabilirsiniz. Bunu yapmak için uygulamanızın
AndroidManifest.xml
dosyasına aşağıdaki bildirimi ekleyin:<application ...> ... <meta-data android:name="com.google.mlkit.vision.DEPENDENCIES" android:value="barcode" > <!-- To use multiple models: android:value="barcode,model2,model3" --> </application>
Modelin kullanılabilirliğini açıkça kontrol edebilir ve Google Play Hizmetleri ModuleInstallClient API aracılığıyla indirme isteğinde bulunabilirsiniz.
Yükleme sırasında model indirmelerini etkinleştirmezseniz veya açıkça indirme isteğinde bulunmazsanız model, tarayıcıyı ilk çalıştırdığınızda indirilir. İndirme tamamlanmadan önce yaptığınız istekler sonuç vermez.
Giriş resmi kuralları
-
ML Kit'in barkodları doğru şekilde okuyabilmesi için giriş resimlerinde yeterli piksel verisiyle temsil edilen barkodlar bulunmalıdır.
Belirli piksel verileriyle ilgili şartlar, hem barkodun türüne hem de barkodda kodlanan veri miktarına bağlıdır. Bunun nedeni, birçok barkodun değişken boyutlu yükü desteklemesidir. Genel olarak, barkodun en küçük anlamlı birimi en az 2 piksel genişliğinde, 2 boyutlu kodlar için ise 2 piksel yüksekliğinde olmalıdır.
Örneğin, EAN-13 barkodları 1, 2, 3 veya 4 birim genişliğinde çubuk ve boşluklardan oluşur. Bu nedenle, EAN-13 barkod görüntüsünde ideal olarak en az 2, 4, 6 ve 8 piksel genişliğinde çubuklar ve boşluklar bulunur. EAN-13 barkodunun toplam genişliği 95 birim olduğundan barkodun genişliği en az 190 piksel olmalıdır.
PDF417 gibi daha yoğun biçimlerin, ML Kit tarafından güvenilir bir şekilde okunabilmesi için daha büyük piksel boyutları gerekir. Örneğin, bir PDF417 kodu tek bir satırda 34 adet 17 birim genişliğinde "kelime" içerebilir. Bu da ideal olarak en az 1.156 piksel genişliğinde olmalıdır.
-
Resmin net olmaması, tarama doğruluğunu etkileyebilir. Uygulamanız kabul edilebilir sonuçlar almıyorsa kullanıcıdan resmi yeniden çekmesini isteyin.
-
Tipik uygulamalar için, barkodların kameradan daha uzakta taranabilmesini sağlayan 1280x720 veya 1920x1080 gibi daha yüksek çözünürlüklü bir resim sağlamanız önerilir.
Ancak gecikmenin kritik olduğu uygulamalarda, görüntüleri daha düşük çözünürlükte yakalayarak performansı artırabilirsiniz. Bu durumda, barkodun giriş görüntüsünün çoğunu oluşturması gerekir. Ayrıca Gerçek zamanlı performansı artırmaya yönelik ipuçları başlıklı makaleye de göz atın.
1. Barkod tarayıcıyı yapılandırma
Hangi barkod biçimlerini okumayı beklediğinizi biliyorsanız barkod algılayıcıyı yalnızca bu biçimleri algılayacak şekilde yapılandırarak hızını artırabilirsiniz.Örneğin, yalnızca Aztec kodu ve QR kodlarını algılamak için aşağıdaki örnekte gösterildiği gibi bir BarcodeScannerOptions
nesnesi oluşturun:
Kotlin
val options = BarcodeScannerOptions.Builder() .setBarcodeFormats( Barcode.FORMAT_QR_CODE, Barcode.FORMAT_AZTEC) .build()
Java
BarcodeScannerOptions options = new BarcodeScannerOptions.Builder() .setBarcodeFormats( Barcode.FORMAT_QR_CODE, Barcode.FORMAT_AZTEC) .build();
Aşağıdaki biçimler desteklenir:
- Code 128 (
FORMAT_CODE_128
) - Code 39 (
FORMAT_CODE_39
) - Code 93 (
FORMAT_CODE_93
) - Codabar (
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 kodu (
FORMAT_QR_CODE
) - PDF417 (
FORMAT_PDF417
) - Aztek (
FORMAT_AZTEC
) - Data Matrix (
FORMAT_DATA_MATRIX
)
Paketlenmiş model 17.1.0 ve paketlenmemiş model 18.2.0'dan itibaren, kodları çözülemese bile olası tüm barkodları döndürmek için enableAllPotentialBarcodes()
işlevini de çağırabilirsiniz. Bu, daha fazla algılamayı kolaylaştırmak için kullanılabilir. Örneğin, döndürülen sınırlayıcı kutudaki barkodların daha net bir görüntüsünü elde etmek için kamerayı yakınlaştırabilirsiniz.
Kotlin
val options = BarcodeScannerOptions.Builder() .setBarcodeFormats(...) .enableAllPotentialBarcodes() // Optional .build()
Java
BarcodeScannerOptions options = new BarcodeScannerOptions.Builder() .setBarcodeFormats(...) .enableAllPotentialBarcodes() // Optional .build();
Further on, starting from bundled library 17.2.0 and unbundled library 18.3.0, a new feature called auto-zoom has been introduced to further enhance the barcode scanning experience. With this feature enabled, the app is notified when all barcodes within the view are too distant for decoding. As a result, the app can effortlessly adjust the camera's zoom ratio to the recommended setting provided by the library, ensuring optimal focus and readability. This feature will significantly enhance the accuracy and success rate of barcode scanning, making it easier for apps to capture information precisely.
To enable auto-zooming and customize the experience, you can utilize the
setZoomSuggestionOptions()
method along with your
own ZoomCallback
handler and desired maximum zoom
ratio, as demonstrated in the code below.
Kotlin
val options = BarcodeScannerOptions.Builder() .setBarcodeFormats(...) .setZoomSuggestionOptions( new ZoomSuggestionOptions.Builder(zoomCallback) .setMaxSupportedZoomRatio(maxSupportedZoomRatio) .build()) // Optional .build()
Java
BarcodeScannerOptions options = new BarcodeScannerOptions.Builder() .setBarcodeFormats(...) .setZoomSuggestionOptions( new ZoomSuggestionOptions.Builder(zoomCallback) .setMaxSupportedZoomRatio(maxSupportedZoomRatio) .build()) // Optional .build();
zoomCallback
is required to be provided to handle whenever the library
suggests a zoom should be performed and this callback will always be called on
the main thread.
The following code snippet shows an example of defining a simple callback.
Kotlin
fun setZoom(ZoomRatio: Float): Boolean { if (camera.isClosed()) return false camera.getCameraControl().setZoomRatio(zoomRatio) return true }
Java
boolean setZoom(float zoomRatio) { if (camera.isClosed()) { return false; } camera.getCameraControl().setZoomRatio(zoomRatio); return true; }
maxSupportedZoomRatio
is related to the camera hardware, and different camera
libraries have different ways to fetch it (see the javadoc of the setter
method). In case this is not provided, an
unbounded zoom ratio might be produced by the library which might not be
supported. Refer to the
setMaxSupportedZoomRatio()
method
introduction to see how to get the max supported zoom ratio with different
Camera libraries.
When auto-zooming is enabled and no barcodes are successfully decoded within
the view, BarcodeScanner
triggers your zoomCallback
with the requested
zoomRatio
. If the callback correctly adjusts the camera to this zoomRatio
,
it is highly probable that the most centered potential barcode will be decoded
and returned.
A barcode may remain undecodable even after a successful zoom-in. In such cases,
BarcodeScanner
may either invoke the callback for another round of zoom-in
until the maxSupportedZoomRatio
is reached, or provide an empty list (or a
list containing potential barcodes that were not decoded, if
enableAllPotentialBarcodes()
was called) to the OnSuccessListener
(which
will be defined in step 4. Process the image).
2. Prepare the input image
To recognize barcodes in an image, create anInputImage
object
from either a Bitmap
, media.Image
, ByteBuffer
, byte array, or a file on
the device. Then, pass the InputImage
object to the
BarcodeScanner
's process
method.
You can create an InputImage
object from different sources, each is explained below.
Using a media.Image
To create an InputImage
object from a media.Image
object, such as when you capture an image from a
device's camera, pass the media.Image
object and the image's
rotation to InputImage.fromMediaImage()
.
If you use the
CameraX library, the OnImageCapturedListener
and
ImageAnalysis.Analyzer
classes calculate the rotation value
for you.
Kotlin
private class YourImageAnalyzer : ImageAnalysis.Analyzer { override fun analyze(imageProxy: ImageProxy) { val mediaImage = imageProxy.image if (mediaImage != null) { val image = InputImage.fromMediaImage(mediaImage, imageProxy.imageInfo.rotationDegrees) // Pass image to an ML Kit Vision API // ... } } }
Java
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 // ... } } }
Resmin dönüş derecesini veren bir kamera kitaplığı kullanmıyorsanız, cihazın dönüş derecesi ve cihazdaki kamera sensörünün yönlendirmesinden yararlanarak dönüş derecesini hesaplayabilirsiniz:
Kotlin
private val ORIENTATIONS = SparseIntArray() init { ORIENTATIONS.append(Surface.ROTATION_0, 0) ORIENTATIONS.append(Surface.ROTATION_90, 90) ORIENTATIONS.append(Surface.ROTATION_180, 180) ORIENTATIONS.append(Surface.ROTATION_270, 270) } /** * Get the angle by which an image must be rotated given the device's current * orientation. */ @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) @Throws(CameraAccessException::class) private fun getRotationCompensation(cameraId: String, activity: Activity, isFrontFacing: Boolean): Int { // Get the device's current rotation relative to its "native" orientation. // Then, from the ORIENTATIONS table, look up the angle the image must be // rotated to compensate for the device's rotation. val deviceRotation = activity.windowManager.defaultDisplay.rotation var rotationCompensation = ORIENTATIONS.get(deviceRotation) // Get the device's sensor orientation. val cameraManager = activity.getSystemService(CAMERA_SERVICE) as CameraManager val sensorOrientation = cameraManager .getCameraCharacteristics(cameraId) .get(CameraCharacteristics.SENSOR_ORIENTATION)!! if (isFrontFacing) { rotationCompensation = (sensorOrientation + rotationCompensation) % 360 } else { // back-facing rotationCompensation = (sensorOrientation - rotationCompensation + 360) % 360 } return rotationCompensation }
Java
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; }
Ardından, media.Image
nesnesini ve dönüş derecesi değerini InputImage.fromMediaImage()
'ye iletin:
Kotlin
val image = InputImage.fromMediaImage(mediaImage, rotation)
Java
InputImage image = InputImage.fromMediaImage(mediaImage, rotation);
Dosya URI'si kullanma
Dosya URI'sinden InputImage
nesnesi oluşturmak için uygulama bağlamını ve dosya URI'sini InputImage.fromFilePath()
'ye iletin. Bu, kullanıcıdan galeri uygulamasından bir resim seçmesini istemek için ACTION_GET_CONTENT
amacını kullandığınızda yararlıdır.
Kotlin
val image: InputImage try { image = InputImage.fromFilePath(context, uri) } catch (e: IOException) { e.printStackTrace() }
Java
InputImage image; try { image = InputImage.fromFilePath(context, uri); } catch (IOException e) { e.printStackTrace(); }
ByteBuffer
veya ByteArray
kullanma
ByteBuffer
veya ByteArray
öğesinden InputImage
nesnesi oluşturmak için öncelikle media.Image
girişi için daha önce açıklandığı gibi görüntü döndürme derecesini hesaplayın.
Ardından, arabellek veya diziyle birlikte resmin yüksekliği, genişliği, renk kodlama biçimi ve döndürme derecesiyle InputImage
nesnesini oluşturun:
Kotlin
val image = InputImage.fromByteBuffer( byteBuffer, /* image width */ 480, /* image height */ 360, rotationDegrees, InputImage.IMAGE_FORMAT_NV21 // or IMAGE_FORMAT_YV12 ) // Or: val image = InputImage.fromByteArray( byteArray, /* image width */ 480, /* image height */ 360, rotationDegrees, InputImage.IMAGE_FORMAT_NV21 // or IMAGE_FORMAT_YV12 )
Java
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
kullanma
Bitmap
nesnesinden InputImage
nesnesi oluşturmak için aşağıdaki bildirimi yapın:
Kotlin
val image = InputImage.fromBitmap(bitmap, 0)
Java
InputImage image = InputImage.fromBitmap(bitmap, rotationDegree);
Resim, döndürme dereceleriyle birlikte bir Bitmap
nesnesiyle gösterilir.
3. BarcodeScanner örneğini alma
Kotlin
val scanner = BarcodeScanning.getClient() // Or, to specify the formats to recognize: // val scanner = BarcodeScanning.getClient(options)
Java
BarcodeScanner scanner = BarcodeScanning.getClient(); // Or, to specify the formats to recognize: // BarcodeScanner scanner = BarcodeScanning.getClient(options);
4. Resmi işleme
Resmiprocess
yöntemine iletin:
Kotlin
val result = scanner.process(image) .addOnSuccessListener { barcodes -> // Task completed successfully // ... } .addOnFailureListener { // Task failed with an exception // ... }
Java
Task<List<Barcode>> result = scanner.process(image) .addOnSuccessListener(new OnSuccessListener<List<Barcode>>() { @Override public void onSuccess(List<Barcode> barcodes) { // Task completed successfully // ... } }) .addOnFailureListener(new OnFailureListener() { @Override public void onFailure(@NonNull Exception e) { // Task failed with an exception // ... } });
5. Barkodlardan bilgi alma
Barkod tanıma işlemi başarılı olursaBarcode
nesnenin listesi başarı dinleyicisine iletilir. Her Barcode
nesnesi, resimde algılanan bir barkodu temsil eder. Her barkod için giriş resmindeki sınırlayıcı koordinatlarını ve barkod tarafından kodlanan ham verileri alabilirsiniz. Ayrıca, barkod tarayıcı barkodla kodlanan veri türünü belirleyebildiyse ayrıştırılmış verileri içeren bir nesne alabilirsiniz.
Örneğin:
Kotlin
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) { Barcode.TYPE_WIFI -> { val ssid = barcode.wifi!!.ssid val password = barcode.wifi!!.password val type = barcode.wifi!!.encryptionType } Barcode.TYPE_URL -> { val title = barcode.url!!.title val url = barcode.url!!.url } } }
Java
for (Barcode 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 Barcode.TYPE_WIFI: String ssid = barcode.getWifi().getSsid(); String password = barcode.getWifi().getPassword(); int type = barcode.getWifi().getEncryptionType(); break; case Barcode.TYPE_URL: String title = barcode.getUrl().getTitle(); String url = barcode.getUrl().getUrl(); break; } }
Anlık performansı artırmaya yönelik ipuçları
Barkodları gerçek zamanlı bir uygulamada taramak istiyorsanız en iyi kare hızlarını elde etmek için aşağıdaki yönergeleri uygulayın:
-
Girişi kameranın doğal çözünürlüğünde yakalamayın. Bazı cihazlarda, yerel çözünürlükte giriş yakalama işlemi son derece büyük (10+ megapiksel) görüntüler oluşturur. Bu da doğruluk açısından herhangi bir fayda sağlamadan çok kötü bir gecikmeye neden olur. Bunun yerine, yalnızca barkod algılama için gereken boyutu (genellikle 2 megapikselden fazla değildir) kameradan isteyin.
Tarama hızı önemliyse görüntü yakalama çözünürlüğünü daha da düşürebilirsiniz. Ancak yukarıda belirtilen minimum barkod boyutu şartlarını göz önünde bulundurun.
Akış video kareleri dizisindeki barkodları tanımaya çalışıyorsanız tanıyıcı, kareden kareye farklı sonuçlar üretebilir. İyi bir sonuç döndürdüğünüzden emin olmak için aynı değerin art arda gelmesini beklemeniz gerekir.
ITF ve CODE-39 için sağlama toplamı rakamı desteklenmez.
Camera
veyacamera2
API'sini kullanıyorsanız dedektöre yapılan çağrıları sınırlayın. Dedektör çalışırken yeni bir video karesi kullanılabilir hale gelirse kareyi bırakın. Örnek için hızlı başlangıç örnek uygulamasındakiVisionProcessorBase
sınıfına bakın.CameraX
API'sini kullanıyorsanız geri basınç stratejisinin varsayılan değerine ayarlandığından emin olunImageAnalysis.STRATEGY_KEEP_ONLY_LATEST
. Bu, analiz için aynı anda yalnızca bir resmin gönderilmesini sağlar. Analizör meşgulken daha fazla resim üretilirse bunlar otomatik olarak bırakılır ve teslimat için sıraya alınmaz. Analiz edilen görüntü ImageProxy.close() çağrılarak kapatıldığında, en son görüntü teslim edilir.- Giriş resmine grafik yerleştirmek için algılayıcının çıkışını kullanıyorsanız önce ML Kit'ten sonucu alın, ardından resmi tek adımda oluşturun ve yerleştirin. Bu, her giriş karesi için yalnızca bir kez görüntüleme yüzeyinde oluşturulur. Örnek için hızlı başlangıç örnek uygulamasındaki
CameraSourcePreview
veGraphicOverlay
sınıflarına bakın. - Camera2 API'yi kullanıyorsanız
ImageFormat.YUV_420_888
biçiminde resim çekin. Eski Camera API'yi kullanıyorsanız görüntüleriImageFormat.NV21
biçiminde çekin.
Aksi belirtilmediği sürece bu sayfanın içeriği Creative Commons Atıf 4.0 Lisansı altında ve kod örnekleri Apache 2.0 Lisansı altında lisanslanmıştır. Ayrıntılı bilgi için Google Developers Site Politikaları'na göz atın. Java, Oracle ve/veya satış ortaklarının tescilli ticari markasıdır.
Son güncelleme tarihi: 2025-09-04 UTC.