直方图在vImageHistogramCalculation_Planar8中的不同通道是如何工作的

时间:2021-06-02 21:21:35

I am attempting to calculate a histogram for the Y channel in a kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange image buffer. When I use vImageHistogramCalculation_Planar8 I pass in a reference to only a single histogram.

我正在尝试在kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange图像缓冲区中计算Y通道的直方图。当我使用vImageHistogramCalculation_Planar8时,我只传递一个对单个直方图的引用。

How do I know which channel is being used to create the histogram? What would I do if I wanted to read all channels?

如何知道使用哪个通道来创建直方图?如果我想阅读所有频道,我该怎么办?

Also open to critiques of the code sample.

也欢迎对代码示例的批评。

extension ViewController: AVCaptureVideoDataOutputSampleBufferDelegate {
    func captureOutput(_ captureOutput: AVCaptureOutput!,
                       didOutputSampleBuffer sampleBuffer: CMSampleBuffer!,
                       from connection: AVCaptureConnection!) {

        let imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer)!
        CVPixelBufferLockBaseAddress(imageBuffer, CVPixelBufferLockFlags(rawValue: 0))

        let height = CVPixelBufferGetHeight(imageBuffer)
        let width = CVPixelBufferGetWidth(imageBuffer)
        let bytesPerRow = CVPixelBufferGetBytesPerRow(imageBuffer)
        let pixelBuffer = CVPixelBufferGetBaseAddress(imageBuffer)

//        let format = CVPixelBufferGetPixelFormatType(imageBuffer)
//        print("format: \(format)")

        ///kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange = '420v'

        var vBuffer = vImage_Buffer()
        vBuffer.data = pixelBuffer
        vBuffer.rowBytes = bytesPerRow
        vBuffer.width = vImagePixelCount(width)
        vBuffer.height = vImagePixelCount(height)

        let luma = [UInt](repeating: 0, count: 256)

        let lumaHist = UnsafeMutablePointer<vImagePixelCount>(mutating: luma)

        vImageHistogramCalculation_Planar8(&vBuffer, lumaHist, UInt32(kvImageNoFlags))

        CVPixelBufferUnlockBaseAddress(imageBuffer, CVPixelBufferLockFlags(rawValue: 0))
    }
}

2 个解决方案

#1


2  

The kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange is a planar format with all the planes encoded into the buffer. And vImage planar functions only work on one plane at a time. The above code is computing an histogram on the three planes but treated as one big plane which is probably not what you want.

kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange是一个平面格式,所有平面都被编码到缓冲区中。而vImage平面函数一次只能在一个平面上工作。上面的代码是计算三个平面上的直方图,但将其视为一个大平面,这可能不是您想要的。

It is possible to access the base address and the number of bytes per row for the Y plane with these functions:

可以使用以下函数访问Y平面的基本地址和每行字节数:

let bytesPerRow = CVPixelBufferGetBytesPerRowOfPlane(imageBuffer, 0)
let pixelBuffer = CVPixelBufferGetBaseAddressOfPlane(imageBuffer, 0)

The plane index depends of the buffer format. The name usually gives you a hint. Here it's YpCbCr so the Y plane should be the first one, at index 0.

平面索引取决于缓冲区格式。这个名字通常会给你一个提示。这里是YpCbCr所以Y平面应该是第一个,在索引0处。

#2


0  

According to the header, CVPixelBufferGetBaseAddress will return:

根据header, CVPixelBufferGetBaseAddress将返回:

    For chunky buffers, this will return a pointer to the pixel at 
      0,0 in the buffer. 
    For planar buffers this will return a pointer to a PlanarComponentInfo struct 
       (defined in QuickTime). 

So, if true, it is not computing the histogram of all three channels at once. It is computing the even less useful histogram of the PlanarComponentInfo struct and possibly crashing.

