1 /*M///////////////////////////////////////////////////////////////////////////////////////
3 // IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
5 // By downloading, copying, installing or using the software you agree to this license.
6 // If you do not agree to this license, do not download, install,
7 // copy or use the software.
11 // For Open Source Computer Vision Library
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.
17 // Redistribution and use in source and binary forms, with or without modification,
18 // are permitted provided that the following conditions are met:
20 // * Redistribution's of source code must retain the above copyright notice,
21 // this list of conditions and the following disclaimer.
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.
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.
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.
43 #include "precomp.hpp"
47 /****************************************************************************************\
48 Basic Morphological Operations: Erosion & Dilation
49 \****************************************************************************************/
54 template<typename T> struct MinOp
59 T operator ()(T a, T b) const { return std::min(a, b); }
62 template<typename T> struct MaxOp
67 T operator ()(T a, T b) const { return std::max(a, b); }
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)))
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); }
80 template<class VecUpdate> struct MorphRowIVec
82 enum { ESZ = VecUpdate::ESZ };
84 MorphRowIVec(int _ksize, int _anchor) : ksize(_ksize), anchor(_anchor) {}
85 int operator()(const uchar* src, uchar* dst, int width, int cn) const
87 if( !checkHardwareSupport(CV_CPU_SSE2) )
91 int i, k, _ksize = ksize*cn;
92 width = (width & -4)*cn;
95 for( i = 0; i <= width - 16; i += 16 )
97 __m128i s = _mm_loadu_si128((const __m128i*)(src + i));
98 for( k = cn; k < _ksize; k += cn )
100 __m128i x = _mm_loadu_si128((const __m128i*)(src + i + k));
103 _mm_storeu_si128((__m128i*)(dst + i), s);
106 for( ; i < width; i += 4 )
108 __m128i s = _mm_cvtsi32_si128(*(const int*)(src + i));
109 for( k = cn; k < _ksize; k += cn )
111 __m128i x = _mm_cvtsi32_si128(*(const int*)(src + i + k));
114 *(int*)(dst + i) = _mm_cvtsi128_si32(s);
124 template<class VecUpdate> struct MorphRowFVec
126 MorphRowFVec(int _ksize, int _anchor) : ksize(_ksize), anchor(_anchor) {}
127 int operator()(const uchar* src, uchar* dst, int width, int cn) const
129 if( !checkHardwareSupport(CV_CPU_SSE) )
132 int i, k, _ksize = ksize*cn;
133 width = (width & -4)*cn;
136 for( i = 0; i < width; i += 4 )
138 __m128 s = _mm_loadu_ps((const float*)src + i);
139 for( k = cn; k < _ksize; k += cn )
141 __m128 x = _mm_loadu_ps((const float*)src + i + k);
144 _mm_storeu_ps((float*)dst + i, s);
154 template<class VecUpdate> struct MorphColumnIVec
156 enum { ESZ = VecUpdate::ESZ };
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
161 if( !checkHardwareSupport(CV_CPU_SSE2) )
164 int i = 0, k, _ksize = ksize;
168 for( i = 0; i < count + ksize - 1; i++ )
169 CV_Assert( ((size_t)src[i] & 15) == 0 );
171 for( ; _ksize > 1 && count > 1; count -= 2, dst += dststep*2, src += 2 )
173 for( i = 0; i <= width - 32; i += 32 )
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));
180 for( k = 2; k < _ksize; k++ )
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);
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));
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));
202 for( ; i <= width - 8; i += 8 )
204 __m128i s0 = _mm_loadl_epi64((const __m128i*)(src[1] + i)), x0;
206 for( k = 2; k < _ksize; k++ )
208 x0 = _mm_loadl_epi64((const __m128i*)(src[k] + i));
209 s0 = updateOp(s0, x0);
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));
219 for( ; count > 0; count--, dst += dststep, src++ )
221 for( i = 0; i <= width - 32; i += 32 )
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));
228 for( k = 1; k < _ksize; k++ )
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);
236 _mm_storeu_si128((__m128i*)(dst + i), s0);
237 _mm_storeu_si128((__m128i*)(dst + i + 16), s1);
240 for( ; i <= width - 8; i += 8 )
242 __m128i s0 = _mm_loadl_epi64((const __m128i*)(src[0] + i)), x0;
244 for( k = 1; k < _ksize; k++ )
246 x0 = _mm_loadl_epi64((const __m128i*)(src[k] + i));
247 s0 = updateOp(s0, x0);
249 _mm_storel_epi64((__m128i*)(dst + i), s0);
260 template<class VecUpdate> struct MorphColumnFVec
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
265 if( !checkHardwareSupport(CV_CPU_SSE) )
268 int i = 0, k, _ksize = ksize;
271 for( i = 0; i < count + ksize - 1; i++ )
272 CV_Assert( ((size_t)_src[i] & 15) == 0 );
274 const float** src = (const float**)_src;
275 float* dst = (float*)_dst;
276 dststep /= sizeof(dst[0]);
278 for( ; _ksize > 1 && count > 1; count -= 2, dst += dststep*2, src += 2 )
280 for( i = 0; i <= width - 16; i += 16 )
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;
289 for( k = 2; k < _ksize; k++ )
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);
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));
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));
323 for( ; i <= width - 4; i += 4 )
325 __m128 s0 = _mm_load_ps(src[1] + i), x0;
327 for( k = 2; k < _ksize; k++ )
329 x0 = _mm_load_ps(src[k] + i);
330 s0 = updateOp(s0, x0);
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));
340 for( ; count > 0; count--, dst += dststep, src++ )
342 for( i = 0; i <= width - 16; i += 16 )
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;
351 for( k = 1; k < _ksize; k++ )
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);
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);
369 for( i = 0; i <= width - 4; i += 4 )
371 __m128 s0 = _mm_load_ps(src[0] + i), x0;
372 for( k = 1; k < _ksize; k++ )
374 x0 = _mm_load_ps(src[k] + i);
375 s0 = updateOp(s0, x0);
377 _mm_storeu_ps(dst + i, s0);
388 template<class VecUpdate> struct MorphIVec
390 enum { ESZ = VecUpdate::ESZ };
392 int operator()(uchar** src, int nz, uchar* dst, int width) const
394 if( !checkHardwareSupport(CV_CPU_SSE2) )
401 for( i = 0; i <= width - 32; i += 32 )
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));
408 for( k = 1; k < nz; k++ )
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);
416 _mm_storeu_si128((__m128i*)(dst + i), s0);
417 _mm_storeu_si128((__m128i*)(dst + i + 16), s1);
420 for( ; i <= width - 8; i += 8 )
422 __m128i s0 = _mm_loadl_epi64((const __m128i*)(src[0] + i)), x0;
424 for( k = 1; k < nz; k++ )
426 x0 = _mm_loadl_epi64((const __m128i*)(src[k] + i));
427 s0 = updateOp(s0, x0);
429 _mm_storel_epi64((__m128i*)(dst + i), s0);
437 template<class VecUpdate> struct MorphFVec
439 int operator()(uchar** _src, int nz, uchar* _dst, int width) const
441 if( !checkHardwareSupport(CV_CPU_SSE) )
444 const float** src = (const float**)_src;
445 float* dst = (float*)_dst;
449 for( i = 0; i <= width - 16; i += 16 )
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;
458 for( k = 1; k < nz; k++ )
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);
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);
476 for( ; i <= width - 4; i += 4 )
478 __m128 s0 = _mm_loadu_ps(src[0] + i), x0;
480 for( k = 1; k < nz; k++ )
482 x0 = _mm_loadu_ps(src[k] + i);
483 s0 = updateOp(s0, x0);
485 _mm_storeu_ps(dst + i, s0);
488 for( ; i < width; i++ )
490 __m128 s0 = _mm_load_ss(src[0] + i), x0;
492 for( k = 1; k < nz; k++ )
494 x0 = _mm_load_ss(src[k] + i);
495 s0 = updateOp(s0, x0);
497 _mm_store_ss(dst + i, s0);
507 __m128i operator()(const __m128i& a, const __m128i& b) const { return _mm_min_epu8(a,b); }
512 __m128i operator()(const __m128i& a, const __m128i& b) const { return _mm_max_epu8(a,b); }
517 __m128i operator()(const __m128i& a, const __m128i& b) const
518 { return _mm_subs_epu16(a,_mm_subs_epu16(a,b)); }
523 __m128i operator()(const __m128i& a, const __m128i& b) const
524 { return _mm_adds_epu16(_mm_subs_epu16(a,b), b); }
529 __m128i operator()(const __m128i& a, const __m128i& b) const
530 { return _mm_min_epi16(a, b); }
535 __m128i operator()(const __m128i& a, const __m128i& b) const
536 { return _mm_max_epi16(a, b); }
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); }};
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;
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;
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;
572 MorphRowNoVec(int, int) {}
573 int operator()(const uchar*, uchar*, int, int) const { return 0; }
576 struct MorphColumnNoVec
578 MorphColumnNoVec(int, int) {}
579 int operator()(const uchar**, uchar*, int, int, int) const { return 0; }
584 int operator()(uchar**, int, uchar*, int) const { return 0; }
587 #ifdef HAVE_TEGRA_OPTIMIZATION
588 using tegra::ErodeRowVec8u;
589 using tegra::DilateRowVec8u;
591 using tegra::ErodeColumnVec8u;
592 using tegra::DilateColumnVec8u;
594 typedef MorphRowNoVec ErodeRowVec8u;
595 typedef MorphRowNoVec DilateRowVec8u;
597 typedef MorphColumnNoVec ErodeColumnVec8u;
598 typedef MorphColumnNoVec DilateColumnVec8u;
601 typedef MorphRowNoVec ErodeRowVec16u;
602 typedef MorphRowNoVec DilateRowVec16u;
603 typedef MorphRowNoVec ErodeRowVec16s;
604 typedef MorphRowNoVec DilateRowVec16s;
605 typedef MorphRowNoVec ErodeRowVec32f;
606 typedef MorphRowNoVec DilateRowVec32f;
608 typedef MorphColumnNoVec ErodeColumnVec16u;
609 typedef MorphColumnNoVec DilateColumnVec16u;
610 typedef MorphColumnNoVec ErodeColumnVec16s;
611 typedef MorphColumnNoVec DilateColumnVec16s;
612 typedef MorphColumnNoVec ErodeColumnVec32f;
613 typedef MorphColumnNoVec DilateColumnVec32f;
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;
627 template<class Op, class VecOp> struct MorphRowFilter : public BaseRowFilter
629 typedef typename Op::rtype T;
631 MorphRowFilter( int _ksize, int _anchor ) : vecOp(_ksize, _anchor)
637 void operator()(const uchar* src, uchar* dst, int width, int cn)
639 int i, j, k, _ksize = ksize*cn;
640 const T* S = (const T*)src;
646 for( i = 0; i < width*cn; i++ )
651 int i0 = vecOp(src, dst, width, cn);
654 for( k = 0; k < cn; k++, S++, D++ )
656 for( i = i0; i <= width - cn*2; i += cn*2 )
660 for( j = cn*2; j < _ksize; j += cn )
663 D[i+cn] = op(m, s[j]);
666 for( ; i < width; i += cn )
670 for( j = cn; j < _ksize; j += cn )
681 template<class Op, class VecOp> struct MorphColumnFilter : public BaseColumnFilter
683 typedef typename Op::rtype T;
685 MorphColumnFilter( int _ksize, int _anchor ) : vecOp(_ksize, _anchor)
691 void operator()(const uchar** _src, uchar* dst, int dststep, int count, int width)
693 int i, k, _ksize = ksize;
694 const T** src = (const T**)_src;
698 int i0 = vecOp(_src, dst, dststep, count, width);
699 dststep /= sizeof(D[0]);
701 for( ; _ksize > 1 && count > 1; count -= 2, D += dststep*2, src += 2 )
704 #if CV_ENABLE_UNROLLED
705 for( ; i <= width - 4; i += 4 )
707 const T* sptr = src[1] + i;
708 T s0 = sptr[0], s1 = sptr[1], s2 = sptr[2], s3 = sptr[3];
710 for( k = 2; k < _ksize; k++ )
713 s0 = op(s0, sptr[0]); s1 = op(s1, sptr[1]);
714 s2 = op(s2, sptr[2]); s3 = op(s3, sptr[3]);
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]);
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]);
730 for( ; i < width; i++ )
734 for( k = 2; k < _ksize; k++ )
735 s0 = op(s0, src[k][i]);
737 D[i] = op(s0, src[0][i]);
738 D[i+dststep] = op(s0, src[k][i]);
742 for( ; count > 0; count--, D += dststep, src++ )
745 #if CV_ENABLE_UNROLLED
746 for( ; i <= width - 4; i += 4 )
748 const T* sptr = src[0] + i;
749 T s0 = sptr[0], s1 = sptr[1], s2 = sptr[2], s3 = sptr[3];
751 for( k = 1; k < _ksize; k++ )
754 s0 = op(s0, sptr[0]); s1 = op(s1, sptr[1]);
755 s2 = op(s2, sptr[2]); s3 = op(s3, sptr[3]);
758 D[i] = s0; D[i+1] = s1;
759 D[i+2] = s2; D[i+3] = s3;
762 for( ; i < width; i++ )
765 for( k = 1; k < _ksize; k++ )
766 s0 = op(s0, src[k][i]);
776 template<class Op, class VecOp> struct MorphFilter : BaseFilter
778 typedef typename Op::rtype T;
780 MorphFilter( const Mat& _kernel, Point _anchor )
783 ksize = _kernel.size();
784 CV_Assert( _kernel.type() == CV_8U );
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() );
792 void operator()(const uchar** src, uchar* dst, int dststep, int count, int width, int cn)
794 const Point* pt = &coords[0];
795 const T** kp = (const T**)&ptrs[0];
796 int i, k, nz = (int)coords.size();
800 for( ; count > 0; count--, dst += dststep, src++ )
804 for( k = 0; k < nz; k++ )
805 kp[k] = (const T*)src[pt[k].y] + pt[k].x*cn;
807 i = vecOp(&ptrs[0], nz, dst, width);
808 #if CV_ENABLE_UNROLLED
809 for( ; i <= width - 4; i += 4 )
811 const T* sptr = kp[0] + i;
812 T s0 = sptr[0], s1 = sptr[1], s2 = sptr[2], s3 = sptr[3];
814 for( k = 1; k < nz; k++ )
817 s0 = op(s0, sptr[0]); s1 = op(s1, sptr[1]);
818 s2 = op(s2, sptr[2]); s3 = op(s3, sptr[3]);
821 D[i] = s0; D[i+1] = s1;
822 D[i+2] = s2; D[i+3] = s3;
825 for( ; i < width; i++ )
828 for( k = 1; k < nz; k++ )
829 s0 = op(s0, kp[k][i]);
835 vector<Point> coords;
842 /////////////////////////////////// External Interface /////////////////////////////////////
844 cv::Ptr<cv::BaseRowFilter> cv::getMorphologyRowFilter(int op, int type, int ksize, int anchor)
846 int depth = CV_MAT_DEPTH(type);
849 CV_Assert( op == MORPH_ERODE || op == MORPH_DILATE );
850 if( op == MORPH_ERODE )
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));
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));
881 CV_Error_( CV_StsNotImplemented, ("Unsupported data type (=%d)", type));
882 return Ptr<BaseRowFilter>(0);
885 cv::Ptr<cv::BaseColumnFilter> cv::getMorphologyColumnFilter(int op, int type, int ksize, int anchor)
887 int depth = CV_MAT_DEPTH(type);
890 CV_Assert( op == MORPH_ERODE || op == MORPH_DILATE );
891 if( op == MORPH_ERODE )
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));
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));
922 CV_Error_( CV_StsNotImplemented, ("Unsupported data type (=%d)", type));
923 return Ptr<BaseColumnFilter>(0);
927 cv::Ptr<cv::BaseFilter> cv::getMorphologyFilter(int op, int type, InputArray _kernel, Point anchor)
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 )
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));
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));
956 CV_Error_( CV_StsNotImplemented, ("Unsupported data type (=%d)", type));
957 return Ptr<BaseFilter>(0);
961 cv::Ptr<cv::FilterEngine> cv::createMorphologyFilter( int op, int type, InputArray _kernel,
962 Point anchor, int _rowBorderType, int _columnBorderType,
963 const Scalar& _borderValue )
965 Mat kernel = _kernel.getMat();
966 anchor = normalizeAnchor(anchor, kernel.size());
968 Ptr<BaseRowFilter> rowFilter;
969 Ptr<BaseColumnFilter> columnFilter;
970 Ptr<BaseFilter> filter2D;
972 if( countNonZero(kernel) == kernel.rows*kernel.cols )
974 // rectangular structuring element
975 rowFilter = getMorphologyRowFilter(op, type, kernel.cols, anchor.x);
976 columnFilter = getMorphologyColumnFilter(op, type, kernel.rows, anchor.y);
979 filter2D = getMorphologyFilter(op, type, kernel, anchor);
981 Scalar borderValue = _borderValue;
982 if( (_rowBorderType == BORDER_CONSTANT || _columnBorderType == BORDER_CONSTANT) &&
983 borderValue == morphologyDefaultBorderValue() )
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 );
992 borderValue = Scalar::all( depth == CV_8U || depth == CV_16U ? 0. :
993 depth == CV_16S ? (double)SHRT_MIN : (double)-FLT_MAX );
996 return Ptr<FilterEngine>(new FilterEngine(filter2D, rowFilter, columnFilter,
997 type, type, type, _rowBorderType, _columnBorderType, borderValue ));
1001 cv::Mat cv::getStructuringElement(int shape, Size ksize, Point anchor)
1007 CV_Assert( shape == MORPH_RECT || shape == MORPH_CROSS || shape == MORPH_ELLIPSE );
1009 anchor = normalizeAnchor(anchor, ksize);
1011 if( ksize == Size(1,1) )
1014 if( shape == MORPH_ELLIPSE )
1018 inv_r2 = r ? 1./((double)r*r) : 0;
1021 Mat elem(ksize, CV_8U);
1023 for( i = 0; i < ksize.height; i++ )
1025 uchar* ptr = elem.data + i*elem.step;
1028 if( shape == MORPH_RECT || (shape == MORPH_CROSS && i == anchor.y) )
1030 else if( shape == MORPH_CROSS )
1031 j1 = anchor.x, j2 = j1 + 1;
1035 if( std::abs(dy) <= r )
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 );
1043 for( j = 0; j < j1; j++ )
1045 for( ; j < j2; j++ )
1047 for( ; j < ksize.width; j++ )
1057 class MorphologyRunner
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)
1068 nStripes = _nStripes;
1069 iterations = _iterations;
1074 rowBorderType = _rowBorderType;
1075 columnBorderType = _columnBorderType;
1078 void operator () ( const BlockedRange& range ) const
1080 int row0 = min(cvRound(range.begin() * src.rows / nStripes), src.rows);
1081 int row1 = min(cvRound(range.end() * src.rows / nStripes), src.rows);
1084 printf("Size = (%d, %d), range[%d,%d), row0 = %d, row1 = %d\n",
1085 src.rows, src.cols, range.begin(), range.end(), row0, row1);*/
1087 Mat srcStripe = src.rowRange(row0, row1);
1088 Mat dstStripe = dst.rowRange(row0, row1);
1090 Ptr<FilterEngine> f = createMorphologyFilter(op, src.type(), kernel, anchor,
1091 rowBorderType, columnBorderType, borderValue );
1093 f->apply( srcStripe, dstStripe );
1094 for( int i = 1; i < iterations; i++ )
1095 f->apply( dstStripe, dstStripe );
1108 int columnBorderType;
1112 static void morphOp( int op, InputArray _src, OutputArray _dst,
1114 Point anchor, int iterations,
1115 int borderType, const Scalar& borderValue )
1117 Mat src = _src.getMat(), kernel = _kernel.getMat();
1118 Size ksize = kernel.data ? kernel.size() : Size(3,3);
1119 anchor = normalizeAnchor(anchor, ksize);
1121 CV_Assert( anchor.inside(Rect(0, 0, ksize.width, ksize.height)) );
1123 _dst.create( src.size(), src.type() );
1124 Mat dst = _dst.getMat();
1126 if( iterations == 0 || kernel.rows*kernel.cols == 1 )
1134 kernel = getStructuringElement(MORPH_RECT, Size(1+iterations*2,1+iterations*2));
1135 anchor = Point(iterations, iterations);
1138 else if( iterations > 1 && countNonZero(kernel) == kernel.rows*kernel.cols )
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)),
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
1156 parallel_for(BlockedRange(0, nStripes),
1157 MorphologyRunner(src, dst, nStripes, iterations, op, kernel, anchor, borderType, borderType, borderValue));
1159 //Ptr<FilterEngine> f = createMorphologyFilter(op, src.type(),
1160 // kernel, anchor, borderType, borderType, borderValue );
1162 //f->apply( src, dst );
1163 //for( int i = 1; i < iterations; i++ )
1164 // f->apply( dst, dst );
1167 template<> void Ptr<IplConvKernel>::delete_obj()
1168 { cvReleaseStructuringElement(&obj); }
1172 void cv::erode( InputArray src, OutputArray dst, InputArray kernel,
1173 Point anchor, int iterations,
1174 int borderType, const Scalar& borderValue )
1176 morphOp( MORPH_ERODE, src, dst, kernel, anchor, iterations, borderType, borderValue );
1180 void cv::dilate( InputArray src, OutputArray dst, InputArray kernel,
1181 Point anchor, int iterations,
1182 int borderType, const Scalar& borderValue )
1184 morphOp( MORPH_DILATE, src, dst, kernel, anchor, iterations, borderType, borderValue );
1188 void cv::morphologyEx( InputArray _src, OutputArray _dst, int op,
1189 InputArray kernel, Point anchor, int iterations,
1190 int borderType, const Scalar& borderValue )
1192 Mat src = _src.getMat(), temp;
1193 _dst.create(src.size(), src.type());
1194 Mat dst = _dst.getMat();
1199 erode( src, dst, kernel, anchor, iterations, borderType, borderValue );
1202 dilate( src, dst, kernel, anchor, iterations, borderType, borderValue );
1205 erode( src, dst, kernel, anchor, iterations, borderType, borderValue );
1206 dilate( dst, dst, kernel, anchor, iterations, borderType, borderValue );
1209 dilate( src, dst, kernel, anchor, iterations, borderType, borderValue );
1210 erode( dst, dst, kernel, anchor, iterations, borderType, borderValue );
1212 case CV_MOP_GRADIENT:
1213 erode( src, temp, kernel, anchor, iterations, borderType, borderValue );
1214 dilate( src, dst, kernel, anchor, iterations, borderType, borderValue );
1218 if( src.data != dst.data )
1220 erode( src, temp, kernel, anchor, iterations, borderType, borderValue );
1221 dilate( temp, temp, kernel, anchor, iterations, borderType, borderValue );
1224 case CV_MOP_BLACKHAT:
1225 if( src.data != dst.data )
1227 dilate( src, temp, kernel, anchor, iterations, borderType, borderValue );
1228 erode( temp, temp, kernel, anchor, iterations, borderType, borderValue );
1232 CV_Error( CV_StsBadArg, "unknown morphological operation" );
1236 CV_IMPL IplConvKernel *
1237 cvCreateStructuringElementEx( int cols, int rows,
1238 int anchorX, int anchorY,
1239 int shape, int *values )
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));
1246 int i, size = rows * cols;
1247 int element_size = sizeof(IplConvKernel) + size*sizeof(int);
1248 IplConvKernel *element = (IplConvKernel*)cvAlloc(element_size + 32);
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);
1257 if( shape == CV_SHAPE_CUSTOM )
1259 for( i = 0; i < size; i++ )
1260 element->values[i] = values[i];
1264 cv::Mat elem = cv::getStructuringElement(shape, ksize, anchor);
1265 for( i = 0; i < size; i++ )
1266 element->values[i] = elem.data[i];
1274 cvReleaseStructuringElement( IplConvKernel ** element )
1277 CV_Error( CV_StsNullPtr, "" );
1282 static void convertConvKernel( const IplConvKernel* src, cv::Mat& dst, cv::Point& anchor )
1286 anchor = cv::Point(1,1);
1290 anchor = cv::Point(src->anchorX, src->anchorY);
1291 dst.create(src->nRows, src->nCols, CV_8U);
1293 int i, size = src->nRows*src->nCols;
1294 for( i = 0; i < size; i++ )
1295 dst.data[i] = (uchar)src->values[i];
1300 cvErode( const CvArr* srcarr, CvArr* dstarr, IplConvKernel* element, int iterations )
1302 cv::Mat src = cv::cvarrToMat(srcarr), dst = cv::cvarrToMat(dstarr), kernel;
1303 CV_Assert( src.size() == dst.size() && src.type() == dst.type() );
1305 convertConvKernel( element, kernel, anchor );
1306 cv::erode( src, dst, kernel, anchor, iterations, cv::BORDER_REPLICATE );
1311 cvDilate( const CvArr* srcarr, CvArr* dstarr, IplConvKernel* element, int iterations )
1313 cv::Mat src = cv::cvarrToMat(srcarr), dst = cv::cvarrToMat(dstarr), kernel;
1314 CV_Assert( src.size() == dst.size() && src.type() == dst.type() );
1316 convertConvKernel( element, kernel, anchor );
1317 cv::dilate( src, dst, kernel, anchor, iterations, cv::BORDER_REPLICATE );
1322 cvMorphologyEx( const void* srcarr, void* dstarr, void*,
1323 IplConvKernel* element, int op, int iterations )
1325 cv::Mat src = cv::cvarrToMat(srcarr), dst = cv::cvarrToMat(dstarr), kernel;
1326 CV_Assert( src.size() == dst.size() && src.type() == dst.type() );
1328 IplConvKernel* temp_element = NULL;
1331 temp_element = cvCreateStructuringElementEx(3, 3, 1, 1, CV_SHAPE_RECT);
1333 temp_element = element;
1335 convertConvKernel( temp_element, kernel, anchor );
1338 cvReleaseStructuringElement(&temp_element);
1340 cv::morphologyEx( src, dst, op, kernel, anchor, iterations, cv::BORDER_REPLICATE );