使用 vImage 计算 CVPixelBuffer 的直方图

问题描述 投票:0回答:1

我有来自相机的 YCbCr(422 或 420 双平面 10 位视频范围)中的 CVPixelBuffers。我发现 vImage 框架足够复杂,可以处理各种图像格式(包括各种 YCbCr 格式的像素缓冲区)。我正在计算 Y(亮度)和 RGB 的直方图。对于 8 位 YCbCr 样本,我可以使用此代码来计算 Y 分量的直方图。

            var alphaBin = [vImagePixelCount](repeating: 0, count: Int(numBins))

            CVPixelBufferLockBaseAddress(pixelBuffer, .readOnly)
            
            let bytesPerRow = CVPixelBufferGetBytesPerRowOfPlane(pixelBuffer, 0)
            let baseAddress = CVPixelBufferGetBaseAddressOfPlane(pixelBuffer, 0)
            let height = CVPixelBufferGetHeightOfPlane(pixelBuffer, 0)
            let width = CVPixelBufferGetWidthOfPlane(pixelBuffer, 0)
            
            CVPixelBufferUnlockBaseAddress(pixelBuffer, .readOnly)
            
            var buffer = vImage_Buffer(data: baseAddress, height: vImagePixelCount( height), width: vImagePixelCount(width), rowBytes: bytesPerRow)
            
            alphaBin.withUnsafeMutableBufferPointer { alphaPtr in
                let error = vImageHistogramCalculation_Planar8(&buffer, alphaPtr.baseAddress!, UInt32(kvImageNoFlags))
                
                guard error == kvImageNoError else {
                    fatalError("Error calculating histogram luma: \(error)")
                }
                
            }

如何对 10 位 HDR 像素缓冲区实现相同的功能,最好使用提供更多灵活性的新 iOS 16 vImage API(例如,从 YCbCr 样本获取 RGB 直方图,而无需显式执行像素格式转换)?

ios histogram accelerate-framework cvpixelbuffer vimage
1个回答
0
投票

正如您在 vImage/Histogram.h 中看到的,(当前)仅具有 1 通道和 4 通道 8 位和浮点图像的直方图功能。可以想象,您可以将 10 位信号转换为平面 FP 图像序列,并将直方图条目数设置为 2**10,但可惜的是,我认为这不会表现得那么好。

但这并不是世界末日。使用当今的 SIMD ISA 确实无法对直方图进行矢量化。 AVX-512 有一些技巧,但我不确定它们是否真的能通过观察到的性能改进获得回报——还没有尝试过。否则,它在很大程度上是一个固有的标量过程,因为对直方图的读取和写入不能组合成向量,至少对于 10 位图像来说是这样,除非您计划首先将其转换为感知色彩空间或者其他什么,不需要对颜色值进行太多算术。阅读它们,找到垃圾箱,增加它。 vImage 直方图例程的存在是为了完整性,不一定是因为有一些令人惊叹的 AltiVec(或现在的 SSE/Neon)秘密武器使它们飞得超快。

因此,如果您只是编写自己的未优化标量代码,那么与假设的 vImage 函数相比,它的性能应该相当好。这也可能是为什么 vImage 团队没有带着各种格式的直方图进城的原因。熟练的从业者可能会通过软件流水线或向量像素加载来获得比简单标量代码高出两倍的性能,以防止直方图内存访问相互干扰,但这不会是您通常认为的性能改进请参阅 vImage 中的其他地方。

可能会看到使用dispatch_apply()来同时处理条带中的图像并在最后将直方图添加到一起的一些改进,但这也取决于性能受带宽限制的程度。一旦你编写了标量代码来处理整个图像,将其分解为dispatch_apply()就非常容易了,你可以做一些基准测试。

© www.soinside.com 2019 - 2024. All rights reserved.