如何编译vImage浮雕效果示例代码?

时间:2013-09-15 11:08:15

标签: ios objective-c accelerate-framework vimage

以下是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;
}

问题在于:内核变量似乎引用了三种不同的类型:

  1. 在正式参数列表中的void *内核
  2. 一个未定义的unsigned int uint_8内核,作为一个新的变量,可能会影响形式参数
  3. 调用vImageConvolve_ARGB8888时,const signed int *内核。
  4. 这是实际代码吗?我该如何编译这个函数?

3 个答案:

答案 0 :(得分:2)

这是我使用它来处理使用AVAssetReader从视频读取的帧的方式。这很模糊,但您可以更改内核以满足您的需求。 'imageData'当然可以通过其他方式获得,例如来自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

答案 1 :(得分:2)

内核只是卷积中使用的内核。在数学术语中,矩阵与图像卷积,以实现模糊/锐化/浮雕或其他效果。你提供的这个函数只是一个围绕vimage卷积函数的薄包装器。要实际执行卷积,您可以按照下面的代码。代码全部是手动输入的,因此不一定100%正确,但应指向正确的方向。

要使用此功能,首先需要对图像进行像素访问。假设你有一个UIImage,你可以这样做:

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

接下来,构建将传递给函数

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

同样分配outBuffer

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

现在我们创建内核,在您的示例中是相同的内核,这是一个3x3矩阵 如果它们是浮点数(它们需要为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 ;

现在对图像执行卷积!

//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);

现在从outBuffer构建一个新的UIImage并完成!

请记住释放内核和outBuffer数据。

答案 2 :(得分:2)

你说这个功能搞砸了是对的。我建议使用“提供反馈”小部件让Apple知道。

我认为您应该从功能签名中删除kernelkernel_widthkernel_height参数。这些似乎是来自应用调用者提供的内核的函数的延续,但这个例子是关于应用内部定义的内核。

修正了kernel局部变量的声明,使其成为uint8_t的数组,如下所示:

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

然后,在致电vImageConvolve_ARGB8888()时,将kernel_widthkernel_height替换为3。由于内核是硬编码的,因此尺寸也可以。