您可以使用 ML Kit 辨識條碼並加以解碼。
功能 | 未分類 | 組合 |
---|---|---|
導入作業 | 模型會透過 Google Play 服務動態下載。 | 模型會在建構期間以靜態方式連結至應用程式。 |
應用程式大小 | 大小增加約 200 KB。 | 大小增加約 2.4 MB。 |
初始化時間 | 可能要等到模型下載完畢再開始使用。 | 模型可立即使用。 |
立即試用
- 使用範例應用程式試試 請查看此 API 的使用範例。
- 請參閱 Material Design 展示區 應用程式,瞭解這個 API 的端對端實作。
事前準備
在專案層級的
build.gradle
檔案中,請務必加入 Google 的buildscript
和allprojects
區段內的 Maven 存放區。將 ML Kit Android 程式庫的依附元件新增至模組的 應用程式層級的 Gradle 檔案,通常為
app/build.gradle
。選擇下列其中一項 並授予下列依附元件:將模型與應用程式搭配使用:
dependencies { // ... // Use this dependency to bundle the model with your app implementation 'com.google.mlkit:barcode-scanning:17.3.0' }
在 Google Play 服務中使用模型的步驟如下:
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 服務中使用模型,可以 讓應用程式自動下載至裝置, 安裝如果要這麼做,請將下列宣告加入 應用程式的
AndroidManifest.xml
檔案:<application ...> ... <meta-data android:name="com.google.mlkit.vision.DEPENDENCIES" android:value="barcode" > <!-- To use multiple models: android:value="barcode,model2,model3" --> </application>
您也可以明確確認模型可用性,並透過下列任一方式要求下載: Google Play 服務 ModuleInstallClient API。
如果您沒有啟用安裝期間模型下載功能或要求明確下載, 模型會在您初次執行掃描器時下載您提出的要求 就無法取得任何結果。
輸入圖片規範
-
為了讓 ML Kit 準確讀取條碼,輸入圖片必須包含 以充足的像素資料表示條碼
具體的像素資料規定取決於 包括條碼和編碼的資料量,因為許多條碼 可支援可變大小酬載一般來說,最小的 條碼單元寬度至少須為 2 像素, 2 維代碼,高度為 2 像素。
例如,EAN-13 條碼是由 1 號的酒吧和空格組成。 寬 2、3 或 4 個單位,因此在理想情況下,EAN-13 條碼圖片應有長條 顯示寬度至少為 2、4、6 和 8 像素的空間。因為 EAN-13 條碼的總寬為 95 個單位,條碼至少應為 190 像素寬。
密度格式 (例如 PDF417) 需要更大的像素尺寸 可靠的機器學習套件例如,PDF417 程式碼最多可包含 寬 34 個 17 單位的「words」理想情況下 1156 像素寬。
-
圖像對焦品質不佳可能會影響掃描的準確度。如果應用程式無法 可接受的結果,請使用者重新拍攝圖片。
-
建議您為一般應用程式提供 解析度圖片,例如 1280x720 或 1920x1080,才能製作條碼 從遠一點的相機鏡頭掃描即可。
不過,若是應用程式比較注重延遲狀況,您可以提高 低解析度的圖像,但我們需要 條碼構成大部分的輸入圖片另請參閱 即時效能改善秘訣。
1. 設定條碼掃描器
如果您知道預期會讀取哪些條碼格式,則可加快速度 ,藉此選擇只偵測這些格式。舉例來說,如果只要偵測 Aztec 代碼和 QR code,請建立
BarcodeScannerOptions
物件,如以下範例所示:
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();
支援下列格式:
- 代碼 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
) - 通用產品代碼 (
FORMAT_UPC_A
) - UPC-E (
FORMAT_UPC_E
) - QR code (
FORMAT_QR_CODE
) - PDF417 (
FORMAT_PDF417
) - 阿茲特克 (
FORMAT_AZTEC
) - 資料矩陣 (
FORMAT_DATA_MATRIX
)
從隨附型號 17.1.0 和未組合模型 18.2.0 開始,您也可以呼叫
enableAllPotentialBarcodes()
即可傳回所有可能的條碼
無法解碼這可以幫助我們進一步偵測,例如
也可以放大鏡頭,針對傳回的
定界框。
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 // ... } } }
如果您沒有使用相機程式庫提供圖片的旋轉角度, 可根據裝置的旋轉角度和相機方向來計算 感應器:
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; }
然後,請傳遞 media.Image
物件和
將度數值旋轉為 InputImage.fromMediaImage()
:
Kotlin
val image = InputImage.fromMediaImage(mediaImage, rotation)
Java
InputImage image = InputImage.fromMediaImage(mediaImage, rotation);
使用檔案 URI
如要建立InputImage
物件,將應用程式結構定義與檔案 URI 傳遞至
InputImage.fromFilePath()
。如果您要
使用 ACTION_GET_CONTENT
意圖提示使用者選取
取自圖片庫應用程式中的圖片。
Kotlin
val image: InputImage try { image = InputImage.fromFilePath(context, uri) } catch (e: IOException) { e.printStackTrace() }
Java
InputImage image; try { image = InputImage.fromFilePath(context, uri); } catch (IOException e) { e.printStackTrace(); }
使用 ByteBuffer
或 ByteArray
如要建立InputImage
ByteBuffer
或 ByteArray
的物件,請先計算圖片
與先前 media.Image
輸入中所述的旋轉角度相同。
接著,使用緩衝區或陣列建立 InputImage
物件,以及
高度、寬度、顏色編碼格式以及旋轉角度:
Kotlin
val image = InputImage.fromByteBuffer( byteBuffer, /* image width */ 480, /* image height */ 360, rotationDegrees, InputImage.IMAGE_FORMAT_NV21 // or IMAGE_FORMAT_YV12 ) // Or: val image = InputImage.fromByteArray( byteArray, /* image width */ 480, /* image height */ 360, rotationDegrees, InputImage.IMAGE_FORMAT_NV21 // or IMAGE_FORMAT_YV12 )
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
如要建立InputImage
物件中,Bitmap
物件,請做出以下宣告:
Kotlin
val image = InputImage.fromBitmap(bitmap, 0)
Java
InputImage image = InputImage.fromBitmap(bitmap, rotationDegree);
圖像以 Bitmap
物件和旋轉角度表示。
3. 取得 BarcodeScanner 的執行個體
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. 處理圖片
將圖片傳遞至process
方法:
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. 透過條碼取得資訊
如果條碼辨識作業成功,系統會顯示Barcode
清單。
會將物件傳遞到成功事件監聽器每個 Barcode
物件代表
在圖片中偵測到的條碼針對每個條碼
輸入圖像中的邊界座標,以及由
條碼此外,如果條碼掃描器能夠判斷資料類型
您可以取得包含剖析資料的物件。
例如:
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; } }
即時效能改善訣竅
如要在即時應用程式中掃描條碼,請按照下列指示操作: 實現最佳影格速率:
-
請勿以相機原始解析度擷取輸入內容。在部分裝置上, 以原生解析度擷取輸入內容會產生極大檔案 (10+ 才能確保延遲時間極短,而且 準確度。請改為只從必要的相機要求大小 ,這通常不會超過 200 萬像素。
如果掃描速度很重要,可以進一步降低圖片拍攝速度 解析度。但請注意,條碼大小下限規定 即可。
如果您嘗試從串流序列中辨識條碼 辨識器可能會針對不同影格產生不同結果 相框。您應等待系統連續收到相同的一系列相同的 ,這樣很有自信地傳回最佳結果。
ITF 和 CODE-39 不支援總和檢查碼。
- 如果您使用
Camera
或camera2
API、 限制對偵測工具的呼叫如果影片有新影片 影格掉落時,表示影格是否可用。詳情請參閱VisionProcessorBase
類別的範例。 - 如果您是使用
CameraX
API, 請務必將背壓策略設為預設值ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST
。 這麼做可保證系統一次只會傳送一張圖片進行分析。如果圖片較多 會在分析器忙碌時產生,這些作業會自動遭到捨棄,不會排入佇列 廣告放送。以呼叫方式關閉要分析的圖片後 ImageProxy.close(),最新一張圖片才會放送。 - 如果使用偵測工具的輸出內容將圖像重疊
先從 ML Kit 取得結果,然後算繪圖片
並疊加單一步驟這會轉譯至顯示介面
每個輸入影格只能建立一次詳情請參閱
CameraSourcePreview
和 如需範例,請前往快速入門導覽課程範例應用程式中的GraphicOverlay
類別。 - 如果你使用 Camera2 API,
ImageFormat.YUV_420_888
格式。如果使用舊版 Camera API,請以ImageFormat.NV21
格式。
除非另有註明,否則本頁面中的內容是採用創用 CC 姓名標示 4.0 授權,程式碼範例則為阿帕契 2.0 授權。詳情請參閱《Google Developers 網站政策》。Java 是 Oracle 和/或其關聯企業的註冊商標。
上次更新時間:2024-08-20 (世界標準時間)。