借鉴:http://blog.sina.com.cn/s/blog_861912cd0101957x.html http://www.ruanyifeng.com/blog/2012/11/gaussian_blur.html
二维高斯曲面的公式
![](https://p-blog.csdn.net/images/p_blog_csdn_net/hoodlum1980/gauss_formular.jpg)
高斯半径(σ)对曲线形状的影响,σ越小,曲线越高越尖,σ越大,曲线越低越平缓。因此高斯半径越小,则模糊越小,高斯半径越大,则模糊程度越大。
模版矩阵的大小一般设为 ( 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);
}