ОБНОВЛЕНИЕ: см. Дополнительный вопрос ниже с дополнительным кодом;
Я пытаюсь кодировать категорию для размытия изображения. Моя отправная точка - образец Джеффа Ламарша здесь . Хотя это (после исправлений, предложенных другими) работает нормально, для моих требований это на порядок медленнее - на 3GS для приличного размытия может потребоваться, возможно, 3 секунды, и я бы хотел уменьшить это значение до 0,5 сек для полного экрана (чем быстрее, тем лучше).
Он упоминает инфраструктуру Accelerate как повышение производительности, поэтому я провел последний день, рассматривая это, и в частности vDSP_f3x3, который согласно документации Apple
Фильтрует изображение, выполняя
двумерная свертка с 3x3
ядро; одинарная точность.
Отлично - у меня есть подходящая матрица фильтров, и у меня есть изображение ... но это то место, где я в тупике.
vDSP_f3x3 предполагает, что данные изображения (float *), но мое изображение взято;
srcData = (unsigned char *)CGBitmapContextGetData (context);
и контекст исходит из CGBitmapContextCreate с kCGImageAlphaPremultipliedFirst, поэтому мой srcData действительно ARGB с 8 битами на компонент.
Я подозреваю, что мне действительно нужен контекст с плавающими компонентами, но в соответствии с документацией Quartz здесь , kCGBitMapFloatComponents доступен только в Mac OS, а не в iOS: - (
Существует ли действительно быстрый способ использования ускоряющей структуры для преобразования целочисленных компонентов, которые у меня есть, в компоненты с плавающей запятой, которые нужны vDSP_f3x3? Я имею в виду, что мог бы сделать это сам, но к тому времени, когда я это сделаю, потом сверну, а затем вернусь обратно, я подозреваю, что сделаю это еще медленнее, чем сейчас, так как я мог бы так же свернуться, как и я.
Может, у меня неправильный подход?
У кого-нибудь есть какие-нибудь советы для меня, которые выполнили некоторую обработку изображений на iphone с использованием vDSP? Документация, которую я могу найти, ориентирована на справочную информацию и не очень удобна для новичков, когда дело доходит до такого рода вещей.
Если у кого-то есть ссылка на действительно быстрое размытие (и высокое качество, а не уменьшенное разрешение, а затем масштабируемый материал, который я видел, и смотрит штаны), это было бы потрясающе!
EDIT:
Спасибо, @ Джейсон. Я сделал это, и это почти работает, но теперь моя проблема заключается в том, что, хотя изображение размыто, при каждом вызове оно сдвигается влево на 1 пиксель. Также кажется, что изображение черно-белое, но это может быть что-то еще.
Есть ли в этом коде что-то, что выдается за явно неверный? Я еще не оптимизировал его, и он немного грубоват, но, надеюсь, код свертки достаточно ясен.
CGImageRef CreateCGImageByBlurringImage(CGImageRef inImage, NSUInteger pixelRadius, NSUInteger gaussFactor)
{
unsigned char *srcData, *finalData;
CGContextRef context = CreateARGBBitmapContext(inImage);
if (context == NULL)
return NULL;
size_t width = CGBitmapContextGetWidth(context);
size_t height = CGBitmapContextGetHeight(context);
size_t bpr = CGBitmapContextGetBytesPerRow(context);
int componentsPerPixel = 4; // ARGB
CGRect rect = {{0,0},{width,height}};
CGContextDrawImage(context, rect, inImage);
// Now we can get a pointer to the image data associated with the bitmap
// context.
srcData = (unsigned char *)CGBitmapContextGetData (context);
if (srcData != NULL)
{
size_t dataSize = bpr * height;
finalData = malloc(dataSize);
memcpy(finalData, srcData, dataSize);
//Generate Gaussian kernel
float *kernel;
// Limit the pixelRadius
pixelRadius = MIN(MAX(1,pixelRadius), 248);
int kernelSize = pixelRadius * 2 + 1;
kernel = malloc(kernelSize * sizeof *kernel);
int gauss_sum =0;
for (int i = 0; i < pixelRadius; i++)
{
kernel[i] = 1 + (gaussFactor*i);
kernel[kernelSize - (i + 1)] = 1 + (gaussFactor * i);
gauss_sum += (kernel[i] + kernel[kernelSize - (i + 1)]);
}
kernel[(kernelSize - 1)/2] = 1 + (gaussFactor*pixelRadius);
gauss_sum += kernel[(kernelSize-1)/2];
// Scale the kernel
for (int i=0; i<kernelSize; ++i) {
kernel[i] = kernel[i]/gauss_sum;
}
float * srcAsFloat,* resultAsFloat;
srcAsFloat = malloc(width*height*sizeof(float)*componentsPerPixel);
resultAsFloat = malloc(width*height*sizeof(float)*componentsPerPixel);
// Convert uint source ARGB to floats
vDSP_vfltu8(srcData,1,srcAsFloat,1,width*height*componentsPerPixel);
// Convolve (hence the -1) with the kernel
vDSP_conv(srcAsFloat, 1, &kernel[kernelSize-1],-1, resultAsFloat, 1, width*height*componentsPerPixel, kernelSize);
// Copy the floats back to ints
vDSP_vfixu8(resultAsFloat, 1, finalData, 1, width*height*componentsPerPixel);
free(resultAsFloat);
free(srcAsFloat);
}
size_t bitmapByteCount = bpr * height;
CGDataProviderRef dataProvider = CGDataProviderCreateWithData(NULL, finalData, bitmapByteCount, &providerRelease);
CGImageRef cgImage = CGImageCreate(width, height, CGBitmapContextGetBitsPerComponent(context),
CGBitmapContextGetBitsPerPixel(context), CGBitmapContextGetBytesPerRow(context), CGBitmapContextGetColorSpace(context), CGBitmapContextGetBitmapInfo(context),
dataProvider, NULL, true, kCGRenderingIntentDefault);
CGDataProviderRelease(dataProvider);
CGContextRelease(context);
return cgImage;
}
Я должен добавить это, если я закомментирую строку vDSP_conv и изменим следующую строку на;
vDSP_vfixu8(srcAsFloat, 1, finalData, 1, width*height*componentsPerPixel);
Тогда, как и ожидалось, мой результат - клон оригинального источника. По цвету и не смещено влево. Это означает для меня, что это Свертка, которая идет не так, но я не вижу, где: - (
МЫСЛЬ: На самом деле, думая об этом, мне кажется, что сверточник должен знать, что входные пиксели находятся в формате ARGB, так как в противном случае свертка будет умножать значения вместе без знания их значения (т. Е. Оно будет кратно R * Б и т. Д.). Это объясняет, почему я думаю, что получаю черно-белый результат, но не сдвиг. Опять же, я думаю, что здесь может быть что-то большее, чем моя наивная версия ...
ЗАКЛЮЧИТЕЛЬНАЯ МЫСЛЬ: Я думаю, что сдвиг влево - это естественный результат фильтра, и мне нужно посмотреть на размеры изображения и, возможно, дополнить его ... поэтому я думаю, что код на самом деле работает нормально, учитывая то, что я передал это.