OpenCV中提供了三种常用的线性滤波函数,它们分别是方框滤波,均值滤波和高斯滤波。
均值滤波从频域来看,它是一种低通滤波器,高频信号会被滤掉。均值滤波可以帮助消除图像尖锐噪声,实现图像平滑,模糊等功能。理想的均值滤波是用每个像素和它周围像素计算出来的平均值替换图像中每个像素。
均值滤波器一般是使用下面的模板和图像做卷积来实现。
即以当前像素点为中心,求窗口内所有灰度值的和,以其平均值作为中心像素新的灰度值。
均值滤波有平均均值滤波和加权均值滤波。分别如下所示:
左边是平均均值滤波 右边是加权均值滤波
均值滤波可以模糊图像从而得到图像的大致描述。
方框滤波和均值滤波的原理是类似的,因为均值滤波是方框滤波的归一化表现。在OpenCV中,方框滤波使用的模板如下:
从方框滤波的模板可以看到,如果α = 1,那么就是方框滤波,不进行归一化;如果α != 1那么就进行归一化操作。
以5*5的卷积核为例,如果normalize == true,那么就是均值滤波,模板如下:
如果normalize != true,那么就是计算邻域像素和,不平均,卷积核如下:
百度百科是这样介绍高斯滤波的,很清晰明了。
高斯滤波是一种线性平滑滤波,适用于消除高斯噪声(高斯噪声是指它的概率密度函数服从高斯分布(即正态分布)的一类噪声)。高斯滤波就是对整幅图像进行加权平均的过程,每一个像素点的值,都由其本身和邻域内的其他像素值经过加权平均后得到。高斯滤波的具体操作是:用一个模板(或称卷积、掩模)扫描图像中的每一个像素,用模板确定的邻域内像素的加权平均灰度值去替代模板中心像素点的值。
一维高斯分布
通常我们在使用的时候都取标准正态分布。这时候
以3*3的模板为例,给出高斯滤波的卷积核
从卷积核可以看到,每一个像素点的权值不是全部相同的。更突出了中心点在像素平滑后的权重,相比于均值滤波而言,有着更好的平滑效果。
介绍完了方框滤波,均值滤波和高斯滤波的原理之后,我们来看看OpenCV提供的实现滤波的API。
首先介绍filter2D函数,这个函数需要给出卷积核即可实现各种滤波操作。
//filter2D函数原型
void filter2D( InputArray src, OutputArray dst, int ddepth,
InputArray kernel, Point anchor = Point(-1,-1),
double delta = 0, int borderType = BORDER_DEFAULT );
参数1:输入图像
参数2:输出图像
参数3:图像深度(指存储每个像素所用的位数),如果没写将生成与原图像深度相同的图像。当ddepth输入值为-1时,目标图像和原图像深度保持一致。
参数4:卷积核
参数5:卷积基准点(默认值为Point(-1,-1)表示取卷积中心即锚点)。
参数6:在储存目标图像前可选的添加到像素的值,默认值为0。一般不用
参数7: 像素向外逼近的方法,默认值是BORDER_DEFAULT,即对全部边界进行计算。
//boxFilter函数原型
void boxFilter( InputArray src, OutputArray dst, int ddepth,
Size ksize, Point anchor = Point(-1,-1),
bool normalize = true,
int borderType = BORDER_DEFAULT );
参数1:输入图像;
参数2:输出图像;
参数3:图像深度(指存储每个像素所用的位数),如果没写将生成与原图像深度相同的图像。当ddepth输入值为-1时,目标图像和原图像深度保持一致。
参数4:Size类型的ksize,卷积核的大小。一般这样写Size( w,h )来表示卷积核的大小( 其中,w 为像素宽度, h为像素高度)。Size(3,3)就表示3x3的核大小,Size(5,5)就表示5x5的核大小;
参数5:卷积基准点(默认值为Point(-1,-1)表示取卷积中心即锚点)。
参数6:默认值为true,根据上面讲述的原理,也就是默认归一化。
参数7: 像素向外逼近的方法,默认值是BORDER_DEFAULT,即对全部边界进行计算。
//blur函数原型
void blur( InputArray src, OutputArray dst,
Size ksize, Point anchor = Point(-1,-1),
int borderType = BORDER_DEFAULT );
参数1:输入图像;
参数2:输出图像;
参数3:卷积核的大小;
参数4:卷积基准点(默认值为Point(-1,-1)表示取卷积中心即锚点)。
参数5: 像素向外逼近的方法,默认值是BORDER_DEFAULT,即对全部边界进行计算。
//GaussianBlur函数原型
void GaussianBlur( InputArray src, OutputArray dst, Size ksize,
double sigmaX, double sigmaY = 0,
int borderType = BORDER_DEFAULT );
参数1:输入图像;
参数2:输出图像;
参数3:卷积核的大小;
参数4:表示高斯核函数在X方向的的标准偏差;
参数5:表示高斯核函数在Y方向的的标准偏差;如果sigmaY为零,则将其设置为等于sigmaX;如果两个都为零,则分别从ksize.width和ksize.height计算得出sigmaX和sigmaY;
参数6:像素向外逼近的方法,默认值是BORDER_DEFAULT,即对全部边界进行计算。
到此为止,需要用到的函数以及全部介绍完毕了。下面来看看实际的代码使用情况。
#include
using namespace cv;
int main()
{
//使用boxFilter函数实现方框滤波
Mat src1 = imread("C:/Users/zhou_/Desktop/1.jpg");
Mat dst1(src1.size(), src1.type());
if (!src1.data)
{
perror("load failed:");
exit(-1);
}
imshow("src1", src1);
boxFilter(src1, dst1, -1, Size(3, 3), Point(-1, -1));
imshow("方框滤波", dst1);
//同时,我们使用filter2D函数来实现模板是3*3的均值滤波
Mat dst11;
Mat kernel = (Mat_(3, 3) << \
1, 1, 1, \
1, 1, 1, \
1, 1, 1);
kernel /= 9; //归一化变换核,保持图像亮度不变
filter2D(src1, dst11, -1, kernel);
imshow("使用filter2D实现均值滤波", dst11);
//均值滤波是方框滤波归一化后的特殊情形
Mat blurresult;
blur(src1, blurresult, Size(3, 3));
imshow("使用blur实现均值滤波", blurresult);
//高斯滤波
Mat dst2;
GaussianBlur(src1, dst2, Size(3, 3), 0, 0);
imshow("使用GaussianBlur实现高斯滤波", dst2);
Mat dst22;
kernel = (Mat_(3, 3) << \
1, 2, 1, \
2, 4, 2, \
1, 2, 1);
kernel /= 16;
filter2D(src1, dst22, -1, kernel);
imshow("使用filter2D实现高斯滤波", dst22);
waitKey(0);
return 0;
}
结果如下所示:
可以看到使用filter2D函数和Blur函数实现的效果是一样的。另外当方框滤波的卷积核大小和均值滤波一致并且归一化时,两者的效果也是一样的,所以上面三幅图像处理的效果时相同的。
使用filter2D和GaussianBlur的结果也是一样的。
另外,也可以看到均值滤波对于图像的模糊程度比高斯滤波要严重。