4639: Add new morphological operators.

https://svn.lrde.epita.fr/svn/oln/trunk/milena/sandbox Index: ChangeLog from Thierry Geraud <thierry.geraud@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()); +}
participants (1)
-
Thierry Geraud