Skanowanie kodów kreskowych za pomocą ML Kit na iOS

Do rozpoznawania i dekodowania kodów kreskowych możesz używać pakietu ML Kit.

Wypróbuj

Zanim zaczniesz

  1. W pliku Podfile umieść te pody ML Kit:
    pod 'GoogleMLKit/BarcodeScanning', '3.2.0'
    
  2. Po zainstalowaniu lub zaktualizowaniu podów projektu otwórz projekt Xcode za pomocą .xcworkspace ML Kit jest obsługiwany w Xcode w wersji 12.4 lub nowszej.

Wytyczne dotyczące obrazu wejściowego

  • Aby ML Kit mógł dokładnie odczytywać kody kreskowe, obrazy wejściowe muszą zawierać również kody kreskowe, które są reprezentowane przez wystarczającą ilość danych pikseli.

    Konkretne wymagania dotyczące danych pikseli zależą od typu i ilości zakodowanych w nim danych, ponieważ wiele kodów kreskowych obsługują ładunek o zmiennym rozmiarze. Ogólnie rzecz biorąc, najmniej istotne musi mieć co najmniej 2 piksele szerokości, a w przypadku Dwuwymiarowe kody o wysokości 2 pikseli.

    Na przykład kody kreskowe EAN-13 składają się z kresek i spacji oznaczonych znakiem 1, 2, 3 lub 4 jednostki szerokości, więc na obrazie z kodem kreskowym EAN-13 powinny być słupki i o szerokości co najmniej 2, 4, 6 lub 8 pikseli. Ponieważ kod EAN-13 Kod kreskowy ma łącznie 95 jednostek szerokości, a kod kreskowy powinien mieć co najmniej 190 jednostek. pikseli szerokości ekranu.

    Formaty o większej gęstości, np. PDF417, wymagają większych wymiarów w pikselach ML Kit. Na przykład kod PDF417 może mieć maksymalnie 34 „słowa” o szerokości 17 jednostek w jednym wierszu, czyli przynajmniej 1156 pikseli szerokości.

  • Słaba ostrość obrazu może mieć wpływ na dokładność skanowania. Jeśli aplikacja nie otrzymuje akceptowalne, poproś użytkownika o ponowne przechwycenie obrazu.

  • W typowych zastosowaniach zaleca się podanie wyższej wartości obrazu o rozdzielczości, np. 1280 x 720 lub 1920 x 1080, który tworzy kody kreskowe i można je zeskanować z większej odległości od aparatu.

    Jednak w aplikacjach, w których opóźnienia są kluczowe, można poprawić dzięki możliwości robienia zdjęć w niższej rozdzielczości, ale wymagając kod kreskowy stanowi większość zdjęcia wejściowego. Zobacz też Wskazówki, jak zwiększyć skuteczność w czasie rzeczywistym.

1. Konfigurowanie skanera kodów kreskowych

Wiedząc, jakie formaty kodu kreskowego spodziewasz się odczytać, możesz zwiększyć szybkość skanera kodów paskowych przez skonfigurowanie w nim skanowania tylko tych formatów.

Aby np. zeskanować tylko kod Aztec i kody QR, utwórz BarcodeScannerOptions, taki jak następujący przykład:

Swift

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

Obsługiwane formaty:

  • code128
  • code39
  • code93
  • codaBar
  • dataMatrix
  • EAN13
  • EAN8
  • ITF
  • qrCode
  • UPCA
  • UPCE
  • PDF417
  • Aztec

Objective-C

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

Obsługiwane formaty:

  • Kod-128 (MLKBarcodeFormatCode128)
  • Kod-39 (MLKBarcodeFormatCode39)
  • Kod-93 (MLKBarcodeFormatCode93)
  • Codabar (MLKBarcodeFormatCodaBar)
  • Macierz danych (MLKBarcodeFormatDataMatrix)
  • EAN-13 (MLKBarcodeFormatEAN13)
  • EAN-8 (MLKBarcodeFormatEAN8)
  • ITF (MLKBarcodeFormatITF)
  • Kod QR (MLKBarcodeFormatQRCode)
  • UPC-A (MLKBarcodeFormatUPCA)
  • UPC-E (MLKBarcodeFormatUPCE)
  • PDF-417 (MLKBarcodeFormatPDF417)
  • Kod Aztecki (MLKBarcodeFormatAztec)

2. Przygotowywanie obrazu wejściowego

