【问题标题】:Vision Framework Barcode detection for iOS 11适用于 iOS 11 的 Vision Framework 条码检测
【发布时间】:2018-05-04 06:53:16
【问题描述】:

我一直在对 Apple 在 WWDC2017 中引入的新 Vision 框架进行测试。我正在专门研究条形码检测 - 在从相机/画廊扫描图像后,我能够得到它是否是条形码图像。但是,在查看barcodeDescriptor 时,我看不到实际的条形码值或有效负载数据。 https://developer.apple.com/documentation/coreimage/cibarcodedescriptor 页面上似乎没有任何内容可以识别任何属性。

我收到以下错误:

  • 无法连接到远程服务:错误域 = NSCocoaErrorDomain 代码 = 4097“连接到命名服务
    com.apple.BarcodeSupport.BarcodeNotificationService"
  • libMobileGestalt MobileGestalt.c:555:无法访问 InverseDeviceID(参见问题/11744455>)
  • 连接到名为 com.apple.BarcodeSupport.BarcodeNotificationService 的服务错误
    域=NSCocoaErrorDomain 代码=4097

有没有办法从 VNBarcodeObservation 访问条形码值? 任何帮助将不胜感激。谢谢! 这是我正在使用的代码:

@IBAction func chooseImage(_ sender: Any) {
        imagePicker.allowsEditing = true
        imagePicker.sourceType = .photoLibrary

        present(imagePicker, animated: true, completion: nil)
    }

    @IBAction func takePicture(_ sender: Any) {
        if(UIImagePickerController .isSourceTypeAvailable(UIImagePickerControllerSourceType.camera)){
            imagePicker.sourceType = UIImagePickerControllerSourceType.camera
            self .present(imagePicker, animated: true, completion: nil)
        }
        else{
            let alert = UIAlertController(title: "Warning", message: "Camera not available", preferredStyle: UIAlertControllerStyle.alert)
            alert.addAction(UIAlertAction(title: "Dismiss", style: UIAlertActionStyle.default, handler: nil))
            self.present(alert, animated: true, completion: nil)
        }
    }

    //PickerView Delegate Methods

    func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {

        imagePicker .dismiss(animated: true, completion: nil)
        classificationLabel.text = "Analyzing Image…"

        guard let pickedImage = info[UIImagePickerControllerOriginalImage] as? UIImage
            else { fatalError("no image from image picker") }
        guard let ciImage = CIImage(image: pickedImage)
            else { fatalError("can't create CIImage from UIImage") }

        imageView.image = pickedImage
        inputImage = ciImage

        // Run the rectangle detector, which upon completion runs the ML classifier.
        let handler = VNImageRequestHandler(ciImage: ciImage, options: [.properties : ""])
        DispatchQueue.global(qos: .userInteractive).async {
            do {
                try handler.perform([self.barcodeRequest])
            } catch {
                print(error)
            }
        }
    }

    func imagePickerControllerDidCancel(_ picker: UIImagePickerController){
        picker .dismiss(animated: true, completion: nil)
        print("picker cancel.")
    }

    lazy var barcodeRequest: VNDetectBarcodesRequest = {
        return VNDetectBarcodesRequest(completionHandler: self.handleBarcodes)
    }()

    func handleBarcodes(request: VNRequest, error: Error?) {
        guard let observations = request.results as? [VNBarcodeObservation]
            else { fatalError("unexpected result type from VNBarcodeRequest") }
        guard observations.first != nil else {
            DispatchQueue.main.async {
                self.classificationLabel.text = "No Barcode detected."
            }
            return
        }

        // Loop through the found results
        for result in request.results! {

            // Cast the result to a barcode-observation
            if let barcode = result as? VNBarcodeObservation {

                // Print barcode-values
                print("Symbology: \(barcode.symbology.rawValue)")

                if let desc = barcode.barcodeDescriptor as? CIQRCodeDescriptor {
                    let content = String(data: desc.errorCorrectedPayload, encoding: .utf8)

                    // FIXME: This currently returns nil. I did not find any docs on how to encode the data properly so far.
                    print("Payload: \(String(describing: content))\n")
                    print("Error-Correction-Level: \(desc.errorCorrectedPayload)\n")
                    print("Symbol-Version: \(desc.symbolVersion)\n")
                }
            }
        }
    }

