iOS Vision:iPhone实时相机预览可绘制检测矩形,iPad异常求助
解决iPad上Vision框架矩形检测实时预览适配问题
问题现象
- iPhone端:使用iOS Vision框架实现相机实时矩形检测,实时预览中黄色矩形可准确追踪目标图形
- iPad端:X轴追踪准确,但Y轴始终偏移中心且缩放异常;仅实时预览存在问题,捕获1920×1080完整相机帧后绘制矩形显示正常
问题根源
iPhone屏幕为16:9,1920×1080原始帧可等比例缩放到预览层;iPad屏幕为4:3,全屏预览时原始帧被强制拉伸适配,导致坐标转换时Y轴比例错误。
适配方案
通过计算预览层中视频实际显示的有效区域(排除黑边),基于该区域做坐标转换,避免拉伸导致的误差:
修改后的坐标转换代码
let rect: VNRectangleObservation // Camera preview layer dimensions (full screen) let previewLayerBounds = self.previewLayer!.bounds let previewWidth = previewLayerBounds.width let previewHeight = previewLayerBounds.height // Raw camera frame dimensions (1920x1080) let frameWidth = self.frame!.width let frameHeight = self.frame!.height // 1. 计算原始帧和预览层的宽高比 let frameAspectRatio = frameWidth / frameHeight let previewAspectRatio = previewWidth / previewHeight // 2. 确定视频在预览层中的有效显示区域(无拉伸) var videoDisplayFrame: CGRect if previewAspectRatio > frameAspectRatio { // 预览层更宽,视频上下有黑边 let scaledHeight = previewWidth / frameAspectRatio let yOffset = (previewHeight - scaledHeight) / 2 videoDisplayFrame = CGRect(x: 0, y: yOffset, width: previewWidth, height: scaledHeight) } else { // 预览层更高,视频左右有黑边 let scaledWidth = previewHeight * frameAspectRatio let xOffset = (previewWidth - scaledWidth) / 2 videoDisplayFrame = CGRect(x: xOffset, y: 0, width: scaledWidth, height: previewHeight) } // 3. 构建转换矩阵:先归一化坐标到有效区域,再转换坐标系 // 从Vision的归一化坐标(左下原点)转换到预览层有效区域的坐标 let scaleToVideoFrame = CGAffineTransform(scaleX: videoDisplayFrame.width, y: videoDisplayFrame.height) // 翻转Y轴并偏移到预览层的实际位置 let transformToPreview = CGAffineTransform(scaleX: 1, y: -1) .translatedBy(x: videoDisplayFrame.origin.x, y: -(videoDisplayFrame.origin.y + videoDisplayFrame.height)) // 应用变换得到最终绘制的矩形 var bounds: CGRect = rect.boundingBox.applying(scaleToVideoFrame).applying(transformToPreview)
代码说明
- 先计算视频在全屏预览层中的无拉伸显示区域,确保坐标基于实际显示的视频画面
- 转换时先将Vision的归一化坐标缩放到有效视频区域,再调整坐标系到SwiftUI的左上原点,同时偏移到有效区域的位置
内容的提问来源于stack exchange,提问作者lepapillon
相关产品推荐
相关产品推荐

