Bạn có thể sử dụng Bộ công cụ học máy để nhận dạng và giải mã mã vạch.
Dùng thử
- Hãy thử dùng ứng dụng mẫu để xem ví dụ về cách sử dụng API này.
Trước khi bắt đầu
- Đưa các nhóm Bộ công cụ học máy sau đây vào Podfile của bạn:
pod 'GoogleMLKit/BarcodeScanning', '3.2.0'
- Sau khi cài đặt hoặc cập nhật Nhóm của dự án, hãy mở dự án Xcode của bạn bằng
.xcworkspace
của dự án. Bộ công cụ học máy được hỗ trợ trong Xcode phiên bản 12.4 trở lên.
Nguyên tắc về hình ảnh đầu vào
-
Để Bộ công cụ học máy đọc chính xác mã vạch, hình ảnh đầu vào phải chứa mã vạch được biểu thị bằng đủ dữ liệu pixel.
Các yêu cầu cụ thể về dữ liệu pixel phụ thuộc vào cả loại mã vạch và lượng dữ liệu được mã hoá trong mã đó, vì nhiều mã vạch hỗ trợ tải trọng có kích thước thay đổi. Nói chung, đơn vị ý nghĩa nhỏ nhất của mã vạch phải có chiều rộng tối thiểu là 2 pixel và đối với mã 2 chiều, phải cao hơn 2 pixel.
Ví dụ: mã vạch EAN-13 được tạo thành từ các thanh và khoảng trắng có chiều rộng là 1, 2, 3 hoặc 4 đơn vị. Vì vậy, hình ảnh mã vạch EAN-13 lý tưởng nhất là có các thanh và khoảng rộng ít nhất là 2, 4, 6 và 8 pixel. Vì mã vạch EAN-13 có tổng chiều rộng là 95 đơn vị nên mã vạch phải có chiều rộng tối thiểu là 190 pixel.
Các định dạng mật mã (chẳng hạn như PDF417) cần có kích thước pixel lớn hơn để Bộ công cụ học máy đọc được một cách đáng tin cậy. Ví dụ: mã PDF417 có thể có tối đa 34 "từ" với chiều rộng 17 đơn vị trong một hàng, lý tưởng là chiều rộng tối thiểu là 1156 pixel.
-
Hình ảnh lấy nét kém có thể ảnh hưởng đến độ chính xác khi quét. Nếu ứng dụng của bạn không nhận được kết quả chấp nhận được, hãy yêu cầu người dùng chụp lại hình ảnh.
-
Đối với các ứng dụng thông thường, bạn nên cung cấp hình ảnh có độ phân giải cao hơn, chẳng hạn như 1280x720 hoặc 1920x1080 để giúp người dùng có thể quét được mã vạch ở khoảng cách lớn hơn so với máy ảnh.
Tuy nhiên, trong các ứng dụng có độ trễ quan trọng, bạn có thể cải thiện hiệu suất bằng cách chụp ảnh ở độ phân giải thấp hơn, nhưng yêu cầu mã vạch chiếm phần lớn hình ảnh đầu vào. Ngoài ra, hãy xem phần Mẹo cải thiện hiệu suất theo thời gian thực.
1. Định cấu hình máy quét mã vạch
Nếu biết định dạng mã vạch nào mình muốn đọc, bạn có thể cải thiện tốc độ của máy quét mã vạch bằng cách định cấu hình để máy chỉ quét những định dạng đó.Ví dụ: để chỉ quét mã Aztec và mã QR, hãy tạo đối tượng BarcodeScannerOptions
như trong ví dụ sau:
Swift
let format = .all let barcodeOptions = BarcodeScannerOptions(formats: format)
Các định dạng sau được hỗ trợ:
- code128
- code39
- code93
- codaBar
- dataMatrix
- EAN13
- EAN8
- CNTTF
- qrCode
- UPCA (Đạo luật về quyền riêng tư của người tiêu dùng tại California)
- Hàm UPCE
- PDF417
- aztec
Objective-C
MLKBarcodeScannerOptions *options = [[MLKBarcodeScannerOptions alloc] initWithFormats: MLKBarcodeFormatQRCode | MLKBarcodeFormatAztec];
Các định dạng sau được hỗ trợ:
- Mã-128 (
MLKBarcodeFormatCode128
) - Mã-39 (
MLKBarcodeFormatCode39
) - Mã-93 (
MLKBarcodeFormatCode93
) - Codabar (
MLKBarcodeFormatCodaBar
) - Ma trận dữ liệu (
MLKBarcodeFormatDataMatrix
) - EAN-13 (
MLKBarcodeFormatEAN13
) - EAN-8 (
MLKBarcodeFormatEAN8
) - ITF (
MLKBarcodeFormatITF
) - Mã QR (
MLKBarcodeFormatQRCode
) - UPC-A (
MLKBarcodeFormatUPCA
) - UPC-E (
MLKBarcodeFormatUPCE
) - PDF-417 (
MLKBarcodeFormatPDF417
) - Mã Aztec (
MLKBarcodeFormatAztec
)
2. Chuẩn bị hình ảnh đầu vào
Để quét mã vạch trong một hình ảnh, hãy chuyển hình ảnh đó dưới dạngUIImage
hoặc CMSampleBufferRef
vào phương thức process()
hoặc results(in:)
của BarcodeScanner
:
Tạo đối tượng VisionImage
bằng UIImage
hoặc CMSampleBuffer
.
Nếu bạn sử dụng UIImage
, hãy làm theo các bước sau:
- Tạo đối tượng
VisionImage
bằngUIImage
. Hãy nhớ chỉ định đúng.orientation
.Swift
let image = VisionImage(image: UIImage) visionImage.orientation = image.imageOrientation
Objective-C
MLKVisionImage *visionImage = [[MLKVisionImage alloc] initWithImage:image]; visionImage.orientation = image.imageOrientation;
Nếu bạn sử dụng CMSampleBuffer
, hãy làm theo các bước sau:
-
Chỉ định hướng của dữ liệu hình ảnh có trong
CMSampleBuffer
.Cách tải hướng của hình ảnh:
Swift
func imageOrientation( deviceOrientation: UIDeviceOrientation, cameraPosition: AVCaptureDevice.Position ) -> UIImage.Orientation { switch deviceOrientation { case .portrait: return cameraPosition == .front ? .leftMirrored : .right case .landscapeLeft: return cameraPosition == .front ? .downMirrored : .up case .portraitUpsideDown: return cameraPosition == .front ? .rightMirrored : .left case .landscapeRight: return cameraPosition == .front ? .upMirrored : .down case .faceDown, .faceUp, .unknown: return .up } }
Objective-C
- (UIImageOrientation) imageOrientationFromDeviceOrientation:(UIDeviceOrientation)deviceOrientation cameraPosition:(AVCaptureDevicePosition)cameraPosition { switch (deviceOrientation) { case UIDeviceOrientationPortrait: return cameraPosition == AVCaptureDevicePositionFront ? UIImageOrientationLeftMirrored : UIImageOrientationRight; case UIDeviceOrientationLandscapeLeft: return cameraPosition == AVCaptureDevicePositionFront ? UIImageOrientationDownMirrored : UIImageOrientationUp; case UIDeviceOrientationPortraitUpsideDown: return cameraPosition == AVCaptureDevicePositionFront ? UIImageOrientationRightMirrored : UIImageOrientationLeft; case UIDeviceOrientationLandscapeRight: return cameraPosition == AVCaptureDevicePositionFront ? UIImageOrientationUpMirrored : UIImageOrientationDown; case UIDeviceOrientationUnknown: case UIDeviceOrientationFaceUp: case UIDeviceOrientationFaceDown: return UIImageOrientationUp; } }
- Tạo đối tượng
VisionImage
bằng cách sử dụng đối tượng và hướngCMSampleBuffer
:Swift
let image = VisionImage(buffer: sampleBuffer) image.orientation = imageOrientation( deviceOrientation: UIDevice.current.orientation, cameraPosition: cameraPosition)
Objective-C
MLKVisionImage *image = [[MLKVisionImage alloc] initWithBuffer:sampleBuffer]; image.orientation = [self imageOrientationFromDeviceOrientation:UIDevice.currentDevice.orientation cameraPosition:cameraPosition];
3. Tải một phiên bản của BarcodeScanner
Tạo một thực thể củaBarcodeScanner
:
Swift
let barcodeScanner = BarcodeScanner.barcodeScanner() // Or, to change the default settings: // let barcodeScanner = BarcodeScanner.barcodeScanner(options: barcodeOptions)
Objective-C
MLKBarcodeScanner *barcodeScanner = [MLKBarcodeScanner barcodeScanner]; // Or, to change the default settings: // MLKBarcodeScanner *barcodeScanner = // [MLKBarcodeScanner barcodeScannerWithOptions:options];
4. Xử lý hình ảnh
Sau đó, truyền hình ảnh này vào phương thứcprocess()
:
Swift
barcodeScanner.process(visionImage) { features, error in guard error == nil, let features = features, !features.isEmpty else { // Error handling return } // Recognized barcodes }
Objective-C
[barcodeScanner processImage:image completion:^(NSArray<MLKBarcode *> *_Nullable barcodes, NSError *_Nullable error) { if (error != nil) { // Error handling return; } if (barcodes.count > 0) { // Recognized barcodes } }];
5. Nhận thông tin từ mã vạch
Nếu quét mã vạch thành công, thì trình quét sẽ trả về một loạt các đối tượngBarcode
. Mỗi đối tượng Barcode
đại diện cho một mã vạch được phát hiện trong hình ảnh. Đối với mỗi mã vạch, bạn có thể lấy toạ độ giới hạn trong hình ảnh đầu vào cũng như dữ liệu thô được mã hoá bằng mã vạch. Ngoài ra, nếu máy quét mã vạch có thể xác định loại dữ liệu được mã hoá bằng mã vạch, thì bạn có thể nhận được một đối tượng chứa dữ liệu đã phân tích cú pháp.
Ví dụ:
Swift
for barcode in barcodes { let corners = barcode.cornerPoints let displayValue = barcode.displayValue let rawValue = barcode.rawValue let valueType = barcode.valueType switch valueType { case .wiFi: let ssid = barcode.wifi?.ssid let password = barcode.wifi?.password let encryptionType = barcode.wifi?.type case .URL: let title = barcode.url!.title let url = barcode.url!.url default: // See API reference for all supported value types } }
Objective-C
for (MLKBarcode *barcode in barcodes) { NSArray *corners = barcode.cornerPoints; NSString *displayValue = barcode.displayValue; NSString *rawValue = barcode.rawValue; MLKBarcodeValueType valueType = barcode.valueType; switch (valueType) { case MLKBarcodeValueTypeWiFi: ssid = barcode.wifi.ssid; password = barcode.wifi.password; encryptionType = barcode.wifi.type; break; case MLKBarcodeValueTypeURL: url = barcode.URL.url; title = barcode.URL.title; break; // ... default: break; } }
Mẹo cải thiện hiệu suất theo thời gian thực
Nếu bạn muốn quét mã vạch trong một ứng dụng theo thời gian thực, hãy làm theo các nguyên tắc sau để đạt được tốc độ khung hình tốt nhất:
-
Đừng chụp dữ liệu đầu vào ở độ phân giải gốc của máy ảnh. Trên một số thiết bị, việc chụp ảnh đầu vào ở độ phân giải gốc sẽ tạo ra hình ảnh cực lớn (10 megapixel trở lên), dẫn đến độ trễ rất thấp mà không có lợi ích về độ chính xác. Thay vào đó, chỉ yêu cầu kích thước từ máy ảnh cần để quét mã vạch, thường không quá 2 megapixel.
Bạn không nên đặt giá trị đặt trước cho phiên chụp ảnh đã đặt tên (
AVCaptureSessionPresetDefault
,AVCaptureSessionPresetLow
,AVCaptureSessionPresetMedium
, v.v.) vì chúng có thể ánh xạ tới độ phân giải không phù hợp trên một số thiết bị. Thay vào đó, hãy sử dụng các giá trị đặt trước cụ thể, chẳng hạn nhưAVCaptureSessionPreset1280x720
.Nếu tốc độ quét là yếu tố quan trọng, bạn có thể giảm thêm độ phân giải của ảnh chụp. Tuy nhiên, hãy lưu ý đến các yêu cầu tối thiểu về kích thước mã vạch nêu trên.
Nếu bạn đang cố gắng nhận dạng mã vạch trong một chuỗi các khung hình video truyền trực tuyến, thì trình nhận dạng này có thể tạo ra các kết quả khác nhau giữa các khung hình. Bạn nên đợi cho đến khi nhận được một chuỗi liên tiếp có cùng giá trị để chắc chắn rằng mình đang trả về một kết quả tốt.
Chữ số Tổng kiểm không được hỗ trợ cho ITF và CODE-39.
- Để xử lý khung video, hãy sử dụng API đồng bộ
results(in:)
của trình phát hiện. Hãy gọi phương thức này từ hàmcaptureOutput(_, didOutput:from:)
củaAVCaptureVideoDataOutputSampleBufferDelegate
để nhận kết quả đồng bộ từ khung hình video đã cho. GiữalwaysDiscardsLateVideoFrames
củaAVCaptureVideoDataOutput
ở dạngtrue
để điều tiết lệnh gọi đến trình phát hiện. Nếu có một khung hình video mới trong khi trình phát hiện đang chạy, thì khung hình đó sẽ bị loại bỏ. - Nếu bạn sử dụng đầu ra của trình phát hiện để phủ đồ hoạ lên hình ảnh đầu vào, trước tiên, hãy lấy kết quả từ Bộ công cụ học máy, sau đó kết xuất hình ảnh và lớp phủ chỉ qua một bước. Bằng cách này, bạn chỉ kết xuất trên giao diện màn hình một lần cho mỗi khung đầu vào được xử lý. Hãy xem ví dụ về updatePreviewOverlayViewWithLastFrame trong mẫu bắt đầu nhanh của Bộ công cụ học máy.