滤波器是根据原有图像的某个像素的周围像素来确定新的像素值,滤波器主要的作用是用来消去噪声的,消除图像中的不合理的像素点。滤波器主要包括线性滤波器和非线性滤波器,其中线性滤波器包括均值滤波,方框滤波和高斯滤波,非线性的主要是中值滤波。主要介绍一下滤波器的原理和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;
}

原图像为

opencv Wiener opencv wiener滤波_opencv


滤波操作之后的图像

opencv Wiener opencv wiener滤波_均值滤波_02


可以看出来方框滤波之后的图像明显比原来的图片噪声减少了,但是很明显,整个图像变得模糊了,因为每个像素的值都是由其周围像素的均值得来,因此边缘和轮廓会更不清晰。

均值滤波

均值滤波在前面说过,当方框滤波的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);

高斯滤波后的结果为

opencv Wiener opencv wiener滤波_opencv_03

非线性滤波器

可以看到线性滤波器绝大多数把图像模糊化了,而且线性滤波有一个最大的弱点在于,如果图片中的噪声脉冲比较大(即像素值跟周围像素点差距过大),那么这个噪声并不会被消除,只是会被减弱,而且会对周围正常像素的值产生影响,这些都是因为我们采用新像素等于其周围像素线性组合得到的原因。

非线性滤波器主要是针对这种问题提出了解决方案,今天只介绍一个,叫中值滤波器,其原理为


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);

中值滤波的图像为

opencv Wiener opencv wiener滤波_线性滤波_04

可以看到中值滤波之后的结果是最理想的,而且图像模糊程度并没有非线性那么厉害,如果噪声的脉冲比较大,分布比较密集,可以采用中值滤波去除噪声。