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
75IPCV_MORPHOLOGY_PTRS( Erode, 8u )
76IPCV_MORPHOLOGY_PTRS( Erode, 16u )
77IPCV_MORPHOLOGY_PTRS( Erode, 32f )
78IPCV_MORPHOLOGY_PTRS( Dilate, 8u )
79IPCV_MORPHOLOGY_PTRS( Dilate, 16u )
80IPCV_MORPHOLOGY_PTRS( Dilate, 32f )
81IPCV_MORPHOLOGY_INITALLOC_PTRS( 8u )
82IPCV_MORPHOLOGY_INITALLOC_PTRS( 16u )
83IPCV_MORPHOLOGY_INITALLOC_PTRS( 32f )
84
85icvMorphFree_t icvMorphFree_p = 0;
86
87/****************************************************************************************\
88                     Basic Morphological Operations: Erosion & Dilation
89\****************************************************************************************/
90
91static void icvErodeRectRow_8u( const uchar* src, uchar* dst, void* params );
92static void icvErodeRectRow_16u( const ushort* src, ushort* dst, void* params );
93static void icvErodeRectRow_32f( const int* src, int* dst, void* params );
94static void icvDilateRectRow_8u( const uchar* src, uchar* dst, void* params );
95static void icvDilateRectRow_16u( const ushort* src, ushort* dst, void* params );
96static void icvDilateRectRow_32f( const int* src, int* dst, void* params );
97
98static void icvErodeRectCol_8u( const uchar** src, uchar* dst, int dst_step,
99                                int count, void* params );
100static void icvErodeRectCol_16u( const ushort** src, ushort* dst, int dst_step,
101                                 int count, void* params );
102static void icvErodeRectCol_32f( const int** src, int* dst, int dst_step,
103                                 int count, void* params );
104static void icvDilateRectCol_8u( const uchar** src, uchar* dst, int dst_step,
105                                 int count, void* params );
106static void icvDilateRectCol_16u( const ushort** src, ushort* dst, int dst_step,
107                                  int count, void* params );
108static void icvDilateRectCol_32f( const int** src, int* dst, int dst_step,
109                                  int count, void* params );
110
111static void icvErodeAny_8u( const uchar** src, uchar* dst, int dst_step,
112                            int count, void* params );
113static void icvErodeAny_16u( const ushort** src, ushort* dst, int dst_step,
114                             int count, void* params );
115static void icvErodeAny_32f( const int** src, int* dst, int dst_step,
116                             int count, void* params );
117static void icvDilateAny_8u( const uchar** src, uchar* dst, int dst_step,
118                             int count, void* params );
119static void icvDilateAny_16u( const ushort** src, ushort* dst, int dst_step,
120                              int count, void* params );
121static void icvDilateAny_32f( const int** src, int* dst, int dst_step,
122                              int count, void* params );
123
124CvMorphology::CvMorphology()
125{
126    element = 0;
127    el_sparse = 0;
128}
129
130CvMorphology::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
143void CvMorphology::clear()
144{
145    cvReleaseMat( &element );
146    cvFree( &el_sparse );
147    CvBaseImageFilter::clear();
148}
149
150
151CvMorphology::~CvMorphology()
152{
153    clear();
154}
155
156
157void 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
292void 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
302void 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
321int 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
377void 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 )   \
463static void                                                 \
464icv##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
512ICV_MORPH_RECT_ROW( Erode, 8u, uchar, int, CV_CALC_MIN_8U )
513ICV_MORPH_RECT_ROW( Dilate, 8u, uchar, int, CV_CALC_MAX_8U )
514ICV_MORPH_RECT_ROW( Erode, 16u, ushort, int, CV_CALC_MIN )
515ICV_MORPH_RECT_ROW( Dilate, 16u, ushort, int, CV_CALC_MAX )
516ICV_MORPH_RECT_ROW( Erode, 32f, int, int, CV_CALC_MIN )
517ICV_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 )         \
522static void                                                 \
523icv##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
641ICV_MORPH_RECT_COL( Erode, 8u, uchar, int, CV_CALC_MIN_8U, CV_NOP )
642ICV_MORPH_RECT_COL( Dilate, 8u, uchar, int, CV_CALC_MAX_8U, CV_NOP )
643ICV_MORPH_RECT_COL( Erode, 16u, ushort, int, CV_CALC_MIN, CV_NOP )
644ICV_MORPH_RECT_COL( Dilate, 16u, ushort, int, CV_CALC_MAX, CV_NOP )
645ICV_MORPH_RECT_COL( Erode, 32f, int, int, CV_CALC_MIN, CV_TOGGLE_FLT )
646ICV_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 )    \
651static void                                                 \
652icv##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
715ICV_MORPH_ANY( Erode, 8u, uchar, int, CV_CALC_MIN, CV_NOP )
716ICV_MORPH_ANY( Dilate, 8u, uchar, int, CV_CALC_MAX, CV_NOP )
717ICV_MORPH_ANY( Erode, 16u, ushort, int, CV_CALC_MIN, CV_NOP )
718ICV_MORPH_ANY( Dilate, 16u, ushort, int, CV_CALC_MAX, CV_NOP )
719ICV_MORPH_ANY( Erode, 32f, int, int, CV_CALC_MIN, CV_TOGGLE_FLT )
720ICV_MORPH_ANY( Dilate, 32f, int, int, CV_CALC_MAX, CV_TOGGLE_FLT )
721
722/////////////////////////////////// External Interface /////////////////////////////////////
723
724
725CV_IMPL IplConvKernel *
726cvCreateStructuringElementEx( 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
780CV_IMPL void
781cvReleaseStructuringElement( 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
795typedef CvStatus (CV_STDCALL * CvMorphRectGetBufSizeFunc_IPP)
796    ( int width, CvSize el_size, int* bufsize );
797
798typedef 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
802typedef CvStatus (CV_STDCALL * CvMorphCustomInitAllocFunc_IPP)
803    ( int width, const uchar* element, CvSize el_size,
804      CvPoint el_anchor, void** morphstate );
805
806typedef CvStatus (CV_STDCALL * CvMorphCustomFunc_IPP)
807    ( const void* src, int srcstep, void* dst, int dststep,
808      CvSize roi, int bordertype, void* morphstate );
809
810static void
811icvMorphOp( 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
1108CV_IMPL void
1109cvErode( const void* src, void* dst, IplConvKernel* element, int iterations )
1110{
1111    icvMorphOp( src, dst, element, iterations, 0 );
1112}
1113
1114
1115CV_IMPL void
1116cvDilate( const void* src, void* dst, IplConvKernel* element, int iterations )
1117{
1118    icvMorphOp( src, dst, element, iterations, 1 );
1119}
1120
1121
1122CV_IMPL void
1123cvMorphologyEx( 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