iOS Vision框架矩形检测结果不准确 识别框与真实矩形不匹配求助
问题修复方案
核心问题1:矩形检测参数配置错误
当前设置的宽高比检测范围为1.3~1.6,是适配长方形信用卡检测的参数,和你需要检测的正方形特征不匹配,导致Vision框架主动过滤了正方形的检测结果,返回符合设置宽高比的错误结果。
核心问题2:坐标转换未适配预览层缩放规则
预览层videoGravity设置为.resizeAspectFill后,相机原始帧比例和屏幕预览比例不一致,直接用预览层宽高做坐标缩放会导致绘制的框出现尺寸、位置偏差。
核心问题3:图像检测未传入正确方向参数
初始化VNImageRequestHandler时未指定图像方向,Vision框架基于默认方向检测也会导致坐标结果偏差。
修改后的代码
1. 调整矩形检测参数与图像方向配置
private func detectRectangle(in image: CVPixelBuffer) { let request = VNDetectRectanglesRequest(completionHandler: { (request: VNRequest, error: Error?) in DispatchQueue.main.async { guard let results = request.results as? [VNRectangleObservation], let rect = results.first else { self.maskLayer.removeFromSuperlayer() return } self.drawBoundingBox(rect: rect, image: image) } }) // 适配正方形检测,宽高比范围调整为0.9~1.1,可根据实际需求调整容差 request.minimumAspectRatio = VNAspectRatio(0.9) request.maximumAspectRatio = VNAspectRatio(1.1) request.minimumSize = Float(0.5) request.maximumObservations = 1 // 传入和相机输出匹配的图像方向参数 let imageRequestHandler = VNImageRequestHandler(cvPixelBuffer: image, orientation: .right, options: [:]) try? imageRequestHandler.perform([request]) }
2. 调整坐标转换逻辑适配预览层缩放
func drawBoundingBox(rect : VNRectangleObservation, image: CVPixelBuffer) { // 计算原始图像和预览层的缩放比例与偏移量 let imageSize = CVImageBufferGetEncodedSize(image) let previewSize = previewLayer.bounds.size let imageAspect = imageSize.width / imageSize.height let previewAspect = previewSize.width / previewSize.height var scale: CGFloat var xOffset: CGFloat = 0 var yOffset: CGFloat = 0 if imageAspect > previewAspect { scale = previewSize.height / imageSize.height xOffset = (previewSize.width - imageSize.width * scale) / 2 } else { scale = previewSize.width / imageSize.width yOffset = (previewSize.height - imageSize.height * scale) / 2 } // 修正坐标转换逻辑 let transform = CGAffineTransform(scaleX: scale, y: -scale) .translatedBy(x: xOffset/scale, y: -(previewSize.height/scale + yOffset/scale)) let path = UIBezierPath() path.move(to: rect.bottomLeft) path.addLine(to: rect.bottomRight) path.addLine(to: rect.topRight) path.addLine(to: rect.topLeft) path.close() path.apply(transform) maskLayer.removeFromSuperlayer() maskLayer = CAShapeLayer() maskLayer.fillColor = UIColor.clear.cgColor maskLayer.lineWidth = 5 maskLayer.strokeColor = UIColor.red.cgColor maskLayer.path = path.cgPath previewLayer.insertSublayer(maskLayer, at: 1) }
内容的提问来源于stack exchange,提问作者sergii.tsyban
相关产品推荐
相关产品推荐

