Catch up on highlights from Firebase at Google I/O 2023. Learn more

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

Bạn có thể sử dụng ML Kit để nhận dạng và giải mã mã vạch.

Trước khi bắt đầu

  1. Nếu bạn chưa thêm Firebase vào ứng dụng của mình, hãy làm như vậy bằng cách làm theo các bước trong hướng dẫn bắt đầu .
  2. Bao gồm các thư viện ML Kit trong Podfile của bạn:
    pod 'Firebase/MLVision'
    pod 'Firebase/MLVisionBarcodeModel'
    
    Sau khi bạn cài đặt hoặc cập nhật Pods của dự án, hãy nhớ mở dự án Xcode của bạn bằng cách sử dụng .xcworkspace của nó.
  3. Trong ứng dụng của bạn, hãy nhập Firebase:

    Nhanh

    import Firebase

    Objective-C

    @import Firebase;

Nguyên tắc đầu vào hình ảnh

  • Để ML Kit có thể đọc chính xác mã vạch, hình ảnh đầu vào phải chứa mã vạch được thể hiện bằng đủ dữ liệu pixel.

    Các yêu cầu về dữ liệu pixel cụ thể phụ thuộc vào cả loại mã vạch và số lượng dữ liệu được mã hóa trong đó (vì hầu hết các mã vạch đều hỗ trợ trọng tải có độ dài thay đổi). Nói chung, đơn vị có ý nghĩa nhỏ nhất của mã vạch phải rộng ít nhất 2 pixel (và đối với mã 2 chiều, cao 2 pixel).

    Ví dụ: mã vạch EAN-13 được tạo thành từ các thanh và khoảng trắng 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 ít nhất là 2, 4, 6 và Rộng 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 nhất là 190 pixel.

    Các định dạng dày đặc hơn, chẳng hạn như PDF417, cần kích thước pixel lớn hơn để ML Kit có thể đọc chúng một cách đáng tin cậy. Ví dụ: mã PDF417 có thể có tối đa 34 "từ" rộng 17 đơn vị trong một hàng, lý tưởng là rộng ít nhất 1156 pixel.

  • Lấy nét hình ảnh kém có thể làm ảnh hưởng đến độ chính xác của quá trình quét. Nếu bạn không nhận được kết quả chấp nhận được, hãy thử yêu cầu người dùng lấy lại hình ảnh.

  • Đối với các ứng dụng điển hình, 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 mã vạch có thể phát hiện được từ khoảng cách xa máy ảnh hơn.

    Tuy nhiên, trong các ứng dụng có độ trễ là 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 Mẹo để cải thiện hiệu suất thời gian thực .

1. Định cấu hình máy dò mã vạch

Nếu bạn biết định dạng mã vạch nào bạn muốn đọc, bạn có thể cải thiện tốc độ của máy dò mã vạch bằng cách định cấu hình nó để chỉ phát hiện các định dạng đó.

Ví dụ: để chỉ phát hiện mã Aztec và mã QR, hãy xây dựng đối tượng VisionBarcodeDetectorOptions như trong ví dụ sau:

Nhanh

let format = VisionBarcodeFormat.all
let barcodeOptions = VisionBarcodeDetectorOptions(formats: format)

Các định dạng sau được hỗ trợ:

  • Mã128
  • Mã39
  • Mã số93
  • CodaBar
  • EAN13
  • EAN8
  • ITF
  • UPCA
  • LÊN
  • Mã QR
  • PDF417
  • Aztec
  • Ma trận dữ liệu

Objective-C

FIRVisionBarcodeDetectorOptions *options =
    [[FIRVisionBarcodeDetectorOptions alloc]
     initWithFormats: FIRVisionBarcodeFormatQRCode | FIRVisionBarcodeFormatAztec];

Các định dạng sau được hỗ trợ:

  • Mã 128 ( FIRVisionBarcodeFormatCode128 )
  • Mã 39 ( FIRVisionBarcodeFormatCode39 )
  • Mã 93 ( FIRVisionBarcodeFormatCode93 )
  • Codabar ( FIRVisionBarcodeFormatCodaBar )
  • EAN-13 ( FIRVisionBarcodeFormatEAN13 )
  • EAN-8 ( FIRVisionBarcodeFormatEAN8 )
  • ITF ( FIRVisionBarcodeFormatITF )
  • UPC-A ( FIRVisionBarcodeFormatUPCA )
  • UPC-E ( FIRVisionBarcodeFormatUPCE )
  • Mã QR ( FIRVisionBarcodeFormatQRCode )
  • PDF417 ( FIRVisionBarcodeFormatPDF417 )
  • Aztec ( FIRVisionBarcodeFormatAztec )
  • Ma trận dữ liệu ( FIRVisionBarcodeFormatDataMatrix )

