滤波器是根据原有图像的某个像素的周围像素来确定新的像素值,滤波器主要的作用是用来消去噪声的,消除图像中的不合理的像素点。滤波器主要包括线性滤波器和非线性滤波器,其中线性滤波器包括均值滤波,方框滤波和高斯滤波,非线性的主要是中值滤波。主要介绍一下滤波器的原理和Opencv使用语法。
- 滤波器的概念
- 线性滤波器
- 方框滤波
- 均值滤波
- 高斯滤波
- 非线性滤波器
滤波器的概念
在介绍滤波器的概念之前首先说明一下线性卷积的概念,设I和I’是二维函数,I(u,v)表示像素点(u,v)代表的像素值,H为一个二维函数,线性卷积操作的定义如下:
I′(u,v)=∑i=−∞∞∑j=−∞∞I(u−i,v−j)⋅H(i,j)
新图像的像素值I’(u,v)是由旧像素的所有周围像素及本身像素与其权重H(i,j)乘积的和,如果H(i,j)只在某个范围内取到值,而在其他范围内值均为0,那么对每个像素来说,对于其新像素的值,只有特定范围的相邻像素贡献了值,在这里,H(i,j)就可以被称为滤波器的核或者滤波矩阵,这个过程描述的是线性滤波器的原理,对于非线性滤波器,后面会有相应的介绍。
线性滤波器
方框滤波
假设我们采用滤波器核的大小为L*W(L=3,W=3),方框滤波采用的滤波矩阵如下
K=a⎡⎣⎢111111111⎤⎦⎥
这里a有两个取值
a={1L⋅M1
在第一种情况下,方框滤波即为均值滤波,下面介绍一下opencv提供的方框滤波的方法
void boxFilter(InputArray src,OutputArray dst,int depth,Size ksize,Point anchor=Point(-1,-1),bool normalize=true,int borderType=BORDER_DEFAULT)
boxFilter的参数说明
参数名 | 说明 |
src | 输入图像 |
dst | 输出图像 |
depth | 图像的深度,负值则为输入图像的深度 |
ksize | 滤波核的大小(K*M) |
anchor | 锚点,表示需要被重新生成像素的点,默认为(-1,-1),即为滤波核的中心点 |
normalize | 是否归一化,表示a的取值,false取1,true的话跟均值滤波相同 |
borderType | 边界模式 |
下面的这段代码实现了读取文件,并且进行方框滤波,并且展示
#include <iostream>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
using namespace std;
using namespace cv;
int main(){
Mat src,dst;
src=imread("测试.jpg"); //读取测试文件
boxFilter(src,dst,-1,Size(3,3)); //选择3*3的滤波器大小
namedWindow("方框滤波",WINDOW_NORMAL);
imshow("方框滤波",dst); //显示文件
waitKey(6000);
return 0;
}
原图像为
滤波操作之后的图像
可以看出来方框滤波之后的图像明显比原来的图片噪声减少了,但是很明显,整个图像变得模糊了,因为每个像素的值都是由其周围像素的均值得来,因此边缘和轮廓会更不清晰。
均值滤波
均值滤波在前面说过,当方框滤波的normalize取为true,即为均值滤波,但同时opencv提供了专门的均值滤波函数。
void blur(InputArray src, OutputArray dst, Size ksize,Point anchor=Point(-1,-1),int borderType=BORDER_DEFAULT)
blur方法的参数说明
参数名 | 说明 |
src | 输入图像 |
dst | 输出图像 |
ksize | 滤波核的大小(K*M) |
anchor | 锚点,表示需要被重新生成像素的点,默认为(-1,-1),即为滤波核的中心点 |
borderType | 边界模式 |
blur方法的代码只需要把前面的代码段中的boxFilter方法更改为blur方法即可。
高斯滤波
高斯滤波采用的滤波矩阵为根据二维高斯函数生成的高斯矩阵
H(i,j)=e−i2÷j22σ2
其中
σ表示的函数的宽度(标准差)—具体高斯函数的解释请查阅相关数学书,我也不太懂。。。
Opencv提供的高斯滤波的方法为
void GaussianBlur(InputArray src,OutputArray dst,Size ksize,double sigmaX,double sigmaY=0,int borderType=BORDER_DEFAULT)
GaussianBlur方法的参数说明
参数名 | 说明 |
src | 输入图像 |
dst | 输出图像 |
ksize | 滤波核的大小(K*M) |
sigmaX | 高斯函数在X方向的标准差 |
sigmaY | 高斯函数在Y方面的标准差,若sigmaX=sigmaY=0,那么标准差将根据ksize的大小计算得到 |
borderType | 边界模式 |
代码只需要把第一段的boxFilter改成下面的代码即可
GaussianBlur(src,dst,Size(3,3),0);
高斯滤波后的结果为
非线性滤波器
可以看到线性滤波器绝大多数把图像模糊化了,而且线性滤波有一个最大的弱点在于,如果图片中的噪声脉冲比较大(即像素值跟周围像素点差距过大),那么这个噪声并不会被消除,只是会被减弱,而且会对周围正常像素的值产生影响,这些都是因为我们采用新像素等于其周围像素线性组合得到的原因。
非线性滤波器主要是针对这种问题提出了解决方案,今天只介绍一个,叫中值滤波器,其原理为
I′(u,v)=median{I(u+i,v+j)|(i,j)∈H}
即新像素的值为滤波区域H内的所有像素值得中位数,有时候可能会做一些处理,比如说先对所有的像素值做加权,然后再去求中位数。
Oopencv提供的中值滤波方法为
void medianBlur(InputArray src,OutputArray dst,int ksize)
函数的参数说明
参数名 | 说明 |
src | 输入图像 |
dst | 输出图像 |
ksize | 滤波核孔径的大小,必须为奇数1、3、5….. |
代码的话只需要把第一个的boxFilter改成下面这句即可
medianBlur(src,dst,3);
中值滤波的图像为
可以看到中值滤波之后的结果是最理想的,而且图像模糊程度并没有非线性那么厉害,如果噪声的脉冲比较大,分布比较密集,可以采用中值滤波去除噪声。