สแกนบาร์โค้ดด้วย ML Kit บน iOS

คุณสามารถใช้ ML Kit เพื่อจดจำและถอดรหัสบาร์โค้ดได้

ก่อนที่คุณจะเริ่ม

  1. หากคุณยังไม่ได้เพิ่ม Firebase ลงในแอปของคุณ ให้ทำตามขั้นตอนใน คู่มือการเริ่มต้นใช้งาน
  2. รวมไลบรารี ML Kit ไว้ใน Podfile ของคุณ:
    pod 'Firebase/MLVision'
    pod 'Firebase/MLVisionBarcodeModel'
    
    หลังจากที่คุณติดตั้งหรืออัปเดต Pod ของโปรเจ็กต์แล้ว อย่าลืมเปิดโปรเจ็กต์ Xcode โดยใช้ .xcworkspace
  3. ในแอปของคุณ ให้นำเข้า Firebase:

    สวิฟท์

    import Firebase

    วัตถุประสงค์-C

    @import Firebase;

แนวทางการป้อนรูปภาพ

  • เพื่อให้ ML Kit อ่านบาร์โค้ดได้อย่างแม่นยำ รูปภาพที่ป้อนจะต้องมีบาร์โค้ดที่แสดงด้วยข้อมูลพิกเซลที่เพียงพอ

    ข้อกำหนดข้อมูลพิกเซลเฉพาะจะขึ้นอยู่กับประเภทของบาร์โค้ดและจำนวนข้อมูลที่เข้ารหัส (เนื่องจากบาร์โค้ดส่วนใหญ่รองรับเพย์โหลดความยาวผันแปรได้) โดยทั่วไป หน่วยที่มีความหมายน้อยที่สุดของบาร์โค้ดควรมีความกว้างอย่างน้อย 2 พิกเซล (และสำหรับโค้ด 2 มิติควรมีความสูง 2 พิกเซล)

    ตัวอย่างเช่น บาร์โค้ด EAN-13 ประกอบด้วยแท่งและช่องว่างที่มีความกว้าง 1, 2, 3 หรือ 4 หน่วย ดังนั้นรูปภาพบาร์โค้ด EAN-13 จึงควรมีแถบและช่องว่างอย่างน้อย 2, 4, 6 และ กว้าง 8 พิกเซล เนื่องจากบาร์โค้ด EAN-13 มีความกว้างทั้งหมด 95 หน่วย บาร์โค้ดจึงควรมีความกว้างอย่างน้อย 190 พิกเซล

    รูปแบบที่หนาแน่นมากขึ้น เช่น PDF417 จำเป็นต้องมีขนาดพิกเซลที่มากขึ้นเพื่อให้ ML Kit อ่านได้อย่างน่าเชื่อถือ ตัวอย่างเช่น โค้ด PDF417 สามารถมี "คำ" กว้าง 17 หน่วยได้สูงสุด 34 คำในแถวเดียว ซึ่งตามหลักการแล้วควรมีความกว้างอย่างน้อย 1156 พิกเซล

  • การโฟกัสภาพที่ไม่ดีอาจส่งผลเสียต่อความแม่นยำในการสแกน หากคุณไม่ได้รับผลลัพธ์ที่ยอมรับได้ ให้ลองขอให้ผู้ใช้จับภาพใหม่

  • สำหรับการใช้งานทั่วไป ขอแนะนำให้จัดเตรียมภาพที่มีความละเอียดสูงกว่า (เช่น 1280x720 หรือ 1920x1080) ซึ่งทำให้สามารถตรวจจับบาร์โค้ดได้จากระยะห่างที่มากขึ้นจากกล้อง

    อย่างไรก็ตาม ในแอปพลิเคชันที่เวลาแฝงเป็นสิ่งสำคัญ คุณสามารถปรับปรุงประสิทธิภาพได้โดยการถ่ายภาพด้วยความละเอียดที่ต่ำกว่า แต่กำหนดให้บาร์โค้ดเป็นส่วนใหญ่ของภาพที่ป้อนเข้า ดู เคล็ดลับในการปรับปรุงประสิทธิภาพแบบเรียลไทม์ ด้วย

1. กำหนดค่าตัวตรวจจับบาร์โค้ด