2. Chạy máy dò mã vạch

Để quét mã vạch trong hình ảnh, hãy chuyển hình ảnh dưới dạng UIImage hoặc CMSampleBufferRef đến phương thức detect(in:) của VisionBarcodeDetector :

  1. Nhận một phiên bản của VisionBarcodeDetector :

    Nhanh

    lazy var vision = Vision.vision()
    
    let barcodeDetector = vision.barcodeDetector(options: barcodeOptions)
    

    Objective-C

    FIRVision *vision = [FIRVision vision];
    FIRVisionBarcodeDetector *barcodeDetector = [vision barcodeDetector];
    // Or, to change the default settings:
    // FIRVisionBarcodeDetector *barcodeDetector =
    //     [vision barcodeDetectorWithOptions:options];
    
  2. Tạo đối tượng VisionImage bằng UIImage hoặc CMSampleBufferRef .

    Để sử dụng UIImage :

    1. Nếu cần, hãy xoay hình ảnh để thuộc tính imageOrientation của nó là .up .
    2. Tạo một đối tượng VisionImage bằng cách sử dụng UIImage được xoay chính xác. Không chỉ định bất kỳ siêu dữ liệu xoay vòng nào — phải sử dụng giá trị mặc định, .topLeft .

      Nhanh

      let image = VisionImage(image: uiImage)

      Objective-C

      FIRVisionImage *image = [[FIRVisionImage alloc] initWithImage:uiImage];

    Để sử dụng CMSampleBufferRef :

    1. Tạo một đối tượng VisionImageMetadata chỉ định hướng của dữ liệu hình ảnh có trong bộ đệm CMSampleBufferRef .

      Để có được hướng hình ảnh:

      Nhanh

      func imageOrientation(
          deviceOrientation: UIDeviceOrientation,
          cameraPosition: AVCaptureDevice.Position
          ) -> VisionDetectorImageOrientation {
          switch deviceOrientation {
          case .portrait:
              return cameraPosition == .front ? .leftTop : .rightTop
          case .landscapeLeft:
              return cameraPosition == .front ? .bottomLeft : .topLeft
          case .portraitUpsideDown:
              return cameraPosition == .front ? .rightBottom : .leftBottom
          case .landscapeRight:
              return cameraPosition == .front ? .topRight : .bottomRight
          case .faceDown, .faceUp, .unknown:
              return .leftTop
          }
      }

      Objective-C

      - (FIRVisionDetectorImageOrientation)
          imageOrientationFromDeviceOrientation:(UIDeviceOrientation)deviceOrientation
                                 cameraPosition:(AVCaptureDevicePosition)cameraPosition {
        switch (deviceOrientation) {
          case UIDeviceOrientationPortrait:
            if (cameraPosition == AVCaptureDevicePositionFront) {
              return FIRVisionDetectorImageOrientationLeftTop;
            } else {
              return FIRVisionDetectorImageOrientationRightTop;
            }
          case UIDeviceOrientationLandscapeLeft:
            if (cameraPosition == AVCaptureDevicePositionFront) {
              return FIRVisionDetectorImageOrientationBottomLeft;
            } else {
              return FIRVisionDetectorImageOrientationTopLeft;
            }
          case UIDeviceOrientationPortraitUpsideDown:
            if (cameraPosition == AVCaptureDevicePositionFront) {
              return FIRVisionDetectorImageOrientationRightBottom;
            } else {
              return FIRVisionDetectorImageOrientationLeftBottom;
            }
          case UIDeviceOrientationLandscapeRight:
            if (cameraPosition == AVCaptureDevicePositionFront) {
              return FIRVisionDetectorImageOrientationTopRight;
            } else {
              return FIRVisionDetectorImageOrientationBottomRight;
            }
          default:
            return FIRVisionDetectorImageOrientationTopLeft;
        }
      }

      Sau đó, tạo đối tượng siêu dữ liệu:

      Nhanh

      let cameraPosition = AVCaptureDevice.Position.back  // Set to the capture device you used.
      let metadata = VisionImageMetadata()
      metadata.orientation = imageOrientation(
          deviceOrientation: UIDevice.current.orientation,
          cameraPosition: cameraPosition
      )

      Objective-C

      FIRVisionImageMetadata *metadata = [[FIRVisionImageMetadata alloc] init];
      AVCaptureDevicePosition cameraPosition =
          AVCaptureDevicePositionBack;  // Set to the capture device you used.
      metadata.orientation =
          [self imageOrientationFromDeviceOrientation:UIDevice.currentDevice.orientation
                                       cameraPosition:cameraPosition];
    2. Tạo đối tượng VisionImage bằng đối tượng CMSampleBufferRef và siêu dữ liệu xoay:

      Nhanh

      let image = VisionImage(buffer: sampleBuffer)
      image.metadata = metadata

      Objective-C

      FIRVisionImage *image = [[FIRVisionImage alloc] initWithBuffer:sampleBuffer];
      image.metadata = metadata;
  3. Sau đó, chuyển hình ảnh vào phương thức detect(in:) :

    Nhanh

    barcodeDetector.detect(in: visionImage) { features, error in
      guard error == nil, let features = features, !features.isEmpty else {
        // ...
        return
      }
    
      // ...
    }
    

    Objective-C

    [barcodeDetector detectInImage:image
                        completion:^(NSArray<FIRVisionBarcode *> *barcodes,
                                     NSError *error) {
      if (error != nil) {
        return;
      } else if (barcodes != nil) {
        // Recognized barcodes
        // ...
      }
    }];
    

