刚才发现一份快速高速模糊的实现。
源地址为: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.
时间: 2024-10-18 18:41:07