TuttleOFX
1
|
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