高斯滤波是一种线性平滑滤波,适用于消除高斯噪声,广泛应用于图像处理的减噪过程。通俗的讲,高斯滤波就是对整幅图像进行加权平均的过程,每一个像素点的值,都由其本身和邻域内的其他像素值经过加权平均后得到。高斯滤波的具体操作是:用一个模板(或称卷积、掩模)扫描图像中的每一个像素,用模板确定的邻域内像素的加权平均灰度值去替代模板中心像素点的值。
高斯滤波(Gauss filter)实质上是一种信号的滤波器,其用途为信号的平滑处理,数字图像用于后期应用,其噪声是最大的问题,因为误差会累计传递等原因,大多图像处理教材会在很早的时候介绍Gauss滤波器,用于得到信噪比SNR较高的图像(反应真实信号)。高斯平滑滤波器对于抑制服从正态分布的噪声非常有效。
下面我们来看一下高斯函数:
这是一维的
这是二维的
一维函数图
二维函数图
我们对图像进行处理时,我们需要取一块区域(一般是3*3的像素点图)。以这个矩形的中心为原点,去任意的运sigma,用上面的二维高斯函数我们可以求出这个3*3区域每个点的权值(权值相加之和为1)
比如我们取sigma为1.5
我们运行一下代码求出3*3矩阵的权值数组
double arr[3][3];
double sum = 0.0;
double sigma = 1.5;
for (int i = 0; i < 3; ++i)
for (int j = 0; j < 3; ++j)
sum += arr[i][j] = exp(-((i - 1)*(i - 1) + (j - 1)*(j - 1)) / (2 * sigma*sigma));
for (int i = 0; i < 3; ++i)
for (int j = 0; j < 3; ++j)
arr[i][j] /= sum;
for (int i = 0; i < 3; ++i) {
for (int j = 0; j < 3; ++j)
cout << arr[i][j] << " ";
cout << endl;
}
这是运行结果
如果我们改变sigma为0.5:
可以看见当sigma为0.5时,越靠近中间的值越大,我们在进行高斯滤波处理时就可以选择不同的sigma的值来对图像进行相应的操作。值越大图像越模糊。
下面我们进行图像操作示例:
首先编写我们自己的高斯滤波器,然后导入我们要进行处理的图像并椒盐化,接着分别用openCV自带的高斯滤波器以及我们自己编写的高斯滤波器来看看有什么不同。
double **getGuassionArray(int size,double sigma) {
int i, j;
double sum = 0.0;
int center = size; //以第一个点的坐标为原点,求出中心点的坐标
double **arr = new double*[size];//建立一个size*size大小的二维数组
for (i = 0; i < size; ++i)
arr[i] = new double[size];
for (i = 0; i < size; ++i)
for (j = 0; j < size; ++j) {
arr[i][j] = exp(-((i - center)*(i - center) + (j - center)*(j - center)) / (sigma*sigma * 2));
sum += arr[i][j];
}
for (i = 0; i < size; ++i)
for (j = 0; j < size; ++j)
arr[i][j] /= sum;
return arr;
}
void myGaussian(const Mat _src, Mat &_dst) {
if (!_src.data) return;
double **arr;
Mat tmp(_src.size(), _src.type());
for (int i = 0; i < _src.rows; ++i)
for (int j = 0; j < _src.cols; ++j) {
//边缘不进行处理
if ((i - 1) > 0 && (i + 1) < _src.rows && (j - 1) > 0 && (j + 1) < _src.cols) {
arr = getGuassionArray(3, 1);//自定义得到的权值数组
tmp.at<Vec3b>(i, j)[0] = 0;
tmp.at<Vec3b>(i, j)[1] = 0;
tmp.at<Vec3b>(i, j)[2] = 0;
for (int x = 0; x < 3; ++x) {
for (int y = 0; y < 3; ++y) {
tmp.at<Vec3b>(i, j)[0] += arr[x][y] * _src.at<Vec3b>(i + 1 - x, j + 1 - y)[0];
tmp.at<Vec3b>(i, j)[1] += arr[x][y] * _src.at<Vec3b>(i + 1 - x, j + 1 - y)[1];
tmp.at<Vec3b>(i, j)[2] += arr[x][y] * _src.at<Vec3b>(i + 1 - x, j + 1 - y)[2];
}
}
}
}
tmp.copyTo(_dst);
}
void main() {
Mat image = imread("路飞.jpg");
Mat salt_image;
image.copyTo(salt_image);
Mat _gaussian;
Mat image1;
salt(salt_image, 1000);
myGaussian(salt_image, _gaussian);
GaussianBlur(salt_image, image1, Size(3, 3), 1);
imshow("原图", image);
imshow("椒盐化图", salt_image);
imshow("opencv自带的高斯滤波", image1);
imshow("自定义高斯滤波", _gaussian);
waitKey();
}
可以看到openCV的高斯滤波器与自己编写的处理效果是差不多的,即便我们在改变sigma值之后处理后图像依然看不出有很大的差别,说明我们的编写算是成功了。