cleanup-2008 2739: Add a generic discrete distance transform.

https://svn.lrde.epita.fr/svn/oln/branches/cleanup-2008 Index: ChangeLog from Thierry Geraud <thierry.geraud@lrde.epita.fr> Add a generic discrete distance transform. * milena/mln/transform: New. * milena/mln/transform/distance.hh: New. * milena/tests/transform: New directory. * milena/tests/transform/Makefile.am: New. * milena/tests/transform/distance.cc: New. * milena/sandbox/geraud/skel.cc: Layout. * milena/sandbox/geraud/dmap.cc: Update. Slight change in w_window. * milena/mln/core/w_window.hh (from_to): Prepare new overload. For that, add some new meta-code: * milena/mln/metal/math/root.hh: New. * milena/mln/metal/math/all.hh: Update. * milena/mln/metal/math/sqrt.hh (todo): New. * milena/tests/metal/math/root.cc: New. * milena/tests/metal/math/pow.cc: Remove echo. * milena/tests/metal/math/Makefile.am: Update. * milena/tests/morpho/Makefile.am (SUBDIRS): Fix missing. mln/core/w_window.hh | 17 +++ mln/metal/math/all.hh | 3 mln/metal/math/root.hh | 71 +++++---------- mln/metal/math/sqrt.hh | 2 mln/transform/distance.hh | 197 +++++++++++++++++++++++++++++++++++++++++++ sandbox/geraud/dmap.cc | 33 +++---- sandbox/geraud/skel.cc | 4 tests/metal/math/Makefile.am | 4 tests/metal/math/pow.cc | 5 - tests/metal/math/root.cc | 15 +-- tests/morpho/Makefile.am | 2 tests/transform/Makefile.am | 10 ++ tests/transform/distance.cc | 61 +++++++++++++ 13 files changed, 349 insertions(+), 75 deletions(-) Index: milena/tests/metal/math/root.cc --- milena/tests/metal/math/root.cc (revision 2732) +++ milena/tests/metal/math/root.cc (working copy) @@ -1,4 +1,4 @@ -// Copyright (C) 2007 EPITA Research and Development Laboratory +// Copyright (C) 2007, 2008 EPITA Research and Development Laboratory // // This file is part of the Olena Library. This library is free // software; you can redistribute it and/or modify it under the terms @@ -25,23 +25,20 @@ // reasons why the executable file might be covered by the GNU General // Public License. -/*! \file tests/metal/math/pow.cc +/*! \file tests/metal/math/root.cc * - * \brief Test on mln::metal::math::pow. + * \brief Test on mln::metal::math::root. */ #include <iostream> #include <mln/core/contract.hh> -#include <mln/metal/math/pow.hh> +#include <mln/metal/math/root.hh> int main() { using namespace mln; - using namespace mln::metal; - int res = metal::math::pow_int<2,3>::value; - mln_assertion(res == 8); - - std::cout << metal::math::pow< int_<2>, int_<3> >::ret().name() << std::endl; + int res = metal::math::root<3,8>::value; + mln_assertion(res == 2); } Index: milena/tests/metal/math/pow.cc --- milena/tests/metal/math/pow.cc (revision 2738) +++ milena/tests/metal/math/pow.cc (working copy) @@ -1,4 +1,4 @@ -// Copyright (C) 2007 EPITA Research and Development Laboratory +// Copyright (C) 2007, 2008 EPITA Research and Development Laboratory // // This file is part of the Olena Library. This library is free // software; you can redistribute it and/or modify it under the terms @@ -43,5 +43,6 @@ int res = metal::math::pow_int<2,3>::value; mln_assertion(res == 8); - std::cout << metal::math::pow< int_<2>, int_<3> >::ret().name() << std::endl; + std::string s = metal::math::pow< int_<2>, int_<3> >::ret().name(); + mln_assertion(s == "metal::int_<8>"); } Index: milena/tests/metal/math/Makefile.am --- milena/tests/metal/math/Makefile.am (revision 2738) +++ milena/tests/metal/math/Makefile.am (working copy) @@ -3,8 +3,10 @@ include $(top_srcdir)/milena/tests/tests.mk check_PROGRAMS = \ - pow + pow \ + root pow_SOURCES = pow.cc +root_SOURCES = root.cc TESTS = $(check_PROGRAMS) Index: milena/tests/transform/Makefile.am --- milena/tests/transform/Makefile.am (revision 0) +++ milena/tests/transform/Makefile.am (revision 0) @@ -0,0 +1,10 @@ +## Process this file through Automake to create Makefile.in -*- Makefile -*- + +include $(top_srcdir)/milena/tests/tests.mk + +check_PROGRAMS = \ + distance + +distance_SOURCES = distance.cc + +TESTS = $(check_PROGRAMS) Index: milena/tests/transform/distance.cc --- milena/tests/transform/distance.cc (revision 0) +++ milena/tests/transform/distance.cc (revision 0) @@ -0,0 +1,61 @@ +// Copyright (C) 2008 EPITA Research and Development Laboratory (LRDE) +// +// This file is part of the Olena Library. This library is free +// software; you can redistribute it and/or modify it under the terms +// of the GNU General Public License version 2 as published by the +// Free Software Foundation. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this library; see the file COPYING. If not, write to +// the Free Software Foundation, 51 Franklin Street, Fifth Floor, +// Boston, MA 02111-1307, USA. +// +// As a special exception, you may use this file as part of a free +// software library without restriction. Specifically, if other files +// instantiate templates or use macros or inline functions from this +// file, or you compile this file and link it with other files to +// produce an executable, this file does not by itself cause the +// resulting executable to be covered by the GNU General Public +// License. This exception does not however invalidate any other +// reasons why the executable file might be covered by the GNU General +// Public License. + +/*! \file tests/transform/distance.cc + * + * \brief Test on mln::transform::distance. + */ + +#include <mln/core/image/image2d.hh> +#include <mln/core/alias/neighb2d.hh> +#include <mln/make/w_window2d_int.hh> +#include <mln/value/int_u8.hh> +#include <mln/level/fill.hh> +#include <mln/debug/println.hh> + +#include <mln/transform/distance.hh> + + +int main() +{ + using namespace mln; + using value::int_u8; + + image2d<bool> input(9, 9); + level::fill(input, false); + input.at(4, 4) = true; + + int vals[] = { 0, 9, 0, 9, 0, + 9, 6, 4, 6, 9, + 0, 4, 0, 4, 0, + 9, 6, 4, 6, 9, + 0, 9, 0, 9, 0 }; + + image2d<int_u8> output = transform::distance(int_u8(), input, + c4(), make::w_window2d_int(vals)); + debug::println(output); +} Index: milena/tests/morpho/Makefile.am --- milena/tests/morpho/Makefile.am (revision 2738) +++ milena/tests/morpho/Makefile.am (working copy) @@ -2,6 +2,8 @@ include $(top_srcdir)/milena/tests/tests.mk +SUBDIRS = elementary + check_PROGRAMS = \ artificial_line_graph_image_wst \ closing_area \ Index: milena/mln/core/w_window.hh --- milena/mln/core/w_window.hh (revision 2738) +++ milena/mln/core/w_window.hh (working copy) @@ -148,6 +148,10 @@ void from_to(const Image<I>& from, w_window<D,W>& to); + template <typename V, unsigned S, typename D, typename W> + void + from_to(const V (&values)[S], w_window<D,W>& to); + } // end of namespace mln::convert @@ -339,6 +343,19 @@ to.insert(ima(p), convert::to<D>(p)); } +// template <typename V, unsigned S, typename D, typename W> +// void +// from_to(const V (&values)[S], w_window<D,W>& to) +// { +// enum { d = D::dim, +// s = mlc_root(d,S)::value / 2 }; +// metal::bool_<(mlc_pow_int(2 * s + 1, d) == S)>::check(); +// to.clear(); +// D dp; +// dp.set_all(-s); +// FIXME +// } + } // end of namespace mln::convert Index: milena/mln/metal/math/root.hh --- milena/mln/metal/math/root.hh (revision 2732) +++ milena/mln/metal/math/root.hh (working copy) @@ -25,19 +25,20 @@ // reasons why the executable file might be covered by the GNU General // Public License. -#ifndef MLN_METAL_MATH_SQRT_HH -# define MLN_METAL_MATH_SQRT_HH +#ifndef MLN_METAL_MATH_ROOT_HH +# define MLN_METAL_MATH_ROOT_HH -/*! \file mln/metal/math/sqrt.hh +/*! \file mln/metal/math/root.hh * - * \brief Definition of the 'sqrt' static function. + * \brief Definition of the 'nth-root' static function. + * + * \todo Have consistent writing of math meta-routines. */ -# include <mln/metal/bool.hh> -# include <mln/metal/int.hh> +# include <mln/metal/math/pow.hh> -# define mlc_sqrt_int(N) mln::metal::math::sqrt_int<( N )>::value +# define mlc_root(N,X) mln::metal::math::root<( N ),( X )> namespace mln @@ -49,63 +50,43 @@ namespace math { - // sqrt_int<x> - namespace impl { - template <int n, int lo = 1, int hi = n> - struct sqrt_int_ + template <unsigned n, unsigned x, + unsigned lo = 1, unsigned hi = x> + struct root { enum { mid = (lo + hi + 1) / 2, - val_lo = sqrt_int_<n, lo, mid-1>::value, - val_hi = sqrt_int_<n, mid, hi>::value + val_lo = root<n, x, lo, mid-1>::value, + val_hi = root<n, x, mid, hi>::value }; - enum { value = n < mid * mid ? val_lo : val_hi }; + enum { value = x < mlc_pow_int(mid, n) ? val_lo : val_hi }; }; - template<int n, int m> - struct sqrt_int_<n, m, m> - { - enum { value = m }; - }; - - // Entry. - - template <int n, bool b> - struct sqrt_int_if_ : sqrt_int_<n> - { - enum { value_ = sqrt_int_<n>::value, - reminder_ = n - value_ * value_ }; - // FIXME: Check that reminder_ == 0. - }; - - template <int n> - struct sqrt_int_if_< n, false > + template<unsigned n, unsigned x, unsigned m> + struct root<n, x, m, m> { + enum { value = m }; // Found. }; } // end of namespace mln::metal::math::impl - template <int n> - struct sqrt_int : impl::sqrt_int_if_< n, (n >= 0) > + template <unsigned n, unsigned x> + struct root : bool_<(n != 0)>::check_t { + enum { value = impl::root<n,x>::value, + reminder = x - mlc_pow_int(value, n) }; }; - - // sqrt<N> - - template <typename N> - struct sqrt; - - template <int n> - struct sqrt< int_<n> > + template <unsigned n> + struct root<n, 0> : bool_<(n != 0)>::check_t { - typedef int_< sqrt_int<n>::value > ret; + enum { value = 0, + reminder = 0}; }; - } // end of namespace mln::metal::math } // end of namespace mln::metal @@ -113,4 +94,4 @@ } // end of namespace mln -#endif // ! MLN_METAL_MATH_SQRT_HH +#endif // ! MLN_METAL_MATH_ROOT_HH Index: milena/mln/metal/math/all.hh --- milena/mln/metal/math/all.hh (revision 2738) +++ milena/mln/metal/math/all.hh (working copy) @@ -1,4 +1,4 @@ -// Copyright (C) 2007 EPITA Research and Development Laboratory +// Copyright (C) 2007, 2008 EPITA Research and Development Laboratory // // This file is part of the Olena Library. This library is free // software; you can redistribute it and/or modify it under the terms @@ -54,6 +54,7 @@ # include <mln/metal/math/pow.hh> +# include <mln/metal/math/root.hh> # include <mln/metal/math/sqrt.hh> # include <mln/metal/math/max.hh> // ... Index: milena/mln/metal/math/sqrt.hh --- milena/mln/metal/math/sqrt.hh (revision 2738) +++ milena/mln/metal/math/sqrt.hh (working copy) @@ -31,6 +31,8 @@ /*! \file mln/metal/math/sqrt.hh * * \brief Definition of the 'sqrt' static function. + * + * \todo Rely on nth-root. */ # include <mln/metal/bool.hh> Index: milena/mln/transform/distance.hh --- milena/mln/transform/distance.hh (revision 0) +++ milena/mln/transform/distance.hh (revision 0) @@ -0,0 +1,197 @@ +// Copyright (C) 2008 EPITA Research and Development Laboratory (LRDE) +// +// This file is part of the Olena Library. This library is free +// software; you can redistribute it and/or modify it under the terms +// of the GNU General Public License version 2 as published by the +// Free Software Foundation. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this library; see the file COPYING. If not, write to +// the Free Software Foundation, 51 Franklin Street, Fifth Floor, +// Boston, MA 02111-1307, USA. +// +// As a special exception, you may use this file as part of a free +// software library without restriction. Specifically, if other files +// instantiate templates or use macros or inline functions from this +// file, or you compile this file and link it with other files to +// produce an executable, this file does not by itself cause the +// resulting executable to be covered by the GNU General Public +// License. This exception does not however invalidate any other +// reasons why the executable file might be covered by the GNU General +// Public License. + +#ifndef MLN_TRANSFORM_DISTANCE_HH +# define MLN_TRANSFORM_DISTANCE_HH + +/*! \file mln/transform/distance.hh + * + * \brief Discrete distance transform. + */ + +# include <vector> +# include <mln/core/concept/image.hh> +# include <mln/core/concept/neighborhood.hh> +# include <mln/core/concept/weighted_window.hh> +# include <mln/level/fill.hh> +# include <mln/accu/max.hh> + + + +namespace mln +{ + + namespace transform + { + + /*! Discrete distance transform. + * + * FIXME: doc. + */ + template <typename D, typename I, typename N, typename W> + mln_ch_value(I, D) + distance(D, const Image<I>& input, + const Neighborhood<N>& nbh, const Weighted_Window<W>& w_win); + + +# ifndef MLN_INCLUDE_ONLY + + namespace impl + { + + namespace generic + { + + template <typename D, typename I, typename N, typename W> + mln_ch_value(I, D) + distance(D, const Image<I>& input_, + const Neighborhood<N>& nbh_, const Weighted_Window<W>& w_win_) + { + trace::entering("transform::impl::generic::distance"); + + const I& input = exact(input_); + const N& nbh = exact(nbh_); + const W& w_win = exact(w_win_); + + mln_precondition(input.has_data()); + + const D Max = mln_max(D); + + typedef mln_site(I) P; + typedef std::vector<P> bucket_t; + + mln_ch_value(I, D) output; + initialize(output, input); + level::fill(output, Max); + + // Modulus determination. + unsigned mod; + { + mln::accu::max<unsigned> accu; + P p; + mln_qiter(W) q(w_win, p); + for_all(q) + accu.take(q.w()); + mod = accu.to_result() + 1; + } + + std::vector<bucket_t> bucket; + bucket.resize(mod); + unsigned bucket_size = 0; + + // Initialization. + { + mln_piter(I) p(input.domain()); + mln_niter(N) n(nbh, p); + for_all(p) + if (input(p) == true) + { + output(p) = literal::zero; + for_all(n) + if (input.domain().has(n) && input(n) == false) + { + bucket[0].push_back(p); + ++bucket_size; + break; + } + } + } + + // Propagation. + { + P p; + mln_qiter(W) q(w_win, p); + + for (unsigned d = 0; bucket_size != 0; ++d) + { + bucket_t& bucket_d = bucket[d % mod]; + for (unsigned i = 0; i < bucket_d.size(); ++i) + { + p = bucket_d[i]; + if (output(p) < d) + continue; + + for_all(q) + if (output.domain().has(q) && output(q) > d) + { + if (unsigned(Max - q.w()) < d) // Saturation => Stop! + { + // trace::warning... + trace::exiting("transform::impl::generic::distance"); + return output; + } + unsigned d_ = d + q.w(); + + if (d_ < output(q)) + { + output(q) = d_; + bucket[d_ % mod].push_back(q); + ++bucket_size; + } + } + } + bucket_size -= bucket_d.size(); + bucket_d.clear(); + } + } + + trace::exiting("transform::impl::generic::distance"); + return output; + + } + + } // end of namespace mln::transform::impl::generic + + } // end of namespace mln::transform::impl + + + // Facade. + + template <typename D, typename I, typename N, typename W> + inline + mln_ch_value(I, D) + distance(D, const Image<I>& input, + const Neighborhood<N>& nbh, const Weighted_Window<W>& w_win) + { + trace::entering("transform::distance"); + + // FIXME: tests. + mln_ch_value(I, D) output = impl::generic::distance(D(), input, + nbh, w_win); + + trace::exiting("transform::distance"); + return output; + } + +# endif // ! MLN_INCLUDE_ONLY + + } // end of namespace mln::transform + +} // end of namespace mln + + +#endif // ! MLN_TRANSFORM_DISTANCE_HH Index: milena/sandbox/geraud/skel.cc --- milena/sandbox/geraud/skel.cc (revision 2738) +++ milena/sandbox/geraud/skel.cc (working copy) @@ -12,7 +12,6 @@ # include <mln/debug/println.hh> - namespace mln { @@ -75,6 +74,9 @@ return output; } +*/ + + } // mln Index: milena/sandbox/geraud/dmap.cc --- milena/sandbox/geraud/dmap.cc (revision 2738) +++ milena/sandbox/geraud/dmap.cc (working copy) @@ -21,14 +21,14 @@ const W& win = exact(win_); mln_precondition(input.has_data()); - typedef std::vector<mln_point(I)> bucket_t; + typedef std::vector<mln_site(I)> bucket_t; // Initialization of distance. mln_ch_value(I, unsigned) distance; initialize(distance, input); // Mod determination. - mln_accu_with_(accu::max, unsigned) max; + accu::max<unsigned> max; for (unsigned i = 0; i < win.size(); ++i) max.take(win.w(i)); unsigned mod = unsigned(max) + 1; @@ -59,7 +59,7 @@ // Propagation. { - mln_point(I) p; + mln_site(I) p; mln_qiter(W) q(win, p); for (unsigned d = 0; bucket_size != 0; ++d) @@ -104,26 +104,27 @@ using namespace mln; using value::int_u8; - const unsigned n = 256; + const unsigned n = 9; image2d<bool> ima(n, n); level::fill(ima, false); ima.at(n / 2, n / 2) = true; - int ws[] = { 3, 2, 3, - 2, 0, 2, - 3, 2, 3 }; - -// int ws[] = { 0, 9, 0, 9, 0, -// 9, 6, 4, 6, 9, -// 0, 4, 0, 4, 0, -// 9, 6, 4, 6, 9, -// 0, 9, 0, 9, 0 }; // coef = 4.1203 +// int ws[] = { 3, 2, 3, +// 2, 0, 2, +// 3, 2, 3 }; + + int ws[] = { 0, 9, 0, 9, 0, + 9, 6, 4, 6, 9, + 0, 4, 0, 4, 0, + 9, 6, 4, 6, 9, + 0, 9, 0, 9, 0 }; // coef = 4.1203 w_window2d_int win = make::w_window2d(ws); image2d<unsigned> d = dmap(ima, win); + debug::println(d); - image2d<int_u8> out(d.domain()); - level::stretch(d, out); - io::pgm::save(out, "out.pgm"); +// image2d<int_u8> out; +// level::stretch(d, out); +// io::pgm::save(out, "out.pgm"); }
participants (1)
-
Thierry Geraud