Histogram calculation using vImage

I am getting pixel buffers in BGRA32 format in real time through AVCaptureVideoDataOutput and I am trying to compute Histogram. Following is my code to process pixel buffers to get histogram:


CVPixelBufferLockBaseAddress(pixelBuffer, kCVPixelBufferLock_ReadOnly);

vImage_Error err;
vImage_Buffer buffer;
buffer.data = (unsigned char *)CVPixelBufferGetBaseAddress( pixelBuffer );
buffer.rowBytes = CVPixelBufferGetBytesPerRow( pixelBuffer );
buffer.width = CVPixelBufferGetWidth( pixelBuffer );
buffer.height = CVPixelBufferGetHeight( pixelBuffer );
vImageCVImageFormatRef vformat = vImageCVImageFormat_CreateWithCVPixelBuffer( pixelBuffer );
vImageBuffer_InitWithCVPixelBuffer(&buffer, NULL, pixelBuffer, vformat, NULL, kvImageNoAllocate);

vImagePixelCount alpha[256];
vImagePixelCount red[256];
vImagePixelCount green[256];
vImagePixelCount blue[256];
vImagePixelCount *histogram[4] = {blue, green, red, alpha};

err = vImageHistogramCalculation_ARGB8888(&buffer, histogram, kvImageNoFlags);

CVPixelBufferUnlockBaseAddress(pixelBuffer, kCVPixelBufferLock_ReadOnly);


However, I get a warning "Null passed to a callee that requires a non-null argument" for the second argument passed to vImageBuffer_InitWithCVPixelBuffer. All I want is to initialize and process the vImage and compute the histogram with minimal format conversions. Is there a passthrough way to convert pixel buffer to vImage which preserves BGRA32 format?

Could not find in doculmentation InitWithCVPixelBuffer with the signature you use.


Only found


- (instancetype)initWithCVPixelBuffer:(CVPixelBufferRef)pixelBuffer options:(NSDictionary<VNImageOption, id> *)options;


May be, instead of passing NULL, you could pass an empty dictionary ?

There is this signature in vImage_CVUtilities.h


vImage_Error vImageBuffer_InitWithCVPixelBuffer( vImage_Buffer *buffer,

vImage_CGImageFormat *desiredFormat,

CVPixelBufferRef cvPixelBuffer,

vImageCVImageFormatRef cvImageFormat,

const CGFloat *backgroundColor,

vImage_Flags flags )

Skip the vImageBuffer_InitWithCVPixelBuffer, you don't need that.

vImageBufferInitWithCVPixelBuffer reads the CVPixelBuffer and copies the data to a (typically internally allocated) vImageBuffer.data memory store. Along the way it will convert from the CVPixelBuffer format to the format provided as the 2nd argument of the vImageBufferInitWithCVPixelBuffer call. Since you passed NULL there, the compiler is complaining there is no format to convert to. You also aren't using it correctly, thinking that you are supposed to init the vImageBuffer itself and then (unknown magic) happens in the vImageBuffer_InitWithCVPixelBuffer call.

If the CVPixelBuffer is not ARGB8888, then the code will look like:

Code Block
vImage_Error err;
vImage_Buffer buffer;
vImageCVImageFormatRef vformat = vImageCVImageFormat_CreateWithCVPixelBuffer( pixelBuffer );
vImage_CGImageFormat resultFormat = (vImage_CGImageFormat){
.bitsPerComponent = 8,
.bitsPerPixel = 32,
.colorSpace = CGColorspaceCreateDeviceRGB(),
.bitmapInfo = kCGImageAlphaPremultipliedFirst | kCGImageByteOrderDefault
};
err = vImageBuffer_InitWithCVPixelBuffer(&buffer, &resultFormat, pixelBuffer, vformat, NULL, kvImageNoFlags);
vImagePixelCount alpha[256] = {0};
vImagePixelCount red[256] = {0};
vImagePixelCount green[256] = {0};
vImagePixelCount blue[256] = {0};
vImagePixelCount *histogram[4] = {blue, green, red, alpha};
err = vImageHistogramCalculation_ARGB8888(&buffer, histogram, kvImageNoFlags);
free(buffer.data);
vImageCVImageFormat_Release(vformat);


If it is ARGB8888, then you can just wrap the CVPixelBuffer with the vImageBuffer:

Code Block
vImage_Buffer buffer;
buffer.data = (unsigned char *)CVPixelBufferGetBaseAddress( pixelBuffer );
buffer.rowBytes = CVPixelBufferGetBytesPerRow( pixelBuffer );
buffer.width = CVPixelBufferGetWidth( pixelBuffer );
buffer.height = CVPixelBufferGetHeight( pixelBuffer );
vImagePixelCount alpha[256] = {0};
vImagePixelCount red[256] = {0};
vImagePixelCount green[256] = {0};
vImagePixelCount blue[256] = {0};
vImagePixelCount *histogram[4] = {blue, green, red, alpha};
err = vImageHistogramCalculation_ARGB8888(&buffer, histogram, kvImageNoFlags);

Histogram calculation using vImage
 
 
Q