【拜小白opencv】34-图像平滑处理,6种滤波总结的综合示例【盒式滤波、均值滤波、高斯滤波、中值滤波、双边滤波、导向滤波】

常言道“温故而知新”,写此文章就是对自己目前学习内容的小小的总结与记录。

本文力求用最简洁的语言,详细的代码将此部分内容讲解清楚,但由于博主同样是刚刚接触OpenCV,或许表达上有些瑕疵,还望读者能够指教探讨,大家共同进步。

博主机器配置为:VS2013+opencv2.4.13+Win-64bit。

若本文能给读者带来一点点启示与帮助,我就很开心了。

====================分割线====================


1-图像滤波

  • 1.图像滤波,即在尽量保留图像细节特征的条件下对目标图像的噪声进行抑制,是图像预处理中不可缺少的操作,其处理效果的好坏将直接影响到后续图像处理和分析的有效性和可靠性。
  • 2.消除图像中的噪声成分叫作图像的平滑化或滤波操作。信号或图像的能量大部分集中在幅度谱的低频和中频段是很常见的,而在较高频段,感兴趣的信息经常被噪声淹没。因此一个能降低高频成分幅度的滤波器就能够减弱噪声的影响。
  • 3.平滑滤波是低频增强的空间域滤波技术。它的目的有两类:一类是模糊;另一类是消除噪音。空间域的平滑滤波一般采用简单平均法进行,就是求邻近像元点的平均亮度值。邻域的大小与平滑的效果直接相关,邻域越大平滑的效果越好,但邻域过大,平滑会使边缘信息损失的越大,从而使输出的图像变得模糊,因此需合理选择邻域的大小。
  • 4.关于滤波器,一种形象的比喻法是:我们可以把滤波器想象成一个包含加权系数的窗口,当使用这个滤波器平滑处理图像时,就把这个窗口放到图像之上,透过这个窗口来看我们得到的图像。

滤波目的

  • 1、消除图像中混入的噪声。
  • 2、为图像识别抽取出图像特征。

滤波要求

  • 1、不能损坏图像轮廓及边缘 。
  • 2、图像视觉效果应当更好。

滤波器的种类有很多, 本文结合前几节的内容,写了个综合示例,包含6种滤波方法:

盒式滤波、平滑处理1线性滤波之——盒式滤波(方框滤波)

均值滤波、平滑处理2线性滤波之——均值滤波

高斯滤波、平滑处理3线性滤波之——高斯滤波

中值滤波、平滑处理4非线性滤波之——中值滤波

双边滤波、平滑处理5非线性滤波之——双边滤波

导向滤波、平滑处理6——引导滤波/导向滤波(Guided Filter)

其中阈值量可通过滑动条来调节,下面来看看程序是如何实现的。

=======================分割线====================

2-代码演示

/*
	功能:用滚动条来控制6种滤波方式的参数值。
		  盒式滤波、均值滤波、高斯滤波、中值滤波、双边滤波、导向滤波。
*/
#include                     
#include         
#include     
#include        
using namespace std;
using namespace cv;

#define WINDOWNAME "【滤波处理结果窗口】"

//---------------【全局变量声明部分】-------------------------
Mat g_srcIamge, g_dstImage1, g_dstImage2, g_dstImage3, g_dstImage4, g_dstImage5, g_dstImage6;
int g_nBoxFilterValue = 1;//盒式滤波内核值
int g_nMeanBlurValue = 1;//均值滤波内核值
int g_nGaussianBlurValue = 1;//高斯滤波内核值
int g_nMedianBlurValue = 1;//中值滤波内核值
int g_nBilateralFilterValue = 1;//双边滤波内核值
int g_nGuidedFilterValue = 1;//导向滤波内核值
const int g_nMaxVal = 20; //预设滑动条最大值 
//--------------【全局函数声明部分】-------------------------
//轨迹条回调函数
static void on_BoxFilter(int, void*);//盒式滤波器
static void on_MeanBlur(int, void*);//均值滤波器
static void on_GaussianBlur(int, void*);//高斯滤波器
static void on_MedianBlur(int, void*);//中值滤波器
static void on_BilateralFilter(int, void*);//双边滤波器
static void on_GuidedFilter(int, void*);//导向滤波器
void guidedFilter(Mat &srcMat, Mat &guidedMat, Mat &dstImage, int radius, double eps);//导向滤波器

