Added support of CV_16S depth in morphology operations
[profile/ivi/opencv.git] / modules / imgproc / src / morph.cpp
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 //                           License Agreement
11 //                For Open Source Computer Vision Library
12 //
13 // Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
14 // Copyright (C) 2009, Willow Garage Inc., all rights reserved.
15 // Third party copyrights are property of their respective owners.
16 //
17 // Redistribution and use in source and binary forms, with or without modification,
18 // are permitted provided that the following conditions are met:
19 //
20 //   * Redistribution's of source code must retain the above copyright notice,
21 //     this list of conditions and the following disclaimer.
22 //
23 //   * Redistribution's in binary form must reproduce the above copyright notice,
24 //     this list of conditions and the following disclaimer in the documentation
25 //     and/or other materials provided with the distribution.
26 //
27 //   * The name of the copyright holders may not be used to endorse or promote products
28 //     derived from this software without specific prior written permission.
29 //
30 // This software is provided by the copyright holders and contributors "as is" and
31 // any express or implied warranties, including, but not limited to, the implied
32 // warranties of merchantability and fitness for a particular purpose are disclaimed.
33 // In no event shall the Intel Corporation or contributors be liable for any direct,
34 // indirect, incidental, special, exemplary, or consequential damages
35 // (including, but not limited to, procurement of substitute goods or services;
36 // loss of use, data, or profits; or business interruption) however caused
37 // and on any theory of liability, whether in contract, strict liability,
38 // or tort (including negligence or otherwise) arising in any way out of
39 // the use of this software, even if advised of the possibility of such damage.
40 //
41 //M*/
42
43 #include "precomp.hpp"
44 #include <limits.h>
45 #include <stdio.h>
46
47 /****************************************************************************************\
48                      Basic Morphological Operations: Erosion & Dilation
49 \****************************************************************************************/
50
51 namespace cv
52 {
53
54 template<typename T> struct MinOp
55 {
56     typedef T type1;
57     typedef T type2;
58     typedef T rtype;
59     T operator ()(T a, T b) const { return std::min(a, b); }
60 };
61
62 template<typename T> struct MaxOp
63 {
64     typedef T type1;
65     typedef T type2;
66     typedef T rtype;
67     T operator ()(T a, T b) const { return std::max(a, b); }
68 };
69
70 #undef CV_MIN_8U
71 #undef CV_MAX_8U
72 #define CV_MIN_8U(a,b)       ((a) - CV_FAST_CAST_8U((a) - (b)))
73 #define CV_MAX_8U(a,b)       ((a) + CV_FAST_CAST_8U((b) - (a)))
74
75 template<> inline uchar MinOp<uchar>::operator ()(uchar a, uchar b) const { return CV_MIN_8U(a, b); }
76 template<> inline uchar MaxOp<uchar>::operator ()(uchar a, uchar b) const { return CV_MAX_8U(a, b); }
77
78 #if CV_SSE2
79
80 template<class VecUpdate> struct MorphRowIVec
81 {
82     enum { ESZ = VecUpdate::ESZ };
83
84     MorphRowIVec(int _ksize, int _anchor) : ksize(_ksize), anchor(_anchor) {}
85     int operator()(const uchar* src, uchar* dst, int width, int cn) const
86     {
87         if( !checkHardwareSupport(CV_CPU_SSE2) )
88             return 0;
89         
90         cn *= ESZ;
91         int i, k, _ksize = ksize*cn;
92         width = (width & -4)*cn;
93         VecUpdate updateOp;
94
95         for( i = 0; i <= width - 16; i += 16 )
96         {
97             __m128i s = _mm_loadu_si128((const __m128i*)(src + i));
98             for( k = cn; k < _ksize; k += cn )
99             {
100                 __m128i x = _mm_loadu_si128((const __m128i*)(src + i + k));
101                 s = updateOp(s, x);
102             }
103             _mm_storeu_si128((__m128i*)(dst + i), s);
104         }
105
106         for( ; i < width; i += 4 )
107         {
108             __m128i s = _mm_cvtsi32_si128(*(const int*)(src + i));
109             for( k = cn; k < _ksize; k += cn )
110             {
111                 __m128i x = _mm_cvtsi32_si128(*(const int*)(src + i + k));
112                 s = updateOp(s, x);
113             }
114             *(int*)(dst + i) = _mm_cvtsi128_si32(s);
115         }
116
117         return i/ESZ;
118     }
119
120     int ksize, anchor;
121 };
122
123
124 template<class VecUpdate> struct MorphRowFVec
125 {
126     MorphRowFVec(int _ksize, int _anchor) : ksize(_ksize), anchor(_anchor) {}
127     int operator()(const uchar* src, uchar* dst, int width, int cn) const
128     {
129         if( !checkHardwareSupport(CV_CPU_SSE) )
130             return 0;
131         
132         int i, k, _ksize = ksize*cn;
133         width = (width & -4)*cn;
134         VecUpdate updateOp;
135
136         for( i = 0; i < width; i += 4 )
137         {
138             __m128 s = _mm_loadu_ps((const float*)src + i);
139             for( k = cn; k < _ksize; k += cn )
140             {
141                 __m128 x = _mm_loadu_ps((const float*)src + i + k);
142                 s = updateOp(s, x);
143             }
144             _mm_storeu_ps((float*)dst + i, s);
145         }
146
147         return i;
148     }
149
150     int ksize, anchor;
151 };
152
153
154 template<class VecUpdate> struct MorphColumnIVec
155 {
156     enum { ESZ = VecUpdate::ESZ };
157
158     MorphColumnIVec(int _ksize, int _anchor) : ksize(_ksize), anchor(_anchor) {}
159     int operator()(const uchar** src, uchar* dst, int dststep, int count, int width) const
160     {
161         if( !checkHardwareSupport(CV_CPU_SSE2) )
162             return 0;
163         
164         int i = 0, k, _ksize = ksize;
165         width *= ESZ;
166         VecUpdate updateOp;
167
168         for( i = 0; i < count + ksize - 1; i++ )
169             CV_Assert( ((size_t)src[i] & 15) == 0 );
170
171         for( ; _ksize > 1 && count > 1; count -= 2, dst += dststep*2, src += 2 )
172         {
173             for( i = 0; i <= width - 32; i += 32 )
174             {
175                 const uchar* sptr = src[1] + i;
176                 __m128i s0 = _mm_load_si128((const __m128i*)sptr);
177                 __m128i s1 = _mm_load_si128((const __m128i*)(sptr + 16));
178                 __m128i x0, x1;
179
180                 for( k = 2; k < _ksize; k++ )
181                 {
182                     sptr = src[k] + i;
183                     x0 = _mm_load_si128((const __m128i*)sptr);
184                     x1 = _mm_load_si128((const __m128i*)(sptr + 16));
185                     s0 = updateOp(s0, x0);
186                     s1 = updateOp(s1, x1);
187                 }
188
189                 sptr = src[0] + i;
190                 x0 = _mm_load_si128((const __m128i*)sptr);
191                 x1 = _mm_load_si128((const __m128i*)(sptr + 16));
192                 _mm_storeu_si128((__m128i*)(dst + i), updateOp(s0, x0));
193                 _mm_storeu_si128((__m128i*)(dst + i + 16), updateOp(s1, x1));
194
195                 sptr = src[k] + i;
196                 x0 = _mm_load_si128((const __m128i*)sptr);
197                 x1 = _mm_load_si128((const __m128i*)(sptr + 16));
198                 _mm_storeu_si128((__m128i*)(dst + dststep + i), updateOp(s0, x0));
199                 _mm_storeu_si128((__m128i*)(dst + dststep + i + 16), updateOp(s1, x1));
200             }
201
202             for( ; i <= width - 8; i += 8 )
203             {
204                 __m128i s0 = _mm_loadl_epi64((const __m128i*)(src[1] + i)), x0;
205
206                 for( k = 2; k < _ksize; k++ )
207                 {
208                     x0 = _mm_loadl_epi64((const __m128i*)(src[k] + i));
209                     s0 = updateOp(s0, x0);
210                 }
211
212                 x0 = _mm_loadl_epi64((const __m128i*)(src[0] + i));
213                 _mm_storel_epi64((__m128i*)(dst + i), updateOp(s0, x0));
214                 x0 = _mm_loadl_epi64((const __m128i*)(src[k] + i));
215                 _mm_storel_epi64((__m128i*)(dst + dststep + i), updateOp(s0, x0));
216             }
217         }
218
219         for( ; count > 0; count--, dst += dststep, src++ )
220         {
221             for( i = 0; i <= width - 32; i += 32 )
222             {
223                 const uchar* sptr = src[0] + i;
224                 __m128i s0 = _mm_load_si128((const __m128i*)sptr);
225                 __m128i s1 = _mm_load_si128((const __m128i*)(sptr + 16));
226                 __m128i x0, x1;
227
228                 for( k = 1; k < _ksize; k++ )
229                 {
230                     sptr = src[k] + i;
231                     x0 = _mm_load_si128((const __m128i*)sptr);
232                     x1 = _mm_load_si128((const __m128i*)(sptr + 16));
233                     s0 = updateOp(s0, x0);
234                     s1 = updateOp(s1, x1);
235                 }
236                 _mm_storeu_si128((__m128i*)(dst + i), s0);
237                 _mm_storeu_si128((__m128i*)(dst + i + 16), s1);
238             }
239
240             for( ; i <= width - 8; i += 8 )
241             {
242                 __m128i s0 = _mm_loadl_epi64((const __m128i*)(src[0] + i)), x0;
243
244                 for( k = 1; k < _ksize; k++ )
245                 {
246                     x0 = _mm_loadl_epi64((const __m128i*)(src[k] + i));
247                     s0 = updateOp(s0, x0);
248                 }
249                 _mm_storel_epi64((__m128i*)(dst + i), s0);
250             }
251         }
252
253         return i/ESZ;
254     }
255
256     int ksize, anchor;
257 };
258
259
260 template<class VecUpdate> struct MorphColumnFVec
261 {
262     MorphColumnFVec(int _ksize, int _anchor) : ksize(_ksize), anchor(_anchor) {}
263     int operator()(const uchar** _src, uchar* _dst, int dststep, int count, int width) const
264     {
265         if( !checkHardwareSupport(CV_CPU_SSE) )
266             return 0;
267         
268         int i = 0, k, _ksize = ksize;
269         VecUpdate updateOp;
270
271         for( i = 0; i < count + ksize - 1; i++ )
272             CV_Assert( ((size_t)_src[i] & 15) == 0 );
273
274         const float** src = (const float**)_src;
275         float* dst = (float*)_dst;
276         dststep /= sizeof(dst[0]);
277
278         for( ; _ksize > 1 && count > 1; count -= 2, dst += dststep*2, src += 2 )
279         {
280             for( i = 0; i <= width - 16; i += 16 )
281             {
282                 const float* sptr = src[1] + i;
283                 __m128 s0 = _mm_load_ps(sptr);
284                 __m128 s1 = _mm_load_ps(sptr + 4);
285                 __m128 s2 = _mm_load_ps(sptr + 8);
286                 __m128 s3 = _mm_load_ps(sptr + 12);
287                 __m128 x0, x1, x2, x3;
288
289                 for( k = 2; k < _ksize; k++ )
290                 {
291                     sptr = src[k] + i;
292                     x0 = _mm_load_ps(sptr);
293                     x1 = _mm_load_ps(sptr + 4);
294                     s0 = updateOp(s0, x0);
295                     s1 = updateOp(s1, x1);
296                     x2 = _mm_load_ps(sptr + 8);
297                     x3 = _mm_load_ps(sptr + 12);
298                     s2 = updateOp(s2, x2);
299                     s3 = updateOp(s3, x3);
300                 }
301
302                 sptr = src[0] + i;
303                 x0 = _mm_load_ps(sptr);
304                 x1 = _mm_load_ps(sptr + 4);
305                 x2 = _mm_load_ps(sptr + 8);
306                 x3 = _mm_load_ps(sptr + 12);
307                 _mm_storeu_ps(dst + i, updateOp(s0, x0));
308                 _mm_storeu_ps(dst + i + 4, updateOp(s1, x1));
309                 _mm_storeu_ps(dst + i + 8, updateOp(s2, x2));
310                 _mm_storeu_ps(dst + i + 12, updateOp(s3, x3));
311
312                 sptr = src[k] + i;
313                 x0 = _mm_load_ps(sptr);
314                 x1 = _mm_load_ps(sptr + 4);
315                 x2 = _mm_load_ps(sptr + 8);
316                 x3 = _mm_load_ps(sptr + 12);
317                 _mm_storeu_ps(dst + dststep + i, updateOp(s0, x0));
318                 _mm_storeu_ps(dst + dststep + i + 4, updateOp(s1, x1));
319                 _mm_storeu_ps(dst + dststep + i + 8, updateOp(s2, x2));
320                 _mm_storeu_ps(dst + dststep + i + 12, updateOp(s3, x3));
321             }
322
323             for( ; i <= width - 4; i += 4 )
324             {
325                 __m128 s0 = _mm_load_ps(src[1] + i), x0;
326
327                 for( k = 2; k < _ksize; k++ )
328                 {
329                     x0 = _mm_load_ps(src[k] + i);
330                     s0 = updateOp(s0, x0);
331                 }
332
333                 x0 = _mm_load_ps(src[0] + i);
334                 _mm_storeu_ps(dst + i, updateOp(s0, x0));
335                 x0 = _mm_load_ps(src[k] + i);
336                 _mm_storeu_ps(dst + dststep + i, updateOp(s0, x0));
337             }
338         }
339
340         for( ; count > 0; count--, dst += dststep, src++ )
341         {
342             for( i = 0; i <= width - 16; i += 16 )
343             {
344                 const float* sptr = src[0] + i;
345                 __m128 s0 = _mm_load_ps(sptr);
346                 __m128 s1 = _mm_load_ps(sptr + 4);
347                 __m128 s2 = _mm_load_ps(sptr + 8);
348                 __m128 s3 = _mm_load_ps(sptr + 12);
349                 __m128 x0, x1, x2, x3;
350
351                 for( k = 1; k < _ksize; k++ )
352                 {
353                     sptr = src[k] + i;
354                     x0 = _mm_load_ps(sptr);
355                     x1 = _mm_load_ps(sptr + 4);
356                     s0 = updateOp(s0, x0);
357                     s1 = updateOp(s1, x1);
358                     x2 = _mm_load_ps(sptr + 8);
359                     x3 = _mm_load_ps(sptr + 12);
360                     s2 = updateOp(s2, x2);
361                     s3 = updateOp(s3, x3);
362                 }
363                 _mm_storeu_ps(dst + i, s0);
364                 _mm_storeu_ps(dst + i + 4, s1);
365                 _mm_storeu_ps(dst + i + 8, s2);
366                 _mm_storeu_ps(dst + i + 12, s3);
367             }
368
369             for( i = 0; i <= width - 4; i += 4 )
370             {
371                 __m128 s0 = _mm_load_ps(src[0] + i), x0;
372                 for( k = 1; k < _ksize; k++ )
373                 {
374                     x0 = _mm_load_ps(src[k] + i);
375                     s0 = updateOp(s0, x0);
376                 }
377                 _mm_storeu_ps(dst + i, s0);
378             }
379         }
380
381         return i;
382     }
383
384     int ksize, anchor;
385 };
386
387
388 template<class VecUpdate> struct MorphIVec
389 {
390     enum { ESZ = VecUpdate::ESZ };
391
392     int operator()(uchar** src, int nz, uchar* dst, int width) const
393     {
394         if( !checkHardwareSupport(CV_CPU_SSE2) )
395             return 0;
396         
397         int i, k;
398         width *= ESZ;
399         VecUpdate updateOp;
400
401         for( i = 0; i <= width - 32; i += 32 )
402         {
403             const uchar* sptr = src[0] + i;
404             __m128i s0 = _mm_loadu_si128((const __m128i*)sptr);
405             __m128i s1 = _mm_loadu_si128((const __m128i*)(sptr + 16));
406             __m128i x0, x1;
407
408             for( k = 1; k < nz; k++ )
409             {
410                 sptr = src[k] + i;
411                 x0 = _mm_loadu_si128((const __m128i*)sptr);
412                 x1 = _mm_loadu_si128((const __m128i*)(sptr + 16));
413                 s0 = updateOp(s0, x0);
414                 s1 = updateOp(s1, x1);
415             }
416             _mm_storeu_si128((__m128i*)(dst + i), s0);
417             _mm_storeu_si128((__m128i*)(dst + i + 16), s1);
418         }
419
420         for( ; i <= width - 8; i += 8 )
421         {
422             __m128i s0 = _mm_loadl_epi64((const __m128i*)(src[0] + i)), x0;
423
424             for( k = 1; k < nz; k++ )
425             {
426                 x0 = _mm_loadl_epi64((const __m128i*)(src[k] + i));
427                 s0 = updateOp(s0, x0);
428             }
429             _mm_storel_epi64((__m128i*)(dst + i), s0);
430         }
431
432         return i/ESZ;
433     }
434 };
435
436
437 template<class VecUpdate> struct MorphFVec
438 {
439     int operator()(uchar** _src, int nz, uchar* _dst, int width) const
440     {
441         if( !checkHardwareSupport(CV_CPU_SSE) )
442             return 0;
443         
444         const float** src = (const float**)_src;
445         float* dst = (float*)_dst;
446         int i, k;
447         VecUpdate updateOp;
448
449         for( i = 0; i <= width - 16; i += 16 )
450         {
451             const float* sptr = src[0] + i;
452             __m128 s0 = _mm_loadu_ps(sptr);
453             __m128 s1 = _mm_loadu_ps(sptr + 4);
454             __m128 s2 = _mm_loadu_ps(sptr + 8);
455             __m128 s3 = _mm_loadu_ps(sptr + 12);
456             __m128 x0, x1, x2, x3;
457
458             for( k = 1; k < nz; k++ )
459             {
460                 sptr = src[k] + i;
461                 x0 = _mm_loadu_ps(sptr);
462                 x1 = _mm_loadu_ps(sptr + 4);
463                 x2 = _mm_loadu_ps(sptr + 8);
464                 x3 = _mm_loadu_ps(sptr + 12);
465                 s0 = updateOp(s0, x0);
466                 s1 = updateOp(s1, x1);
467                 s2 = updateOp(s2, x2);
468                 s3 = updateOp(s3, x3);
469             }
470             _mm_storeu_ps(dst + i, s0);
471             _mm_storeu_ps(dst + i + 4, s1);
472             _mm_storeu_ps(dst + i + 8, s2);
473             _mm_storeu_ps(dst + i + 12, s3);
474         }
475
476         for( ; i <= width - 4; i += 4 )
477         {
478             __m128 s0 = _mm_loadu_ps(src[0] + i), x0;
479
480             for( k = 1; k < nz; k++ )
481             {
482                 x0 = _mm_loadu_ps(src[k] + i);
483                 s0 = updateOp(s0, x0);
484             }
485             _mm_storeu_ps(dst + i, s0);
486         }
487
488         for( ; i < width; i++ )
489         {
490             __m128 s0 = _mm_load_ss(src[0] + i), x0;
491
492             for( k = 1; k < nz; k++ )
493             {
494                 x0 = _mm_load_ss(src[k] + i);
495                 s0 = updateOp(s0, x0);
496             }
497             _mm_store_ss(dst + i, s0);
498         }
499
500         return i;
501     }
502 };
503
504 struct VMin8u
505 {
506     enum { ESZ = 1 };
507     __m128i operator()(const __m128i& a, const __m128i& b) const { return _mm_min_epu8(a,b); }
508 };
509 struct VMax8u
510 {
511     enum { ESZ = 1 };
512     __m128i operator()(const __m128i& a, const __m128i& b) const { return _mm_max_epu8(a,b); }
513 };
514 struct VMin16u
515 {
516     enum { ESZ = 2 };
517     __m128i operator()(const __m128i& a, const __m128i& b) const
518     { return _mm_subs_epu16(a,_mm_subs_epu16(a,b)); }
519 };
520 struct VMax16u
521 {
522     enum { ESZ = 2 };
523     __m128i operator()(const __m128i& a, const __m128i& b) const
524     { return _mm_adds_epu16(_mm_subs_epu16(a,b), b); }
525 };
526 struct VMin16s
527 {
528     enum { ESZ = 2 };
529     __m128i operator()(const __m128i& a, const __m128i& b) const
530     { return _mm_min_epi16(a, b); }
531 };
532 struct VMax16s
533 {
534     enum { ESZ = 2 };
535     __m128i operator()(const __m128i& a, const __m128i& b) const
536     { return _mm_max_epi16(a, b); }
537 };
538 struct VMin32f { __m128 operator()(const __m128& a, const __m128& b) const { return _mm_min_ps(a,b); }};
539 struct VMax32f { __m128 operator()(const __m128& a, const __m128& b) const { return _mm_max_ps(a,b); }};
540
541 typedef MorphRowIVec<VMin8u> ErodeRowVec8u;
542 typedef MorphRowIVec<VMax8u> DilateRowVec8u;
543 typedef MorphRowIVec<VMin16u> ErodeRowVec16u;
544 typedef MorphRowIVec<VMax16u> DilateRowVec16u;
545 typedef MorphRowIVec<VMin16s> ErodeRowVec16s;
546 typedef MorphRowIVec<VMax16s> DilateRowVec16s;
547 typedef MorphRowFVec<VMin32f> ErodeRowVec32f;
548 typedef MorphRowFVec<VMax32f> DilateRowVec32f;
549
550 typedef MorphColumnIVec<VMin8u> ErodeColumnVec8u;
551 typedef MorphColumnIVec<VMax8u> DilateColumnVec8u;
552 typedef MorphColumnIVec<VMin16u> ErodeColumnVec16u;
553 typedef MorphColumnIVec<VMax16u> DilateColumnVec16u;
554 typedef MorphColumnIVec<VMin16s> ErodeColumnVec16s;
555 typedef MorphColumnIVec<VMax16s> DilateColumnVec16s;
556 typedef MorphColumnFVec<VMin32f> ErodeColumnVec32f;
557 typedef MorphColumnFVec<VMax32f> DilateColumnVec32f;
558
559 typedef MorphIVec<VMin8u> ErodeVec8u;
560 typedef MorphIVec<VMax8u> DilateVec8u;
561 typedef MorphIVec<VMin16u> ErodeVec16u;
562 typedef MorphIVec<VMax16u> DilateVec16u;
563 typedef MorphIVec<VMin16s> ErodeVec16s;
564 typedef MorphIVec<VMax16s> DilateVec16s;
565 typedef MorphFVec<VMin32f> ErodeVec32f;
566 typedef MorphFVec<VMax32f> DilateVec32f;
567
568 #else
569
570 struct MorphRowNoVec
571 {
572     MorphRowNoVec(int, int) {}
573     int operator()(const uchar*, uchar*, int, int) const { return 0; }
574 };
575
576 struct MorphColumnNoVec
577 {
578     MorphColumnNoVec(int, int) {}
579     int operator()(const uchar**, uchar*, int, int, int) const { return 0; }
580 };
581
582 struct MorphNoVec
583 {
584     int operator()(uchar**, int, uchar*, int) const { return 0; }
585 };
586
587 #ifdef HAVE_TEGRA_OPTIMIZATION
588 using tegra::ErodeRowVec8u;
589 using tegra::DilateRowVec8u;
590
591 using tegra::ErodeColumnVec8u;
592 using tegra::DilateColumnVec8u;
593 #else
594 typedef MorphRowNoVec ErodeRowVec8u;
595 typedef MorphRowNoVec DilateRowVec8u;
596
597 typedef MorphColumnNoVec ErodeColumnVec8u;
598 typedef MorphColumnNoVec DilateColumnVec8u;
599 #endif
600
601 typedef MorphRowNoVec ErodeRowVec16u;
602 typedef MorphRowNoVec DilateRowVec16u;
603 typedef MorphRowNoVec ErodeRowVec16s;
604 typedef MorphRowNoVec DilateRowVec16s;
605 typedef MorphRowNoVec ErodeRowVec32f;
606 typedef MorphRowNoVec DilateRowVec32f;
607
608 typedef MorphColumnNoVec ErodeColumnVec16u;
609 typedef MorphColumnNoVec DilateColumnVec16u;
610 typedef MorphColumnNoVec ErodeColumnVec16s;
611 typedef MorphColumnNoVec DilateColumnVec16s;
612 typedef MorphColumnNoVec ErodeColumnVec32f;
613 typedef MorphColumnNoVec DilateColumnVec32f;
614
615 typedef MorphNoVec ErodeVec8u;
616 typedef MorphNoVec DilateVec8u;
617 typedef MorphNoVec ErodeVec16u;
618 typedef MorphNoVec DilateVec16u;
619 typedef MorphNoVec ErodeVec16s;
620 typedef MorphNoVec DilateVec16s;
621 typedef MorphNoVec ErodeVec32f;
622 typedef MorphNoVec DilateVec32f;
623
624 #endif
625
626
627 template<class Op, class VecOp> struct MorphRowFilter : public BaseRowFilter
628 {
629     typedef typename Op::rtype T;
630
631     MorphRowFilter( int _ksize, int _anchor ) : vecOp(_ksize, _anchor)
632     {
633         ksize = _ksize;
634         anchor = _anchor;
635     }
636
637     void operator()(const uchar* src, uchar* dst, int width, int cn)
638     {
639         int i, j, k, _ksize = ksize*cn;
640         const T* S = (const T*)src;
641         Op op;
642         T* D = (T*)dst;
643
644         if( _ksize == cn )
645         {
646             for( i = 0; i < width*cn; i++ )
647                 D[i] = S[i];
648             return;
649         }
650
651         int i0 = vecOp(src, dst, width, cn);
652         width *= cn;
653
654         for( k = 0; k < cn; k++, S++, D++ )
655         {
656             for( i = i0; i <= width - cn*2; i += cn*2 )
657             {
658                 const T* s = S + i;
659                 T m = s[cn];
660                 for( j = cn*2; j < _ksize; j += cn )
661                     m = op(m, s[j]);
662                 D[i] = op(m, s[0]);
663                 D[i+cn] = op(m, s[j]);
664             }
665
666             for( ; i < width; i += cn )
667             {
668                 const T* s = S + i;
669                 T m = s[0];
670                 for( j = cn; j < _ksize; j += cn )
671                     m = op(m, s[j]);
672                 D[i] = m;
673             }
674         }
675     }
676
677     VecOp vecOp;
678 };
679
680
681 template<class Op, class VecOp> struct MorphColumnFilter : public BaseColumnFilter
682 {
683     typedef typename Op::rtype T;
684
685     MorphColumnFilter( int _ksize, int _anchor ) : vecOp(_ksize, _anchor)
686     {
687         ksize = _ksize;
688         anchor = _anchor;
689     }
690
691     void operator()(const uchar** _src, uchar* dst, int dststep, int count, int width)
692     {
693         int i, k, _ksize = ksize;
694         const T** src = (const T**)_src;
695         T* D = (T*)dst;
696         Op op;
697
698         int i0 = vecOp(_src, dst, dststep, count, width);
699         dststep /= sizeof(D[0]);
700
701         for( ; _ksize > 1 && count > 1; count -= 2, D += dststep*2, src += 2 )
702         {
703                         i = i0;
704                         #if CV_ENABLE_UNROLLED
705             for( ; i <= width - 4; i += 4 )
706             {
707                 const T* sptr = src[1] + i;
708                 T s0 = sptr[0], s1 = sptr[1], s2 = sptr[2], s3 = sptr[3];
709
710                 for( k = 2; k < _ksize; k++ )
711                 {
712                     sptr = src[k] + i;
713                     s0 = op(s0, sptr[0]); s1 = op(s1, sptr[1]);
714                     s2 = op(s2, sptr[2]); s3 = op(s3, sptr[3]);
715                 }
716
717                 sptr = src[0] + i;
718                 D[i] = op(s0, sptr[0]);
719                 D[i+1] = op(s1, sptr[1]);
720                 D[i+2] = op(s2, sptr[2]);
721                 D[i+3] = op(s3, sptr[3]);
722
723                 sptr = src[k] + i;
724                 D[i+dststep] = op(s0, sptr[0]);
725                 D[i+dststep+1] = op(s1, sptr[1]);
726                 D[i+dststep+2] = op(s2, sptr[2]);
727                 D[i+dststep+3] = op(s3, sptr[3]);
728             }
729             #endif
730             for( ; i < width; i++ )
731             {
732                 T s0 = src[1][i];
733
734                 for( k = 2; k < _ksize; k++ )
735                     s0 = op(s0, src[k][i]);
736
737                 D[i] = op(s0, src[0][i]);
738                 D[i+dststep] = op(s0, src[k][i]);
739             }
740         }
741
742         for( ; count > 0; count--, D += dststep, src++ )
743         {
744                         i = i0;
745                         #if CV_ENABLE_UNROLLED
746             for( ; i <= width - 4; i += 4 )
747             {
748                 const T* sptr = src[0] + i;
749                 T s0 = sptr[0], s1 = sptr[1], s2 = sptr[2], s3 = sptr[3];
750
751                 for( k = 1; k < _ksize; k++ )
752                 {
753                     sptr = src[k] + i;
754                     s0 = op(s0, sptr[0]); s1 = op(s1, sptr[1]);
755                     s2 = op(s2, sptr[2]); s3 = op(s3, sptr[3]);
756                 }
757
758                 D[i] = s0; D[i+1] = s1;
759                 D[i+2] = s2; D[i+3] = s3;
760             }
761             #endif
762             for( ; i < width; i++ )
763             {
764                 T s0 = src[0][i];
765                 for( k = 1; k < _ksize; k++ )
766                     s0 = op(s0, src[k][i]);
767                 D[i] = s0;
768             }
769         }
770     }
771
772     VecOp vecOp;
773 };
774
775
776 template<class Op, class VecOp> struct MorphFilter : BaseFilter
777 {
778     typedef typename Op::rtype T;
779
780     MorphFilter( const Mat& _kernel, Point _anchor )
781     {
782         anchor = _anchor;
783         ksize = _kernel.size();
784         CV_Assert( _kernel.type() == CV_8U );
785
786         vector<uchar> coeffs; // we do not really the values of non-zero
787         // kernel elements, just their locations
788         preprocess2DKernel( _kernel, coords, coeffs );
789         ptrs.resize( coords.size() );
790     }
791
792     void operator()(const uchar** src, uchar* dst, int dststep, int count, int width, int cn)
793     {
794         const Point* pt = &coords[0];
795         const T** kp = (const T**)&ptrs[0];
796         int i, k, nz = (int)coords.size();
797         Op op;
798
799         width *= cn;
800         for( ; count > 0; count--, dst += dststep, src++ )
801         {
802             T* D = (T*)dst;
803
804             for( k = 0; k < nz; k++ )
805                 kp[k] = (const T*)src[pt[k].y] + pt[k].x*cn;
806
807             i = vecOp(&ptrs[0], nz, dst, width);
808             #if CV_ENABLE_UNROLLED
809             for( ; i <= width - 4; i += 4 )
810             {
811                 const T* sptr = kp[0] + i;
812                 T s0 = sptr[0], s1 = sptr[1], s2 = sptr[2], s3 = sptr[3];
813
814                 for( k = 1; k < nz; k++ )
815                 {
816                     sptr = kp[k] + i;
817                     s0 = op(s0, sptr[0]); s1 = op(s1, sptr[1]);
818                     s2 = op(s2, sptr[2]); s3 = op(s3, sptr[3]);
819                 }
820
821                 D[i] = s0; D[i+1] = s1;
822                 D[i+2] = s2; D[i+3] = s3;
823             }
824             #endif
825             for( ; i < width; i++ )
826             {
827                 T s0 = kp[0][i];
828                 for( k = 1; k < nz; k++ )
829                     s0 = op(s0, kp[k][i]);
830                 D[i] = s0;
831             }
832         }
833     }
834
835     vector<Point> coords;
836     vector<uchar*> ptrs;
837     VecOp vecOp;
838 };
839
840 }
841
842 /////////////////////////////////// External Interface /////////////////////////////////////
843
844 cv::Ptr<cv::BaseRowFilter> cv::getMorphologyRowFilter(int op, int type, int ksize, int anchor)
845 {
846     int depth = CV_MAT_DEPTH(type);
847     if( anchor < 0 )
848         anchor = ksize/2;
849     CV_Assert( op == MORPH_ERODE || op == MORPH_DILATE );
850     if( op == MORPH_ERODE )
851     {
852         if( depth == CV_8U )
853             return Ptr<BaseRowFilter>(new MorphRowFilter<MinOp<uchar>,
854                                       ErodeRowVec8u>(ksize, anchor));
855         if( depth == CV_16U )
856             return Ptr<BaseRowFilter>(new MorphRowFilter<MinOp<ushort>,
857                                       ErodeRowVec16u>(ksize, anchor));
858         if( depth == CV_16S )
859             return Ptr<BaseRowFilter>(new MorphRowFilter<MinOp<short>,
860                                       ErodeRowVec16s>(ksize, anchor));
861         if( depth == CV_32F )
862             return Ptr<BaseRowFilter>(new MorphRowFilter<MinOp<float>,
863                                       ErodeRowVec32f>(ksize, anchor));
864     }
865     else
866     {
867         if( depth == CV_8U )
868             return Ptr<BaseRowFilter>(new MorphRowFilter<MaxOp<uchar>,
869                                       DilateRowVec8u>(ksize, anchor));
870         if( depth == CV_16U )
871             return Ptr<BaseRowFilter>(new MorphRowFilter<MaxOp<ushort>,
872                                       DilateRowVec16u>(ksize, anchor));
873         if( depth == CV_16S )
874             return Ptr<BaseRowFilter>(new MorphRowFilter<MaxOp<short>,
875                                       DilateRowVec16s>(ksize, anchor));
876         if( depth == CV_32F )
877             return Ptr<BaseRowFilter>(new MorphRowFilter<MaxOp<float>,
878                                       DilateRowVec32f>(ksize, anchor));
879     } 
880
881     CV_Error_( CV_StsNotImplemented, ("Unsupported data type (=%d)", type));
882     return Ptr<BaseRowFilter>(0);
883 }
884
885 cv::Ptr<cv::BaseColumnFilter> cv::getMorphologyColumnFilter(int op, int type, int ksize, int anchor)
886 {
887     int depth = CV_MAT_DEPTH(type);
888     if( anchor < 0 )
889         anchor = ksize/2;
890     CV_Assert( op == MORPH_ERODE || op == MORPH_DILATE );
891     if( op == MORPH_ERODE )
892     {
893         if( depth == CV_8U )
894             return Ptr<BaseColumnFilter>(new MorphColumnFilter<MinOp<uchar>,
895                                          ErodeColumnVec8u>(ksize, anchor));
896         if( depth == CV_16U )
897             return Ptr<BaseColumnFilter>(new MorphColumnFilter<MinOp<ushort>,
898                                          ErodeColumnVec16u>(ksize, anchor));
899         if( depth == CV_16S )
900             return Ptr<BaseColumnFilter>(new MorphColumnFilter<MinOp<short>,
901                                          ErodeColumnVec16s>(ksize, anchor));
902         if( depth == CV_32F )
903             return Ptr<BaseColumnFilter>(new MorphColumnFilter<MinOp<float>,
904                                          ErodeColumnVec32f>(ksize, anchor));
905     }
906     else
907     {
908         if( depth == CV_8U )
909             return Ptr<BaseColumnFilter>(new MorphColumnFilter<MaxOp<uchar>,
910                                          DilateColumnVec8u>(ksize, anchor));
911         if( depth == CV_16U )
912             return Ptr<BaseColumnFilter>(new MorphColumnFilter<MaxOp<ushort>,
913                                          DilateColumnVec16u>(ksize, anchor));
914         if( depth == CV_16S )
915             return Ptr<BaseColumnFilter>(new MorphColumnFilter<MaxOp<short>,
916                                          DilateColumnVec16s>(ksize, anchor));
917         if( depth == CV_32F )
918             return Ptr<BaseColumnFilter>(new MorphColumnFilter<MaxOp<float>,
919                                          DilateColumnVec32f>(ksize, anchor));
920     }
921
922     CV_Error_( CV_StsNotImplemented, ("Unsupported data type (=%d)", type));
923     return Ptr<BaseColumnFilter>(0);
924 }
925
926
927 cv::Ptr<cv::BaseFilter> cv::getMorphologyFilter(int op, int type, InputArray _kernel, Point anchor)
928 {
929     Mat kernel = _kernel.getMat();
930     int depth = CV_MAT_DEPTH(type);
931     anchor = normalizeAnchor(anchor, kernel.size());
932     CV_Assert( op == MORPH_ERODE || op == MORPH_DILATE );
933     if( op == MORPH_ERODE )
934     {
935         if( depth == CV_8U )
936             return Ptr<BaseFilter>(new MorphFilter<MinOp<uchar>, ErodeVec8u>(kernel, anchor));
937         if( depth == CV_16U )
938             return Ptr<BaseFilter>(new MorphFilter<MinOp<ushort>, ErodeVec16u>(kernel, anchor));
939         if( depth == CV_16S )
940             return Ptr<BaseFilter>(new MorphFilter<MinOp<short>, ErodeVec16s>(kernel, anchor));
941         if( depth == CV_32F )
942             return Ptr<BaseFilter>(new MorphFilter<MinOp<float>, ErodeVec32f>(kernel, anchor));
943     }
944     else
945     {
946         if( depth == CV_8U )
947             return Ptr<BaseFilter>(new MorphFilter<MaxOp<uchar>, DilateVec8u>(kernel, anchor));
948         if( depth == CV_16U )
949             return Ptr<BaseFilter>(new MorphFilter<MaxOp<ushort>, DilateVec16u>(kernel, anchor));
950         if( depth == CV_16S )
951             return Ptr<BaseFilter>(new MorphFilter<MaxOp<short>, DilateVec16s>(kernel, anchor));
952         if( depth == CV_32F )
953             return Ptr<BaseFilter>(new MorphFilter<MaxOp<float>, DilateVec32f>(kernel, anchor));
954     }
955
956     CV_Error_( CV_StsNotImplemented, ("Unsupported data type (=%d)", type));
957     return Ptr<BaseFilter>(0);
958 }
959
960
961 cv::Ptr<cv::FilterEngine> cv::createMorphologyFilter( int op, int type, InputArray _kernel,
962                                                       Point anchor, int _rowBorderType, int _columnBorderType,
963                                                       const Scalar& _borderValue )
964 {
965     Mat kernel = _kernel.getMat();
966     anchor = normalizeAnchor(anchor, kernel.size());
967
968     Ptr<BaseRowFilter> rowFilter;
969     Ptr<BaseColumnFilter> columnFilter;
970     Ptr<BaseFilter> filter2D;
971
972     if( countNonZero(kernel) == kernel.rows*kernel.cols )
973     {
974         // rectangular structuring element
975         rowFilter = getMorphologyRowFilter(op, type, kernel.cols, anchor.x);
976         columnFilter = getMorphologyColumnFilter(op, type, kernel.rows, anchor.y);
977     }
978     else
979         filter2D = getMorphologyFilter(op, type, kernel, anchor);
980
981     Scalar borderValue = _borderValue;
982     if( (_rowBorderType == BORDER_CONSTANT || _columnBorderType == BORDER_CONSTANT) &&
983             borderValue == morphologyDefaultBorderValue() )
984     {
985         int depth = CV_MAT_DEPTH(type);
986         CV_Assert( depth == CV_8U || depth == CV_16U || depth == CV_16S || depth == CV_32F );
987         if( op == MORPH_ERODE )
988             borderValue = Scalar::all( depth == CV_8U ? (double)UCHAR_MAX :
989                                                         depth == CV_16U ? (double)USHRT_MAX :
990                                                         depth == CV_16S ? (double)SHRT_MAX : (double)FLT_MAX );
991         else
992             borderValue = Scalar::all( depth == CV_8U || depth == CV_16U ? 0. :
993                                                          depth == CV_16S ? (double)SHRT_MIN : (double)-FLT_MAX );
994     }
995
996     return Ptr<FilterEngine>(new FilterEngine(filter2D, rowFilter, columnFilter,
997                                               type, type, type, _rowBorderType, _columnBorderType, borderValue ));
998 }
999
1000
1001 cv::Mat cv::getStructuringElement(int shape, Size ksize, Point anchor)
1002 {
1003     int i, j;
1004     int r = 0, c = 0;
1005     double inv_r2 = 0;
1006
1007     CV_Assert( shape == MORPH_RECT || shape == MORPH_CROSS || shape == MORPH_ELLIPSE );
1008
1009     anchor = normalizeAnchor(anchor, ksize);
1010
1011     if( ksize == Size(1,1) )
1012         shape = MORPH_RECT;
1013
1014     if( shape == MORPH_ELLIPSE )
1015     {
1016         r = ksize.height/2;
1017         c = ksize.width/2;
1018         inv_r2 = r ? 1./((double)r*r) : 0;
1019     }
1020
1021     Mat elem(ksize, CV_8U);
1022
1023     for( i = 0; i < ksize.height; i++ )
1024     {
1025         uchar* ptr = elem.data + i*elem.step;
1026         int j1 = 0, j2 = 0;
1027
1028         if( shape == MORPH_RECT || (shape == MORPH_CROSS && i == anchor.y) )
1029             j2 = ksize.width;
1030         else if( shape == MORPH_CROSS )
1031             j1 = anchor.x, j2 = j1 + 1;
1032         else
1033         {
1034             int dy = i - r;
1035             if( std::abs(dy) <= r )
1036             {
1037                 int dx = saturate_cast<int>(c*std::sqrt((r*r - dy*dy)*inv_r2));
1038                 j1 = std::max( c - dx, 0 );
1039                 j2 = std::min( c + dx + 1, ksize.width );
1040             }
1041         }
1042
1043         for( j = 0; j < j1; j++ )
1044             ptr[j] = 0;
1045         for( ; j < j2; j++ )
1046             ptr[j] = 1;
1047         for( ; j < ksize.width; j++ )
1048             ptr[j] = 0;
1049     }
1050
1051     return elem;
1052 }
1053
1054 namespace cv
1055 {
1056
1057 class MorphologyRunner
1058 {
1059 public:
1060     MorphologyRunner(Mat _src, Mat _dst, int _nStripes, int _iterations,
1061                      int _op, Mat _kernel, Point _anchor,
1062                      int _rowBorderType, int _columnBorderType, const Scalar& _borderValue) :
1063         borderValue(_borderValue)
1064     {
1065         src = _src;
1066         dst = _dst;
1067
1068         nStripes = _nStripes;
1069         iterations = _iterations;
1070
1071         op = _op;
1072         kernel = _kernel;
1073         anchor = _anchor;
1074         rowBorderType = _rowBorderType;
1075         columnBorderType = _columnBorderType;
1076     }
1077
1078     void operator () ( const BlockedRange& range ) const
1079     {
1080         int row0 = min(cvRound(range.begin() * src.rows / nStripes), src.rows);
1081         int row1 = min(cvRound(range.end() * src.rows / nStripes), src.rows);
1082
1083         /*if(0)
1084             printf("Size = (%d, %d), range[%d,%d), row0 = %d, row1 = %d\n",
1085                    src.rows, src.cols, range.begin(), range.end(), row0, row1);*/
1086
1087         Mat srcStripe = src.rowRange(row0, row1);
1088         Mat dstStripe = dst.rowRange(row0, row1);
1089
1090         Ptr<FilterEngine> f = createMorphologyFilter(op, src.type(), kernel, anchor,
1091                                                      rowBorderType, columnBorderType, borderValue );
1092
1093         f->apply( srcStripe, dstStripe );
1094         for( int i = 1; i < iterations; i++ )
1095             f->apply( dstStripe, dstStripe );
1096     }
1097
1098 private:
1099     Mat src;
1100     Mat dst;
1101     int nStripes;
1102     int iterations;
1103
1104     int op;
1105     Mat kernel;
1106     Point anchor;
1107     int rowBorderType;
1108     int columnBorderType;
1109     Scalar borderValue;
1110 };
1111
1112 static void morphOp( int op, InputArray _src, OutputArray _dst,
1113                      InputArray _kernel,
1114                      Point anchor, int iterations,
1115                      int borderType, const Scalar& borderValue )
1116 {
1117     Mat src = _src.getMat(), kernel = _kernel.getMat();
1118     Size ksize = kernel.data ? kernel.size() : Size(3,3);
1119     anchor = normalizeAnchor(anchor, ksize);
1120
1121     CV_Assert( anchor.inside(Rect(0, 0, ksize.width, ksize.height)) );
1122
1123     _dst.create( src.size(), src.type() );
1124     Mat dst = _dst.getMat();
1125     
1126     if( iterations == 0 || kernel.rows*kernel.cols == 1 )
1127     {
1128         src.copyTo(dst);
1129         return;
1130     }
1131
1132     if( !kernel.data )
1133     {
1134         kernel = getStructuringElement(MORPH_RECT, Size(1+iterations*2,1+iterations*2));
1135         anchor = Point(iterations, iterations);
1136         iterations = 1;
1137     }
1138     else if( iterations > 1 && countNonZero(kernel) == kernel.rows*kernel.cols )
1139     {
1140         anchor = Point(anchor.x*iterations, anchor.y*iterations);
1141         kernel = getStructuringElement(MORPH_RECT,
1142                                        Size(ksize.width + iterations*(ksize.width-1),
1143                                             ksize.height + iterations*(ksize.height-1)),
1144                                        anchor);
1145         iterations = 1;
1146     }
1147
1148     int nStripes = 1;
1149 #if defined HAVE_TBB && defined HAVE_TEGRA_OPTIMIZATION
1150     if (src.data != dst.data && iterations == 1 &&  //NOTE: threads are not used for inplace processing
1151         (borderType & BORDER_ISOLATED) == 0 && //TODO: check border types
1152         src.rows >= 64 ) //NOTE: just heuristics
1153         nStripes = 4;
1154 #endif
1155
1156     parallel_for(BlockedRange(0, nStripes),
1157                  MorphologyRunner(src, dst, nStripes, iterations, op, kernel, anchor, borderType, borderType, borderValue));
1158
1159     //Ptr<FilterEngine> f = createMorphologyFilter(op, src.type(),
1160     //                                             kernel, anchor, borderType, borderType, borderValue );
1161
1162     //f->apply( src, dst );
1163     //for( int i = 1; i < iterations; i++ )
1164     //    f->apply( dst, dst );
1165 }
1166
1167 template<> void Ptr<IplConvKernel>::delete_obj()
1168 { cvReleaseStructuringElement(&obj); }
1169
1170 }
1171
1172 void cv::erode( InputArray src, OutputArray dst, InputArray kernel,
1173                 Point anchor, int iterations,
1174                 int borderType, const Scalar& borderValue )
1175 {
1176     morphOp( MORPH_ERODE, src, dst, kernel, anchor, iterations, borderType, borderValue );
1177 }
1178
1179
1180 void cv::dilate( InputArray src, OutputArray dst, InputArray kernel,
1181                  Point anchor, int iterations,
1182                  int borderType, const Scalar& borderValue )
1183 {
1184     morphOp( MORPH_DILATE, src, dst, kernel, anchor, iterations, borderType, borderValue );
1185 }
1186
1187
1188 void cv::morphologyEx( InputArray _src, OutputArray _dst, int op,
1189                        InputArray kernel, Point anchor, int iterations,
1190                        int borderType, const Scalar& borderValue )
1191 {
1192     Mat src = _src.getMat(), temp;
1193     _dst.create(src.size(), src.type());
1194     Mat dst = _dst.getMat();
1195     
1196     switch( op )
1197     {
1198     case MORPH_ERODE:
1199         erode( src, dst, kernel, anchor, iterations, borderType, borderValue );
1200         break;    
1201     case MORPH_DILATE:
1202         dilate( src, dst, kernel, anchor, iterations, borderType, borderValue );
1203         break;    
1204     case MORPH_OPEN:
1205         erode( src, dst, kernel, anchor, iterations, borderType, borderValue );
1206         dilate( dst, dst, kernel, anchor, iterations, borderType, borderValue );
1207         break;
1208     case CV_MOP_CLOSE:
1209         dilate( src, dst, kernel, anchor, iterations, borderType, borderValue );
1210         erode( dst, dst, kernel, anchor, iterations, borderType, borderValue );
1211         break;
1212     case CV_MOP_GRADIENT:
1213         erode( src, temp, kernel, anchor, iterations, borderType, borderValue );
1214         dilate( src, dst, kernel, anchor, iterations, borderType, borderValue );
1215         dst -= temp;
1216         break;
1217     case CV_MOP_TOPHAT:
1218         if( src.data != dst.data )
1219             temp = dst;
1220         erode( src, temp, kernel, anchor, iterations, borderType, borderValue );
1221         dilate( temp, temp, kernel, anchor, iterations, borderType, borderValue );
1222         dst = src - temp;
1223         break;
1224     case CV_MOP_BLACKHAT:
1225         if( src.data != dst.data )
1226             temp = dst;
1227         dilate( src, temp, kernel, anchor, iterations, borderType, borderValue );
1228         erode( temp, temp, kernel, anchor, iterations, borderType, borderValue );
1229         dst = temp - src;
1230         break;
1231     default:
1232         CV_Error( CV_StsBadArg, "unknown morphological operation" );
1233     }
1234 }
1235
1236 CV_IMPL IplConvKernel *
1237 cvCreateStructuringElementEx( int cols, int rows,
1238                               int anchorX, int anchorY,
1239                               int shape, int *values )
1240 {
1241     cv::Size ksize = cv::Size(cols, rows);
1242     cv::Point anchor = cv::Point(anchorX, anchorY);
1243     CV_Assert( cols > 0 && rows > 0 && anchor.inside(cv::Rect(0,0,cols,rows)) &&
1244                (shape != CV_SHAPE_CUSTOM || values != 0));
1245
1246     int i, size = rows * cols;
1247     int element_size = sizeof(IplConvKernel) + size*sizeof(int);
1248     IplConvKernel *element = (IplConvKernel*)cvAlloc(element_size + 32);
1249
1250     element->nCols = cols;
1251     element->nRows = rows;
1252     element->anchorX = anchorX;
1253     element->anchorY = anchorY;
1254     element->nShiftR = shape < CV_SHAPE_ELLIPSE ? shape : CV_SHAPE_CUSTOM;
1255     element->values = (int*)(element + 1);
1256
1257     if( shape == CV_SHAPE_CUSTOM )
1258     {
1259         for( i = 0; i < size; i++ )
1260             element->values[i] = values[i];
1261     }
1262     else
1263     {
1264         cv::Mat elem = cv::getStructuringElement(shape, ksize, anchor);
1265         for( i = 0; i < size; i++ )
1266             element->values[i] = elem.data[i];
1267     }
1268
1269     return element;
1270 }
1271
1272
1273 CV_IMPL void
1274 cvReleaseStructuringElement( IplConvKernel ** element )
1275 {
1276     if( !element )
1277         CV_Error( CV_StsNullPtr, "" );
1278     cvFree( element );
1279 }
1280
1281
1282 static void convertConvKernel( const IplConvKernel* src, cv::Mat& dst, cv::Point& anchor )
1283 {
1284     if(!src)
1285     {
1286         anchor = cv::Point(1,1);
1287         dst.release();
1288         return;
1289     }
1290     anchor = cv::Point(src->anchorX, src->anchorY);
1291     dst.create(src->nRows, src->nCols, CV_8U);
1292
1293     int i, size = src->nRows*src->nCols;
1294     for( i = 0; i < size; i++ )
1295         dst.data[i] = (uchar)src->values[i];
1296 }
1297
1298
1299 CV_IMPL void
1300 cvErode( const CvArr* srcarr, CvArr* dstarr, IplConvKernel* element, int iterations )
1301 {
1302     cv::Mat src = cv::cvarrToMat(srcarr), dst = cv::cvarrToMat(dstarr), kernel;
1303     CV_Assert( src.size() == dst.size() && src.type() == dst.type() );
1304     cv::Point anchor;
1305     convertConvKernel( element, kernel, anchor );
1306     cv::erode( src, dst, kernel, anchor, iterations, cv::BORDER_REPLICATE );
1307 }
1308
1309
1310 CV_IMPL void
1311 cvDilate( const CvArr* srcarr, CvArr* dstarr, IplConvKernel* element, int iterations )
1312 {
1313     cv::Mat src = cv::cvarrToMat(srcarr), dst = cv::cvarrToMat(dstarr), kernel;
1314     CV_Assert( src.size() == dst.size() && src.type() == dst.type() );
1315     cv::Point anchor;
1316     convertConvKernel( element, kernel, anchor );
1317     cv::dilate( src, dst, kernel, anchor, iterations, cv::BORDER_REPLICATE );
1318 }
1319
1320
1321 CV_IMPL void
1322 cvMorphologyEx( const void* srcarr, void* dstarr, void*,
1323                 IplConvKernel* element, int op, int iterations )
1324 {
1325     cv::Mat src = cv::cvarrToMat(srcarr), dst = cv::cvarrToMat(dstarr), kernel;
1326     CV_Assert( src.size() == dst.size() && src.type() == dst.type() );
1327     cv::Point anchor;
1328     IplConvKernel* temp_element = NULL;
1329     if (!element)
1330     {
1331         temp_element = cvCreateStructuringElementEx(3, 3, 1, 1, CV_SHAPE_RECT);
1332     } else {
1333         temp_element = element;
1334     }
1335     convertConvKernel( temp_element, kernel, anchor );
1336     if (!element)
1337     {
1338         cvReleaseStructuringElement(&temp_element);
1339     }
1340     cv::morphologyEx( src, dst, op, kernel, anchor, iterations, cv::BORDER_REPLICATE );
1341 }
1342
1343 /* End of file. */