54a1fc976ff7a1244a04ad8c424eef1e3889889b
[platform/upstream/opencv.git] / modules / imgproc / src / floodfill.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, Intel Corporation, all rights reserved.
14 // Copyright (C) 2013, OpenCV Foundation, 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
45 #if defined(__GNUC__) && (__GNUC__ == 4) && (__GNUC_MINOR__ == 8)
46 # pragma GCC diagnostic ignored "-Warray-bounds"
47 #endif
48
49 namespace cv
50 {
51
52 struct FFillSegment
53 {
54     ushort y;
55     ushort l;
56     ushort r;
57     ushort prevl;
58     ushort prevr;
59     short dir;
60 };
61
62 enum
63 {
64     UP = 1,
65     DOWN = -1
66 };
67
68 #define ICV_PUSH( Y, L, R, PREV_L, PREV_R, DIR )  \
69 {                                                 \
70     tail->y = (ushort)(Y);                        \
71     tail->l = (ushort)(L);                        \
72     tail->r = (ushort)(R);                        \
73     tail->prevl = (ushort)(PREV_L);               \
74     tail->prevr = (ushort)(PREV_R);               \
75     tail->dir = (short)(DIR);                     \
76     if( ++tail == buffer_end )                    \
77     {                                             \
78         buffer->resize(buffer->size() * 3/2);     \
79         tail = &buffer->front() + (tail - head);  \
80         head = &buffer->front();                  \
81         buffer_end = head + buffer->size();       \
82     }                                             \
83 }
84
85 #define ICV_POP( Y, L, R, PREV_L, PREV_R, DIR )   \
86 {                                                 \
87     --tail;                                       \
88     Y = tail->y;                                  \
89     L = tail->l;                                  \
90     R = tail->r;                                  \
91     PREV_L = tail->prevl;                         \
92     PREV_R = tail->prevr;                         \
93     DIR = tail->dir;                              \
94 }
95
96 struct ConnectedComp
97 {
98     ConnectedComp();
99     Rect rect;
100     Point pt;
101     int threshold;
102     int label;
103     int area;
104     int harea;
105     int carea;
106     int perimeter;
107     int nholes;
108     int ninflections;
109     double mx;
110     double my;
111     Scalar avg;
112     Scalar sdv;
113 };
114
115 ConnectedComp::ConnectedComp()
116 {
117     rect = Rect(0, 0, 0, 0);
118     pt = Point(-1, -1);
119     threshold = -1;
120     label = -1;
121     area = harea = carea = perimeter = nholes = ninflections = 0;
122     mx = my = 0;
123     avg = sdv = Scalar::all(0);
124 }
125
126 // Simple Floodfill (repainting single-color connected component)
127
128 template<typename _Tp>
129 static void
130 floodFill_CnIR( Mat& image, Point seed,
131                _Tp newVal, ConnectedComp* region, int flags,
132                std::vector<FFillSegment>* buffer )
133 {
134     _Tp* img = image.ptr<_Tp>(seed.y);
135     Size roi = image.size();
136     int i, L, R;
137     int area = 0;
138     int XMin, XMax, YMin = seed.y, YMax = seed.y;
139     int _8_connectivity = (flags & 255) == 8;
140     FFillSegment* buffer_end = &buffer->front() + buffer->size(), *head = &buffer->front(), *tail = &buffer->front();
141
142     L = R = XMin = XMax = seed.x;
143
144     _Tp val0 = img[L];
145     img[L] = newVal;
146
147     while( ++R < roi.width && img[R] == val0 )
148         img[R] = newVal;
149
150     while( --L >= 0 && img[L] == val0 )
151         img[L] = newVal;
152
153     XMax = --R;
154     XMin = ++L;
155
156     ICV_PUSH( seed.y, L, R, R + 1, R, UP );
157
158     while( head != tail )
159     {
160         int k, YC, PL, PR, dir;
161         ICV_POP( YC, L, R, PL, PR, dir );
162
163         int data[][3] =
164         {
165             {-dir, L - _8_connectivity, R + _8_connectivity},
166             {dir, L - _8_connectivity, PL - 1},
167             {dir, PR + 1, R + _8_connectivity}
168         };
169
170         if( region )
171         {
172             area += R - L + 1;
173
174             if( XMax < R ) XMax = R;
175             if( XMin > L ) XMin = L;
176             if( YMax < YC ) YMax = YC;
177             if( YMin > YC ) YMin = YC;
178         }
179
180         for( k = 0; k < 3; k++ )
181         {
182             dir = data[k][0];
183
184             if( (unsigned)(YC + dir) >= (unsigned)roi.height )
185                 continue;
186
187             img = image.ptr<_Tp>(YC + dir);
188             int left = data[k][1];
189             int right = data[k][2];
190
191             for( i = left; i <= right; i++ )
192             {
193                 if( (unsigned)i < (unsigned)roi.width && img[i] == val0 )
194                 {
195                     int j = i;
196                     img[i] = newVal;
197                     while( --j >= 0 && img[j] == val0 )
198                         img[j] = newVal;
199
200                     while( ++i < roi.width && img[i] == val0 )
201                         img[i] = newVal;
202
203                     ICV_PUSH( YC + dir, j+1, i-1, L, R, -dir );
204                 }
205             }
206         }
207     }
208
209     if( region )
210     {
211         region->pt = seed;
212         region->area = area;
213         region->rect.x = XMin;
214         region->rect.y = YMin;
215         region->rect.width = XMax - XMin + 1;
216         region->rect.height = YMax - YMin + 1;
217     }
218 }
219
220 /****************************************************************************************\
221 *                                   Gradient Floodfill                                   *
222 \****************************************************************************************/
223
224 struct Diff8uC1
225 {
226     Diff8uC1(uchar _lo, uchar _up) : lo(_lo), interval(_lo + _up) {}
227     bool operator()(const uchar* a, const uchar* b) const
228     { return (unsigned)(a[0] - b[0] + lo) <= interval; }
229     unsigned lo, interval;
230 };
231
232 struct Diff8uC3
233 {
234     Diff8uC3(Vec3b _lo, Vec3b _up)
235     {
236         for( int k = 0; k < 3; k++ )
237             lo[k] = _lo[k], interval[k] = _lo[k] + _up[k];
238     }
239     bool operator()(const Vec3b* a, const Vec3b* b) const
240     {
241         return (unsigned)(a[0][0] - b[0][0] + lo[0]) <= interval[0] &&
242                (unsigned)(a[0][1] - b[0][1] + lo[1]) <= interval[1] &&
243                (unsigned)(a[0][2] - b[0][2] + lo[2]) <= interval[2];
244     }
245     unsigned lo[3], interval[3];
246 };
247
248 template<typename _Tp>
249 struct DiffC1
250 {
251     DiffC1(_Tp _lo, _Tp _up) : lo(-_lo), up(_up) {}
252     bool operator()(const _Tp* a, const _Tp* b) const
253     {
254         _Tp d = a[0] - b[0];
255         return lo <= d && d <= up;
256     }
257     _Tp lo, up;
258 };
259
260 template<typename _Tp>
261 struct DiffC3
262 {
263     DiffC3(_Tp _lo, _Tp _up) : lo(-_lo), up(_up) {}
264     bool operator()(const _Tp* a, const _Tp* b) const
265     {
266         _Tp d = *a - *b;
267         return lo[0] <= d[0] && d[0] <= up[0] &&
268                lo[1] <= d[1] && d[1] <= up[1] &&
269                lo[2] <= d[2] && d[2] <= up[2];
270     }
271     _Tp lo, up;
272 };
273
274 typedef DiffC1<int> Diff32sC1;
275 typedef DiffC3<Vec3i> Diff32sC3;
276 typedef DiffC1<float> Diff32fC1;
277 typedef DiffC3<Vec3f> Diff32fC3;
278
279 template<typename _Tp, typename _MTp, typename _WTp, class Diff>
280 static void
281 floodFillGrad_CnIR( Mat& image, Mat& msk,
282                    Point seed, _Tp newVal, _MTp newMaskVal,
283                    Diff diff, ConnectedComp* region, int flags,
284                    std::vector<FFillSegment>* buffer )
285 {
286     int step = (int)image.step, maskStep = (int)msk.step;
287     uchar* pImage = image.ptr();
288     _Tp* img = (_Tp*)(pImage + step*seed.y);
289     uchar* pMask = msk.ptr() + maskStep + sizeof(_MTp);
290     _MTp* mask = (_MTp*)(pMask + maskStep*seed.y);
291     int i, L, R;
292     int area = 0;
293     int XMin, XMax, YMin = seed.y, YMax = seed.y;
294     int _8_connectivity = (flags & 255) == 8;
295     int fixedRange = flags & FLOODFILL_FIXED_RANGE;
296     int fillImage = (flags & FLOODFILL_MASK_ONLY) == 0;
297     FFillSegment* buffer_end = &buffer->front() + buffer->size(), *head = &buffer->front(), *tail = &buffer->front();
298
299     L = R = seed.x;
300     if( mask[L] )
301         return;
302
303     mask[L] = newMaskVal;
304     _Tp val0 = img[L];
305
306     if( fixedRange )
307     {
308         while( !mask[R + 1] && diff( img + (R+1), &val0 ))
309             mask[++R] = newMaskVal;
310
311         while( !mask[L - 1] && diff( img + (L-1), &val0 ))
312             mask[--L] = newMaskVal;
313     }
314     else
315     {
316         while( !mask[R + 1] && diff( img + (R+1), img + R ))
317             mask[++R] = newMaskVal;
318
319         while( !mask[L - 1] && diff( img + (L-1), img + L ))
320             mask[--L] = newMaskVal;
321     }
322
323     XMax = R;
324     XMin = L;
325
326     ICV_PUSH( seed.y, L, R, R + 1, R, UP );
327
328     while( head != tail )
329     {
330         int k, YC, PL, PR, dir;
331         ICV_POP( YC, L, R, PL, PR, dir );
332
333         int data[][3] =
334         {
335             {-dir, L - _8_connectivity, R + _8_connectivity},
336             {dir, L - _8_connectivity, PL - 1},
337             {dir, PR + 1, R + _8_connectivity}
338         };
339
340         unsigned length = (unsigned)(R-L);
341
342         if( region )
343         {
344             area += (int)length + 1;
345
346             if( XMax < R ) XMax = R;
347             if( XMin > L ) XMin = L;
348             if( YMax < YC ) YMax = YC;
349             if( YMin > YC ) YMin = YC;
350         }
351
352         for( k = 0; k < 3; k++ )
353         {
354             dir = data[k][0];
355             img = (_Tp*)(pImage + (YC + dir) * step);
356             _Tp* img1 = (_Tp*)(pImage + YC * step);
357             mask = (_MTp*)(pMask + (YC + dir) * maskStep);
358             int left = data[k][1];
359             int right = data[k][2];
360
361             if( fixedRange )
362                 for( i = left; i <= right; i++ )
363                 {
364                     if( !mask[i] && diff( img + i, &val0 ))
365                     {
366                         int j = i;
367                         mask[i] = newMaskVal;
368                         while( !mask[--j] && diff( img + j, &val0 ))
369                             mask[j] = newMaskVal;
370
371                         while( !mask[++i] && diff( img + i, &val0 ))
372                             mask[i] = newMaskVal;
373
374                         ICV_PUSH( YC + dir, j+1, i-1, L, R, -dir );
375                     }
376                 }
377             else if( !_8_connectivity )
378                 for( i = left; i <= right; i++ )
379                 {
380                     if( !mask[i] && diff( img + i, img1 + i ))
381                     {
382                         int j = i;
383                         mask[i] = newMaskVal;
384                         while( !mask[--j] && diff( img + j, img + (j+1) ))
385                             mask[j] = newMaskVal;
386
387                         while( !mask[++i] &&
388                               (diff( img + i, img + (i-1) ) ||
389                                (diff( img + i, img1 + i) && i <= R)))
390                             mask[i] = newMaskVal;
391
392                         ICV_PUSH( YC + dir, j+1, i-1, L, R, -dir );
393                     }
394                 }
395             else
396                 for( i = left; i <= right; i++ )
397                 {
398                     int idx;
399                     _Tp val;
400
401                     if( !mask[i] &&
402                        (((val = img[i],
403                           (unsigned)(idx = i-L-1) <= length) &&
404                          diff( &val, img1 + (i-1))) ||
405                         ((unsigned)(++idx) <= length &&
406                          diff( &val, img1 + i )) ||
407                         ((unsigned)(++idx) <= length &&
408                          diff( &val, img1 + (i+1) ))))
409                     {
410                         int j = i;
411                         mask[i] = newMaskVal;
412                         while( !mask[--j] && diff( img + j, img + (j+1) ))
413                             mask[j] = newMaskVal;
414
415                         while( !mask[++i] &&
416                               ((val = img[i],
417                                 diff( &val, img + (i-1) )) ||
418                                (((unsigned)(idx = i-L-1) <= length &&
419                                  diff( &val, img1 + (i-1) ))) ||
420                                ((unsigned)(++idx) <= length &&
421                                 diff( &val, img1 + i )) ||
422                                ((unsigned)(++idx) <= length &&
423                                 diff( &val, img1 + (i+1) ))))
424                             mask[i] = newMaskVal;
425
426                         ICV_PUSH( YC + dir, j+1, i-1, L, R, -dir );
427                     }
428                 }
429         }
430
431         img = (_Tp*)(pImage + YC * step);
432         if( fillImage )
433             for( i = L; i <= R; i++ )
434                 img[i] = newVal;
435         /*else if( region )
436          for( i = L; i <= R; i++ )
437          sum += img[i];*/
438     }
439
440     if( region )
441     {
442         region->pt = seed;
443         region->label = saturate_cast<int>(newMaskVal);
444         region->area = area;
445         region->rect.x = XMin;
446         region->rect.y = YMin;
447         region->rect.width = XMax - XMin + 1;
448         region->rect.height = YMax - YMin + 1;
449     }
450 }
451
452 }
453
454 /****************************************************************************************\
455 *                                    External Functions                                  *
456 \****************************************************************************************/
457
458 int cv::floodFill( InputOutputArray _image, InputOutputArray _mask,
459                   Point seedPoint, Scalar newVal, Rect* rect,
460                   Scalar loDiff, Scalar upDiff, int flags )
461 {
462     ConnectedComp comp;
463     std::vector<FFillSegment> buffer;
464
465     if( rect )
466         *rect = Rect();
467
468     int i, connectivity = flags & 255;
469     union {
470         uchar b[4];
471         int i[4];
472         float f[4];
473         double _[4];
474     } nv_buf;
475     nv_buf._[0] = nv_buf._[1] = nv_buf._[2] = nv_buf._[3] = 0;
476
477     struct { Vec3b b; Vec3i i; Vec3f f; } ld_buf, ud_buf;
478     Mat img = _image.getMat(), mask;
479     if( !_mask.empty() )
480         mask = _mask.getMat();
481     Size size = img.size();
482
483     int type = img.type();
484     int depth = img.depth();
485     int cn = img.channels();
486
487     if( connectivity == 0 )
488         connectivity = 4;
489     else if( connectivity != 4 && connectivity != 8 )
490         CV_Error( CV_StsBadFlag, "Connectivity must be 4, 0(=4) or 8" );
491
492     bool is_simple = mask.empty() && (flags & FLOODFILL_MASK_ONLY) == 0;
493
494     for( i = 0; i < cn; i++ )
495     {
496         if( loDiff[i] < 0 || upDiff[i] < 0 )
497             CV_Error( CV_StsBadArg, "lo_diff and up_diff must be non-negative" );
498         is_simple = is_simple && fabs(loDiff[i]) < DBL_EPSILON && fabs(upDiff[i]) < DBL_EPSILON;
499     }
500
501     if( (unsigned)seedPoint.x >= (unsigned)size.width ||
502        (unsigned)seedPoint.y >= (unsigned)size.height )
503         CV_Error( CV_StsOutOfRange, "Seed point is outside of image" );
504
505     scalarToRawData( newVal, &nv_buf, type, 0);
506     size_t buffer_size = MAX( size.width, size.height ) * 2;
507     buffer.resize( buffer_size );
508
509     if( is_simple )
510     {
511         size_t elem_size = img.elemSize();
512         const uchar* seed_ptr = img.ptr(seedPoint.y) + elem_size*seedPoint.x;
513
514         size_t k = 0;
515         for(; k < elem_size; k++)
516             if (seed_ptr[k] != nv_buf.b[k])
517                 break;
518
519         if( k != elem_size )
520         {
521             if( type == CV_8UC1 )
522                 floodFill_CnIR(img, seedPoint, nv_buf.b[0], &comp, flags, &buffer);
523             else if( type == CV_8UC3 )
524                 floodFill_CnIR(img, seedPoint, Vec3b(nv_buf.b), &comp, flags, &buffer);
525             else if( type == CV_32SC1 )
526                 floodFill_CnIR(img, seedPoint, nv_buf.i[0], &comp, flags, &buffer);
527             else if( type == CV_32FC1 )
528                 floodFill_CnIR(img, seedPoint, nv_buf.f[0], &comp, flags, &buffer);
529             else if( type == CV_32SC3 )
530                 floodFill_CnIR(img, seedPoint, Vec3i(nv_buf.i), &comp, flags, &buffer);
531             else if( type == CV_32FC3 )
532                 floodFill_CnIR(img, seedPoint, Vec3f(nv_buf.f), &comp, flags, &buffer);
533             else
534                 CV_Error( CV_StsUnsupportedFormat, "" );
535             if( rect )
536                 *rect = comp.rect;
537             return comp.area;
538         }
539     }
540
541     if( mask.empty() )
542     {
543         Mat tempMask( size.height + 2, size.width + 2, CV_8UC1 );
544         tempMask.setTo(Scalar::all(0));
545         mask = tempMask;
546     }
547     else
548     {
549         CV_Assert( mask.rows == size.height+2 && mask.cols == size.width+2 );
550         CV_Assert( mask.type() == CV_8U );
551     }
552
553     memset( mask.ptr(), 1, mask.cols );
554     memset( mask.ptr(mask.rows-1), 1, mask.cols );
555
556     for( i = 1; i <= size.height; i++ )
557     {
558         mask.at<uchar>(i, 0) = mask.at<uchar>(i, mask.cols-1) = (uchar)1;
559     }
560
561     if( depth == CV_8U )
562         for( i = 0; i < cn; i++ )
563         {
564             ld_buf.b[i] = saturate_cast<uchar>(cvFloor(loDiff[i]));
565             ud_buf.b[i] = saturate_cast<uchar>(cvFloor(upDiff[i]));
566         }
567     else if( depth == CV_32S )
568         for( i = 0; i < cn; i++ )
569         {
570             ld_buf.i[i] = cvFloor(loDiff[i]);
571             ud_buf.i[i] = cvFloor(upDiff[i]);
572         }
573     else if( depth == CV_32F )
574         for( i = 0; i < cn; i++ )
575         {
576             ld_buf.f[i] = (float)loDiff[i];
577             ud_buf.f[i] = (float)upDiff[i];
578         }
579     else
580         CV_Error( CV_StsUnsupportedFormat, "" );
581
582     uchar newMaskVal = (uchar)((flags & ~0xff) == 0 ? 1 : ((flags >> 8) & 255));
583
584     if( type == CV_8UC1 )
585         floodFillGrad_CnIR<uchar, uchar, int, Diff8uC1>(
586                 img, mask, seedPoint, nv_buf.b[0], newMaskVal,
587                 Diff8uC1(ld_buf.b[0], ud_buf.b[0]),
588                 &comp, flags, &buffer);
589     else if( type == CV_8UC3 )
590         floodFillGrad_CnIR<Vec3b, uchar, Vec3i, Diff8uC3>(
591                 img, mask, seedPoint, Vec3b(nv_buf.b), newMaskVal,
592                 Diff8uC3(ld_buf.b, ud_buf.b),
593                 &comp, flags, &buffer);
594     else if( type == CV_32SC1 )
595         floodFillGrad_CnIR<int, uchar, int, Diff32sC1>(
596                 img, mask, seedPoint, nv_buf.i[0], newMaskVal,
597                 Diff32sC1(ld_buf.i[0], ud_buf.i[0]),
598                 &comp, flags, &buffer);
599     else if( type == CV_32SC3 )
600         floodFillGrad_CnIR<Vec3i, uchar, Vec3i, Diff32sC3>(
601                 img, mask, seedPoint, Vec3i(nv_buf.i), newMaskVal,
602                 Diff32sC3(ld_buf.i, ud_buf.i),
603                 &comp, flags, &buffer);
604     else if( type == CV_32FC1 )
605         floodFillGrad_CnIR<float, uchar, float, Diff32fC1>(
606                 img, mask, seedPoint, nv_buf.f[0], newMaskVal,
607                 Diff32fC1(ld_buf.f[0], ud_buf.f[0]),
608                 &comp, flags, &buffer);
609     else if( type == CV_32FC3 )
610         floodFillGrad_CnIR<Vec3f, uchar, Vec3f, Diff32fC3>(
611                 img, mask, seedPoint, Vec3f(nv_buf.f), newMaskVal,
612                 Diff32fC3(ld_buf.f, ud_buf.f),
613                 &comp, flags, &buffer);
614     else
615         CV_Error(CV_StsUnsupportedFormat, "");
616
617     if( rect )
618         *rect = comp.rect;
619     return comp.area;
620 }
621
622
623 int cv::floodFill( InputOutputArray _image, Point seedPoint,
624                   Scalar newVal, Rect* rect,
625                   Scalar loDiff, Scalar upDiff, int flags )
626 {
627     return floodFill(_image, Mat(), seedPoint, newVal, rect, loDiff, upDiff, flags);
628 }
629
630
631 CV_IMPL void
632 cvFloodFill( CvArr* arr, CvPoint seed_point,
633              CvScalar newVal, CvScalar lo_diff, CvScalar up_diff,
634              CvConnectedComp* comp, int flags, CvArr* maskarr )
635 {
636     if( comp )
637         memset( comp, 0, sizeof(*comp) );
638
639     cv::Mat img = cv::cvarrToMat(arr), mask = cv::cvarrToMat(maskarr);
640     int area = cv::floodFill(img, mask, seed_point, newVal,
641                              comp ? (cv::Rect*)&comp->rect : 0,
642                              lo_diff, up_diff, flags );
643     if( comp )
644     {
645         comp->area = area;
646         comp->value = newVal;
647     }
648 }
649
650 /* End of file. */