在 Swift 中以浮点精度从 CMSampleBuffer 获取“CIAreaAverage”的 RGB 平均值

Posted

技术标签:

【中文标题】在 Swift 中以浮点精度从 CMSampleBuffer 获取“CIAreaAverage”的 RGB 平均值【英文标题】:Get RGB average of "CIAreaAverage" from CMSampleBuffer in Float precision in Swift 【发布时间】:2022-01-15 13:58:33 【问题描述】:

我正在尝试获取“AVCaptureVideoDataOutput”提要的平均 RGB 值。我在 *** 上找到了以下解决方案:

let pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer)
let cameraImage = CIImage(CVPixelBuffer: pixelBuffer!)
let filter = CIFilter(name: "CIAreaAverage")
filter!.setValue(cameraImage, forKey: kCIInputImageKey)
let outputImage = filter!.valueForKey(kCIOutputImageKey) as! CIImage!

let ctx = CIContext(options:nil)
let cgImage = ctx.createCGImage(outputImage, fromRect:outputImage.extent)

let rawData:NSData = CGDataProviderCopyData(CGImageGetDataProvider(cgImage))!
let pixels = UnsafePointer<UInt8>(rawData.bytes)
let bytes = UnsafeBufferPointer<UInt8>(start:pixels, count:rawData.length)
var BGRA_index = 0
for pixel in UnsafeBufferPointer(start: bytes.baseAddress, count: bytes.count) 
     switch BGRA_index 
         case 0:
              bluemean = CGFloat (pixel)
         case 1:
              greenmean = CGFloat (pixel)
         case 2:
              redmean = CGFloat (pixel)
         case 3:
              break
         default:
              break
     
     BGRA_index++

但这会产生 Int 的平均值,但我需要保持精度的浮点格式。在我正在使用的问题域中,舍入是相当有问题的。有没有一种方法可以有效地实现 Float 平均值?

非常感谢!

【问题讨论】:

因为像素是 8 位,所以最大值是 255。假设浮点值是从 0.0 到 1.0,计算应该是 CGFloat(pixel) / 255.0 是的,问题在于它将平均值输出为 8 位整数,因此它将浮点数舍入为整数...我想要 0-255 范围内的浮点平均值,无需转换到 8 位像素值 你指的是什么像素值转换?像素由 8 位值表示。相当标准的东西。 好吧,我希望在将其转换为 8 位整数之前获得平均像素值 - 所以它不会四舍五入,因为我需要在浮点精度级别上进行那些微小的更改。 【参考方案1】:

我可以推荐使用我们的库CoreImageExtensions 来读取值吗?我们添加了从CIImages 以不同格式读取像素值的方法。对于您的情况,它看起来像这样:

 import CoreImageExtensions

 let pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer)
 let cameraImage = CIImage(cvPixelBuffer: pixelBuffer!)
 let filter = CIFilter(name: "CIAreaAverage")!
 filter.setValue(cameraImage, forKey: kCIInputImageKey)
 filter.setValue(CIVector(cgRect: cameraImage.extent), forKey: kCIInputExtentKey)
 let outputImage = filter.outputImage!

 let context = CIContext()
 // get the value of a specific pixel as a `SIMD4<Float32>`
 let average = context.readFloat32PixelValue(from: outputImage, at: CGPoint.zero)

另外请记住,如果您想定期(不仅仅是一次)计算平均值,请只创建一个 CIContext 实例并将其用于每个相机帧。创建它的成本很高,而且它实际上会提高使用相同实例的性能,因为它会缓存内部资源。

【讨论】:

这太棒了!谢谢你分享这个。只是一个简单的问题,浮动值在 0-1 范围内。这些是根据浮点数中的实际像素平均值计算得出的,还是只是将每个颜色通道的 8 位输出除以 255?我进行了一些实验,似乎是前者,但想仔细检查! Core Image 实际上以默认为 16 位浮点的工作格式运行(不过,您可以在创建上下文时将其设置为选项)。因此,当加载图像时,它会在应用任何过滤器之前转换为工作格式。然后将 8 位 uchar 值 [0...255] 转换为 [0.0...1.0]。然后根据浮点值计算平均值(因此也更精确)。 知道了!非常感谢!

以上是关于在 Swift 中以浮点精度从 CMSampleBuffer 获取“CIAreaAverage”的 RGB 平均值的主要内容,如果未能解决你的问题,请参考以下文章

NSDecimalNumber 用于 Swift 中的货币精度 [重复]

如何在 PySpark 1.6 中将 DataFrame 列从字符串转换为浮点/双精度?

从浮点 lat long 创建的 CLLocation 显示更高的精度

OpenGL浮点精度

深入C语言中数据的存储

OC、swift数据JSON序列化后,浮点型数据丢失的问题