Aby skanować kody kreskowe na obrazie, przekaż go w formacie UIImage lub CMSampleBufferRef na: process() lub results(in:) BarcodeScanner :

Utwórz obiekt VisionImage za pomocą UIImage lub CMSampleBuffer.

Jeśli używasz UIImage, wykonaj te czynności:

  • Utwórz obiekt VisionImage za pomocą UIImage. Pamiętaj, by określić prawidłowy .orientation.

    Swift

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

    Objective-C

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

Jeśli używasz CMSampleBuffer, wykonaj te czynności:

  • Określ orientację danych zdjęć zawartych w pliku CMSampleBuffer

    Aby sprawdzić orientację obrazu:

    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;
      }
    }
          
  • Utwórz obiekt VisionImage za pomocą CMSampleBuffer obiekt i orientacja:

    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. Pobieranie instancji BarcodeScanner

Pobierz instancję 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. Przetwarzanie zdjęcia

Następnie przekaż obraz do metody 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. Uzyskiwanie informacji z kodów kreskowych

Jeśli skanowanie kodu się powiedzie, skaner zwróci tablicę Barcode obiektów. Każdy obiekt Barcode reprezentuje kodu kreskowego wykrytego na zdjęciu. Dla każdego kodu kreskowego można sprawdzić jego wartość współrzędnych ograniczających w obrazie wejściowym, jak i nieprzetworzonych danych zakodowanych przez kodu kreskowego. Ponadto, jeśli skaner kodów kreskowych był w stanie określić typ danych zakodowanym kodem kreskowym, otrzymasz obiekt zawierający przeanalizowane dane.

Na przykład:

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

Wskazówki dotyczące poprawy skuteczności w czasie rzeczywistym

Jeśli chcesz skanować kody kreskowe za pomocą aplikacji działającej w czasie rzeczywistym, postępuj zgodnie z tymi wytycznych dotyczących uzyskiwania najlepszej liczby klatek na sekundę:

  • Nie rejestruj danych wejściowych w rozdzielczości natywnej kamery. Na niektórych urządzeniach przechwytywanie danych wejściowych w rozdzielczości natywnej zapewnia bardzo duże w megapikselach), co skutkuje bardzo małym opóźnieniem bez dokładności. Zamiast tego wysyłaj z aparatu tylko ten rozmiar, który jest wymagany dla skanowania kodów kreskowych, które mają zwykle nie więcej niż 2 megapiksele.

    Gotowe ustawienia sesji nagrywania nazwanych: AVCaptureSessionPresetDefault, AVCaptureSessionPresetLow, AVCaptureSessionPresetMedium itp.) — nie są jednak zalecane, ponieważ mogą odpowiadać w nieodpowiednich rozdzielczościach na niektórych urządzeniach. Zamiast tego użyj określonych gotowych ustawień, na przykład AVCaptureSessionPreset1280x720.

    Jeśli szybkość skanowania jest ważna, możesz zmniejszyć zakres skanowania i ich rozwiązania. Należy jednak pamiętać o minimalnym rozmiarze kodu kreskowego. opisane powyżej.

    Jeśli próbujesz rozpoznać kody kreskowe z sekwencji transmisji, klatek wideo, moduł rozpoznawania może generować różne wyniki ramki. Zaczekaj, aż otrzymasz kolejną serię daje Ci pewność, że zwracasz dobry wynik.

    Cyfra kontrolna nie jest obsługiwana w przypadku ITF i CODE-39.

  • Do przetwarzania klatek wideo używaj synchronicznego interfejsu API results(in:) detektora. Zadzwoń do nas tę metodę z AVCaptureVideoDataOutputSampleBufferDelegate . captureOutput(_, didOutput:from:), aby synchronicznie pobierać wyniki dotyczące danego filmu ramki. Zachowaj AVCaptureVideoDataOutput: alwaysDiscardsLateVideoFrames jako true, aby ograniczyć wywołania detektora. Jeśli nowy gdy klatka wideo jest dostępna, gdy jest uruchomiony detektor, zostanie usunięta.
  • Jeśli użyjesz danych wyjściowych detektora do nakładania grafiki na obrazu wejściowego, najpierw pobierz wynik z ML Kit, a następnie wyrenderuj obraz i nakładanie nakładek w jednym kroku. W ten sposób renderowanie na powierzchni tylko raz na każdą przetworzoną ramkę wejściową. Zobacz updatePreviewOverlayViewWithLastFrame. znajdziesz na przykład w krótkim wprowadzeniu do korzystania z ML Kit.