Problem with vImagePiecewiseGamma_Planar8

In our app we use the following function for inverting a CGImageRef using vImage. The workflow is a obj-c version of the code in the AdjustingTheBrightnessAndContrastOfAnImage sample from Apple:

CGImageRef InvertImage( CGImageRef frameImageRef )
{
	CGImageRef resultImage = nil;
	
	CGBitmapInfo imgBitmapInfo =  CGImageGetBitmapInfo( frameImageRef );
	size_t img_bPC = CGImageGetBitsPerComponent( frameImageRef );
	size_t img_bPP = CGImageGetBitsPerPixel( frameImageRef );
	
	vImage_CGImageFormat invIFormat;
	invIFormat.bitsPerComponent = img_bPC;
	invIFormat.bitsPerPixel = img_bPP;
	invIFormat.colorSpace = (img_bPP == 8) ? gDeviceGrayColorSpaceRef : gDeviceRGBColorSpaceRef;
	invIFormat.bitmapInfo = imgBitmapInfo;
	invIFormat.version = 0;
	invIFormat.decode = 0;
	invIFormat.renderingIntent = kCGRenderingIntentDefault;
	
	vImage_Buffer sourceVImageBuffer;
	
	vImage_Error viErr = vImageBuffer_InitWithCGImage( &sourceVImageBuffer, &invIFormat, nil, frameImageRef, kvImageNoFlags );
	if (viErr == kvImageNoError)
	{
		vImage_Buffer destinationVImageBuffer;
		viErr = vImageBuffer_Init( &destinationVImageBuffer, sourceVImageBuffer.height, sourceVImageBuffer.width, img_bPP, kvImageNoFlags );
		if (viErr == kvImageNoError)
		{
			float linearCoeffs[2] = { -1.0, 1.0 };
			float expoCoeffs[3] = { 1.0, 0.0, 0.0 };
			float gamma = 0.0;
			Pixel_8 boundary = 255;
			
			viErr = vImagePiecewiseGamma_Planar8( &sourceVImageBuffer, &destinationVImageBuffer, expoCoeffs, gamma, linearCoeffs, boundary, kvImageNoFlags );
			if (viErr == kvImageNoError)
			{
				CGImageRef newImgRef = vImageCreateCGImageFromBuffer( &destinationVImageBuffer, &invIFormat, nil, nil, kvImageNoFlags, &viErr );
				
				if (viErr == kvImageNoError)
					resultImage = newImgRef;
			}
			
			free( destinationVImageBuffer.data );
		}
		
		free( sourceVImageBuffer.data );
	}
	
	return  resultImage;
}

The function works fine for 8-bit monochrome images. When I try it with 24-bit RGB images, although I get no errors from any of the calls, the output shows only the 1/3 of the image inverted as expected.

What am I missing? I suspect I might have to use a different function for 24-bit images (instead of the vImagePiecewiseGamma_Planar8) but I cannot find which one in the headers.

Thanks.

Replies

Does the original Objective-C have the same problem?

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

The original works without problem but it is written in swift. It is the sample code from "Adjusting the brightness and contrast of an image" . I translated the code to obj-c myself, since I couldn't find an obj-c version.

Oh, sorry, I got this backwards. Thanks for clarifying.

When you say it “original works without problem”, does that mean that the Swift version works with both 8- and 24-bit images?

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Exactly.

When I grep the sample code project for vImagePiecewiseGamma_Planar8, I get no hits. So in what sense is your code a translation?

Correct. The original uses:

            source.applyGamma(linearParameters: linearCoefficients,
                              exponentialParameters: exponentialCoefficients,
                              boundary: preset.boundary,
                              destination: destination)

In case it helps:

Stepping my app and the swift sample under the debugger I noticed something: for an 800x600 RGB image the function vImageBuffer_InitWithCGImage returns a vImage_Buffer with rowBytes=2400 in my obj-c app, instead of the expected 2432 that I get with the swift version. Inquiring about the imageAlignment I get the correct value of 64 in both apps.

I searched the SDK for vImagePiecewiseGamma_Planar8, just to get a feel for the context of that routine, and lo! I found that shows up in the inline implementation of applyGamma(linearParameters:exponentialParameters:boundary:destination:). Check out usr/lib/swift/Accelerate.swiftmodule/arm64-apple-ios.swiftinterface (or the equivalent file in other platforms SDKs). Does that offer any clues?

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Thanks Quinn, it finally works.

Copying the logic from the swiftinterface for macOS I replaced

			viErr = vImagePiecewiseGamma_Planar8( &sourceVImageBuffer, &destinationVImageBuffer, expoCoeffs, gamma, linearCoeffs, boundary, kvImageNoFlags );
			if (viErr == kvImageNoError)
			{
				CGImageRef newImgRef = vImageCreateCGImageFromBuffer( &destinationVImageBuffer, &invIFormat, nil, nil, kvImageNoFlags, &viErr );

with

			vImage_Buffer bufSrc;
			vImage_Buffer bufDest;
			
			bufSrc.data = sourceVImageBuffer.data;
			bufSrc.width = sourceVImageBuffer.width * img_bPP / img_bPC;
			bufSrc.height = sourceVImageBuffer.height;
			bufSrc.rowBytes = sourceVImageBuffer.rowBytes;
			
			bufDest.data = destinationVImageBuffer.data;
			bufDest.width = destinationVImageBuffer.width * img_bPP / img_bPC;
			bufDest.height = destinationVImageBuffer.height;
			bufDest.rowBytes = destinationVImageBuffer.rowBytes;
			
			viErr = vImagePiecewiseGamma_Planar8( &bufSrc, &bufDest, expoCoeffs, gamma, linearCoeffs, boundary, kvImageNoFlags );
			if (viErr == kvImageNoError)
			{
        CGImageRef newImgRef = vImageCreateCGImageFromBuffer( &destinationVImageBuffer, &invIFormat, nil, nil, kvImageNoFlags, &viErr );

and it works for both monochrome and RGB images.

Interesting trick to know.

Many thanks again.

  • [too much graphics, head swimming] Excellent news!

Add a Comment