iOS에서 ML Kit를 사용하여 바코드 스캔

ML Kit를 사용하여 바코드를 인식하고 디코딩할 수 있습니다.

사용해 보기

  • 샘플 앱을 사용해 보고 이 API의 사용 예를 확인하세요.

시작하기 전에

  1. Podfile에 다음 ML Kit 포드를 포함합니다.
    pod 'GoogleMLKit/BarcodeScanning', '3.2.0'
    
  2. 프로젝트의 포드를 설치하거나 업데이트한 후 .xcworkspace를 사용하여 Xcode 프로젝트를 엽니다. ML Kit는 Xcode 버전 12.4 이상에서 지원됩니다.

입력 이미지 가이드라인

  • 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 코드는 한 행에 최대 34개의 17단위 너비 '단어'를 포함할 수 있으며 너비는 최소 1,156픽셀입니다.

  • 이미지 초점이 잘 맞지 않으면 스캔 정확도가 저하될 수 있습니다. 앱에서 허용되는 결과를 얻지 못하는 경우 사용자에게 이미지를 다시 캡처하도록 요청합니다.

  • 일반적인 애플리케이션의 경우 카메라에서 먼 거리에서 바코드를 스캔할 수 있도록 1280x720 또는 1920x1080과 같이 더 높은 해상도의 이미지를 제공하는 것이 좋습니다.

    하지만 지연 시간이 중요한 애플리케이션에서는 더 낮은 해상도로 이미지를 캡처하되 바코드가 입력 이미지의 대부분을 차지하도록 하여 성능을 개선할 수 있습니다. 실시간 성능 향상을 위한 팁도 참조하세요.

1. 바코드 스캐너 구성

읽으려는 바코드 형식을 알고 있는 경우 해당 형식만 스캔하도록 구성하여 바코드 스캐너의 속도를 높일 수 있습니다.

예를 들어 Aztec 코드와 QR 코드만 스캔하려면 다음 예와 같이 BarcodeScannerOptions 객체를 빌드합니다.

Swift

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

지원되는 형식은 다음과 같습니다.

  • 코드128
  • 코드39
  • 코드93
  • 코다바
  • dataMatrix
  • EAN13
  • EAN8
  • TFTF
  • qr코드
  • UPC
  • 위쪽
  • PDF417
  • Aztec

Objective-C

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

지원되는 형식은 다음과 같습니다.

  • Code-128 (MLKBarcodeFormatCode128)
  • Code-39 (MLKBarcodeFormatCode39)
  • Code-93 (MLKBarcodeFormatCode93)
  • Codabar (MLKBarcodeFormatCodaBar)
  • Data Matrix(MLKBarcodeFormatDataMatrix)
  • EAN-13 (MLKBarcodeFormatEAN13)
  • EAN-8(MLKBarcodeFormatEAN8)
  • ITF (MLKBarcodeFormatITF)
  • QR 코드(MLKBarcodeFormatQRCode)
  • UPC-A (MLKBarcodeFormatUPCA)
  • UPC-E(MLKBarcodeFormatUPCE)
  • PDF-417(MLKBarcodeFormatPDF417)
  • Aztec 코드(MLKBarcodeFormatAztec)

2. 입력 이미지 준비

이미지 속 바코드를 스캔하려면 이미지를 UIImage 또는 CMSampleBufferRefBarcodeScannerprocess() 또는 results(in:) 메서드에 전달합니다.

UIImage 또는 CMSampleBuffer를 사용하여 VisionImage 객체를 만듭니다.

UIImage를 사용하는 경우 다음 단계를 따르세요.

  • UIImage를 사용하여 VisionImage 객체를 만듭니다. 올바른 .orientation을 지정해야 합니다.

    Swift

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

    Objective-C

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

CMSampleBuffer를 사용하는 경우 다음 단계를 따르세요.

  • CMSampleBuffer에 포함된 이미지 데이터의 방향을 지정합니다.

    이미지 방향을 가져오는 방법은 다음과 같습니다.

    Swift

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

    Objective-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;
      }
    }
          
  • CMSampleBuffer 객체 및 방향을 사용하여 VisionImage 객체를 만듭니다.

    Swift

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

    Objective-C

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

3. BarcodeScanner의 인스턴스 가져오기

BarcodeScanner의 인스턴스를 가져옵니다.

Swift

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

Objective-C

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

4. 이미지 처리

그런 다음 이미지를 process() 메서드에 전달합니다.

Swift

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

Objective-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 객체는 이미지에서 감지된 바코드를 나타냅니다. 바코드별로 입력 이미지의 경계 좌표 및 바코드로 인코딩된 원시 데이터를 가져올 수 있습니다. 또한 바코드 스캐너가 바코드로 인코딩된 데이터 유형을 파악할 수 있는 경우 파싱된 데이터가 포함된 객체를 가져올 수 있습니다.

예를 들면 다음과 같습니다.

Swift

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 (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에는 체크섬 숫자가 지원되지 않습니다.

  • 동영상 프레임 처리에는 감지기의 results(in:) 동기 API를 사용합니다. AVCaptureVideoDataOutputSampleBufferDelegate captureOutput(_, didOutput:from:) 함수에서 이 메서드를 호출하여 지정된 동영상 프레임에서 동기식으로 결과를 가져옵니다. 감지기 호출을 제한하기 위해 AVCaptureVideoDataOutputalwaysDiscardsLateVideoFramestrue으로 유지합니다. 인식기가 실행 중일 때 새 동영상 프레임이 제공되는 경우 프레임이 삭제됩니다.
  • 인식기 출력을 사용하여 입력 이미지에 그래픽을 오버레이하는 경우 먼저 ML Kit에서 결과를 가져온 후 이미지를 렌더링하고 단일 단계로 오버레이합니다. 이렇게 하면 처리된 각 입력 프레임에 대해 한 번만 디스플레이 표면에 렌더링됩니다. 예시는 ML Kit 빠른 시작 샘플에서 updatePreviewOverlayViewWithLastFrame을 참조하세요.