Home | History | Annotate | Download | only in src
      1 /*M///////////////////////////////////////////////////////////////////////////////////////
      2 //
      3 //  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
      4 //
      5 //  By downloading, copying, installing or using the software you agree to this license.
      6 //  If you do not agree to this license, do not download, install,
      7 //  copy or use the software.
      8 //
      9 //
     10 //                        Intel License Agreement
     11 //                For Open Source Computer Vision Library
     12 //
     13 // Copyright (C) 2000, Intel Corporation, all rights reserved.
     14 // Third party copyrights are property of their respective owners.
     15 //
     16 // Redistribution and use in source and binary forms, with or without modification,
     17 // are permitted provided that the following conditions are met:
     18 //
     19 //   * Redistribution's of source code must retain the above copyright notice,
     20 //     this list of conditions and the following disclaimer.
     21 //
     22 //   * Redistribution's in binary form must reproduce the above copyright notice,
     23 //     this list of conditions and the following disclaimer in the documentation
     24 //     and/or other materials provided with the distribution.
     25 //
     26 //   * The name of Intel Corporation may not be used to endorse or promote products
     27 //     derived from this software without specific prior written permission.
     28 //
     29 // This software is provided by the copyright holders and contributors "as is" and
     30 // any express or implied warranties, including, but not limited to, the implied
     31 // warranties of merchantability and fitness for a particular purpose are disclaimed.
     32 // In no event shall the Intel Corporation or contributors be liable for any direct,
     33 // indirect, incidental, special, exemplary, or consequential damages
     34 // (including, but not limited to, procurement of substitute goods or services;
     35 // loss of use, data, or profits; or business interruption) however caused
     36 // and on any theory of liability, whether in contract, strict liability,
     37 // or tort (including negligence or otherwise) arising in any way out of
     38 // the use of this software, even if advised of the possibility of such damage.
     39 //
     40 //M*/
     41 
     42 #include "_cv.h"
     43 #include <limits.h>
     44 #include <stdio.h>
     45 
     46 #define IPCV_MORPHOLOGY_PTRS( morphtype, flavor )               \
     47     icv##morphtype##Rect_##flavor##_C1R_t                       \
     48         icv##morphtype##Rect_##flavor##_C1R_p = 0;              \
     49     icv##morphtype##Rect_GetBufSize_##flavor##_C1R_t            \
     50         icv##morphtype##Rect_GetBufSize_##flavor##_C1R_p = 0;   \
     51     icv##morphtype##Rect_##flavor##_C3R_t                       \
     52         icv##morphtype##Rect_##flavor##_C3R_p = 0;              \
     53     icv##morphtype##Rect_GetBufSize_##flavor##_C3R_t            \
     54         icv##morphtype##Rect_GetBufSize_##flavor##_C3R_p = 0;   \
     55     icv##morphtype##Rect_##flavor##_C4R_t                       \
     56         icv##morphtype##Rect_##flavor##_C4R_p = 0;              \
     57     icv##morphtype##Rect_GetBufSize_##flavor##_C4R_t            \
     58         icv##morphtype##Rect_GetBufSize_##flavor##_C4R_p = 0;   \
     59                                                                 \
     60     icv##morphtype##_##flavor##_C1R_t                           \
     61         icv##morphtype##_##flavor##_C1R_p = 0;                  \
     62     icv##morphtype##_##flavor##_C3R_t                           \
     63         icv##morphtype##_##flavor##_C3R_p = 0;                  \
     64     icv##morphtype##_##flavor##_C4R_t                           \
     65         icv##morphtype##_##flavor##_C4R_p = 0;
     66 
     67 #define IPCV_MORPHOLOGY_INITALLOC_PTRS( flavor )                \
     68     icvMorphInitAlloc_##flavor##_C1R_t                          \
     69         icvMorphInitAlloc_##flavor##_C1R_p = 0;                 \
     70     icvMorphInitAlloc_##flavor##_C3R_t                          \
     71         icvMorphInitAlloc_##flavor##_C3R_p = 0;                 \
     72     icvMorphInitAlloc_##flavor##_C4R_t                          \
     73         icvMorphInitAlloc_##flavor##_C4R_p = 0;
     74 
     75 IPCV_MORPHOLOGY_PTRS( Erode, 8u )
     76 IPCV_MORPHOLOGY_PTRS( Erode, 16u )
     77 IPCV_MORPHOLOGY_PTRS( Erode, 32f )
     78 IPCV_MORPHOLOGY_PTRS( Dilate, 8u )
     79 IPCV_MORPHOLOGY_PTRS( Dilate, 16u )
     80 IPCV_MORPHOLOGY_PTRS( Dilate, 32f )
     81 IPCV_MORPHOLOGY_INITALLOC_PTRS( 8u )
     82 IPCV_MORPHOLOGY_INITALLOC_PTRS( 16u )
     83 IPCV_MORPHOLOGY_INITALLOC_PTRS( 32f )
     84 
     85 icvMorphFree_t icvMorphFree_p = 0;
     86 
     87 /****************************************************************************************\
     88                      Basic Morphological Operations: Erosion & Dilation
     89 \****************************************************************************************/
     90 
     91 static void icvErodeRectRow_8u( const uchar* src, uchar* dst, void* params );
     92 static void icvErodeRectRow_16u( const ushort* src, ushort* dst, void* params );
     93 static void icvErodeRectRow_32f( const int* src, int* dst, void* params );
     94 static void icvDilateRectRow_8u( const uchar* src, uchar* dst, void* params );
     95 static void icvDilateRectRow_16u( const ushort* src, ushort* dst, void* params );
     96 static void icvDilateRectRow_32f( const int* src, int* dst, void* params );
     97 
     98 static void icvErodeRectCol_8u( const uchar** src, uchar* dst, int dst_step,
     99                                 int count, void* params );
    100 static void icvErodeRectCol_16u( const ushort** src, ushort* dst, int dst_step,
    101                                  int count, void* params );
    102 static void icvErodeRectCol_32f( const int** src, int* dst, int dst_step,
    103                                  int count, void* params );
    104 static void icvDilateRectCol_8u( const uchar** src, uchar* dst, int dst_step,
    105                                  int count, void* params );
    106 static void icvDilateRectCol_16u( const ushort** src, ushort* dst, int dst_step,
    107                                   int count, void* params );
    108 static void icvDilateRectCol_32f( const int** src, int* dst, int dst_step,
    109                                   int count, void* params );
    110 
    111 static void icvErodeAny_8u( const uchar** src, uchar* dst, int dst_step,
    112                             int count, void* params );
    113 static void icvErodeAny_16u( const ushort** src, ushort* dst, int dst_step,
    114                              int count, void* params );
    115 static void icvErodeAny_32f( const int** src, int* dst, int dst_step,
    116                              int count, void* params );
    117 static void icvDilateAny_8u( const uchar** src, uchar* dst, int dst_step,
    118                              int count, void* params );
    119 static void icvDilateAny_16u( const ushort** src, ushort* dst, int dst_step,
    120                               int count, void* params );
    121 static void icvDilateAny_32f( const int** src, int* dst, int dst_step,
    122                               int count, void* params );
    123 
    124 CvMorphology::CvMorphology()
    125 {
    126     element = 0;
    127     el_sparse = 0;
    128 }
    129 
    130 CvMorphology::CvMorphology( int _operation, int _max_width, int _src_dst_type,
    131                             int _element_shape, CvMat* _element,
    132                             CvSize _ksize, CvPoint _anchor,
    133                             int _border_mode, CvScalar _border_value )
    134 {
    135     element = 0;
    136     el_sparse = 0;
    137     init( _operation, _max_width, _src_dst_type,
    138           _element_shape, _element, _ksize, _anchor,
    139           _border_mode, _border_value );
    140 }
    141 
    142 
    143 void CvMorphology::clear()
    144 {
    145     cvReleaseMat( &element );
    146     cvFree( &el_sparse );
    147     CvBaseImageFilter::clear();
    148 }
    149 
    150 
    151 CvMorphology::~CvMorphology()
    152 {
    153     clear();
    154 }
    155 
    156 
    157 void CvMorphology::init( int _operation, int _max_width, int _src_dst_type,
    158                          int _element_shape, CvMat* _element,
    159                          CvSize _ksize, CvPoint _anchor,
    160                          int _border_mode, CvScalar _border_value )
    161 {
    162     CV_FUNCNAME( "CvMorphology::init" );
    163 
    164     __BEGIN__;
    165 
    166     int depth = CV_MAT_DEPTH(_src_dst_type);
    167     int el_type = 0, nz = -1;
    168 
    169     if( _operation != ERODE && _operation != DILATE )
    170         CV_ERROR( CV_StsBadArg, "Unknown/unsupported morphological operation" );
    171 
    172     if( _element_shape == CUSTOM )
    173     {
    174         if( !CV_IS_MAT(_element) )
    175             CV_ERROR( CV_StsBadArg,
    176             "structuring element should be valid matrix if CUSTOM element shape is specified" );
    177 
    178         el_type = CV_MAT_TYPE(_element->type);
    179         if( el_type != CV_8UC1 && el_type != CV_32SC1 )
    180             CV_ERROR( CV_StsUnsupportedFormat, "the structuring element must have 8uC1 or 32sC1 type" );
    181 
    182         _ksize = cvGetMatSize(_element);
    183         CV_CALL( nz = cvCountNonZero(_element));
    184         if( nz == _ksize.width*_ksize.height )
    185             _element_shape = RECT;
    186     }
    187 
    188     operation = _operation;
    189     el_shape = _element_shape;
    190 
    191     CV_CALL( CvBaseImageFilter::init( _max_width, _src_dst_type, _src_dst_type,
    192         _element_shape == RECT, _ksize, _anchor, _border_mode, _border_value ));
    193 
    194     if( el_shape == RECT )
    195     {
    196         if( operation == ERODE )
    197         {
    198             if( depth == CV_8U )
    199                 x_func = (CvRowFilterFunc)icvErodeRectRow_8u,
    200                 y_func = (CvColumnFilterFunc)icvErodeRectCol_8u;
    201             else if( depth == CV_16U )
    202                 x_func = (CvRowFilterFunc)icvErodeRectRow_16u,
    203                 y_func = (CvColumnFilterFunc)icvErodeRectCol_16u;
    204             else if( depth == CV_32F )
    205                 x_func = (CvRowFilterFunc)icvErodeRectRow_32f,
    206                 y_func = (CvColumnFilterFunc)icvErodeRectCol_32f;
    207         }
    208         else
    209         {
    210             assert( operation == DILATE );
    211             if( depth == CV_8U )
    212                 x_func = (CvRowFilterFunc)icvDilateRectRow_8u,
    213                 y_func = (CvColumnFilterFunc)icvDilateRectCol_8u;
    214             else if( depth == CV_16U )
    215                 x_func = (CvRowFilterFunc)icvDilateRectRow_16u,
    216                 y_func = (CvColumnFilterFunc)icvDilateRectCol_16u;
    217             else if( depth == CV_32F )
    218                 x_func = (CvRowFilterFunc)icvDilateRectRow_32f,
    219                 y_func = (CvColumnFilterFunc)icvDilateRectCol_32f;
    220         }
    221     }
    222     else
    223     {
    224         int i, j, k = 0;
    225         int cn = CV_MAT_CN(src_type);
    226         CvPoint* nz_loc;
    227 
    228         if( !(element && el_sparse &&
    229             _ksize.width == element->cols && _ksize.height == element->rows) )
    230         {
    231             cvReleaseMat( &element );
    232             cvFree( &el_sparse );
    233             CV_CALL( element = cvCreateMat( _ksize.height, _ksize.width, CV_8UC1 ));
    234             CV_CALL( el_sparse = (uchar*)cvAlloc(
    235                 ksize.width*ksize.height*(2*sizeof(int) + sizeof(uchar*))));
    236         }
    237 
    238         if( el_shape == CUSTOM )
    239         {
    240             CV_CALL( cvConvert( _element, element ));
    241         }
    242         else
    243         {
    244             CV_CALL( init_binary_element( element, el_shape, anchor ));
    245         }
    246 
    247         if( operation == ERODE )
    248         {
    249             if( depth == CV_8U )
    250                 y_func = (CvColumnFilterFunc)icvErodeAny_8u;
    251             else if( depth == CV_16U )
    252                 y_func = (CvColumnFilterFunc)icvErodeAny_16u;
    253             else if( depth == CV_32F )
    254                 y_func = (CvColumnFilterFunc)icvErodeAny_32f;
    255         }
    256         else
    257         {
    258             assert( operation == DILATE );
    259             if( depth == CV_8U )
    260                 y_func = (CvColumnFilterFunc)icvDilateAny_8u;
    261             else if( depth == CV_16U )
    262                 y_func = (CvColumnFilterFunc)icvDilateAny_16u;
    263             else if( depth == CV_32F )
    264                 y_func = (CvColumnFilterFunc)icvDilateAny_32f;
    265         }
    266 
    267         nz_loc = (CvPoint*)el_sparse;
    268 
    269         for( i = 0; i < ksize.height; i++ )
    270             for( j = 0; j < ksize.width; j++ )
    271             {
    272                 if( element->data.ptr[i*element->step+j] )
    273                     nz_loc[k++] = cvPoint(j*cn,i);
    274             }
    275         if( k == 0 )
    276             nz_loc[k++] = cvPoint(anchor.x*cn,anchor.y);
    277         el_sparse_count = k;
    278     }
    279 
    280     if( depth == CV_32F && border_mode == IPL_BORDER_CONSTANT )
    281     {
    282         int i, cn = CV_MAT_CN(src_type);
    283         int* bt = (int*)border_tab;
    284         for( i = 0; i < cn; i++ )
    285             bt[i] = CV_TOGGLE_FLT(bt[i]);
    286     }
    287 
    288     __END__;
    289 }
    290 
    291 
    292 void CvMorphology::init( int _max_width, int _src_type, int _dst_type,
    293                          bool _is_separable, CvSize _ksize,
    294                          CvPoint _anchor, int _border_mode,
    295                          CvScalar _border_value )
    296 {
    297     CvBaseImageFilter::init( _max_width, _src_type, _dst_type, _is_separable,
    298                              _ksize, _anchor, _border_mode, _border_value );
    299 }
    300 
    301 
    302 void CvMorphology::start_process( CvSlice x_range, int width )
    303 {
    304     CvBaseImageFilter::start_process( x_range, width );
    305     if( el_shape == RECT )
    306     {
    307         // cut the cyclic buffer off by 1 line if need, to make
    308         // the vertical part of separable morphological filter
    309         // always process 2 rows at once (except, may be,
    310         // for the last one in a stripe).
    311         int t = buf_max_count - max_ky*2;
    312         if( t > 1 && t % 2 != 0 )
    313         {
    314             buf_max_count--;
    315             buf_end -= buf_step;
    316         }
    317     }
    318 }
    319 
    320 
    321 int CvMorphology::fill_cyclic_buffer( const uchar* src, int src_step,
    322                                       int y0, int y1, int y2 )
    323 {
    324     int i, y = y0, bsz1 = border_tab_sz1, bsz = border_tab_sz;
    325     int pix_size = CV_ELEM_SIZE(src_type);
    326     int width_n = (prev_x_range.end_index - prev_x_range.start_index)*pix_size;
    327 
    328     if( CV_MAT_DEPTH(src_type) != CV_32F )
    329         return CvBaseImageFilter::fill_cyclic_buffer( src, src_step, y0, y1, y2 );
    330 
    331     // fill the cyclic buffer
    332     for( ; buf_count < buf_max_count && y < y2; buf_count++, y++, src += src_step )
    333     {
    334         uchar* trow = is_separable ? buf_end : buf_tail;
    335 
    336         for( i = 0; i < width_n; i += sizeof(int) )
    337         {
    338             int t = *(int*)(src + i);
    339             *(int*)(trow + i + bsz1) = CV_TOGGLE_FLT(t);
    340         }
    341 
    342         if( border_mode != IPL_BORDER_CONSTANT )
    343         {
    344             for( i = 0; i < bsz1; i++ )
    345             {
    346                 int j = border_tab[i];
    347                 trow[i] = trow[j];
    348             }
    349             for( ; i < bsz; i++ )
    350             {
    351                 int j = border_tab[i];
    352                 trow[i + width_n] = trow[j];
    353             }
    354         }
    355         else
    356         {
    357             const uchar *bt = (uchar*)border_tab;
    358             for( i = 0; i < bsz1; i++ )
    359                 trow[i] = bt[i];
    360 
    361             for( ; i < bsz; i++ )
    362                 trow[i + width_n] = bt[i];
    363         }
    364 
    365         if( is_separable )
    366             x_func( trow, buf_tail, this );
    367 
    368         buf_tail += buf_step;
    369         if( buf_tail >= buf_end )
    370             buf_tail = buf_start;
    371     }
    372 
    373     return y - y0;
    374 }
    375 
    376 
    377 void CvMorphology::init_binary_element( CvMat* element, int element_shape, CvPoint anchor )
    378 {
    379     CV_FUNCNAME( "CvMorphology::init_binary_element" );
    380 
    381     __BEGIN__;
    382 
    383     int type;
    384     int i, j, cols, rows;
    385     int r = 0, c = 0;
    386     double inv_r2 = 0;
    387 
    388     if( !CV_IS_MAT(element) )
    389         CV_ERROR( CV_StsBadArg, "element must be valid matrix" );
    390 
    391     type = CV_MAT_TYPE(element->type);
    392     if( type != CV_8UC1 && type != CV_32SC1 )
    393         CV_ERROR( CV_StsUnsupportedFormat, "element must have 8uC1 or 32sC1 type" );
    394 
    395     if( anchor.x == -1 )
    396         anchor.x = element->cols/2;
    397 
    398     if( anchor.y == -1 )
    399         anchor.y = element->rows/2;
    400 
    401     if( (unsigned)anchor.x >= (unsigned)element->cols ||
    402         (unsigned)anchor.y >= (unsigned)element->rows )
    403         CV_ERROR( CV_StsOutOfRange, "anchor is outside of element" );
    404 
    405     if( element_shape != RECT && element_shape != CROSS && element_shape != ELLIPSE )
    406         CV_ERROR( CV_StsBadArg, "Unknown/unsupported element shape" );
    407 
    408     rows = element->rows;
    409     cols = element->cols;
    410 
    411     if( rows == 1 || cols == 1 )
    412         element_shape = RECT;
    413 
    414     if( element_shape == ELLIPSE )
    415     {
    416         r = rows/2;
    417         c = cols/2;
    418         inv_r2 = r ? 1./((double)r*r) : 0;
    419     }
    420 
    421     for( i = 0; i < rows; i++ )
    422     {
    423         uchar* ptr = element->data.ptr + i*element->step;
    424         int j1 = 0, j2 = 0, jx, t = 0;
    425 
    426         if( element_shape == RECT || (element_shape == CROSS && i == anchor.y) )
    427             j2 = cols;
    428         else if( element_shape == CROSS )
    429             j1 = anchor.x, j2 = j1 + 1;
    430         else
    431         {
    432             int dy = i - r;
    433             if( abs(dy) <= r )
    434             {
    435                 int dx = cvRound(c*sqrt(((double)r*r - dy*dy)*inv_r2));
    436                 j1 = MAX( c - dx, 0 );
    437                 j2 = MIN( c + dx + 1, cols );
    438             }
    439         }
    440 
    441         for( j = 0, jx = j1; j < cols; )
    442         {
    443             for( ; j < jx; j++ )
    444             {
    445                 if( type == CV_8UC1 )
    446                     ptr[j] = (uchar)t;
    447                 else
    448                     ((int*)ptr)[j] = t;
    449             }
    450             if( jx == j2 )
    451                 jx = cols, t = 0;
    452             else
    453                 jx = j2, t = 1;
    454         }
    455     }
    456 
    457     __END__;
    458 }
    459 
    460 
    461 #define ICV_MORPH_RECT_ROW( name, flavor, arrtype,          \
    462                             worktype, update_extr_macro )   \
    463 static void                                                 \
    464 icv##name##RectRow_##flavor( const arrtype* src,            \
    465                              arrtype* dst, void* params )   \
    466 {                                                           \
    467     const CvMorphology* state = (const CvMorphology*)params;\
    468     int ksize = state->get_kernel_size().width;             \
    469     int width = state->get_width();                         \
    470     int cn = CV_MAT_CN(state->get_src_type());              \
    471     int i, j, k;                                            \
    472                                                             \
    473     width *= cn; ksize *= cn;                               \
    474                                                             \
    475     if( ksize == cn )                                       \
    476     {                                                       \
    477         for( i = 0; i < width; i++ )                        \
    478             dst[i] = src[i];                                \
    479         return;                                             \
    480     }                                                       \
    481                                                             \
    482     for( k = 0; k < cn; k++, src++, dst++ )                 \
    483     {                                                       \
    484         for( i = 0; i <= width - cn*2; i += cn*2 )          \
    485         {                                                   \
    486             const arrtype* s = src + i;                     \
    487             worktype m = s[cn], t;                          \
    488             for( j = cn*2; j < ksize; j += cn )             \
    489             {                                               \
    490                 t = s[j]; update_extr_macro(m,t);           \
    491             }                                               \
    492             t = s[0]; update_extr_macro(t,m);               \
    493             dst[i] = (arrtype)t;                            \
    494             t = s[j]; update_extr_macro(t,m);               \
    495             dst[i+cn] = (arrtype)t;                         \
    496         }                                                   \
    497                                                             \
    498         for( ; i < width; i += cn )                         \
    499         {                                                   \
    500             const arrtype* s = src + i;                     \
    501             worktype m = s[0], t;                           \
    502             for( j = cn; j < ksize; j += cn )               \
    503             {                                               \
    504                 t = s[j]; update_extr_macro(m,t);           \
    505             }                                               \
    506             dst[i] = (arrtype)m;                            \
    507         }                                                   \
    508     }                                                       \
    509 }
    510 
    511 
    512 ICV_MORPH_RECT_ROW( Erode, 8u, uchar, int, CV_CALC_MIN_8U )
    513 ICV_MORPH_RECT_ROW( Dilate, 8u, uchar, int, CV_CALC_MAX_8U )
    514 ICV_MORPH_RECT_ROW( Erode, 16u, ushort, int, CV_CALC_MIN )
    515 ICV_MORPH_RECT_ROW( Dilate, 16u, ushort, int, CV_CALC_MAX )
    516 ICV_MORPH_RECT_ROW( Erode, 32f, int, int, CV_CALC_MIN )
    517 ICV_MORPH_RECT_ROW( Dilate, 32f, int, int, CV_CALC_MAX )
    518 
    519 
    520 #define ICV_MORPH_RECT_COL( name, flavor, arrtype,          \
    521         worktype, update_extr_macro, toggle_macro )         \
    522 static void                                                 \
    523 icv##name##RectCol_##flavor( const arrtype** src,           \
    524     arrtype* dst, int dst_step, int count, void* params )   \
    525 {                                                           \
    526     const CvMorphology* state = (const CvMorphology*)params;\
    527     int ksize = state->get_kernel_size().height;            \
    528     int width = state->get_width();                         \
    529     int cn = CV_MAT_CN(state->get_src_type());              \
    530     int i, k;                                               \
    531                                                             \
    532     width *= cn;                                            \
    533     dst_step /= sizeof(dst[0]);                             \
    534                                                             \
    535     for( ; ksize > 1 && count > 1; count -= 2,              \
    536                         dst += dst_step*2, src += 2 )       \
    537     {                                                       \
    538         for( i = 0; i <= width - 4; i += 4 )                \
    539         {                                                   \
    540             const arrtype* sptr = src[1] + i;               \
    541             worktype s0 = sptr[0], s1 = sptr[1],            \
    542                 s2 = sptr[2], s3 = sptr[3], t0, t1;         \
    543                                                             \
    544             for( k = 2; k < ksize; k++ )                    \
    545             {                                               \
    546                 sptr = src[k] + i;                          \
    547                 t0 = sptr[0]; t1 = sptr[1];                 \
    548                 update_extr_macro(s0,t0);                   \
    549                 update_extr_macro(s1,t1);                   \
    550                 t0 = sptr[2]; t1 = sptr[3];                 \
    551                 update_extr_macro(s2,t0);                   \
    552                 update_extr_macro(s3,t1);                   \
    553             }                                               \
    554                                                             \
    555             sptr = src[0] + i;                              \
    556             t0 = sptr[0]; t1 = sptr[1];                     \
    557             update_extr_macro(t0,s0);                       \
    558             update_extr_macro(t1,s1);                       \
    559             dst[i] = (arrtype)toggle_macro(t0);             \
    560             dst[i+1] = (arrtype)toggle_macro(t1);           \
    561             t0 = sptr[2]; t1 = sptr[3];                     \
    562             update_extr_macro(t0,s2);                       \
    563             update_extr_macro(t1,s3);                       \
    564             dst[i+2] = (arrtype)toggle_macro(t0);           \
    565             dst[i+3] = (arrtype)toggle_macro(t1);           \
    566                                                             \
    567             sptr = src[k] + i;                              \
    568             t0 = sptr[0]; t1 = sptr[1];                     \
    569             update_extr_macro(t0,s0);                       \
    570             update_extr_macro(t1,s1);                       \
    571             dst[i+dst_step] = (arrtype)toggle_macro(t0);    \
    572             dst[i+dst_step+1] = (arrtype)toggle_macro(t1);  \
    573             t0 = sptr[2]; t1 = sptr[3];                     \
    574             update_extr_macro(t0,s2);                       \
    575             update_extr_macro(t1,s3);                       \
    576             dst[i+dst_step+2] = (arrtype)toggle_macro(t0);  \
    577             dst[i+dst_step+3] = (arrtype)toggle_macro(t1);  \
    578         }                                                   \
    579                                                             \
    580         for( ; i < width; i++ )                             \
    581         {                                                   \
    582             const arrtype* sptr = src[1] + i;               \
    583             worktype s0 = sptr[0], t0;                      \
    584                                                             \
    585             for( k = 2; k < ksize; k++ )                    \
    586             {                                               \
    587                 sptr = src[k] + i; t0 = sptr[0];            \
    588                 update_extr_macro(s0,t0);                   \
    589             }                                               \
    590                                                             \
    591             sptr = src[0] + i; t0 = sptr[0];                \
    592             update_extr_macro(t0,s0);                       \
    593             dst[i] = (arrtype)toggle_macro(t0);             \
    594                                                             \
    595             sptr = src[k] + i; t0 = sptr[0];                \
    596             update_extr_macro(t0,s0);                       \
    597             dst[i+dst_step] = (arrtype)toggle_macro(t0);    \
    598         }                                                   \
    599     }                                                       \
    600                                                             \
    601     for( ; count > 0; count--, dst += dst_step, src++ )     \
    602     {                                                       \
    603         for( i = 0; i <= width - 4; i += 4 )                \
    604         {                                                   \
    605             const arrtype* sptr = src[0] + i;               \
    606             worktype s0 = sptr[0], s1 = sptr[1],            \
    607                 s2 = sptr[2], s3 = sptr[3], t0, t1;         \
    608                                                             \
    609             for( k = 1; k < ksize; k++ )                    \
    610             {                                               \
    611                 sptr = src[k] + i;                          \
    612                 t0 = sptr[0]; t1 = sptr[1];                 \
    613                 update_extr_macro(s0,t0);                   \
    614                 update_extr_macro(s1,t1);                   \
    615                 t0 = sptr[2]; t1 = sptr[3];                 \
    616                 update_extr_macro(s2,t0);                   \
    617                 update_extr_macro(s3,t1);                   \
    618             }                                               \
    619             dst[i] = (arrtype)toggle_macro(s0);             \
    620             dst[i+1] = (arrtype)toggle_macro(s1);           \
    621             dst[i+2] = (arrtype)toggle_macro(s2);           \
    622             dst[i+3] = (arrtype)toggle_macro(s3);           \
    623         }                                                   \
    624                                                             \
    625         for( ; i < width; i++ )                             \
    626         {                                                   \
    627             const arrtype* sptr = src[0] + i;               \
    628             worktype s0 = sptr[0], t0;                      \
    629                                                             \
    630             for( k = 1; k < ksize; k++ )                    \
    631             {                                               \
    632                 sptr = src[k] + i; t0 = sptr[0];            \
    633                 update_extr_macro(s0,t0);                   \
    634             }                                               \
    635             dst[i] = (arrtype)toggle_macro(s0);             \
    636         }                                                   \
    637     }                                                       \
    638 }
    639 
    640 
    641 ICV_MORPH_RECT_COL( Erode, 8u, uchar, int, CV_CALC_MIN_8U, CV_NOP )
    642 ICV_MORPH_RECT_COL( Dilate, 8u, uchar, int, CV_CALC_MAX_8U, CV_NOP )
    643 ICV_MORPH_RECT_COL( Erode, 16u, ushort, int, CV_CALC_MIN, CV_NOP )
    644 ICV_MORPH_RECT_COL( Dilate, 16u, ushort, int, CV_CALC_MAX, CV_NOP )
    645 ICV_MORPH_RECT_COL( Erode, 32f, int, int, CV_CALC_MIN, CV_TOGGLE_FLT )
    646 ICV_MORPH_RECT_COL( Dilate, 32f, int, int, CV_CALC_MAX, CV_TOGGLE_FLT )
    647 
    648 
    649 #define ICV_MORPH_ANY( name, flavor, arrtype, worktype,     \
    650                        update_extr_macro, toggle_macro )    \
    651 static void                                                 \
    652 icv##name##Any_##flavor( const arrtype** src, arrtype* dst, \
    653                     int dst_step, int count, void* params ) \
    654 {                                                           \
    655     CvMorphology* state = (CvMorphology*)params;            \
    656     int width = state->get_width();                         \
    657     int cn = CV_MAT_CN(state->get_src_type());              \
    658     int i, k;                                               \
    659     CvPoint* el_sparse = (CvPoint*)state->get_element_sparse_buf();\
    660     int el_count = state->get_element_sparse_count();       \
    661     const arrtype** el_ptr = (const arrtype**)(el_sparse + el_count);\
    662     const arrtype** el_end = el_ptr + el_count;             \
    663                                                             \
    664     width *= cn;                                            \
    665     dst_step /= sizeof(dst[0]);                             \
    666                                                             \
    667     for( ; count > 0; count--, dst += dst_step, src++ )     \
    668     {                                                       \
    669         for( k = 0; k < el_count; k++ )                     \
    670             el_ptr[k] = src[el_sparse[k].y]+el_sparse[k].x; \
    671                                                             \
    672         for( i = 0; i <= width - 4; i += 4 )                \
    673         {                                                   \
    674             const arrtype** psptr = el_ptr;                 \
    675             const arrtype* sptr = *psptr++;                 \
    676             worktype s0 = sptr[i], s1 = sptr[i+1],          \
    677                      s2 = sptr[i+2], s3 = sptr[i+3], t;     \
    678                                                             \
    679             while( psptr != el_end )                        \
    680             {                                               \
    681                 sptr = *psptr++;                            \
    682                 t = sptr[i];                                \
    683                 update_extr_macro(s0,t);                    \
    684                 t = sptr[i+1];                              \
    685                 update_extr_macro(s1,t);                    \
    686                 t = sptr[i+2];                              \
    687                 update_extr_macro(s2,t);                    \
    688                 t = sptr[i+3];                              \
    689                 update_extr_macro(s3,t);                    \
    690             }                                               \
    691                                                             \
    692             dst[i] = (arrtype)toggle_macro(s0);             \
    693             dst[i+1] = (arrtype)toggle_macro(s1);           \
    694             dst[i+2] = (arrtype)toggle_macro(s2);           \
    695             dst[i+3] = (arrtype)toggle_macro(s3);           \
    696         }                                                   \
    697                                                             \
    698         for( ; i < width; i++ )                             \
    699         {                                                   \
    700             const arrtype* sptr = el_ptr[0] + i;            \
    701             worktype s0 = sptr[0], t0;                      \
    702                                                             \
    703             for( k = 1; k < el_count; k++ )                 \
    704             {                                               \
    705                 sptr = el_ptr[k] + i;                       \
    706                 t0 = sptr[0];                               \
    707                 update_extr_macro(s0,t0);                   \
    708             }                                               \
    709                                                             \
    710             dst[i] = (arrtype)toggle_macro(s0);             \
    711         }                                                   \
    712     }                                                       \
    713 }
    714 
    715 ICV_MORPH_ANY( Erode, 8u, uchar, int, CV_CALC_MIN, CV_NOP )
    716 ICV_MORPH_ANY( Dilate, 8u, uchar, int, CV_CALC_MAX, CV_NOP )
    717 ICV_MORPH_ANY( Erode, 16u, ushort, int, CV_CALC_MIN, CV_NOP )
    718 ICV_MORPH_ANY( Dilate, 16u, ushort, int, CV_CALC_MAX, CV_NOP )
    719 ICV_MORPH_ANY( Erode, 32f, int, int, CV_CALC_MIN, CV_TOGGLE_FLT )
    720 ICV_MORPH_ANY( Dilate, 32f, int, int, CV_CALC_MAX, CV_TOGGLE_FLT )
    721 
    722 /////////////////////////////////// External Interface /////////////////////////////////////
    723 
    724 
    725 CV_IMPL IplConvKernel *
    726 cvCreateStructuringElementEx( int cols, int rows,
    727                               int anchorX, int anchorY,
    728                               int shape, int *values )
    729 {
    730     IplConvKernel *element = 0;
    731     int i, size = rows * cols;
    732     int element_size = sizeof(*element) + size*sizeof(element->values[0]);
    733 
    734     CV_FUNCNAME( "cvCreateStructuringElementEx" );
    735 
    736     __BEGIN__;
    737 
    738     if( !values && shape == CV_SHAPE_CUSTOM )
    739         CV_ERROR_FROM_STATUS( CV_NULLPTR_ERR );
    740 
    741     if( cols <= 0 || rows <= 0 ||
    742         (unsigned) anchorX >= (unsigned) cols ||
    743         (unsigned) anchorY >= (unsigned) rows )
    744         CV_ERROR_FROM_STATUS( CV_BADSIZE_ERR );
    745 
    746     CV_CALL( element = (IplConvKernel *)cvAlloc(element_size + 32));
    747     if( !element )
    748         CV_ERROR_FROM_STATUS( CV_OUTOFMEM_ERR );
    749 
    750     element->nCols = cols;
    751     element->nRows = rows;
    752     element->anchorX = anchorX;
    753     element->anchorY = anchorY;
    754     element->nShiftR = shape < CV_SHAPE_ELLIPSE ? shape : CV_SHAPE_CUSTOM;
    755     element->values = (int*)(element + 1);
    756 
    757     if( shape == CV_SHAPE_CUSTOM )
    758     {
    759         if( !values )
    760             CV_ERROR( CV_StsNullPtr, "Null pointer to the custom element mask" );
    761         for( i = 0; i < size; i++ )
    762             element->values[i] = values[i];
    763     }
    764     else
    765     {
    766         CvMat el_hdr = cvMat( rows, cols, CV_32SC1, element->values );
    767         CV_CALL( CvMorphology::init_binary_element(&el_hdr,
    768                         shape, cvPoint(anchorX,anchorY)));
    769     }
    770 
    771     __END__;
    772 
    773     if( cvGetErrStatus() < 0 )
    774         cvReleaseStructuringElement( &element );
    775 
    776     return element;
    777 }
    778 
    779 
    780 CV_IMPL void
    781 cvReleaseStructuringElement( IplConvKernel ** element )
    782 {
    783     CV_FUNCNAME( "cvReleaseStructuringElement" );
    784 
    785     __BEGIN__;
    786 
    787     if( !element )
    788         CV_ERROR( CV_StsNullPtr, "" );
    789     cvFree( element );
    790 
    791     __END__;
    792 }
    793 
    794 
    795 typedef CvStatus (CV_STDCALL * CvMorphRectGetBufSizeFunc_IPP)
    796     ( int width, CvSize el_size, int* bufsize );
    797 
    798 typedef CvStatus (CV_STDCALL * CvMorphRectFunc_IPP)
    799     ( const void* src, int srcstep, void* dst, int dststep,
    800       CvSize roi, CvSize el_size, CvPoint el_anchor, void* buffer );
    801 
    802 typedef CvStatus (CV_STDCALL * CvMorphCustomInitAllocFunc_IPP)
    803     ( int width, const uchar* element, CvSize el_size,
    804       CvPoint el_anchor, void** morphstate );
    805 
    806 typedef CvStatus (CV_STDCALL * CvMorphCustomFunc_IPP)
    807     ( const void* src, int srcstep, void* dst, int dststep,
    808       CvSize roi, int bordertype, void* morphstate );
    809 
    810 static void
    811 icvMorphOp( const void* srcarr, void* dstarr, IplConvKernel* element,
    812             int iterations, int mop )
    813 {
    814     CvMorphology morphology;
    815     void* buffer = 0;
    816     int local_alloc = 0;
    817     void* morphstate = 0;
    818     CvMat* temp = 0;
    819 
    820     CV_FUNCNAME( "icvMorphOp" );
    821 
    822     __BEGIN__;
    823 
    824     int i, coi1 = 0, coi2 = 0;
    825     CvMat srcstub, *src = (CvMat*)srcarr;
    826     CvMat dststub, *dst = (CvMat*)dstarr;
    827     CvMat el_hdr, *el = 0;
    828     CvSize size, el_size;
    829     CvPoint el_anchor;
    830     int el_shape;
    831     int type;
    832     bool inplace;
    833 
    834     if( !CV_IS_MAT(src) )
    835         CV_CALL( src = cvGetMat( src, &srcstub, &coi1 ));
    836 
    837     if( src != &srcstub )
    838     {
    839         srcstub = *src;
    840         src = &srcstub;
    841     }
    842 
    843     if( dstarr == srcarr )
    844         dst = src;
    845     else
    846     {
    847         CV_CALL( dst = cvGetMat( dst, &dststub, &coi2 ));
    848 
    849         if( !CV_ARE_TYPES_EQ( src, dst ))
    850             CV_ERROR( CV_StsUnmatchedFormats, "" );
    851 
    852         if( !CV_ARE_SIZES_EQ( src, dst ))
    853             CV_ERROR( CV_StsUnmatchedSizes, "" );
    854     }
    855 
    856     if( dst != &dststub )
    857     {
    858         dststub = *dst;
    859         dst = &dststub;
    860     }
    861 
    862     if( coi1 != 0 || coi2 != 0 )
    863         CV_ERROR( CV_BadCOI, "" );
    864 
    865     type = CV_MAT_TYPE( src->type );
    866     size = cvGetMatSize( src );
    867     inplace = src->data.ptr == dst->data.ptr;
    868 
    869     if( iterations == 0 || (element && element->nCols == 1 && element->nRows == 1))
    870     {
    871         if( src->data.ptr != dst->data.ptr )
    872             cvCopy( src, dst );
    873         EXIT;
    874     }
    875 
    876     if( element )
    877     {
    878         el_size = cvSize( element->nCols, element->nRows );
    879         el_anchor = cvPoint( element->anchorX, element->anchorY );
    880         el_shape = (int)(element->nShiftR);
    881         el_shape = el_shape < CV_SHAPE_CUSTOM ? el_shape : CV_SHAPE_CUSTOM;
    882     }
    883     else
    884     {
    885         el_size = cvSize(3,3);
    886         el_anchor = cvPoint(1,1);
    887         el_shape = CV_SHAPE_RECT;
    888     }
    889 
    890     if( el_shape == CV_SHAPE_RECT && iterations > 1 )
    891     {
    892         el_size.width = 1 + (el_size.width-1)*iterations;
    893         el_size.height = 1 + (el_size.height-1)*iterations;
    894         el_anchor.x *= iterations;
    895         el_anchor.y *= iterations;
    896         iterations = 1;
    897     }
    898 
    899     if( el_shape == CV_SHAPE_RECT && icvErodeRect_GetBufSize_8u_C1R_p )
    900     {
    901         CvMorphRectFunc_IPP rect_func = 0;
    902         CvMorphRectGetBufSizeFunc_IPP rect_getbufsize_func = 0;
    903 
    904         if( mop == 0 )
    905         {
    906             if( type == CV_8UC1 )
    907                 rect_getbufsize_func = icvErodeRect_GetBufSize_8u_C1R_p,
    908                 rect_func = icvErodeRect_8u_C1R_p;
    909             else if( type == CV_8UC3 )
    910                 rect_getbufsize_func = icvErodeRect_GetBufSize_8u_C3R_p,
    911                 rect_func = icvErodeRect_8u_C3R_p;
    912             else if( type == CV_8UC4 )
    913                 rect_getbufsize_func = icvErodeRect_GetBufSize_8u_C4R_p,
    914                 rect_func = icvErodeRect_8u_C4R_p;
    915             else if( type == CV_16UC1 )
    916                 rect_getbufsize_func = icvErodeRect_GetBufSize_16u_C1R_p,
    917                 rect_func = icvErodeRect_16u_C1R_p;
    918             else if( type == CV_16UC3 )
    919                 rect_getbufsize_func = icvErodeRect_GetBufSize_16u_C3R_p,
    920                 rect_func = icvErodeRect_16u_C3R_p;
    921             else if( type == CV_16UC4 )
    922                 rect_getbufsize_func = icvErodeRect_GetBufSize_16u_C4R_p,
    923                 rect_func = icvErodeRect_16u_C4R_p;
    924             else if( type == CV_32FC1 )
    925                 rect_getbufsize_func = icvErodeRect_GetBufSize_32f_C1R_p,
    926                 rect_func = icvErodeRect_32f_C1R_p;
    927             else if( type == CV_32FC3 )
    928                 rect_getbufsize_func = icvErodeRect_GetBufSize_32f_C3R_p,
    929                 rect_func = icvErodeRect_32f_C3R_p;
    930             else if( type == CV_32FC4 )
    931                 rect_getbufsize_func = icvErodeRect_GetBufSize_32f_C4R_p,
    932                 rect_func = icvErodeRect_32f_C4R_p;
    933         }
    934         else
    935         {
    936             if( type == CV_8UC1 )
    937                 rect_getbufsize_func = icvDilateRect_GetBufSize_8u_C1R_p,
    938                 rect_func = icvDilateRect_8u_C1R_p;
    939             else if( type == CV_8UC3 )
    940                 rect_getbufsize_func = icvDilateRect_GetBufSize_8u_C3R_p,
    941                 rect_func = icvDilateRect_8u_C3R_p;
    942             else if( type == CV_8UC4 )
    943                 rect_getbufsize_func = icvDilateRect_GetBufSize_8u_C4R_p,
    944                 rect_func = icvDilateRect_8u_C4R_p;
    945             else if( type == CV_16UC1 )
    946                 rect_getbufsize_func = icvDilateRect_GetBufSize_16u_C1R_p,
    947                 rect_func = icvDilateRect_16u_C1R_p;
    948             else if( type == CV_16UC3 )
    949                 rect_getbufsize_func = icvDilateRect_GetBufSize_16u_C3R_p,
    950                 rect_func = icvDilateRect_16u_C3R_p;
    951             else if( type == CV_16UC4 )
    952                 rect_getbufsize_func = icvDilateRect_GetBufSize_16u_C4R_p,
    953                 rect_func = icvDilateRect_16u_C4R_p;
    954             else if( type == CV_32FC1 )
    955                 rect_getbufsize_func = icvDilateRect_GetBufSize_32f_C1R_p,
    956                 rect_func = icvDilateRect_32f_C1R_p;
    957             else if( type == CV_32FC3 )
    958                 rect_getbufsize_func = icvDilateRect_GetBufSize_32f_C3R_p,
    959                 rect_func = icvDilateRect_32f_C3R_p;
    960             else if( type == CV_32FC4 )
    961                 rect_getbufsize_func = icvDilateRect_GetBufSize_32f_C4R_p,
    962                 rect_func = icvDilateRect_32f_C4R_p;
    963         }
    964 
    965         if( rect_getbufsize_func && rect_func )
    966         {
    967             int bufsize = 0;
    968 
    969             CvStatus status = rect_getbufsize_func( size.width, el_size, &bufsize );
    970             if( status >= 0 && bufsize > 0 )
    971             {
    972                 if( bufsize < CV_MAX_LOCAL_SIZE )
    973                 {
    974                     buffer = cvStackAlloc( bufsize );
    975                     local_alloc = 1;
    976                 }
    977                 else
    978                     CV_CALL( buffer = cvAlloc( bufsize ));
    979             }
    980 
    981             if( status >= 0 )
    982             {
    983                 int src_step, dst_step = dst->step ? dst->step : CV_STUB_STEP;
    984 
    985                 if( inplace )
    986                 {
    987                     CV_CALL( temp = cvCloneMat( dst ));
    988                     src = temp;
    989                 }
    990                 src_step = src->step ? src->step : CV_STUB_STEP;
    991 
    992                 status = rect_func( src->data.ptr, src_step, dst->data.ptr,
    993                                     dst_step, size, el_size, el_anchor, buffer );
    994             }
    995 
    996             if( status >= 0 )
    997                 EXIT;
    998         }
    999     }
   1000     else if( el_shape == CV_SHAPE_CUSTOM && icvMorphInitAlloc_8u_C1R_p && icvMorphFree_p &&
   1001              src->data.ptr != dst->data.ptr )
   1002     {
   1003         CvMorphCustomFunc_IPP custom_func = 0;
   1004         CvMorphCustomInitAllocFunc_IPP custom_initalloc_func = 0;
   1005         const int bordertype = 1; // replication border
   1006 
   1007         if( type == CV_8UC1 )
   1008             custom_initalloc_func = icvMorphInitAlloc_8u_C1R_p,
   1009             custom_func = mop == 0 ? icvErode_8u_C1R_p : icvDilate_8u_C1R_p;
   1010         else if( type == CV_8UC3 )
   1011             custom_initalloc_func = icvMorphInitAlloc_8u_C3R_p,
   1012             custom_func = mop == 0 ? icvErode_8u_C3R_p : icvDilate_8u_C3R_p;
   1013         else if( type == CV_8UC4 )
   1014             custom_initalloc_func = icvMorphInitAlloc_8u_C4R_p,
   1015             custom_func = mop == 0 ? icvErode_8u_C4R_p : icvDilate_8u_C4R_p;
   1016         else if( type == CV_16UC1 )
   1017             custom_initalloc_func = icvMorphInitAlloc_16u_C1R_p,
   1018             custom_func = mop == 0 ? icvErode_16u_C1R_p : icvDilate_16u_C1R_p;
   1019         else if( type == CV_16UC3 )
   1020             custom_initalloc_func = icvMorphInitAlloc_16u_C3R_p,
   1021             custom_func = mop == 0 ? icvErode_16u_C3R_p : icvDilate_16u_C3R_p;
   1022         else if( type == CV_16UC4 )
   1023             custom_initalloc_func = icvMorphInitAlloc_16u_C4R_p,
   1024             custom_func = mop == 0 ? icvErode_16u_C4R_p : icvDilate_16u_C4R_p;
   1025         else if( type == CV_32FC1 )
   1026             custom_initalloc_func = icvMorphInitAlloc_32f_C1R_p,
   1027             custom_func = mop == 0 ? icvErode_32f_C1R_p : icvDilate_32f_C1R_p;
   1028         else if( type == CV_32FC3 )
   1029             custom_initalloc_func = icvMorphInitAlloc_32f_C3R_p,
   1030             custom_func = mop == 0 ? icvErode_32f_C3R_p : icvDilate_32f_C3R_p;
   1031         else if( type == CV_32FC4 )
   1032             custom_initalloc_func = icvMorphInitAlloc_32f_C4R_p,
   1033             custom_func = mop == 0 ? icvErode_32f_C4R_p : icvDilate_32f_C4R_p;
   1034 
   1035         if( custom_initalloc_func && custom_func )
   1036         {
   1037             uchar *src_ptr, *dst_ptr = dst->data.ptr;
   1038             int src_step, dst_step = dst->step ? dst->step : CV_STUB_STEP;
   1039             int el_len = el_size.width*el_size.height;
   1040             uchar* el_mask = (uchar*)cvStackAlloc( el_len );
   1041             CvStatus status;
   1042 
   1043             for( i = 0; i < el_len; i++ )
   1044                 el_mask[i] = (uchar)(element->values[i] != 0);
   1045 
   1046             status = custom_initalloc_func( size.width, el_mask, el_size,
   1047                                             el_anchor, &morphstate );
   1048 
   1049             if( status >= 0 && (inplace || iterations > 1) )
   1050             {
   1051                 CV_CALL( temp = cvCloneMat( src ));
   1052                 src = temp;
   1053             }
   1054 
   1055             src_ptr = src->data.ptr;
   1056             src_step = src->step ? src->step : CV_STUB_STEP;
   1057 
   1058             for( i = 0; i < iterations && status >= 0 && morphstate; i++ )
   1059             {
   1060                 uchar* t_ptr;
   1061                 int t_step;
   1062                 status = custom_func( src_ptr, src_step, dst_ptr, dst_step,
   1063                                       size, bordertype, morphstate );
   1064                 CV_SWAP( src_ptr, dst_ptr, t_ptr );
   1065                 CV_SWAP( src_step, dst_step, t_step );
   1066                 if( i == 0 && temp )
   1067                 {
   1068                     dst_ptr = temp->data.ptr;
   1069                     dst_step = temp->step ? temp->step : CV_STUB_STEP;
   1070                 }
   1071             }
   1072 
   1073             if( status >= 0 )
   1074             {
   1075                 if( iterations % 2 == 0 )
   1076                     cvCopy( temp, dst );
   1077                 EXIT;
   1078             }
   1079         }
   1080     }
   1081 
   1082     if( el_shape != CV_SHAPE_RECT )
   1083     {
   1084         el_hdr = cvMat( element->nRows, element->nCols, CV_32SC1, element->values );
   1085         el = &el_hdr;
   1086         el_shape = CV_SHAPE_CUSTOM;
   1087     }
   1088 
   1089     CV_CALL( morphology.init( mop, src->cols, src->type,
   1090                     el_shape, el, el_size, el_anchor ));
   1091 
   1092     for( i = 0; i < iterations; i++ )
   1093     {
   1094         CV_CALL( morphology.process( src, dst ));
   1095         src = dst;
   1096     }
   1097 
   1098     __END__;
   1099 
   1100     if( !local_alloc )
   1101         cvFree( &buffer );
   1102     if( morphstate )
   1103         icvMorphFree_p( morphstate );
   1104     cvReleaseMat( &temp );
   1105 }
   1106 
   1107 
   1108 CV_IMPL void
   1109 cvErode( const void* src, void* dst, IplConvKernel* element, int iterations )
   1110 {
   1111     icvMorphOp( src, dst, element, iterations, 0 );
   1112 }
   1113 
   1114 
   1115 CV_IMPL void
   1116 cvDilate( const void* src, void* dst, IplConvKernel* element, int iterations )
   1117 {
   1118     icvMorphOp( src, dst, element, iterations, 1 );
   1119 }
   1120 
   1121 
   1122 CV_IMPL void
   1123 cvMorphologyEx( const void* src, void* dst,
   1124                 void* temp, IplConvKernel* element, int op, int iterations )
   1125 {
   1126     CV_FUNCNAME( "cvMorhologyEx" );
   1127 
   1128     __BEGIN__;
   1129 
   1130     if( (op == CV_MOP_GRADIENT ||
   1131         ((op == CV_MOP_TOPHAT || op == CV_MOP_BLACKHAT) && src == dst)) && temp == 0 )
   1132         CV_ERROR( CV_HeaderIsNull, "temp image required" );
   1133 
   1134     if( temp == src || temp == dst )
   1135         CV_ERROR( CV_HeaderIsNull, "temp image is equal to src or dst" );
   1136 
   1137     switch (op)
   1138     {
   1139     case CV_MOP_OPEN:
   1140         CV_CALL( cvErode( src, dst, element, iterations ));
   1141         CV_CALL( cvDilate( dst, dst, element, iterations ));
   1142         break;
   1143     case CV_MOP_CLOSE:
   1144         CV_CALL( cvDilate( src, dst, element, iterations ));
   1145         CV_CALL( cvErode( dst, dst, element, iterations ));
   1146         break;
   1147     case CV_MOP_GRADIENT:
   1148         CV_CALL( cvErode( src, temp, element, iterations ));
   1149         CV_CALL( cvDilate( src, dst, element, iterations ));
   1150         CV_CALL( cvSub( dst, temp, dst ));
   1151         break;
   1152     case CV_MOP_TOPHAT:
   1153         if( src != dst )
   1154             temp = dst;
   1155         CV_CALL( cvErode( src, temp, element, iterations ));
   1156         CV_CALL( cvDilate( temp, temp, element, iterations ));
   1157         CV_CALL( cvSub( src, temp, dst ));
   1158         break;
   1159     case CV_MOP_BLACKHAT:
   1160         if( src != dst )
   1161             temp = dst;
   1162         CV_CALL( cvDilate( src, temp, element, iterations ));
   1163         CV_CALL( cvErode( temp, temp, element, iterations ));
   1164         CV_CALL( cvSub( temp, src, dst ));
   1165         break;
   1166     default:
   1167         CV_ERROR( CV_StsBadArg, "unknown morphological operation" );
   1168     }
   1169 
   1170     __END__;
   1171 }
   1172 
   1173 /* End of file. */
   1174