高斯图像模糊算法及其 C 实现

高斯模糊的基本思路是根据二维 正太分布 正态分布 (感谢 xhr 大牛指正错别字) 公式生成一个高斯矩阵, 求新图像中的每一点时, 将高斯矩阵的中心对准旧图像的这一点, 并将所有点根据高斯矩阵上对应的点加权平均. 二维正态分布公式如下:

u, v 分别为水平、竖直距离. 观察可得, 当 r>3σ 时, 高斯矩阵上对应的权值已经小得可以忽略. 因此可以只计算一个大小为 (6σ+1)^2 的矩阵. 我们设置一个 radius 参数, 表示要计算的高斯矩阵的半径.

更详细的介绍参见维基百科: http://zh.wikipedia.org/wiki/%E9%AB%98%E6%96%AF%E6%A8%A1%E7%B3%8A

实验时发现, 当 radius 很小 (比如 1) 时, 矩阵内的所有值之和可能比 1 小一些, 这样就会出现偏差. 因此不如在生成矩阵的时候不去除以 2πσ^2, 而是用计入一个累加变量, 之后再将矩阵中的所有值除以这个变量. 这样可以在 radius 很小时也不至于影响图像的 '对比度'.

用 C 实现的代码如下:

  1. #include <windows.h>   
  2.   
  3. int gaussBlur(int *data, int width, int height, double sigma, int radius)   
  4. {   
  5.     double *gaussMatrix, gaussSum = 0.0, _2sigma2 = 2 * sigma * sigma;   
  6.     int x, y, xx, yy, xxx, yyy;   
  7.     double *pdbl, a, r, g, b, d;   
  8.     unsigned char *bbb, *pout, *poutb;   
  9.     pout = poutb = (unsigned char *)LocalAlloc(LMEM_FIXED, width * height * 4);   
  10.     if (!pout) return 0;   
  11.     gaussMatrix = pdbl = (double *)LocalAlloc(LMEM_FIXED, (radius * 2 + 1) * (radius * 2 + 1) * sizeof(double));   
  12.     if (!gaussMatrix) {   
  13.         LocalFree(pout);   
  14.         return 0;   
  15.     }   
  16.     for (y = -radius; y <= radius; y++) {   
  17.         for (x = -radius; x <= radius; x++) {   
  18.             a = exp(-(double)(x * x + y * y) / _2sigma2);   
  19.             *pdbl++ = a;   
  20.             gaussSum += a;   
  21.         }   
  22.     }   
  23.     pdbl = gaussMatrix;   
  24.     for (y = -radius; y <= radius; y++) {   
  25.         for (x = -radius; x <= radius; x++) {   
  26.             *pdbl++ /= gaussSum;   
  27.         }   
  28.     }   
  29.     for (y = 0; y < height; y++) {   
  30.         for (x = 0; x < width; x++) {   
  31.             a = r = g = b = 0.0;   
  32.             pdbl = gaussMatrix;   
  33.             for (yy = -radius; yy <= radius; yy++) {   
  34.                 yyy = y + yy;   
  35.                 if (yyy >= 0 && yyy < height) {   
  36.                     for (xx = -radius; xx <= radius; xx++) {   
  37.                         xxx = x + xx;   
  38.                         if (xxx >= 0 && xxx < width) {   
  39.                             bbb = (unsigned char *)&data[xxx + yyy * width];   
  40.                             d = *pdbl;   
  41.                             b += d * bbb[0];   
  42.                             g += d * bbb[1];   
  43.                             r += d * bbb[2];   
  44.                             a += d * bbb[3];   
  45.                         }   
  46.                         pdbl++;   
  47.                     }   
  48.                 } else {   
  49.                     pdbl += (radius * 2 + 1);   
  50.                 }   
  51.             }   
  52.             *pout++ = (unsigned char)b;   
  53.             *pout++ = (unsigned char)g;   
  54.             *pout++ = (unsigned char)r;   
  55.             *pout++ = (unsigned char)a;   
  56.         }   
  57.     }   
  58.     RtlMoveMemory(data, poutb, width * height * 4);   
  59.     LocalFree(gaussMatrix);   
  60.     LocalFree(poutb);   
  61.     return 1;   
  62. }  

sigma 参数表示模糊程度, radius 参数表示图像质量. radius = 0 时等同于什么都没做.

下面是 sigma = 1.0, radius = 3 时的效果:

同样的算法, 用 VB.NET 实现, 就硬生生地慢了 10 倍.
原因是没有指针, 数据必须拷来拷去的.

看来托管代码的确不适合写算法.


http://hi.baidu.com/iceboy_/item/d5e0c643a3ec2692823ae1fe

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值