如何提取VNClassificationObservation对象颜色及静态图像中对应坐标位置
关于VNClassificationObservation的坐标与颜色值提取说明
首先明确:VNClassificationObservation 是全局图像分类请求的输出类,默认仅包含分类置信度、类别标识符两个核心属性,本身不携带目标区域坐标和图像颜色信息,你当前的代码只能实现打印Top2分类的置信度与类别,无法拿到你需要的坐标和颜色值,具体实现方法如下:
1. 如何获取分类对象对应的图像坐标
如果需要同时拿到类别和对应物体的边界框,你需要替换全局图像分类请求为目标检测类请求,使用VNRecognizedObjectObservation类,它自带boundingBox属性,返回的是归一化坐标(原点在图像左下角,值范围0~1),可以按以下方式转换为图像实际像素坐标:
// 示例:用目标检测请求同时获取类别和坐标 let request = VNRecognizeObjectsRequest { request, error in guard let results = request.results as? [VNRecognizedObjectObservation] else { return } let topResults = results.prefix(2) topResults.forEach { obj in // 拿到分类信息 guard let topClass = obj.labels.first else { return } print(String(format: " (%.2f) %@", topClass.confidence, topClass.identifier)) // 归一化坐标转实际图像坐标(imageSize为原始图像的实际尺寸) let imageSize: CGSize = UIImage(named: "你的原始图像")!.size let boundingBox = obj.boundingBox // 转换坐标系(从左下原点适配为UIKit通用的左上原点) let actualRect = VNImageRectForNormalizedRect(boundingBox, Int(imageSize.width), Int(imageSize.height)) .applying(CGAffineTransform(scaleX: 1, y: -1).translatedBy(x: 0, y: -imageSize.height)) print("对应区域坐标:\(actualRect)") } }
如果你确实需要用全局分类请求,可以先把图像按自定义规则裁剪为多个子块,分别对每个子块做分类,同时提前记录每个子块对应的原始图像坐标,就可以把分类结果和坐标关联起来。
2. 如何提取对应区域的颜色值
拿到边界框的实际像素坐标后,你可以从原始图像中裁剪出对应区域,再提取颜色,以下是提取区域平均色的示例:
// 从UIImage中裁剪指定区域并提取平均色 extension UIImage { func averageColor(in rect: CGRect) -> UIColor? { guard let cgImage = self.cgImage, let croppedImg = cgImage.cropping(to: rect) else { return nil } let ciImage = CIImage(cgImage: croppedImg) let filter = CIFilter(name: "CIAreaAverage", parameters: [ kCIInputImageKey: ciImage, kCIInputExtentKey: CIVector(cgRect: ciImage.extent) ]) guard let outputImage = filter?.outputImage else { return nil } var bitmap = [UInt8](repeating: 0, count: 4) let context = CIContext(options: [.workingColorSpace: kCFNull!]) context.render(outputImage, toBitmap: &bitmap, rowBytes: 4, bounds: CGRect(x: 0, y: 0, width: 1, height: 1), format: .RGBA8, colorSpace: nil) return UIColor(red: CGFloat(bitmap[0])/255, green: CGFloat(bitmap[1])/255, blue: CGFloat(bitmap[2])/255, alpha: CGFloat(bitmap[3])/255) } } // 调用示例 if let areaColor = yourOriginalImage.averageColor(in: actualRect) { print("区域平均色:\(areaColor)") }
如果需要提取区域内所有像素的颜色值,遍历裁剪后图像的像素位图即可。
内容的提问来源于stack exchange,提问作者Saad
相关产品推荐
相关产品推荐

