Как скомпилировать пример кода с эффектом тиснения vImage?
Вот код, найденный в документации:
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;
}
Вот проблема: переменная ядра, по-видимому, относится к трем различным типам:
- ядро void * в списке формальных параметров
- неопределенное ядро unsigned int uint_8 как новая переменная, которая, вероятно, будет скрывать формальный параметр
- ядро int с подписью const при вызове vImageConvolve_ARGB8888.
Это актуальный код? Как я могу скомпилировать эту функцию?
3 ответа
Вы правы, что эта функция довольно запутана. Я рекомендую использовать виджет "Предоставить отзыв", чтобы сообщить об этом Apple.
Я думаю, что вы должны удалить kernel
, kernel_width
, а также kernel_height
параметры из сигнатуры функции. Похоже, что они являются пережитками функции, которая применяет ядро, предоставляемое вызывающей стороной, но этот пример касается применения внутренне определенного ядра.
Исправлено объявление о kernel
локальная переменная, чтобы сделать его массивом uint8_t
, вот так:
uint8_t kernel[] = {-2, -2, 0, -2, 6, 0, 0, 0, 0}; // 1
Затем при звонке vImageConvolve_ARGB8888()
заменить kernel_width
а также kernel_height
от 3
, Поскольку ядро жестко запрограммировано, размеры также могут быть.
Именно так я использую его для обработки кадров, считываемых из видео, с помощью 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
Ядро - это просто ядро, используемое в свертке. С математической точки зрения это матрица, которая свернута с вашим изображением для достижения размытия / резкости / тиснения или других эффектов. Эта функция, которую вы предоставили, является просто тонкой оберткой вокруг функции свертки 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 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);
Теперь создайте новый UIImage из outBuffer и все готово!
Не забудьте освободить ядро и данные outBuffer.