如何识别黑底黑点式二维码?已尝试Vision+AVFoundation未解决
黑底黑点二维码识别解决方案建议
需求描述
识别黑底黑点样式的二维码(二维码为黑色点状图案,背景为黑色)。
已尝试方案
使用Vision Framework结合AVFoundation进行扫描,同时调整ISO参数,但均未成功识别。
可行解决方案建议
1. 修复核心逻辑错误
现有代码存在关键问题:仅对预览画面应用了滤镜,但二维码识别仍使用原始低对比度的像素缓冲区,这直接导致识别失败。必须将预处理后的图像传给Vision进行识别。
2. 针对性图像预处理
黑底黑点二维码的核心问题是对比度极低,Vision默认依赖清晰的明暗边界识别二维码。需要通过以下步骤强化边界:
- 图像反转:将黑底黑点转换为白底灰点,放大明暗差异
- 对比度增强:进一步拉大二维码与背景的灰度差
- 阈值化处理:将灰度差异转化为明确的黑白边界
3. 可选替代方案
如果Vision Framework经过预处理后仍识别困难,可以尝试使用ZXingObjC库,它对低对比度、非标准样式的二维码兼容性更好,支持自定义图像预处理逻辑。
修改后的代码示例
import Foundation import UIKit import AVFoundation import Vision class QRScannerVC: UIViewController, AVCaptureVideoDataOutputSampleBufferDelegate { var captureSession: AVCaptureSession! var previewLayer: AVCaptureVideoPreviewLayer! let invertFilter = CIFilter(name: "CIColorInvert") let contrastFilter = CIFilter(name: "CIColorControls") let thresholdFilter = CIFilter(name: "CIColorThreshold") override func viewDidLoad() { super.viewDidLoad() captureSession = AVCaptureSession() captureSession.sessionPreset = .high // 提高分辨率助力识别 guard let videoCaptureDevice = AVCaptureDevice.default(for: .video) else { return } let videoInput: AVCaptureDeviceInput do { videoInput = try AVCaptureDeviceInput(device: videoCaptureDevice) // 调整摄像头参数,优化进光量 try videoCaptureDevice.lockForConfiguration() videoCaptureDevice.isAutoExposureEnabled = true videoCaptureDevice.isAutoWhiteBalanceEnabled = true videoCaptureDevice.unlockForConfiguration() } catch { return } if captureSession.canAddInput(videoInput) { captureSession.addInput(videoInput) } else { return } let videoOutput = AVCaptureVideoDataOutput() videoOutput.setSampleBufferDelegate(self, queue: DispatchQueue(label: "videoQueue")) captureSession.addOutput(videoOutput) videoOutput.connection(with: .video)?.videoOrientation = .portrait previewLayer = AVCaptureVideoPreviewLayer(session: captureSession) previewLayer.frame = view.layer.bounds previewLayer.videoGravity = .resizeAspectFill view.layer.addSublayer(previewLayer) captureSession.startRunning() // 配置完成后再启动会话,避免异常 } func captureOutput(_ output: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer, from connection: AVCaptureConnection) { guard let pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer) else { return } // 应用预处理滤镜 guard let processedPixelBuffer = applyPreprocessing(to: pixelBuffer) else { return } // 更新预览画面 let previewImage = CIImage(cvPixelBuffer: processedPixelBuffer) if let previewCGImage = CIContext().createCGImage(previewImage, from: previewImage.extent) { DispatchQueue.main.async { self.previewLayer.contents = previewCGImage } } // 使用预处理后的图像进行识别 let imageRequestHandler = VNImageRequestHandler(cvPixelBuffer: processedPixelBuffer, orientation: .up, options: [:]) do { try imageRequestHandler.perform([detectQRCodeRequest]) } catch { print(error) } } lazy var detectQRCodeRequest: VNDetectBarcodesRequest = { let request = VNDetectBarcodesRequest(completionHandler: { [weak self] request, error in guard let results = request.results as? [VNBarcodeObservation], let result = results.first, let payload = result.payloadStringValue else { return } DispatchQueue.main.async { let alert = UIAlertController(title: "识别成功", message: payload, preferredStyle: .alert) alert.addAction(UIAlertAction(title: "确定", style: .default)) self?.present(alert, animated: true) } }) request.symbologies = [.qr] // 仅保留QR码识别,提升效率 return request }() func applyPreprocessing(to pixelBuffer: CVPixelBuffer) -> CVPixelBuffer? { let inputImage = CIImage(cvPixelBuffer: pixelBuffer) // 1. 反转图像:黑底变白底,黑点变灰点 invertFilter?.setValue(inputImage, forKey: kCIInputImageKey) guard let invertedImage = invertFilter?.outputImage else { return nil } // 2. 增强对比度:拉大灰度差异 contrastFilter?.setValue(invertedImage, forKey: kCIInputImageKey) contrastFilter?.setValue(3.0, forKey: kCIInputContrastKey) // 对比度可根据实际场景调整 guard let contrastImage = contrastFilter?.outputImage else { return nil } // 3. 阈值化:将灰点转为白点,形成明确黑白边界 thresholdFilter?.setValue(contrastImage, forKey: kCIInputImageKey) thresholdFilter?.setValue(0.6, forKey: kCIInputThresholdKey) // 阈值可根据实际场景调整 guard let outputImage = thresholdFilter?.outputImage else { return nil } // 渲染处理后的图像到新的像素缓冲区 var outputPixelBuffer: CVPixelBuffer? let attributes = [ kCVPixelBufferCGImageCompatibilityKey: true, kCVPixelBufferCGBitmapContextCompatibilityKey: true ] as CFDictionary CVPixelBufferCreate(nil, Int(outputImage.extent.width), Int(outputImage.extent.height), kCVPixelFormatType_32BGRA, attributes, &outputPixelBuffer) guard let buffer = outputPixelBuffer else { return nil } CIContext().render(outputImage, to: buffer) return buffer } }
示例二维码样式



内容的提问来源于stack exchange,提问作者Bhautik R
相关产品推荐
相关产品推荐

