Quét mã vạch bằng Bộ công cụ máy học trên iOS

Sử dụng bộ sưu tập để sắp xếp ngăn nắp các trang Lưu và phân loại nội dung dựa trên lựa chọn ưu tiên của bạn.

Bạn có thể sử dụng Bộ công cụ máy học để nhận dạng và giải mã mã vạch.

Trước khi bắt đầu

  1. Đưa các nhóm Bộ công cụ máy học sau vào Podfile:
    pod 'GoogleMLKit/BarcodeScanning', '3.2.0'
    
  2. Sau khi bạn cài đặt hoặc cập nhật Nhóm của dự án, hãy mở dự án Xcode bằng cách sử dụng .xcworkspace của dự án đó. Bộ công cụ máy học được hỗ trợ trong Xcode phiên bản 12.4 trở lên.

Nhập nguyên tắc về hình ảnh

  • Để bộ công cụ máy học đọc được mã vạch chính xác, hình ảnh nhập 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 lẫn lượng dữ liệu được mã hoá trong đó, vì nhiều mã vạch hỗ trợ trọng tải khác nhau. Nhìn chung, đơn vị nhỏ nhất có ý nghĩa của mã vạch phải rộng ít nhất 2 pixel và cao 2 pixel cho mã 2 chiều.

    Ví dụ: mã vạch EAN-13 bao gồm các thanh và không gian rộng 1, 2, 3 hoặc 4 đơn vị, vì vậy, hình ảnh mã vạch EAN-13 lý tưởng có các thanh và khoảng trắng rộng ít nhất 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 độ, chẳng hạn như PDF417, cần có kích thước pixel lớn hơn để Bộ công cụ máy học đọc được các dữ liệu đó một cách đáng tin cậy. Ví dụ: mã PDF417 có thể có tối đa 34 đơn vị rộng 17 đơn vị "từ" trong một hàng, tốt nhất nên rộng tối thiểu 1156 pixel.

  • Tiêu điểm kém về hình ảnh có thể ảnh hưởng đến độ chính xác của việc 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, để cho phép quét mã vạch từ một khoảng cách lớn hơn từ máy ảnh.

    Tuy nhiên, trong các ứng dụng cần độ trễ, 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 nhập vào. Ngoài ra, hãy xem bài viết 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 mình muốn đọc định dạng mã vạch nào, 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 quét để chỉ quét các định dạng đó.

Ví dụ: để chỉ quét mã Aztec và mã QR, hãy tạo một đố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ợ:

  • mã128
  • mã_39
  • mã99
  • Thanh toán
  • ma trận dữ liệu
  • EAN13
  • EAN8
  • Ý
  • Mã qrCode
  • Uỷ ban bầu cử Liên bang (UPCA)
  • BẬT
  • 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)
  • Thanh Coda (MLKBarcodeFormatCodaBar)
  • Ma trận dữ liệu (MLKBarcodeFormatDataMatrix)
  • EAN-13 (MLKBarcodeFormatEAN13)
  • EAN-8 (MLKBarcodeFormatEAN8)
  • Ý (MLKBarcodeFormatITF)
  • Mã QR (MLKBarcodeFormatQRCode)
  • UPC-A (MLKBarcodeFormatUPCA)
  • UPC-E (MLKBarcodeFormatUPCE)
  • PDF-417 (MLKBarcodeFormatPDF417)
  • Mã Aztec (MLKBarcodeFormatAztec)

2. Chuẩn bị hình ảnh nhập

Để quét mã vạch trong một hình ảnh, hãy truyền hình ảnh dưới dạng UIImage hoặc CMSampleBufferRef vào phương thức process() hoặc results(in:) của BarcodeScanner&3:

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ằng UIImage. 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 trong CMSampleBuffer.

    Cách lấy hướng 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ướng CMSampleBuffer:

    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. Nhận thực thể của BarcodeScanner

Nhận thực thể của BarcodeScanner:

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 đó, hãy truyền hình ảnh đến phương thức process():

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 thao tác quét mã vạch thành công, trình quét sẽ trả về một loạt các đối tượng Barcode. 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 của mã đó trong hình ảnh nhập vào, cũng như dữ liệu thô được mã hoá bằng mã vạch. Ngoài ra, nếu trình 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 được 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 ứng dụng theo thời gian thực, hãy làm theo những nguyên tắc sau để đạt được tốc độ khung hình tốt nhất:

  • Không chụp ảnh đầu vào ở độ phân giải gốc của máy ảnh. Trên một số thiết bị, tính năng chụp ảnh ở độ phân giải gốc sẽ tạo ra hình ảnh cực lớn (hơn 10 megapixel), dẫn đến độ trễ rất thấp mà không mang lại độ chính xác. Thay vào đó, chỉ yêu cầu kích thước của máy ảnh cần có để quét mã vạch, thường không quá 2 megapixel.

    Tuy nhiên, bạn không nên sử dụng giá trị đặt trước cho phiên chụp ảnh có tên – AVCaptureSessionPresetDefault, AVCaptureSessionPresetLow, AVCaptureSessionPresetMedium, v.v.) vì chúng có thể liên kết với những độ 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 quan trọng, bạn có thể giảm độ phân giải chụp ảnh hơn nữa. Tuy nhiên, hãy lưu ý các yêu cầu tối thiểu về kích thước mã vạch cũng như các yêu cầu nêu trên.

    Nếu bạn đang cố gắng nhận dạng mã vạch từ một chuỗi khung hình video phát trực tuyến, thì trình nhận dạng 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 cùng một chuỗi giá trị liên tục để 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 hình video, hãy sử dụng API đồng bộ results(in:) của trình phát hiện. Gọi phương thức này từ hàm captureOutput(_, didOutput:from:) của AVCaptureVideoDataOutputSampleBufferDelegate để nhận kết quả từ một khung hình video nhất định. Giữ AVCaptureVideoDataOutput\39; alwaysDiscardsLateVideoFrames làm true để điều tiết các lệnh gọi đến trình phát hiện. Nếu một khung hình video mới ra mắt trong khi trình phát hiện đang chạy, thì trình phát hiện đó sẽ bị loại bỏ.
  • Nếu bạn sử dụng đầu ra của trình phát hiện để che phủ hình ảnh trên hình ảnh nhập vào, trước tiên, hãy lấy kết quả từ Bộ công cụ máy học, sau đó kết xuất hình ảnh và lớp phủ trong một bước duy nhất. Bằng cách này, bạn chỉ hiển thị trên nền tảng hiển thị một lần cho mỗi khung đầu vào đã xử lý. Hãy xem ví dụ về updatePreviewOverlayViewWithLastFrame trong mẫu bắt đầu nhanh của Bộ công cụ máy học.