بارکدها را با کیت ML در iOS اسکن کنید

برای شناسایی و رمزگشایی بارکدها می توانید از کیت ML استفاده کنید.

قبل از اینکه شروع کنی

  1. اگر قبلاً Firebase را به برنامه خود اضافه نکرده اید، این کار را با دنبال کردن مراحل راهنمای شروع کار انجام دهید.
  2. کتابخانه‌های ML Kit را در فایل پادفایل خود قرار دهید:
    pod 'Firebase/MLVision'
    pod 'Firebase/MLVisionBarcodeModel'
    
    پس از نصب یا به‌روزرسانی Pods پروژه، حتماً پروژه Xcode خود را با استفاده از .xcworkspace آن باز کنید.
  3. در برنامه خود، Firebase را وارد کنید:

    سریع

    import Firebase

    هدف-C

    @import Firebase;

دستورالعمل های تصویر ورودی

  • برای اینکه کیت ML بتواند بارکدها را به طور دقیق بخواند، تصاویر ورودی باید حاوی بارکدهایی باشند که با داده های پیکسلی کافی نشان داده شوند.

    نیازهای خاص داده پیکسلی هم به نوع بارکد و هم به مقدار داده ای که در آن کدگذاری می شود بستگی دارد (زیرا اکثر بارکدها از یک بار با طول متغیر پشتیبانی می کنند). به طور کلی، کوچکترین واحد معنی دار بارکد باید حداقل 2 پیکسل عرض داشته باشد (و برای کدهای 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
  • کد QRC
  • PDF417
  • آزتک
  • DataMatrix

هدف-C

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

فرمت های زیر پشتیبانی می شوند:

  • کد 128 ( FIRVisionBarcodeFormatCode128 )
  • کد 39 ( FIRVisionBarcodeFormatCode39 )
  • کد 93 ( FIRVisionBarcodeFormatCode93 )
  • کدابار ( 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)
    

    هدف-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 دریافت کنید، سپس تصویر را رندر کنید و در یک مرحله همپوشانی کنید. با انجام این کار، برای هر فریم ورودی فقط یک بار به سطح نمایشگر رندر می دهید. به عنوان مثال، کلاس‌های previewOverlayView و FIRDetectionOverlayView را در برنامه نمونه ویترینی ببینید.