icub-basic-demos
cvfloodfill2.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 // Intel License Agreement
11 // For Open Source Computer Vision Library
12 //
13 // Copyright (C) 2000, Intel Corporation, all rights reserved.
14 // Third party copyrights are property of their respective owners.
15 //
16 // Redistribution and use in source and binary forms, with or without modification,
17 // are permitted provided that the following conditions are met:
18 //
19 // * Redistribution's of source code must retain the above copyright notice,
20 // this list of conditions and the following disclaimer.
21 //
22 // * Redistribution's in binary form must reproduce the above copyright notice,
23 // this list of conditions and the following disclaimer in the documentation
24 // and/or other materials provided with the distribution.
25 //
26 // * The name of Intel Corporation may not be used to endorse or promote products
27 // derived from this software without specific prior written permission.
28 //
29 // This software is provided by the copyright holders and contributors "as is" and
30 // any express or implied warranties, including, but not limited to, the implied
31 // warranties of merchantability and fitness for a particular purpose are disclaimed.
32 // In no event shall the Intel Corporation or contributors be liable for any direct,
33 // indirect, incidental, special, exemplary, or consequential damages
34 // (including, but not limited to, procurement of substitute goods or services;
35 // loss of use, data, or profits; or business interruption) however caused
36 // and on any theory of liability, whether in contract, strict liability,
37 // or tort (including negligence or otherwise) arising in any way out of
38 // the use of this software, even if advised of the possibility of such damage.
39 //
40 //M*/
41 
42 /*
43  * Notes:
44  * This code is part of the OpenCV library, with a couple of changes marked with the comments "//martim".
45  * A slight change was made in the threshold criteria of the floodfill algorithm.
46  *
47  * Author of changes: Martim Brandao
48  *
49  */
50 
51 #include <opencv2/opencv.hpp>
52 #include <opencv2/core/types_c.h>
53 #include <opencv2/imgproc/imgproc_c.h>
54 
55 #ifndef __BEGIN__
56 #define __BEGIN__ __CV_BEGIN__
57 #endif
58 
59 #ifndef __END__
60 #define __END__ __CV_END__
61 #endif
62 
63 #ifndef EXIT
64 #define EXIT __CV_EXIT__
65 #endif
66 
67 typedef struct CvFFillSegment
68 {
69  ushort y;
70  ushort l;
71  ushort r;
72  ushort prevl;
73  ushort prevr;
74  short dir;
75 }
76 CvFFillSegment;
77 
78 #define UP 1
79 #define DOWN -1
80 
81 #define ICV_PUSH( Y, L, R, PREV_L, PREV_R, DIR )\
82 { \
83  tail->y = (ushort)(Y); \
84  tail->l = (ushort)(L); \
85  tail->r = (ushort)(R); \
86  tail->prevl = (ushort)(PREV_L); \
87  tail->prevr = (ushort)(PREV_R); \
88  tail->dir = (short)(DIR); \
89  if( ++tail >= buffer_end ) \
90  tail = buffer; \
91 }
92 
93 
94 #define ICV_POP( Y, L, R, PREV_L, PREV_R, DIR ) \
95 { \
96  Y = head->y; \
97  L = head->l; \
98  R = head->r; \
99  PREV_L = head->prevl; \
100  PREV_R = head->prevr; \
101  DIR = head->dir; \
102  if( ++head >= buffer_end ) \
103  head = buffer; \
104 }
105 
106 #define DIFF_FLT_C1(p1,p2) (fabs((p1)[0] - (p2)[0] + d_lw[0]) <= interval[0])
107 
108 static void
109 icvFloodFill_Grad_32f_CnIR2( float* pImage, int step, uchar* pMask, int maskStep,
110  CvSize /*roi*/, CvPoint seed, float* _newVal, float* _d_lw,
111  float* _d_up, CvConnectedComp* region, int flags,
112  CvFFillSegment* buffer, int buffer_size, int cn )
113 {
114  float* img = pImage + (step /= sizeof(float))*seed.y;
115  uchar* mask = (pMask += maskStep + 1) + maskStep*seed.y;
116  int i, L, R;
117  int area = 0;
118  double sum[] = {0,0,0}, val0[] = {0,0,0};
119  float newVal[] = {0,0,0};
120  float d_lw[] = {0,0,0};
121  float interval[] = {0,0,0};
122  int XMin, XMax, YMin = seed.y, YMax = seed.y;
123  int _8_connectivity = (flags & 255) == 8;
124  int fixedRange = flags & CV_FLOODFILL_FIXED_RANGE;
125  int fillImage = (flags & CV_FLOODFILL_MASK_ONLY) == 0;
126  uchar newMaskVal = (uchar)(flags & 0xff00 ? flags >> 8 : 1);
127  CvFFillSegment* buffer_end = buffer + buffer_size, *head = buffer, *tail = buffer;
128  //-------------------------------------------------------------------martim
129  // variance-adaptive threshold
130  double varAdaptA=0, varAdaptB=0; //cumulative p(i) and p(i)² where p=pixel value
131  double varAdaptN=0; //N(i) where N=number of pixels
132  double varAdaptAlpha=0.9; //weight on current threshold (0<alpha<1)
133  double varAdaptK=0.5; //sauvola's weight on the standard deviance component (0.2<=k<=0.5)
134  double varAdaptKa=1.5; //alex's weight on the standard deviance component (ka~1)
135  double varAdapt_aux=0;
136  if( cn!=1 ) return;
137  //--end
138 
139  L = R = seed.x;
140  if( mask[L] )
141  return;
142 
143  mask[L] = newMaskVal;
144 
145  for( i = 0; i < cn; i++ )
146  {
147  newVal[i] = _newVal[i];
148  d_lw[i] = 0.5f*(_d_lw[i] - _d_up[i]);
149  interval[i] = 0.5f*(_d_lw[i] + _d_up[i]);
150  if( fixedRange )
151  val0[i] = img[L*cn+i];
152  }
153 
154  if( cn == 1 )
155  {
156  if( fixedRange )
157  {
158  while( !mask[R + 1] && DIFF_FLT_C1( img + (R+1), val0 )){
159  //-------------------------------------------------------------------martim
160  // variance-adaptive threshold
161  varAdapt_aux = (img+ R+1)[0];
162  varAdaptA += varAdapt_aux;
163  varAdaptB += varAdapt_aux*varAdapt_aux;
164  varAdaptN++;
165  //Sauvola:
166  varAdapt_aux = sqrt( varAdaptB/varAdaptN - (varAdaptA*varAdaptA/(varAdaptN*varAdaptN)) );
167  varAdapt_aux = val0[0] - (varAdaptA/varAdaptN)*( 1+varAdaptK*((varAdapt_aux/128)-1) );
168  interval[0] = (float)(varAdaptAlpha*interval[0] + (1-varAdaptAlpha)*varAdapt_aux);
169  //Alex:
170 // varAdapt_aux = val0[0] - (varAdaptA/varAdaptN) + varAdaptKa*varAdapt_aux;
171 // interval[0] = varAdaptAlpha*interval[0] + (1-varAdaptAlpha)*varAdapt_aux;
172  mask[++R] = newMaskVal;
173  //--end
174  }
175 
176  while( !mask[L - 1] && DIFF_FLT_C1( img + (L-1), val0 )){
177  //-------------------------------------------------------------------martim
178  // variance-adaptive threshold
179  varAdapt_aux = (img+ L-1)[0];
180  varAdaptA += varAdapt_aux;
181  varAdaptB += varAdapt_aux*varAdapt_aux;
182  varAdaptN++;
183  //Sauvola:
184  varAdapt_aux = sqrt( varAdaptB/varAdaptN - (varAdaptA*varAdaptA/(varAdaptN*varAdaptN)) );
185  varAdapt_aux = val0[0] - (varAdaptA/varAdaptN)*( 1+varAdaptK*((varAdapt_aux/128)-1) );
186  interval[0] = (float)(varAdaptAlpha*interval[0] + (1-varAdaptAlpha)*varAdapt_aux);
187  //Alex:
188 // varAdapt_aux = val0[0] - (varAdaptA/varAdaptN) + varAdaptKa*varAdapt_aux;
189 // interval[0] = varAdaptAlpha*interval[0] + (1-varAdaptAlpha)*varAdapt_aux;
190  mask[--L] = newMaskVal;
191  //--end
192  }
193  }
194  else
195  {
196  while( !mask[R + 1] && DIFF_FLT_C1( img + (R+1), img + R ))
197  mask[++R] = newMaskVal;
198 
199  while( !mask[L - 1] && DIFF_FLT_C1( img + (L-1), img + L ))
200  mask[--L] = newMaskVal;
201  }
202  }
203 
204  XMax = R;
205  XMin = L;
206  ICV_PUSH( seed.y, L, R, R + 1, R, UP );
207 
208  while( head != tail )
209  {
210  int k, YC, PL, PR, dir, curstep;
211  ICV_POP( YC, L, R, PL, PR, dir );
212 
213  int data[][3] =
214  {
215  {-dir, L - _8_connectivity, R + _8_connectivity},
216  {dir, L - _8_connectivity, PL - 1},
217  {dir, PR + 1, R + _8_connectivity}
218  };
219 
220  unsigned length = (unsigned)(R-L);
221 
222  if( region )
223  {
224  area += (int)length + 1;
225 
226  if( XMax < R ) XMax = R;
227  if( XMin > L ) XMin = L;
228  if( YMax < YC ) YMax = YC;
229  if( YMin > YC ) YMin = YC;
230  }
231 
232  if( cn == 1 )
233  {
234  for( k = 0; k < 3; k++ )
235  {
236  dir = data[k][0];
237  curstep = dir * step;
238  img = pImage + (YC + dir) * step;
239  mask = pMask + (YC + dir) * maskStep;
240  int left = data[k][1];
241  int right = data[k][2];
242 
243  if( fixedRange )
244  //-------------------------------------------------------------------martim
245  // variance-adaptive threshold
246  for( i = left; i <= right; i++ )
247  {
248  if( !mask[i] && DIFF_FLT_C1( img + i, val0 ))
249  {
250  int j = i;
251  mask[i] = newMaskVal;
252  while( !mask[--j] && DIFF_FLT_C1( img + j, val0 )){
253  mask[j] = newMaskVal;
254  varAdapt_aux = (img+j)[0];
255  varAdaptA += varAdapt_aux;
256  varAdaptB += varAdapt_aux*varAdapt_aux;
257  varAdaptN++;
258  //Sauvola:
259  varAdapt_aux = sqrt( varAdaptB/varAdaptN - (varAdaptA*varAdaptA/(varAdaptN*varAdaptN)) );
260  varAdapt_aux = val0[0] - (varAdaptA/varAdaptN)*( 1+varAdaptK*((varAdapt_aux/128)-1) );
261  interval[0] = (float)(varAdaptAlpha*interval[0] + (1-varAdaptAlpha)*varAdapt_aux);
262  //Alex:
263 // varAdapt_aux = val0[0] - (varAdaptA/varAdaptN) + varAdaptKa*varAdapt_aux;
264 // interval[0] = varAdaptAlpha*interval[0] + (1-varAdaptAlpha)*varAdapt_aux;
265  }
266 
267  while( !mask[++i] && DIFF_FLT_C1( img + i, val0 )){
268  mask[i] = newMaskVal;
269  varAdapt_aux = (img+i)[0];
270  varAdaptA += varAdapt_aux;
271  varAdaptB += varAdapt_aux*varAdapt_aux;
272  varAdaptN++;
273  //Sauvola:
274  varAdapt_aux = sqrt( varAdaptB/varAdaptN - (varAdaptA*varAdaptA/(varAdaptN*varAdaptN)) );
275  varAdapt_aux = val0[0] - (varAdaptA/varAdaptN)*( 1+varAdaptK*((varAdapt_aux/128)-1) );
276  interval[0] = (float)(varAdaptAlpha*interval[0] + (1-varAdaptAlpha)*varAdapt_aux);
277  //Alex:
278 // varAdapt_aux = val0[0] - (varAdaptA/varAdaptN) + varAdaptKa*varAdapt_aux;
279 // interval[0] = varAdaptAlpha*interval[0] + (1-varAdaptAlpha)*varAdapt_aux;
280  }
281 
282  ICV_PUSH( YC + dir, j+1, i-1, L, R, -dir );
283  }
284  }
285  //--end
286  else if( !_8_connectivity )
287  for( i = left; i <= right; i++ )
288  {
289  if( !mask[i] && DIFF_FLT_C1( img + i, img - curstep + i ))
290  {
291  int j = i;
292  mask[i] = newMaskVal;
293  while( !mask[--j] && DIFF_FLT_C1( img + j, img + (j+1) ))
294  mask[j] = newMaskVal;
295 
296  while( !mask[++i] &&
297  (DIFF_FLT_C1( img + i, img + (i-1) ) ||
298  (DIFF_FLT_C1( img + i, img + i - curstep) && i <= R)))
299  mask[i] = newMaskVal;
300 
301  ICV_PUSH( YC + dir, j+1, i-1, L, R, -dir );
302  }
303  }
304  else
305  for( i = left; i <= right; i++ )
306  {
307  int idx;
308  float val[1];
309 
310  if( !mask[i] &&
311  (((val[0] = img[i],
312  (unsigned)(idx = i-L-1) <= length) &&
313  DIFF_FLT_C1( val, img - curstep + (i-1) )) ||
314  ((unsigned)(++idx) <= length &&
315  DIFF_FLT_C1( val, img - curstep + i )) ||
316  ((unsigned)(++idx) <= length &&
317  DIFF_FLT_C1( val, img - curstep + (i+1) ))))
318  {
319  int j = i;
320  mask[i] = newMaskVal;
321  while( !mask[--j] && DIFF_FLT_C1( img + j, img + (j+1) ))
322  mask[j] = newMaskVal;
323 
324  while( !mask[++i] &&
325  ((val[0] = img[i],
326  DIFF_FLT_C1( val, img + (i-1) )) ||
327  (((unsigned)(idx = i-L-1) <= length &&
328  DIFF_FLT_C1( val, img - curstep + (i-1) ))) ||
329  ((unsigned)(++idx) <= length &&
330  DIFF_FLT_C1( val, img - curstep + i )) ||
331  ((unsigned)(++idx) <= length &&
332  DIFF_FLT_C1( val, img - curstep + (i+1) ))))
333  mask[i] = newMaskVal;
334 
335  ICV_PUSH( YC + dir, j+1, i-1, L, R, -dir );
336  }
337  }
338  }
339 
340  img = pImage + YC * step;
341  if( fillImage )
342  for( i = L; i <= R; i++ )
343  img[i] = newVal[0];
344  else if( region )
345  for( i = L; i <= R; i++ )
346  sum[0] += img[i];
347  }
348  }
349 
350  if( region )
351  {
352  region->area = area;
353  region->rect.x = XMin;
354  region->rect.y = YMin;
355  region->rect.width = XMax - XMin + 1;
356  region->rect.height = YMax - YMin + 1;
357 
358  if( fillImage )
359  region->value = cvScalar(newVal[0], newVal[1], newVal[2]);
360  else
361  {
362  double iarea = area ? 1./area : 0;
363  region->value = cvScalar(sum[0]*iarea, sum[1]*iarea, sum[2]*iarea);
364  }
365  }
366 
367 // printf("Tf=%.4f, avg=%.4f, sigma=%.4f\n", interval[0], varAdaptA/varAdaptN, sqrt(varAdaptB/varAdaptN-(varAdaptA*varAdaptA/(varAdaptN*varAdaptN))) );
368 // printf("----------end floodfill\n");
369 
370  return;
371 }
372 
373 typedef void (*CvFloodFillFunc2)(
374  void* img, int step, CvSize size, CvPoint seed, void* newval,
375  CvConnectedComp* comp, int flags, void* buffer, int buffer_size, int cn );
376 
377 typedef void (*CvFloodFillGradFunc2)(
378  void* img, int step, uchar* mask, int maskStep, CvSize size,
379  CvPoint seed, void* newval, void* d_lw, void* d_up, void* ccomp,
380  int flags, void* buffer, int buffer_size, int cn );
381 
382 
383 static void icvInitFloodFill( void** ffill_tab, void** ffillgrad_tab )
384 {
385  ffill_tab[0] = NULL; //(void*)icvFloodFill_8u_CnIR2;
386  ffill_tab[1] = NULL; //(void*)icvFloodFill_32f_CnIR2;
387 
388  ffillgrad_tab[0] = NULL; //(void*)icvFloodFill_Grad_8u_CnIR2;
389  ffillgrad_tab[1] = (void*)icvFloodFill_Grad_32f_CnIR2;
390 }
391 
392 
393 void
394 cvFloodFill2( CvArr* arr, CvPoint seed_point,
395  CvScalar newVal, CvScalar lo_diff, CvScalar up_diff,
396  CvConnectedComp* comp, int flags, CvArr* maskarr )
397 {
398  static void* ffill_tab[4];
399  static void* ffillgrad_tab[4];
400  static int inittab = 0;
401 
402  CvMat* tempMask = 0;
403  CvFFillSegment* buffer = 0;
404  CV_FUNCNAME( "cvFloodFill" );
405 
406  if( comp )
407  memset( comp, 0, sizeof(*comp) );
408 
409  __BEGIN__;
410 
411  int i, type, depth, cn, is_simple, idx;
412  int buffer_size, connectivity = flags & 255;
413  double nv_buf[4] = {0,0,0,0};
414  union { uchar b[4]; float f[4]; } ld_buf, ud_buf;
415  CvMat stub, *img = (CvMat*)arr;
416  CvMat maskstub, *mask = (CvMat*)maskarr;
417  CvSize size;
418 
419  if( !inittab )
420  {
421  icvInitFloodFill( ffill_tab, ffillgrad_tab );
422  inittab = 1;
423  }
424 
425  CV_CALL( img = cvGetMat( img, &stub ));
426  type = CV_MAT_TYPE( img->type );
427  depth = CV_MAT_DEPTH(type);
428  cn = CV_MAT_CN(type);
429 
430  idx = type == CV_8UC1 || type == CV_8UC3 ? 0 :
431  type == CV_32FC1 || type == CV_32FC3 ? 1 : -1;
432 
433  if( idx < 0 )
434  CV_ERROR( CV_StsUnsupportedFormat, "" );
435 
436  if( connectivity == 0 )
437  connectivity = 4;
438  else if( connectivity != 4 && connectivity != 8 )
439  CV_ERROR( CV_StsBadFlag, "Connectivity must be 4, 0(=4) or 8" );
440 
441  is_simple = mask == 0 && (flags & CV_FLOODFILL_MASK_ONLY) == 0;
442 
443  for( i = 0; i < cn; i++ )
444  {
445  if( lo_diff.val[i] < 0 || up_diff.val[i] < 0 )
446  CV_ERROR( CV_StsBadArg, "lo_diff and up_diff must be non-negative" );
447  is_simple &= fabs(lo_diff.val[i]) < DBL_EPSILON && fabs(up_diff.val[i]) < DBL_EPSILON;
448  }
449 
450  if( (unsigned)seed_point.x >= (unsigned)size.width ||
451  (unsigned)seed_point.y >= (unsigned)size.height )
452  CV_ERROR( CV_StsOutOfRange, "Seed point is outside of image" );
453 
454  cvScalarToRawData( &newVal, &nv_buf, type, 0 );
455  buffer_size = MAX( size.width, size.height )*2;
456  CV_CALL( buffer = (CvFFillSegment*)cvAlloc( buffer_size*sizeof(buffer[0])));
457 
458  if( is_simple )
459  {
460  int elem_size = CV_ELEM_SIZE(type);
461  const uchar* seed_ptr = img->data.ptr + img->step*seed_point.y + elem_size*seed_point.x;
462  CvFloodFillFunc2 func = (CvFloodFillFunc2)ffill_tab[idx];
463  if( !func )
464  CV_ERROR( CV_StsUnsupportedFormat, "" );
465  // check if the new value is different from the current value at the seed point.
466  // if they are exactly the same, use the generic version with mask to avoid infinite loops.
467  for( i = 0; i < elem_size; i++ )
468  if( seed_ptr[i] != ((uchar*)nv_buf)[i] )
469  break;
470  if( i < elem_size )
471  {
472  func( img->data.ptr, img->step, size,
473  seed_point, &nv_buf, comp, flags,
474  buffer, buffer_size, cn );
475  EXIT;
476  }
477  }
478 
479  {
480  CvFloodFillGradFunc2 func = (CvFloodFillGradFunc2)ffillgrad_tab[idx];
481  if( !func )
482  CV_ERROR( CV_StsUnsupportedFormat, "" );
483 
484  if( !mask )
485  {
486  /* created mask will be 8-byte aligned */
487  tempMask = cvCreateMat( size.height + 2, (size.width + 9) & -8, CV_8UC1 );
488  mask = tempMask;
489  }
490  else
491  {
492  CV_CALL( mask = cvGetMat( mask, &maskstub ));
493  if( !CV_IS_MASK_ARR( mask ))
494  CV_ERROR( CV_StsBadMask, "" );
495 
496  if( mask->width != size.width + 2 || mask->height != size.height + 2 )
497  CV_ERROR( CV_StsUnmatchedSizes, "mask must be 2 pixel wider "
498  "and 2 pixel taller than filled image" );
499  }
500 
501  {
502  int width = tempMask ? mask->step : size.width + 2;
503  uchar* mask_row = mask->data.ptr + mask->step;
504  memset( mask_row - mask->step, 1, width );
505 
506  for( i = 1; i <= size.height; i++, mask_row += mask->step )
507  {
508  if( tempMask )
509  memset( mask_row, 0, width );
510  mask_row[0] = mask_row[size.width+1] = (uchar)1;
511  }
512  memset( mask_row, 1, width );
513  }
514 
515  if( depth == CV_8U )
516  for( i = 0; i < cn; i++ )
517  {
518  ld_buf.b[i] = cv::saturate_cast<uchar>(cvFloor(lo_diff.val[i]));
519  ud_buf.b[i] = cv::saturate_cast<uchar>(cvFloor(up_diff.val[i]));
520  }
521  else
522  for( i = 0; i < cn; i++ )
523  {
524  ld_buf.f[i] = (float)lo_diff.val[i];
525  ud_buf.f[i] = (float)up_diff.val[i];
526  }
527 
528  func( img->data.ptr, img->step, mask->data.ptr, mask->step,
529  size, seed_point, &nv_buf, ld_buf.f, ud_buf.f,
530  comp, flags, buffer, buffer_size, cn );
531  }
532 
533  __END__;
534 
535  cvFree( &buffer );
536  cvReleaseMat( &tempMask );
537 }