一、线性滤波
1.1 均值滤波
顾名思义,对目标像素以及周围像素求均值代替原像素值,下图为一个3×3的滤波模板
代码语言:javascript复制void cv::boxFilter(
InputArray src,
OutputArray dst,
Int ddepth, //输出图像的深度(例如CV_8U),设为-1时表示与源图像保持一致
cv::Size ksize, //滤波器尺寸
cv::Point anchor = cv::Point(-1,-1), //核在滤波器的位置,默认在中间
bool nomalize = true,
int borderType = cv::BORDER_DEFAULT
)
1.2 高斯滤波
最常用的滤波
先说一下高斯噪声:
高斯噪声:
高斯噪声是指幅值的概率密度函数服从高斯分布的噪声,如果其功率谱密度服从均匀分布,则为高斯白噪声。
数字图像中的高斯噪声的主要来源出现在采集期间。 由于不良照明和/或高温引起的传感器噪声。在数字图像处理中,可以使用空间滤波器来降低高斯噪声,但是当对图像进行平滑时,结果可能导致精细缩放的图像边缘和细节的模糊,因为它们也对应于被阻挡的高频。
高斯函数: 如图为一个二维高斯函数
空间域的高斯滤波是采用离散化窗口(卷积核)滑动图像进行卷积操作,而频域中需要进行傅里叶变换,一般均为空间域操作。
高斯滤波相比于均值滤波就是对图像求平均时进行了加权,且加权系数随着远离核中心而减小。
下图为一个高斯滤波模板
(1)二维高斯函数具有旋转对称性,即滤波器在各个方向上的平滑程度是相同的.一般来说,一幅图像的边缘方向是事先不知道的,因此,在滤波前是无法确定一个方向上比另一方向上需要更多的平滑.旋转对称性意味着高斯平滑滤波器在后续边缘检测中不会偏向任一方向.
(2)高斯函数是单值函数.这表明,高斯滤波器用像素邻域的加权均值来代替该点的像素值,而每一邻域像素点权值是随该点与中心点的距离单调增减的.这一性质是很重要的,因为边缘是一种图像局部特征,如果平滑运算对离算子中心很远的像素点仍然有很大作用,则平滑运算会使图像失真.
(3)高斯函数的傅立叶变换频谱是单瓣的.这一性质是高斯函数傅里叶变换等于高斯函数本身这一事实的直接推论.图像常被不希望的高频信号所污染(噪声和细纹理).而所希望的图像特征(如边缘),既含有低频分量,又含有高频分量.高斯函数傅里叶变换的单瓣意味着平滑图像不会被不需要的高频信号所污染,同时保留了大部分所需信号.
(4)高斯滤波器宽度(决定着平滑程度)是由参数σ表征的,而且σ和平滑程度的关系是非常简单的.σ越大,高斯滤波器的频带就越宽,平滑程度就越高(越接近均值滤波).通过调节平滑程度参数σ,可在图像特征过分模糊(过平滑)与平滑图像中由于噪声和细纹理所引起的过多的不希望突变量(欠平滑)之间取得折衷.
(5)由于高斯函数的可分离性,较大尺寸的高斯滤波器可以得以有效地实现,可分离滤波器,就是可以把多维的卷积化成多个一维卷积。具体到二维的高斯滤波,就是指先对行做一维卷积,再对列做一维卷积。这样就可以将计算复杂度从O(MMNN)降到O(2MMN),M,N分别是图像和滤波器的窗口大小。因此,二维高斯滤波的计算量随滤波模板宽度成线性增长而不是成平方增长。
OpenCV函数:
代码语言:javascript复制void cv::GaussiBlur(
InputArray src,
OutputArray dst,
Int ddepth, //输出图像的深度(例如CV_8U),设为-1时表示与源图像保持一致
cv::Size ksize, //滤波器尺寸
double sigmaX, //x方向上的高斯标准差
double sigmaY = 0.0 //y方向的标准差,只给的x方向,y方向为0(默认)时,则y将等于x
int borderType = cv::BORDER_DEFAULT
)
二、非线性滤波
2.1 中值滤波
将每个像素替换成其周围所有像素中的“中位”像素,对于值较为异常(过大或过小)的孤立点由很好的消除作用,例如椒盐噪声,高斯滤波和均值滤波无法很好的消除椒盐噪声,只能使其一定程度上柔化。使用中值滤波能够得到比较好的滤波效果
因为是非线性的,所以不能显式的表示其模板。
OpenCV函数:
代码语言:javascript复制medianBlur(inputArray src,OutputArray dst,int ksize);
2.2 双边滤波
高斯滤波是只考虑像素的空间位置(距离中心的欧氏距离)来确定其加权系数,因此高斯滤波会破坏边缘信息,模糊了图像边缘。双边滤波则是在高斯滤波的基础上考虑灰度(色彩)强度差来对权值进行修正。
权值由两部分组成,一部分为等同于高斯滤波的权值(坐标空间);第二部分也是高斯权重的形式,但是将高斯权重中的距离差替换成了灰度强度差(颜色空间),其表示公式如下:
其中k,l为模板中心坐标,i,j为模板其它位置,d(i,j,k,l) 和r(i,j,k,l)分别为上述所说的第一部分和第二部分,其相乘结果为式中右侧的形式,f(x,y)表示在(x,y)处的灰度值,sigma_d和sigma_r分别表示坐标空间与颜色空间的高斯标准差。
注:一般来说,不一定非要使用高斯函数的形式,只是OpenCV中双边滤波实现使用了高斯分布函数
OpenCV函数:
代码语言:javascript复制void cv::bilateralFilter(
InputArray src,
OutputArray dst,
Int d, //像素邻域的直径
double sigmaColor, //颜色空间的标准差
double sigmaSpace, //坐标空间标准差
int borderType = cv::BORDER_DEFAULT
)
d 的大小对算法效率影响较大,在对快速性要求较高时一般设定为不大于5的值。
实验代码以及结果
代码语言:javascript复制int main()
{
Mat src = imread("../Images/9.jpg");
if (src.empty()) { cout << "read the image failed!!!!!!" << endl; return -1; }
//Mat GaussianNoiseImage = addGaussianNoise(src); //添加高斯噪声,此函数需要自己实现,opencv3没有该函数
Mat GaussianNoiseImage = src; //对噪声图片处理后展示效果不明显,遂直接对原图处理
Mat Gaussian_dst;
Mat median_dst;
Mat boxFilter_dst;
Mat bilateral_dst;
boxFilter(GaussianNoiseImage, boxFilter_dst, -1, Size(5, 5));
medianBlur(GaussianNoiseImage, median_dst,5);
GaussianBlur(GaussianNoiseImage, Gaussian_dst, Size(5, 5), 150);
bilateralFilter(GaussianNoiseImage, bilateral_dst, 5, 50, 150);
namedWindow("src", WINDOW_NORMAL);
namedWindow("GaussianNoiseImage", WINDOW_NORMAL);
namedWindow("Gaussian_dst", WINDOW_NORMAL);
namedWindow("median_dst", WINDOW_NORMAL);
namedWindow("boxFilter_dst", WINDOW_NORMAL);
namedWindow("bilateral_dst", WINDOW_NORMAL);
imshow("src", src);
imshow("GaussianNoiseImage", GaussianNoiseImage);
imshow("Gaussian_dst", Gaussian_dst);
imshow("median_dst", median_dst);
imshow("boxFilter_dst", boxFilter_dst);
imshow("bilateral_dst", bilateral_dst);
waitKey(0);
return 0;
}
下面分别为四种滤波处理结果与原图对比,左侧均为原图。