https://svn.lrde.epita.fr/svn/oln/trunk/milena/sandbox
Index: ChangeLog
from Thierry Geraud <thierry.geraud(a)lrde.epita.fr>
Add new morphological operators.
* theo/mln/morpho/reconstruction: New directory.
* theo/mln/morpho/reconstruction/by_dilation.cc: New.
* theo/mln/morpho/reconstruction/by_dilation_tiny.cc: New.
* theo/mln/morpho/reconstruction/by_dilation.hh: New.
* theo/mln/morpho/geodesic/dilation.hh: Fix layout.
Fix typo in postconditions.
* theo/mln/morpho/geodesic/dilation_permissive.hh (todo): New.
(nota): New.
(FIXME): New.
* theo/mln/morpho/max.hh: New.
* theo/mln/morpho/conditional: New directory.
* theo/mln/morpho/conditional/dilation.hh: New.
* theo/mln/morpho/conditional/dilation.cc: New.
conditional/dilation.cc | 29 +
conditional/dilation.hh | 111 +++++
geodesic/dilation.hh | 4
geodesic/dilation_permissive.hh | 17
max.hh | 59 +-
reconstruction/by_dilation.cc | 68 +++
reconstruction/by_dilation.hh | 778 +++++++++++++++++++++++++++++++++++++
reconstruction/by_dilation_tiny.cc | 71 +++
8 files changed, 1106 insertions(+), 31 deletions(-)
Index: theo/mln/morpho/reconstruction/by_dilation.cc
--- theo/mln/morpho/reconstruction/by_dilation.cc (revision 0)
+++ theo/mln/morpho/reconstruction/by_dilation.cc (revision 0)
@@ -0,0 +1,68 @@
+#include <mln/core/image/image2d.hh>
+#include <mln/core/alias/neighb2d.hh>
+#include <mln/debug/println.hh>
+#include <mln/io/pbm/load.hh>
+#include <mln/io/pbm/save.hh>
+# include <mln/util/timer.hh>
+
+#include "by_dilation.hh"
+
+
+int main()
+{
+ using namespace mln;
+
+ image2d<bool> f, g, o;
+ neighb2d nbh = c4();
+
+ io::pbm::load(f, "f_and_g.pbm");
+ io::pbm::load(g, "g.pbm");
+
+ float t_tufa, t_tufa_alt, t_tufa_fast, t_hybrid, t_hybrid_2, t_hybrid_fast;
+ util::timer t;
+
+ {
+ t.start();
+ o = morpho::reconstruction::impl::by_dilation_tufa_on_set(f, g, nbh);
+ t_tufa = t.stop();
+ }
+
+ {
+ t.start();
+ o = morpho::reconstruction::impl::by_dilation_tufa_on_set_alt(f, g, nbh);
+ t_tufa_alt = t.stop();
+ }
+
+ {
+ t.start();
+ o = morpho::reconstruction::impl::by_dilation_hybrid_on_set(f, g, nbh);
+ t_hybrid = t.stop();
+ }
+
+ {
+ t.start();
+ o = morpho::reconstruction::impl::by_dilation_hybrid_on_set__two_loops(f, g, nbh);
+ t_hybrid_2 = t.stop();
+ }
+
+ {
+ t.start();
+ o = morpho::reconstruction::impl::by_dilation_tufa_on_set_fastest(f, g, nbh);
+ t_tufa_fast = t.stop();
+ }
+
+ {
+ t.start();
+ o = morpho::reconstruction::impl::by_dilation_hybrid_on_set_fastest(f, g, nbh);
+ t_hybrid_fast = t.stop();
+ }
+
+ std::cout << "tufa " << t_tufa << std::endl
+ << "tufa_alt " << t_tufa_alt << std::endl
+ << "hybrid " << t_hybrid << std::endl
+ << "hybrid two loops " << t_hybrid_2 << std::endl
+ << "tufa_fast " << t_tufa_fast << std::endl
+ << "hybrid_fast " << t_hybrid_fast << std::endl;
+
+ io::pbm::save(o, "o.pbm");
+}
Index: theo/mln/morpho/reconstruction/by_dilation_tiny.cc
--- theo/mln/morpho/reconstruction/by_dilation_tiny.cc (revision 0)
+++ theo/mln/morpho/reconstruction/by_dilation_tiny.cc (revision 0)
@@ -0,0 +1,71 @@
+#include <mln/core/image/image2d.hh>
+#include <mln/core/alias/neighb2d.hh>
+#include <mln/debug/println.hh>
+#include <mln/io/pbm/load.hh>
+#include <mln/io/pbm/save.hh>
+
+#include "by_dilation.hh"
+
+
+int main()
+{
+ using namespace mln;
+
+ image2d<bool> f, g, o;
+ neighb2d nbh = c4();
+
+ bool gvals[9][5] = { { 0, 1, 1, 1, 0 },
+ { 0, 0, 0, 1, 0 },
+ { 0, 1, 1, 1, 0 },
+ { 0, 1, 0, 0, 0 },
+ { 0, 1, 1, 1, 0 },
+ { 0, 0, 0, 1, 0 },
+ { 0, 1, 1, 1, 0 },
+ { 0, 1, 0, 0, 0 },
+ { 0, 1, 1, 1, 0 } };
+ g = make::image(gvals);
+ debug::println("g", g);
+
+ bool fvals[9][5] = { { 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0 },
+ { 0, 0, 1, 0, 0 },
+ { 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0 } };
+ f = make::image(fvals);
+ debug::println("f", f);
+
+ o = morpho::reconstruction::impl::by_dilation_hybrid_on_set_fastest(f, g, nbh);
+}
+
+
+
+
+/*
+ bool gvals[9][5] = { { 0, 0, 0, 0, 0 },
+ { 0, 1, 1, 0, 0 },
+ { 0, 1, 0, 0, 0 },
+ { 0, 1, 1, 1, 0 },
+ { 0, 0, 0, 1, 0 },
+ { 0, 1, 1, 1, 0 },
+ { 0, 1, 0, 0, 0 },
+ { 0, 1, 1, 1, 0 },
+ { 0, 0, 0, 0, 0 } };
+ g = make::image(gvals);
+ debug::println("g", g);
+
+ bool fvals[9][5] = { { 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0 },
+ { 0, 0, 1, 0, 0 },
+ { 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0 } };
+ f = make::image(fvals);
+ debug::println("f", f);
+*/
Index: theo/mln/morpho/reconstruction/by_dilation.hh
--- theo/mln/morpho/reconstruction/by_dilation.hh (revision 0)
+++ theo/mln/morpho/reconstruction/by_dilation.hh (revision 0)
@@ -0,0 +1,778 @@
+// Copyright (C) 2009 EPITA Research and Development Laboratory (LRDE)
+//
+// This file is part of Olena.
+//
+// Olena is free software: you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation, version 2 of the License.
+//
+// Olena 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 Olena. If not, see <http://www.gnu.org/licenses/>.
+//
+// As a special exception, you may use this file as part of a free
+// software project 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.
+
+#ifndef MLN_MORPHO_RECONSTRUCTION_BY_DILATION_HH
+# define MLN_MORPHO_RECONSTRUCTION_BY_DILATION_HH
+
+# include <mln/core/concept/image.hh>
+# include <mln/core/concept/neighborhood.hh>
+# include <mln/data/fill.hh>
+# include <mln/data/compare.hh>
+# include <mln/border/equalize.hh>
+# include <mln/border/fill.hh>
+
+# include <mln/core/site_set/p_queue.hh>
+# include <mln/debug/println.hh>
+
+
+
+namespace mln
+{
+
+ namespace morpho
+ {
+
+ namespace reconstruction
+ {
+
+ template <typename I, typename J, typename N>
+ mln_concrete(I)
+ by_dilation(const Image<I>& f, const Image<J>& g,
+ const Neighborhood<N>& nbh);
+
+
+# ifndef MLN_INCLUDE_ONLY
+
+
+ // Tests.
+
+ namespace internal
+ {
+
+ template <typename I, typename J, typename N>
+ inline
+ void
+ by_dilation_tests(const Image<I>& f_, const Image<J>& g_,
+ const Neighborhood<N>& nbh_)
+ {
+ const I& f = exact(f_);
+ const J& g = exact(g_);
+ const N& nbh = exact(nbh_);
+
+ mln_precondition(f.is_valid());
+ mln_precondition(g.is_valid());
+ mln_precondition(nbh.is_valid());
+
+ mln_precondition(f.domain() == g.domain()); // FIXME: Relax?
+ mln_precondition(f <= g);
+
+ // mlc_equal(mln_value(I), mln_value(J))::check(); // FIXME: Too strong!
+ // FIXME: Also check that we have a total ordering for values.
+
+ (void) f;
+ (void) g;
+ (void) nbh;
+ }
+
+
+
+ template <typename Par>
+ inline
+ mln_site(Par) find_root(Par& parent, mln_site(Par) x)
+ {
+ if (parent(x) == x)
+ return x;
+ else
+ return parent(x) = find_root(parent, parent(x));
+ }
+
+ template <typename Par>
+ inline
+ unsigned find_root_fastest(Par& parent, unsigned x)
+ {
+ if (parent.element(x) == x)
+ return x;
+ else
+ return parent.element(x) = find_root_fastest(parent, parent.element(x));
+ }
+
+ } // end of namespace mln::morpho::reconstruction::internal
+
+
+
+ // Implementations.
+
+ namespace impl
+ {
+
+
+ template <typename I, typename J, typename N>
+ inline
+ mln_concrete(I)
+ by_dilation_tufa_on_set(const Image<I>& f_, const Image<J>& g_,
+ const Neighborhood<N>& nbh_)
+ {
+ trace::entering("morpho::reconstruction::impl::by_dilation_tufa_on_set");
+
+ const I& f = exact(f_);
+ const J& g = exact(g_);
+ const N& nbh = exact(nbh_);
+
+ internal::by_dilation_tests(f, g, nbh);
+
+ typedef mln_site(I) P;
+ typedef mln_value(I) V;
+
+ // Auxiliary data.
+ mln_ch_value(I, bool) deja_vu;
+ mln_ch_value(I, P) parent;
+ mln_concrete(I) output;
+
+ // Initialization.
+ {
+ initialize(parent, f);
+ initialize(deja_vu, f);
+ initialize(output, f);
+
+ data::fill(deja_vu, false);
+ data::fill(output, false);
+ }
+
+ // First pass.
+ {
+ mln_fwd_piter(I) p(f.domain());
+ mln_niter(N) n(nbh, p);
+ for_all(p)
+ if (g(p)) // <- D'
+ {
+ // Make-Set.
+ parent(p) = p;
+ output(p) = f(p); // <-- INIT
+
+ for_all(n) if (f.domain().has(n))
+ {
+ if (g(n) // <- D'
+ && deja_vu(n))
+ {
+ // Do-Union.
+ P r = internal::find_root(parent, n);
+ if (r != p)
+ {
+ // set_parent, i.e., union
+ parent(r) = p;
+ output(p) = output(p) || output(r); // <-- MERGE
+ }
+ }
+ else
+ ; // <-- BORDER
+ }
+ deja_vu(p) = true;
+ }
+ }
+
+ // Second pass.
+ {
+ mln_bkd_piter(I) p(f.domain());
+ for_all(p)
+ if (g(p)) // <- D'
+ if (parent(p) != p)
+ output(p) = output(parent(p));
+ }
+
+ mln_postcondition(output >= f);
+ mln_postcondition(output <= g);
+
+ trace::exiting("morpho::reconstruction::impl::by_dilation_tufa_on_set");
+ return output;
+ }
+
+
+ template <typename I, typename J, typename N>
+ inline
+ mln_concrete(I)
+ by_dilation_tufa_on_set_fastest(const Image<I>& f_, const Image<J>&
g_,
+ const Neighborhood<N>& nbh_)
+ {
+
trace::entering("morpho::reconstruction::impl::by_dilation_tufa_on_set_fastest");
+
+ const I& f = exact(f_);
+ const J& g = exact(g_);
+ const N& nbh = exact(nbh_);
+
+ internal::by_dilation_tests(f, g, nbh);
+
+ typedef mln_site(I) P;
+ typedef mln_value(I) V;
+
+ // Auxiliary data.
+ mln_ch_value(I, bool) deja_vu;
+ mln_ch_value(I, unsigned) parent;
+ mln_concrete(I) output;
+
+ // Initialization.
+ {
+ border::equalize(f, g, nbh.delta());
+ border::fill(g, false);
+ initialize(parent, f);
+ initialize(output, f);
+
+ data::fill(output, false);
+ }
+
+ util::array<int> dp = negative_offsets_wrt(f, nbh);
+ const unsigned n_nbhs = dp.nelements();
+
+ // First pass.
+ {
+ mln_fwd_pixter(const I) pxl(f);
+ for_all(pxl)
+ {
+ unsigned p = pxl.offset();
+ if (g.element(p)) // <- D'
+ {
+ // Make-Set.
+ parent.element(p) = p;
+ output.element(p) = f.element(p); // <-- INIT
+
+ for (unsigned j = 0; j < n_nbhs; ++j)
+ {
+ unsigned n = p + dp[j];
+ if (g.element(n)) // <- D'
+ {
+ // Do-Union.
+ unsigned r = internal::find_root_fastest(parent, n);
+ if (r != p)
+ {
+ // set_parent, i.e., union
+ parent.element(r) = p;
+ output.element(p) = output.element(p) || output.element(r); // <-- MERGE
+ }
+ }
+ else
+ ; // <-- BORDER
+ }
+ }
+ }
+ }
+
+ // Second pass.
+ {
+ mln_bkd_pixter(const I) pxl(f);
+ for_all(pxl)
+ {
+ unsigned p = pxl.offset();
+ if (g.element(p)) // <- D'
+ if (parent.element(p) != p)
+ output.element(p) = output.element(parent.element(p));
+ }
+ }
+
+ mln_postcondition(output >= f);
+ mln_postcondition(output <= g);
+
+
trace::exiting("morpho::reconstruction::impl::by_dilation_tufa_on_set_fastest");
+ return output;
+ }
+
+
+
+
+ template <typename I, typename J, typename N>
+ inline
+ mln_concrete(I)
+ by_dilation_tufa_on_set_alt(const Image<I>& f_, const Image<J>& g_,
+ const Neighborhood<N>& nbh_)
+ {
+
trace::entering("morpho::reconstruction::impl::by_dilation_tufa_on_set_alt");
+
+ const I& f = exact(f_);
+ const J& g = exact(g_);
+ const N& nbh = exact(nbh_);
+
+ internal::by_dilation_tests(f, g, nbh);
+
+ typedef mln_site(I) P;
+ typedef mln_value(I) V;
+
+ // Auxiliary data.
+ mln_ch_value(I, bool) deja_vu;
+ mln_ch_value(I, P) parent;
+ mln_concrete(I) output;
+
+ // Initialization.
+ {
+ initialize(parent, f);
+ initialize(deja_vu, f);
+ initialize(output, f);
+
+ data::fill(deja_vu, false);
+ data::fill(output, f);
+ }
+
+ // First pass.
+ {
+ mln_fwd_piter(I) p(f.domain());
+ mln_niter(N) n(nbh, p);
+ for_all(p)
+ if (g(p) && ! f(p)) // <- D'
+ {
+ // Make-Set.
+ parent(p) = p;
+ output(p) = false; // <-- INIT
+
+ for_all(n) if (f.domain().has(n))
+ {
+ if (g(n) && ! f(n) // <- D'
+ && deja_vu(n))
+ {
+ // Do-Union.
+ P r = internal::find_root(parent, n);
+ if (r != p)
+ {
+ // set_parent, i.e., union
+ parent(r) = p;
+ output(p) = output(p) || output(r); // <-- MERGE
+ }
+ }
+ else
+ if (f(n))
+ output(p) = true; // <-- BORDER
+ }
+ deja_vu(p) = true;
+ }
+ }
+
+ // Second pass.
+ {
+ mln_bkd_piter(I) p(f.domain());
+ for_all(p)
+ if (g(p) && ! f(p)) // <-
D'
+ if (parent(p) != p)
+ output(p) = output(parent(p));
+ }
+
+ mln_postcondition(output >= f);
+ mln_postcondition(output <= g);
+
+
trace::exiting("morpho::reconstruction::impl::by_dilation_tufa_on_set_alt");
+ return output;
+ }
+
+
+
+
+ template <typename I, typename J, typename N>
+ inline
+ mln_concrete(I)
+ by_dilation_hybrid_on_set(const Image<I>& f_, const Image<J>& g_,
+ const Neighborhood<N>& nbh_)
+ {
+ trace::entering("morpho::reconstruction::impl::by_dilation_hybrid_on_set");
+
+ // Both loops (just below) are merged into a single one
+ // in the implementation below. This merge results in
+ // -10% at run-time.
+
+ // // Sequence---Forth.
+ // {
+ // data::fill(deja_vu, false);
+ // mln_fwd_piter(I) p(f.domain());
+ // mln_niter(N) n(nbh, p);
+ // for_all(p)
+ // {
+ // if (g(p) && ! output(p))
+ // {
+ // for_all(n)
+ // if (f.domain().has(n) && deja_vu(n) // N+
+ // && g(n) && output(n))
+ // {
+ // output(p) = true;
+ // break;
+ // }
+ // }
+ // if (output(p))
+ // {
+ // for_all(n)
+ // if (f.domain().has(n) && deja_vu(n) // N+
+ // && output(n) == false && g(n) == true)
+ // {
+ // q.push(p);
+ // break;
+ // }
+ // }
+ // }
+ // }
+
+ const I& f = exact(f_);
+ const J& g = exact(g_);
+ const N& nbh = exact(nbh_);
+
+ internal::by_dilation_tests(f, g, nbh);
+
+ typedef mln_value(I) V;
+ typedef mln_psite(I) P;
+ p_queue<P> q;
+
+ // Initialisation.
+ mln_concrete(I) output = duplicate(f);
+ mln_ch_value(I, bool) deja_vu;
+ initialize(deja_vu, f);
+
+ // Sequence---Back.
+ {
+ data::fill(deja_vu, false);
+ mln_bkd_piter(I) p(f.domain());
+ mln_niter(N) n(nbh, p);
+ for_all(p)
+ {
+ if (g(p) && ! output(p))
+ {
+ for_all(n)
+ if (f.domain().has(n) && deja_vu(n) // N-
+ && g(n) && output(n))
+ {
+ output(p) = true;
+ break;
+ }
+ }
+ deja_vu(p) = true;
+ }
+ }
+
+ // Sequence---Forth.
+ {
+ data::fill(deja_vu, false);
+ mln_fwd_piter(I) p(f.domain());
+ mln_niter(N) n(nbh, p);
+ for_all(p)
+ {
+ if (g(p) && ! output(p))
+ {
+ bool queueable = false;
+ for_all(n)
+ if (f.domain().has(n) && deja_vu(n) // N+
+ && g(n))
+ {
+ if (output(n))
+ output(p) = true;
+ else
+ queueable = true;
+ }
+ if (output(p) && queueable)
+ q.push(p); // Need for propagation from p.
+ }
+
+ deja_vu(p) = true;
+ }
+ }
+
+ // Propagation.
+ {
+ P p;
+ mln_niter(N) n(nbh, p);
+ while (! q.is_empty())
+ {
+ p = q.pop_front();
+ mln_invariant(output(p) == true);
+ for_all(n)
+ if (f.domain().has(n)
+ && output(n) == false && g(n) == true)
+ {
+ output(n) = true;
+ q.push(n);
+ }
+ }
+ }
+
+ trace::exiting("morpho::reconstruction::impl::by_dilation_hybrid_on_set");
+ return output;
+ }
+
+
+ template <typename I, typename J, typename N>
+ inline
+ mln_concrete(I)
+ by_dilation_hybrid_on_set_fastest(const Image<I>& f_, const
Image<J>& g_,
+ const Neighborhood<N>& nbh_)
+ {
+
trace::entering("morpho::reconstruction::impl::by_dilation_hybrid_on_set_fastest");
+
+ const I& f = exact(f_);
+ const J& g = exact(g_);
+ const N& nbh = exact(nbh_);
+
+ internal::by_dilation_tests(f, g, nbh);
+
+ typedef mln_value(I) V;
+ typedef mln_psite(I) P;
+ p_queue<unsigned> q;
+
+ // Initialisation.
+ border::equalize(f, g, nbh.delta());
+ mln_concrete(I) output = duplicate(f);
+
+ util::array<int> dp = negative_offsets_wrt(f, nbh);
+ unsigned n_nbhs = dp.nelements();
+
+ // Sequence---Back.
+ {
+ mln_bkd_pixter(const I) pxl(f);
+ for_all(pxl)
+ {
+ unsigned p = pxl.offset();
+ if (g.element(p) && ! output.element(p))
+ {
+ for (unsigned j = 0; j < n_nbhs; ++j)
+ {
+ unsigned n = p - dp[j]; // n in N-
+ if (g.element(n) && output.element(n))
+ {
+ output.element(p) = true;
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ // debug::println("output (back)", output);
+
+ // Sequence---Forth.
+ {
+ mln_fwd_pixter(const I) pxl(f);
+ for_all(pxl)
+ {
+ unsigned p = pxl.offset();
+ if (g.element(p) && ! output.element(p))
+ {
+ bool queueable = false;
+ for (unsigned j = 0; j < n_nbhs; ++j)
+ {
+ unsigned n = p + dp[j]; // n in N+
+ if (g.element(n))
+ {
+ if (output.element(n))
+ output.element(p) = true;
+ else
+ queueable = true;
+ }
+ }
+ if (output.element(p) && queueable)
+ q.push(p); // Need for propagation from p.
+ }
+ }
+ }
+
+ // debug::println("output (forth)", output);
+ // std::cout << q << std::endl;
+
+ // Propagation.
+ {
+ dp = offsets_wrt(f, nbh);
+ n_nbhs = dp.nelements();
+
+ unsigned p;
+ while (! q.is_empty())
+ {
+ p = q.pop_front();
+ mln_invariant(output.element(p) == true);
+ for (unsigned j = 0; j < n_nbhs; ++j)
+ {
+ unsigned n = p + dp[j]; // n in N
+ if (output.element(n) == false && g.element(n) == true)
+ {
+ output.element(n) = true;
+ q.push(n);
+ }
+ }
+ }
+ }
+
+ // debug::println("output (propag)", output);
+
+
trace::exiting("morpho::reconstruction::impl::by_dilation_hybrid_on_set_fastest");
+ return output;
+ }
+
+
+
+
+
+
+
+ template <typename I, typename J, typename N>
+ inline
+ mln_concrete(I)
+ by_dilation_hybrid_on_set__two_loops(const Image<I>& f_, const
Image<J>& g_,
+ const Neighborhood<N>& nbh_)
+ {
+
trace::entering("morpho::reconstruction::impl::by_dilation_hybrid_on_set__two_loops");
+
+ const I& f = exact(f_);
+ const J& g = exact(g_);
+ const N& nbh = exact(nbh_);
+
+ internal::by_dilation_tests(f, g, nbh);
+
+ typedef mln_value(I) V;
+ typedef mln_psite(I) P;
+ p_queue<P> q;
+
+ // Initialisation.
+ mln_concrete(I) output = duplicate(f);
+ mln_ch_value(I, bool) deja_vu;
+ initialize(deja_vu, f);
+
+ // Sequence---Back.
+ {
+ data::fill(deja_vu, false);
+ mln_bkd_piter(I) p(f.domain());
+ mln_niter(N) n(nbh, p);
+ for_all(p)
+ {
+ if (g(p) && ! output(p))
+ {
+ for_all(n)
+ if (f.domain().has(n) && deja_vu(n) // N-
+ && g(n) && output(n))
+ {
+ output(p) = true;
+ break;
+ }
+ }
+ deja_vu(p) = true;
+ }
+ }
+
+
+ // Sequence---Forth.
+ {
+ data::fill(deja_vu, false);
+ mln_fwd_piter(I) p(f.domain());
+ mln_niter(N) n(nbh, p);
+ for_all(p)
+ {
+ if (g(p) && ! output(p))
+ {
+ for_all(n)
+ if (f.domain().has(n) && deja_vu(n) // N+
+ && g(n) && output(n))
+ {
+ output(p) = true;
+ break;
+ }
+ }
+ if (output(p))
+ {
+ for_all(n)
+ if (f.domain().has(n) && deja_vu(n) // N+
+ && output(n) == false && g(n) == true)
+ {
+ q.push(p);
+ break;
+ }
+ }
+ }
+ }
+
+
+ // Propagation.
+ {
+ P p;
+ mln_niter(N) n(nbh, p);
+ while (! q.is_empty())
+ {
+ p = q.pop_front();
+ mln_invariant(output(p) == true);
+ for_all(n)
+ if (f.domain().has(n)
+ && output(n) == false && g(n) == true)
+ {
+ output(n) = true;
+ q.push(n);
+ }
+ }
+ }
+
+
trace::exiting("morpho::reconstruction::impl::by_dilation_hybrid_on_set__two_loops");
+ return output;
+ }
+
+
+
+
+
+
+ } // end of namespace mln::morpho::reconstruction::impl
+
+
+
+ // Dispatch.
+
+ namespace internal
+ {
+
+ template <typename I, typename J, typename N>
+ inline
+ mln_concrete(I)
+ by_dilation_dispatch(trait::image::kind::logic,
+ const Image<I>& f, const Image<J>& g,
+ const Neighborhood<N>& nbh)
+ {
+ return impl::by_dilation_tufa_on_set(f, g, nbh); // FIXME
+ }
+
+ template <typename I, typename J, typename N>
+ inline
+ mln_concrete(I)
+ by_dilation_dispatch(const Image<I>& f, const Image<J>& g,
+ const Neighborhood<N>& nbh)
+ {
+ return by_dilation_dispatch(mln_trait_image_kind(I)(),
+ f, g, nbh);
+ }
+
+ } // end of namespace mln::morpho::reconstruction::internal
+
+
+ // Facade.
+
+ template <typename I, typename J, typename N>
+ inline
+ mln_concrete(I)
+ by_dilation(const Image<I>& f, const Image<J>& g,
+ const Neighborhood<N>& nbh)
+ {
+ trace::entering("morpho::reconstruction::by_dilation");
+
+ internal::by_dilation_tests(f, g, nbh);
+
+ mln_concrete(I) output;
+ output = internal::by_dilation_dispatch(f, g, nbh);
+
+ trace::exiting("morpho::reconstruction::by_dilation");
+ return output;
+ }
+
+# endif // ! MLN_INCLUDE_ONLY
+
+ } // end of namespace mln::morpho::reconstruction
+
+ } // end of namespace mln::morpho
+
+} // end of namespace mln
+
+
+#endif // ! MLN_MORPHO_RECONSTRUCTION_BY_DILATION_HH
Index: theo/mln/morpho/geodesic/dilation.hh
--- theo/mln/morpho/geodesic/dilation.hh (revision 4638)
+++ theo/mln/morpho/geodesic/dilation.hh (working copy)
@@ -69,8 +69,8 @@
mln_concrete(I) output;
output = internal::dilation_permissive_dispatch(f, g, nbh, n);
- mln_precondition(output >= f);
- mln_precondition(output <= g);
+ mln_postcondition(output >= f);
+ mln_postcondition(output <= g);
trace::exiting("morpho::geodesic::dilation");
return output;
Index: theo/mln/morpho/geodesic/dilation_permissive.hh
--- theo/mln/morpho/geodesic/dilation_permissive.hh (revision 4638)
+++ theo/mln/morpho/geodesic/dilation_permissive.hh (working copy)
@@ -29,6 +29,13 @@
/// \file
///
/// Morphological geodesic dilation; permissive version.
+///
+/// \todo We should add some other implementations for size n > 1. We
+/// have the iterative version (dilation_permissive_n); we should also
+/// have at least the front-base version...
+///
+/// \todo We should use a point-wise morpho::sup instead of
+/// fun::vv2v::max.
# include <mln/morpho/includes.hh>
# include <mln/morpho/elementary/dilation.hh>
@@ -54,6 +61,9 @@
const Neighborhood<N>& nbh,
unsigned n = 1);
+ // Nota bene : We have
+ // dilation permissive (f, g) = dilation strict (f inter g, g) union (f and not
g).
+
# ifndef MLN_INCLUDE_ONLY
@@ -429,6 +439,13 @@
mln_concrete(I) output;
output = internal::dilation_permissive_dispatch(f, g, nbh, n);
+ mln_postcondition(output >= f);
+
+ // FIXME: Is the post-condition bellow correct and sufficient?
+ // mln_postcondition(morpho::minus(output, f) <= g);
+ // FIXME: What about this other one below?
+ // mln_postcondition(output <= morpho::max(f, g));
+
trace::exiting("morpho::geodesic::dilation_permissive");
return output;
}
Index: theo/mln/morpho/max.hh
--- theo/mln/morpho/max.hh (revision 4636)
+++ theo/mln/morpho/max.hh (working copy)
@@ -23,19 +23,20 @@
// exception does not however invalidate any other reasons why the
// executable file might be covered by the GNU General Public License.
-#ifndef MLN_MORPHO_MIN_HH
-# define MLN_MORPHO_MIN_HH
+#ifndef MLN_MORPHO_MAX_HH
+# define MLN_MORPHO_MAX_HH
/*!
* \file
*
- * \brief Definition of a function that make a min
- * (logical and or arithmetical min) of an image.
+ * \brief Definition of a function that performs a point-wise operator
+ * on a couple of images: a logical 'or' in the case of binary images
+ * (sets), a 'max' otherwise (functions).
*/
# include <mln/data/compare.hh>
-# include <mln/logical/and.hh>
-# include <mln/arith/min.hh>
+# include <mln/logical/or.hh>
+# include <mln/arith/max.hh>
namespace mln
@@ -44,20 +45,20 @@
namespace morpho
{
- /*! Morphological min: either a logical "and" (if morpho on sets)
- * or an arithmetical min (if morpho on functions).
+ /*! Morphological max: either a logical "or" (if morpho on sets)
+ * or an arithmetical max (if morpho on functions).
*/
template <typename I, typename J>
mln_concrete(I)
- min(const Image<I>& lhs, const Image<J>& rhs);
+ max(const Image<I>& lhs, const Image<J>& rhs);
- /*! Morphological min, inplace version: either a logical "and" (if
- * morpho on sets) or an arithmetical min (if morpho on
+ /*! Morphological max, inplace version: either a logical "or" (if
+ * morpho on sets) or an arithmetical max (if morpho on
* functions).
*/
template <typename I, typename J>
- void min_inplace(Image<I>& lhs, const Image<J>& rhs);
+ void max_inplace(Image<I>& lhs, const Image<J>& rhs);
# ifndef MLN_INCLUDE_ONLY
@@ -69,36 +70,36 @@
template <typename I, typename J, typename O>
inline
- mln_concrete(I) min_(trait::image::kind::logic,
+ mln_concrete(I) max_(trait::image::kind::logic,
const I& lhs, const J& rhs)
{
- return logical::and_(lhs, rhs);
+ return logical::or_(lhs, rhs);
}
template <typename I, typename J>
inline
- void min_inplace_(trait::image::kind::logic,
+ void max_inplace_(trait::image::kind::logic,
I& lhs, const J& rhs)
{
- logical::and_inplace(lhs, rhs);
+ logical::or_inplace(lhs, rhs);
}
// Otherwise => morphology on functions.
template <typename I, typename J>
inline
- mln_concrete(I) min_(trait::image::kind::any,
+ mln_concrete(I) max_(trait::image::kind::any,
const I& lhs, const J& rhs)
{
- return arith::min(lhs, rhs);
+ return arith::max(lhs, rhs);
}
template <typename I, typename J>
inline
- void min_inplace_(trait::image::kind::any,
+ void max_inplace_(trait::image::kind::any,
I& lhs, const J& rhs)
{
- arith::min_inplace(lhs, rhs);
+ arith::max_inplace(lhs, rhs);
}
} // end of namespace mln::morpho::impl
@@ -109,27 +110,27 @@
template <typename I, typename J>
inline
mln_concrete(I)
- min(const Image<I>& lhs, const Image<J>& rhs)
+ max(const Image<I>& lhs, const Image<J>& rhs)
{
- trace::entering("morpho::min");
+ trace::entering("morpho::max");
mln_precondition(exact(rhs).domain() == exact(lhs).domain());
- mln_concrete(I) output = impl::min_(mln_trait_image_kind(I)(), exact(lhs),
exact(rhs));
+ mln_concrete(I) output = impl::max_(mln_trait_image_kind(I)(), exact(lhs),
exact(rhs));
- trace::exiting("morpho::min");
+ trace::exiting("morpho::max");
return output;
}
template <typename I, typename J>
inline
- void min_inplace(Image<I>& lhs, const Image<J>& rhs)
+ void max_inplace(Image<I>& lhs, const Image<J>& rhs)
{
- trace::entering("morpho::min_inplace");
+ trace::entering("morpho::max_inplace");
mln_precondition(exact(rhs).domain() == exact(lhs).domain());
- impl::min_inplace_(mln_trait_image_kind(I)(), exact(lhs), exact(rhs));
+ impl::max_inplace_(mln_trait_image_kind(I)(), exact(lhs), exact(rhs));
- trace::exiting("morpho::min_inplace_");
+ trace::exiting("morpho::max_inplace_");
}
# endif // ! MLN_INCLUDE_ONLY
@@ -139,4 +140,4 @@
} // end of namespace mln
-#endif // ! MLN_MORPHO_MIN_HH
+#endif // ! MLN_MORPHO_MAX_HH
Property changes on: theo/mln/morpho/max.hh
___________________________________________________________________
Added: svn:mergeinfo
Index: theo/mln/morpho/conditional/dilation.hh
--- theo/mln/morpho/conditional/dilation.hh (revision 0)
+++ theo/mln/morpho/conditional/dilation.hh (revision 0)
@@ -0,0 +1,111 @@
+// Copyright (C) 2009 EPITA Research and Development Laboratory (LRDE)
+//
+// This file is part of Olena.
+//
+// Olena is free software: you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation, version 2 of the License.
+//
+// Olena 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 Olena. If not, see <http://www.gnu.org/licenses/>.
+//
+// As a special exception, you may use this file as part of a free
+// software project 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.
+
+#ifndef MLN_MORPHO_CONDITIONAL_DILATION_HH
+# define MLN_MORPHO_CONDITIONAL_DILATION_HH
+
+/// \file
+///
+/// Morphological conditional dilation.
+///
+/// \todo Write a version with (f, g, nbh, n) instead of (f, g, win).
+
+# include <mln/morpho/includes.hh>
+
+
+namespace mln
+{
+
+ namespace morpho
+ {
+
+ namespace conditional
+ {
+
+ /// Morphological conditional dilation.
+ template <typename I, typename J, typename W>
+ mln_concrete(I)
+ dilation(const Image<I>& f, const Image<J>& g,
+ const Window<W>& win);
+
+
+# ifndef MLN_INCLUDE_ONLY
+
+
+ // Tests.
+
+ namespace internal
+ {
+
+ template <typename I, typename J, typename W>
+ inline
+ void
+ dilation_tests(const Image<I>& f_, const Image<J>& g_,
+ const Window<W>& win_)
+ {
+ const I& f = exact(f_);
+ const J& g = exact(g_);
+ const W& win = exact(win_);
+
+ mln_precondition(f.is_valid());
+ mln_precondition(g.is_valid());
+ mln_precondition(win.is_valid());
+
+ mln_precondition(f.domain() == g.domain());
+
+ (void) f;
+ (void) g;
+ (void) win;
+ }
+
+ } // end of namespace morpho::conditional::internal
+
+
+ template <typename I, typename J, typename W>
+ inline
+ mln_concrete(I)
+ dilation(const Image<I>& f, const Image<J>& g,
+ const Window<W>& win)
+ {
+ trace::entering("morpho::conditional::dilation");
+
+ internal::dilation_tests(f, g, win);
+
+ mln_concrete(I) output = morpho::min(morpho::dilation(f, win), g);
+
+ trace::exiting("morpho::conditional::dilation");
+ return output;
+ }
+
+# endif // ! MLN_INCLUDE_ONLY
+
+ } // end of namespace mln::conditional
+
+ } // end of namespace mln::morpho
+
+} // end of namespace mln
+
+
+#endif // ! MLN_MORPHO_CONDITIONAL_DILATION_HH
Index: theo/mln/morpho/conditional/dilation.cc
--- theo/mln/morpho/conditional/dilation.cc (revision 0)
+++ theo/mln/morpho/conditional/dilation.cc (revision 0)
@@ -0,0 +1,29 @@
+#include <mln/core/image/image2d.hh>
+#include <mln/core/alias/neighb2d.hh>
+#include <mln/logical/and.hh>
+
+#include "dilation.hh"
+
+
+int main()
+{
+ using namespace mln;
+
+ image2d<bool> f, g, o;
+
+ bool gvals[] = { 1, 1, 0, 0, 1,
+ 1, 1, 1, 1, 0,
+ 0, 1, 1, 1, 0,
+ 0, 1, 1, 1, 0,
+ 0, 1, 0, 0, 0 };
+ g = make::image2d(gvals);
+
+ bool fvals[] = { 0, 0, 0, 0, 0,
+ 0, 0, 1, 1, 1,
+ 1, 1, 1, 1, 0,
+ 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0 };
+ f = make::image2d(fvals);
+
+ o = morpho::conditional::dilation(f, g, c4().win());
+}