https://svn.lrde.epita.fr/svn/oln/trunk/milena Index: ChangeLog from Thierry Geraud <thierry.geraud@lrde.epita.fr> Make morpho erosion rely on a general code. * mln/morpho/erosion.spe.hh (erosion_on_set, erosion_on_set_fastest): Rename as... * mln/morpho/erosion.hh (general_on_set, general_on_set_fastest): ...these. (erosion_op): New. (erosion): Call the general facade. * mln/morpho/erosion.spe.hh: Rename as... * mln/morpho/general.spe.hh: ...this new file. (*erosion*): Rename routines as... (*general*):... these. (general_dispatch_for_generic): New overload for logic and fastest. Now _on_set_fastest routines can be accessible! * mln/accu/land_basic.hh (todo): New. (land_basic): New meta version. * mln/accu/land.hh: Likewise. * mln/morpho/general.hh: New. * tests/morpho/erosion.cc: Copy to... * tests/morpho/general.cc: ...this new file. Update. * tests/morpho/erosion.cc: Update. mln/accu/land.hh | 22 ++ mln/accu/land_basic.hh | 20 ++ mln/morpho/erosion.hh | 117 +++++++++------ mln/morpho/general.hh | 95 ++++++++---- mln/morpho/general.spe.hh | 339 ++++++++++++++++++++-------------------------- tests/morpho/erosion.cc | 65 +------- tests/morpho/general.cc | 160 ++++++++------------- 7 files changed, 403 insertions(+), 415 deletions(-) Index: tests/morpho/general.cc --- tests/morpho/general.cc (revision 2970) +++ tests/morpho/general.cc (working copy) @@ -26,19 +26,16 @@ // reasons why the executable file might be covered by the GNU General // Public License. -/// \file tests/morpho/erosion.cc +/// \file tests/morpho/general.cc /// -/// Test on mln::morpho::erosion. +/// Test on mln::morpho::general. #include <mln/core/image/image2d.hh> -#include <mln/win/all.hh> - -#include <mln/debug/iota.hh> - +#include <mln/value/int_u8.hh> #include <mln/io/pgm/load.hh> -#include <mln/io/pgm/save.hh> +#include <mln/io/pbm/load.hh> -#include <mln/value/int_u8.hh> +#include <mln/win/all.hh> #include <mln/morpho/erosion.hh> #include "tests/data.hh" @@ -49,130 +46,101 @@ using namespace mln; using value::int_u8; - border::thickness = 0; - image2d<int_u8> lena; - io::pgm::load(lena, MLN_IMG_DIR "/lena.pgm"); + // Windows. + win::rectangle2d rec(5, 5); + win::hline2d hline(7); + win::vline2d vline(7); + win::diag2d diag2d(7); + win::backdiag2d backdiag2d(7); + win::octagon2d oct(2 * 3 + 1); - win::rectangle2d rec(21, 21); - win::hline2d hline(31); - win::vline2d vline(31); - win::diag2d diag2d(31); - win::backdiag2d backdiag2d(31); - win::octagon2d oct(6 * 3 + 1); - image2d<int_u8> out; - image2d<int_u8> ref; - -// trace::quiet = false; + morpho::erosion_op ero; + { + image2d<int_u8> lena, out, ref; + io::pgm::load(lena, MLN_IMG_DIR "/tiny.pgm"); - // Rectangle - { - ref = morpho::impl::generic::erosion_on_function(lena, rec); - } + // Rectangle. - { - out = morpho::erosion(lena, rec); - bool test = out == ref; - mln_assertion(test); - } + ref = morpho::impl::generic::general_on_function(ero, lena, rec); - { - out = morpho::impl::erosion_arbitrary_2d(lena, rec); - bool test = out == ref; - mln_assertion(test); - } + out = morpho::impl::general_rectangle2d(ero, lena, rec); + mln_assertion(out == ref); + out = morpho::impl::general_arbitrary_2d(ero, lena, rec); + mln_assertion(out == ref); - // Hline + out = morpho::impl::general_directional(ero, lena, rec, 0); + mln_assertion(out == ref); - { - ref = morpho::impl::generic::erosion_on_function(lena, hline); - } + out = morpho::impl::general_directional(ero, lena, rec, 1); + mln_assertion(out == ref); - { - out = morpho::erosion(lena, hline); - bool test = out == ref; - mln_assertion(test); - } + /* - { - out = morpho::impl::erosion_arbitrary_2d(lena, hline); - bool test = out == ref; - mln_assertion(test); - } + // Hline. + ref = morpho::impl::generic::general_on_function(ero, lena, hline); + // Vline. + ref = morpho::impl::generic::general_on_function(ero, lena, vline); - // Vline + // Diag2d. + ref = morpho::impl::generic::erosion_on_function(lena, diag2d); - { - ref = morpho::impl::generic::erosion_on_function(lena, vline); - } + // Backdiag2d. + ref = morpho::impl::generic::erosion_on_function(lena, backdiag2d); - { - out = morpho::erosion(lena, vline); - bool test = out == ref; - mln_assertion(test); - } + // Octagon + ref = morpho::impl::generic::erosion_on_function(lena, oct); + // io::pgm::save(ref, "out_oct_ref.pgm"); - { - out = morpho::impl::erosion_arbitrary_2d(lena, vline); - bool test = out == ref; - mln_assertion(test); + */ } - // Diag2d + /* { - ref = morpho::impl::generic::erosion_on_function(lena, diag2d); - } + trace::quiet = false; - { - out = morpho::erosion(lena, diag2d); - bool test = out == ref; - mln_assertion(test); - } + image2d<bool> pic; + io::pbm::load(pic, MLN_IMG_DIR "/tiny.pbm"); - { - out = morpho::impl::erosion_arbitrary_2d(lena, diag2d); - bool test = out == ref; - mln_assertion(test); + morpho::general(ero, pic, win::rectangle2d(3,3)); + + trace::quiet = true; } + */ - // Backdiag2d { - ref = morpho::impl::generic::erosion_on_function(lena, backdiag2d); - } + image2d<bool> pic, out, ref; + io::pbm::load(pic, MLN_IMG_DIR "/tiny.pbm"); - { - out = morpho::erosion(lena, backdiag2d); - bool test = out == ref; - mln_assertion(test); - } + // Rectangle. - { - out = morpho::impl::erosion_arbitrary_2d(lena, backdiag2d); - bool test = out == ref; - mln_assertion(test); - } + ref = morpho::impl::generic::general_on_set(ero, pic, rec); + out = morpho::impl::general_on_set_centered(ero, pic, rec); + mln_assertion(out == ref); + out = morpho::impl::general_on_set_centered_fastest(ero, pic, rec); + mln_assertion(out == ref); - // Octagon + out = morpho::impl::general_rectangle2d(ero, pic, rec); + mln_assertion(out == ref); - { - ref = morpho::impl::generic::erosion_on_function(lena, oct); - io::pgm::save(ref, "out_oct_ref.pgm"); - } + out = morpho::impl::general_arbitrary_2d(ero, pic, rec); + mln_assertion(out == ref); - { - out = morpho::erosion(lena, oct); - bool test = out == ref; - mln_assertion(test); + out = morpho::impl::general_directional(ero, pic, rec, 0); + mln_assertion(out == ref); + + out = morpho::impl::general_directional(ero, pic, rec, 1); + mln_assertion(out == ref); } } Index: tests/morpho/erosion.cc --- tests/morpho/erosion.cc (revision 2971) +++ tests/morpho/erosion.cc (working copy) @@ -32,13 +32,9 @@ #include <mln/core/image/image2d.hh> #include <mln/win/all.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/morpho/erosion.hh> #include "tests/data.hh" @@ -63,6 +59,7 @@ image2d<int_u8> out; image2d<int_u8> ref; + // trace::quiet = false; @@ -70,18 +67,12 @@ { ref = morpho::impl::generic::erosion_on_function(lena, rec); - } - { out = morpho::erosion(lena, rec); - bool test = out == ref; - mln_assertion(test); - } + mln_assertion(out == ref); - { out = morpho::impl::erosion_arbitrary_2d(lena, rec); - bool test = out == ref; - mln_assertion(test); + mln_assertion(out == ref); } @@ -89,18 +80,12 @@ { ref = morpho::impl::generic::erosion_on_function(lena, hline); - } - { out = morpho::erosion(lena, hline); - bool test = out == ref; - mln_assertion(test); - } + mln_assertion(out == ref); - { out = morpho::impl::erosion_arbitrary_2d(lena, hline); - bool test = out == ref; - mln_assertion(test); + mln_assertion(out == ref); } @@ -108,18 +93,12 @@ { ref = morpho::impl::generic::erosion_on_function(lena, vline); - } - { out = morpho::erosion(lena, vline); - bool test = out == ref; - mln_assertion(test); - } + mln_assertion(out == ref); - { out = morpho::impl::erosion_arbitrary_2d(lena, vline); - bool test = out == ref; - mln_assertion(test); + mln_assertion(out == ref); } @@ -127,18 +106,12 @@ { ref = morpho::impl::generic::erosion_on_function(lena, diag2d); - } - { out = morpho::erosion(lena, diag2d); - bool test = out == ref; - mln_assertion(test); - } + mln_assertion(out == ref); - { out = morpho::impl::erosion_arbitrary_2d(lena, diag2d); - bool test = out == ref; - mln_assertion(test); + mln_assertion(out == ref); } @@ -146,18 +119,12 @@ { ref = morpho::impl::generic::erosion_on_function(lena, backdiag2d); - } - { out = morpho::erosion(lena, backdiag2d); - bool test = out == ref; - mln_assertion(test); - } + mln_assertion(out == ref); - { out = morpho::impl::erosion_arbitrary_2d(lena, backdiag2d); - bool test = out == ref; - mln_assertion(test); + mln_assertion(out == ref); } @@ -166,13 +133,9 @@ { ref = morpho::impl::generic::erosion_on_function(lena, oct); - io::pgm::save(ref, "out_oct_ref.pgm"); - } - - { + // io::pgm::save(ref, "out_oct_ref.pgm"); out = morpho::erosion(lena, oct); - bool test = out == ref; - mln_assertion(test); + mln_assertion(out == ref); } } Index: mln/accu/land_basic.hh --- mln/accu/land_basic.hh (revision 2971) +++ mln/accu/land_basic.hh (working copy) @@ -32,6 +32,8 @@ /// \file mln/accu/land_basic.hh /// /// Define a basic 'logical-and' accumulator. +/// +/// \todo Have land_basic be parameterized. # include <mln/accu/internal/base.hh> @@ -77,6 +79,24 @@ }; + namespace meta + { + + /// Meta accumulator for land_basic. + + struct land_basic : public Meta_Accumulator< land_basic > + { + template <typename T> + struct with + { + typedef accu::land_basic ret; + }; + }; + + } // end of namespace mln::accu::meta + + + # ifndef MLN_INCLUDE_ONLY inline Index: mln/accu/land.hh --- mln/accu/land.hh (revision 2971) +++ mln/accu/land.hh (working copy) @@ -1,4 +1,5 @@ -// Copyright (C) 2007, 2008 EPITA Research and Development Laboratory (LRDE) +// 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 @@ -32,6 +33,7 @@ /// /// Define a 'logical-and' accumulator. /// +/// \todo Have land_basic be parameterized. # include <mln/accu/internal/base.hh> @@ -73,6 +75,24 @@ }; + namespace meta + { + + /// Meta accumulator for land. + + struct land : public Meta_Accumulator< land > + { + template <typename T> + struct with + { + typedef accu::land ret; + }; + }; + + } // end of namespace mln::accu::meta + + + # ifndef MLN_INCLUDE_ONLY inline Index: mln/morpho/erosion.hh --- mln/morpho/erosion.hh (revision 2971) +++ mln/morpho/erosion.hh (working copy) @@ -31,12 +31,10 @@ /// \file mln/morpho/erosion.hh /// -/// \brief Morphological erosion. +/// Morphological erosion. # include <mln/morpho/includes.hh> - -// Specializations are in: -# include <mln/morpho/erosion.spe.hh> +# include <mln/morpho/general.hh> namespace mln @@ -45,8 +43,7 @@ namespace morpho { - /*! Morphological erosion. - */ + /// Morphological erosion. template <typename I, typename W> mln_concrete(I) erosion(const Image<I>& input, const Window<W>& win); @@ -55,80 +52,106 @@ # ifndef MLN_INCLUDE_ONLY - namespace internal + struct erosion_op { - template <typename I, typename W> - inline - void - erosion_tests(const Image<I>& input_, const Window<W>& win_) + template <typename I> + mln_morpho_select_accu(I, land_basic, min) + accu(const Image<I>&) const { - const I& input = exact(input_); - const W& win = exact(win_); + mln_morpho_select_accu(I, land_basic, min) tmp; + return tmp; + } - mln_precondition(input.has_data()); - mln_precondition(! win.is_empty()); - // mln_precondition(win.is_valid()); + template <typename I> + mln_morpho_select_accu(I, land, min_h) + accu_incr(const Image<I>&) const + { + mln_morpho_select_accu(I, land, min_h) tmp; + return tmp; + } - (void) input; - (void) win; + template <typename I> + mln_value(I) neutral(const Image<I>&) const + { + return internal::neutral<I>::supremum(); } - } // end of mln::morpho::internal + }; namespace impl { - namespace generic - { - - // On function. + // On set with centered window (overloads). template <typename I, typename W> - inline mln_concrete(I) - erosion_on_function(const Image<I>& input, const Window<W>& win) + general_on_set_centered(const erosion_op&, + const Image<I>& input_, const Window<W>& win_) { - trace::entering("morpho::impl::generic::erosion_on_function"); + trace::entering("morpho::impl::general_on_set_centered__erosion"); + + typedef mln_concrete(I) O; + const I& input = exact(input_); + const W& win = exact(win_); - internal::erosion_tests(input, win); + extension::adjust_fill(input, win, true); + + O output; + output = clone(input); - extension::adjust_fill(input, win, mln_max(mln_value(I))); - mln_concrete(I) output; - output = accu::transform(input, accu::meta::min(), win); + mln_piter(I) p(input.domain()); + mln_qiter(W) q(win, p); + for_all(p) + if (input(p) == true) + for_all(q) if (input.has(q)) + if (input(q) == false) + { + output(p) = false; + break; + } - trace::exiting("morpho::impl::generic::erosion_on_function"); + trace::exiting("morpho::impl::general_on_set_centered__erosion"); return output; } - // On set. template <typename I, typename W> - inline mln_concrete(I) - erosion_on_set(const Image<I>& input, const Window<W>& win) + general_on_set_centered_fastest(const erosion_op&, + const Image<I>& input_, const Window<W>& win_) { - trace::entering("morpho::impl::generic::erosion_on_set"); + trace::entering("morpho::impl::general_on_set_centered_fastest__erosion"); - internal::erosion_tests(input, win); + typedef mln_concrete(I) O; + const I& input = exact(input_); + const W& win = exact(win_); extension::adjust_fill(input, win, true); - mln_concrete(I) output; - output = accu::transform_stop(input, accu::land_basic(), win); - trace::exiting("morpho::impl::generic::erosion_on_set"); - return output; - } - - } // end of namespace mln::morpho::impl::generic + O output; + output = clone(input); - } // end of namespace mln::morpho::impl + mln_pixter(const I) p(input); + mln_qixter(const I, W) q(p, win); + mln_pixter(O) p_out(output); + for_all_2(p, p_out) + if (p.val() == true) + for_all(q) + if (q.val() == false) + { + p_out.val() = false; + break; + } + trace::exiting("morpho::impl::general_on_set_centered_fastest__erosion"); + return output; + } + } // end of namespace morpho::impl - // Facades. template <typename I, typename W> inline @@ -139,11 +162,11 @@ mln_precondition(exact(input).has_data()); mln_precondition(! exact(win).is_empty()); - internal::erosion_tests(input, win); - mln_concrete(I) output = internal::erosion_dispatch(input, win); + mln_concrete(I) output = general(erosion_op(), input, win); if (exact(win).is_centered()) mln_postcondition(output <= input); + trace::exiting("morpho::erosion"); return output; } Index: mln/morpho/general.spe.hh --- mln/morpho/general.spe.hh (revision 2970) +++ mln/morpho/general.spe.hh (working copy) @@ -26,12 +26,12 @@ // reasons why the executable file might be covered by the GNU General // Public License. -#ifndef MLN_MORPHO_EROSION_SPE_HH -# define MLN_MORPHO_EROSION_SPE_HH +#ifndef MLN_MORPHO_GENERAL_SPE_HH +# define MLN_MORPHO_GENERAL_SPE_HH -# ifndef MLN_MORPHO_EROSION_HH +# ifndef MLN_MORPHO_GENERAL_HH # error "Forbidden inclusion of *.spe.hh" -# endif // ! MLN_MORPHO_EROSION_HH +# endif // ! MLN_MORPHO_GENERAL_HH # include <mln/core/alias/window2d.hh> # include <mln/core/alias/dpoint2d.hh> @@ -43,14 +43,18 @@ # include <mln/accu/line.hh> -/// \file mln/morpho/erosion.spe.hh +/// \file mln/morpho/general.spe.hh /// -/// Specialization for mln::morpho::erosion. +/// Specialization for mln::morpho::general. /// /// \todo Warning: we should also have the "arbitrary" versions working /// on sets (not only on functions!) /// /// \todo HERE Factor dispatch for lines... +/// +/// \todo Re-activate impl::line_on_function. +/// +/// \todo Re-activate special code for centered window on sets. # ifndef MLN_INCLUDE_ONLY @@ -62,9 +66,9 @@ { // Fwd decl of the facade. - template <typename I, typename W> + template <typename Op, typename I, typename W> mln_concrete(I) - erosion(const Image<I>& input, const Window<W>& win); + general(const Op& op, const Image<I>& input, const Window<W>& win); namespace impl @@ -73,94 +77,49 @@ namespace generic { - // Fwd decl. - // Implementation is in mln/morpho/erosion.hh. - template <typename I, typename W> + // Forward declaration. + // Implementation is in mln/morpho/general.hh. + template <typename Op, typename I, typename W> mln_concrete(I) - erosion_on_function(const Image<I>& input_, const Window<W>& win_); + general_on_function(const Op& op, const Image<I>& input_, const Window<W>& win_); - // Fwd decl. - // Implementation is in mln/morpho/erosion.hh. - template <typename I, typename W> + // Forward declaration. + // Implementation is in mln/morpho/general.hh. + template <typename Op, typename I, typename W> mln_concrete(I) - erosion_on_set(const Image<I>& input_, const Window<W>& win_); + general_on_set(const Op& op, const Image<I>& input_, const Window<W>& win_); } + // On set with centered window. - template <typename I, typename W> + template <typename Op, typename I, typename W> mln_concrete(I) - erosion_on_set_centered(const Image<I>& input_, const Window<W>& win_) - { - trace::entering("morpho::impl::erosion_on_set_centered"); - - typedef mln_concrete(I) O; - const I& input = exact(input_); - const W& win = exact(win_); - - extension::adjust_fill(input, win, true); - - O output; - output = clone(input); - - mln_piter(I) p(input.domain()); - mln_qiter(W) q(win, p); - for_all(p) - if (input(p) == true) - for_all(q) if (input.has(q)) - if (input(q) == false) + general_on_set_centered(const Op& op, const Image<I>& input, const Window<W>& win) { - output(p) = false; - break; + return generic::general_on_set(op, input, win); } - trace::exiting("morpho::impl::erosion_on_set_centered"); - return output; - } - - template <typename I, typename W> + template <typename Op, typename I, typename W> mln_concrete(I) - erosion_on_set_centered_fastest(const Image<I>& input_, const Window<W>& win_) - { - trace::entering("morpho::impl::erosion_on_set_centered_fastest"); - - typedef mln_concrete(I) O; - const I& input = exact(input_); - const W& win = exact(win_); - - extension::adjust_fill(input, win, true); - - O output; - output = clone(input); - - mln_pixter(const I) p(input); - mln_qixter(const I, W) q(p, win); - mln_pixter(O) p_out(output); - for_all_2(p, p_out) - if (p.val() == true) - for_all(q) - if (q.val() == false) + general_on_set_centered_fastest(const Op& op, const Image<I>& input, const Window<W>& win) { - p_out.val() = false; - break; - } - trace::exiting("morpho::impl::erosion_on_set_centered_fastest"); - - return output; + return generic::general_on_set(op, input, win); } +/* // Line case. - template <typename I, typename G, unsigned Dir, typename C> + template <typename Op, typename I, typename G, unsigned Dir, typename C> inline mln_concrete(I) - erosion_line_on_function(const Image<I>& input_, const win::line<G,Dir,C>& win) + general_line_on_function(const Op& op, const Image<I>& input_, const win::line<G,Dir,C>& win) { - trace::entering("morpho::impl::erosion_line"); + trace::entering("morpho::impl::general_line"); typedef mln_site(I) P; enum { dim = P::dim }; @@ -199,108 +158,100 @@ } while (p != pmin); - trace::exiting("morpho::impl::erosion_line"); + trace::exiting("morpho::impl::general_line"); return output; } +*/ // Particular windows. - template <typename I> + template <typename Op, typename I> inline mln_concrete(I) - erosion_rectangle2d(const Image<I>& input_, const win::rectangle2d& win) + general_rectangle2d(const Op& op, const Image<I>& input_, const win::rectangle2d& win) { - trace::entering("morpho::impl::erosion_rectangle2d"); + trace::entering("morpho::impl::general_rectangle2d"); const I& input = exact(input_); mln_concrete(I) temp, output; - temp = morpho::erosion(input, win::hline2d(win.width())); - output = morpho::erosion(temp, win::vline2d(win.height())); + temp = morpho::general(op, input, win::hline2d(win.width())); + output = morpho::general(op, temp, win::vline2d(win.height())); - trace::exiting("morpho::impl::erosion_rectangle2d"); + trace::exiting("morpho::impl::general_rectangle2d"); return output; } - template <typename I> + template <typename Op, typename I> inline mln_concrete(I) - erosion_octagon2d(const Image<I>& input_, const win::octagon2d& win) + general_octagon2d(const Op& op, const Image<I>& input_, const win::octagon2d& win) { - trace::entering("morpho::impl::erosion_octagon2d"); + trace::entering("morpho::impl::general_octagon2d"); const I& input = exact(input_); const unsigned len = (win.length() + 2) / 3; mln_concrete(I) output; - output = morpho::erosion(input, win::hline2d(len)); - output = morpho::erosion(output, win::vline2d(len)); - output = morpho::erosion(output, win::diag2d(len)); - output = morpho::erosion(output, win::backdiag2d(len)); + output = morpho::general(op, input, win::hline2d(len)); + output = morpho::general(op, output, win::vline2d(len)); + output = morpho::general(op, output, win::diag2d(len)); + output = morpho::general(op, output, win::backdiag2d(len)); - trace::exiting("morpho::impl::erosion_(win::octagon2d)"); + trace::exiting("morpho::impl::general_(win::octagon2d)"); return output; } - template <typename I, typename W> + template <typename Op, typename I, typename W> inline mln_concrete(I) - erosion_arbitrary_2d(const Image<I>& input, const Window<W>& win) + general_arbitrary_2d(const Op& op, const Image<I>& input, const Window<W>& win) { - trace::entering("morpho::impl:erosion_arbitrary_2d"); + trace::entering("morpho::impl:general_arbitrary_2d"); - typedef mlc_is(mln_trait_image_kind(I), trait::image::kind::binary) is_binary; - typedef mlc_if(is_binary, accu::land, accu::min_h<mln_value(I)>) A; - A a; - - extension::adjust_fill(input, geom::delta(win) + 1, a); - mln_concrete(I) output = accu::transform_snake(a, input, win); + extension::adjust_fill(input, geom::delta(win) + 1, op.neutral(input)); + mln_concrete(I) output; + output = accu::transform_snake(op.accu_incr(input), input, win); - trace::exiting("morpho::impl:erosion_arbitrary_2d"); + trace::exiting("morpho::impl:general_arbitrary_2d"); return output; } - template <typename I, typename W> + template <typename Op, typename I, typename W> inline mln_concrete(I) - erosion_directional(const Image<I>& input, const Window<W>& win, unsigned dir) + general_directional(const Op& op, const Image<I>& input, const Window<W>& win, unsigned dir) { - trace::entering("morpho::impl:erosion_directional"); + trace::entering("morpho::impl:general_directional"); - typedef mlc_is(mln_trait_image_kind(I), trait::image::kind::binary) is_binary; - typedef mlc_if(is_binary, accu::land, accu::min_h<mln_value(I)>) A; - A a; - - extension::adjust_fill(input, geom::delta(win) + 1, a); - mln_concrete(I) output = accu::transform_directional(a, input, win, dir); + extension::adjust_fill(input, geom::delta(win) + 1, op.neutral(input)); + mln_concrete(I) output; + output = accu::transform_directional(op.accu_incr(input), input, win, dir); - trace::exiting("morpho::impl:erosion_directional"); + trace::exiting("morpho::impl:general_directional"); return output; } - template <typename I, typename W> + template <typename Op, typename I, typename W> inline mln_concrete(I) - erosion_diagonal_2d(const Image<I>& input, const Window<W>& win) + general_diagonal_2d(const Op& op, const Image<I>& input, const Window<W>& win) { - trace::entering("morpho::impl:erosion_diagonal_2d"); - - typedef mlc_is(mln_trait_image_kind(I), trait::image::kind::binary) is_binary; - typedef mlc_if(is_binary, accu::land, accu::min_h<mln_value(I)>) A; - A a; + trace::entering("morpho::impl:general_diagonal_2d"); - extension::adjust_fill(input, geom::delta(win) + 1, a); - mln_concrete(I) output = accu::transform_diagonal(a, input, win); + extension::adjust_fill(input, geom::delta(win) + 1, op.neutral(input)); + mln_concrete(I) output; + output = accu::transform_diagonal(op.accu_incr(input), input, win); - trace::exiting("morpho::impl:erosion_diagonal_2d"); + trace::exiting("morpho::impl:general_diagonal_2d"); return output; } @@ -317,37 +268,49 @@ namespace internal { - template <typename I, typename W> + template <typename Op, typename I, typename W> mln_concrete(I) - erosion_dispatch_for_generic(trait::image::kind::logic, // On sets. - trait::image::speed::any, - const I& input, const W& win) + general_dispatch_for_generic(trait::image::kind::logic, // On sets. + trait::image::speed::any, // Any speed. + const Op& op, const I& input, const W& win) { if (win.is_centered()) - return impl::erosion_on_set_centered(input, win); + return impl::general_on_set_centered(op, input, win); else - return impl::generic::erosion_on_set(input, win); + return impl::generic::general_on_set(op, input, win); } - template <typename I, typename W> + template <typename Op, typename I, typename W> mln_concrete(I) - erosion_dispatch_for_generic(trait::image::kind::any, // On functions. + general_dispatch_for_generic(trait::image::kind::logic, // On sets. + trait::image::speed::fastest, // Fastest. + const Op& op, const I& input, const W& win) + { + if (win.is_centered()) + return impl::general_on_set_centered_fastest(op, input, win); + else + return impl::generic::general_on_set(op, input, win); + } + + template <typename Op, typename I, typename W> + mln_concrete(I) + general_dispatch_for_generic(trait::image::kind::any, // On functions. trait::image::speed::any, - const I& input, const W& win) + const Op& op, const I& input, const W& win) { - return impl::generic::erosion_on_function(input, win); + return impl::generic::general_on_function(op, input, win); } - template <typename I, typename W> + template <typename Op, typename I, typename W> mln_concrete(I) - erosion_dispatch_for_generic(const I& input, const W& win) // Entry point. + general_dispatch_for_generic(const Op& op, const I& input, const W& win) // Entry point. { - trace::entering("morpho::erosion_dispatch_for_generic"); + trace::entering("morpho::general_dispatch_for_generic"); mln_concrete(I) ima = - erosion_dispatch_for_generic(mln_trait_image_kind(I)(), + general_dispatch_for_generic(mln_trait_image_kind(I)(), mln_trait_image_speed(I)(), - input, win); - trace::entering("morpho::erosion_dispatch_for_generic"); + op, input, win); + trace::entering("morpho::general_dispatch_for_generic"); return ima; } @@ -357,25 +320,25 @@ // dispatch w.r.t. win - template <typename I, typename W> + template <typename Op, typename I, typename W> mln_concrete(I) - erosion_dispatch_wrt_arbitrary_win(metal::true_, - const I& input, const W& win) + general_dispatch_wrt_arbitrary_win(metal::true_, + const Op& op, const I& input, const W& win) { - return morpho::impl::erosion_arbitrary_2d(input, win); + return morpho::impl::general_arbitrary_2d(op, input, win); } - template <typename I, typename W> + template <typename Op, typename I, typename W> mln_concrete(I) - erosion_dispatch_wrt_arbitrary_win(metal::false_, - const I& input, const W& win) + general_dispatch_wrt_arbitrary_win(metal::false_, + const Op& op, const I& input, const W& win) { - return erosion_dispatch_for_generic(input, win); + return general_dispatch_for_generic(op, input, win); } - template <typename I, typename W> + template <typename Op, typename I, typename W> mln_concrete(I) - erosion_dispatch_wrt_win(const I& input, const W& win) + general_dispatch_wrt_win(const I& input, const W& win) { // FIXME: // The test "win.size() >= 10" (size is not too small) has been @@ -389,32 +352,32 @@ && mlc_not_equal(mln_trait_image_value_storage(I), trait::image::value_storage::disrupted)::value }; - return erosion_dispatch_wrt_arbitrary_win(metal::bool_<test>(), + return general_dispatch_wrt_arbitrary_win(metal::bool_<test>(), input, win); } - template <typename I> + template <typename Op, typename I> mln_concrete(I) - erosion_dispatch_wrt_win(const I& input, const win::rectangle2d& win) + general_dispatch_wrt_win(const Op& op, const I& input, const win::rectangle2d& win) { if (win.size() == 1) return clone(input); if (win.size() <= 9) // FIXME: Hard-coded! - return erosion_dispatch_for_generic(input, win); - return impl::erosion_rectangle2d(input, win); + return general_dispatch_for_generic(op, input, win); + return impl::general_rectangle2d(op, input, win); } - template <typename I> + template <typename Op, typename I> mln_concrete(I) - erosion_dispatch_wrt_win(const I& input, const win::octagon2d& win) + general_dispatch_wrt_win(const Op& op, const I& input, const win::octagon2d& win) { if (win.length() < 5) - return impl::erosion_arbitrary_2d(input, win); + return impl::general_arbitrary_2d(op, input, win); else - return impl::erosion_octagon2d(input, win); + return impl::general_octagon2d(op, input, win); } @@ -422,37 +385,37 @@ /// Handling win::line(s). /// \{ - template <typename I, typename W> + template <typename Op, typename I, typename W> mln_concrete(I) - erosion_dispatch_line(metal::true_, - const I& input, const W& win) + general_dispatch_line(metal::true_, + const Op& op, const I& input, const W& win) { - return impl::erosion_directional(input, win, W::dir); + return impl::general_directional(op, input, win, W::dir); } - template <typename I, typename W> + template <typename Op, typename I, typename W> mln_concrete(I) - erosion_dispatch_line(metal::false_, - const I& input, const W& win) + general_dispatch_line(metal::false_, + const Op& op, const I& input, const W& win) { - return erosion_dispatch_for_generic(input, win); + return general_dispatch_for_generic(op, input, win); } - template <typename I, typename M, unsigned i, typename C> + template <typename Op, typename I, typename M, unsigned i, typename C> mln_concrete(I) - erosion_dispatch_wrt_win(const I& input, const win::line<M,i,C>& win) + general_dispatch_wrt_win(const Op& op, const I& input, const win::line<M,i,C>& win) { if (win.size() == 1) return clone(input); else if (win.size() == 3) - return erosion_dispatch_for_generic(input, win); + return general_dispatch_for_generic(op, input, win); else { enum { test = mlc_is_a(mln_pset(I), Box)::value && mlc_equal(mln_trait_image_quant(I), mln::trait::image::quant::low)::value }; - return erosion_dispatch_line(metal::bool_<test>(), - input, win); + return general_dispatch_line(metal::bool_<test>(), + op, input, win); } } @@ -464,53 +427,53 @@ /// Handling diagonals. /// \{ - template <typename I, typename W> + template <typename Op, typename I, typename W> mln_concrete(I) - erosion_dispatch_diagonal(metal::true_, - const I& input, const W& win) + general_dispatch_diagonal(metal::true_, + const Op& op, const I& input, const W& win) { - return impl::erosion_diagonal_2d(input, win); + return impl::general_diagonal_2d(op, input, win); } - template <typename I, typename W> + template <typename Op, typename I, typename W> mln_concrete(I) - erosion_dispatch_diagonal(metal::false_, - const I& input, const W& win) + general_dispatch_diagonal(metal::false_, + const Op& op, const I& input, const W& win) { - return erosion_dispatch_for_generic(input, win); + return general_dispatch_for_generic(op, input, win); } - template <typename I, typename W> + template <typename Op, typename I, typename W> mln_concrete(I) - erosion_dispatch_diagonal(const I& input, const W& win) + general_dispatch_diagonal(const Op& op, const I& input, const W& win) { if (win.size() == 1) return clone(input); else if (win.size() == 3) - return erosion_dispatch_for_generic(input, win); + return general_dispatch_for_generic(op, input, win); else { enum { test = mlc_is_a(mln_pset(I), Box)::value && mlc_equal(mln_trait_image_quant(I), mln::trait::image::quant::low)::value }; - return erosion_dispatch_diagonal(metal::bool_<test>(), - input, win); + return general_dispatch_diagonal(metal::bool_<test>(), + op, input, win); } } - template <typename I> + template <typename Op, typename I> mln_concrete(I) - erosion_dispatch_wrt_win(const I& input, const win::diag2d& win) + general_dispatch_wrt_win(const Op& op, const I& input, const win::diag2d& win) { - return erosion_dispatch_diagonal(input, win); + return general_dispatch_diagonal(op, input, win); } - template <typename I> + template <typename Op, typename I> mln_concrete(I) - erosion_dispatch_wrt_win(const I& input, const win::backdiag2d& win) + general_dispatch_wrt_win(const Op& op, const I& input, const win::backdiag2d& win) { - return erosion_dispatch_diagonal(input, win); + return general_dispatch_diagonal(op, input, win); } /// \} @@ -519,11 +482,11 @@ // The dispatch entry point. - template <typename I, typename W> + template <typename Op, typename I, typename W> mln_concrete(I) - erosion_dispatch(const Image<I>& input, const Window<W>& win) + general_dispatch(const Op& op, const Image<I>& input, const Window<W>& win) { - return erosion_dispatch_wrt_win(exact(input), exact(win)); + return general_dispatch_wrt_win(op, exact(input), exact(win)); } } // end of namespace mln::morpho::internal @@ -535,4 +498,4 @@ # endif // ! MLN_INCLUDE_ONLY -#endif // ! MLN_MORPHO_EROSION_SPE_HH +#endif // ! MLN_MORPHO_GENERAL_SPE_HH Index: mln/morpho/general.hh --- mln/morpho/general.hh (revision 2970) +++ mln/morpho/general.hh (working copy) @@ -26,17 +26,28 @@ // reasons why the executable file might be covered by the GNU General // Public License. -#ifndef MLN_MORPHO_EROSION_HH -# define MLN_MORPHO_EROSION_HH +#ifndef MLN_MORPHO_GENERAL_HH +# define MLN_MORPHO_GENERAL_HH -/// \file mln/morpho/erosion.hh +/// \file mln/morpho/general.hh /// -/// \brief Morphological erosion. +/// Morphological general routine with dispatch. +/// +/// \todo Have infimum and supremum for value types, apart from +/// morphology! # include <mln/morpho/includes.hh> // Specializations are in: -# include <mln/morpho/erosion.spe.hh> +# include <mln/morpho/general.spe.hh> + + + +# define mln_morpho_select_accu(I, S, F) \ +typename mln::metal::if_< mln::metal::is< mln_trait_image_kind(I), \ + trait::image::kind::binary >, \ + mln::accu::meta::S, \ + mln::accu::meta::F >::ret namespace mln @@ -45,11 +56,10 @@ namespace morpho { - /*! Morphological erosion. - */ - template <typename I, typename W> + /// Morphological general routine. + template <typename Op, typename I, typename W> mln_concrete(I) - erosion(const Image<I>& input, const Window<W>& win); + general(const Op& op, const Image<I>& input, const Window<W>& win); # ifndef MLN_INCLUDE_ONLY @@ -58,10 +68,10 @@ namespace internal { - template <typename I, typename W> + template <typename Op, typename I, typename W> inline void - erosion_tests(const Image<I>& input_, const Window<W>& win_) + general_tests(const Op& op, const Image<I>& input_, const Window<W>& win_) { const I& input = exact(input_); const W& win = exact(win_); @@ -70,10 +80,31 @@ mln_precondition(! win.is_empty()); // mln_precondition(win.is_valid()); + (void) op; (void) input; (void) win; } + + // Temporary code; see 'todo' above. + template <typename I, bool is_binary> // true + struct neutral_impl + { + static mln_value(I) infimum() { return false; } + static mln_value(I) supremum() { return true; } + }; + template <typename I> + struct neutral_impl< I, false > + { + static mln_value(I) infimum() { return mln_min(mln_value(I)); } + static mln_value(I) supremum() { return mln_max(mln_value(I)); } + }; + template <typename I> + struct neutral : neutral_impl< I, mlc_is(mln_trait_image_kind(I), + trait::image::kind::binary)::value > + { + }; + } // end of mln::morpho::internal @@ -86,39 +117,39 @@ // On function. - template <typename I, typename W> + template <typename Op, typename I, typename W> inline mln_concrete(I) - erosion_on_function(const Image<I>& input, const Window<W>& win) + general_on_function(const Op& op, const Image<I>& input, const Window<W>& win) { - trace::entering("morpho::impl::generic::erosion_on_function"); + trace::entering("morpho::impl::generic::general_on_function"); - internal::erosion_tests(input, win); + internal::general_tests(op, input, win); - extension::adjust_fill(input, win, mln_max(mln_value(I))); + extension::adjust_fill(input, win, op.neutral(input)); mln_concrete(I) output; - output = accu::transform(input, accu::meta::min(), win); + output = accu::transform(input, op.accu(input), win); - trace::exiting("morpho::impl::generic::erosion_on_function"); + trace::exiting("morpho::impl::generic::general_on_function"); return output; } // On set. - template <typename I, typename W> + template <typename Op, typename I, typename W> inline mln_concrete(I) - erosion_on_set(const Image<I>& input, const Window<W>& win) + general_on_set(const Op& op, const Image<I>& input, const Window<W>& win) { - trace::entering("morpho::impl::generic::erosion_on_set"); + trace::entering("morpho::impl::generic::general_on_set"); - internal::erosion_tests(input, win); + internal::general_tests(op, input, win); - extension::adjust_fill(input, win, true); + extension::adjust_fill(input, win, op.neutral(input)); mln_concrete(I) output; - output = accu::transform_stop(input, accu::land_basic(), win); + output = accu::transform_stop(input, op.accu(input), win); - trace::exiting("morpho::impl::generic::erosion_on_set"); + trace::exiting("morpho::impl::generic::general_on_set"); return output; } @@ -130,21 +161,21 @@ // Facades. - template <typename I, typename W> + template <typename Op, typename I, typename W> inline mln_concrete(I) - erosion(const Image<I>& input, const Window<W>& win) + general(const Op& op, const Image<I>& input, const Window<W>& win) { - trace::entering("morpho::erosion"); + trace::entering("morpho::general"); mln_precondition(exact(input).has_data()); mln_precondition(! exact(win).is_empty()); - internal::erosion_tests(input, win); - mln_concrete(I) output = internal::erosion_dispatch(input, win); + internal::general_tests(op, input, win); + mln_concrete(I) output = internal::general_dispatch(op, input, win); if (exact(win).is_centered()) mln_postcondition(output <= input); - trace::exiting("morpho::erosion"); + trace::exiting("morpho::general"); return output; } @@ -155,4 +186,4 @@ } // end of namespace mln -#endif // ! MLN_MORPHO_EROSION_HH +#endif // ! MLN_MORPHO_GENERAL_HH