4635: Add a 1st version of some morpho geodesic ops.

https://svn.lrde.epita.fr/svn/oln/trunk/milena/sandbox Index: ChangeLog from Thierry Geraud <thierry.geraud@lrde.epita.fr> Add a 1st version of some morpho geodesic ops. * theo/mln/morpho: New directory. * theo/mln/morpho/geodesic: New directory. * theo/mln/morpho/geodesic/dilation.hh: New. * theo/mln/morpho/geodesic/dilation_permissive.hh: New. * theo/mln/morpho/geodesic/dilation.cc: New. * theo/mln/morpho/geodesic/dilation_permissive_n.cc: New. * theo/mln/morpho/geodesic/dilation_permissive_bench.cc: New. * theo/mln/morpho/geodesic/dilation_permissive.cc: New. dilation.cc | 31 ++ dilation.hh | 88 ++++++++ dilation_permissive.cc | 47 ++++ dilation_permissive.hh | 446 +++++++++++++++++++++++++++++++++++++++++++ dilation_permissive_bench.cc | 60 +++++ dilation_permissive_n.cc | 35 +++ 6 files changed, 707 insertions(+) Index: theo/mln/morpho/geodesic/dilation.hh --- theo/mln/morpho/geodesic/dilation.hh (revision 0) +++ theo/mln/morpho/geodesic/dilation.hh (revision 0) @@ -0,0 +1,88 @@ +// 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_GEODESIC_DILATION_HH +# define MLN_MORPHO_GEODESIC_DILATION_HH + +/// \file +/// +/// Morphological geodesic dilation; strict version. + +// # include <mln/morpho/geodesic/dilation_permissive.hh> +# include "dilation_permissive.hh" + + +namespace mln +{ + + namespace morpho + { + + namespace geodesic + { + + /// Morphological geodesic dilation of size n; strict version. + template <typename I, typename J, typename N> + mln_concrete(I) + dilation(const Image<I>& f, const Image<J>& g, + const Neighborhood<N>& nbh, + unsigned n = 1); + + +# ifndef MLN_INCLUDE_ONLY + + template <typename I, typename J, typename N> + inline + mln_concrete(I) + dilation(const Image<I>& f, const Image<J>& g, + const Neighborhood<N>& nbh, + unsigned n) + { + trace::entering("morpho::geodesic::dilation"); + + mln_precondition(n != 0); + internal::dilation_permissive_tests(f, g, nbh); + mln_precondition(f <= g); + + mln_concrete(I) output; + output = internal::dilation_permissive_dispatch(f, g, nbh, n); + + mln_precondition(output >= f); + mln_precondition(output <= g); + + trace::exiting("morpho::geodesic::dilation"); + return output; + } + +# endif // ! MLN_INCLUDE_ONLY + + } // end of namespace mln::geodesic + + } // end of namespace mln::morpho + +} // end of namespace mln + + +#endif // ! MLN_MORPHO_GEODESIC_DILATION_HH Index: theo/mln/morpho/geodesic/dilation_permissive.hh --- theo/mln/morpho/geodesic/dilation_permissive.hh (revision 0) +++ theo/mln/morpho/geodesic/dilation_permissive.hh (revision 0) @@ -0,0 +1,446 @@ +// 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_GEODESIC_DILATION_PERMISSIVE_HH +# define MLN_MORPHO_GEODESIC_DILATION_PERMISSIVE_HH + +/// \file +/// +/// Morphological geodesic dilation; permissive version. + +# include <mln/morpho/includes.hh> +# include <mln/morpho/elementary/dilation.hh> +# include <mln/logical/and.hh> +# include <mln/data/transform_inplace.hh> +# include <mln/fun/vv2v/max.hh> +# include <mln/border/equalize.hh> + + +namespace mln +{ + + namespace morpho + { + + namespace geodesic + { + + /// Morphological geodesic dilation of size n; permissive version. + template <typename I, typename J, typename N> + mln_concrete(I) + dilation_permissive(const Image<I>& f, const Image<J>& g, + const Neighborhood<N>& nbh, + unsigned n = 1); + + +# ifndef MLN_INCLUDE_ONLY + + // Tests. + + namespace internal + { + + template <typename I, typename J, typename N> + inline + void + dilation_permissive_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()); + + (void) f; + (void) g; + (void) nbh; + } + + } // end of namespace morpho::geodesic::internal + + + // Implementations. + + namespace impl + { + + + template <typename I, typename J, typename N> + inline + mln_concrete(I) + dilation_strict_1_set_formula(const Image<I>& f, const Image<J>& g, + const Neighborhood<N>& nbh) + { + trace::entering("morpho::geodesic::impl::dilation_strict_1_set_formula"); + + internal::dilation_permissive_tests(f, g, nbh); + + mln_concrete(I) output = morpho::elementary::dilation(f, nbh); + logical::and_inplace(output, g); + + trace::exiting("morpho::geodesic::impl::dilation_strict_1_set_formula"); + return output; + } + + + template <typename I, typename J, typename N> + inline + mln_concrete(I) + dilation_strict_1_function_formula(const Image<I>& f, const Image<J>& g, + const Neighborhood<N>& nbh) + { + trace::entering("morpho::geodesic::impl::dilation_strict_1_function_formula"); + + internal::dilation_permissive_tests(f, g, nbh); + + mln_concrete(I) output = morpho::elementary::dilation(f, nbh); + fun::vv2v::max<mln_value(I)> max_; + data::transform_inplace(output, g, max_); + + trace::exiting("morpho::geodesic::impl::dilation_strict_1_function_formula"); + return output; + } + + + template <typename I, typename J, typename N> + inline + mln_concrete(I) + dilation_permissive_n(const Image<I>& f, const Image<J>& g, + const Neighborhood<N>& nbh, + unsigned n) + { + trace::entering("morpho::geodesic::impl::dilation_permissive_n"); + + mln_precondition(n != 0); + internal::dilation_permissive_tests(f, g, nbh); + + mln_concrete(I) work = duplicate(f); + for (unsigned i = 0; i < n; ++i) + work = dilation_permissive(work, g, nbh, 1); + + trace::exiting("morpho::geodesic::impl::dilation_permissive_n"); + return work; + } + + + template <typename I, typename J, typename N> + inline + mln_concrete(I) + dilation_permissive_1_set_generic(const Image<I>& f_, const Image<J>& g_, + const Neighborhood<N>& nbh_) + { + trace::entering("morpho::geodesic::impl::dilation_permissive_1_set_generic"); + + const I& f = exact(f_); + const J& g = exact(g_); + const N& nbh = exact(nbh_); + + internal::dilation_permissive_tests(f, g, nbh); + + mln_piter(I) p(f.domain()); + mln_niter(N) n(nbh, p); + + // We dilate from the inner boundary of f. + + mln_concrete(I) output = duplicate(f); + for_all(p) + { + if (! f(p)) + continue; + for_all(n) if (f.domain().has(n)) + { + if (output(n)) // already at true + continue; + if (g(n)) // conditioning + output(n) = true; + } + } + + trace::exiting("morpho::geodesic::impl::dilation_permissive_1_set_generic"); + return output; + } + + + template <typename I, typename J, typename N> + inline + mln_concrete(I) + dilation_permissive_1_set_fastest(const Image<I>& f_, const Image<J>& g_, + const Neighborhood<N>& nbh_) + { + trace::entering("morpho::geodesic::impl::dilation_permissive_1_set_fastest"); + + const I& f = exact(f_); + const J& g = exact(g_); + const N& nbh = exact(nbh_); + + internal::dilation_permissive_tests(f, g, nbh); + + border::equalize(f, g, nbh.delta()); + typedef mln_concrete(I) O; + O output = duplicate(f); + border::fill(output, true); + + util::array<int> dp = offsets_wrt(f, nbh); + const unsigned n_nbhs = dp.nelements(); + + mln_box_runstart_piter(I) s(f.domain()); + s.start(); + const unsigned len = s.run_length(); + + // We dilate from the inner boundary of f. + + for (; s.is_valid(); s.next()) + { + unsigned p = f.index_of_point(s); + for (unsigned i = 0; i < len; ++i, ++p) + { + if (! f.element(p)) + continue; + for (unsigned j = 0; j < n_nbhs; ++j) + { + unsigned n = p + dp[j]; + if (output.element(n)) // already at true + continue; + if (g.element(n)) // conditioning + output.element(n) = true; + } + } + } + + trace::exiting("morpho::geodesic::impl::dilation_permissive_1_set_fastest"); + return output; + } + + + template <typename I, typename J, typename N> + inline + mln_concrete(I) + dilation_permissive_1_set_generic_alt(const Image<I>& f_, const Image<J>& g_, + const Neighborhood<N>& nbh_) + { + trace::entering("morpho::geodesic::impl::dilation_permissive_1_set_generic_alt"); + + const I& f = exact(f_); + const J& g = exact(g_); + const N& nbh = exact(nbh_); + + internal::dilation_permissive_tests(f, g, nbh); + + mln_piter(I) p(f.domain()); + mln_niter(N) n(nbh, p); + + // We browse the "(not f) and g" domain. + + mln_concrete(I) output = duplicate(f); + for_all(p) + { + if (f(p) // output(p) is already at true... + || ! g(p) // ...or conditioning by g not satisfied + ) + continue; + for_all(n) if (f.domain().has(n)) + if (f(n)) // p is in the outer boundary of f + { + output(p) = true; + break; // we are done for p + } + } + + trace::exiting("morpho::geodesic::impl::dilation_permissive_1_set_generic_alt"); + return output; + } + + + + template <typename I, typename J, typename N> + inline + mln_concrete(I) + dilation_permissive_1_set_fastest_alt(const Image<I>& f_, const Image<J>& g_, + const Neighborhood<N>& nbh_) + { + trace::entering("morpho::geodesic::impl::dilation_permissive_1_set_fastest_alt"); + + const I& f = exact(f_); + const J& g = exact(g_); + const N& nbh = exact(nbh_); + + internal::dilation_permissive_tests(f, g, nbh); + + border::equalize(f, g, nbh.delta()); + typedef mln_concrete(I) O; + O output = duplicate(f); + border::fill(f, false); + + util::array<int> dp = offsets_wrt(f, nbh); + const unsigned n_nbhs = dp.nelements(); + + mln_box_runstart_piter(I) s(f.domain()); + s.start(); + const unsigned len = s.run_length(); + + // We browse the "(not f) and g" domain. + + for (; s.is_valid(); s.next()) + { + unsigned p = f.index_of_point(s); + for (unsigned i = 0; i < len; ++i, ++p) + { + if (f.element(p) // output.element(p) is already at true... + || ! g.element(p) // ...or conditioning by g not satisfied + ) + continue; + for (unsigned j = 0; j < n_nbhs; ++j) + { + unsigned n = p + dp[j]; + if (f.element(n)) // p is in the outer boundary of f + { + output.element(p) = true; + break; // we are done for p + } + } + } + } + + trace::exiting("morpho::geodesic::impl::dilation_permissive_1_set_fastest_alt"); + return output; + } + + + } // end of namespace morpho::geodesic::impl + + + + // Dispatch. + + namespace internal + { + + + // For size 1. + + template <typename M, + typename I, typename J, typename N> + inline + mln_concrete(I) + dilation_permissive_1_dispatch(trait::image::kind::any, + M, + const Image<I>& f, const Image<J>& g, + const Neighborhood<N>& nbh) + { + // FIXME + std::cerr << "NYI: replace by strict version!" << std::endl; + return impl::dilation_strict_1_function_formula(f, g, nbh); + } + + template <typename I, typename J, typename N> + inline + mln_concrete(I) + dilation_permissive_1_dispatch(trait::image::kind::binary, + metal::false_, + const Image<I>& f, const Image<J>& g, + const Neighborhood<N>& nbh) + { + return impl::dilation_permissive_1_set_generic(f, g, nbh); + } + + template <typename I, typename J, typename N> + inline + mln_concrete(I) + dilation_permissive_1_dispatch(trait::image::kind::binary, + metal::true_, + const Image<I>& f, const Image<J>& g, + const Neighborhood<N>& nbh) + { + return impl::dilation_permissive_1_set_fastest(f, g, nbh); + } + + + + // Entry point. + + template <typename I, typename J, typename N> + inline + mln_concrete(I) + dilation_permissive_dispatch(const Image<I>& f, const Image<J>& g, + const Neighborhood<N>& nbh, + unsigned n) + { + enum { + is_fastest = (mlc_equal(mln_trait_image_speed(I), + trait::image::speed::fastest)::value && + mlc_equal(mln_trait_image_speed(J), + trait::image::speed::fastest)::value && + mln_is_simple_neighborhood(N)::value) + }; + if (n == 1) + return dilation_permissive_1_dispatch(mln_trait_image_kind(I)(), + metal::bool_<is_fastest>(), + f, g, nbh); + else + return impl::dilation_permissive_n(f, g, nbh, n); + } + + + } // end of namespace morpho::geodesic::internal + + + + // Facade. + + template <typename I, typename J, typename N> + inline + mln_concrete(I) + dilation_permissive(const Image<I>& f, const Image<J>& g, + const Neighborhood<N>& nbh, + unsigned n) + { + trace::entering("morpho::geodesic::dilation_permissive"); + + mln_precondition(n != 0); + internal::dilation_permissive_tests(f, g, nbh); + + mln_concrete(I) output; + output = internal::dilation_permissive_dispatch(f, g, nbh, n); + + trace::exiting("morpho::geodesic::dilation_permissive"); + return output; + } + + +# endif // ! MLN_INCLUDE_ONLY + + } // end of namespace mln::geodesic + + } // end of namespace mln::morpho + +} // end of namespace mln + + +#endif // ! MLN_MORPHO_GEODESIC_DILATION_PERMISSIVE_HH Index: theo/mln/morpho/geodesic/dilation.cc --- theo/mln/morpho/geodesic/dilation.cc (revision 0) +++ theo/mln/morpho/geodesic/dilation.cc (revision 0) @@ -0,0 +1,31 @@ +#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; + neighb2d nbh = c4(); + + 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::geodesic::dilation(logical::and_(f, g), g, nbh); +} Index: theo/mln/morpho/geodesic/dilation_permissive_n.cc --- theo/mln/morpho/geodesic/dilation_permissive_n.cc (revision 0) +++ theo/mln/morpho/geodesic/dilation_permissive_n.cc (revision 0) @@ -0,0 +1,35 @@ +#include <cstdlib> +#include <mln/core/image/image2d.hh> +#include <mln/core/alias/neighb2d.hh> +#include <mln/io/pbm/load.hh> +#include <mln/io/pbm/save.hh> +#include <mln/logical/and.hh> +#include <mln/util/timer.hh> + +#include "dilation_permissive.hh" + + +int main(int argc, char* argv[]) +{ + using namespace mln; + + + image2d<bool> + f = io::pbm::load("./+f.pbm"), + g = io::pbm::load("./+g.pbm"), + o; + neighb2d nbh = c8(); + + int n = std::atoi(argv[1]); + +// image2d<bool> f_g = logical::and_(f, g); +// io::pbm::save(f_g, "f_g.pbm"); +// o = morpho::geodesic::dilation_permissive(f_g, g, nbh, n); + + util::timer t; + t.start(); + o = morpho::geodesic::dilation_permissive(f, g, nbh, n); + std::cout << t.stop() << std::endl; + + io::pbm::save(o, "o.pbm"); +} Index: theo/mln/morpho/geodesic/dilation_permissive_bench.cc --- theo/mln/morpho/geodesic/dilation_permissive_bench.cc (revision 0) +++ theo/mln/morpho/geodesic/dilation_permissive_bench.cc (revision 0) @@ -0,0 +1,60 @@ +#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 "dilation_permissive.hh" + + +int main() +{ + using namespace mln; + + image2d<bool> + f = io::pbm::load("./+f.pbm"), + g = io::pbm::load("./+g.pbm"), + o; + neighb2d nbh = c4(); + + util::timer t; + const unsigned n = 20; + + { + t.start(); + for (unsigned i = 0; i < n; ++i) + o = morpho::geodesic::impl::dilation_strict_1_set_formula(f, g, nbh); + std::cout << "dilation_strict_1_set_formula " << t.stop() << std::endl; + io::pbm::save(o, "o.pbm"); + } + + { + t.start(); + for (unsigned i = 0; i < n; ++i) + o = morpho::geodesic::impl::dilation_permissive_1_set_generic(f, g, nbh); + std::cout << "dilation_permissive_1_set_generic " << t.stop() << std::endl; + } + + { + t.start(); + for (unsigned i = 0; i < n; ++i) + o = morpho::geodesic::impl::dilation_permissive_1_set_fastest(f, g, nbh); + std::cout << "dilation_permissive_1_set_fastest " << t.stop() << std::endl; +// io::pbm::save(o, "o.pbm"); + } + + { + t.start(); + for (unsigned i = 0; i < n; ++i) + o = morpho::geodesic::impl::dilation_permissive_1_set_generic_alt(f, g, nbh); + std::cout << "dilation_permissive_1_set_generic_alt " << t.stop() << std::endl; + } + + { + t.start(); + for (unsigned i = 0; i < n; ++i) + o = morpho::geodesic::impl::dilation_permissive_1_set_fastest_alt(f, g, nbh); + std::cout << "dilation_permissive_1_set_fastest_alt " << t.stop() << std::endl; + } +} Index: theo/mln/morpho/geodesic/dilation_permissive.cc --- theo/mln/morpho/geodesic/dilation_permissive.cc (revision 0) +++ theo/mln/morpho/geodesic/dilation_permissive.cc (revision 0) @@ -0,0 +1,47 @@ +#include <mln/core/image/image2d.hh> +#include <mln/core/alias/neighb2d.hh> +#include <mln/debug/println.hh> + +#include "dilation_permissive.hh" + + +int main() +{ + using namespace mln; + + image2d<bool> f, g, d_ref, d_gen, d_fast, d_gen_alt, d_fast_alt; + neighb2d nbh = c4(); + + 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); + debug::println("g", g); + + 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); + debug::println("f", f); + + + d_ref = morpho::geodesic::impl::dilation_strict_1_set_formula(f, g, nbh); + debug::println("d", d_ref); + + d_gen = morpho::geodesic::impl::dilation_permissive_1_set_generic(f, g, nbh); + mln_assertion(logical::and_(d_gen, g) == d_ref); + + d_fast = morpho::geodesic::impl::dilation_permissive_1_set_fastest(f, g, nbh); + mln_assertion(d_fast == d_gen); + + d_gen_alt = morpho::geodesic::impl::dilation_permissive_1_set_generic_alt(f, g, nbh); + mln_assertion(logical::and_(d_gen_alt, g) == d_ref); + mln_assertion(d_gen_alt == d_gen); + + d_fast_alt = morpho::geodesic::impl::dilation_permissive_1_set_fastest_alt(f, g, nbh); + mln_assertion(d_fast_alt == d_gen_alt); +}
participants (1)
-
Thierry Geraud