VNBarcodeObservation的结果中observation.boundingBox 是什么类型?

大家好,我的开源项目PakePlus可以将网页/Vue/React项目打包为桌面/手机应用并且小于5M只需几分钟,官网地址:pakeplus.com

observation.boundingBox 的类型是 CGRect

CGRect 结构

CGRect 是 Core Graphics 框架中的结构体,表示一个矩形区域:

swift 复制代码
public struct CGRect {
    public var origin: CGPoint
    public var size: CGSize
}

在 Vision 框架中的特性

在 Vision 框架中,boundingBox 使用归一化坐标系统

Swift 复制代码
let barcodeRequest = VNDetectBarcodesRequest { request, error in
    guard let results = request.results as? [VNBarcodeObservation] else { return }
    
    for observation in results {
        let boundingBox: CGRect = observation.boundingBox
        print("boundingBox: \(boundingBox)")
        
        // 访问具体属性
        print("原点: \(boundingBox.origin)")      // CGPoint
        print("尺寸: \(boundingBox.size)")        // CGSize
        print("x: \(boundingBox.origin.x)")      // CGFloat
        print("y: \(boundingBox.origin.y)")      // CGFloat
        print("宽度: \(boundingBox.size.width)")   // CGFloat
        print("高度: \(boundingBox.size.height)")  // CGFloat
        
        // 其他便捷属性
        print("最小X: \(boundingBox.minX)")
        print("最小Y: \(boundingBox.minY)")
        print("最大X: \(boundingBox.maxX)")
        print("最大Y: \(boundingBox.maxY)")
        print("中心X: \(boundingBox.midX)")
        print("中心Y: \(boundingBox.midY)")
    }
}

归一化坐标系统

Vision 框架的 boundingBox 使用归一化坐标:

  • 坐标范围: (0.0, 0.0) 到 (1.0, 1.0)

  • 原点: 左下角 (与 UIKit 的左上角不同!)

  • x: 从左到右 (0.0 = 左边缘, 1.0 = 右边缘)

  • y: 从下到上 (0.0 = 下边缘, 1.0 = 上边缘)

Swift 复制代码
// 示例 boundingBox 值
let exampleBox = CGRect(x: 0.2, y: 0.3, width: 0.4, height: 0.3)
// 表示:
// - 从图像左边 20% 的位置开始
// - 从图像底部 30% 的位置开始  
// - 宽度为图像的 40%
// - 高度为图像的 30%

坐标转换

由于归一化坐标和 UIKit 坐标系统不同,需要进行转换:

1. 转换为图像像素坐标

Swift 复制代码
func convertToImageCoordinates(boundingBox: CGRect, imageSize: CGSize) -> CGRect {
    // Vision → 图像坐标 (左下角原点)
    let imageRect = VNImageRectForNormalizedRect(
        boundingBox, 
        Int(imageSize.width), 
        Int(imageSize.height)
    )
    return imageRect
}

2. 转换为 UIKit 视图坐标

Swift 复制代码
func convertToViewCoordinates(boundingBox: CGRect, viewSize: CGSize) -> CGRect {
    // Vision → UIKit 坐标 (左上角原点)
    let viewRect = CGRect(
        x: boundingBox.origin.x * viewSize.width,
        y: (1 - boundingBox.origin.y - boundingBox.size.height) * viewSize.height,
        width: boundingBox.size.width * viewSize.width,
        height: boundingBox.size.height * viewSize.height
    )
    return viewRect
}

完整的使用示例

Swift 复制代码
import Vision
import UIKit

class BarcodeDetector {
    func processBarcodeObservation(_ observation: VNBarcodeObservation, 
                                 imageSize: CGSize, 
                                 targetView: UIView) {
        
        let boundingBox: CGRect = observation.boundingBox
        
        // 1. 打印原始 boundingBox
        print("原始 boundingBox: \(boundingBox)")
        
        // 2. 转换为图像坐标
        let imageRect = VNImageRectForNormalizedRect(
            boundingBox,
            Int(imageSize.width),
            Int(imageSize.height)
        )
        print("图像坐标: \(imageRect)")
        
        // 3. 转换为视图坐标 (用于在屏幕上绘制)
        let viewRect = convertToViewRect(boundingBox: boundingBox, 
                                       viewSize: targetView.bounds.size)
        print("视图坐标: \(viewRect)")
        
        // 4. 在界面上绘制边界框
        drawBoundingBox(on: targetView, rect: viewRect)
    }
    
    private func convertToViewRect(boundingBox: CGRect, viewSize: CGSize) -> CGRect {
        return CGRect(
            x: boundingBox.origin.x * viewSize.width,
            y: (1 - boundingBox.origin.y - boundingBox.size.height) * viewSize.height,
            width: boundingBox.size.width * viewSize.width,
            height: boundingBox.size.height * viewSize.height
        )
    }
    
    private func drawBoundingBox(on view: UIView, rect: CGRect) {
        // 移除之前的边界框
        view.layer.sublayers?.removeAll(where: { $0.name == "boundingBox" })
        
        // 创建新的边界框图层
        let boxLayer = CAShapeLayer()
        boxLayer.name = "boundingBox"
        boxLayer.frame = rect
        boxLayer.borderColor = UIColor.green.cgColor
        boxLayer.borderWidth = 2.0
        boxLayer.backgroundColor = UIColor.clear.cgColor
        
        view.layer.addSublayer(boxLayer)
    }
}

重要注意事项

  1. 坐标系统差异: Vision 使用左下角原点,UIKit 使用左上角原点

  2. 归一化范围: 坐标值在 0.0-1.0 范围内

  3. 空矩形检查: 检查 boundingBox 是否有效

  4. 边界处理: 确保转换后的坐标在有效范围内

Swift 复制代码
// 检查 boundingBox 是否有效
if boundingBox.isNull || boundingBox.isInfinite {
    print("无效的 boundingBox")
    return
}

// 检查是否在有效范围内
if boundingBox.minX < 0 || boundingBox.maxX > 1 || 
   boundingBox.minY < 0 || boundingBox.maxY > 1 {
    print("boundingBox 超出有效范围")
}

总结:observation.boundingBoxCGRect 类型,使用归一化坐标系统表示检测对象在图像中的位置和大小,需要进行适当的坐标转换才能在 UIKit 界面中使用。
大家好,我是1024小神,技术群 / 私活群 / 股票群 或 交朋友 都可以私信我。 如果你觉得本文有用,一键三连 (点赞、评论、关注),就是对我最大的支持~

相关推荐
xun_xing2 小时前
Javascript的Iterator和Generator
前端·javascript
秃了才能变得更强2 小时前
React Native 新、旧架构集成原生模块方式
前端
1024小神2 小时前
swift中VNDetectBarcodesRequest VNImageRequestHandler 是什么?有什么作用?VN是什么意思
前端
加个鸡腿儿2 小时前
React项目实战 | 修复Table可展开行,点击一个全部展开
前端·react.js·编程语言
在泡泡里2 小时前
前端规范【五】biomejs自动化工具-ultracite
前端
_野猪佩奇_牛马版2 小时前
node/py实现 qwen多轮对话
前端
残冬醉离殇2 小时前
函数柯里化(curry)是什么?🤔
前端·javascript
1024小神2 小时前
在 Vision 框架中,request.results 是什么类型的数据
前端
亮子AI2 小时前
【CSS】cursor: auto, default, none 有什么区别?
前端·css