-
结构图
暂且不画
里面涉及到的滤波器引擎,参考 https://blog.csdn.net/u014676657/article/details/82970932
-
边界类型
//! Various border types, image boundaries are denoted with `|`
//! @see borderInterpolate, copyMakeBorder 插值边界 复制制作边框
enum BorderTypes {
BORDER_CONSTANT = 0, //!< `iiiiii|abcdefgh|iiiiiii` with some specified `i` 常量
BORDER_REPLICATE = 1, //!< `aaaaaa|abcdefgh|hhhhhhh` 最外面
BORDER_REFLECT = 2, //!< `fedcba|abcdefgh|hgfedcb` 最外面对称
BORDER_WRAP = 3, //!< `cdefgh|abcdefgh|abcdefg` 反向填充
BORDER_REFLECT_101 = 4, //!< `gfedcb|abcdefgh|gfedcba`
BORDER_TRANSPARENT = 5, //!< `uvwxyz|abcdefgh|ijklmno`
BORDER_REFLECT101 = BORDER_REFLECT_101, //!< same as BORDER_REFLECT_101
BORDER_DEFAULT = BORDER_REFLECT_101, //!< same as BORDER_REFLECT_101
BORDER_ISOLATED = 16 //!< do not look outside of ROI
};
-
boxFilter函数
-
//盒状滤波器 //函数采用元素全为1的核去平滑图像 // inline CV_EXPORTS_W void boxFilter(InputArray src, //输入图像 OutputArray dst, //输出图像,大小和类型和输入图像一样 int ddepth, //输出图像的深度,(-1时,使用src.depth()) Size ksize, //核大小 Point anchor = Point(-1,-1),//锚点,default=(-1,-1),为核的中心 bool normalize = true, //指定是否由核的面积归一化, int borderType = BORDER_DEFAULT)//边界类型,确定超出图像的外推像素 { 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) //目标图像的深度默认值时,与原图像一致 ddepth = sdepth; _dst.create(src.size(), CV_MAKETYPE(ddepth, cn));//创建目标实际图像矩阵 Mat dst = _dst.getMat();//获取目标图像矩阵 if (borderType != BORDER_CONSTANT && normalize && (borderType & BORDER_ISOLATED) != 0) { //边界类型不为常量,且滤波器进行归一化,边界不进行填充 //设置核大小 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))//考虑边界问题,则定位在父矩阵的位置, 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.row-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<FilterEngine> f = createBoxFilter(src.type(), dst.type(), ksize, anchor, normalize, borderType); f->apply(src, dst, wsz, ofs);//对图像进行滤波 }
-
createBoxFilter
//! returns box filter engine 返回盒状滤波器引擎
Ptr<FilterEngine> createBoxFilter( int srcType,//原图像类型
int dstType, //目标图像类型
Size ksize, //核大小
Point anchor = Point(-1,-1),//锚点
bool normalize = true, //是否归一化
int borderType = BORDER_DEFAULT) //边界类型
{
int sdepth = CV_MAT_DEPTH(srcType);//获取原图像的深度
int cn = CV_MAT_CN(srcType), sumType = CV_64F;//通道数,缓冲类型(中间数据类型)
if( sdepth == CV_8U && CV_MAT_DEPTH(dstType) == CV_8U &&
ksize.width*ksize.height <= 256 ) //如果核面积小于256,且原图像和目标图像类型都是8位的uchar则中间数据类型为16位的数据类型
sumType = CV_16U;
else if( sdepth <= CV_32S && (!normalize ||
ksize.width*ksize.height <= (sdepth == CV_8U ? (1<<23) :
sdepth == CV_16U ? (1 << 15) : (1 << 16))) )
sumType = CV_32S;
sumType = CV_MAKETYPE( sumType, cn );
//获取行滤波器
Ptr<BaseRowFilter> rowFilter = getRowSumFilter(srcType, sumType, ksize.width, anchor.x );
//获取列滤波器
Ptr<BaseColumnFilter> columnFilter = getColumnSumFilter(sumType,
dstType, ksize.height, anchor.y, normalize ? 1./(ksize.width*ksize.height) : 1);
//返回盒状滤波器
return makePtr<FilterEngine>(Ptr<BaseFilter>(), rowFilter, columnFilter,
srcType, dstType, sumType, borderType );
}
-
blur滤波器
在opencv中,blur滤波器其实就是boxFilter的一种特殊情况,就是调用盒状滤波器实现的。实现代码如下:
void cv::blur(InputArray src, OutputArray dst,
Size ksize, Point anchor, int borderType )
{
CV_INSTRUMENT_REGION()//这个不用管,现在好多东西不会,只能分析到这里了
boxFilter( src, dst, -1, ksize, anchor, true, borderType );
}
-
sqrBoxFilter滤波器
sqrBoxFilter滤波器的实现和BoxFilter滤波器区别不大,唯一的区别就是行滤波器,sqrBoxFilter滤波器获取的是SqrRowSum滤波器,而后者使用的是RowSum滤波器,注释不写,SqrRowSum和RowSum滤波器,详见:https://blog.csdn.net/u014676657/article/details/82994552
void cv::sqrBoxFilter( InputArray _src, OutputArray _dst, int ddepth,
Size ksize, Point anchor,
bool normalize, int borderType )
{
CV_INSTRUMENT_REGION()
int srcType = _src.type(), sdepth = CV_MAT_DEPTH(srcType), cn = CV_MAT_CN(srcType);
Size size = _src.size();
if( ddepth < 0 )
ddepth = sdepth < CV_32F ? CV_32F : CV_64F;
if( borderType != BORDER_CONSTANT && normalize )
{
if( size.height == 1 )
ksize.height = 1;
if( size.width == 1 )
ksize.width = 1;
}
CV_OCL_RUN(_dst.isUMat() && _src.dims() <= 2,
ocl_boxFilter(_src, _dst, ddepth, ksize, anchor, borderType, normalize, true))
int sumDepth = CV_64F;
if( sdepth == CV_8U )
sumDepth = CV_32S;
int sumType = CV_MAKETYPE( sumDepth, cn ), dstType = CV_MAKETYPE(ddepth, cn);
Mat src = _src.getMat();
_dst.create( size, dstType );
Mat dst = _dst.getMat();
Ptr<BaseRowFilter> rowFilter = getSqrRowSumFilter(srcType, sumType, ksize.width, anchor.x );
Ptr<BaseColumnFilter> columnFilter = getColumnSumFilter(sumType,
dstType, ksize.height, anchor.y,
normalize ? 1./(ksize.width*ksize.height) : 1);
Ptr<FilterEngine> f = makePtr<FilterEngine>(Ptr<BaseFilter>(), rowFilter, columnFilter,
srcType, dstType, sumType, borderType );
Point ofs;
Size wsz(src.cols, src.rows);
src.locateROI( wsz, ofs );
f->apply( src, dst, wsz, ofs );
}