Сканируйте штрих-коды с помощью ML Kit на iOS

Вы можете использовать ML Kit для распознавания и декодирования штрих-кодов.

Попробуйте

Прежде чем вы начнете

  1. Включите в свой подфайл следующие модули ML Kit:
    pod 'GoogleMLKit/BarcodeScanning', '3.2.0'
    
    .
  2. После установки или обновления модулей вашего проекта откройте проект Xcode, используя его .xcworkspace . ML Kit поддерживается в Xcode версии 12.4 или выше.

Инструкции по входному изображению

  • Чтобы ML Kit точно считывал штрих-коды, входные изображения должны содержать штрих-коды, представленные достаточным количеством данных пикселей.

    Конкретные требования к пиксельным данным зависят как от типа штрих-кода, так и от количества закодированных в нем данных, поскольку многие штрих-коды поддерживают полезную нагрузку переменного размера. Как правило, наименьшая значимая единица штрих-кода должна иметь ширину не менее 2 пикселей, а для двумерных кодов — 2 пикселя в высоту.

    Например, штрих-коды EAN-13 состоят из штрихов и пробелов шириной 1, 2, 3 или 4 единицы, поэтому изображение штрих-кода EAN-13 в идеале содержит штрихи и пробелы шириной не менее 2, 4, 6 и 4 единиц. 8 пикселей в ширину. Поскольку штрих-код EAN-13 имеет общую ширину 95 единиц, ширина штрих-кода должна быть не менее 190 пикселей.

    Более плотные форматы, такие как PDF417, требуют больших размеров в пикселях, чтобы ML Kit мог их надежно читать. Например, код PDF417 может содержать до 34 «слов» шириной 17 единиц в одной строке, что в идеале должно иметь ширину не менее 1156 пикселей.

  • Плохая фокусировка изображения может повлиять на точность сканирования. Если ваше приложение не дает приемлемых результатов, попросите пользователя повторно захватить изображение.

  • Для типичных приложений рекомендуется предоставлять изображение с более высоким разрешением, например 1280 x 720 или 1920 x 1080, что позволяет сканировать штрих-коды с большего расстояния от камеры.

    Однако в приложениях, где задержка имеет решающее значение, вы можете повысить производительность, захватывая изображения с более низким разрешением, но требуя, чтобы штрих-код составлял большую часть входного изображения. Также см. Советы по повышению производительности в реальном времени .

1. Настройте сканер штрих-кода

Если вы знаете, какие форматы штрих-кодов вы ожидаете считывать, вы можете повысить скорость сканера штрих-кодов, настроив его на сканирование только этих форматов.

Например, чтобы сканировать только код Aztec и QR-коды, создайте объект BarcodeScannerOptions , как показано в следующем примере:

Быстрый

let format = .all
let barcodeOptions = BarcodeScannerOptions(formats: format)
  

Поддерживаются следующие форматы:

  • код128
  • код 39
  • код93
  • codaBar
  • матрица данных
  • EAN13
  • EAN8
  • МФТ
  • QR код
  • УПЦА
  • UPCE
  • PDF417
  • ацтек

Цель-C

MLKBarcodeScannerOptions *options =
  [[MLKBarcodeScannerOptions alloc]
   initWithFormats: MLKBarcodeFormatQRCode | MLKBarcodeFormatAztec];

Поддерживаются следующие форматы:

  • Код-128 ( MLKBarcodeFormatCode128 )
  • Код-39 ( MLKBarcodeFormatCode39 )
  • Код-93 ( MLKBarcodeFormatCode93 )
  • Кодабар ( MLKBarcodeFormatCodaBar )
  • Матрица данных ( MLKBarcodeFormatDataMatrix )
  • EAN-13 ( MLKBarcodeFormatEAN13 )
  • EAN-8 ( MLKBarcodeFormatEAN8 )
  • ITF ( MLKBarcodeFormatITF )
  • QR-код ( MLKBarcodeFormatQRCode )
  • СКП-А ( MLKBarcodeFormatUPCA )
  • UPC-E ( MLKBarcodeFormatUPCE )
  • PDF-417 ( MLKBarcodeFormatPDF417 )
  • Код ацтеков ( MLKBarcodeFormatAztec )

2. Подготовьте входное изображение

Чтобы сканировать штрих-коды в изображении, передайте изображение как UIImage или CMSampleBufferRef process() или results(in:) BarcodeScanner :

Создайте объект VisionImage , используя UIImage или CMSampleBuffer .

Если вы используете UIImage , выполните следующие действия:

  • Создайте объект VisionImage с UIImage . Убедитесь, что вы правильно .orientation .

    Быстрый

    let image = VisionImage(image: UIImage)
    visionImage.orientation = image.imageOrientation

    Цель-C

    MLKVisionImage *visionImage = [[MLKVisionImage alloc] initWithImage:image];
    visionImage.orientation = image.imageOrientation;