//----------------------------【主函数】---------------------------
int main()
{
	//------------【1】读取源图像并检查图像是否读取成功------------  
	g_srcIamge = imread("D:\\OutPutResult\\ImageTest\\boatLong.jpg");
	if (!g_srcIamge.data)
	{
		cout << "读取图片错误,请重新输入正确路径!\n";
		system("pause");
		return -1;
	}
	namedWindow("【源图像】", 1);//创建窗口
	imshow("【源图像】", g_srcIamge);//显示窗口
	//------------【2】在WINDOWNAME窗口上分别创建滤波6个滑动条------------       
	namedWindow(WINDOWNAME);//创建窗口	
	createTrackbar("方框滤波", WINDOWNAME, &g_nBoxFilterValue, g_nMaxVal, on_BoxFilter);//创建方框滤波轨迹条
	on_BoxFilter(g_nBoxFilterValue, 0);	//轨迹条的回调函数
	createTrackbar("均值滤波", WINDOWNAME, &g_nMeanBlurValue, g_nMaxVal, on_MeanBlur);//创建均值滤波轨迹条
	on_MeanBlur(g_nMeanBlurValue, 0);
	createTrackbar("高斯滤波", WINDOWNAME, &g_nGaussianBlurValue, g_nMaxVal, on_GaussianBlur);//创建高斯滤波轨迹条
	on_GaussianBlur(g_nGaussianBlurValue, 0);
	createTrackbar("中值滤波", WINDOWNAME, &g_nMedianBlurValue, g_nMaxVal, on_MedianBlur);//创建中值滤波轨迹条
	on_MedianBlur(g_nMedianBlurValue, 0);
	createTrackbar("双边滤波", WINDOWNAME, &g_nBilateralFilterValue, g_nMaxVal, on_BilateralFilter);//创建双边滤波轨迹条
	on_BilateralFilter(g_nBilateralFilterValue, 0);
	createTrackbar("导向滤波", WINDOWNAME, &g_nGuidedFilterValue, g_nMaxVal, on_GuidedFilter);//创建导向滤波轨迹条
	on_GuidedFilter(g_nGuidedFilterValue, 0);
	//------------【3】退出程序------------  
	cout << "\t按下'q'键,退出程序~!\n" << endl;
	while (char(waitKey(1)) != 'q'){}
	return 0;
}

//----------------------【on_BoxFilter()函数】------------------------
static void on_BoxFilter(int, void*)
{
	boxFilter(g_srcIamge, g_dstImage1, -1, Size(g_nBoxFilterValue * 2 + 1, g_nBoxFilterValue * 2 + 1));
	cout << "\n当前为【盒式滤波】处理效果,其内核大小为:" << g_nBoxFilterValue * 2 + 1 << endl;
	imshow(WINDOWNAME, g_dstImage1);
}
//----------------------【on_MeanBlur()函数】------------------------
static void on_MeanBlur(int, void*)
{
	blur(g_srcIamge, g_dstImage2, Size(g_nMeanBlurValue * 2 + 1, g_nMeanBlurValue * 2 + 1), Point(-1, -1));
	cout << "\n当前为【均值滤波】处理效果,其内核大小为:" << g_nMeanBlurValue * 2 + 1 << endl;
	imshow(WINDOWNAME, g_dstImage2);
}
//----------------------【on_GaussianBlur()函数】------------------------
static void on_GaussianBlur(int, void*)
{
	GaussianBlur(g_srcIamge, g_dstImage3, Size(g_nGaussianBlurValue * 2 + 1, g_nGaussianBlurValue * 2 + 1), 0, 0);
	cout << "\n当前为【高斯滤波】处理效果,其内核大小为:" << g_nGaussianBlurValue * 2 + 1 << endl;
	imshow(WINDOWNAME, g_dstImage3);
}
//----------------------【on_MedianBlur()函数】------------------------
static void on_MedianBlur(int, void*)
{
	medianBlur(g_srcIamge, g_dstImage4, g_nMedianBlurValue * 2 + 1);
	cout << "\n当前为【中值滤波】处理效果,其内核大小为:" << g_nMedianBlurValue * 2 + 1 << endl;
	imshow(WINDOWNAME, g_dstImage4);
}
//----------------------【on_BilateralFilter()函数】------------------------
static void on_BilateralFilter(int, void*)
{
	bilateralFilter(g_srcIamge, g_dstImage5, g_nBilateralFilterValue, g_nBilateralFilterValue * 2, g_nBilateralFilterValue / 2);
	cout << "\n当前为【双边滤波】处理效果,其内核大小为:" << g_nBilateralFilterValue << endl;
	imshow(WINDOWNAME, g_dstImage5);
}
//----------------------【on_GuidedFilter()函数】------------------------
static void on_GuidedFilter(int, void*)
{
	vector vSrcImage, vResultImage;
	//【1】对源图像进行通道分离,并对每个分通道进行导向滤波操作
	split(g_srcIamge, vSrcImage);
	for (int i = 0; i < 3; i++)
	{
		Mat tempImage;
		vSrcImage[i].convertTo(tempImage, CV_64FC1, 1.0 / 255.0);//将分通道转换成浮点型数据
		Mat cloneImage = tempImage.clone();	//将tempImage复制一份到cloneImage
		Mat resultImage;
		guidedFilter(tempImage, cloneImage, resultImage, g_nGuidedFilterValue * 2 + 1, 0.01);//对分通道分别进行导向滤波
		vResultImage.push_back(resultImage);//将分通道导向滤波后的结果存放到vResultImage中
	}
	//【2】将分通道导向滤波后结果合并
	merge(vResultImage, g_dstImage6);
	cout << "\n当前处理为【导向滤波】,其内核大小为:" << g_nGuidedFilterValue * 2 + 1 << endl;
	imshow(WINDOWNAME, g_dstImage6);
}