【问题讨论】:

  • 在 35 分钟查看Session #510 - Advances in Core Image: Filters, Metal, Vision, and More - WWDC 2017,他们开始谈论 CIBarcodeDescriptor 和 errorCorrectedPayload。遗憾的是,我也无法读取有效负载中的消息。
  • 是的,我可以通过在“编辑方案”-> 运行-> 参数中将“OS_ACTIVITY_MODE”添加为禁用来修复这些错误,但我无法从有效负载中提取数据。我可以扫描条形码,然后用它制作视频中显示的图像,但我仍然坚持从数据类型中提取信息字符串。
  • 我已将您的代码用作我自己测试的基础,并且我有 一些 运气(iOS 11 beta 3),但结果令人费解。 errorCorrectedPayload 包含有时可读的数据。 stackoverflow.com/questions/45037418/…
  • Apple 支持团队更新:Engineering has determined that this issue behaves as intended based on the following information: You’ll need to write your own parser.

标签: barcode ios11 xcode9-beta swift4 apple-vision


【解决方案1】:

显然,在 iOS 11 beta 5 中,Apple 引入了 VNBarcodeObservation 的新 payloadStringValue 属性。现在您可以毫无问题地从二维码读取信息

if let payload = barcodeObservation.payloadStringValue {
    print("payload is \(payload)")
}

【讨论】:

    【解决方案2】:

    如果 Apple 不为此提供库,则可以使用以下方法:

    extension CIQRCodeDescriptor {
        var bytes: Data? {
            return errorCorrectedPayload.withUnsafeBytes { (pointer: UnsafePointer<UInt8>) in
                var cursor = pointer
    
                let representation = (cursor.pointee >> 4) & 0x0f
                guard representation == 4 /* byte encoding */ else { return nil }
    
                var count = (cursor.pointee << 4) & 0xf0
                cursor = cursor.successor()
                count |= (cursor.pointee >> 4) & 0x0f
    
                var out = Data(count: Int(count))
                guard count > 0 else { return out }
    
                var prev = (cursor.pointee << 4) & 0xf0
                for i in 2...errorCorrectedPayload.count {
                    if (i - 2) == count { break }
    
                    let cursor = pointer.advanced(by: Int(i))
                    let byte = cursor.pointee
                    let current = prev | ((byte >> 4) & 0x0f)
                    out[i - 2] = current
                    prev = (cursor.pointee << 4) & 0xf0
                }
                return out
            }
        }
    }
    

    然后

    String(data: descriptor.bytes!, encoding: .utf8 /* or whatever */)
    

    【讨论】:

    • 你能解释/链接representation变量的保护吗?我正在尝试解析CIQRCodeDescriptor,而representation 的值(即2)导致我的descriptor.bytes 为零。
    • 您的表示是“字母数字”,因此您需要不同的算法。 thonky.com/qr-code-tutorial/alphanumeric-mode-encoding
    【解决方案3】:

    如果您想直接从 VNBarcodeObservation 获取原始数据,而不必符合某些字符串编码,您可以像这样去除前 2 和 1/2 字节,并获取没有 QR 码标头的实际数据。

                guard let barcode = barcodeObservation.barcodeDescriptor as? CIQRCodeDescriptor else { return }
                let errorCorrectedPayload = barcode.errorCorrectedPayload
                let payloadData = Data(bytes: zip(errorCorrectedPayload.advanced(by: 2),
                                                  errorCorrectedPayload.advanced(by: 3)).map { (byte1, byte2) in
                    return byte1 << 4 | byte2 >> 4
                })
    

    【讨论】:

      猜你喜欢
      • 2020-06-19
      • 2018-06-08
      • 2016-01-15
      • 2017-06-30
      • 2018-01-26
      • 2020-02-05
      • 2021-10-21
      • 1970-01-01
      • 2016-02-22
      相关资源
      最近更新 更多