所以,如果这是真的,它不是同时计算这三个通道的直方图。它正在计算更不实用的PlanarComponentInfo结构的直方图,并可能崩溃。

To read all the channels, you can get the second plane out using the interfaces described in Sparga's answer above (CVPixelBufferGetBytesPerRowOfPlane(imageBuffer,1) and CVPixelBufferGetBaseAddressOfPlane(imageBuffer,1)), and do a ARGB histogram of the half width chroma image and add the even histograms together and the odd histograms together. Note that because this is 420, the height and width of the chroma plane is not the same as the luminance plane.

要读取所有通道,可以使用上面Sparga回答中描述的接口(CVPixelBufferGetBytesPerRowOfPlane(imageBuffer,1)和CVPixelBufferGetBaseAddressOfPlane(imageBuffer,1))获取第二个平面,并对半宽色度图像进行ARGB直方图,并将奇数直方图加在一起。注意,因为这是420,色层的高度和宽度与亮度平面不相同。

I would also file a bug report with apple asking for vImageHistogramCalculation_RG88 to deal with biplanar chroma data.

我还会向苹果提交一个bug报告,请求vImageHistogramCalculation_RG88处理双平面色度数据。

#1


2  

The kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange is a planar format with all the planes encoded into the buffer. And vImage planar functions only work on one plane at a time. The above code is computing an histogram on the three planes but treated as one big plane which is probably not what you want.

kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange是一个平面格式,所有平面都被编码到缓冲区中。而vImage平面函数一次只能在一个平面上工作。上面的代码是计算三个平面上的直方图,但将其视为一个大平面,这可能不是您想要的。

It is possible to access the base address and the number of bytes per row for the Y plane with these functions:

可以使用以下函数访问Y平面的基本地址和每行字节数:

let bytesPerRow = CVPixelBufferGetBytesPerRowOfPlane(imageBuffer, 0)
let pixelBuffer = CVPixelBufferGetBaseAddressOfPlane(imageBuffer, 0)

The plane index depends of the buffer format. The name usually gives you a hint. Here it's YpCbCr so the Y plane should be the first one, at index 0.

平面索引取决于缓冲区格式。这个名字通常会给你一个提示。这里是YpCbCr所以Y平面应该是第一个,在索引0处。

#2


0  

According to the header, CVPixelBufferGetBaseAddress will return:

根据header, CVPixelBufferGetBaseAddress将返回:

    For chunky buffers, this will return a pointer to the pixel at 
      0,0 in the buffer. 
    For planar buffers this will return a pointer to a PlanarComponentInfo struct 
       (defined in QuickTime). 

So, if true, it is not computing the histogram of all three channels at once. It is computing the even less useful histogram of the PlanarComponentInfo struct and possibly crashing.

所以,如果这是真的,它不是同时计算这三个通道的直方图。它正在计算更不实用的PlanarComponentInfo结构的直方图,并可能崩溃。

To read all the channels, you can get the second plane out using the interfaces described in Sparga's answer above (CVPixelBufferGetBytesPerRowOfPlane(imageBuffer,1) and CVPixelBufferGetBaseAddressOfPlane(imageBuffer,1)), and do a ARGB histogram of the half width chroma image and add the even histograms together and the odd histograms together. Note that because this is 420, the height and width of the chroma plane is not the same as the luminance plane.

要读取所有通道,可以使用上面Sparga回答中描述的接口(CVPixelBufferGetBytesPerRowOfPlane(imageBuffer,1)和CVPixelBufferGetBaseAddressOfPlane(imageBuffer,1))获取第二个平面,并对半宽色度图像进行ARGB直方图,并将奇数直方图加在一起。注意,因为这是420,色层的高度和宽度与亮度平面不相同。

I would also file a bug report with apple asking for vImageHistogramCalculation_RG88 to deal with biplanar chroma data.

我还会向苹果提交一个bug报告,请求vImageHistogramCalculation_RG88处理双平面色度数据。