滤波的目的:
1、抽出对象的特征作为图像识别的特征模式
2、适应图像处理的要求,消除图像数字化时所混入的噪声
平滑滤波是低频增强的空间域滤波技术,一般用来模糊图像或者消除噪声
这里我们简单谈空间域的滤波处理,主要是把滤波器想象成一个包含加权系数的窗口,平滑是,进行加权平均,得到像素点的值
1、方框滤波之BoxBlur函数
boxblur函数的作用是使用boxfilter(方框滤波器),从src输入,dst输出,如下:
CV_EXPORTS_W void boxFilter( InputArray src, OutputArray dst, int ddepth,
Size ksize, Point anchor = Point(-1,-1),
bool normalize = true,
int borderType = BORDER_DEFAULT );
各参数如下:
第一个参数、InputArray src:输入图像,Mat 类的对象
第二个参数、OutputArray dst:目标图像
第三个参数、int ddepth: 输入图像的深度,-1代表使用原图的深度
第四个参数、Size kize: 内核的大小,一般用Size(w,h)表示内核的大小
第五个参数、Point:默认值为(-1,-1)代表核的中心,其他的是需要被平滑的那个点
第六个参数、bool normalize:默认true。表示是否归一化,如果是的话,就相当于均值滤波
第七个参数、int borderType:这个不是很清楚,一般不管
2、均值滤波之blur函数
void blur( InputArray src, OutputArray dst,
Size ksize, Point anchor = Point(-1,-1),
int borderType = BORDER_DEFAULT );
具体参数和1方框滤波一样
第一个参数、InputArray src:输入图像,Mat 类的对象
第二个参数、OutputArray dst:目标图像
第三个参数、Size kize: 内核的大小,一般用Size(w,h)表示内核的大小
第四个参数、Point:默认值为(-1,-1)代表核的中心,其他的是需要被平滑的那个点
3、高斯滤波
先简单谈一下关于高斯滤波,之前我转过一篇文章
想了解相关原理的可以看看
这里先简单提一下
高斯滤波函数为:
离散的高斯卷积核H: (2k+1)×(2k+1)维,其元素计算方法为:
其中Sigma为方差,k确定核矩阵的维数,关于这两个取值,在下文进行分析。
opencv中,关于高斯函数,有有两个设置方差的参数,具体如下
简单提了一个高斯函数,来具体看看Opencv是怎么实现的
void GaussianBlur( InputArray src, OutputArray dst, Size ksize,
double sigmaX, double sigmaY = 0,
int borderType = BORDER_DEFAULT );
第一个参数、InputArray src:输入图像,Mat 类的对象
第二个参数、OutputArray dst:目标图像
第三个参数、Size kize: 内核的大小,其中ksize.width金额ksize.height可以不同,但是必须是整数和奇数,或者0.腰要算sigma的
第四个参数、sigmaX:表示高斯核在X方向的标准偏差
第五个参数、sigmaY,表示高斯核在Y方向的标准偏差,如果为0,则设置为sigmaX,如果两个都是0,则有kisze的width和height计算出来
简单看一下个函数的使用情况吧,下面是一段小程序
#include "stdafx.h"
#include
using namespace cv;
using namespace std;
int main()
{
Mat img = imread("F:/Digital-image-project/BMPimages/24-512-512.bmp");
imshow("原图", img);
Mat dstImg;
boxFilter(img, dstImg, img.depth(), Size(5, 5));
imshow("方框滤波", dstImg);
blur(img, dstImg, Size(3, 3));
imshow("均值滤波", dstImg);
GaussianBlur(img, dstImg, Size(3, 3), 0,0);
imshow("高斯滤波", dstImg);
waitKey(0);
return 0;
}
效果如下
现在来看看方框滤波的源码
void cv::boxFilter( InputArray _src, OutputArray _dst, int ddepth,
Size ksize, Point anchor,
bool normalize, int borderType )
/*第一个参数、InputArray src:输入图像,Mat 类的对象
第二个参数、OutputArray dst:目标图像
第三个参数、int ddepth: 输入图像的深度,-1代表使用原图的深度
第四个参数、Size kize: 内核的大小,一般用Size(w,h)表示内核的大小
第五个参数、Point:默认值为(-1,-1)代表核的中心,其他的是需要被平滑的那个点
第六个参数、bool normalize:默认true。表示是否归一化,如果是的话,就相当于均值滤波
第七个参数、int borderType:这个不是很清楚,一般不管*/
{
CV_INSTRUMENT_REGION()
CV_OCL_RUN(_dst.isUMat() &&
(borderType == BORDER_REPLICATE || borderType == BORDER_CONSTANT ||
borderType == BORDER_REFLECT || borderType == BORDER_REFLECT_101),
ocl_boxFilter3x3_8UC1(_src, _dst, ddepth, ksize, anchor, borderType, normalize))
CV_OCL_RUN(_dst.isUMat(), ocl_boxFilter(_src, _dst, ddepth, ksize, anchor, borderType, normalize))
Mat src = _src.getMat();//复制原图的形参Mat数据到临时变量
int stype = src.type(), sdepth = CV_MAT_DEPTH(stype), cn = CV_MAT_CN(stype);//得到深度、通道数
if( ddepth < 0 )//处理depth小于0的情况
ddepth = sdepth;
_dst.create( src.size(), CV_MAKETYPE(ddepth, cn) );//初始化目标图
Mat dst = _dst.getMat();//复制目标图的形参Mat数据到临时变量
if( borderType != BORDER_CONSTANT && normalize && (borderType & BORDER_ISOLATED) != 0 )//处理borederType不为BORDER_CONSTANT等其他情况
{
if( src.rows == 1 )
ksize.height = 1;
if( src.cols == 1 )
ksize.width = 1;
}
Point ofs;
Size wsz(src.cols, src.rows);
if(!(borderType&BORDER_ISOLATED))//处理borederType不为
src.locateROI( wsz, ofs );
CALL_HAL(boxFilter, cv_hal_boxFilter, src.ptr(), src.step, dst.ptr(), dst.step, src.cols, src.rows, sdepth, ddepth, cn,
ofs.x, ofs.y, wsz.width - src.cols - ofs.x, wsz.height - src.rows - ofs.y, ksize.width, ksize.height,
anchor.x, anchor.y, normalize, borderType&~BORDER_ISOLATED);
CV_OVX_RUN(true,
openvx_boxfilter(src, dst, ddepth, ksize, anchor, normalize, borderType))
CV_IPP_RUN_FAST(ipp_boxfilter(src, dst, ksize, anchor, normalize, borderType));
borderType = (borderType&~BORDER_ISOLATED);
Ptr f = createBoxFilter( src.type(), dst.type(),//重点来看这个函数吧,调用DilterEngine引擎,正式开始滤波操作,Ptr是只能分配动态指针的模板类
ksize, anchor, normalize, borderType );
f->apply( src, dst, wsz, ofs );//
}
从上面我们可以看到FilterEngine引擎承担了很大的作用,关于这个引擎的具体实现,笔者截止目前也没有搞清楚,就不献丑了,有兴趣的同学可以多查查资料
看一下均值滤波的源码
void cv::blur( InputArray src, OutputArray dst,
Size ksize, Point anchor, int borderType )
{
CV_INSTRUMENT_REGION()
boxFilter( src, dst, -1, ksize, anchor, true, borderType );
}
哈哈,是不是很简单,直接调用方框滤波就可以了,只不过第6个参数设置成true,即方框滤波的标准化操作
高斯滤波的源码暂时看不懂