借鉴:http://blog.sina.com.cn/s/blog_861912cd0101957x.html http://www.ruanyifeng.com/blog/2012/11/gaussian_blur.html
二维高斯曲面的公式
高斯半径(σ)对曲线形状的影响,σ越小,曲线越高越尖,σ越大,曲线越低越平缓。因此高斯半径越小,则模糊越小,高斯半径越大,则模糊程度越大。 模版矩阵的大小一般设为 ( 6*sigma+1 ) *( 6*sigma+1 )
模版搜索半径一般为 3σ 为合适
3*3模版 1 2 1 2 4 2 /16 1 2 1 是对r=0.849时的一个近似 guass radius=0.849000 0.062467 0.125000 0.062467 0.125000 0.250131 0.125000 0.062467 0.125000 0.062467 int r= (f1(i - 1,j - 1) + f1(i - 1,j + 1) + f1(i + 1,j - 1) + f1(i + 1,j + 1) + (f1(i - 1,j) + f1(i,j - 1) + f1(i + 1,j) + f1(i,j + 1)) * 2 + f1(i,j) * 4 ) / 16; int g = (f2(i - 1, j - 1) + f2(i - 1, j + 1) + f2(i + 1, j - 1) + f2(i + 1, j + 1) + (f2(i - 1, j) + f2(i, j - 1) + f2(i + 1, j) + f2(i, j + 1)) * 2 + f2(i, j) * 4) / 16; int b = (f3(i - 1, j - 1) + f3(i - 1, j + 1) + f3(i + 1, j - 1) + f3(i + 1, j + 1) + (f3(i - 1, j) + f3(i, j - 1) + f3(i + 1, j) + f3(i, j + 1)) * 2 + f3(i, j) * 4) / 16;
附 :源代码
//一般情况下模版为( 6*sigma+1 ) *( 6*sigma+1 )的矩阵。 注:sigma为高斯公式中的sigma #define sigma 1 //高斯半径 const int N = (int)(sigma * 3); #define M_PI 3.1415926535898 double a[2 * N + 1][2 * N + 1]; d CMFCAppDlg::CalcMatrix() //计算权重矩阵 { /* 高斯半径越小,则模糊越小,高斯半径越大,则模糊程度越大。我们将看到ps对高斯半径的范围定义是【0.1~250】 半径为r时,取σ为 r/3 是一个比较合适的取值 */ int i, j; double A = 1 / (2 * M_PI*sigma*sigma); double sum = 0.0; for (i = -1 * N; i <= N; i++) { for (j = -1 * N; j <= N; j++) { a[i + N][j + N] = A*exp((-1)*(i*i + j*j) / (2 * sigma * sigma)); } } if (sum == 1.0) return; for (i = 0; i < 2 * N + 1; i++) for (j = 0; j < 2 * N + 1; j++) sum += a[i][j];//计算权值和 /*归一化: 首先求得权重总和,为了须让它们的权重之和等于1, 还要把上面值还要分别除以这个和,得到最终的权重矩阵。 若滤镜的权重总值不等于1,使用总值大于1的滤镜会让图像偏亮,小于1的滤镜会让图像偏暗。 */ for (i = 0; i < 2 * N + 1; i++) for (j = 0; j < 2 * N + 1; j++) a[i][j] /= sum; } int CMFCAppDlg::f1(int x, int y) { return GetRValue(img.GetPixel(x, y)); } int CMFCAppDlg::f2(int x, int y) { return GetGValue(img.GetPixel(x, y)); } int CMFCAppDlg::f3(int x, int y) { return GetBValue(img.GetPixel(x, y)); } void CMFCAppDlg::OnBnClickedButton2() { // TODO: 在此添加控件通知处理程序代码 bStart = TRUE; CDC *pDC = GetDC(); img.Load(_T("D:\\1.png")); //给图片做高斯处理 int i, j; for(i = N;i<img.GetWidth()-N;i++) for (j = N; j < img.GetHeight()-N; j++) { /* 3*3模版 1 2 1 2 4 2 /16 1 2 1 是对r=0.849时的一个近似 guass radius=0.849000 0.062467 0.125000 0.062467 0.125000 0.250131 0.125000 0.062467 0.125000 0.062467 int r= (f1(i - 1,j - 1) + f1(i - 1,j + 1) + f1(i + 1,j - 1) + f1(i + 1,j + 1) + (f1(i - 1,j) + f1(i,j - 1) + f1(i + 1,j) + f1(i,j + 1)) * 2 + f1(i,j) * 4 ) / 16; int g = (f2(i - 1, j - 1) + f2(i - 1, j + 1) + f2(i + 1, j - 1) + f2(i + 1, j + 1) + (f2(i - 1, j) + f2(i, j - 1) + f2(i + 1, j) + f2(i, j + 1)) * 2 + f2(i, j) * 4) / 16; int b = (f3(i - 1, j - 1) + f3(i - 1, j + 1) + f3(i + 1, j - 1) + f3(i + 1, j + 1) + (f3(i - 1, j) + f3(i, j - 1) + f3(i + 1, j) + f3(i, j + 1)) * 2 + f3(i, j) * 4) / 16; */ CalcMatrix(); /* 下面两层for含义: 例: a11 a12 a13 a21 a22 a23 a31 a32 a33 此时N等于1 由于权值矩阵中,a11, a13, a31, a33 的值是相等的,所以只需要把四个角落的计算一遍即可 */ int r, g, b; r = g = b = 0; for (int m = 0; m < N + 1; m++) { for (int n = 0; n < N + 1; n++) { if (N - m != 0 && N - n != 0) { /* 由于高斯分布是对称的,所以只要计算左上角,然后四个角落分别相乘自己对应的矩阵权值。 如果列或者行与中点在同一直线上,则计算两次。 中点计算一次。 */ r += f1(i - (N - m), j - (N - n))*a[m][n]; g += f2(i - (N - m), j - (N - n))*a[m][n]; b += f3(i - (N - m), j - (N - n))*a[m][n]; r += f1(i - (N - m), j + (N - n))*a[m][n]; g += f2(i - (N - m), j + (N - n))*a[m][n]; b += f3(i - (N - m), j + (N - n))*a[m][n]; r += f1(i + (N - m), j - (N - n))*a[m][n]; g += f2(i + (N - m), j - (N - n))*a[m][n]; b += f3(i + (N - m), j - (N - n))*a[m][n]; r += f1(i + (N - m), j + (N - n))*a[m][n]; g += f2(i + (N - m), j + (N - n))*a[m][n]; b += f3(i + (N - m), j + (N - n))*a[m][n]; } else if (N - m == 0 && N - n == 0)//中心点 { r += f1(i , j )*a[m][n]; g += f2(i , j )*a[m][n]; b += f3(i , j )*a[m][n]; } else //与中心点在同一直线上的非中心点 {//由于在同一直线上必然有 N-m 或 N-n 为0,所以只需要- -与 + +情况 r += f1(i - (N - m), j - (N - n))*a[m][n]; g += f2(i - (N - m), j - (N - n))*a[m][n]; b += f3(i - (N - m), j - (N - n))*a[m][n]; r += f1(i + (N - m), j + (N - n))*a[m][n]; g += f2(i + (N - m), j + (N - n))*a[m][n]; b += f3(i + (N - m), j + (N - n))*a[m][n]; } } } img.SetPixel(i, j, RGB(r,g,b));//将经过模糊处理后的像素值赋值到相应的位置 //更新进度信息 m_progress.SetPos((i*j) / (double)(img.GetWidth()*img.GetHeight()) * 100); } //绘制处理完成后的新图像 img.Draw(pDC->m_hDC, 0,0); }