在cv.h文件中对cvDilate的定义如下
/* dilates input image (applies maximum filter) one or more times.
If element pointer is NULL, 3x3 rectangular element is used */
CVAPI(void) cvDilate( const CvArr* src, CvArr* dst,
IplConvKernel* element CV_DEFAULT(NULL),
int iterations CV_DEFAULT(1) );
IplConvKernel* 指向的是一个结构元素块;
在cxtypes.h中对 IplConvKernel 有如下定义
typedef struct _IplConvKernel
{
int nCols;
int nRows;
int anchorX;
int anchorY;
int *values;
int nShiftR;
}
IplConvKernel;
element 如果为NULL 则使用 3x3 矩形元素进行膨胀。
element 不为NULL,可通过函数cvCreateStructuringElementEx创建
在cv.h中
/* creates structuring element used for morphological operations */
CVAPI(IplConvKernel*) cvCreateStructuringElementEx(
int cols, int rows, int anchor_x, int anchor_y,
int shape, int* values CV_DEFAULT(NULL) );
在cvmorph.cpp中
CV_IMPL IplConvKernel *
cvCreateStructuringElementEx( int cols, int rows,
int anchorX, int anchorY,
int shape, int *values )
{
IplConvKernel *element = 0;
int i, size = rows * cols;
int element_size = sizeof(*element) + size*sizeof(element->values[0]);
CV_FUNCNAME( "cvCreateStructuringElementEx" );
__BEGIN__;
//对函数参数进行有效性检查
if( !values && shape == CV_SHAPE_CUSTOM )
CV_ERROR_FROM_STATUS( CV_NULLPTR_ERR );
if( cols <= 0 || rows <= 0 ||
(unsigned) anchorX >= (unsigned) cols ||
(unsigned) anchorY >= (unsigned) rows )
CV_ERROR_FROM_STATUS( CV_BADSIZE_ERR );
//为结构元素分配内存
CV_CALL( element = (IplConvKernel *)cvAlloc(element_size + 32));
if( !element )
CV_ERROR_FROM_STATUS( CV_OUTOFMEM_ERR );
element->nCols = cols;
element->nRows = rows;
element->anchorX = anchorX;
element->anchorY = anchorY;
//nShiftR ?
element->nShiftR = shape < CV_SHAPE_ELLIPSE ? shape : CV_SHAPE_CUSTOM;
element->values = (int*)(element + 1);
if( shape == CV_SHAPE_CUSTOM )
{//如果为自定义结构元素
if( !values )
CV_ERROR( CV_StsNullPtr, "Null pointer to the custom element mask" );
for( i = 0; i < size; i++ )
element->values[i] = values[i];
}
else
{
CvMat el_hdr = cvMat( rows, cols, CV_32SC1, element->values );
//初始化结构元素
CV_CALL( CvMorphology::init_binary_element(&el_hdr,
shape, cvPoint(anchorX,anchorY)));
}
__END__;
if( cvGetErrStatus() < 0 )
cvReleaseStructuringElement( &element );
return element;
}
/*
名称:init_binary_element
说明:
如果输入的element_shape为RECT类型,则结构元素的所有元素被初始化为1;
如果输入的element_shape为CROSS类型,列anchorX,行anchorY的元素为1,其它为0;
如:anchorX = 0, anchorY = 0; 则3 x 3的结构元素将初始化为
1, 1, 1
1, 0, 0
1, 0, 0
anchorX = 1, anchorY = 1; 则3 x 3的结构元素将初始化为
0, 1, 0
1, 1, 1
0, 1, 0
如果输入的element_shape为ELLIPSE,则row * col矩形的内接ELLIPSE区域都为1;
如:3 x 3的结构元素将初始化为
0, 1, 0
1, 1, 1
0, 1, 0
5 x 5的结构元素将初始化为
0, 0, 1, 0, 0
1, 1, 1, 1, 1
1, 1, 1, 1, 1
1, 1, 1, 1, 1
0, 0, 1, 0, 0
5 x 3的结构元素将初始化为
0, 1, 0
1, 1, 1
1, 1, 1
1, 1, 1
0, 1, 0
*/
在cvmorph.cpp中
void CvMorphology::init_binary_element( CvMat* element, int element_shape, CvPoint anchor )
{
CV_FUNCNAME( "CvMorphology::init_binary_element" );
__BEGIN__;
int type;
int i, j, cols, rows;
int r = 0, c = 0;
double inv_r2 = 0;
if( !CV_IS_MAT(element) )
CV_ERROR( CV_StsBadArg, "element must be valid matrix" );
type = CV_MAT_TYPE(element->type);
if( type != CV_8UC1 && type != CV_32SC1 )
CV_ERROR( CV_StsUnsupportedFormat, "element must have 8uC1 or 32sC1 type" );
if( anchor.x == -1 )
anchor.x = element->cols/2;
if( anchor.y == -1 )
anchor.y = element->rows/2;
if( (unsigned)anchor.x >= (unsigned)element->cols ||
(unsigned)anchor.y >= (unsigned)element->rows )
CV_ERROR( CV_StsOutOfRange, "anchor is outside of element" );
if( element_shape != RECT && element_shape != CROSS && element_shape != ELLIPSE )
CV_ERROR( CV_StsBadArg, "Unknown/unsupported element shape" );
rows = element->rows;
cols = element->cols;
if( rows == 1 || cols == 1 )
element_shape = RECT;
if( element_shape == ELLIPSE )
{
r = rows/2;
c = cols/2;
inv_r2 = r ? 1./((double)r*r) : 0;
}
for( i = 0; i < rows; i++ )
{
uchar* ptr = element->data.ptr + i*element->step;
int j1 = 0, j2 = 0, jx, t = 0;
if( element_shape == RECT || element_shape == CROSS && i == anchor.y )
j2 = cols;
else if( element_shape == CROSS )
j1 = anchor.x, j2 = j1 + 1;
else
{
int dy = i - r;
if( abs(dy) <= r )
{
//((double)r*r - dy*dy 表示第 i 行直线在以r为圆的圆心左侧部分的大小
//cvRound(c*sqrt(((double)r*r - dy*dy)*inv_r2))表示 第 i 行直线在椭圆的中心左侧部分的大小
int dx = cvRound(c*sqrt(((double)r*r - dy*dy)*inv_r2));
j1 = MAX( c - dx, 0 );
j2 = MIN( c + dx + 1, cols );
}
}
for( j = 0, jx = j1; j < cols; )
{
for( ; j < jx; j++ )
{
if( type == CV_8UC1 )
ptr[j] = (uchar)t;
else
((int*)ptr)[j] = t;
}
if( jx == j2 )
jx = cols, t = 0;
else
jx = j2, t = 1;
}
}
__END__;
}
至此结构元素创建完了
CV_IMPL void
cvDilate( const void* src, void* dst, IplConvKernel* element, int iterations )
{
icvMorphOp( src, dst, element, iterations, 1 );
}
static void
icvMorphOp( const void* srcarr, void* dstarr, IplConvKernel* element,
int iterations, int mop )
{
CvMorphology morphology;
void* buffer = 0;
int local_alloc = 0;
void* morphstate = 0;
CvMat* temp = 0;
CV_FUNCNAME( "icvMorphOp" );
__BEGIN__;
int i, coi1 = 0, coi2 = 0;
CvMat srcstub, *src = (CvMat*)srcarr;
CvMat dststub, *dst = (CvMat*)dstarr;
CvMat el_hdr, *el = 0;
CvSize size, el_size;
CvPoint el_anchor;
int el_shape;
int type;
bool inplace;
if( !CV_IS_MAT(src) )
CV_CALL( src = cvGetMat( src, &srcstub, &coi1 ));
if( src != &srcstub )
{
srcstub = *src;
src = &srcstub;
}
if( dstarr == srcarr )
dst = src;
else
{
CV_CALL( dst = cvGetMat( dst, &dststub, &coi2 ));
if( !CV_ARE_TYPES_EQ( src, dst ))
CV_ERROR( CV_StsUnmatchedFormats, "" );
if( !CV_ARE_SIZES_EQ( src, dst ))
CV_ERROR( CV_StsUnmatchedSizes, "" );
}
if( dst != &dststub )
{
dststub = *dst;
dst = &dststub;
}
if( coi1 != 0 || coi2 != 0 )
CV_ERROR( CV_BadCOI, "" );
type = CV_MAT_TYPE( src->type );
size = cvGetMatSize( src );
inplace = src->data.ptr == dst->data.ptr;
if( iterations == 0 || (element && element->nCols == 1 && element->nRows == 1))
{
if( src->data.ptr != dst->data.ptr )
cvCopy( src, dst );
EXIT;
}
if( element )
{
el_size = cvSize( element->nCols, element->nRows );
el_anchor = cvPoint( element->anchorX, element->anchorY );
el_shape = (int)(element->nShiftR);
el_shape = el_shape < CV_SHAPE_CUSTOM ? el_shape : CV_SHAPE_CUSTOM;
}
else
{//如果element为NULL,则默认使用3x3的结构元素,anchor点为(1, 1),类型为RECT
el_size = cvSize(3,3);
el_anchor = cvPoint(1,1);
el_shape = CV_SHAPE_RECT;
}
if( el_shape == CV_SHAPE_RECT && iterations > 1 )
{//矩形结构元素的多次处理将变成1次处理
el_size.width += (el_size.width-1)*iterations;
el_size.height += (el_size.height-1)*iterations;
el_anchor.x *= iterations;
el_anchor.y *= iterations;
iterations = 1;
}
if( el_shape == CV_SHAPE_RECT && icvErodeRect_GetBufSize_8u_C1R_p )
{
CvMorphRectFunc_IPP rect_func = 0;
CvMorphRectGetBufSizeFunc_IPP rect_getbufsize_func = 0;
if( mop == 0 )
{
if( type == CV_8UC1 )
rect_getbufsize_func = icvErodeRect_GetBufSize_8u_C1R_p,
rect_func = icvErodeRect_8u_C1R_p;
else if( type == CV_8UC3 )
rect_getbufsize_func = icvErodeRect_GetBufSize_8u_C3R_p,
rect_func = icvErodeRect_8u_C3R_p;
else if( type == CV_8UC4 )
rect_getbufsize_func = icvErodeRect_GetBufSize_8u_C4R_p,
rect_func = icvErodeRect_8u_C4R_p;
else if( type == CV_32FC1 )
rect_getbufsize_func = icvErodeRect_GetBufSize_32f_C1R_p,
rect_func = icvErodeRect_32f_C1R_p;
else if( type == CV_32FC3 )
rect_getbufsize_func = icvErodeRect_GetBufSize_32f_C3R_p,
rect_func = icvErodeRect_32f_C3R_p;
else if( type == CV_32FC4 )
rect_getbufsize_func = icvErodeRect_GetBufSize_32f_C4R_p,
rect_func = icvErodeRect_32f_C4R_p;
}
else
{
if( type == CV_8UC1 )
rect_getbufsize_func = icvDilateRect_GetBufSize_8u_C1R_p,
rect_func = icvDilateRect_8u_C1R_p;
else if( type == CV_8UC3 )
rect_getbufsize_func = icvDilateRect_GetBufSize_8u_C3R_p,
rect_func = icvDilateRect_8u_C3R_p;
else if( type == CV_8UC4 )
rect_getbufsize_func = icvDilateRect_GetBufSize_8u_C4R_p,
rect_func = icvDilateRect_8u_C4R_p;
else if( type == CV_32FC1 )
rect_getbufsize_func = icvDilateRect_GetBufSize_32f_C1R_p,
rect_func = icvDilateRect_32f_C1R_p;
else if( type == CV_32FC3 )
rect_getbufsize_func = icvDilateRect_GetBufSize_32f_C3R_p,
rect_func = icvDilateRect_32f_C3R_p;
else if( type == CV_32FC4 )
rect_getbufsize_func = icvDilateRect_GetBufSize_32f_C4R_p,
rect_func = icvDilateRect_32f_C4R_p;
}
if( rect_getbufsize_func && rect_func )
{
int bufsize = 0;
CvStatus status = rect_getbufsize_func( size.width, el_size, &bufsize );
if( status >= 0 && bufsize > 0 )
{
if( bufsize < CV_MAX_LOCAL_SIZE )
{
buffer = cvStackAlloc( bufsize );
local_alloc = 1;
}
else
CV_CALL( buffer = cvAlloc( bufsize ));
}
if( status >= 0 )
{
int src_step, dst_step = dst->step ? dst->step : CV_STUB_STEP;
if( inplace )
{
CV_CALL( temp = cvCloneMat( dst ));
src = temp;
}
src_step = src->step ? src->step : CV_STUB_STEP;
status = rect_func( src->data.ptr, src_step, dst->data.ptr,
dst_step, size, el_size, el_anchor, buffer );
}
if( status >= 0 )
EXIT;
}
}
else if( el_shape == CV_SHAPE_CUSTOM && icvMorphInitAlloc_8u_C1R_p && icvMorphFree_p &&
src->data.ptr != dst->data.ptr )
{
CvMorphCustomFunc_IPP custom_func = 0;
CvMorphCustomInitAllocFunc_IPP custom_initalloc_func = 0;
const int bordertype = 1; // replication border
if( type == CV_8UC1 )
custom_initalloc_func = icvMorphInitAlloc_8u_C1R_p,
custom_func = mop == 0 ? icvErode_8u_C1R_p : icvDilate_8u_C1R_p;
else if( type == CV_8UC3 )
custom_initalloc_func = icvMorphInitAlloc_8u_C3R_p,
custom_func = mop == 0 ? icvErode_8u_C3R_p : icvDilate_8u_C3R_p;
else if( type == CV_8UC4 )
custom_initalloc_func = icvMorphInitAlloc_8u_C4R_p,
custom_func = mop == 0 ? icvErode_8u_C4R_p : icvDilate_8u_C4R_p;
else if( type == CV_32FC1 )
custom_initalloc_func = icvMorphInitAlloc_32f_C1R_p,
custom_func = mop == 0 ? icvErode_32f_C1R_p : icvDilate_32f_C1R_p;
else if( type == CV_32FC3 )
custom_initalloc_func = icvMorphInitAlloc_32f_C3R_p,
custom_func = mop == 0 ? icvErode_32f_C3R_p : icvDilate_32f_C3R_p;
else if( type == CV_32FC4 )
custom_initalloc_func = icvMorphInitAlloc_32f_C4R_p,
custom_func = mop == 0 ? icvErode_32f_C4R_p : icvDilate_32f_C4R_p;
if( custom_initalloc_func && custom_func )
{
uchar *src_ptr, *dst_ptr = dst->data.ptr;
int src_step, dst_step = dst->step ? dst->step : CV_STUB_STEP;
int el_len = el_size.width*el_size.height;
uchar* el_mask = (uchar*)cvStackAlloc( el_len );
CvStatus status;
for( i = 0; i < el_len; i++ )
el_mask[i] = (uchar)(element->values[i] != 0);
status = custom_initalloc_func( size.width, el_mask, el_size,
el_anchor, &morphstate );
if( status >= 0 && (inplace || iterations > 1) )
{
CV_CALL( temp = cvCloneMat( dst ));
src = temp;
}
src_ptr = src->data.ptr;
src_step = src->step ? src->step : CV_STUB_STEP;
for( i = 0; i < iterations && status >= 0 && morphstate; i++ )
{
uchar* t_ptr;
int t_step;
status = custom_func( src_ptr, src_step, dst_ptr, dst_step,
size, bordertype, morphstate );
CV_SWAP( src_ptr, dst_ptr, t_ptr );
CV_SWAP( src_step, dst_step, t_step );
if( i == 0 && temp )
{
dst_ptr = temp->data.ptr;
dst_step = temp->step ? temp->step : CV_STUB_STEP;
}
}
if( status >= 0 )
{
if( iterations % 2 == 0 )
cvCopy( temp, dst );
EXIT;
}
}
}
if( el_shape != CV_SHAPE_RECT )
{
el_hdr = cvMat( element->nRows, element->nCols, CV_32SC1, element->values );
el = &el_hdr;
el_shape = CV_SHAPE_CUSTOM;
}
//进入init
CV_CALL( morphology.init( mop, src->cols, src->type,
el_shape, el, el_size, el_anchor ));
for( i = 0; i < iterations; i++ )
{//进行处理
CV_CALL( morphology.process( src, dst ));
src = dst;
}
__END__;
if( !local_alloc )
cvFree( &buffer );
if( morphstate )
icvMorphFree_p( morphstate );
cvReleaseMat( &temp );
}