在这个教程中你将学会怎么使用OpenCV的函数去应用各种不同的滤波器去平滑图像,例如:
blur
GaussianBlur
medianBlur
bilateralFilter
理论:
平滑,也叫模糊,是一种简单也经常被使用的图像处理操作;
平滑的原因有很多。在这个教程中我们将主要集中在为了减少噪音而平滑(其他的平滑方法将在接下来的教程中看到);
去达到平滑效果我们将对我们的图像应用一个滤波器。最常见的滤波器类型是线性滤波器,这种滤波器输出图像的像素是由输入图像像素的权重之和决定的:
其中h(k,l)被叫做核,它就是滤波器的系数。
为了便于可视化,一个滤波器就像一个核窗口在图像上滑过。
有很多种的滤波器,这里将介绍一些最常用的。
第一种是低通滤波器:
这种滤波器是最简单的,每个输出像素都是它的核周围像素的平均值(所有领域内的像素的权重都一样)。
这种核就是下面这种:
第二种就是高斯滤波器:
这可能是最常用的滤波器(尽管并不是最快的)。高斯滤波器通过求输入数组中的每一个点的卷积然后把他们求和去产生新的输出数组来完成平滑。
仅仅为了图像更加清晰,记住一维高斯核是什么样子。
假设图像是一维的,你可以注意到在中间的像素占的权重最大。周围像素的权重随着他们和中心像素的空间距离的增加而减少。
注意二维高斯滤波器可以被下面的公式表示
其中u是平均值(峰值)并且分母代表偏差。
第三种是中值滤波器:
中值滤波器扫描图像的每一个像素,并且以每个像素所有领域内的点的中间值去取代该像素值。
第四种是双向滤波器:
到这里为止,我们已经讲解了一些滤波器,他们的主要目标是去平滑输入图像。然而,有时候滤波器不仅仅要去处理噪音,还要去平滑掉边缘。为了避免这个(至少从某种程度上),我们可以使用一种双边滤波器。
类似于高斯滤波器的方式,双边滤波器也通过赋予领域内的像素的权重来衡量他们。这些权重有两个组成部分,第一个是使用高斯滤波器一样的权重,第二种就考虑到了在领域像素和要评估像素之间的紧密程度的不同。
代码:
/*******************************************************
** Translator:York.
** Email:1508108492@qq.com
** Date:2016/03/07
********************************************************/
#include<imgproc\imgproc.hpp>
#include<highgui.h>
using namespace std;
using namespace cv;
/// Global Variables
int DELAY_CAPTION = 1500;
int DELAY_BLUR = 100;
int MAX_KERNEL_LENGTH = 31;
Mat src; Mat dst;
char window_name[] = "Filter Demo 1";
/// Function headers
int display_caption(char* caption);
int display_dst(int delay);
/**
* function main
*/
int main(int argc, char** argv)
{
namedWindow(window_name, CV_WINDOW_AUTOSIZE);
/// Load the source image
src = imread("F:/Photo/OpenCV_Photo/lena.jpg", 1);
if (display_caption("Original Image") != 0) { return 0; }
dst = src.clone();
if (display_dst(DELAY_CAPTION) != 0) { return 0; }
/// Applying Homogeneous blur
if (display_caption("Homogeneous Blur") != 0) { return 0; }
for (int i = 1; i < MAX_KERNEL_LENGTH; i = i + 2)
{
blur(src, dst, Size(i, i), Point(-1, -1));
if (display_dst(DELAY_BLUR) != 0) { return 0; }
}
/// Applying Gaussian blur
if (display_caption("Gaussian Blur") != 0) { return 0; }
for (int i = 1; i < MAX_KERNEL_LENGTH; i = i + 2)
{
GaussianBlur(src, dst, Size(i, i), 0, 0);
if (display_dst(DELAY_BLUR) != 0) { return 0; }
}
/// Applying Median blur
if (display_caption("Median Blur") != 0) { return 0; }
for (int i = 1; i < MAX_KERNEL_LENGTH; i = i + 2)
{
medianBlur(src, dst, i);
if (display_dst(DELAY_BLUR) != 0) { return 0; }
}
/// Applying Bilateral Filter
if (display_caption("Bilateral Blur") != 0) { return 0; }
for (int i = 1; i < MAX_KERNEL_LENGTH; i = i + 2)
{
bilateralFilter(src, dst, i, i * 2, i / 2);
if (display_dst(DELAY_BLUR) != 0) { return 0; }
}
/// Wait until user press a key
display_caption("End: Press a key!");
waitKey(0);
return 0;
}
int display_caption(char* caption)
{
dst = Mat::zeros(src.size(), src.type());
putText(dst, caption,
Point(src.cols / 4, src.rows / 2),
CV_FONT_HERSHEY_COMPLEX, 1, Scalar(255, 255, 255));
imshow(window_name, dst);
int c = waitKey(DELAY_CAPTION);
if (c >= 0) { return -1; }
return 0;
}
int display_dst(int delay)
{
imshow(window_name, dst);
int c = waitKey(delay);
if (c >= 0) { return -1; }
return 0;
}
解释:
1、 我们来看看涉及到平滑的部分OpenCV函数:
2、 低通滤波:
OpenCV提供了blur()函数来用这种滤波器平滑:
blur( src, dst, Size( i, i ), Point(-1,-1) );
blur函数有4个参数:其中Size(w,h)是核的尺寸,Point(-1,-1)显示要评估的店相对于领域内的位置。如果是一个负数的话就把核的中心当作为要评估的点。
3、 高斯滤波器:GaussianBlur
GaussianBlur(src, dst, Size( i, i ), 0, 0 );
有四个参数,Size(w,h)同样的是核的尺寸。注意w,h必须是奇数并且是正数,否则将用sigma_{x}和sigma_{y}来计算。
Sigmax和sigmay表示两个的标准差,如果是0的话就表示标准差使用核的尺寸计算。
4、 中值滤波
medianBlur ( src, dst, i );
其中i是核的尺寸(因为是方形所以只有一个尺寸参数),必须是奇数。
5、双边滤波:
bilateralFilter( src, dst, i, i*2, i/2 );
其中d表示每个像素领域的直径,1*2表示颜色空间中的标准差,i/2表示是坐标空间的标准差(从像素的角度来看)。