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.
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
88 int i, k, _ksize = ksize*cn;
92 for( i = 0; i <= width - 16; i += 16 )
94 __m128i s = _mm_loadu_si128((const __m128i*)(src + i));
95 for( k = cn; k < _ksize; k += cn )
97 __m128i x = _mm_loadu_si128((const __m128i*)(src + i + k));
100 _mm_storeu_si128((__m128i*)(dst + i), s);
103 for( ; i <= width - 4; i += 4 )
105 __m128i s = _mm_cvtsi32_si128(*(const int*)(src + i));
106 for( k = cn; k < _ksize; k += cn )
108 __m128i x = _mm_cvtsi32_si128(*(const int*)(src + i + k));
111 *(int*)(dst + i) = _mm_cvtsi128_si32(s);
121 template<class VecUpdate> struct MorphRowFVec
123 MorphRowFVec(int _ksize, int _anchor) : ksize(_ksize), anchor(_anchor) {}
124 int operator()(const uchar* src, uchar* dst, int width, int cn) const
126 int i, k, _ksize = ksize*cn;
130 for( i = 0; i <= width - 4; i += 4 )
132 __m128 s = _mm_loadu_ps((const float*)src + i);
133 for( k = cn; k < _ksize; k += cn )
135 __m128 x = _mm_loadu_ps((const float*)src + i + k);
138 _mm_storeu_ps((float*)dst + i, s);
148 template<class VecUpdate> struct MorphColumnIVec
150 enum { ESZ = VecUpdate::ESZ };
152 MorphColumnIVec(int _ksize, int _anchor) : ksize(_ksize), anchor(_anchor) {}
153 int operator()(const uchar** src, uchar* dst, int dststep, int count, int width) const
155 int i = 0, k, _ksize = ksize;
159 for( i = 0; i < count + ksize - 1; i++ )
160 CV_Assert( ((size_t)src[i] & 15) == 0 );
162 for( ; _ksize > 1 && count > 1; count -= 2, dst += dststep*2, src += 2 )
164 for( i = 0; i <= width - 32; i += 32 )
166 const uchar* sptr = src[1] + i;
167 __m128i s0 = _mm_load_si128((const __m128i*)sptr);
168 __m128i s1 = _mm_load_si128((const __m128i*)(sptr + 16));
171 for( k = 2; k < _ksize; k++ )
174 x0 = _mm_load_si128((const __m128i*)sptr);
175 x1 = _mm_load_si128((const __m128i*)(sptr + 16));
176 s0 = updateOp(s0, x0);
177 s1 = updateOp(s1, x1);
181 x0 = _mm_load_si128((const __m128i*)sptr);
182 x1 = _mm_load_si128((const __m128i*)(sptr + 16));
183 _mm_storeu_si128((__m128i*)(dst + i), updateOp(s0, x0));
184 _mm_storeu_si128((__m128i*)(dst + i + 16), updateOp(s1, x1));
187 x0 = _mm_load_si128((const __m128i*)sptr);
188 x1 = _mm_load_si128((const __m128i*)(sptr + 16));
189 _mm_storeu_si128((__m128i*)(dst + dststep + i), updateOp(s0, x0));
190 _mm_storeu_si128((__m128i*)(dst + dststep + i + 16), updateOp(s1, x1));
193 for( ; i <= width - 8; i += 8 )
195 __m128i s0 = _mm_loadl_epi64((const __m128i*)(src[1] + i)), x0;
197 for( k = 2; k < _ksize; k++ )
199 x0 = _mm_loadl_epi64((const __m128i*)(src[k] + i));
200 s0 = updateOp(s0, x0);
203 x0 = _mm_loadl_epi64((const __m128i*)(src[0] + i));
204 _mm_storel_epi64((__m128i*)(dst + i), updateOp(s0, x0));
205 x0 = _mm_loadl_epi64((const __m128i*)(src[k] + i));
206 _mm_storel_epi64((__m128i*)(dst + dststep + i), updateOp(s0, x0));
210 for( ; count > 0; count--, dst += dststep, src++ )
212 for( i = 0; i <= width - 32; i += 32 )
214 const uchar* sptr = src[0] + i;
215 __m128i s0 = _mm_load_si128((const __m128i*)sptr);
216 __m128i s1 = _mm_load_si128((const __m128i*)(sptr + 16));
219 for( k = 1; k < _ksize; k++ )
222 x0 = _mm_load_si128((const __m128i*)sptr);
223 x1 = _mm_load_si128((const __m128i*)(sptr + 16));
224 s0 = updateOp(s0, x0);
225 s1 = updateOp(s1, x1);
227 _mm_storeu_si128((__m128i*)(dst + i), s0);
228 _mm_storeu_si128((__m128i*)(dst + i + 16), s1);
231 for( ; i <= width - 8; i += 8 )
233 __m128i s0 = _mm_loadl_epi64((const __m128i*)(src[0] + i)), x0;
235 for( k = 1; k < _ksize; k++ )
237 x0 = _mm_loadl_epi64((const __m128i*)(src[k] + i));
238 s0 = updateOp(s0, x0);
240 _mm_storel_epi64((__m128i*)(dst + i), s0);
251 template<class VecUpdate> struct MorphColumnFVec
253 MorphColumnFVec(int _ksize, int _anchor) : ksize(_ksize), anchor(_anchor) {}
254 int operator()(const uchar** _src, uchar* _dst, int dststep, int count, int width) const
256 int i = 0, k, _ksize = ksize;
259 for( i = 0; i < count + ksize - 1; i++ )
260 CV_Assert( ((size_t)_src[i] & 15) == 0 );
262 const float** src = (const float**)_src;
263 float* dst = (float*)_dst;
264 dststep /= sizeof(dst[0]);
266 for( ; _ksize > 1 && count > 1; count -= 2, dst += dststep*2, src += 2 )
268 for( i = 0; i <= width - 16; i += 16 )
270 const float* sptr = src[1] + i;
271 __m128 s0 = _mm_load_ps(sptr);
272 __m128 s1 = _mm_load_ps(sptr + 4);
273 __m128 s2 = _mm_load_ps(sptr + 8);
274 __m128 s3 = _mm_load_ps(sptr + 12);
275 __m128 x0, x1, x2, x3;
277 for( k = 2; k < _ksize; k++ )
280 x0 = _mm_load_ps(sptr);
281 x1 = _mm_load_ps(sptr + 4);
282 s0 = updateOp(s0, x0);
283 s1 = updateOp(s1, x1);
284 x2 = _mm_load_ps(sptr + 8);
285 x3 = _mm_load_ps(sptr + 12);
286 s2 = updateOp(s2, x2);
287 s3 = updateOp(s3, x3);
291 x0 = _mm_load_ps(sptr);
292 x1 = _mm_load_ps(sptr + 4);
293 x2 = _mm_load_ps(sptr + 8);
294 x3 = _mm_load_ps(sptr + 12);
295 _mm_storeu_ps(dst + i, updateOp(s0, x0));
296 _mm_storeu_ps(dst + i + 4, updateOp(s1, x1));
297 _mm_storeu_ps(dst + i + 8, updateOp(s2, x2));
298 _mm_storeu_ps(dst + i + 12, updateOp(s3, x3));
301 x0 = _mm_load_ps(sptr);
302 x1 = _mm_load_ps(sptr + 4);
303 x2 = _mm_load_ps(sptr + 8);
304 x3 = _mm_load_ps(sptr + 12);
305 _mm_storeu_ps(dst + dststep + i, updateOp(s0, x0));
306 _mm_storeu_ps(dst + dststep + i + 4, updateOp(s1, x1));
307 _mm_storeu_ps(dst + dststep + i + 8, updateOp(s2, x2));
308 _mm_storeu_ps(dst + dststep + i + 12, updateOp(s3, x3));
311 for( ; i <= width - 4; i += 4 )
313 __m128 s0 = _mm_load_ps(src[1] + i), x0;
315 for( k = 2; k < _ksize; k++ )
317 x0 = _mm_load_ps(src[k] + i);
318 s0 = updateOp(s0, x0);
321 x0 = _mm_load_ps(src[0] + i);
322 _mm_storeu_ps(dst + i, updateOp(s0, x0));
323 x0 = _mm_load_ps(src[k] + i);
324 _mm_storeu_ps(dst + dststep + i, updateOp(s0, x0));
328 for( ; count > 0; count--, dst += dststep, src++ )
330 for( i = 0; i <= width - 16; i += 16 )
332 const float* sptr = src[0] + i;
333 __m128 s0 = _mm_load_ps(sptr);
334 __m128 s1 = _mm_load_ps(sptr + 4);
335 __m128 s2 = _mm_load_ps(sptr + 8);
336 __m128 s3 = _mm_load_ps(sptr + 12);
337 __m128 x0, x1, x2, x3;
339 for( k = 1; k < _ksize; k++ )
342 x0 = _mm_load_ps(sptr);
343 x1 = _mm_load_ps(sptr + 4);
344 s0 = updateOp(s0, x0);
345 s1 = updateOp(s1, x1);
346 x2 = _mm_load_ps(sptr + 8);
347 x3 = _mm_load_ps(sptr + 12);
348 s2 = updateOp(s2, x2);
349 s3 = updateOp(s3, x3);
351 _mm_storeu_ps(dst + i, s0);
352 _mm_storeu_ps(dst + i + 4, s1);
353 _mm_storeu_ps(dst + i + 8, s2);
354 _mm_storeu_ps(dst + i + 12, s3);
357 for( i = 0; i <= width - 4; i += 4 )
359 __m128 s0 = _mm_load_ps(src[0] + i), x0;
360 for( k = 1; k < _ksize; k++ )
362 x0 = _mm_load_ps(src[k] + i);
363 s0 = updateOp(s0, x0);
365 _mm_storeu_ps(dst + i, s0);
376 template<class VecUpdate> struct MorphIVec
378 enum { ESZ = VecUpdate::ESZ };
380 int operator()(uchar** src, int nz, uchar* dst, int width) const
386 for( i = 0; i <= width - 32; i += 32 )
388 const uchar* sptr = src[0] + i;
389 __m128i s0 = _mm_loadu_si128((const __m128i*)sptr);
390 __m128i s1 = _mm_loadu_si128((const __m128i*)(sptr + 16));
393 for( k = 1; k < nz; k++ )
396 x0 = _mm_loadu_si128((const __m128i*)sptr);
397 x1 = _mm_loadu_si128((const __m128i*)(sptr + 16));
398 s0 = updateOp(s0, x0);
399 s1 = updateOp(s1, x1);
401 _mm_storeu_si128((__m128i*)(dst + i), s0);
402 _mm_storeu_si128((__m128i*)(dst + i + 16), s1);
405 for( ; i <= width - 8; i += 8 )
407 __m128i s0 = _mm_loadl_epi64((const __m128i*)(src[0] + i)), x0;
409 for( k = 1; k < nz; k++ )
411 x0 = _mm_loadl_epi64((const __m128i*)(src[k] + i));
412 s0 = updateOp(s0, x0);
414 _mm_storel_epi64((__m128i*)(dst + i), s0);
422 template<class VecUpdate> struct MorphFVec
424 int operator()(uchar** _src, int nz, uchar* _dst, int width) const
426 const float** src = (const float**)_src;
427 float* dst = (float*)_dst;
431 for( i = 0; i <= width - 16; i += 16 )
433 const float* sptr = src[0] + i;
434 __m128 s0 = _mm_loadu_ps(sptr);
435 __m128 s1 = _mm_loadu_ps(sptr + 4);
436 __m128 s2 = _mm_loadu_ps(sptr + 8);
437 __m128 s3 = _mm_loadu_ps(sptr + 12);
438 __m128 x0, x1, x2, x3;
440 for( k = 1; k < nz; k++ )
443 x0 = _mm_loadu_ps(sptr);
444 x1 = _mm_loadu_ps(sptr + 4);
445 x2 = _mm_loadu_ps(sptr + 8);
446 x3 = _mm_loadu_ps(sptr + 12);
447 s0 = updateOp(s0, x0);
448 s1 = updateOp(s1, x1);
449 s2 = updateOp(s2, x2);
450 s3 = updateOp(s3, x3);
452 _mm_storeu_ps(dst + i, s0);
453 _mm_storeu_ps(dst + i + 4, s1);
454 _mm_storeu_ps(dst + i + 8, s2);
455 _mm_storeu_ps(dst + i + 12, s3);
458 for( ; i <= width - 4; i += 4 )
460 __m128 s0 = _mm_loadu_ps(src[0] + i), x0;
462 for( k = 1; k < nz; k++ )
464 x0 = _mm_loadu_ps(src[k] + i);
465 s0 = updateOp(s0, x0);
467 _mm_storeu_ps(dst + i, s0);
470 for( ; i < width; i++ )
472 __m128 s0 = _mm_load_ss(src[0] + i), x0;
474 for( k = 1; k < nz; k++ )
476 x0 = _mm_load_ss(src[k] + i);
477 s0 = updateOp(s0, x0);
479 _mm_store_ss(dst + i, s0);
490 __m128i operator()(const __m128i& a, const __m128i& b) const { return _mm_min_epu8(a,b); }
495 __m128i operator()(const __m128i& a, const __m128i& b) const { return _mm_max_epu8(a,b); }
500 __m128i operator()(const __m128i& a, const __m128i& b) const
501 { return _mm_subs_epu16(a,_mm_subs_epu16(a,b)); }
506 __m128i operator()(const __m128i& a, const __m128i& b) const
507 { return _mm_adds_epu16(_mm_subs_epu16(a,b),b); }
512 __m128i operator()(const __m128i& a, const __m128i& b) const
513 { return _mm_min_epi16(a, b); }
518 __m128i operator()(const __m128i& a, const __m128i& b) const
519 { return _mm_max_epi16(a, b); }
521 struct VMin32f { __m128 operator()(const __m128& a, const __m128& b) const { return _mm_min_ps(a,b); }};
522 struct VMax32f { __m128 operator()(const __m128& a, const __m128& b) const { return _mm_max_ps(a,b); }};
524 typedef MorphRowIVec<VMin8u> ErodeRowVec8u;
525 typedef MorphRowIVec<VMax8u> DilateRowVec8u;
526 typedef MorphRowIVec<VMin16u> ErodeRowVec16u;
527 typedef MorphRowIVec<VMax16u> DilateRowVec16u;
528 typedef MorphRowIVec<VMin16s> ErodeRowVec16s;
529 typedef MorphRowIVec<VMax16s> DilateRowVec16s;
530 typedef MorphRowFVec<VMin32f> ErodeRowVec32f;
531 typedef MorphRowFVec<VMax32f> DilateRowVec32f;
533 typedef MorphColumnIVec<VMin8u> ErodeColumnVec8u;
534 typedef MorphColumnIVec<VMax8u> DilateColumnVec8u;
535 typedef MorphColumnIVec<VMin16u> ErodeColumnVec16u;
536 typedef MorphColumnIVec<VMax16u> DilateColumnVec16s;
537 typedef MorphColumnIVec<VMin16s> ErodeColumnVec16s;
538 typedef MorphColumnIVec<VMax16s> DilateColumnVec16u;
539 typedef MorphColumnFVec<VMin32f> ErodeColumnVec32f;
540 typedef MorphColumnFVec<VMax32f> DilateColumnVec32f;
542 typedef MorphIVec<VMin8u> ErodeVec8u;
543 typedef MorphIVec<VMax8u> DilateVec8u;
544 typedef MorphIVec<VMin16u> ErodeVec16u;
545 typedef MorphIVec<VMax16u> DilateVec16u;
546 typedef MorphIVec<VMin16s> ErodeVec16s;
547 typedef MorphIVec<VMax16s> DilateVec16s;
548 typedef MorphFVec<VMin32f> ErodeVec32f;
549 typedef MorphFVec<VMax32f> DilateVec32f;
555 MorphRowNoVec(int, int) {}
556 int operator()(const uchar*, uchar*, int, int) const { return 0; }
559 struct MorphColumnNoVec
561 MorphColumnNoVec(int, int) {}
562 int operator()(const uchar**, uchar*, int, int, int) const { return 0; }
567 int operator()(uchar**, int, uchar*, int) const { return 0; }
570 typedef MorphRowNoVec ErodeRowVec8u;
571 typedef MorphRowNoVec DilateRowVec8u;
572 typedef MorphRowNoVec ErodeRowVec16u;
573 typedef MorphRowNoVec DilateRowVec16u;
574 typedef MorphRowNoVec ErodeRowVec16s;
575 typedef MorphRowNoVec DilateRowVec16s;
576 typedef MorphRowNoVec ErodeRowVec32f;
577 typedef MorphRowNoVec DilateRowVec32f;
579 typedef MorphColumnNoVec ErodeColumnVec8u;
580 typedef MorphColumnNoVec DilateColumnVec8u;
581 typedef MorphColumnNoVec ErodeColumnVec16u;
582 typedef MorphColumnNoVec DilateColumnVec16u;
583 typedef MorphColumnNoVec ErodeColumnVec16s;
584 typedef MorphColumnNoVec DilateColumnVec16s;
585 typedef MorphColumnNoVec ErodeColumnVec32f;
586 typedef MorphColumnNoVec DilateColumnVec32f;
588 typedef MorphNoVec ErodeVec8u;
589 typedef MorphNoVec DilateVec8u;
590 typedef MorphNoVec ErodeVec16u;
591 typedef MorphNoVec DilateVec16u;
592 typedef MorphNoVec ErodeVec16s;
593 typedef MorphNoVec DilateVec16s;
594 typedef MorphNoVec ErodeVec32f;
595 typedef MorphNoVec DilateVec32f;
599 template<class Op, class VecOp> struct MorphRowFilter : public BaseRowFilter
601 typedef typename Op::rtype T;
603 MorphRowFilter( int _ksize, int _anchor ) : vecOp(_ksize, _anchor)
609 void operator()(const uchar* src, uchar* dst, int width, int cn)
611 int i, j, k, _ksize = ksize*cn;
612 const T* S = (const T*)src;
618 for( i = 0; i < width*cn; i++ )
623 int i0 = vecOp(src, dst, width, cn);
626 for( k = 0; k < cn; k++, S++, D++ )
628 for( i = i0; i <= width - cn*2; i += cn*2 )
632 for( j = cn*2; j < _ksize; j += cn )
635 D[i+cn] = op(m, s[j]);
638 for( ; i < width; i += cn )
642 for( j = cn; j < _ksize; j += cn )
653 template<class Op, class VecOp> struct MorphColumnFilter : public BaseColumnFilter
655 typedef typename Op::rtype T;
657 MorphColumnFilter( int _ksize, int _anchor ) : vecOp(_ksize, _anchor)
663 void operator()(const uchar** _src, uchar* dst, int dststep, int count, int width)
665 int i, k, _ksize = ksize;
666 const T** src = (const T**)_src;
670 int i0 = vecOp(_src, dst, dststep, count, width);
671 dststep /= sizeof(D[0]);
673 for( ; _ksize > 1 && count > 1; count -= 2, D += dststep*2, src += 2 )
675 for( i = i0; i <= width - 4; i += 4 )
677 const T* sptr = src[1] + i;
678 T s0 = sptr[0], s1 = sptr[1], s2 = sptr[2], s3 = sptr[3];
680 for( k = 2; k < _ksize; k++ )
683 s0 = op(s0, sptr[0]); s1 = op(s1, sptr[1]);
684 s2 = op(s2, sptr[2]); s3 = op(s3, sptr[3]);
688 D[i] = op(s0, sptr[0]);
689 D[i+1] = op(s1, sptr[1]);
690 D[i+2] = op(s2, sptr[2]);
691 D[i+3] = op(s3, sptr[3]);
694 D[i+dststep] = op(s0, sptr[0]);
695 D[i+dststep+1] = op(s1, sptr[1]);
696 D[i+dststep+2] = op(s2, sptr[2]);
697 D[i+dststep+3] = op(s3, sptr[3]);
700 for( ; i < width; i++ )
704 for( k = 2; k < _ksize; k++ )
705 s0 = op(s0, src[k][i]);
707 D[i] = op(s0, src[0][i]);
708 D[i+dststep] = op(s0, src[k][i]);
712 for( ; count > 0; count--, D += dststep, src++ )
714 for( i = i0; i <= width - 4; i += 4 )
716 const T* sptr = src[0] + i;
717 T s0 = sptr[0], s1 = sptr[1], s2 = sptr[2], s3 = sptr[3];
719 for( k = 1; k < _ksize; k++ )
722 s0 = op(s0, sptr[0]); s1 = op(s1, sptr[1]);
723 s2 = op(s2, sptr[2]); s3 = op(s3, sptr[3]);
726 D[i] = s0; D[i+1] = s1;
727 D[i+2] = s2; D[i+3] = s3;
730 for( ; i < width; i++ )
733 for( k = 1; k < _ksize; k++ )
734 s0 = op(s0, src[k][i]);
744 template<class Op, class VecOp> struct MorphFilter : BaseFilter
746 typedef typename Op::rtype T;
748 MorphFilter( const Mat& _kernel, Point _anchor )
751 ksize = _kernel.size();
752 CV_Assert( _kernel.type() == CV_8U );
754 vector<uchar> coeffs; // we do not really the values of non-zero
755 // kernel elements, just their locations
756 preprocess2DKernel( _kernel, coords, coeffs );
757 ptrs.resize( coords.size() );
760 void operator()(const uchar** src, uchar* dst, int dststep, int count, int width, int cn)
762 const Point* pt = &coords[0];
763 const T** kp = (const T**)&ptrs[0];
764 int i, k, nz = (int)coords.size();
768 for( ; count > 0; count--, dst += dststep, src++ )
772 for( k = 0; k < nz; k++ )
773 kp[k] = (const T*)src[pt[k].y] + pt[k].x*cn;
775 i = vecOp(&ptrs[0], nz, dst, width);
777 for( ; i <= width - 4; i += 4 )
779 const T* sptr = kp[0] + i;
780 T s0 = sptr[0], s1 = sptr[1], s2 = sptr[2], s3 = sptr[3];
782 for( k = 1; k < nz; k++ )
785 s0 = op(s0, sptr[0]); s1 = op(s1, sptr[1]);
786 s2 = op(s2, sptr[2]); s3 = op(s3, sptr[3]);
789 D[i] = s0; D[i+1] = s1;
790 D[i+2] = s2; D[i+3] = s3;
793 for( ; i < width; i++ )
796 for( k = 1; k < nz; k++ )
797 s0 = op(s0, kp[k][i]);
803 vector<Point> coords;
808 /////////////////////////////////// External Interface /////////////////////////////////////
810 Ptr<BaseRowFilter> getMorphologyRowFilter(int op, int type, int ksize, int anchor)
812 int depth = CV_MAT_DEPTH(type);
815 CV_Assert( op == MORPH_ERODE || op == MORPH_DILATE );
816 if( op == MORPH_ERODE )
819 return Ptr<BaseRowFilter>(new MorphRowFilter<MinOp<uchar>,
820 ErodeRowVec8u>(ksize, anchor));
821 if( depth == CV_16U )
822 return Ptr<BaseRowFilter>(new MorphRowFilter<MinOp<ushort>,
823 ErodeRowVec16u>(ksize, anchor));
824 if( depth == CV_16S )
825 return Ptr<BaseRowFilter>(new MorphRowFilter<MinOp<short>,
826 ErodeRowVec16s>(ksize, anchor));
827 if( depth == CV_32F )
828 return Ptr<BaseRowFilter>(new MorphRowFilter<MinOp<float>,
829 ErodeRowVec32f>(ksize, anchor));
834 return Ptr<BaseRowFilter>(new MorphRowFilter<MaxOp<uchar>,
835 DilateRowVec8u>(ksize, anchor));
836 if( depth == CV_16U )
837 return Ptr<BaseRowFilter>(new MorphRowFilter<MaxOp<ushort>,
838 DilateRowVec16u>(ksize, anchor));
839 if( depth == CV_16S )
840 return Ptr<BaseRowFilter>(new MorphRowFilter<MaxOp<short>,
841 DilateRowVec16s>(ksize, anchor));
842 if( depth == CV_32F )
843 return Ptr<BaseRowFilter>(new MorphRowFilter<MaxOp<float>,
844 DilateRowVec32f>(ksize, anchor));
847 CV_Error_( CV_StsNotImplemented, ("Unsupported data type (=%d)", type));
848 return Ptr<BaseRowFilter>(0);
851 Ptr<BaseColumnFilter> getMorphologyColumnFilter(int op, int type, int ksize, int anchor)
853 int depth = CV_MAT_DEPTH(type);
856 CV_Assert( op == MORPH_ERODE || op == MORPH_DILATE );
857 if( op == MORPH_ERODE )
860 return Ptr<BaseColumnFilter>(new MorphColumnFilter<MinOp<uchar>,
861 ErodeColumnVec8u>(ksize, anchor));
862 if( depth == CV_16U )
863 return Ptr<BaseColumnFilter>(new MorphColumnFilter<MinOp<ushort>,
864 ErodeColumnVec16u>(ksize, anchor));
865 if( depth == CV_16S )
866 return Ptr<BaseColumnFilter>(new MorphColumnFilter<MinOp<short>,
867 ErodeColumnVec16s>(ksize, anchor));
868 if( depth == CV_32F )
869 return Ptr<BaseColumnFilter>(new MorphColumnFilter<MinOp<float>,
870 ErodeColumnVec32f>(ksize, anchor));
875 return Ptr<BaseColumnFilter>(new MorphColumnFilter<MaxOp<uchar>,
876 DilateColumnVec8u>(ksize, anchor));
877 if( depth == CV_16U )
878 return Ptr<BaseColumnFilter>(new MorphColumnFilter<MaxOp<ushort>,
879 DilateColumnVec16u>(ksize, anchor));
880 if( depth == CV_16S )
881 return Ptr<BaseColumnFilter>(new MorphColumnFilter<MaxOp<short>,
882 DilateColumnVec16u>(ksize, anchor));
883 if( depth == CV_32F )
884 return Ptr<BaseColumnFilter>(new MorphColumnFilter<MaxOp<float>,
885 DilateColumnVec32f>(ksize, anchor));
888 CV_Error_( CV_StsNotImplemented, ("Unsupported data type (=%d)", type));
889 return Ptr<BaseColumnFilter>(0);
893 Ptr<BaseFilter> getMorphologyFilter(int op, int type, const Mat& kernel, Point anchor)
895 int depth = CV_MAT_DEPTH(type);
896 anchor = normalizeAnchor(anchor, kernel.size());
897 CV_Assert( op == MORPH_ERODE || op == MORPH_DILATE );
898 if( op == MORPH_ERODE )
901 return Ptr<BaseFilter>(new MorphFilter<MinOp<uchar>, ErodeVec8u>(kernel, anchor));
902 if( depth == CV_16U )
903 return Ptr<BaseFilter>(new MorphFilter<MinOp<ushort>, ErodeVec16u>(kernel, anchor));
904 if( depth == CV_16S )
905 return Ptr<BaseFilter>(new MorphFilter<MinOp<short>, ErodeVec16s>(kernel, anchor));
906 if( depth == CV_32F )
907 return Ptr<BaseFilter>(new MorphFilter<MinOp<float>, ErodeVec32f>(kernel, anchor));
912 return Ptr<BaseFilter>(new MorphFilter<MaxOp<uchar>, DilateVec8u>(kernel, anchor));
913 if( depth == CV_16U )
914 return Ptr<BaseFilter>(new MorphFilter<MaxOp<ushort>, DilateVec16u>(kernel, anchor));
915 if( depth == CV_16S )
916 return Ptr<BaseFilter>(new MorphFilter<MaxOp<short>, DilateVec16s>(kernel, anchor));
917 if( depth == CV_32F )
918 return Ptr<BaseFilter>(new MorphFilter<MaxOp<float>, DilateVec32f>(kernel, anchor));
921 CV_Error_( CV_StsNotImplemented, ("Unsupported data type (=%d)", type));
922 return Ptr<BaseFilter>(0);
926 Ptr<FilterEngine> createMorphologyFilter( int op, int type, const Mat& kernel,
927 Point anchor, int _rowBorderType, int _columnBorderType,
928 const Scalar& _borderValue )
930 anchor = normalizeAnchor(anchor, kernel.size());
932 Ptr<BaseRowFilter> rowFilter;
933 Ptr<BaseColumnFilter> columnFilter;
934 Ptr<BaseFilter> filter2D;
936 if( countNonZero(kernel) == kernel.rows*kernel.cols )
938 // rectangular structuring element
939 rowFilter = getMorphologyRowFilter(op, type, kernel.cols, anchor.x);
940 columnFilter = getMorphologyColumnFilter(op, type, kernel.rows, anchor.y);
943 filter2D = getMorphologyFilter(op, type, kernel, anchor);
945 Scalar borderValue = _borderValue;
946 if( (_rowBorderType == BORDER_CONSTANT || _columnBorderType == BORDER_CONSTANT) &&
947 borderValue == morphologyDefaultBorderValue() )
949 int depth = CV_MAT_TYPE(type);
950 CV_Assert( depth == CV_8U || depth == CV_16U || depth == CV_32F );
951 if( op == MORPH_ERODE )
952 borderValue = Scalar::all( depth == CV_8U ? (double)UCHAR_MAX :
953 depth == CV_16U ? (double)USHRT_MAX : (double)FLT_MAX );
955 borderValue = Scalar::all( depth == CV_8U || depth == CV_16U ?
956 0. : (double)-FLT_MAX );
959 return Ptr<FilterEngine>(new FilterEngine(filter2D, rowFilter, columnFilter,
960 type, type, type, _rowBorderType, _columnBorderType, borderValue ));
964 Mat getStructuringElement(int shape, Size ksize, Point anchor)
970 CV_Assert( shape == MORPH_RECT || shape == MORPH_CROSS || shape == MORPH_ELLIPSE );
972 anchor = normalizeAnchor(anchor, ksize);
974 if( ksize == Size(1,1) )
977 if( shape == MORPH_ELLIPSE )
981 inv_r2 = r ? 1./((double)r*r) : 0;
984 Mat elem(ksize, CV_8U);
986 for( i = 0; i < ksize.height; i++ )
988 uchar* ptr = elem.data + i*elem.step;
991 if( shape == MORPH_RECT || (shape == MORPH_CROSS && i == anchor.y) )
993 else if( shape == MORPH_CROSS )
994 j1 = anchor.x, j2 = j1 + 1;
998 if( std::abs(dy) <= r )
1000 int dx = saturate_cast<int>(c*std::sqrt((r*r - dy*dy)*inv_r2));
1001 j1 = std::max( c - dx, 0 );
1002 j2 = std::min( c + dx + 1, ksize.width );
1006 for( j = 0; j < j1; j++ )
1008 for( ; j < j2; j++ )
1010 for( ; j < ksize.width; j++ )
1017 static void morphOp( int op, const Mat& src, Mat& dst, const Mat& _kernel,
1018 Point anchor, int iterations,
1019 int borderType, const Scalar& borderValue )
1022 Size ksize = _kernel.data ? _kernel.size() : Size(3,3);
1023 anchor = normalizeAnchor(anchor, ksize);
1025 CV_Assert( anchor.inside(Rect(0, 0, ksize.width, ksize.height)) );
1027 if( iterations == 0 || _kernel.rows*_kernel.cols == 1 )
1033 dst.create( src.size(), src.type() );
1037 kernel = getStructuringElement(MORPH_RECT, Size(1+iterations*2,1+iterations*2));
1038 anchor = Point(iterations, iterations);
1041 else if( iterations > 1 && countNonZero(_kernel) == _kernel.rows*_kernel.cols )
1043 anchor = Point(anchor.x*iterations, anchor.y*iterations);
1044 kernel = getStructuringElement(MORPH_RECT,
1045 Size(ksize.width + iterations*(ksize.width-1),
1046 ksize.height + iterations*(ksize.height-1)),
1053 Ptr<FilterEngine> f = createMorphologyFilter(op, src.type(),
1054 kernel, anchor, borderType, borderType, borderValue );
1056 f->apply( src, dst );
1057 for( int i = 1; i < iterations; i++ )
1058 f->apply( dst, dst );
1062 void erode( const Mat& src, Mat& dst, const Mat& kernel,
1063 Point anchor, int iterations,
1064 int borderType, const Scalar& borderValue )
1066 morphOp( MORPH_ERODE, src, dst, kernel, anchor, iterations, borderType, borderValue );
1070 void dilate( const Mat& src, Mat& dst, const Mat& kernel,
1071 Point anchor, int iterations,
1072 int borderType, const Scalar& borderValue )
1074 morphOp( MORPH_DILATE, src, dst, kernel, anchor, iterations, borderType, borderValue );
1078 void morphologyEx( const Mat& src, Mat& dst, int op, const Mat& kernel,
1079 Point anchor, int iterations, int borderType,
1080 const Scalar& borderValue )
1086 erode( src, dst, kernel, anchor, iterations, borderType, borderValue );
1087 dilate( dst, dst, kernel, anchor, iterations, borderType, borderValue );
1090 dilate( src, dst, kernel, anchor, iterations, borderType, borderValue );
1091 erode( dst, dst, kernel, anchor, iterations, borderType, borderValue );
1093 case CV_MOP_GRADIENT:
1094 erode( src, temp, kernel, anchor, iterations, borderType, borderValue );
1095 dilate( src, dst, kernel, anchor, iterations, borderType, borderValue );
1099 if( src.data != dst.data )
1101 erode( src, temp, kernel, anchor, iterations, borderType, borderValue );
1102 dilate( temp, temp, kernel, anchor, iterations, borderType, borderValue );
1105 case CV_MOP_BLACKHAT:
1106 if( src.data != dst.data )
1108 dilate( src, temp, kernel, anchor, iterations, borderType, borderValue );
1109 erode( temp, temp, kernel, anchor, iterations, borderType, borderValue );
1113 CV_Error( CV_StsBadArg, "unknown morphological operation" );
1119 CV_IMPL IplConvKernel *
1120 cvCreateStructuringElementEx( int cols, int rows,
1121 int anchorX, int anchorY,
1122 int shape, int *values )
1124 cv::Size ksize = cv::Size(cols, rows);
1125 cv::Point anchor = cv::Point(anchorX, anchorY);
1126 CV_Assert( cols > 0 && rows > 0 && anchor.inside(cv::Rect(0,0,cols,rows)) &&
1127 (shape != CV_SHAPE_CUSTOM || values != 0));
1129 int i, size = rows * cols;
1130 int element_size = sizeof(IplConvKernel) + size*sizeof(int);
1131 IplConvKernel *element = (IplConvKernel*)cvAlloc(element_size + 32);
1133 element->nCols = cols;
1134 element->nRows = rows;
1135 element->anchorX = anchorX;
1136 element->anchorY = anchorY;
1137 element->nShiftR = shape < CV_SHAPE_ELLIPSE ? shape : CV_SHAPE_CUSTOM;
1138 element->values = (int*)(element + 1);
1140 if( shape == CV_SHAPE_CUSTOM )
1142 for( i = 0; i < size; i++ )
1143 element->values[i] = values[i];
1147 cv::Mat elem = cv::getStructuringElement(shape, ksize, anchor);
1148 for( i = 0; i < size; i++ )
1149 element->values[i] = elem.data[i];
1157 cvReleaseStructuringElement( IplConvKernel ** element )
1160 CV_Error( CV_StsNullPtr, "" );
1165 static void convertConvKernel( const IplConvKernel* src, cv::Mat& dst, cv::Point& anchor )
1169 anchor = cv::Point(1,1);
1173 anchor = cv::Point(src->anchorX, src->anchorY);
1174 dst.create(src->nRows, src->nCols, CV_8U);
1176 int i, size = src->nRows*src->nCols;
1177 for( i = 0; i < size; i++ )
1178 dst.data[i] = (uchar)src->values[i];
1183 cvErode( const CvArr* srcarr, CvArr* dstarr, IplConvKernel* element, int iterations )
1185 cv::Mat src = cv::cvarrToMat(srcarr), dst = cv::cvarrToMat(dstarr), kernel;
1186 CV_Assert( src.size() == dst.size() && src.type() == dst.type() );
1188 convertConvKernel( element, kernel, anchor );
1189 cv::erode( src, dst, kernel, anchor, iterations, cv::BORDER_REPLICATE );
1194 cvDilate( const CvArr* srcarr, CvArr* dstarr, IplConvKernel* element, int iterations )
1196 cv::Mat src = cv::cvarrToMat(srcarr), dst = cv::cvarrToMat(dstarr), kernel;
1197 CV_Assert( src.size() == dst.size() && src.type() == dst.type() );
1199 convertConvKernel( element, kernel, anchor );
1200 cv::dilate( src, dst, kernel, anchor, iterations, cv::BORDER_REPLICATE );
1205 cvMorphologyEx( const void* srcarr, void* dstarr, void*,
1206 IplConvKernel* element, int op, int iterations )
1208 cv::Mat src = cv::cvarrToMat(srcarr), dst = cv::cvarrToMat(dstarr), kernel;
1209 CV_Assert( src.size() == dst.size() && src.type() == dst.type() );
1211 IplConvKernel* temp_element = NULL;
1214 temp_element = cvCreateStructuringElementEx(3, 3, 1, 1, CV_SHAPE_RECT);
1216 temp_element = element;
1218 convertConvKernel( temp_element, kernel, anchor );
1221 cvReleaseStructuringElement(&temp_element);
1223 cv::morphologyEx( src, dst, op, kernel, anchor, iterations, cv::BORDER_REPLICATE );