标签:
刚才发现一份快速高速模糊的实现。
源地址为:http://incubator.quasimondo.com/processing/gaussian_blur_1.php
作者信息为:
Fast Gaussian Blur v1.3 by Mario Klingemann <http://incubator.quasimondo.com>
processing源码: http://incubator.quasimondo.com/processing/fastblur.pde
效果图:

转为C语言实现版本。
代码如下:
// Fast Gaussian Blur v1.3
// by Mario Klingemann <http://incubator.quasimondo.com>
// C version updated and performance optimization by tntmonks(http://tntmonks.cnblogs.com)
// One of my first steps with Processing. I am a fan
// of blurring. Especially as you can use blurred images
// as a base for other effects. So this is something I
// might get back to in later experiments.
//
// What you see is an attempt to implement a Gaussian Blur algorithm
// which is exact but fast. I think that this one should be
// relatively fast because it uses a special trick by first
// making a horizontal blur on the original image and afterwards
// making a vertical blur on the pre-processed image. This
// is a mathematical correct thing to do and reduces the
// calculation a lot.
//
// In order to avoid the overhead of function calls I unrolled
// the whole convolution routine in one method. This may not
// look nice, but brings a huge performance boost.
//
//
// v1.1: I replaced some multiplications by additions
// and added aome minor pre-caclulations.
// Also add correct rounding for float->int conversion
//
// v1.2: I completely got rid of all floating point calculations
// and speeded up the whole process by using a
// precalculated multiplication table. Unfortunately
// a precalculated division table was becoming too
// huge. But maybe there is some way to even speed
// up the divisions.
//
// v1.3: Fixed a bug that caused blurs that start at y>0
// to go wrong. Thanks to Jeroen Schellekens for
// finding it!
//申请二维数组
template <typename T>
T** newArray2D(unsigned int width, unsigned int height)
{
unsigned int size = sizeof(T);
unsigned int point_size = sizeof(T*);
T **arr = (T **)malloc(point_size * width + size * width * height);
memset(arr, 0, point_size * width + size * width * height);
if (arr != NULL)
{
T *head = (T*)((int)arr + point_size * width);
for (unsigned int i = 0; i < width; ++i)
{
arr[i] = (T*)((int)head + i * height * size);
for (unsigned int j = 0; j < height; ++j)
new (&arr[i][j]) T;
}
}
return (T**)arr;
}
//释放二维数组
template <typename T>
void deleteArray2D(T **arr, unsigned int width, unsigned int height)
{
for (unsigned int i = 0; i < width; ++i)
for (unsigned int j = 0; j < height; ++j)
arr[i][j].~T();
if (arr != NULL)
free((void**)arr);
}
void GaussianBlur(unsigned char* img, unsigned int x, unsigned int y, unsigned int w, unsigned int h,unsigned int comp, unsigned int radius)
{
unsigned int i, j;
radius = min(max(1, radius), 248);
unsigned int kernelSize = 1 + radius * 2;
unsigned int* kernel = (unsigned int*)malloc(kernelSize* sizeof(unsigned int));
memset(kernel, 0, kernelSize* sizeof(unsigned int));
unsigned int** mult = newArray2D<unsigned int>(kernelSize, 256);
unsigned int sum = 0;
for (i = 1; i < radius; i++){
unsigned int szi = radius - i;
kernel[radius + i] = kernel[szi] = szi*szi;
sum += kernel[szi] + kernel[szi];
for (j = 0; j < 256; j++){
mult[radius + i][j] = mult[szi][j] = kernel[szi] * j;
}
}
kernel[radius] = radius*radius;
sum += kernel[radius];
for (j = 0; j < 256; j++){
mult[radius][j] = kernel[radius] * j;
}
unsigned int cr, cg, cb;
unsigned int xl, yl, yi, ym, riw;
int read, ri;
unsigned int imgWidth = w;
unsigned int imgHeight = h;
unsigned int imageSize = imgWidth*imgHeight;
unsigned char * rgb = (unsigned char *)malloc(sizeof(unsigned char) * imageSize*3);
unsigned char * r = rgb;
unsigned char * g = rgb + imageSize;
unsigned char * b = rgb + imageSize*2;
unsigned char * rgb2 = (unsigned char *)malloc(sizeof(unsigned char) * imageSize * 3);
unsigned char * r2 = rgb2;
unsigned char * g2 = rgb2 + imageSize;
unsigned char * b2 = rgb2 + imageSize * 2;
for (size_t yh = 0; yh < imgHeight; ++yh) {
for (size_t xw = 0; xw < imgWidth; ++xw) {
unsigned int n = xw + yh* imgWidth;
unsigned int p = n*comp;
r[n] = img[p];
g[n] = img[p + 1];
b[n] = img[p + 2];
}
}
unsigned int Zero = 0;
//max(0, x);
x = x ^ ((x ^ Zero) & -(x < Zero));
//max(0, y);
y = Zero ^ ((Zero ^ y) & -(Zero < y));
w = x + w - max(0, (x + w) - imgWidth);
h = y + h - max(0, (y + h) - imgHeight);
yi = y*imgWidth;
for (yl = y; yl < h; yl++){
for (xl = x; xl < w; xl++){
cb = cg = cr = sum = 0;
ri = xl - radius;
for (i = 0; i < kernelSize; i++){
read = ri + i;
if (read >= x && read < w)
{
read += yi;
cr += mult[i][r[read]];
cg += mult[i][g[read]];
cb += mult[i][b[read]];
sum += kernel[i];
}
}
ri = yi + xl;
r2[ri] = cr / sum;
g2[ri] = cg / sum;
b2[ri] = cb / sum;
}
yi += imgWidth;
}
yi = y*imgWidth;
for (yl = y; yl < h; yl++){
ym = yl - radius;
riw = ym*imgWidth;
for (xl = x; xl < w; xl++){
cb = cg = cr = sum = 0;
ri = ym;
read = xl + riw;
for (i = 0; i < kernelSize; i++){
if (ri < h && ri >= y)
{
cr += mult[i][r2[read]];
cg += mult[i][g2[read]];
cb += mult[i][b2[read]];
sum += kernel[i];
}
ri++;
read += imgWidth;
}
unsigned int p = (xl + yi)*comp;
img[p] = (unsigned char)(cr / sum);
img[p + 1] = (unsigned char)(cg / sum);
img[p + 2] = (unsigned char)(cb / sum);
}
yi += imgWidth;
}
free(rgb);
free(rgb2);
free(kernel);
deleteArray2D(mult, 1 + radius * 2, 256);
}
该代码,将二维数组进一步优化后可提升一定的速度。
在博主机子上测试一张5000x3000的图像,模糊半径为10的情况下,耗时4s.
标签:
原文地址:http://www.cnblogs.com/tntmonks/p/4899649.html