หากคุณทราบว่าคุณต้องการอ่านบาร์โค้ดรูปแบบใด คุณสามารถปรับปรุงความเร็วของตัวตรวจจับบาร์โค้ดได้โดยการกำหนดค่าให้ตรวจจับเฉพาะรูปแบบเหล่านั้นเท่านั้น

ตัวอย่างเช่น หากต้องการตรวจจับเฉพาะรหัส Aztec และรหัส QR ให้สร้างวัตถุ VisionBarcodeDetectorOptions ดังตัวอย่างต่อไปนี้:

สวิฟท์

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

รองรับรูปแบบต่อไปนี้:

  • รหัส128
  • รหัส39
  • รหัส93
  • โคดาบาร์
  • EAN13
  • EAN8
  • ไอทีเอฟ
  • UPCA
  • อัพซีอี
  • คิวอาร์โค้ด
  • PDF417
  • แอซเท็ก
  • ดาต้าเมทริกซ์

วัตถุประสงค์-C

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

รองรับรูปแบบต่อไปนี้:

  • รหัส 128 ( FIRVisionBarcodeFormatCode128 )
  • รหัส 39 ( FIRVisionBarcodeFormatCode39 )
  • รหัส 93 ( FIRVisionBarcodeFormatCode93 )
  • โคดาบาร์ ( FIRVisionBarcodeFormatCodaBar )
  • EAN-13 ( FIRVisionBarcodeFormatEAN13 )
  • EAN-8 ( FIRVisionBarcodeFormatEAN8 )
  • ไอทีเอฟ ( FIRVisionBarcodeFormatITF )
  • UPC-A ( FIRVisionBarcodeFormatUPCA )
  • UPC-E ( FIRVisionBarcodeFormatUPCE )
  • รหัส QR ( FIRVisionBarcodeFormatQRCode )
  • PDF417 ( FIRVisionBarcodeFormatPDF417 )
  • แอซเท็ก ( FIRVisionBarcodeFormatAztec )
  • เมทริกซ์ข้อมูล ( FIRVisionBarcodeFormatDataMatrix )

2. เรียกใช้ตัวตรวจจับบาร์โค้ด

หากต้องการสแกนบาร์โค้ดในรูปภาพ ให้ส่งรูปภาพเป็น UIImage หรือ CMSampleBufferRef ไปยังวิธีการตรวจจับของ VisionBarcodeDetector detect(in:) :

  1. รับอินสแตนซ์ของ VisionBarcodeDetector :

    สวิฟท์

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

    วัตถุประสงค์-C

    FIRVision *vision = [FIRVision vision];
    FIRVisionBarcodeDetector *barcodeDetector = [vision barcodeDetector];
    // Or, to change the default settings:
    // FIRVisionBarcodeDetector *barcodeDetector =
    //     [vision barcodeDetectorWithOptions:options];
    
  2. สร้างวัตถุ VisionImage โดยใช้ UIImage หรือ CMSampleBufferRef

    วิธีใช้ UIImage :

    1. หากจำเป็น ให้หมุนรูปภาพเพื่อให้คุณสมบัติ imageOrientation เป็น .up
    2. สร้างวัตถุ VisionImage โดยใช้ UIImage ที่หมุนอย่างถูกต้อง อย่าระบุข้อมูลเมตาการหมุนเวียนใดๆ ต้องใช้ค่าเริ่มต้น . .topLeft

      สวิฟท์

      let image = VisionImage(image: uiImage)

      วัตถุประสงค์-C

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

    วิธีใช้ CMSampleBufferRef :

    1. สร้างออบเจ็กต์ VisionImageMetadata ที่ระบุการวางแนวของข้อมูลรูปภาพที่มีอยู่ในบัฟเฟอร์ CMSampleBufferRef

      เพื่อให้ได้การวางแนวของภาพ:

      สวิฟท์

      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
          }
      }

      วัตถุประสงค์-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;
        }
      }

      จากนั้นสร้างวัตถุข้อมูลเมตา:

      สวิฟท์

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

      วัตถุประสงค์-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. สร้างวัตถุ VisionImage โดยใช้วัตถุ CMSampleBufferRef และข้อมูลเมตาการหมุน:

      สวิฟท์

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

      วัตถุประสงค์-C

      FIRVisionImage *image = [[FIRVisionImage alloc] initWithBuffer:sampleBuffer];
      image.metadata = metadata;
  3. จากนั้นส่งภาพไปยังวิธี detect(in:) :

    สวิฟท์

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

    วัตถุประสงค์-C

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

