סרוק ברקודים עם ערכת ML ב-iOS

אתה יכול להשתמש ב-ML Kit כדי לזהות ולפענח ברקודים.

לפני שאתה מתחיל

  1. אם עדיין לא הוספת את Firebase לאפליקציה שלך, עשה זאת על ידי ביצוע השלבים במדריך לתחילת העבודה .
  2. כלול את ספריות ML Kit ב-Podfile שלך:
    pod 'Firebase/MLVision'
    pod 'Firebase/MLVisionBarcodeModel'
    
    לאחר שתתקין או תעדכן את ה-Pods של הפרויקט שלך, הקפד לפתוח את פרויקט Xcode שלך ​​באמצעות .xcworkspace שלו.
  3. באפליקציה שלך, ייבא את Firebase:

    מָהִיר

    import Firebase

    Objective-C

    @import Firebase;

הנחיות לקלט תמונה

  • כדי ש-ML Kit תקרא במדויק ברקודים, תמונות קלט חייבות להכיל ברקודים המיוצגים על ידי מספיק נתוני פיקסלים.

    הדרישות הספציפיות לנתוני הפיקסלים תלויות הן בסוג הברקוד והן בכמות הנתונים המקודדת בו (שכן רוב הברקודים תומכים במטען באורך משתנה). באופן כללי, היחידה המשמעותית הקטנה ביותר של הברקוד צריכה להיות ברוחב של 2 פיקסלים לפחות (ועבור קודים דו-ממדיים, גובה של 2 פיקסלים).

    לדוגמה, ברקודים של EAN-13 מורכבים מפס ורווחים ברוחב של 1, 2, 3 או 4 יחידות, כך שלתמונת ברקוד EAN-13 יש באופן אידיאלי פסים ורווחים שהם לפחות 2, 4, 6 ו רוחב 8 פיקסלים. מכיוון ברוחב של ברקוד EAN-13 הוא 95 יחידות בסך הכל, על הברקוד להיות ברוחב של 190 פיקסלים לפחות.

    פורמטים צפופים יותר, כגון PDF417, צריכים ממדי פיקסלים גדולים יותר כדי ש-ML Kit יקרא אותם בצורה מהימנה. לדוגמה, קוד PDF417 יכול לכלול עד 34 "מילים" ברוחב של 17 יחידות בשורה אחת, שבאופן אידיאלי יהיו ברוחב של לפחות 1156 פיקסלים.

  • מיקוד לקוי של התמונה עלול לפגוע בדיוק הסריקה. אם אינך מקבל תוצאות מקובלות, נסה לבקש מהמשתמש לצלם מחדש את התמונה.

  • עבור יישומים טיפוסיים, מומלץ לספק תמונה ברזולוציה גבוהה יותר (כגון 1280x720 או 1920x1080), מה שהופך ברקודים לזיהוי ממרחק גדול יותר מהמצלמה.

    עם זאת, ביישומים שבהם זמן האחזור הוא קריטי, אתה יכול לשפר את הביצועים על ידי לכידת תמונות ברזולוציה נמוכה יותר, אך דורש שהברקוד יהווה את רוב תמונת הקלט. ראה גם טיפים לשיפור הביצועים בזמן אמת .

1. הגדר את גלאי הברקוד

אם אתה יודע אילו פורמטים של ברקוד אתה מצפה לקרוא, אתה יכול לשפר את המהירות של גלאי הברקוד על ידי הגדרתו לזהות רק פורמטים אלה.

לדוגמה, כדי לזהות רק קוד אצטקי וקודי QR, בנו אובייקט VisionBarcodeDetectorOptions כמו בדוגמה הבאה:

מָהִיר

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

הפורמטים הבאים נתמכים:

  • קוד128
  • קוד39
  • קוד93
  • CodaBar
  • EAN13
  • EAN8
  • ITF
  • UPCA
  • UPCE
  • QRCode
  • PDF417
  • אצטקי
  • מטריצת נתונים

Objective-C

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

