TuttleOFX  1
floodFill.hpp
Go to the documentation of this file.
00001 #ifndef _TERRY_FILTER_FLOODFILL_HPP_
00002 #define _TERRY_FILTER_FLOODFILL_HPP_
00003 
00004 #include <terry/globals.hpp>
00005 #include <terry/draw/fill.hpp>
00006 #include <terry/basic_colors.hpp>
00007 #include <terry/channel.hpp>
00008 #include <terry/math/Rect.hpp>
00009 #include <terry/numeric/minmax.hpp>
00010 #include <terry/algorithm/transform_pixels.hpp>
00011 
00012 #include <queue>
00013 #include <list>
00014 
00015 
00016 namespace terry {
00017 namespace filter {
00018 namespace floodFill {
00019 
00020 /**
00021  * @brief fill all pixels respecting the @p condition in a range of pixels (on the same line or with an 1d_traversable image).
00022  */
00023 template<class SIterator, class DIterator, class DPixel, class Test>
00024 GIL_FORCEINLINE
00025 void fill_pixels_range_if( SIterator srcBegin, const SIterator& srcEnd,
00026                     DIterator dstBegin, const DPixel& value,
00027                     const Test& condition )
00028 {
00029         do
00030         {
00031                 if( condition( (*srcBegin)[0] ) )
00032                 {
00033 #ifdef TERRY_DEBUG_FLOODFILL
00034                         if( (*dstBegin)[0] != value[0] )
00035                         {
00036                                 *dstBegin = value;
00037                         }
00038 #else
00039                         *dstBegin = value;
00040 #endif
00041                 }
00042                 ++srcBegin;
00043                 ++dstBegin;
00044         }
00045         while( srcBegin != srcEnd );
00046 }
00047 
00048 struct Connexity4
00049 {
00050         static const std::ssize_t x = 0;
00051 };
00052 
00053 struct Connexity8
00054 {
00055         static const std::ssize_t x = 1;
00056 };
00057 
00058 template<typename T>
00059 struct IsUpper
00060 {
00061         const T _threshold;
00062         IsUpper( const T& threshold )
00063         : _threshold(threshold)
00064         {}
00065         GIL_FORCEINLINE
00066         bool operator()( const T& p ) const
00067         {
00068                 return (p >= _threshold);
00069         }
00070 };
00071 
00072 
00073 typedef enum
00074 {
00075         eDirectionAbove = 0,
00076         eDirectionBellow = 1
00077 } EDirection;
00078 
00079 GIL_FORCEINLINE
00080 EDirection invertDirection( const EDirection d )
00081 {
00082         return d == eDirectionAbove ? eDirectionBellow : eDirectionAbove;
00083 }
00084 
00085 /**
00086  * @brief A range of pixels in a line to propagate.
00087  */
00088 template<class SView, class DView>
00089 struct FloodElement
00090 {
00091         typedef typename SView::xy_locator SLocator;
00092         typedef typename DView::xy_locator DLocator;
00093         typedef typename SView::value_type SPixel;
00094         typedef typename DView::value_type DPixel;
00095 
00096         SLocator _srcBegin; //< locator on the first pixel of the source image of the range to propagate
00097         SLocator _srcEnd;   //< like end() in the stl, this is the pixel after the last pixel of the range
00098         DLocator _dstBegin; //< locator on the first pixel of the dest image
00099         std::ssize_t _xBegin; //< x coordinate of the first pixel
00100         std::ssize_t _xEnd; //< x coordinate of the pixel after the last pixel of the range
00101         std::ssize_t _y; //< y coordinate
00102         EDirection _direction; //< the direction of the propagation to apply
00103 };
00104 
00105 /**
00106  * @brief Flood fill an image, with 2 conditions.
00107  * Fill all pixels respecting the soft condition if connected with a pixel respecting the strong condition.
00108  *
00109  * @param[in] srcView input image
00110  * @param[in] srcRod input image ROD
00111  * @param[out] dstView input image
00112  * @param[in] dstRod output image ROD
00113  * @param[in] procWindow region to process
00114  * @param[in] strongCondition functor with the strong test
00115  * @param[in] softCondition functor with the soft test
00116  *
00117  * @remark Implementation is based on standard filling algorithms. So we use ranges by line (x axis),
00118  * and check connections between these x ranges and possible x ranges in the above or bellow lines.
00119  */
00120 template<class Connexity, class StrongTest, class SoftTest, class SView, class DView, template<class> class Allocator>
00121 void flood_fill( const SView& srcView, const Rect<std::ssize_t>& srcRod,
00122                  DView& dstView, const Rect<std::ssize_t>& dstRod,
00123                                  const Rect<std::ssize_t>& procWindow,
00124                                  const StrongTest& strongTest, const SoftTest& softTest )
00125 {
00126         using namespace terry;
00127         using namespace terry::draw;
00128         typedef typename SView::xy_locator SLocator;
00129         typedef typename DView::xy_locator DLocator;
00130         typedef typename SView::value_type SPixel;
00131         typedef typename DView::value_type DPixel;
00132         typedef typename boost::gil::channel_type<SPixel>::type SChannel;
00133         typedef typename terry::channel_base_type<SChannel>::type SType;
00134         typedef typename SLocator::cached_location_t SCachedLocation;
00135         typedef typename DLocator::cached_location_t DCachedLocation;
00136 
00137         typedef FloodElement<SView, DView> FloodElem;
00138 
00139         static const DPixel white = get_white<DPixel>();
00140 
00141 #ifdef TERRY_DEBUG_FLOODFILL
00142         DPixel red = get_black<DPixel>();
00143         red[0] = 1.0;
00144         DPixel yellow = get_black<DPixel>();
00145         yellow[0] = 1.0;
00146         yellow[1] = 1.0;
00147 #endif
00148         
00149         const Rect<std::ssize_t> rod = rectanglesIntersection( srcRod, dstRod );
00150 
00151         const std::size_t procWidth = (procWindow.x2 - procWindow.x1);
00152         const std::size_t halfProcWidth = procWidth / 2;
00153 
00154         const SLocator sloc_ref( srcView.xy_at(0,0) );
00155         const SLocator dloc_ref( dstView.xy_at(0,0) );
00156 
00157         std::vector<FloodElem, Allocator<FloodElem> > propagation;
00158         propagation.reserve( halfProcWidth );
00159 
00160         SLocator src_loc = srcView.xy_at( procWindow.x1 - srcRod.x1, procWindow.y1 - srcRod.y1 );
00161         DLocator dst_loc = dstView.xy_at( procWindow.x1 - dstRod.x1, procWindow.y1 - dstRod.y1 );
00162 
00163 //      // LT CT RT
00164 //      // LC    RC
00165 //      // LB CB RB
00166 //      const SCachedLocation sLT( src_loc.cache_location(-Connectivity::x,-1) );
00167 //      const SCachedLocation sRT( src_loc.cache_location( Connectivity::x,-1) );
00168 //      const SCachedLocation sLB( src_loc.cache_location(-Connectivity::x, 1) );
00169 //      const SCachedLocation sRB( src_loc.cache_location( Connectivity::x, 1) );
00170 //
00171 //      const DCachedLocation dLT( dst_loc.cache_location(-Connectivity::x,-1) );
00172 //      const DCachedLocation dRT( dst_loc.cache_location( Connectivity::x,-1) );
00173 //      const DCachedLocation dLB( dst_loc.cache_location(-Connectivity::x, 1) );
00174 //      const DCachedLocation dRB( dst_loc.cache_location( Connectivity::x, 1) );
00175 
00176         boost::gil::point2<std::ptrdiff_t> endToBegin( -(procWindow.x2-procWindow.x1),1);
00177         boost::gil::point2<std::ptrdiff_t> nextLine(0,1);
00178         boost::gil::point2<std::ptrdiff_t> previousLine( 0,-1);
00179                 
00180         for( std::ssize_t y = procWindow.y1;
00181              y < procWindow.y2;
00182              ++y )
00183         {
00184                 {
00185                         std::size_t xLastBegin = 0;
00186                         SLocator srcLastBegin;
00187                         DLocator dstLastBegin;
00188                         bool inside = false;
00189                         bool containsStrong = false;
00190 
00191                         for( std::ssize_t x = procWindow.x1;
00192                                  x < procWindow.x2;
00193                                  ++x, ++dst_loc.x(), ++src_loc.x() )
00194                         {
00195                                 if( (*dst_loc)[0] == white[0] )
00196                                 {
00197                                         if( ! inside )
00198                                         {
00199                                                 xLastBegin = x;
00200                                                 srcLastBegin = src_loc;
00201                                                 dstLastBegin = dst_loc;
00202                                                 inside = true;
00203                                         }
00204                                         containsStrong = true;
00205                                 }
00206                                 else if( softTest( (*src_loc)[0] ) )
00207                                 {
00208                                         if( ! inside )
00209                                         {
00210                                                 xLastBegin = x;
00211                                                 srcLastBegin = src_loc;
00212                                                 dstLastBegin = dst_loc;
00213                                                 inside = true;
00214                                         }
00215                                         if( ! containsStrong )
00216                                         {
00217                                                 if( strongTest( (*src_loc)[0] ) )
00218                                                 {
00219                                                         containsStrong = true;
00220                                                 }
00221                                         }
00222                                 }
00223                                 else
00224                                 {
00225                                         // do the same thing at the end of a line
00226                                         if( /*inside &&*/ containsStrong )
00227                                         {
00228                                                 // visit line above
00229                                                 FloodElem el;
00230                                                 el._srcBegin = srcLastBegin;
00231                                                 el._srcEnd = src_loc;
00232                                                 el._dstBegin = dstLastBegin;
00233                                                 el._xBegin = xLastBegin;
00234                                                 el._xEnd = x;
00235                                                 el._y = y;
00236                                                 el._direction = eDirectionAbove;
00237                                                 propagation.push_back( el );
00238 
00239                                                 // current line
00240                                                 // fill output from first to last
00241                                                 fill_pixels_range( dstLastBegin.x(), dst_loc.x(), white );
00242 
00243                                                 // visit line bellow
00244                                                 if( y < rod.y2  )
00245                                                 {
00246         //                                              fill_range_if( srcLastBegin[sLB], src_loc[sRB], dstLastBegin[dLB], white, softTest );
00247                                                         // fill line bellow for current range if respect softTest
00248                                                         fill_pixels_range_if( srcLastBegin.x_at(-Connexity::x,1), src_loc.x_at(Connexity::x,1),
00249                                                                                    dstLastBegin.x_at(-Connexity::x,1),
00250                                                                                    white, softTest );
00251                                                 }
00252                                         }
00253                                         // re-init values
00254                                         inside = false;
00255                                         containsStrong = false;
00256                                 }
00257                         }
00258                         // if all the last pixels are a group of detected pixels
00259                         if( /*inside &&*/ containsStrong )
00260                         {
00261                                 // visit line above
00262                                 FloodElem el;
00263                                 el._srcBegin = srcLastBegin;
00264                                 el._srcEnd = src_loc;
00265                                 el._dstBegin = dstLastBegin;
00266                                 el._xBegin = xLastBegin;
00267                                 el._xEnd = procWindow.x2;
00268                                 el._y = y;
00269                                 el._direction = eDirectionAbove;
00270                                 propagation.push_back( el );
00271 
00272                                 // current line
00273                                 // fill output from first to last
00274                                 fill_pixels_range( dstLastBegin.x(), dst_loc.x(), white );
00275 
00276                                 // visit line bellow
00277                                 if( y < rod.y2  )
00278                                 {
00279                                         // fill line bellow for current range if respect softTest
00280                                         fill_pixels_range_if( srcLastBegin.x_at(-Connexity::x,1), src_loc.x_at(Connexity::x,1),
00281                                                                    dstLastBegin.x_at(-Connexity::x,1),
00282                                                                    white, softTest );
00283                                 }
00284                         }
00285                 }
00286                 // move to the beginning of the next line
00287                 dst_loc += endToBegin;
00288                 src_loc += endToBegin;
00289 
00290                 // do the propagation on the above lines
00291                 while( !propagation.empty() )
00292                 {
00293                         FloodElem iElem = propagation.back();
00294                         propagation.pop_back();
00295 
00296                         // after having been up, we can get down up to next line (at the maximum)
00297                         if( iElem._direction == eDirectionBellow &&
00298                             iElem._y > y+1 )
00299                                 continue;
00300                         if( (iElem._direction == eDirectionAbove && iElem._y < procWindow.y1 ) ||
00301                             (iElem._direction == eDirectionBellow && iElem._y >= procWindow.y2 ) )
00302                                 continue;
00303 
00304                         // i: the "input" range
00305                         // g: is the full range, where we can found f elements
00306                         // f: ranges "founded" (connected with i range)
00307                         // s: futur range to "search"
00308                         //
00309                         // first step:
00310                         // [ggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggg] // current line to apply the propagation
00311                         // [sssssssssssss].[iiiiiiiiiiiiiiiiiiiiiiiiiiii].[ssssssssssssss]
00312                         //                              ^
00313                         //                              |  direction: above
00314                         // 
00315                         // example 1:
00316                         // [sssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss] // search in the same direction
00317                         // [fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff] // current line to apply the propagation
00318                         // [sssssssssssss].[iiiiiiiiiiiiiiiiiiiiiiiiiiii].[ssssssssssssss] // search in the opposite direction
00319                         //                              ^
00320                         //                              |  direction: above
00321                         //
00322                         // example 2:
00323                         // [sssssssssssssss].....[sssss]...[sss]..[ssssssssssssssssssssss] // search in the same direction
00324                         // [fffffffffffffff].....[fffff]...[fff]..[ffffffffffffffffffffff] // current line to apply the propagation
00325                         // [sssssssssssss].[iiiiiiiiiiiiiiiiiiiiiiiiiiii].[ssssssssssssss] // search in the opposite direction
00326                         //                              ^
00327                         //                              |  direction: above
00328                         //
00329                         // example 3:
00330                         // .....................[sssss]....[sss]..[ssssssssssssssssssssss] // search in the same direction
00331                         // .....................[fffff]....[fff]..[ffffffffffffffffffffff] // current line to apply the propagation
00332                         // ................[iiiiiiiiiiiiiiiiiiiiiiiiiiii].[ssssssssssssss] // search in the opposite direction
00333                         //                              ^
00334                         //                              |  direction: above
00335 
00336                         FloodElem gElem = iElem;
00337 
00338                         if( gElem._direction == eDirectionAbove )
00339                         {
00340                                 gElem._srcBegin += previousLine;
00341                                 gElem._srcEnd   += previousLine;
00342                                 gElem._dstBegin += previousLine;
00343                                 --(gElem._y);
00344                         }
00345                         else
00346                         {
00347                                 gElem._srcBegin += nextLine;
00348                                 gElem._srcEnd   += nextLine;
00349                                 gElem._dstBegin += nextLine;
00350                                 ++(gElem._y);
00351                         }
00352 
00353                         // x propagation
00354                         // left
00355                         if( Connexity::x ||
00356                             softTest( (*gElem._srcBegin)[0] ) ) // check first
00357                         {
00358                                 while( gElem._xBegin-1 >= rod.x1 &&
00359                                            softTest( (*(gElem._srcBegin.x()-1))[0] ) )
00360                                 {
00361                                         --(gElem._xBegin);
00362                                         --(gElem._srcBegin.x());
00363                                         --(gElem._dstBegin.x());
00364                                 }
00365                         }
00366                         // right
00367                         if( Connexity::x ||
00368                             softTest( (*(gElem._srcEnd.x()-1))[0] ) ) // check last
00369                         {
00370                                 while( gElem._xEnd < rod.x2 &&
00371                                            softTest( (*gElem._srcEnd)[0] ) )
00372                                 {
00373                                         ++(gElem._xEnd);
00374                                         ++(gElem._srcEnd.x());
00375                                 }
00376                         }
00377 
00378                         // new sub-ranges
00379                         {
00380                                 bool inside = false;
00381                                 bool modified = false;
00382                                 std::list<FloodElem> localPropagation;
00383                                 FloodElem localElem = gElem;
00384                                 localElem._srcEnd = localElem._srcBegin;
00385                                 DLocator dstEnd = localElem._dstBegin;
00386 
00387                                 for( std::ssize_t xx = gElem._xBegin;
00388                                          xx < gElem._xEnd;
00389                                          ++xx )
00390                                 {
00391                                         if( softTest( (*localElem._srcEnd)[0] ) )
00392                                         {
00393                                                 if( ! inside )
00394                                                 {
00395                                                         localElem._srcBegin = localElem._srcEnd;
00396                                                         localElem._dstBegin = dstEnd;
00397                                                         localElem._xBegin = xx;
00398                                                         inside = true;
00399                                                 }
00400                                                 if( !modified )
00401                                                 {
00402                                                         if( (*dstEnd)[0] != white[0] )
00403                                                         {
00404                                                                 modified = true;
00405                                                         }
00406                                                 }
00407 #ifdef TERRY_DEBUG_FLOODFILL
00408                                                 // use one color for each case to debug
00409                                                 if( (*dstEnd)[0] != white[0] )
00410                                                 {
00411                                                         if( iElem._direction == eDirectionAbove )
00412                                                                 *dstEnd = red;
00413                                                         else
00414                                                                 *dstEnd = yellow;
00415                                                 }
00416 #else
00417                                                 *dstEnd = white;
00418 #endif
00419                                         }
00420                                         else
00421                                         {
00422                                                 if( inside )
00423                                                 {
00424                                                         localElem._xEnd = xx;
00425                                                         // if we just have modified a pixel in the output,
00426                                                         // possibly we have to propagate something
00427                                                         if( modified )
00428                                                         {
00429                                                                 // propagation in the same direction
00430                                                                 localPropagation.push_back( localElem );
00431                                                         }
00432                                                         inside = false;
00433                                                 }
00434                                                 modified = false;
00435                                         }
00436                                         ++localElem._srcEnd.x();
00437                                         ++dstEnd.x();
00438                                 }
00439                                 if( inside )
00440                                 {
00441                                         localElem._xEnd = gElem._xEnd;
00442                                         if( modified )
00443                                         {
00444                                                 // propagation in the same direction
00445                                                 localPropagation.push_back( localElem );
00446                                         }
00447                                 }
00448 
00449                                 if( ! localPropagation.empty() )
00450                                 {
00451                                         // propagation in the opposite direction
00452                                         if( localPropagation.front()._xBegin - 1 + Connexity::x < iElem._xBegin )
00453                                         {
00454                                                 FloodElem leftElem = iElem; // same line as source
00455                                                 leftElem._direction = invertDirection( iElem._direction );
00456                                                 leftElem._xBegin = localPropagation.front()._xBegin;
00457                                                 leftElem._xEnd = iElem._xBegin - 1;
00458                                                 leftElem._srcBegin = localPropagation.front()._srcBegin;
00459                                                 leftElem._dstBegin = localPropagation.front()._dstBegin;
00460                                                 leftElem._srcEnd = iElem._srcEnd.xy_at( -1, 0 );
00461                                                 propagation.push_back( leftElem );
00462                                         }
00463                                         if( localPropagation.back()._xEnd + 1 - Connexity::x > iElem._xEnd )
00464                                         {
00465                                                 FloodElem rightElem = iElem; // same line as source
00466                                                 rightElem._direction = invertDirection( iElem._direction );
00467                                                 rightElem._xBegin = iElem._xEnd + 1;
00468                                                 std::size_t shift = rightElem._xBegin - localPropagation.back()._xBegin;
00469                                                 rightElem._srcBegin = localPropagation.back()._srcBegin.xy_at( shift, 0 );
00470                                                 rightElem._dstBegin = localPropagation.back()._dstBegin.xy_at( shift, 0 );
00471                                                 rightElem._xEnd = localPropagation.back()._xEnd;
00472                                                 rightElem._srcEnd = rightElem._srcBegin.xy_at( rightElem._xEnd - rightElem._xBegin, 0 );
00473                                                 propagation.push_back( rightElem );
00474                                         }
00475 
00476                                         propagation.insert( propagation.end(), localPropagation.begin(), localPropagation.end() );
00477                                 }
00478                         }
00479                 }
00480         }
00481 }
00482 
00483 
00484 /**
00485  * @brief Simplest implementation of flood fill algorithm.
00486  * @see flood_fill, faster implementation of the same algorithm
00487  * @remark not in production (only use for debugging)
00488  */
00489 template<class StrongTest, class SoftTest, class SView, class DView>
00490 void flood_fill_bruteForce( const SView& srcView, const Rect<std::ssize_t>& srcRod,
00491                                  DView& dstView, const Rect<std::ssize_t>& dstRod,
00492                                  const Rect<std::ssize_t>& procWindow,
00493                                  const StrongTest& strongTest, const SoftTest& softTest )
00494 {
00495     typedef typename SView::value_type SPixel;
00496     typedef typename boost::gil::channel_type<SView>::type SChannel;
00497         typedef typename SView::iterator SIterator;
00498     typedef typename DView::value_type DPixel;
00499     typedef typename boost::gil::channel_type<DView>::type DChannel;
00500         typedef typename DView::iterator DIterator;
00501 
00502         typedef boost::gil::point2<std::ptrdiff_t> Point2;
00503 
00504         static const std::size_t gradMax = 0;
00505         static const std::size_t lower = 0;
00506         static const std::size_t upper = 1;
00507         static const std::size_t flooding = 2;
00508 
00509         Rect<int> procWindowOutput = translateRegion( procWindow, dstRod );
00510         boost::gil::point2<int> procWindowSize( procWindow.x2 - procWindow.x1, procWindow.y2 - procWindow.y1 );
00511         Rect<int> rectLimit = rectangleReduce(procWindow, 1);
00512 
00513         const Point2 nextLine( -procWindowSize.x, 1 );
00514         typename DView::xy_locator dst_loc = dstView.xy_at( procWindowOutput.x1, procWindowOutput.y1 );
00515         typename DView::xy_locator src_loc = srcView.xy_at( procWindow.x1 - srcRod.x1, procWindow.y1 - srcRod.y1 );
00516 
00517         for( int y = procWindow.y1;
00518                          y < procWindow.y2;
00519                          ++y )
00520         {
00521                 for( int x = procWindow.x1;
00522                          x < procWindow.x2;
00523                          ++x, ++dst_loc.x(), ++src_loc.x() )
00524                 {
00525                         if( softTest( (*src_loc)[gradMax] ) )
00526                         {
00527                                 (*dst_loc)[lower] = boost::gil::channel_traits<DChannel>::max_value();
00528                                 if( strongTest( (*src_loc)[gradMax] ) )
00529                                 {
00530                                         (*dst_loc)[upper] = boost::gil::channel_traits<DChannel>::max_value();
00531                                         std::queue<Point2> fifo; ///< @todo tuttle: use host allocator
00532                                         fifo.push( Point2( x, y ) );
00533                                         while( !fifo.empty() )
00534                                         {
00535                                                 const Point2 p = fifo.front();
00536                                                 fifo.pop();
00537                                                 for( int dy = -1; dy < 2; ++dy )
00538                                                 {
00539                                                         for( int dx = -1; dx < 2; ++dx )
00540                                                         {
00541                                                                 DIterator pix = dstView.at( p.x+dx - dstRod.x1, p.y+dy - dstRod.y1 );
00542                                                                 SIterator spix = srcView.at( p.x+dx - srcRod.x1, p.y+dy - srcRod.y1 );
00543                                                                 if( softTest( (*spix)[gradMax] ) &&
00544                                                                         (*pix)[flooding] != boost::gil::channel_traits<DChannel>::max_value() )
00545                                                                 {
00546                                                                         (*pix)[flooding] = boost::gil::channel_traits<DChannel>::max_value();
00547                                                                         if( ! strongTest( (*spix)[gradMax] ) )
00548                                                                         {
00549                                                                                 Point2 np( p.x+dx, p.y+dy );
00550                                                                                 // inside a subwindow of the rendering,
00551                                                                                 // we can't append border pixels
00552                                                                                 if( pointInRect( np, rectLimit ) )
00553                                                                                         fifo.push( np );
00554                                                                         }
00555                                                                 }
00556                                                         }
00557                                                 }
00558                                         }
00559                                 }
00560                         }
00561 //                      else
00562 //                      {
00563 //                              (*dst_loc)[upper] = boost::gil::channel_traits<DChannel>::max_value();
00564 //                      }
00565                 }
00566                 dst_loc += nextLine;
00567                 src_loc += nextLine;
00568         }
00569 
00570 //      if( _params._fillAllChannels )
00571 //      {
00572         DView tmp_dst = subimage_view( dstView, procWindowOutput.x1, procWindowOutput.y1,
00573                                                                                           procWindowSize.x, procWindowSize.y );
00574         boost::gil::copy_pixels( boost::gil::kth_channel_view<flooding>(tmp_dst), boost::gil::kth_channel_view<lower>(tmp_dst) );
00575         boost::gil::copy_pixels( boost::gil::kth_channel_view<flooding>(tmp_dst), boost::gil::kth_channel_view<upper>(tmp_dst) );
00576         boost::gil::copy_pixels( boost::gil::kth_channel_view<flooding>(tmp_dst), boost::gil::kth_channel_view<3>(tmp_dst) );
00577 //      }
00578 }
00579 
00580 }
00581 
00582 
00583 template<template<class> class Allocator, class SView, class DView>
00584 void applyFloodFill(
00585         const SView& srcView,
00586               DView& dstView,
00587         const double lowerThres, const double upperThres )
00588 {
00589         using namespace boost::gil;
00590         using namespace terry::numeric;
00591 
00592         typedef double Scalar;
00593         typedef typename SView::value_type SPixel;
00594         typedef typename DView::value_type DPixel;
00595 
00596         typedef kth_channel_view_type<0,SView> LocalView;
00597         typename LocalView::type localView( LocalView::make(srcView) );
00598         pixel_minmax_by_channel_t<typename LocalView::type::value_type> minmax( localView(0,0) );
00599 
00600         terry::algorithm::transform_pixels(
00601                 localView,
00602                 minmax );
00603         
00604         const bool isConstantImage = ( minmax.max[0] == minmax.min[0] );
00605         const double lowerThresR = (lowerThres * (minmax.max[0]-minmax.min[0])) + minmax.min[0];
00606         const double upperThresR = (upperThres * (minmax.max[0]-minmax.min[0])) + minmax.min[0];
00607 
00608         terry::draw::fill_pixels( dstView, get_black<DPixel>() );
00609         
00610         if( isConstantImage )
00611                 return;
00612         
00613         floodFill::flood_fill<floodFill::Connexity4, floodFill::IsUpper<Scalar>, floodFill::IsUpper<Scalar>, SView, DView, Allocator>(
00614                                 srcView, getBounds<std::ptrdiff_t>(srcView),
00615                                 dstView, getBounds<std::ptrdiff_t>(dstView),
00616                                 rectangleReduce( getBounds<std::ptrdiff_t>(dstView), 1 ),
00617                                 floodFill::IsUpper<Scalar>(upperThresR),
00618                                 floodFill::IsUpper<Scalar>(lowerThresR)
00619                                 );
00620 }
00621 
00622 
00623 }
00624 }
00625 
00626 #endif