二、深入——OpenCV源码剖析
《1》OpenCV中boxFilter函数源码解析
我们可以在OpenCV的安装路径的\sources\modules\imgproc\src下的smooth.cpp源文件的第711行找到
boxFilter函数的源代码。对应于浅墨将OpenCV 2.4.8安装在D:\Program Files\opencv的路径下,那么,
smooth.cpp文件就在 D:\ProgramFiles\opencv\sources\modules\imgproc\src路径下。
//-----------------------------------【boxFilter()函数中文注释版源代
码】----------------------------
// 代码作用:进行box Filter滤波操作的函数
// 说明:以下代码为来自于计算机开源视觉库OpenCV的官方源代码
// OpenCV源代码版本:2.4.8
// 源码路径:…\opencv\sources\modules\imgproc\src\smooth.cpp
// 源文件中如下代码的起始行数:711行
// 中文注释by浅墨
//------------------------------------------------------------------------------------------
--------------
void cv::boxFilter( InputArray _src,OutputArray _dst, int ddepth,
Size ksize, Point anchor,
bool normalize, int borderType)
{
Mat src = _src.getMat();//拷贝源图的形参Mat数据到临时变量,用于稍后的操作
int sdepth =src.depth(), cn = src.channels();//定义int型临时变量,代表源图深度的sdepth,源图
通道的引用cn
//处理ddepth小于零的情况
if( ddepth 《 0 )
ddepth = sdepth;
_dst.create( src.size(), CV_MAKETYPE(ddepth, cn) );//初始化目标图
Mat dst =_dst.getMat();//拷贝目标图的形参Mat数据到临时变量,用于稍后的操作
//处理 borderType不为 BORDER_CONSTANT 且normalize为真的情况
if( borderType != BORDER_CONSTANT && normalize ){
if( src.rows == 1 )
ksize.height = 1;
if( src.cols == 1 )
ksize.width = 1;
}
//若之前有过HAVE_TEGRA_OPTIMIZATION优化选项的定义,则执行宏体中的tegra优化版函数并返回
#ifdef HAVE_TEGRA_OPTIMIZATION
if ( tegra::box(src, dst, ksize, anchor, normalize, borderType) )
return;
#endif
//调用FilterEngine滤波引擎,正式开始滤波操作
Ptr《FilterEngine》 f = createBoxFilter( src.type(), dst.type(),
ksize, anchor,normalize, borderType );
f-》apply( src, dst );
}
其中的Ptr是用来动态分配的对象的智能指针模板类。可以发现,函数的内部代码思路是很清晰的,先拷
贝源图的形参Mat数据到临时变量,定义一些临时变量,在处理ddepth小于零的情况,接着处理
borderType不为 BORDER_CONSTANT 且normalize为真的情况,最终调用FilterEngine滤波引擎创建一个
BoxFilter,正式开始滤波操作。
这里的FilterEngine是OpenCV图像滤波功能的核心引擎,我们有必要详细剖析看其源代码。
《2》FilterEngine 类解析——OpenCV图像滤波核心引擎
FilterEngine类是OpenCV关于图像滤波的主力军类,OpenCV图像滤波功能的核心引擎。各种滤波函数比如
blur, GaussianBlur,到头来其实是就是在函数末尾处定义了一个Ptr《FilterEngine》类型的f,然后f-
》apply( src, dst )了一下而已。
这个类可以把几乎是所有的滤波操作施加到图像上。它包含了所有必要的中间缓存器。有很多和滤波相关
的create系函数的返回值直接就是Ptr《FilterEngine》。比如cv::createSeparableLinearFilter(),
cv::createLinearFilter(),cv::createGaussianFilter(), cv::createDerivFilter(),
cv::createBoxFilter() 和cv::createMorphologyFilter()。,这里给出其中一个函数的原型吧:
Ptr《FilterEngine》createLinearFilter(int srcType, int dstType, InputArray kernel,
Point_anchor=Point(-1,-1), double delta=0, int rowBorderType=BORDER_DEFAULT,
intcolumnBorderType=-1, const Scalar& borderValue=Scalar() )
上面我们提到过了,其中的Ptr是用来动态分配的对象的智能指针模板类,而上面的尖括号里面的模板参
数就是FilterEngine。
使用FilterEngine类可以分块处理大量的图像,构建复杂的管线,其中就包含一些进行滤波阶段。如果我
们需要使用预先定义好的的滤波操作,cv::filter2D(), cv::erode(),以及cv::dilate(),可以选择,他
们不依赖于FilterEngine,自立自强,在自己函数体内部就实现了FilterEngine提供的功能。不像其他的
诸如我们今天讲的blur系列函数,依赖于FilterEngine引擎。
我们看下其类声明经过浅墨详细注释的源码:
//-----------------------------------【FilterEngine类中文注释版源代
码】----------------------------
// 代码作用:FilterEngine类,OpenCV图像滤波功能的核心引擎
// 说明:以下代码为来自于计算机开源视觉库OpenCV的官方源代码
// OpenCV源代码版本:2.4.8
// 源码路径:…\opencv\sources\modules\imgproc\include\opencv2\imgproc\imgproc.hpp
// 源文件中如下代码的起始行数:222行
// 中文注释by浅墨
//------------------------------------------------------------------------------------------
--------------
class CV_EXPORTS FilterEngine
{
public:
//默认构造函数
FilterEngine();
//完整的构造函数。 _filter2D 、_rowFilter 和 _columnFilter之一,必须为非空
FilterEngine(const Ptr《BaseFilter》& _filter2D,
constPtr《BaseRowFilter》& _rowFilter,
constPtr《BaseColumnFilter》& _columnFilter,
int srcType, int dstType, intbufType,
int_rowBorderType=BORDER_REPLICATE,
int _columnBorderType=-1,
const Scalar&_borderValue=Scalar());
//默认析构函数
virtual ~FilterEngine();
//重新初始化引擎。释放之前滤波器申请的内存。
void init(const Ptr《BaseFilter》& _filter2D,
constPtr《BaseRowFilter》& _rowFilter,
constPtr《BaseColumnFilter》& _columnFilter,
int srcType, int dstType, intbufType,
int_rowBorderType=BORDER_REPLICATE, int _columnBorderType=-1,
const Scalar&_borderValue=Scalar());
//开始对指定了ROI区域和尺寸的图片进行滤波操作
virtual int start(Size wholeSize, Rect roi, int maxBufRows=-1);
//开始对指定了ROI区域的图片进行滤波操作
virtual int start(const Mat& src, const Rect&srcRoi=Rect(0,0,-1,-1),
bool isolated=false, intmaxBufRows=-1);
//处理图像的下一个srcCount行(函数的第三个参数)
virtual int proceed(const uchar* src, int srcStep, int srcCount,
uchar* dst, intdstStep);
//对图像指定的ROI区域进行滤波操作,若srcRoi=(0,0,-1,-1),则对整个图像进行滤波操作
virtual void apply( const Mat& src, Mat& dst,
const Rect&srcRoi=Rect(0,0,-1,-1),
Point dstOfs=Point(0,0),
bool isolated=false);
//如果滤波器可分离,则返回true
boolisSeparable() const { return (const BaseFilter*)filter2D == 0; }
//返回输入和输出行数
int remainingInputRows() const;
intremainingOutputRows() const;
//一些成员参数定义
int srcType, dstType, bufType;
Size ksize;
Point anchor;
int maxWidth;
Size wholeSize;
Rect roi;
int dx1, dx2;
int rowBorderType, columnBorderType;
vector《int》 borderTab;
int borderElemSize;
vector《uchar》 ringBuf;
vector《uchar》 srcRow;
vector《uchar》 constBorderValue;
vector《uchar》 constBorderRow;
int bufStep, startY, startY0, endY, rowCount, dstY;
vector《uchar*》 rows;
Ptr《BaseFilter》 filter2D;
Ptr《BaseRowFilter》 rowFilter;
Ptr《BaseColumnFilter》 columnFilter;
};
《3》OpenCV中size类型剖析
size类型我们也讲一下, 通过转到定义,我们可以在……\opencv\sources\modules\core\include
\opencv2\core\core.hpp路径下,对应于浅墨的OpenCV安装路径,就是在
D:\ProgramFiles\opencv\sources\modules\core\include\opencv2\core\core.hpp下,找到其原型声明
:
typedef Size_《int》 Size2i;
typedef Size2i Size;
Size_ 是个模板类,在这里Size_《int》表示其类体内部的模板所代表的类型为int。
那这两句的意思,就是首先给已知的数据类型Size_《int》起个新名字,叫Size2i。
然后又给已知的数据类型Size2i起个新名字,叫Size。
所以,连起来就是,Size_《int》、Size2i、Size这三个类型名等价。
然后我们追根溯源,找到Size_模板类的定义:
//-----------------------------------【Size_类中文注释版源代码】----------------------------
// 代码作用:作为尺寸相关数据结构的Size_ 模板类
// 说明:以下代码为来自于计算机开源视觉库OpenCV的官方源代码
// OpenCV源代码版本:2.4.8
// 源码路径:…\opencv\sources\modules\core\include\opencv2\core\core.hpp
// 源文件中如下代码的起始行数:816行
// 中文注释by浅墨
//------------------------------------------------------------------------------------------
--------------
template《typename _Tp》 class Size_
{
public:
typedef _Tp value_type;
//不同的构造函数定义
Size_();
Size_(_Tp _width, _Tp _height);
Size_(const Size_& sz);
Size_(const CvSize& sz);
Size_(const CvSize2D32f& sz);
Size_(const Point_《_Tp》& pt);
Size_& operator = (const Size_& sz);
//区域(width*height)
_Tp area() const;
//转化另一种数据类型。
template《typename_Tp2》 operator Size_《_Tp2》() const;
//转换为旧式的OpenCV类型。
operator CvSize() const;
operator CvSize2D32f() const;
_Tp width, height; //宽度和高度,常用属性
};
可以看到Size_模板类的内部又是重载了一些构造函数以满足我们的需要,其中,我们用得最多的是如下
这个构造函数:
Size_(_Tp _width, _Tp _height);
另外,代码末尾定义了模板类型的宽度和高度:
_Tp width, height; //宽度和高度
于是我们可以用XXX. width和XXX.height来分别表示其宽度和高度。
给大家一个示例,方便理解:
Size(5, 5);//构造出的Size宽度和高度都为5,即XXX.width和XXX.height都为5
《4》OpenCV中blur函数源码剖析
我们可以在OpenCV的安装路径的\sources\modules\imgproc\src下的smooth.cpp源文件中找到blur的源代
码。对应于浅墨将OpenCV 2.4.8安装在D:\Program Files\opencv下,那么,smooth.cpp文件就在 D:
\ProgramFiles\opencv\sources\modules\imgproc\src路径下。
一起来看一下OpenCV中blur函数定义的真面目:
//-----------------------------------【blur()函数中文注释版源代码】----------------------------
// 代码作用:进行blur均值滤波操作的函数
// 说明:以下代码为来自于计算机开源视觉库OpenCV的官方源代码
// OpenCV源代码版本:2.4.8
// 源码路径:…\opencv\sources\modules\imgproc\src\smooth.cpp
// 源文件中如下代码的起始行数:738行
// 中文注释by浅墨
//------------------------------------------------------------------------------------------
--------------
void cv::blur(InputArray src, OutputArray dst,
Size ksize, Point anchor, int borderType )
{
//调用boxFilter函数进行处理
boxFilter( src, dst, -1, ksize, anchor, true, borderType );
}
可以看到在blur函数内部就是调用了一个boxFilter函数,且第六个参数为true,即我们上文所说的
normalize=true,即均值滤波是均一化后的方框滤波。
《5》OpenCV中GaussianBlur函数源码剖析
最后,我们看一下OpenCV中GaussianBlur函数源代码:
//-----------------------------------【GaussianBlur()函数中文注释版源代码】-----------------------
// 代码作用:封装高斯滤波的GaussianBlur()函数
// 说明:以下代码为来自于计算机开源视觉库OpenCV的官方源代码
// OpenCV源代码版本:2.4.8
// 源码路径:…\opencv\sources\modules\imgproc\src\smooth.cpp
// 源文件中如下代码的起始行数:832行
// 中文注释by浅墨
//------------------------------------------------------------------------------------------
--------------
void cv::GaussianBlur( InputArray _src,OutputArray _dst, Size ksize,
double sigma1, doublesigma2,
int borderType )
{
//拷贝形参Mat数据到临时变量,用于稍后的操作
Mat src = _src.getMat();
_dst.create( src.size(), src.type() );
Mat dst =_dst.getMat();
//处理边界选项不为BORDER_CONSTANT时的情况
if( borderType != BORDER_CONSTANT )
{
if( src.rows == 1 )
ksize.height = 1;
if( src.cols == 1 )
ksize.width = 1;
}
//若ksize长宽都为1,将源图拷贝给目标图
if( ksize.width == 1 && ksize.height == 1 )
{
src.copyTo(dst);
return;
}
//若之前有过HAVE_TEGRA_OPTIMIZATION优化选项的定义,则执行宏体中的tegra优化版函数并返回
#ifdef HAVE_TEGRA_OPTIMIZATION
if(sigma1 == 0 && sigma2 == 0 && tegra::gaussian(src,dst, ksize, borderType))
return;
#endif
//如果HAVE_IPP&& (IPP_VERSION_MAJOR 》= 7为真,则执行宏体中语句
#if defined HAVE_IPP &&(IPP_VERSION_MAJOR 》= 7)
if(src.type() == CV_32FC1 && sigma1 == sigma2 &&ksize.width == ksize.height && sigma1 !=
0.0 )
{
IppiSize roi = {src.cols, src.rows};
int bufSize = 0;
ippiFilterGaussGetBufferSize_32f_C1R(roi, ksize.width, &bufSize);
AutoBuffer《uchar》 buf(bufSize+128);
if( ippiFilterGaussBorder_32f_C1R((const Ipp32f *)src.data,(int)src.step,
(Ipp32f *)dst.data, (int)dst.step,
roi,ksize.width, (Ipp32f)sigma1,
(IppiBorderType)borderType, 0.0,
alignPtr(&buf[0],32)) 》= 0 )
return;
}
#endif
//调动滤波引擎,正式进行高斯滤波操作
Ptr《FilterEngine》 f = createGaussianFilter( src.type(), ksize,sigma1, sigma2, borderType
);
f-》apply( src, dst );
}
嗯,今天的源码解析就到这里吧,原理部分学完,深入OpenCV源码部分也学完,相信大家应该对OpenCV中的线性滤波有了比较详细的认识,已经跃跃欲试想看这个几个函数用起来可以得出什么效果了。
三、浅出——线性滤波函数快速上手攻略
这一部分的内容就是为了大家能快速上手 boxFilter、blur和GaussianBlur 这三个函数所准备的。还等什么呢,开始吧。
《1》boxFilter函数——方框滤波
boxFilter的函数作用是使用方框滤波(box filter)来模糊一张图片,由src输入,dst输出。
函数原型如下:
C++: void boxFilter(InputArray src,OutputArray dst, int ddepth, Size ksize, Point
anchor=Point(-1,-1), boolnormalize=true, int borderType=BORDER_DEFAULT )
参数详解如下:
第一个参数,InputArray类型的src,输入图像,即源图像,填Mat类的对象即可。该函数对通道是独立处
理的,且可以处理任意通道数的图片,但需要注意,待处理的图片深度应该为CV_8U, CV_16U, CV_16S,
CV_32F 以及 CV_64F之一。
第二个参数,OutputArray类型的dst,即目标图像,需要和源图片有一样的尺寸和类型。
第三个参数,int类型的ddepth,输出图像的深度,-1代表使用原图深度,即src.depth()。
第四个参数,Size类型的ksize,内核的大小。一般这样写Size( w,h )来表示内核的大小( 其中,w 为像
素宽度, h为像素高度)。Size(3,3)就表示3x3的核大小,Size(5,5)就表示5x5的核大小
第五个参数,Point类型的anchor,表示锚点(即被平滑的那个点),注意他有默认值Point(-1,-1)。如
果这个点坐标是负值的话,就表示取核的中心为锚点,所以默认值Point(-1,-1)表示这个锚点在核的中心
。
第六个参数,bool类型的normalize,默认值为true,一个标识符,表示内核是否被其区域归一化
(normalized)了。
第七个参数,int类型的borderType,用于推断图像外部像素的某种边界模式。有默认值BORDER_DEFAULT
,我们一般不去管它。
调用代码示范如下:
//载入原图
Matimage=imread(“2.jpg”);
//进行均值滤波操作
Matout;
boxFilter(image, out, -1,Size(5, 5));
用上面三句核心代码架起来的完整程序代码:
//-----------------------------------【头文件包含部
分】---------------------------------------
// 描述:包含程序所依赖的头文件
//------------------------------------------------------------------------------------------
----
#include “opencv2/core/core.hpp”
#include“opencv2/highgui/highgui.hpp”
#include“opencv2/imgproc/imgproc.hpp”
//-----------------------------------【命名空间声明部
分】---------------------------------------
// 描述:包含程序所使用的命名空间
//------------------------------------------------------------------------------------------
-----
using namespace cv;
//-----------------------------------【main( )函
数】--------------------------------------------
// 描述:控制台应用程序的入口函数,我们的程序从这里开始
//------------------------------------------------------------------------------------------
-----
int main( )
{
//载入原图
Matimage=imread(“2.jpg”);
//创建窗口
namedWindow(“均值滤波【原图】” );
namedWindow(“均值滤波【效果图】”);
//显示原图
imshow(“均值滤波【原图】”, image );
//进行滤波操作
Matout;
boxFilter(image, out, -1,Size(5, 5));
//显示效果图
imshow(“均值滤波【效果图】” ,out );
waitKey(0 );
}
运行效果图(内核大小Size(5, 5)):
《2》blur函数——均值滤波
blur的作用是对输入的图像src进行均值滤波后用dst输出。
函数原型如下:
C++: void blur(InputArray src, OutputArraydst, Size ksize, Point anchor=Point(-1,-1), int
borderType=BORDER_DEFAULT )
参数详解如下:
第一个参数,InputArray类型的src,输入图像,即源图像,填Mat类的对象即可。该函数对通道是独立处
理的,且可以处理任意通道数的图片,但需要注意,待处理的图片深度应该为CV_8U, CV_16U, CV_16S,
CV_32F 以及 CV_64F之一。
第二个参数,OutputArray类型的dst,即目标图像,需要和源图片有一样的尺寸和类型。比如可以用
Mat::Clone,以源图片为模板,来初始化得到如假包换的目标图。
第三个参数,Size类型(对Size类型稍后有讲解)的ksize,内核的大小。一般这样写Size( w,h )来表示
内核的大小( 其中,w 为像素宽度, h为像素高度)。Size(3,3)就表示3x3的核大小,Size(5,5)就表
示5x5的核大小
第四个参数,Point类型的anchor,表示锚点(即被平滑的那个点),注意他有默认值Point(-1,-1)。如果这个点坐标是负值的话,就表示取核的中心为锚点,所以默认值Point(-1,-1)表示这个锚点在核的中心。
第五个参数,int类型的borderType,用于推断图像外部像素的某种边界模式。有默认值BORDER_DEFAULT
,我们一般不去管它。
调用代码示范:
//载入原图
Matimage=imread(“1.jpg”);
//进行均值滤波操作
Matout;
blur(image, out, Size(7, 7));
为了大家的理解和应用方便,还是给出用上面三句核心代码架起来完整程序的代码:
//-----------------------------------【头文件包含部分】---------------------------------------
// 描述:包含程序所依赖的头文件
//------------------------------------------------------------------------------------------
----
#include “opencv2/core/core.hpp”
#include“opencv2/highgui/highgui.hpp”
#include“opencv2/imgproc/imgproc.hpp”
#include 《stdio.h》
//-----------------------------------【命名空间声明部分】---------------------------------------
// 描述:包含程序所使用的命名空间
//------------------------------------------------------------------------------------------
-----
using namespace cv;
//-----------------------------------【main( )函数】--------------------------------------------
// 描述:控制台应用程序的入口函数,我们的程序从这里开始
//------------------------------------------------------------------------------------------
-----
int main( )
{
//载入原图
Matimage=imread(“1.jpg”);
//创建窗口
namedWindow(“均值滤波【原图】” );
namedWindow(“均值滤波【效果图】”);
//显示原图
imshow(“均值滤波【原图】”, image );
//进行滤波操作
Matout;
blur(image, out, Size(7, 7));
//显示效果图
imshow(“均值滤波【效果图】” ,out );
waitKey(0 );
}
运行效果图(内核大小Size(7, 7)):
《3》GaussianBlur函数——高斯滤波
GaussianBlur函数的作用是用高斯滤波器来模糊一张图片,对输入的图像src进行高斯滤波后用dst输出。
函数原型如下:
C++: void GaussianBlur(InputArray src,OutputArray dst, Size ksize, double sigmaX, double
sigmaY=0, intborderType=BORDER_DEFAULT )
参数详解如下:
第一个参数,InputArray类型的src,输入图像,即源图像,填Mat类的对象即可。它可以是单独的任意通
道数的图片,但需要注意,图片深度应该为CV_8U,CV_16U, CV_16S, CV_32F 以及 CV_64F之一。
第二个参数,OutputArray类型的dst,即目标图像,需要和源图片有一样的尺寸和类型。比如可以用
Mat::Clone,以源图片为模板,来初始化得到如假包换的目标图。
第三个参数,Size类型的ksize高斯内核的大小。其中ksize.width和ksize.height可以不同,但他们都必
须为正数和奇数。或者,它们可以是零的,它们都是由sigma计算而来。
第四个参数,double类型的sigmaX,表示高斯核函数在X方向的的标准偏差。
第五个参数,double类型的sigmaY,表示高斯核函数在Y方向的的标准偏差。若sigmaY为零,就将它设为
sigmaX,如果sigmaX和sigmaY都是0,那么就由ksize.width和ksize.height计算出来。
为了结果的正确性着想,最好是把第三个参数Size,第四个参数sigmaX和第五个参数sigmaY全部指定到。
第六个参数,int类型的borderType,用于推断图像外部像素的某种边界模式。注意它有默认值
BORDER_DEFAULT。
调用示例:
//载入原图
Matimage=imread(“1.jpg”);
//进行滤波操作
Matout;
blur(image, out, Size(5, 5));
用上面三句核心代码架起来的完整程序代码:
//-----------------------------------【头文件包含部分】---------------------------------------
// 描述:包含程序所依赖的头文件
//------------------------------------------------------------------------------------------
----
#include “opencv2/core/core.hpp”
#include“opencv2/highgui/highgui.hpp”
#include“opencv2/imgproc/imgproc.hpp”
#include 《stdio.h》
//-----------------------------------【命名空间声明部分】---------------------------------------
// 描述:包含程序所使用的命名空间
//------------------------------------------------------------------------------------------
-----
using namespace cv;
//-----------------------------------【main( )函数】--------------------------------------------
// 描述:控制台应用程序的入口函数,我们的程序从这里开始
//------------------------------------------------------------------------------------------
-----
int main( )
{
//载入原图
Matimage=imread(“1.jpg”);
//创建窗口
namedWindow(“均值滤波【原图】” );
namedWindow(“均值滤波【效果图】”);
//显示原图
imshow(“均值滤波【原图】”, image );
//进行均值滤波操作
Matout;
GaussianBlur(image, out, Size( 3, 3 ), 0, 0 );
//显示效果图
imshow(“均值滤波【效果图】” ,out );
waitKey(0 );
}
运行效果图(内核大小Size(5, 5)):
四、图像线性滤波综合示例 程序
依然是每篇文章都会配给大家的一个详细注释的博文配套示例程序,把这篇文章中介绍的知识点以代码为载体,展现给大家。
这个示例程序中可以用轨迹条来控制三种线性滤波的核参数值,通过滑动滚动条,就可以控制图像在三种线性滤波下的模糊度,有一定的可玩性。废话不多说,上代码吧:
//-----------------------------------【程序说明】----------------------------------------------
// 程序名称::【OpenCV入门教程之八】线性滤波专场:方框滤波、均值滤波与高斯滤波 配
套源码
// 开发所用OpenCV版本:2.4.8
// 2014年3月31 日 Create by 浅墨
//------------------------------------------------------------------------------------------
------
//-----------------------------------【头文件包含部分】---------------------------------------
// 描述:包含程序所依赖的头文件
//------------------------------------------------------------------------------------------
----
#include 《opencv2/core/core.hpp》
#include《opencv2/highgui/highgui.hpp》
#include 《opencv2/imgproc/imgproc.hpp》
#include 《iostream》
//-----------------------------------【命名空间声明部分】---------------------------------------
// 描述:包含程序所使用的命名空间
//------------------------------------------------------------------------------------------
-----
using namespace std;
using namespace cv;
//-----------------------------------【全局变量声明部分】--------------------------------------
// 描述:全局变量声明
//------------------------------------------------------------------------------------------
-----
Matg_srcImage,g_dstImage1,g_dstImage2,g_dstImage3;//存储图片的Mat类型
int g_nBoxFilterValue=3; //方框滤波参数值
int g_nMeanBlurValue=3; //均值滤波参数值
int g_nGaussianBlurValue=3; //高斯滤波参数值
//-----------------------------------【全局函数声明部分】--------------------------------------
// 描述:全局函数声明
//------------------------------------------------------------------------------------------
-----
//四个轨迹条的回调函数
static void on_BoxFilter(int, void *); //均值滤波
static void on_MeanBlur(int, void *); //均值滤波
static void on_GaussianBlur(int, void *); //高斯滤波
//-----------------------------------【main( )函数】--------------------------------------------
// 描述:控制台应用程序的入口函数,我们的程序从这里开始
//------------------------------------------------------------------------------------------
-----
int main( )
{
//改变console字体颜色
system(“color5E”);
//载入原图
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( );
//显示原图
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);
//================================================
//输出一些帮助信息
cout《《endl《《“\t嗯。好了,请调整滚动条观察图像效果~\n\n”
《《“\t按下“q”键时,程序退出~!\n”
《《“\n\n\t\t\t\tby浅墨”;
//按下“q”键时,程序退出
while(char(waitKey(1))!= ‘q’) {}
return0;
}
//-----------------------------【on_BoxFilter( )函数】------------------------------------
// 描述:方框滤波操作的回调函数
//------------------------------------------------------------------------------------------
-----
static void on_BoxFilter(int, void *)
{
//方框滤波操作
boxFilter(g_srcImage, g_dstImage1, -1,Size( g_nBoxFilterValue+1, g_nBoxFilterValue+1));
//显示窗口
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);
}
//-----------------------------【ContrastAndBright( )函
数】------------------------------------
// 描述:高斯滤波操作的回调函数
//------------------------------------------------------------------------------------------
-----
static void on_GaussianBlur(int, void *)
{
//高斯滤波操作
GaussianBlur(g_srcImage, g_dstImage3, Size(
g_nGaussianBlurValue*2+1,g_nGaussianBlurValue*2+1 ), 0, 0);
//显示窗口
imshow(“【《3》高斯滤波】”, g_dstImage3);
}
最后是一些运行截图,原图:
方框滤波:
均值滤波:
高斯滤波:
========
评论
查看更多