Question

Here is the code found in the documentation:

int myEmboss(void *inData,
unsigned int inRowBytes,
void *outData,
unsigned int outRowBytes,
unsigned int height,
unsigned int width,
void *kernel,
unsigned int kernel_height,
unsigned int kernel_width,
int divisor ,
vImage_Flags flags ) {
   uint_8 kernel = {-2, -2, 0, -2, 6, 0, 0, 0, 0}; // 1
   vImage_Buffer src = { inData, height, width, inRowBytes }; // 2
   vImage_Buffer dest = { outData, height, width, outRowBytes }; // 3
   unsigned char bgColor[4] = { 0, 0, 0, 0 }; // 4
   vImage_Error err; // 5
   err = vImageConvolve_ARGB8888(    &src,     //const vImage_Buffer *src
                                     &dest,    //const vImage_Buffer *dest,
                                      NULL,
                                      0,    //unsigned int srcOffsetToROI_X,
                                      0,    //unsigned int srcOffsetToROI_Y,
                                      kernel,    //const signed int *kernel,
                                      kernel_height,     //unsigned int
                                      kernel_width,    //unsigned int
                                      divisor,    //int
                                      bgColor,
                                      flags | kvImageBackgroundColorFill
                                      //vImage_Flags flags
                                    );


   return err;
}

Here is the problem: the kernel variable seems to refer to three different types:

  1. void * kernel in the formal parameter list
  2. an undefined unsigned int uint_8 kernel, as a new variable which presumably would shadow the formal parameter
  3. a const signed int *kernel when calling vImageConvolve_ARGB8888.

Is this actual code ? How may I compile this function ?

Was it helpful?

Solution

You are correct that that function is pretty messed up. I recommend using the Provide Feedback widget to let Apple know.

I think you should remove the kernel, kernel_width, and kernel_height parameters from the function signature. Those seem to be holdovers from a function that applies a caller-supplied kernel, but this example is about applying an internally-defined kernel.

Fixed the declaration of the kernel local variable to make it an array of uint8_t, like so:

    uint8_t kernel[] = {-2, -2, 0, -2, 6, 0, 0, 0, 0}; // 1

Then, at the call to vImageConvolve_ARGB8888(), replace kernel_width and kernel_height by 3. Since the kernel is hard-coded, the dimensions can be as well.

OTHER TIPS

The kernel is just the kernel used in the convolution. In mathematical terms, it is the matrix that is convolved with your image, to achieve blur/sharpen/emboss or other effects. This function you provided is just a thin wrapper around the vimage convolution function. To actually perform the convolution you can follow the code below. The code is all hand typed so not necessarily 100% correct but should point you in the right direction.

To use this function, you first need to have pixel access to your image. Assuming you have a UIImage, you do this:

//image is a UIImage
CGImageRef img = image.CGImage;
CGDataProviderRef dataProvider = CGImageGetDataProvider(img); 
CFDataRef cfData = CGDataProviderCopyData(dataProvider);
void * dataPtr = (void*)CFDataGetBytePtr(cfData);

Next, you construct the vImage_Buffer that you will pass to the function

vImage_Buffer inBuffer, outBuffer;
inBuffer.data = dataPtr;
inBuffer.width = CGImageGetWidth(img);
inBuffer.height = CGImageGetHeight(img);
inBuffer.rowBytes = CGImageGetBytesPerRow(img);

Allocate the outBuffer as well

outBuffer.data = malloc(inBuffer.height * inBuffer.rowBytes)
// Setup width, height, rowbytes equal to inBuffer here

Now we create the Kernel, the same one in your example, which is a 3x3 matrix Multiply the values by a divisor if they are float (they need to be int)

int divisor = 1000;
CGSize kernalSize = CGSizeMake(3,3);
int16_t *kernel = (int16_t*)malloc(sizeof(int16_t) * 3 * 3);
// Assign kernel values to the emboss kernel
// uint_8 kernel = {-2, -2, 0, -2, 6, 0, 0, 0, 0} // * 1000 ;

Now perform the convolution on the image!

//Use a background of transparent black as temp
Pixel_8888 temp = 0;
vImageConvolve_ARGB8888(&inBuffer, &outBuffer, NULL, 0, 0, kernel, kernelSize.width, kernelSize.height, divisor, temp, kvImageBackgroundColorFill);

Now construct a new UIImage out of outBuffer and your done!

Remember to free the kernel and the outBuffer data.

This is the way I am using it to process frames read from a video with AVAssetReader. This is a blur, but you can change the kernel to suit your needs. 'imageData' can of course be obtained by other means, e.g. from an UIImage.

     CMSampleBufferRef sampleBuffer = [asset_reader_output copyNextSampleBuffer];
     CVImageBufferRef imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer);            
     CVPixelBufferLockBaseAddress(imageBuffer,0);
     void *imageData = CVPixelBufferGetBaseAddress(imageBuffer);        

     int16_t kernel[9];
     for(int i = 0; i < 9; i++) {
        kernel[i] = 1;
     }
     kernel[4] = 2;

     unsigned char *newData= (unsigned char*)malloc(4*currSize);

     vImage_Buffer  inBuff = { imageData, height, width, 4*width };
     vImage_Buffer  outBuff = { newData, height, width, 4*width };

     vImage_Error err=vImageConvolve_ARGB8888 (&inBuff,&outBuff,NULL, 0,0,kernel,3,3,10,nil,kvImageEdgeExtend);
     if (err != kvImageNoError) NSLog(@"convolve error %ld", err);
     CVPixelBufferUnlockBaseAddress(imageBuffer, 0);

     //newData holds the processed image
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top