1 /*M///////////////////////////////////////////////////////////////////////////////////////
3 // IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
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.
10 // Intel License Agreement
11 // For Open Source Computer Vision Library
13 // Copyright (C) 2000, Intel Corporation, all rights reserved.
14 // Third party copyrights are property of their respective owners.
16 // Redistribution and use in source and binary forms, with or without modification,
17 // are permitted provided that the following conditions are met:
19 // * Redistribution's of source code must retain the above copyright notice,
20 // this list of conditions and the following disclaimer.
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.
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.
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.
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; \
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;
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;
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 )
85 icvMorphFree_t icvMorphFree_p = 0;
87 /****************************************************************************************\
88 Basic Morphological Operations: Erosion & Dilation
89 \****************************************************************************************/
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 );
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 );
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 );
124 CvMorphology::CvMorphology()
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 )
137 init( _operation, _max_width, _src_dst_type,
138 _element_shape, _element, _ksize, _anchor,
139 _border_mode, _border_value );
143 void CvMorphology::clear()
145 cvReleaseMat( &element );
146 cvFree( &el_sparse );
147 CvBaseImageFilter::clear();
151 CvMorphology::~CvMorphology()
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 )
162 CV_FUNCNAME( "CvMorphology::init" );
166 int depth = CV_MAT_DEPTH(_src_dst_type);
167 int el_type = 0, nz = -1;
169 if( _operation != ERODE && _operation != DILATE )
170 CV_ERROR( CV_StsBadArg, "Unknown/unsupported morphological operation" );
172 if( _element_shape == CUSTOM )
174 if( !CV_IS_MAT(_element) )
175 CV_ERROR( CV_StsBadArg,
176 "structuring element should be valid matrix if CUSTOM element shape is specified" );
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" );
182 _ksize = cvGetMatSize(_element);
183 CV_CALL( nz = cvCountNonZero(_element));
184 if( nz == _ksize.width*_ksize.height )
185 _element_shape = RECT;
188 operation = _operation;
189 el_shape = _element_shape;
191 CV_CALL( CvBaseImageFilter::init( _max_width, _src_dst_type, _src_dst_type,
192 _element_shape == RECT, _ksize, _anchor, _border_mode, _border_value ));
194 if( el_shape == RECT )
196 if( operation == ERODE )
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;
210 assert( operation == DILATE );
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;
225 int cn = CV_MAT_CN(src_type);
228 if( !(element && el_sparse &&
229 _ksize.width == element->cols && _ksize.height == element->rows) )
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*))));
238 if( el_shape == CUSTOM )
240 CV_CALL( cvConvert( _element, element ));
244 CV_CALL( init_binary_element( element, el_shape, anchor ));
247 if( operation == ERODE )
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;
258 assert( operation == DILATE );
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;
267 nz_loc = (CvPoint*)el_sparse;
269 for( i = 0; i < ksize.height; i++ )
270 for( j = 0; j < ksize.width; j++ )
272 if( element->data.ptr[i*element->step+j] )
273 nz_loc[k++] = cvPoint(j*cn,i);
276 nz_loc[k++] = cvPoint(anchor.x*cn,anchor.y);
280 if( depth == CV_32F && border_mode == IPL_BORDER_CONSTANT )
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]);
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 )
297 CvBaseImageFilter::init( _max_width, _src_type, _dst_type, _is_separable,
298 _ksize, _anchor, _border_mode, _border_value );
302 void CvMorphology::start_process( CvSlice x_range, int width )
304 CvBaseImageFilter::start_process( x_range, width );
305 if( el_shape == RECT )
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 )
321 int CvMorphology::fill_cyclic_buffer( const uchar* src, int src_step,
322 int y0, int y1, int y2 )
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;
328 if( CV_MAT_DEPTH(src_type) != CV_32F )
329 return CvBaseImageFilter::fill_cyclic_buffer( src, src_step, y0, y1, y2 );
331 // fill the cyclic buffer
332 for( ; buf_count < buf_max_count && y < y2; buf_count++, y++, src += src_step )
334 uchar* trow = is_separable ? buf_end : buf_tail;
336 for( i = 0; i < width_n; i += sizeof(int) )
338 int t = *(int*)(src + i);
339 *(int*)(trow + i + bsz1) = CV_TOGGLE_FLT(t);
342 if( border_mode != IPL_BORDER_CONSTANT )
344 for( i = 0; i < bsz1; i++ )
346 int j = border_tab[i];
349 for( ; i < bsz; i++ )
351 int j = border_tab[i];
352 trow[i + width_n] = trow[j];
357 const uchar *bt = (uchar*)border_tab;
358 for( i = 0; i < bsz1; i++ )
361 for( ; i < bsz; i++ )
362 trow[i + width_n] = bt[i];
366 x_func( trow, buf_tail, this );
368 buf_tail += buf_step;
369 if( buf_tail >= buf_end )
370 buf_tail = buf_start;
377 void CvMorphology::init_binary_element( CvMat* element, int element_shape, CvPoint anchor )
379 CV_FUNCNAME( "CvMorphology::init_binary_element" );
384 int i, j, cols, rows;
388 if( !CV_IS_MAT(element) )
389 CV_ERROR( CV_StsBadArg, "element must be valid matrix" );
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" );
396 anchor.x = element->cols/2;
399 anchor.y = element->rows/2;
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" );
405 if( element_shape != RECT && element_shape != CROSS && element_shape != ELLIPSE )
406 CV_ERROR( CV_StsBadArg, "Unknown/unsupported element shape" );
408 rows = element->rows;
409 cols = element->cols;
411 if( rows == 1 || cols == 1 )
412 element_shape = RECT;
414 if( element_shape == ELLIPSE )
418 inv_r2 = r ? 1./((double)r*r) : 0;
421 for( i = 0; i < rows; i++ )
423 uchar* ptr = element->data.ptr + i*element->step;
424 int j1 = 0, j2 = 0, jx, t = 0;
426 if( element_shape == RECT || element_shape == CROSS && i == anchor.y )
428 else if( element_shape == CROSS )
429 j1 = anchor.x, j2 = j1 + 1;
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 );
441 for( j = 0, jx = j1; j < cols; )
445 if( type == CV_8UC1 )
461 #define ICV_MORPH_RECT_ROW( name, flavor, arrtype, \
462 worktype, update_extr_macro ) \
464 icv##name##RectRow_##flavor( const arrtype* src, \
465 arrtype* dst, void* params ) \
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()); \
473 width *= cn; ksize *= cn; \
477 for( i = 0; i < width; i++ ) \
482 for( k = 0; k < cn; k++, src++, dst++ ) \
484 for( i = 0; i <= width - cn*2; i += cn*2 ) \
486 const arrtype* s = src + i; \
487 worktype m = s[cn], t; \
488 for( j = cn*2; j < ksize; j += cn ) \
490 t = s[j]; update_extr_macro(m,t); \
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; \
498 for( ; i < width; i += cn ) \
500 const arrtype* s = src + i; \
501 worktype m = s[0], t; \
502 for( j = cn; j < ksize; j += cn ) \
504 t = s[j]; update_extr_macro(m,t); \
506 dst[i] = (arrtype)m; \
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 )
520 #define ICV_MORPH_RECT_COL( name, flavor, arrtype, \
521 worktype, update_extr_macro, toggle_macro ) \
523 icv##name##RectCol_##flavor( const arrtype** src, \
524 arrtype* dst, int dst_step, int count, void* params ) \
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()); \
533 dst_step /= sizeof(dst[0]); \
535 for( ; ksize > 1 && count > 1; count -= 2, \
536 dst += dst_step*2, src += 2 ) \
538 for( i = 0; i <= width - 4; i += 4 ) \
540 const arrtype* sptr = src[1] + i; \
541 worktype s0 = sptr[0], s1 = sptr[1], \
542 s2 = sptr[2], s3 = sptr[3], t0, t1; \
544 for( k = 2; k < ksize; k++ ) \
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); \
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); \
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); \
580 for( ; i < width; i++ ) \
582 const arrtype* sptr = src[1] + i; \
583 worktype s0 = sptr[0], t0; \
585 for( k = 2; k < ksize; k++ ) \
587 sptr = src[k] + i; t0 = sptr[0]; \
588 update_extr_macro(s0,t0); \
591 sptr = src[0] + i; t0 = sptr[0]; \
592 update_extr_macro(t0,s0); \
593 dst[i] = (arrtype)toggle_macro(t0); \
595 sptr = src[k] + i; t0 = sptr[0]; \
596 update_extr_macro(t0,s0); \
597 dst[i+dst_step] = (arrtype)toggle_macro(t0); \
601 for( ; count > 0; count--, dst += dst_step, src++ ) \
603 for( i = 0; i <= width - 4; i += 4 ) \
605 const arrtype* sptr = src[0] + i; \
606 worktype s0 = sptr[0], s1 = sptr[1], \
607 s2 = sptr[2], s3 = sptr[3], t0, t1; \
609 for( k = 1; k < ksize; k++ ) \
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); \
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); \
625 for( ; i < width; i++ ) \
627 const arrtype* sptr = src[0] + i; \
628 worktype s0 = sptr[0], t0; \
630 for( k = 1; k < ksize; k++ ) \
632 sptr = src[k] + i; t0 = sptr[0]; \
633 update_extr_macro(s0,t0); \
635 dst[i] = (arrtype)toggle_macro(s0); \
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 )
649 #define ICV_MORPH_ANY( name, flavor, arrtype, worktype, \
650 update_extr_macro, toggle_macro ) \
652 icv##name##Any_##flavor( const arrtype** src, arrtype* dst, \
653 int dst_step, int count, void* params ) \
655 CvMorphology* state = (CvMorphology*)params; \
656 int width = state->get_width(); \
657 int cn = CV_MAT_CN(state->get_src_type()); \
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; \
665 dst_step /= sizeof(dst[0]); \
667 for( ; count > 0; count--, dst += dst_step, src++ ) \
669 for( k = 0; k < el_count; k++ ) \
670 el_ptr[k] = src[el_sparse[k].y]+el_sparse[k].x; \
672 for( i = 0; i <= width - 4; i += 4 ) \
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; \
679 while( psptr != el_end ) \
683 update_extr_macro(s0,t); \
685 update_extr_macro(s1,t); \
687 update_extr_macro(s2,t); \
689 update_extr_macro(s3,t); \
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); \
698 for( ; i < width; i++ ) \
700 const arrtype* sptr = el_ptr[0] + i; \
701 worktype s0 = sptr[0], t0; \
703 for( k = 1; k < el_count; k++ ) \
705 sptr = el_ptr[k] + i; \
707 update_extr_macro(s0,t0); \
710 dst[i] = (arrtype)toggle_macro(s0); \
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 )
722 /////////////////////////////////// External Interface /////////////////////////////////////
725 CV_IMPL IplConvKernel *
726 cvCreateStructuringElementEx( int cols, int rows,
727 int anchorX, int anchorY,
728 int shape, int *values )
730 IplConvKernel *element = 0;
731 int i, size = rows * cols;
732 int element_size = sizeof(*element) + size*sizeof(element->values[0]);
734 CV_FUNCNAME( "cvCreateStructuringElementEx" );
738 if( !values && shape == CV_SHAPE_CUSTOM )
739 CV_ERROR_FROM_STATUS( CV_NULLPTR_ERR );
741 if( cols <= 0 || rows <= 0 ||
742 (unsigned) anchorX >= (unsigned) cols ||
743 (unsigned) anchorY >= (unsigned) rows )
744 CV_ERROR_FROM_STATUS( CV_BADSIZE_ERR );
746 CV_CALL( element = (IplConvKernel *)cvAlloc(element_size + 32));
748 CV_ERROR_FROM_STATUS( CV_OUTOFMEM_ERR );
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);
757 if( shape == CV_SHAPE_CUSTOM )
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];
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)));
773 if( cvGetErrStatus() < 0 )
774 cvReleaseStructuringElement( &element );
781 cvReleaseStructuringElement( IplConvKernel ** element )
783 CV_FUNCNAME( "cvReleaseStructuringElement" );
788 CV_ERROR( CV_StsNullPtr, "" );
795 typedef CvStatus (CV_STDCALL * CvMorphRectGetBufSizeFunc_IPP)
796 ( int width, CvSize el_size, int* bufsize );
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 );
802 typedef CvStatus (CV_STDCALL * CvMorphCustomInitAllocFunc_IPP)
803 ( int width, const uchar* element, CvSize el_size,
804 CvPoint el_anchor, void** morphstate );
806 typedef CvStatus (CV_STDCALL * CvMorphCustomFunc_IPP)
807 ( const void* src, int srcstep, void* dst, int dststep,
808 CvSize roi, int bordertype, void* morphstate );
811 icvMorphOp( const void* srcarr, void* dstarr, IplConvKernel* element,
812 int iterations, int mop )
814 CvMorphology morphology;
817 void* morphstate = 0;
820 CV_FUNCNAME( "icvMorphOp" );
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;
834 if( !CV_IS_MAT(src) )
835 CV_CALL( src = cvGetMat( src, &srcstub, &coi1 ));
837 if( src != &srcstub )
843 if( dstarr == srcarr )
847 CV_CALL( dst = cvGetMat( dst, &dststub, &coi2 ));
849 if( !CV_ARE_TYPES_EQ( src, dst ))
850 CV_ERROR( CV_StsUnmatchedFormats, "" );
852 if( !CV_ARE_SIZES_EQ( src, dst ))
853 CV_ERROR( CV_StsUnmatchedSizes, "" );
856 if( dst != &dststub )
862 if( coi1 != 0 || coi2 != 0 )
863 CV_ERROR( CV_BadCOI, "" );
865 type = CV_MAT_TYPE( src->type );
866 size = cvGetMatSize( src );
867 inplace = src->data.ptr == dst->data.ptr;
869 if( iterations == 0 || (element && element->nCols == 1 && element->nRows == 1))
871 if( src->data.ptr != dst->data.ptr )
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;
885 el_size = cvSize(3,3);
886 el_anchor = cvPoint(1,1);
887 el_shape = CV_SHAPE_RECT;
890 if( el_shape == CV_SHAPE_RECT && iterations > 1 )
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;
899 if( el_shape == CV_SHAPE_RECT && icvErodeRect_GetBufSize_8u_C1R_p )
901 CvMorphRectFunc_IPP rect_func = 0;
902 CvMorphRectGetBufSizeFunc_IPP rect_getbufsize_func = 0;
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;
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;
965 if( rect_getbufsize_func && rect_func )
969 CvStatus status = rect_getbufsize_func( size.width, el_size, &bufsize );
970 if( status >= 0 && bufsize > 0 )
972 if( bufsize < CV_MAX_LOCAL_SIZE )
974 buffer = cvStackAlloc( bufsize );
978 CV_CALL( buffer = cvAlloc( bufsize ));
983 int src_step, dst_step = dst->step ? dst->step : CV_STUB_STEP;
987 CV_CALL( temp = cvCloneMat( dst ));
990 src_step = src->step ? src->step : CV_STUB_STEP;
992 status = rect_func( src->data.ptr, src_step, dst->data.ptr,
993 dst_step, size, el_size, el_anchor, buffer );
1000 else if( el_shape == CV_SHAPE_CUSTOM && icvMorphInitAlloc_8u_C1R_p && icvMorphFree_p &&
1001 src->data.ptr != dst->data.ptr )
1003 CvMorphCustomFunc_IPP custom_func = 0;
1004 CvMorphCustomInitAllocFunc_IPP custom_initalloc_func = 0;
1005 const int bordertype = 1; // replication border
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;
1035 if( custom_initalloc_func && custom_func )
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 );
1043 for( i = 0; i < el_len; i++ )
1044 el_mask[i] = (uchar)(element->values[i] != 0);
1046 status = custom_initalloc_func( size.width, el_mask, el_size,
1047 el_anchor, &morphstate );
1049 if( status >= 0 && (inplace || iterations > 1) )
1051 CV_CALL( temp = cvCloneMat( src ));
1055 src_ptr = src->data.ptr;
1056 src_step = src->step ? src->step : CV_STUB_STEP;
1058 for( i = 0; i < iterations && status >= 0 && morphstate; i++ )
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 )
1068 dst_ptr = temp->data.ptr;
1069 dst_step = temp->step ? temp->step : CV_STUB_STEP;
1075 if( iterations % 2 == 0 )
1076 cvCopy( temp, dst );
1082 if( el_shape != CV_SHAPE_RECT )
1084 el_hdr = cvMat( element->nRows, element->nCols, CV_32SC1, element->values );
1086 el_shape = CV_SHAPE_CUSTOM;
1089 CV_CALL( morphology.init( mop, src->cols, src->type,
1090 el_shape, el, el_size, el_anchor ));
1092 for( i = 0; i < iterations; i++ )
1094 CV_CALL( morphology.process( src, dst ));
1103 icvMorphFree_p( morphstate );
1104 cvReleaseMat( &temp );
1109 cvErode( const void* src, void* dst, IplConvKernel* element, int iterations )
1111 icvMorphOp( src, dst, element, iterations, 0 );
1116 cvDilate( const void* src, void* dst, IplConvKernel* element, int iterations )
1118 icvMorphOp( src, dst, element, iterations, 1 );
1123 cvMorphologyEx( const void* src, void* dst,
1124 void* temp, IplConvKernel* element, int op, int iterations )
1126 CV_FUNCNAME( "cvMorhologyEx" );
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" );
1134 if( temp == src || temp == dst )
1135 CV_ERROR( CV_HeaderIsNull, "temp image is equal to src or dst" );
1140 CV_CALL( cvErode( src, dst, element, iterations ));
1141 CV_CALL( cvDilate( dst, dst, element, iterations ));
1144 CV_CALL( cvDilate( src, dst, element, iterations ));
1145 CV_CALL( cvErode( dst, dst, element, iterations ));
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 ));
1155 CV_CALL( cvErode( src, temp, element, iterations ));
1156 CV_CALL( cvDilate( temp, temp, element, iterations ));
1157 CV_CALL( cvSub( src, temp, dst ));
1159 case CV_MOP_BLACKHAT:
1162 CV_CALL( cvDilate( src, temp, element, iterations ));
1163 CV_CALL( cvErode( temp, temp, element, iterations ));
1164 CV_CALL( cvSub( temp, src, dst ));
1167 CV_ERROR( CV_StsBadArg, "unknown morphological operation" );