cvDilate 源码分析(1)

在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 );
}

 

你可能感兴趣的:(opencv学习,dst,c,buffer,null,matrix,filter)