滤波器的种类有很多, 在新版本的OpenCV中,提供了如下五种常用的图像平滑处理操作方法,且他们分别被封装在单独的函数中,使用起来非常方便:
· 方框滤波——boxblur函数
· 均值滤波——blur函数
· 高斯滤波——GaussianBlur函数
· 中值滤波——medianBlur函数
· 双边滤波——bilateralFilter函数
本文主要以blur展开解析:
CV_EXPORTS_W void blur( InputArray src, OutputArray dst,
Size ksize, Point anchor=Point(-1,-1),
int
· 第一个参数,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
borderType参数解析如下:
/*
Various border types, image boundaries aredenoted with '|'
* BORDER_REPLICATE: aaaaaa|abcdefgh|hhhhhhh
* BORDER_REFLECT: fedcba|abcdefgh|hgfedcb
* BORDER_REFLECT_101: gfedcb|abcdefgh|gfedcba
* BORDER_WRAP: cdefgh|abcdefgh|abcdefg
* BORDER_CONSTANT: iiiiii|abcdefgh|iiiiiii with some specified 'i'
*/
根据borderInterpolate可知其只支持上面五种边缘插值方法,上面的插值按照右边的字符串很形象的表示了。
在OpenCV滤波算法中,有两个非常重要的基本工具函数,copyMakeBorder和borderInterpolate
void copyMakeBorder( const Mat& src,Mat& dst,int top, int bottom, int left, int right,
int borderType, const Scalar& value=Scalar() );
源码在utils.cpp中
功能
扩充src的边缘,将图像变大,然后以各种外插方式自动填充图像边界,这个函数实际上调用了函数cv::borderInterpolate,这个函数最重要的功能就是为了处理边界,比如均值滤波或者中值滤波中,使用copyMakeBorder将原图稍微放大,然后我们就可以处理边界的情况了
// borderInterpolate源码在 filter.cpp里面
BORDER_REPLICATE:复制法,也就是复制最边缘像素。边缘扩大的像素个数根据你的模板大小
BORDER_REFLECT : 对称法,也就是以最边缘像素的边为轴,即该边缘像素会复制一遍
BORDER_REFLECT_101对称法,也就是以最边缘像素为轴,对称,该边缘像素不会复制一遍
BORDER_CONSTANT:常量法:边界填充特点常量,默认为0(没有发现可以修改该值,望补充,MAtlib的可以修改)
BORDER_WRAP:镜像对称复制,但是 blur(Mat(M), tempM, cv::Size(3, 3), Point(-1, -1), BORDER_WRAP);提示错误
根据错误提示你会发现问题来到FilterEngine 类解析——OpenCV图像滤波核心引擎
FilterEngine类是OpenCV关于图像滤波的主力军类,OpenCV图像滤波功能的核心引擎。各种滤波函数比如blur, GaussianBlur,到头来其实是就是在函数末尾处定义了一个Ptr<FilterEngine>类型的f,然后f->apply( src, dst )了一下而已。
这个类可以把几乎是所有的滤波操作施加到图像上。它包含了所有必要的中间缓存器。有很多和滤波相关的create系函数的返回值直接就是Ptr<FilterEngine>。比如cv::createSeparableLinearFilter()。
源码解析BORDER_WRAP在blur(Mat(M), tempM, cv::Size(3, 3), Point(-1, -1), BORDER_WRAP)里面使用错误:
http://www.opencv.org.cn/opencvdoc/2.3.2/html/modules/imgproc/doc/filtering.html?highlight=filterengine#filterengine
void init(const Ptr<BaseFilter>& _filter2D, const Ptr<BaseRowFilter>& _rowFilter, const Ptr<BaseColumnFilter>& _columnFilter, int srcType, int dstType, int bufType, int _rowBorderType = BORDER_REPLICATE, int _columnBorderType = -1, const Scalar& _borderValue = Scalar());发现init函数出现如下代码:
if (_columnBorderType < 0) _columnBorderType = _rowBorderType; rowBorderType = _rowBorderType; columnBorderType = _columnBorderType; CV_Assert(columnBorderType != BORDER_WRAP);
Blur()源码在opencv目录下面
E:\opencv\sources\modules\imgproc\src
filter.cpp
smooth.cpp
最后送各种模板边缘插值测试程序一枚:#include "stdafx.h" #include <cv.h> #include <cxcore.h> #include <highgui.h> using namespace cv; using namespace std; int _tmain(int argc, _TCHAR* argv[]) { vector<double> vecortImg(9); CvMat* M = cvCreateMat(3, 3, CV_64FC1); double num =-1; for (int i = 0; i < 3; i++){ for (int j = 0; j < 3; j++){ cvmSet(M, i, j, ++num); cout << num <<" "; vecortImg.at(i*3+j) = num;//因为滤波的不同导致的不同呀………… } cout << endl; } //! various border interpolation methods /* Various border types, image boundaries are denoted with '|' * BORDER_REPLICATE: aaaaaa|abcdefgh|hhhhhhh * BORDER_REFLECT: fedcba|abcdefgh|hgfedcb * BORDER_REFLECT_101: gfedcb|abcdefgh|gfedcba * BORDER_WRAP: cdefgh|abcdefgh|abcdefg * BORDER_CONSTANT: iiiiii|abcdefgh|iiiiiii with some specified 'i' */ cout <<"平滑后"<<endl; Mat tempM; try{ blur(Mat(M), tempM, cv::Size(3, 3), Point(-1, -1), BORDER_WRAP); } catch (cv::Exception e){ cout << e.what(); } Mat hh = tempM; vector<double> markdata1; int row = hh.rows ; int col = hh.cols; double* pMatdata = (double*)hh.data; for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++){ cout << *(pMatdata + i * 3 + j)<<" "; markdata1.push_back(*(pMatdata + i*3+j)); } cout << endl; } cvReleaseMat(&M); system("PAUSE"); return 0; }