Google is committed to advancing racial equity for Black communities. See how.
Эта страница была переведа с помощью Cloud Translation API.
Switch to English

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

jinja

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

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

  1. Если вы еще не добавили Firebase в свое приложение, сделайте это, следуя инструкциям в руководстве по началу работы .
  2. Включите библиотеки ML Kit в ваш Podfile:
    pod 'Firebase/MLVision'
    pod 'Firebase/MLVisionBarcodeModel'
    
    После установки или обновления .xcworkspace вашего проекта обязательно откройте проект 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. Настройте детектор штрих-кода

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

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

стриж

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

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

  • Code128
  • Code39
  • Code93
  • CODABAR
  • EAN13
  • EAN8
  • ITF
  • UPCA
  • UPCE
  • QR код
  • PDF417
  • ацтекский
  • DataMatrix

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 в VisionBarcodeDetector 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 в примере приложения-витрины для примера.