//-------------------【实现导向滤波器函数部分】-------------------------
void guidedFilter(Mat &srcMat, Mat &guidedMat, Mat &dstImage, int radius, double eps)
{
	//------------【0】转换源图像信息,将输入扩展为64位浮点型,以便以后做乘法------------
	srcMat.convertTo(srcMat, CV_64FC1);
	guidedMat.convertTo(guidedMat, CV_64FC1);
	//--------------【1】各种均值计算----------------------------------
	Mat mean_p, mean_I, mean_Ip, mean_II;
	boxFilter(srcMat, mean_p, CV_64FC1, Size(radius, radius));//生成待滤波图像均值mean_p	
	boxFilter(guidedMat, mean_I, CV_64FC1, Size(radius, radius));//生成导向图像均值mean_I	
	boxFilter(srcMat.mul(guidedMat), mean_Ip, CV_64FC1, Size(radius, radius));//生成互相关均值mean_Ip
	boxFilter(guidedMat.mul(guidedMat), mean_II, CV_64FC1, Size(radius, radius));//生成导向图像自相关均值mean_II
	//--------------【2】计算相关系数,计算Ip的协方差cov和I的方差var------------------
	Mat cov_Ip = mean_Ip - mean_I.mul(mean_p);
	Mat var_I = mean_II - mean_I.mul(mean_I);
	//---------------【3】计算参数系数a、b-------------------
	Mat a = cov_Ip / (var_I + eps);
	Mat b = mean_p - a.mul(mean_I);
	//--------------【4】计算系数a、b的均值-----------------
	Mat mean_a, mean_b;
	boxFilter(a, mean_a, CV_64FC1, Size(radius, radius));
	boxFilter(b, mean_b, CV_64FC1, Size(radius, radius));
	//---------------【5】生成输出矩阵------------------
	dstImage = mean_a.mul(srcMat) + mean_b;
}
========================分割线====================

3-显示结果

原始图像窗口,如下图:



盒式滤波/方框滤波操作,如下图:

【拜小白opencv】34-图像平滑处理,6种滤波总结的综合示例【盒式滤波、均值滤波、高斯滤波、中值滤波、双边滤波、导向滤波】_第1张图片


均值滤波操作,如下图:

【拜小白opencv】34-图像平滑处理,6种滤波总结的综合示例【盒式滤波、均值滤波、高斯滤波、中值滤波、双边滤波、导向滤波】_第2张图片


高斯滤波操作,如下图:

【拜小白opencv】34-图像平滑处理,6种滤波总结的综合示例【盒式滤波、均值滤波、高斯滤波、中值滤波、双边滤波、导向滤波】_第3张图片


中值滤波操作,如下图:

【拜小白opencv】34-图像平滑处理,6种滤波总结的综合示例【盒式滤波、均值滤波、高斯滤波、中值滤波、双边滤波、导向滤波】_第4张图片


双边滤波操作,如下图:

【拜小白opencv】34-图像平滑处理,6种滤波总结的综合示例【盒式滤波、均值滤波、高斯滤波、中值滤波、双边滤波、导向滤波】_第5张图片


导向滤波操作,如下图:

【拜小白opencv】34-图像平滑处理,6种滤波总结的综合示例【盒式滤波、均值滤波、高斯滤波、中值滤波、双边滤波、导向滤波】_第6张图片


=====================分割线==================

4-程序说明

【滤波处理结果窗口】中显示的数值并非实际内核大小,真正内核大小还请看黑窗口的提示信息。

其中前五种滤波方式:盒式滤波、均值滤波、高斯滤波、中值滤波、双边滤波,OpenCV都已封装在函数里了,我们直接调用即可,而导向滤波,是需要自己编写,然后调用即可。


为了便于观察各种滤波方式的效果优缺点,我对原图进行了处理,左边的图像是添加了椒盐噪声,而右边的图像是添加了高斯噪声,同学们可以通过滑动条调节,试试看每种滤波方式对噪声的处理结果是如何情况。


给图像添加噪声也在前几节文章中讲到,不会的同学可以去看看。

传送门:

图像噪声1——椒盐噪声

图像噪声2——高斯噪声

======================END===================

你可能感兴趣的:(【拜小白OpenCV】,一步步学习OpenCV2)