URL:
https://svn.lrde.epita.fr/svn/oln/branches/cleanup-2008/milena
ChangeLog:
2008-10-08 Matthieu Garrigues <garrigues(a)lrde.epita.fr>
Work on erosion and browsing canvas.
Todo: Add a n-dimensional browsing canvas which follows diagonal
directions, to accelerate erosion on diagonal lines.
* mln/morpho/erosion.spe.hh:
* tests/morpho/erosion.cc: More tests and benches on rectangles,
hline2d, vline2d and octogone.
* mln/canvas/browsing/directional.hh: Improve this canvas in order to
use it in erosion, to improve performance on erosion with lines.
* tests/timer.hh: New. Tool to bench tests.
---
mln/canvas/browsing/directional.hh | 13 +
mln/morpho/erosion.spe.hh | 380 ++++++++++++++++++++++++++++++++-----
tests/morpho/erosion.cc | 179 +++++++++++++----
tests/timer.hh | 62 ++++++
4 files changed, 542 insertions(+), 92 deletions(-)
Index: branches/cleanup-2008/milena/tests/morpho/erosion.cc
===================================================================
--- branches/cleanup-2008/milena/tests/morpho/erosion.cc (revision 2531)
+++ branches/cleanup-2008/milena/tests/morpho/erosion.cc (revision 2532)
@@ -33,25 +33,17 @@
#include <mln/core/image/image2d.hh>
#include <mln/win/rectangle2d.hh>
#include <mln/win/octagon2d.hh>
-#include <mln/win/diag2d.hh>
-#include <mln/win/backdiag2d.hh>
-#include <mln/core/alias/window2d.hh>
+
+#include <mln/debug/iota.hh>
#include <mln/io/pgm/load.hh>
#include <mln/io/pgm/save.hh>
#include <mln/value/int_u8.hh>
-#include <mln/level/fill.hh>
#include <mln/morpho/erosion.hh>
-#include <mln/pw/value.hh>
-#include <mln/pw/cst.hh>
-#include <mln/fun/ops.hh>
-
-#include <mln/convert/to_p_array.hh>
-#include <mln/convert/to_window.hh>
-
#include "tests/data.hh"
+#include "tests/timer.hh"
int main()
@@ -76,43 +68,150 @@
// 11 29 1
// 25 66 15
+ border::thickness = 20;
image2d<int_u8> lena;
io::pgm::load(lena, MLN_IMG_DIR "/lena.pgm");
+ win::rectangle2d rec(21, 21);
+ win::hline2d hline(31);
+ win::vline2d vline(31);
+ win::octagon2d oct(15);
+ image2d<int_u8> out;
+ image2d<int_u8> ref;
// trace::quiet = false;
+ timer t;
+
+
+ // Rectangle
+ std::cout << "-------------------------- Rectangle: " <<
std::endl;
{
- win::rectangle2d rec(L_rec, L_rec);
- io::pgm::save(morpho::erosion(lena, rec),
- "out1.pgm");
+ t.start();
+ ref = morpho::impl::generic::erosion_on_function(lena, rec);
+ std::cout << "generic on rectangle2d: " << t <<
std::endl;
}
{
- win::octagon2d oct(L_oct);
- io::pgm::save(morpho::erosion(lena, oct),
- "out2.pgm");
- }
-
-// {
-// p_array<point2d> vec = convert::to_p_array(rec, point2d::zero);
-// window2d win = convert::to_window(vec);
-
-// image2d<int_u8> out(lena.domain());
-// level::ero(lena, win, out);
-// morpho::erosion(lena, win, out);
-// io::pgm::save(out, "out.pgm");
-// }
-
-// {
-// image2d<bool> bin(lena.domain()), out(lena.domain());
-// level::fill(bin, pw::value(lena) > pw::cst(127));
-// morpho::erosion(bin, rec, out);
-
-// image2d<int_u8> test(lena.domain());
-// image2d<int_u8>::fwd_piter p(lena.domain());
-// for_all(p)
-// test(p) = out(p) ? 255 : 0;
-// io::pgm::save(test, "test.pgm");
-// }
+ t.start();
+ out = morpho::erosion(lena, rec);
+ std::cout << "dispach on rectangle2d: " << t <<
std::endl;
+ bool test = out == ref;
+ mln_assertion(test);
+ std::cout << " " << (test ? "OK" :
"KO!!!") << std::endl;
+ }
+
+ {
+ t.start();
+ out = morpho::impl::erosion_arbitrary_2d_fastest(lena, rec);
+ std::cout << "erosion_arbitrary_2d_fastest on rectangle2d: " <<
t << std::endl;
+ bool test = out == ref;
+ mln_assertion(test);
+ std::cout << " " << (test ? "OK" :
"KO!!!") << std::endl;
+ }
+
+ {
+ t.start();
+ out = morpho::impl::erosion_arbitrary_2d(lena, rec);
+ std::cout << "erosion_arbitrary_2d on rectangle2d: " << t
<< std::endl;
+ bool test = out == ref;
+ mln_assertion(test);
+ std::cout << " " << (test ? "OK" :
"KO!!!") << std::endl;
+ }
+
+ //Hline
+
+ std::cout << "-------------------------- Hline2d: " <<
std::endl;
+
+ {
+ t.start();
+ ref = morpho::impl::generic::erosion_on_function(lena, hline);
+ std::cout << "generic on hline2d: " << t << std::endl;
+ }
+
+ {
+ t.start();
+ out = morpho::erosion(lena, hline);
+ std::cout << "dispach on hline2d : " << t << std::endl;
+ bool test = out == ref;
+ mln_assertion(test);
+ std::cout << " " << (test ? "OK" :
"KO!!!") << std::endl;
+ }
+
+ {
+ t.start();
+ out = morpho::impl::erosion_arbitrary_2d_fastest(lena, hline);
+ std::cout << "erosion_arbitrary_2d_fastest on hline2d: " << t
<< std::endl;
+ bool test = out == ref;
+ mln_assertion(test);
+ std::cout << " " << (test ? "OK" :
"KO!!!") << std::endl;
+ }
+
+
+ {
+ t.start();
+ out = morpho::impl::erosion_arbitrary_2d(lena, hline);
+ std::cout << "erosion_arbitrary_2d on hline2d: " << t <<
std::endl;
+ bool test = out == ref;
+ mln_assertion(test);
+ std::cout << " " << (test ? "OK" :
"KO!!!") << std::endl;
+ }
+
+ std::cout << "-------------------------- Vline2d: "<< std::endl;
+
+ //Vline
+ {
+ t.start();
+ ref = morpho::impl::generic::erosion_on_function(lena, vline);
+ std::cout << "generic on vline2d: " << t << std::endl;
+ }
+
+ {
+ t.start();
+ out = morpho::erosion(lena, vline);
+ std::cout << "dispach on vline2d : " << t << std::endl;
+ bool test = out == ref;
+ mln_assertion(test);
+ std::cout << " " << (test ? "OK" :
"KO!!!") << std::endl;
+ }
+
+
+ {
+ t.start();
+ out = morpho::impl::erosion_arbitrary_2d_fastest(lena, vline);
+ std::cout << "erosion_arbitrary_2d_fastest on vline2d: " << t
<< std::endl;
+ bool test = out == ref;
+ mln_assertion(test);
+ std::cout << " " << (test ? "OK" :
"KO!!!") << std::endl;
+ }
+
+
+ {
+ t.start();
+ out = morpho::impl::erosion_arbitrary_2d(lena, vline);
+ std::cout << "erosion_arbitrary_2d on vline2d: " << t <<
std::endl;
+ bool test = out == ref;
+ mln_assertion(test);
+ std::cout << " " << (test ? "OK" :
"KO!!!") << std::endl;
+ }
+
+ std::cout << "-------------------------- Octogone: " <<
std::endl;
+
+ //Octogone
+ {
+ t.start();
+ ref = morpho::impl::generic::erosion_on_function(lena, oct);
+ std::cout << "generic on octogone: " << t << std::endl;
+ io::pgm::save(ref, "out_oct_ref.pgm");
+ }
+
+ {
+ t.start();
+ out = morpho::erosion(lena, oct);
+ std::cout << "dispach on octogone: " << t << std::endl;
+ bool test = out == ref;
+ mln_assertion(test);
+ std::cout << " " << (test ? "OK" :
"KO!!!") << std::endl;
+ io::pgm::save(out, "out_oct.pgm");
+ }
}
Index: branches/cleanup-2008/milena/tests/timer.hh
===================================================================
--- branches/cleanup-2008/milena/tests/timer.hh (revision 0)
+++ branches/cleanup-2008/milena/tests/timer.hh (revision 2532)
@@ -0,0 +1,62 @@
+// Copyright (C) 2007, 2008 EPITA Research and Development Laboratory (LRDE)
+//
+// This file is part of the Olena Library. This library is free
+// software; you can redistribute it and/or modify it under the terms
+// of the GNU General Public License version 2 as published by the
+// Free Software Foundation.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this library; see the file COPYING. If not, write to
+// the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+// Boston, MA 02111-1307, USA.
+//
+// As a special exception, you may use this file as part of a free
+// software library without restriction. Specifically, if other files
+// instantiate templates or use macros or inline functions from this
+// file, or you compile this file and link it with other files to
+// produce an executable, this file does not by itself cause the
+// resulting executable to be covered by the GNU General Public
+// License. This exception does not however invalidate any other
+// reasons why the executable file might be covered by the GNU General
+// Public License.
+
+/*! \file tests/morpho/erosion.cc
+ *
+ * \brief Timer to bench tests.
+ */
+
+class timer
+{
+public:
+ void start()
+ {
+ start_ = clock();
+ }
+
+ void stop()
+ {
+ end_ = clock();
+ len = float(end_ - start_) / CLOCKS_PER_SEC;
+ }
+
+ float lenght()
+ {
+ return float(clock() - start_) / CLOCKS_PER_SEC;
+ }
+
+private:
+ clock_t start_;
+ clock_t end_;
+ float len;
+};
+
+
+std::ostream& operator<<(std::ostream& ostr, timer t)
+{
+ return ostr << t.lenght() << "s";
+}
Index: branches/cleanup-2008/milena/mln/morpho/erosion.spe.hh
===================================================================
--- branches/cleanup-2008/milena/mln/morpho/erosion.spe.hh (revision 2531)
+++ branches/cleanup-2008/milena/mln/morpho/erosion.spe.hh (revision 2532)
@@ -41,6 +41,8 @@
# include <mln/accu/min_h.hh>
# include <mln/canvas/browsing/snake_fwd.hh>
+# include <mln/canvas/browsing/snake_generic.hh>
+# include <mln/canvas/browsing/directional.hh>
/*! \file mln/morpho/erosion.spe.hh
@@ -258,6 +260,10 @@
template <typename I, typename W>
struct erosion_arbitrary_2d_fastest_functor
{
+ typedef erosion_arbitrary_2d_fastest_functor<I,W> self;
+ typedef void (self::*move_fun)();
+ typedef mln_deduce(I, psite, delta) dpsite;
+
const I& input;
const W& win;
mln_concrete(I) output;
@@ -266,30 +272,50 @@
mln_psite(I) p;
window2d
- win_left,
- win_right,
+ win_left_fwd,
+ win_right_fwd,
+ win_left_bkd,
+ win_right_bkd,
win_bot,
win_top;
mln_qixter(const I, window2d)
- q_l,
- q_r,
+ q_l_fwd,
+ q_r_fwd,
+ q_l_bkd,
+ q_r_bkd,
q_top,
q_bot;
+ std::vector<move_fun> moves;
+ std::vector<dpsite> dps;
+
erosion_arbitrary_2d_fastest_functor(const I& input, const W& win)
: input(input),
win(win),
min(),
- win_left(win::shift(win, left) - win),
- win_right(win - win::shift(win, left)),
+ win_left_fwd(win::shift(win, left) - win),
+ win_right_fwd(win - win::shift(win, left)),
+ win_left_bkd(win::shift(win_left_fwd, right)),
+ win_right_bkd(win::shift(win_right_fwd, right)),
win_bot(win - win::shift(win, up)),
win_top(win::shift(win, up) - win),
- q_l(input, win_left, p),
- q_r(input, win_right, p),
+ q_l_fwd(input, win_left_fwd, p),
+ q_r_fwd(input, win_right_fwd, p),
+ q_l_bkd(input, win_left_bkd, p),
+ q_r_bkd(input, win_right_bkd, p),
q_top(input, win_top, p),
- q_bot(input, win_bot, p)
- { }
+ q_bot(input, win_bot, p),
+ moves(3),
+ dps(3)
+ {
+ dps[0] = dpsite(1, 0);
+ dps[1] = dpsite(0, 1);
+ dps[2] = dpsite(0, -1);
+ moves[0] = &self::down;
+ moves[1] = &self::fwd;
+ moves[2] = &self::bkd;
+ }
void init()
{
@@ -301,31 +327,29 @@
mln_qixter(const I, W) q(input, win, p);
for_all(q)
min.take(q.val());
+ p = input.domain().pmin();
}
void fwd()
{
- ++p.col();
- for_all(q_l)
- min.untake(q_l.val());
- for_all(q_r)
- min.take(q_r.val());
+ for_all(q_l_fwd)
+ min.untake(q_l_fwd.val());
+ for_all(q_r_fwd)
+ min.take(q_r_fwd.val());
output(p) = min;
}
void bkd()
{
- --p.col();
- for_all(q_r)
- min.untake(q_r.val());
- for_all(q_l)
- min.take(q_l.val());
+ for_all(q_r_bkd)
+ min.untake(q_r_bkd.val());
+ for_all(q_l_bkd)
+ min.take(q_l_bkd.val());
output(p) = min;
}
void down()
{
- ++p.row();
for_all(q_top)
min.untake(q_top.val());
for_all(q_bot)
@@ -344,7 +368,7 @@
typedef erosion_arbitrary_2d_fastest_functor<I, W> F;
F f(exact(input), exact(win));
- canvas::browsing::snake_fwd(f);
+ canvas::browsing::snake_generic(f);
trace::exiting("morpho::impl:erosion_arbitrary_2d_fastest");
@@ -355,6 +379,10 @@
template <typename I, typename W>
struct erosion_arbitrary_2d_functor
{
+ typedef erosion_arbitrary_2d_functor<I,W> self;
+ typedef void (self::*move_fun)();
+ typedef mln_deduce(I, psite, delta) dpsite;
+
const I& input;
const W& win;
mln_concrete(I) output;
@@ -363,30 +391,50 @@
mln_psite(I) p;
window2d
- win_left,
- win_right,
+ win_left_fwd,
+ win_right_fwd,
+ win_left_bkd,
+ win_right_bkd,
win_bot,
win_top;
mln_qiter(window2d)
- q_l,
- q_r,
+ q_l_fwd,
+ q_r_fwd,
+ q_l_bkd,
+ q_r_bkd,
q_top,
q_bot;
+ std::vector<move_fun> moves;
+ std::vector<dpsite> dps;
+
erosion_arbitrary_2d_functor(const I& input, const W& win)
: input(input),
win(win),
min(),
- win_left(win::shift(win, left) - win),
- win_right(win - win::shift(win, left)),
+ win_left_fwd(win::shift(win, left) - win),
+ win_right_fwd(win - win::shift(win, left)),
+ win_left_bkd(win::shift(win_left_fwd, right)),
+ win_right_bkd(win::shift(win_right_fwd, right)),
win_bot(win - win::shift(win, up)),
win_top(win::shift(win, up) - win),
- q_l(win_left, p),
- q_r(win_right, p),
+ q_l_fwd(win_left_fwd, p),
+ q_r_fwd(win_right_fwd, p),
+ q_l_bkd(win_left_bkd, p),
+ q_r_bkd(win_right_bkd, p),
q_top(win_top, p),
- q_bot(win_bot, p)
- { }
+ q_bot(win_bot, p),
+ moves(3),
+ dps(3)
+ {
+ dps[0] = dpsite(1, 0);
+ dps[1] = dpsite(0, 1);
+ dps[2] = dpsite(0, -1);
+ moves[0] = &self::down;
+ moves[1] = &self::fwd;
+ moves[2] = &self::bkd;
+ }
void init()
{
@@ -398,31 +446,29 @@
mln_qiter(W) q(win, p);
for_all(q)
min.take(input(q));
+ p = input.domain().pmin();
}
void fwd()
{
- ++p.col();
- for_all(q_l)
- min.untake(input(q_l));
- for_all(q_r)
- min.take(input(q_r));
+ for_all(q_l_fwd)
+ min.untake(input(q_l_fwd));
+ for_all(q_r_fwd)
+ min.take(input(q_r_fwd));
output(p) = min;
}
void bkd()
{
- --p.col();
- for_all(q_r)
- min.untake(input(q_r));
- for_all(q_l)
- min.take(input(q_l));
+ for_all(q_r_bkd)
+ min.untake(input(q_r_bkd));
+ for_all(q_l_bkd)
+ min.take(input(q_l_bkd));
output(p) = min;
}
void down()
{
- ++p.row();
for_all(q_top)
min.untake(input(q_top));
for_all(q_bot)
@@ -441,13 +487,192 @@
typedef erosion_arbitrary_2d_functor<I, W> F;
F f(exact(input), exact(win));
- canvas::browsing::snake_fwd(f);
+ canvas::browsing::snake_generic(f);
trace::exiting("morpho::impl:erosion_arbitrary_2d");
return f.output;
}
+
+ template <typename Dp>
+ Dp dp_directional(int dir)
+ {
+ Dp dp = literal::zero;
+ dp[dir] = 1;
+ return dp;
+ }
+
+ template <typename I_, typename W>
+ struct erosion_directional_nd_functor
+ {
+ typedef I_ I;
+ typedef mln_deduce(I, psite, delta) dpsite;
+
+ const I& input;
+ const W& win;
+ mln_concrete(I) output;
+ accu::min_h<mln_value(I)> min;
+ enum { dim = I::site::dim };
+
+ mln_psite(I) p;
+ unsigned dir;
+
+ window2d
+ win_left,
+ win_right;
+
+ mln_qiter(window2d)
+ q_l,
+ q_r;
+
+ erosion_directional_nd_functor(const I& input, const W& win, int dir)
+ : input(input),
+ win(win),
+ min(),
+ dir(dir),
+ win_left(win::shift(win, -dp_directional<dpsite>(dir)) - win),
+ win_right(win - win::shift(win, -dp_directional<dpsite>(dir))),
+ q_l(win_left, p),
+ q_r(win_right, p)
+ {
+
+ }
+
+ void init()
+ {
+ // FIXME: border::adjust(input, win.delta());
+ extension::fill(input, mln_max(mln_value(I)));
+ initialize(output, input);
+ }
+
+
+ void init_run()
+ {
+ min.init();
+ p[dir]--;
+ mln_qiter(W) q(win, p);
+ for_all(q)
+ min.take(input(q));
+ p[dir]++;
+ }
+
+ void next()
+ {
+ for_all(q_l)
+ min.untake(input(q_l));
+ for_all(q_r)
+ min.take(input(q_r));
+ output(p) = min;
+ }
+
+ void final()
+ {
+ }
+
+ };
+
+ template <typename I, typename W>
+ inline
+ mln_concrete(I)
+ erosion_directional_nd(const Image<I>& input, const Window<W>&
win, unsigned dir)
+ {
+ trace::entering("morpho::impl:erosion_directional_nd");
+
+ typedef erosion_directional_nd_functor<I, W> F;
+ F f(exact(input), exact(win), dir);
+ canvas::browsing::directional(f);
+
+ trace::exiting("morpho::impl:erosion_directional_nd");
+
+ return f.output;
+ }
+
+
+ template <typename I_, typename W>
+ struct erosion_directional_nd_fastest_functor
+ {
+ typedef I_ I;
+ typedef mln_deduce(I, psite, delta) dpsite;
+
+ const I& input;
+ const W& win;
+ mln_concrete(I) output;
+ accu::min_h<mln_value(I)> min;
+
+ mln_psite(I) p;
+ enum { dim = I::site::dim };
+ unsigned dir;
+
+ window2d
+ win_left,
+ win_right;
+
+ mln_qixter(const I, window2d)
+ q_l,
+ q_r;
+
+ erosion_directional_nd_fastest_functor(const I& input, const W& win, unsigned
dir)
+ : input(input),
+ win(win),
+ min(),
+ dir(dir),
+ win_left(win::shift(win, -dp_directional<dpsite>(dir)) - win),
+ win_right(win - win::shift(win, -dp_directional<dpsite>(dir))),
+ q_l(input, win_left, p),
+ q_r(input, win_right, p)
+ {
+ }
+
+ void init()
+ {
+ // FIXME: border::adjust(input, win.delta());
+ extension::fill(input, mln_max(mln_value(I)));
+ initialize(output, input);
+ }
+
+ void next()
+ {
+ for_all(q_l)
+ min.untake(q_l.val());
+ for_all(q_r)
+ min.take(q_r.val());
+ output(p) = min;
+ }
+
+
+ void init_run()
+ {
+ min.init();
+ p[dir]--;
+ mln_qixter(const I, W) q(input, win, p);
+ for_all(q)
+ min.take(q.val());
+ p[dir]++;
+ }
+
+ void final()
+ {
+ }
+
+ };
+
+ template <typename I, typename W>
+ inline
+ mln_concrete(I)
+ erosion_directional_nd_fastest(const Image<I>& input, const
Window<W>& win, unsigned dir)
+ {
+ trace::entering("morpho::impl:erosion_directional_nd_fastest");
+
+ typedef erosion_directional_nd_fastest_functor<I, W> F;
+ F f(exact(input), exact(win), dir);
+ canvas::browsing::directional(f);
+
+ trace::exiting("morpho::impl:erosion_directional_nd_fastest");
+
+ return f.output;
+ }
+
} // end of namespace mln::morpho::impl
@@ -505,9 +730,11 @@
mln_concrete(I)
erosion_dispatch_for_generic(const I& input, const W& win) // Entry point.
{
+ trace::entering("morpho::erosion_dispatch_for_generic");
return erosion_dispatch_for_generic(mln_trait_image_kind(I)(),
mln_trait_image_speed(I)(),
input, win);
+ trace::entering("morpho::erosion_dispatch_for_generic");
}
@@ -518,7 +745,7 @@
erosion_chooses_arbitrary(const I& input, const W& win)
{
return
- win.size() >= 25 // size is not too small
+ win.size() >= 10 // size is not too small
&&
// 2d case only
mlc_equal(mln_trait_image_dimension(I),
@@ -553,8 +780,40 @@
mln_concrete(I)
erosion_dispatch_for_arbitrary(const I& input, const W& win)
{
+ trace::entering("morpho::erosion_dispatch_for_arbitrary");
return erosion_dispatch_for_arbitrary(mln_trait_image_speed(I)(),
input, win);
+ trace::exiting("morpho::erosion_dispatch_for_arbitrary");
+ }
+
+
+
+ // dispatch for directional_nd w.r.t. speed
+
+ template <typename I, typename W>
+ mln_concrete(I)
+ erosion_dispatch_for_directional(trait::image::speed::fastest,
+ const I& input, const W& win, unsigned dir)
+ {
+ return impl::erosion_directional_nd_fastest(input, win, dir);
+ }
+
+ template <typename I, typename W>
+ mln_concrete(I)
+ erosion_dispatch_for_directional(trait::image::speed::any,
+ const I& input, const W& win, unsigned dir)
+ {
+ return impl::erosion_directional_nd(input, win, dir);
+ }
+
+ template <typename I, typename W>
+ mln_concrete(I)
+ erosion_dispatch_for_directional(const I& input, const W& win, unsigned
dir)
+ {
+ trace::entering("morpho::erosion_dispatch_for_directional");
+ return erosion_dispatch_for_directional(mln_trait_image_speed(I)(),
+ input, win, dir);
+ trace::exiting("morpho::erosion_dispatch_for_directional");
}
// dispatch w.r.t. win
@@ -567,9 +826,9 @@
// win::shift does not work. We have to introduce
// props from windows, then re-write win::shift.
-// if (erosion_chooses_arbitrary(input, win))
-// return erosion_dispatch_for_arbitrary(input, win);
-// else
+ if (erosion_chooses_arbitrary(input, win))
+ return erosion_dispatch_for_arbitrary(input, win);
+ else
return erosion_dispatch_for_generic(input, win);
}
@@ -587,13 +846,34 @@
mln_concrete(I)
erosion_dispatch_wrt_win(const I& input, const win::octagon2d& win)
{
- if (win.size() <= 9) // FIXME: Hard-coded!
- return erosion_dispatch_for_generic(input, win);
+ if (win.length() < 5)
+ return erosion_dispatch_for_arbitrary(input, win);
else
return impl::erosion_octagon2d(input, win);
}
+ template <typename I>
+ mln_concrete(I)
+ erosion_dispatch_wrt_win(const I& input, const win::hline2d& win)
+ {
+ if (win.size() <= 3)
+ return erosion_dispatch_for_generic(input, win);
+ else
+ return erosion_dispatch_for_directional(input, win, 1);
+ }
+
+ template <typename I>
+ mln_concrete(I)
+ erosion_dispatch_wrt_win(const I& input, const win::vline2d& win)
+ {
+ if (win.size() <= 3)
+ return erosion_dispatch_for_generic(input, win);
+ else
+ return erosion_dispatch_for_directional(input, win, 0);
+ }
+
+
// The dispatch entry point.
template <typename I, typename W>
Index: branches/cleanup-2008/milena/mln/canvas/browsing/directional.hh
===================================================================
--- branches/cleanup-2008/milena/mln/canvas/browsing/directional.hh (revision 2531)
+++ branches/cleanup-2008/milena/mln/canvas/browsing/directional.hh (revision 2532)
@@ -121,10 +121,18 @@
do
{
- trace::entering("canvas::browsing::directional::next");
+
+ // Browse the run
+ f.init_run();
+ while (f.p[f.dir] <= pmax[f.dir])
+ {
f.next();
- trace::exiting("canvas::browsing::directional::next");
+ ++f.p[f.dir];
+ }
+ f.p[f.dir] = pmin[f.dir];
+
+ // Select the next run start
for (int c = F::dim - 1; c >= 0; --c)
{
if (c == int(f.dir))
@@ -136,6 +144,7 @@
}
f.p[c] = pmin[c];
}
+
} while (f.p != pmin);
trace::entering("canvas::browsing::directional::final");