• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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  
CvMorphology()124  CvMorphology::CvMorphology()
125  {
126      element = 0;
127      el_sparse = 0;
128  }
129  
CvMorphology(int _operation,int _max_width,int _src_dst_type,int _element_shape,CvMat * _element,CvSize _ksize,CvPoint _anchor,int _border_mode,CvScalar _border_value)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  
clear()143  void CvMorphology::clear()
144  {
145      cvReleaseMat( &element );
146      cvFree( &el_sparse );
147      CvBaseImageFilter::clear();
148  }
149  
150  
~CvMorphology()151  CvMorphology::~CvMorphology()
152  {
153      clear();
154  }
155  
156  
init(int _operation,int _max_width,int _src_dst_type,int _element_shape,CvMat * _element,CvSize _ksize,CvPoint _anchor,int _border_mode,CvScalar _border_value)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  
init(int _max_width,int _src_type,int _dst_type,bool _is_separable,CvSize _ksize,CvPoint _anchor,int _border_mode,CvScalar _border_value)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  
start_process(CvSlice x_range,int width)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  
fill_cyclic_buffer(const uchar * src,int src_step,int y0,int y1,int y2)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  
init_binary_element(CvMat * element,int element_shape,CvPoint anchor)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 *
cvCreateStructuringElementEx(int cols,int rows,int anchorX,int anchorY,int shape,int * values)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
cvReleaseStructuringElement(IplConvKernel ** element)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
icvMorphOp(const void * srcarr,void * dstarr,IplConvKernel * element,int iterations,int mop)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
cvErode(const void * src,void * dst,IplConvKernel * element,int iterations)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
cvDilate(const void * src,void * dst,IplConvKernel * element,int iterations)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
cvMorphologyEx(const void * src,void * dst,void * temp,IplConvKernel * element,int op,int iterations)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