#if (defined WIN32 || defined WIN64) && defined CVAPI_EXPORTS
#define CV_EXPORTS __declspec(dllexport)
#else
#define CV_EXPORTS
#endif
#ifndef CVAPI
#define CVAPI(rettype) CV_EXTERN_C CV_EXPORTS rettype CV_CDECL
#endif
/* CV_FUNCNAME macro defines icvFuncName constant which is used by CV_ERROR macro */
#ifdef CV_NO_FUNC_NAMES
#define CV_FUNCNAME( Name )
#define cvFuncName ""
#else
#define CV_FUNCNAME( Name ) static char cvFuncName[] = Name
#endif
/*
CV_CALL macro calls CV (or IPL) function, checks error status and
signals a error if the function failed. Useful in "parent node"
error procesing mode
*/
#define CV_CALL( Func ) { Func; CV_CHECK(); }
/* Simplified form of CV_ERROR */
#define CV_ERROR_FROM_CODE( code ) CV_ERROR( code, "" )
/*
CV_CHECK macro checks error status after CV (or IPL)
function call. If error detected, control will be transferred to the exit
label.
*/
#define CV_CHECK() { if( cvGetErrStatus() < 0 ) CV_ERROR( CV_StsBackTrace, "Inner function failed." ); }
#define __BEGIN__ {
#define __END__ goto exit; exit: ; }
#define __CLEANUP__
#define EXIT goto exit
/*
. CV_BLUR_NO_SCALE (简单不带尺度变换的模糊) - 对每个象素的 param1×param2 领域求和。如果邻域大小是变化的,可以事先利用函数 cvIntegral 计算积分图像。
. CV_BLUR (simple blur) - 对每个象素param1×param2邻域 求和并做尺度变换 1/(param1.param2).
. CV_GAUSSIAN (gaussian blur) - 对图像进行核大小为 param1×param2 的高斯卷积
. CV_MEDIAN (median blur) - 对图像进行核大小为param1×param1 的中值滤波(i.e. 邻域是方的).
. CV_BILATERAL (双向滤波) - 应用双向 3x3 滤波,彩色sigma=param1,空间 sigma=param2. 平滑操作的第一个参数.
*/
CV_IMPL void
cvSmooth( const void* srcarr, void* dstarr, int smooth_type,
int param1, int param2, double param3, double param4 )
{
CvBoxFilter box_filter;
//定义一个CvBoxFilter的对象
CvSepFilter gaussian_filter;
//定义一个CvSepFilter的对象
CvMat* temp = 0;
//temp指针为空
CV_FUNCNAME( "cvSmooth" );
/* CV_FUNCNAME macro defines icvFuncName constant which is used by CV_ERROR macro */
__BEGIN__;//这个没啥用,相当于告诉你我要开始干活了
int coi1 = 0, coi2 = 0;//COI感兴趣通道,类似于ROI
CvMat srcstub, *src = (CvMat*)srcarr;//void指针进行类型转换
CvMat dststub, *dst = (CvMat*)dstarr;//void指针进行类型转换
CvSize size;
int src_type, dst_type, depth, cn;
double sigma1 = 0, sigma2 = 0;
bool have_ipp = icvFilterMedian_8u_C1R_p != 0;
CV_CALL( src = cvGetMat( src, &srcstub, &coi1 ));
CV_CALL( dst = cvGetMat( dst, &dststub, &coi2 ));
/*
CV_CALL macro calls CV (or IPL) function, checks error status and
signals a error if the function failed. Useful in "parent node"
error procesing mode
*/
if( coi1 != 0 || coi2 != 0 )//COI必须都是0等价于coi1==0&&coi2==0
CV_ERROR( CV_BadCOI, "" );
src_type = CV_MAT_TYPE( src->type );
//#define CV_MAT_TYPE(flags) ((flags) & CV_MAT_TYPE_MASK)
//#define CV_MAT_TYPE_MASK (CV_DEPTH_MAX*CV_CN_MAX - 1) 结果为:01 1111 1111
//#define CV_CN_MAX 64
//#define CV_CN_SHIFT 3
//#define CV_DEPTH_MAX (1 << CV_CN_SHIFT)
//
dst_type = CV_MAT_TYPE( dst->type );
depth = CV_MAT_DEPTH(src_type);
//#define CV_MAT_DEPTH(flags) ((flags) & CV_MAT_DEPTH_MASK)
//#define CV_MAT_DEPTH_MASK (CV_DEPTH_MAX - 1) 结果为: 00 0000 0111
//#define CV_CN_SHIFT 3
//#define CV_DEPTH_MAX (1 << CV_CN_SHIFT)
cn = CV_MAT_CN(src_type);
//#define CV_MAT_CN(flags) ((((flags) & CV_MAT_CN_MASK) >> CV_CN_SHIFT) + 1)
//#define CV_MAT_CN_MASK ((CV_CN_MAX - 1) << CV_CN_SHIFT) 结果为: 11 1111 1000
//#define CV_CN_MAX 64
//#define CV_CN_SHIFT 3
size = cvGetMatSize(src);
//cvGetSize():
if( !CV_ARE_SIZES_EQ( src, dst ))//判断输入输出大小是否相等
CV_ERROR( CV_StsUnmatchedSizes, "" );
if( smooth_type != CV_BLUR_NO_SCALE && !CV_ARE_TYPES_EQ( src, dst ))//除了CV_BLUR_NO_SCALE情况下,输入输出矩阵类型应该相同
CV_ERROR( CV_StsUnmatchedFormats,
"The specified smoothing algorithm requires input and ouput arrays be of the same type" );
/*
param2
平滑操作的第二个参数. 对于简单/非尺度变换的高斯模糊的情况,如果param2的值 为零,则表示其被设定为param1。
param3
对应高斯参数的 Gaussian sigma (标准差). 如果为零,则标准差由下面的核尺寸计算:
sigma = (n/2 - 1)*0.3 + 0.8, 其中 n=param1 对应水平核,
n=param2 对应垂直核.
*/
if( smooth_type == CV_BLUR || smooth_type == CV_BLUR_NO_SCALE ||
smooth_type == CV_GAUSSIAN || smooth_type == CV_MEDIAN )
{
// automatic detection of kernel size from sigma
if( smooth_type == CV_GAUSSIAN )
{
sigma1 = param3;
sigma2 = param4 ? param4 : param3;
//sigma1,sigma2 为param3和param4,如果param4为0则sigma2为param3的值
if( param1 == 0 && sigma1 > 0 )
param1 = cvRound(sigma1*(depth == CV_8U ? 3 : 4)*2 + 1)|1;
if( param2 == 0 && sigma2 > 0 )
param2 = cvRound(sigma2*(depth == CV_8U ? 3 : 4)*2 + 1)|1;
//p1,p2为0时:使用sigma1*(depth == CV_8U ? 3 : 4)*2 + 1计算窗口大小(为奇数)
}
if( param2 == 0 )
param2 = size.height == 1 ? 1 : param1;
if( param1 < 1 || (param1 & 1) == 0 || param2 < 1 || (param2 & 1) == 0 )//param1,param2为偶数或者负数,报错
CV_ERROR( CV_StsOutOfRange,
"Both mask width and height must be >=1 and odd" );
if( param1 == 1 && param2 == 1 )//param1,param2为1,图像不变
{
cvConvert( src, dst );
EXIT;
}
}
//=================================================================================================================
//使用IPP加速时:
if( have_ipp && (smooth_type == CV_BLUR || smooth_type == CV_MEDIAN) &&
size.width >= param1 && size.height >= param2 && param1 > 1 && param2 > 1 )
{
CvSmoothFixedIPPFunc ipp_median_box_func = 0;
if( smooth_type == CV_BLUR )
{
ipp_median_box_func =
src_type == CV_8UC1 ? icvFilterBox_8u_C1R_p :
src_type == CV_8UC3 ? icvFilterBox_8u_C3R_p :
src_type == CV_8UC4 ? icvFilterBox_8u_C4R_p :
src_type == CV_32FC1 ? icvFilterBox_32f_C1R_p :
src_type == CV_32FC3 ? icvFilterBox_32f_C3R_p :
src_type == CV_32FC4 ? icvFilterBox_32f_C4R_p : 0;//这个写法很给力。。。
}
else if( smooth_type == CV_MEDIAN )
{
ipp_median_box_func =
src_type == CV_8UC1 ? icvFilterMedian_8u_C1R_p :
src_type == CV_8UC3 ? icvFilterMedian_8u_C3R_p :
src_type == CV_8UC4 ? icvFilterMedian_8u_C4R_p : 0;
}
if( ipp_median_box_func )
{
CvSize el_size = { param1, param2 };
CvPoint el_anchor = { param1/2, param2/2 };
int stripe_size = 1 << 14; // the optimal value may depend on CPU cache,
// overhead of the current IPP code etc.
const uchar* shifted_ptr;
int y, dy = 0;
int temp_step, dst_step = dst->step;
CV_CALL( temp = icvIPPFilterInit( src, stripe_size, el_size ));
shifted_ptr = temp->data.ptr +
el_anchor.y*temp->step + el_anchor.x*CV_ELEM_SIZE(src_type);
temp_step = temp->step ? temp->step : CV_STUB_STEP;
for( y = 0; y < src->rows; y += dy )
{
dy = icvIPPFilterNextStripe( src, temp, y, el_size, el_anchor );
IPPI_CALL( ipp_median_box_func( shifted_ptr, temp_step,
dst->data.ptr + y*dst_step, dst_step, cvSize(src->cols, dy),
el_size, el_anchor ));
}
EXIT;
}
}
//=================================================================================================================
if( smooth_type == CV_BLUR || smooth_type == CV_BLUR_NO_SCALE )
{
CV_CALL( box_filter.init( src->cols, src_type, dst_type,
smooth_type == CV_BLUR, cvSize(param1, param2) ));
//初始化box_filter
CV_CALL( box_filter.process( src, dst ));
}
else if( smooth_type == CV_MEDIAN )
{
if( depth != CV_8U || cn != 1 && cn != 3 && cn != 4 )//中值滤波通道数必须为1,3,4,深度必须是CV_8U
CV_ERROR( CV_StsUnsupportedFormat,
"Median filter only supports 8uC1, 8uC3 and 8uC4 images" );
//icvMedianBlur_8u_CnR下节介绍
IPPI_CALL( icvMedianBlur_8u_CnR( src->data.ptr, src->step,
dst->data.ptr, dst->step, size, param1, cn ));
}
else if( smooth_type == CV_GAUSSIAN )
{
CvSize ksize = { param1, param2 };//初始核大小
float* kx = (float*)cvStackAlloc( ksize.width*sizeof(kx[0]) );//分配栈,float类型大小为x轴核宽度
float* ky = (float*)cvStackAlloc( ksize.height*sizeof(ky[0]) );//分配栈,float类型大小为y轴核宽度
CvMat KX = cvMat( 1, ksize.width, CV_32F, kx );//float类型大小为x轴核宽度,向量
CvMat KY = cvMat( 1, ksize.height, CV_32F, ky );//float类型大小为x轴核宽度,向量
CvSepFilter::init_gaussian_kernel( &KX, sigma1 );
if( ksize.width != ksize.height || fabs(sigma1 - sigma2) > FLT_EPSILON )
CvSepFilter::init_gaussian_kernel( &KY, sigma2 );
//#define FLT_EPSILON 1.192092896e-07F /* smallest such that 1.0+FLT_EPSILON != 1.0 */
//================================================================================================
//FLT_EPSILON用于float类型。
//它是满足 x+1.0不等于1.0的最小的正数
//也就是说,所有比FLT_EPSILON小的正数x,x+1.0==1.0都是成立的。
//================================================================================================
else
KY.data.fl = kx;
//=================================================================================================================
//使用IPP加速时:
if( have_ipp && size.width >= param1*3 &&
size.height >= param2 && param1 > 1 && param2 > 1 )
{
int done;
CV_CALL( done = icvIPPSepFilter( src, dst, &KX, &KY,
cvPoint(ksize.width/2,ksize.height/2)));
if( done )
EXIT;
}
//=================================================================================================================
CV_CALL( gaussian_filter.init( src->cols, src_type, dst_type, &KX, &KY ));
CV_CALL( gaussian_filter.process( src, dst ));
}
else if( smooth_type == CV_BILATERAL )
{
if( param1 < 0 || param2 < 0 )//param1,param2检测合法性
CV_ERROR( CV_StsOutOfRange,
"Thresholds in bilaral filtering should not bee negative" );
//如果param1或param2为0,则加1
param1 += param1 == 0;
param2 += param2 == 0;
//depth和chanel的参数检测
if( depth != CV_8U || cn != 1 && cn != 3 )
CV_ERROR( CV_StsUnsupportedFormat,
"Bilateral filter only supports 8uC1 and 8uC3 images" );
//icvBilateralFiltering_8u_CnR函数下节讲解
IPPI_CALL( icvBilateralFiltering_8u_CnR( src->data.ptr, src->step,
dst->data.ptr, dst->step, size, param1, param2, cn ));
}
__END__;
//释放temp
cvReleaseMat( &temp );
}
原文地址:http://blog.csdn.net/tonyshengtan/article/details/40741691