第四课 滤波方式
滤波是过滤图片数据中的噪声,换种说法就是用一些巧妙的计算方法去改变图像矩阵的数值,从而使图像改变状态。
这里以均值滤波为例,均值滤波(即为图片马赛克效果)就是定义了一个自定大小的内核矩阵,在一张1024*960像素大小的图片中,对九十多万个像素点进行运算,当内核矩阵为3x3时,即对矩形范围内的9个像素点的色彩通道等数据取均值,将矩形范围内的九个像素点的值一致化。当这个内核矩阵的边值较小时,图像处理后的效果即为简单的模糊,内核矩阵的边值足够大时,多个像素点的内值一致化,人眼就可看出马赛克的效果。对于高斯滤波、双边滤波、中指滤波等滤波方式,其运算过程也不尽相同,只是内核矩阵可能不同,运算方式可能不同。
对于上面的长篇大论也许不用太深究,当满足实际工程需要时,查找一下各种滤波方式的运算方式即可,比如均值滤波是马赛克效果,高斯滤波是模糊效果。行了废话不多说,下面是示例代码,函数声明以及相关注释代码中都很详细。
#include <opencv2/core/core.hpp>
#include<opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <iostream>
using namespace std;
using namespace cv;
//-----------------------------------【全局变量声明部分】--------------------------------------
Mat g_srcImage, g_dstImage1, g_dstImage2, g_dstImage3,g_dstImage4, g_dstImage5;//存储图片的Mat类型
int g_nBoxFilterValue = 3; //方框滤波参数值
int g_nMeanBlurValue = 3; //均值滤波参数值
int g_nGaussianBlurValue = 3; //高斯滤波参数值
int g_nMedianBlurValue = 10; //中值滤波参数值
int g_nBilateralFilterValue = 10; //双边滤波参数值
//-----------------------------------【全局函数声明部分】--------------------------------------
//轨迹条的回调函数如下
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*); //双边滤波的回调函数
//-----------------------------------【main( )函数】--------------------------------------------
int main()
{
//改变console字体颜色
system("color 5E");
//载入原图
g_srcImage = imread("1.jpg", 1);
if (!g_srcImage.data) { printf("Oh,no,读取srcImage错误~!\n"); return false; }
//克隆原图到三个Mat类型中,尺寸类型必须一致,故直接克隆,或者参考学习程序三,定义一个黑图也可。
g_dstImage1 = g_srcImage.clone();
g_dstImage2 = g_srcImage.clone();
g_dstImage3 = g_srcImage.clone();
g_dstImage4 = g_srcImage.clone();
g_dstImage5 = g_srcImage.clone();
//显示原图
namedWindow("【<0>原图窗口】", 1);
imshow("【<0>原图窗口】", g_srcImage);
//=================【<1>方框滤波】==================
//创建窗口
namedWindow("【<1>方框滤波】", 1);
//创建轨迹条
createTrackbar("内核值:", "【<1>方框滤波】", &g_nBoxFilterValue, 40, on_BoxFilter);
on_MeanBlur(g_nBoxFilterValue, 0);//回调函数
imshow("【<1>方框滤波】", g_dstImage1);
//================================================
//=================【<2>均值滤波】==================
//创建窗口
namedWindow("【<2>均值滤波】", 1);
//创建轨迹条
createTrackbar("内核值:", "【<2>均值滤波】", &g_nMeanBlurValue, 40, on_MeanBlur);
on_MeanBlur(g_nMeanBlurValue, 0);
//================================================
//=================【<3>高斯滤波】=====================
//创建窗口
namedWindow("【<3>高斯滤波】", 1);
//创建轨迹条
createTrackbar("内核值:", "【<3>高斯滤波】", &g_nGaussianBlurValue, 40, on_GaussianBlur);
on_GaussianBlur(g_nGaussianBlurValue, 0);
//================================================
//=================【<4>中值滤波】===========================
//创建窗口
namedWindow("【<4>中值滤波】", 1);
//创建轨迹条
createTrackbar("参数值:", "【<4>中值滤波】", &g_nMedianBlurValue, 50, on_MedianBlur);
on_MedianBlur(g_nMedianBlurValue, 0);
//=======================================================
//=================【<5>双边滤波】===========================
//创建窗口
namedWindow("【<5>双边滤波】", 1);
//创建轨迹条
createTrackbar("参数值:", "【<5>双边滤波】", &g_nBilateralFilterValue, 50, on_BilateralFilter);
on_BilateralFilter(g_nBilateralFilterValue, 0);
//=======================================================
//输出一些帮助信息
cout << endl << "\t嗯。好了,请调整滚动条观察图像效果~\n\n"
<< "\t按下“q”键时,程序退出~!\n"
//按下“q”键时,程序退出
while (char(waitKey(1)) != 'q') {}
return 0;
}
//-----------------------------【on_BoxFilter( )函数】------------------------------------
// 描述:方框滤波操作的回调函数
//-----------------------------------------------------------------------------------------------
static void on_BoxFilter(int, void*)
{
//方框滤波操作
boxFilter(g_srcImage, g_dstImage1, -1, Size(g_nBoxFilterValue + 1, g_nBoxFilterValue + 1));
/*函数参数对应:原图像;目标图像;输出图像的深度,-1代表使用原图深度;Size(w,h)来表示内核的大小(其中,w为像素宽度,h为像素高度)ksize.width和ksize.height可以不同,但他们都必须为正数和奇数。或者,它们可以是零的
这里+10后,当内核值调整为0,仍有内核值为9的滤波效果*/
/*此处的函数参数与均值滤波一致,后面省略了两个参数*/
/*第四个参数,表示锚点(即被平滑的那个点),默认值Point(-1,-1)。如果这个点坐标是负值的话,就表示取核的中心为锚点,所以默认值Point(-1,-1)表示这个锚点在核的中心。
第五个参数,int类型的borderType,用于推断图像外部像素的某种边界模式。有默认值BORDER_DEFAULT,我们一般不去管它。*/
//显示窗口
imshow("【<1>方框滤波】", g_dstImage1);
}
//-----------------------------【on_MeanBlur( )函数】------------------------------------
// 描述:均值滤波操作的回调函数
//-----------------------------------------------------------------------------------------------
static void on_MeanBlur(int, void*)
{
//均值滤波操作
blur(g_srcImage, g_dstImage2, Size(g_nMeanBlurValue + 1, g_nMeanBlurValue + 1), Point(-1, -1));
//显示窗口
imshow("【<2>均值滤波】", g_dstImage2);
}
//-----------------------------【on_GaussianBlur( )函数】------------------------------------
// 描述:高斯滤波操作的回调函数
//-----------------------------------------------------------------------------------------------
static void on_GaussianBlur(int, void*)
{
//高斯滤波操作
GaussianBlur(g_srcImage, g_dstImage3, Size(g_nGaussianBlurValue * 2 + 1, g_nGaussianBlurValue * 2 + 1), 0, 0);
/*前三个参数一致
第四个参数,double类型的sigmaX,表示高斯核函数在X方向的的标准偏差。
第五个参数,double类型的sigmaY,表示高斯核函数在Y方向的的标准偏差。若sigmaY为零,就将它设为sigmaX,如果sigmaX和sigmaY都是0,那么就由ksize.width和ksize.height计算出来。
为了结果的正确性着想,最好是把第三个参数Size,第四个参数sigmaX和第五个参数sigmaY全部指定到。
第六个参数,int类型的borderType,用于推断图像外部像素的某种边界模式。注意它有默认值BORDER_DEFAULT。*/
//显示窗口
imshow("【<3>高斯滤波】", g_dstImage3);
}
//-----------------------------【on_MedianBlur( )函数】------------------------------------
// 描述:中值滤波操作的回调函数
//-----------------------------------------------------------------------------------------------
static void on_MedianBlur(int, void*)
{
medianBlur(g_srcImage, g_dstImage4, g_nMedianBlurValue * 2 + 1);
/*参数详解:
第一个参数,InputArray类型的src,函数的输入参数,填1、3或者4通道的Mat类型的图像;当ksize为3或者5的时候,图像深度需为CV_8U,CV_16U,或CV_32F其中之一,而对于较大孔径尺寸的图片,它只能是CV_8U。
第二个参数,OutputArray类型的dst,即目标图像,函数的输出参数,需要和源图片有一样的尺寸和类型。我们可以用Mat::Clone,以源图片为模板,来初始化得到如假包换的目标图。
第三个参数,int类型的ksize,孔径的线性尺寸(aperture linear size),注意这个参数必须是大于1的奇数,比如:3,5,7,9 ...*/
imshow("【<4>中值滤波】", g_dstImage4);
}
//-----------------------------【on_BilateralFilter( )函数】------------------------------------
// 描述:双边滤波操作的回调函数
//-----------------------------------------------------------------------------------------------
static void on_BilateralFilter(int, void*)
{
bilateralFilter(g_srcImage, g_dstImage5, g_nBilateralFilterValue, g_nBilateralFilterValue * 2, g_nBilateralFilterValue / 2);
/*第一个参数,InputArray类型的src,输入图像,即源图像,需要为8位或者浮点型单通道、三通道的图像。
第二个参数,OutputArray类型的dst,即目标图像,需要和源图片有一样的尺寸和类型。
第三个参数,int类型的d,表示在过滤过程中每个像素邻域的直径。如果这个值我们设其为非正数,那么OpenCV会从第五个参数sigmaSpace来计算出它来。
第四个参数,double类型的sigmaColor,颜色空间滤波器的sigma值。这个参数的值越大,就表明该像素邻域内有更宽广的颜色会被混合到一起,产生较大的半相等颜色区域。
第五个参数,double类型的sigmaSpace坐标空间中滤波器的sigma值,坐标空间的标注方差。他的数值越大,意味着越远的像素会相互影响,从而使更大的区域足够相似的颜色获取相同的颜色。当d>0,d指定了邻域大小且与sigmaSpace无关。否则,d正比于sigmaSpace。
第六个参数,int类型的borderType,用于推断图像外部像素的某种边界模式。注意它有默认值BORDER_DEFAULT。*/
imshow("【<5>双边滤波】", g_dstImage5);
}