3. รับข้อมูลจากบาร์โค้ด

หากการดำเนินการจดจำบาร์โค้ดสำเร็จ อุปกรณ์ตรวจจับจะส่งคืนอาร์เรย์ของออบเจ็กต์ VisionBarcode แต่ละวัตถุ VisionBarcode แสดงถึงบาร์โค้ดที่ตรวจพบในภาพ สำหรับบาร์โค้ดแต่ละอัน คุณสามารถรับพิกัดขอบเขตในรูปภาพอินพุต รวมถึงข้อมูลดิบที่เข้ารหัสด้วยบาร์โค้ด นอกจากนี้ หากตัวตรวจจับบาร์โค้ดสามารถระบุประเภทของข้อมูลที่เข้ารหัสด้วยบาร์โค้ดได้ คุณก็สามารถรับออบเจ็กต์ที่มีข้อมูลที่แยกวิเคราะห์ได้

ตัวอย่างเช่น:

สวิฟท์

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
  }
}

วัตถุประสงค์-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;
   }
 }

เคล็ดลับในการปรับปรุงประสิทธิภาพแบบเรียลไทม์

หากคุณต้องการสแกนบาร์โค้ดในแอปพลิเคชันแบบเรียลไทม์ ให้ปฏิบัติตามคำแนะนำเหล่านี้เพื่อให้ได้เฟรมเรตที่ดีที่สุด:

  • อย่าจับภาพอินพุตที่ความละเอียดดั้งเดิมของกล้อง ในอุปกรณ์บางชนิด การจับอินพุตที่ความละเอียดมาตรฐานจะทำให้ได้ภาพที่มีขนาดใหญ่มาก (10+ ล้านพิกเซล) ซึ่งส่งผลให้มีเวลาแฝงต่ำมากและไม่มีประโยชน์ต่อความแม่นยำ แต่ให้ขอเฉพาะขนาดจากกล้องที่จำเป็นสำหรับการตรวจจับบาร์โค้ดเท่านั้น ซึ่งโดยปกติแล้วจะไม่เกิน 2 เมกะพิกเซล

    อย่างไรก็ตาม ไม่แนะนำให้ใช้การตั้งค่าล่วงหน้าของเซสชันการจับภาพที่มีชื่อ เช่น AVCaptureSessionPresetDefault , AVCaptureSessionPresetLow , AVCaptureSessionPresetMedium เนื่องจากสามารถแมปกับความละเอียดที่ไม่เหมาะสมบนอุปกรณ์บางตัวได้ ให้ใช้ค่าที่ตั้งล่วงหน้าเฉพาะ เช่น AVCaptureSessionPreset1280x720 แทน

    หากความเร็วในการสแกนเป็นสิ่งสำคัญ คุณสามารถลดความละเอียดในการจับภาพลงได้อีก อย่างไรก็ตาม โปรดคำนึงถึงข้อกำหนดขนาดบาร์โค้ดขั้นต่ำที่ระบุไว้ข้างต้น

  • คันเร่งเรียกไปที่เครื่องตรวจจับ หากมีเฟรมวิดีโอใหม่ในขณะที่ตัวตรวจจับกำลังทำงานอยู่ ให้ปล่อยเฟรมนั้น
  • หากคุณใช้เอาต์พุตของตัวตรวจจับเพื่อวางซ้อนกราฟิกบนรูปภาพอินพุต อันดับแรกรับผลลัพธ์จาก ML Kit จากนั้นเรนเดอร์รูปภาพและโอเวอร์เลย์ในขั้นตอนเดียว การทำเช่นนี้ คุณจะเรนเดอร์ไปยังพื้นผิวจอแสดงผลเพียงครั้งเดียวสำหรับแต่ละเฟรมอินพุต ดูตัวอย่างคลาส PreviewOverlayView และ FIRDetectionOverlayView ในแอปตัวอย่าง Showcase