콘솔로 이동

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

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

이 API의 사용 예는 GitHub의 ML Kit 빠른 시작 샘플을 참조하세요.

시작하기 전에

  1. 앱에 Firebase를 아직 추가하지 않은 경우 시작 가이드의 단계에 따라 추가합니다.
  2. Podfile에 ML Kit 라이브러리를 포함합니다.
    pod 'Firebase/Analytics'
    pod 'Firebase/MLVision'
    pod 'Firebase/MLVisionBarcodeModel'
    
    프로젝트의 포드를 설치하거나 업데이트한 후 .xcworkspace를 사용하여 Xcode 프로젝트를 열어야 합니다.
  3. 앱에서 Firebase를 가져옵니다.

    Swift

    import Firebase

    Objective-C

    @import Firebase;

입력 이미지 가이드라인

  • 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 코드는 한 행에 가로 17단위 '단어'를 34개까지 사용할 수 있으므로 가로 1156 픽셀 이상이어야 합니다.

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

  • 실시간 애플리케이션에서 바코드를 스캔하는 경우 입력 이미지의 전체 크기를 고려해야 할 수도 있습니다. 이미지 크기가 작을수록 더 빠르게 처리될 수 있으므로 지연 시간을 줄이려면 위의 정확도 요구사항에 유의하여 낮은 해상도에서 이미지를 캡처하고 바코드가 가능한 많은 이미지를 차지하도록 합니다. 또한 실시간 성능 향상을 위한 팁도 참조하세요.

1. 바코드 감지기 구성

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

예를 들어 Aztec 코드와 QR 코드만 인식하려면 다음 예시와 같이 VisionBarcodeDetectorOptions 객체를 빌드합니다.

Swift

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

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

  • Code128
  • Code39
  • Code93
  • CodaBar
  • EAN13
  • EAN8
  • ITF
  • UPC_A
  • UPCE
  • QRCode
  • PDF417
  • Aztec
  • DataMatrix

Objective-C

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

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

  • Code 128(FIRVisionBarcodeFormatCode128)
  • Code 39(FIRVisionBarcodeFormatCode39)
  • Code 93(FIRVisionBarcodeFormatCode93)
  • Codabar(FIRVisionBarcodeFormatCodaBar)
  • EAN-13(FIRVisionBarcodeFormatEAN13)
  • EAN-8(FIRVisionBarcodeFormatEAN8)
  • ITF(FIRVisionBarcodeFormatITF)
  • UPC-A(FIRVisionBarcodeFormatUPCA)
  • UPC-E(FIRVisionBarcodeFormatUPCE)
  • QR 코드(FIRVisionBarcodeFormatQRCode)
  • PDF417(FIRVisionBarcodeFormatPDF417)
  • Aztec(FIRVisionBarcodeFormatAztec)
  • Data Matrix(FIRVisionBarcodeFormatDataMatrix)

2. 바코드 감지기 실행

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

  1. VisionBarcodeDetector의 인스턴스를 가져옵니다.

    Swift

    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. UIImage 또는 CMSampleBufferRef를 사용하여 VisionImage 객체를 만듭니다.

    UIImage를 사용하는 방법은 다음과 같습니다.

    1. 필요한 경우 imageOrientation 속성이 .up이 되도록 이미지를 회전합니다.
    2. 올바르게 회전된 UIImage를 사용하여 VisionImage 객체를 만듭니다. 회전 메타데이터를 지정하지 마세요. 기본값인 .topLeft를 사용해야 합니다.

      Swift

      let image = VisionImage(image: uiImage)

      Objective-C

      FIRVisionImage *image = [[FIRVisionImage alloc] initWithImage:uiImage];

    CMSampleBufferRef를 사용하는 방법은 다음과 같습니다.

    1. CMSampleBufferRef 버퍼에 포함된 이미지 데이터의 방향을 지정하는 VisionImageMetadata 객체를 만듭니다.

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

      Swift

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

      그런 다음 메타데이터 객체를 만듭니다.

      Swift

      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. CMSampleBufferRef 객체 및 회전 메타데이터를 사용하여 VisionImage 객체를 만듭니다.

      Swift

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

      Objective-C

      FIRVisionImage *image = [[FIRVisionImage alloc] initWithBuffer:sampleBuffer];
      image.metadata = metadata;
  3. 그런 다음 이미지를 detect(in:) 메소드에 전달합니다.

    Swift

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

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

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

실시간 성능 향상을 위한 팁

실시간 애플리케이션에서 바코드를 스캔하려는 경우 최상의 프레임 속도를 얻으려면 다음 안내를 따르세요.

  • 감지기 호출을 제한합니다. 얼굴 감지기가 실행 중일 때 새 동영상 프레임을 사용할 수 있게 되면 프레임을 낮춥니다.
  • 낮은 해상도로 이미지를 캡처하는 것도 고려해 보세요. 단, 이 API의 이미지 크기 요구사항도 유의해야 합니다.