Anda dapat menggunakan ML Kit untuk mengenali dan mendekode kode batang.
Cobalah
- Silakan coba aplikasi contoh ini untuk melihat contoh penggunaan API ini.
Sebelum memulai
- Sertakan pod ML Kit berikut di Podfile Anda:
pod 'GoogleMLKit/BarcodeScanning', '3.2.0'
- Setelah menginstal atau mengupdate Pod project, buka project Xcode menggunakan
.xcworkspace
-nya. ML Kit didukung di Xcode versi 12.4 atau yang lebih baru.
Panduan gambar input
-
Agar ML Kit dapat membaca kode batang secara akurat, gambar input harus berisi kode batang yang diwakili oleh data piksel yang memadai.
Persyaratan data piksel tertentu bergantung pada jenis kode batang dan jumlah data yang dienkode di dalamnya, karena banyak kode batang mendukung payload ukuran variabel. Secara umum, unit terkecil yang bermakna pada kode batang harus berukuran lebar minimal 2 piksel, dan untuk kode 2 dimensi, tingginya minimal 2 piksel.
Misalnya, kode batang EAN-13 terdiri dari batang dan spasi yang lebarnya 1, 2, 3, atau 4 unit, sehingga gambar kode batang EAN-13 idealnya memiliki batang dan spasi yang lebarnya minimal 2, 4, 6, dan 8 piksel. Karena total lebar kode batang EAN-13 adalah 95 unit, kode batang harus memiliki lebar minimal 190 piksel.
Format yang lebih padat, seperti PDF417, memerlukan dimensi piksel yang lebih besar agar ML Kit dapat membacanya dengan andal. Misalnya, kode PDF417 dapat memiliki hingga 34 "kata" dengan lebar unit 17 dalam satu baris, yang idealnya memiliki lebar minimal 1.156 piksel.
-
Fokus gambar yang buruk dapat memengaruhi akurasi pemindaian. Jika aplikasi Anda tidak mendapatkan hasil yang dapat diterima, minta pengguna untuk mengambil ulang gambar.
-
Untuk aplikasi standar, sebaiknya sediakan gambar beresolusi lebih tinggi, seperti 1280x720 atau 1920x1080, agar kode batang dapat dipindai dari jarak yang lebih jauh dari kamera.
Namun, dalam aplikasi yang sangat mementingkan latensi, Anda dapat meningkatkan performa dengan mengambil gambar pada resolusi lebih rendah, tetapi mengharuskan kode batang menjadi bagian utama gambar input. Baca juga Tips untuk meningkatkan performa real-time.
1. Mengonfigurasi pemindai kode batang
Jika mengetahui format kode batang yang ingin dibaca, Anda dapat meningkatkan kecepatan pemindai kode batang dengan mengonfigurasinya agar hanya memindai format tersebut.Misalnya, untuk memindai kode Aztec dan kode QR saja, buat objek BarcodeScannerOptions
seperti pada contoh berikut:
Swift
let format = .all let barcodeOptions = BarcodeScannerOptions(formats: format)
Format berikut ini didukung:
- code128
- code39
- code93
- codaBar
- dataMatrix
- EAN13
- EAN8
- ITF
- qrCode
- {i>UPCA<i}
- UPCE
- PDF417
- Aztec
Objective-C
MLKBarcodeScannerOptions *options = [[MLKBarcodeScannerOptions alloc] initWithFormats: MLKBarcodeFormatQRCode | MLKBarcodeFormatAztec];
Format berikut ini didukung:
- Kode-128 (
MLKBarcodeFormatCode128
) - Kode-39 (
MLKBarcodeFormatCode39
) - Kode-93 (
MLKBarcodeFormatCode93
) - Codabar (
MLKBarcodeFormatCodaBar
) - Matriks Data (
MLKBarcodeFormatDataMatrix
) - EAN-13 (
MLKBarcodeFormatEAN13
) - EAN-8 (
MLKBarcodeFormatEAN8
) - ITF (
MLKBarcodeFormatITF
) - Kode QR (
MLKBarcodeFormatQRCode
) - UPC-A (
MLKBarcodeFormatUPCA
) - UPC-E (
MLKBarcodeFormatUPCE
) - PDF-417 (
MLKBarcodeFormatPDF417
) - Kode Aztec (
MLKBarcodeFormatAztec
)
2. Siapkan gambar input
Untuk memindai kode batang dalam gambar, teruskan gambar sebagaiUIImage
atau
CMSampleBufferRef
ke metode process()
atau results(in:)
BarcodeScanner
:
Buat objek VisionImage
menggunakan UIImage
atau CMSampleBuffer
.
Jika Anda menggunakan UIImage
, ikuti langkah-langkah berikut:
- Buat objek
VisionImage
denganUIImage
. Pastikan untuk menentukan.orientation
yang benar.Swift
let image = VisionImage(image: UIImage) visionImage.orientation = image.imageOrientation
Objective-C
MLKVisionImage *visionImage = [[MLKVisionImage alloc] initWithImage:image]; visionImage.orientation = image.imageOrientation;
Jika Anda menggunakan CMSampleBuffer
, ikuti langkah-langkah berikut:
-
Tentukan orientasi data gambar yang dimuat dalam
CMSampleBuffer
.Untuk mendapatkan orientasi gambar:
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; } }
- Buat objek
VisionImage
menggunakan objek dan orientasiCMSampleBuffer
: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. Mendapatkan instance BarcodeScanner
Dapatkan instanceBarcodeScanner
:
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. Memproses gambar
Lalu, teruskan gambar ke metodeprocess()
:
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. Mendapatkan informasi dari kode batang
Jika operasi pemindaian kode batang berhasil, pemindai akan menampilkan array objekBarcode
. Setiap objek Barcode
mewakili
kode batang yang terdeteksi di dalam gambar. Untuk setiap kode batang, Anda bisa mendapatkan
koordinat pembatasnya di gambar input, serta data mentah yang dienkode oleh
kode batang. Selain itu, jika pemindai kode batang dapat menentukan jenis data yang dienkode oleh kode batang, Anda bisa mendapatkan objek yang berisi data yang telah diuraikan.
Contoh:
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; } }
Tips untuk meningkatkan performa real-time
Jika Anda ingin memindai kode batang dalam aplikasi real-time, ikuti panduan ini untuk mencapai frekuensi gambar terbaik:
-
Jangan ambil input pada resolusi native kamera. Di beberapa perangkat, pengambilan input pada resolusi native akan menghasilkan gambar yang sangat besar (10+ megapiksel), sehingga menghasilkan latensi yang sangat buruk tanpa berpengaruh pada akurasi. Sebagai gantinya, hanya minta ukuran dari kamera yang diperlukan untuk pemindaian kode batang, yang biasanya tidak lebih dari 2 megapiksel.
Namun, sebaiknya jangan gunakan preset sesi pengambilan nama yang bernama—
AVCaptureSessionPresetDefault
,AVCaptureSessionPresetLow
,AVCaptureSessionPresetMedium
, dan seterusnya, karena dapat dipetakan ke resolusi yang tidak sesuai di beberapa perangkat. Sebagai gantinya, gunakan preset spesifik sepertiAVCaptureSessionPreset1280x720
.Jika kecepatan pemindaian penting, Anda dapat menurunkan resolusi pengambilan gambar lebih lanjut. Namun, perhatikan persyaratan ukuran kode batang minimum yang diuraikan di atas.
Jika Anda mencoba mengenali kode batang dari urutan frame video streaming, pengenal mungkin akan memberikan hasil yang berbeda dari satu frame ke frame lainnya. Anda harus menunggu sampai mendapatkan rangkaian berturut-turut dengan nilai yang sama untuk yakin bahwa Anda menampilkan hasil yang baik.
Digit Checksum tidak didukung untuk ITF dan CODE-39.
- Untuk memproses frame video, gunakan API sinkron
results(in:)
dari detektor. Panggil metode ini dari fungsicaptureOutput(_, didOutput:from:)
AVCaptureVideoDataOutputSampleBufferDelegate
untuk mendapatkan hasil dari frame video yang diberikan secara sinkron. PertahankanalwaysDiscardsLateVideoFrames
AVCaptureVideoDataOutput
sebagaitrue
untuk men-throttle panggilan ke detektor. Jika frame video baru tersedia saat detektor sedang berjalan, frame tersebut akan dihapus. - Jika Anda menggunakan output detektor untuk menempatkan grafis pada gambar input, pertama-tama dapatkan hasilnya dari ML Kit, lalu render gambar dan tempatkan grafis dalam satu langkah. Dengan demikian, Anda hanya merender ke permukaan tampilan sekali untuk setiap frame input yang diproses. Lihat updatePreviewOverlayViewWithLastFrame dalam sampel panduan memulai ML Kit sebagai contoh.