הפורמטים הבאים נתמכים:

  • קוד 128 ( FIRVisionBarcodeFormatCode128 )
  • קוד 39 ( FIRVisionBarcodeFormatCode39 )
  • קוד 93 ( FIRVisionBarcodeFormatCode93 )
  • Codabar ( FIRVisionBarcodeFormatCodaBar )
  • EAN-13 ( FIRVisionBarcodeFormatEAN13 )
  • EAN-8 ( FIRVisionBarcodeFormatEAN8 )
  • ITF ( FIRVisionBarcodeFormatITF )
  • UPC-A ( FIRVisionBarcodeFormatUPCA )
  • UPC-E ( FIRVisionBarcodeFormatUPCE )
  • קוד QR ( FIRVisionBarcodeFormatQRCode )
  • PDF417 ( FIRVisionBarcodeFormatPDF417 )
  • אצטקי ( FIRVisionBarcodeFormatAztec )
  • מטריצת נתונים ( FIRVisionBarcodeFormatDataMatrix )

2. הפעל את גלאי הברקוד

כדי לסרוק ברקודים בתמונה, העבר את התמונה כ- UIImage או CMSampleBufferRef לשיטת detect(in:) של VisionBarcodeDetector :

  1. קבל מופע של VisionBarcodeDetector :

    מָהִיר

    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. צור אובייקט VisionImage באמצעות UIImage או CMSampleBufferRef .

    כדי להשתמש UIImage :

    1. במידת הצורך, סובב את התמונה כך שהמאפיין imageOrientation שלה יהיה .up .
    2. צור אובייקט VisionImage באמצעות UIImage המסובב כהלכה. אל תציין מטא נתונים כלשהם של סיבוב - יש להשתמש בערך ברירת המחדל, .topLeft .

      מָהִיר

      let image = VisionImage(image: uiImage)

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

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

      לאחר מכן, צור את אובייקט המטא נתונים:

      מָהִיר

      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. צור אובייקט VisionImage באמצעות האובייקט CMSampleBufferRef והמטא נתונים של הסיבוב:

      מָהִיר

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

      Objective-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
      }
    
      // ...
    }
    

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

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

טיפים לשיפור הביצועים בזמן אמת

אם ברצונך לסרוק ברקודים ביישום בזמן אמת, עקוב אחר ההנחיות הבאות כדי להשיג את קצבי המסגרות הטובים ביותר:

  • אל תלכוד קלט ברזולוציה המקורית של המצלמה. במכשירים מסוימים, לכידת קלט ברזולוציה המקורית מייצרת תמונות גדולות במיוחד (10+ מגה פיקסל), מה שגורם להשהייה נמוכה מאוד ללא תועלת לדיוק. במקום זאת, בקש רק מהמצלמה את הגודל הנדרש לזיהוי ברקוד: בדרך כלל לא יותר מ-2 מגה-פיקסל.

    עם זאת, ההגדרות המוגדרות מראש של הפעלת הלכידה - AVCaptureSessionPresetDefault , AVCaptureSessionPresetLow , AVCaptureSessionPresetMedium וכן הלאה) - אינן מומלצות, מכיוון שהן עלולות למפות לרזולוציות לא מתאימות במכשירים מסוימים. במקום זאת, השתמש בהגדרות המוגדרות מראש הספציפיות כגון AVCaptureSessionPreset1280x720 .

    אם מהירות הסריקה חשובה, תוכל להוריד עוד יותר את רזולוציית לכידת התמונה. עם זאת, זכור את דרישות גודל הברקוד המינימלי המפורטות לעיל.

  • מצערת קוראת לגלאי. אם מסגרת וידאו חדשה הופכת לזמינה בזמן שהגלאי פועל, שחרר את המסגרת.
  • אם אתה משתמש בפלט של הגלאי כדי לשכב גרפיקה על תמונת הקלט, תחילה קבל את התוצאה מ-ML Kit, ולאחר מכן עבד את התמונה ואת שכבת העל בצעד אחד. על ידי כך, אתה מעבד למשטח התצוגה רק פעם אחת עבור כל מסגרת קלט. ראה את המחלקות previewOverlayView ו- FIRDetectionOverlayView באפליקציה לדוגמה לראווה לדוגמא.