我一直在对苹果在WWDC2017年推出的新Vision框架进行测试。我正在专门研究条形码检测 - 我已经能够从相机/图库扫描图像后获得它是否是条形码图像。但是,在查看条形码描述符时,我看不到实际的条形码值或有效负载数据。https://developer.apple.com/documentation/coreimage/cibarcodedescriptor 页面上似乎没有公开任何内容来标识任何属性。
我收到这些错误:
- 无法连接到远程服务:错误域=NSCocoaErrorDomain Code=4097"连接到名为 com.apple.BarcodeSupport.BarcodeNotificationService 的服务
">- libMobileGestalt MobileGestalt.c:555:无法访问InverseDeviceID(请参阅问题/11744455>)
- 连接到名为 com.apple.条形码支持.条形码通知服务错误域=NSCocoa错误
域代码=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")
}
}
}
}
显然,在iOS 11 beta 5中,Apple引入了新的payloadStringValue属性VNBarcodeObservation
。现在您可以毫无问题地从QR码中读取信息
if let payload = barcodeObservation.payloadStringValue {
print("payload is (payload)")
}
如果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 */)
如果您想直接从 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
})