3. Nhận thông tin từ mã vạch

Nếu hoạt động nhận dạng mã vạch thành công, bộ dò sẽ trả về một mảng các đối tượng VisionBarcode . Mỗi đối tượng VisionBarcode đạ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 tọa độ giới hạn của nó trong hình ảnh đầu vào, cũng như dữ liệu thô được mã hóa bởi mã vạch. Ngoài ra, nếu máy dò mã vạch có thể xác định loại dữ liệu được mã hóa bởi mã vạch, 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ụ:

Nhanh

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 (FIRVisionBarcode *barcode in barcodes) {
   NSArray *corners = barcode.cornerPoints;

   NSString *displayValue = barcode.displayValue;
   NSString *rawValue = barcode.rawValue;

   FIRVisionBarcodeValueType valueType = barcode.valueType;
   switch (valueType) {
     case FIRVisionBarcodeValueTypeWiFi:
       // ssid = barcode.wifi.ssid;
       // password = barcode.wifi.password;
       // encryptionType = barcode.wifi.type;
       break;
     case FIRVisionBarcodeValueTypeURL:
       // url = barcode.URL.url;
       // title = barcode.URL.title;
       break;
     // ...
     default:
       break;
   }
 }

Mẹo để cải thiện hiệu suất thời gian thực

Nếu bạn muốn quét mã vạch trong ứng dụng 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:

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

    Các cài đặt trước phiên chụp được đặt tên— AVCaptureSessionPresetDefault , AVCaptureSessionPresetLow , AVCaptureSessionPresetMedium , v.v.) - không được khuyến nghị, tuy nhiên, chúng có thể ánh xạ tới các độ 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 cài đặt trước cụ thể như AVCaptureSessionPreset1280x720 .

    Nếu tốc độ quét là quan trọng, bạn có thể giảm thêm độ phân giải chụp ảnh. Tuy nhiên, hãy nhớ các yêu cầu về kích thước mã vạch tối thiểu được nêu ở trên.

  • Các cuộc gọi từ bướm ga đến máy dò. Nếu có một khung video mới trong khi trình dò ​​đang chạy, hãy thả khung đó xuống.
  • Nếu bạn đang sử dụng đầu ra của máy dò để phủ đồ họa lên hình ảnh đầu vào, trước tiên hãy lấy kết quả từ Bộ công cụ ML, sau đó hiển thị hình ảnh và lớp phủ trong một bước duy nhất. Bằng cách đó, bạn chỉ hiển thị trên bề mặt hiển thị một lần cho mỗi khung hình đầu vào. Xem các lớp previewOverlayViewFIRDetectionOverlayView trong ứng dụng mẫu trưng bày để làm ví dụ.