Если вы используете CMSampleBuffer , выполните следующие действия:

  • Укажите ориентацию данных изображения, содержащихся в CMSampleBuffer .

    Чтобы получить ориентацию изображения:

    Быстрый

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

    Цель-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;
      }
    }
          
  • Создайте объект VisionImage , используя объект CMSampleBuffer и ориентацию:

    Быстрый

    let image = VisionImage(buffer: sampleBuffer)
    image.orientation = imageOrientation(
      deviceOrientation: UIDevice.current.orientation,
      cameraPosition: cameraPosition)

    Цель-C

     MLKVisionImage *image = [[MLKVisionImage alloc] initWithBuffer:sampleBuffer];
     image.orientation =
       [self imageOrientationFromDeviceOrientation:UIDevice.currentDevice.orientation
                                    cameraPosition:cameraPosition];

3. Получите экземпляр BarcodeScanner

Получите экземпляр BarcodeScanner :

Быстрый

let barcodeScanner = BarcodeScanner.barcodeScanner()
// Or, to change the default settings:
// let barcodeScanner = BarcodeScanner.barcodeScanner(options: barcodeOptions)

Цель-C

MLKBarcodeScanner *barcodeScanner = [MLKBarcodeScanner barcodeScanner];
// Or, to change the default settings:
// MLKBarcodeScanner *barcodeScanner =
//     [MLKBarcodeScanner barcodeScannerWithOptions:options];

4. Обработайте изображение

Затем передайте изображение в метод process() :

Быстрый

barcodeScanner.process(visionImage) { features, error in
  guard error == nil, let features = features, !features.isEmpty else {
    // Error handling
    return
  }
  // Recognized barcodes
}

Цель-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. Получите информацию из штрих-кодов

Если операция сканирования штрих-кода прошла успешно, сканер возвращает массив объектов Barcode -кода. Каждый объект Barcode представляет собой штрих-код, обнаруженный на изображении. Для каждого штрих-кода вы можете получить его граничные координаты на входном изображении, а также необработанные данные, закодированные штрих-кодом. Также, если сканер штрих-кода смог определить тип данных, закодированных штрих-кодом, можно получить объект, содержащий разобранные данные.

Например:

Быстрый

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

Советы по улучшению производительности в реальном времени

Если вы хотите сканировать штрих-коды в приложении реального времени, следуйте этим рекомендациям для достижения наилучшей частоты кадров:

  • Не записывайте входные данные с исходным разрешением камеры. На некоторых устройствах захват входных данных с исходным разрешением создает очень большие (10+ мегапикселей) изображения, что приводит к очень малой задержке без повышения точности. Вместо этого запрашивайте у камеры только размер, необходимый для сканирования штрих-кода, который обычно не превышает 2 мегапикселей.

    Однако именованные предварительные настройки сеанса захвата — AVCaptureSessionPresetDefault , AVCaptureSessionPresetLow , AVCaptureSessionPresetMedium и т. д.) — не рекомендуются, поскольку они могут сопоставляться с неподходящим разрешением на некоторых устройствах. Вместо этого используйте определенные пресеты, такие как AVCaptureSessionPreset1280x720 .

    Если скорость сканирования важна, вы можете дополнительно снизить разрешение захвата изображения. Однако помните о требованиях к минимальному размеру штрих-кода, изложенных выше.

    Если вы пытаетесь распознать штрих-коды из последовательности кадров потокового видео, распознаватель может выдавать разные результаты от кадра к кадру. Вам следует подождать, пока вы не получите последовательную серию с одинаковым значением, чтобы быть уверенным, что вы возвращаете хороший результат.

    Цифра контрольной суммы не поддерживается для ITF и CODE-39.

  • Для обработки видеокадров используйте синхронный API results(in:) детектора. Вызовите этот метод из AVCaptureVideoDataOutputSampleBufferDelegate captureOutput(_, didOutput:from:) чтобы синхронно получить результаты из данного видеокадра. Сохраняйте AVCaptureVideoDataOutput alwaysDiscardsLateVideoFrames как true , чтобы ограничить вызовы детектора. Если новый видеокадр становится доступным во время работы детектора, он будет отброшен.
  • Если вы используете выходные данные детектора для наложения графики на входное изображение, сначала получите результат от ML Kit, а затем выполните визуализацию изображения и наложение за один шаг. Поступая таким образом, вы визуализируете на поверхность дисплея только один раз для каждого обработанного входного кадра. В качестве примера см. updatePreviewOverlayViewWithLastFrame в образце быстрого запуска ML Kit.