last-svn-commit-869-g6790b23 Add fastest versions for skeleton constrained related algorithms.

* mln/morpho/skeleton_constrained.hh, * mln/topo/skeleton/crest.hh: Add fastest versions. * mln/topo/skeleton/is_simple_point.hh: Rewrite as functor and add fastest versions. * tests/topo/skeleton/is_simple_point.cc: Fix test. --- milena/ChangeLog | 12 + milena/mln/morpho/skeleton_constrained.hh | 271 ++++++++++++++++++++----- milena/mln/topo/skeleton/crest.hh | 230 +++++++++++++++++---- milena/mln/topo/skeleton/is_simple_point.hh | 221 ++++++++------------ milena/tests/topo/skeleton/is_simple_point.cc | 20 ++- 5 files changed, 525 insertions(+), 229 deletions(-) diff --git a/milena/ChangeLog b/milena/ChangeLog index d12cc20..3437368 100644 --- a/milena/ChangeLog +++ b/milena/ChangeLog @@ -1,3 +1,15 @@ +2011-05-17 Guillaume Lazzara <z@lrde.epita.fr> + + Add fastest versions for skeleton constrained related algorithms. + + * mln/morpho/skeleton_constrained.hh, + * mln/topo/skeleton/crest.hh: Add fastest versions. + + * mln/topo/skeleton/is_simple_point.hh: Rewrite as functor and add + fastest versions. + + * tests/topo/skeleton/is_simple_point.cc: Fix test. + 2011-05-05 Guillaume Lazzara <lazzara@fidji.lrde.epita.fr> * mln/io/magick/save.hh: Add support for opacity. diff --git a/milena/mln/morpho/skeleton_constrained.hh b/milena/mln/morpho/skeleton_constrained.hh index 9dcf3d6..2c986e6 100644 --- a/milena/mln/morpho/skeleton_constrained.hh +++ b/milena/mln/morpho/skeleton_constrained.hh @@ -1,4 +1,5 @@ -// Copyright (C) 2008, 2009 EPITA Research and Development Laboratory (LRDE) +// Copyright (C) 2008, 2009, 2011 EPITA Research and Development +// Laboratory (LRDE) // // This file is part of Olena. // @@ -39,6 +40,7 @@ # include <mln/extension/adjust_duplicate.hh> # include <mln/data/fill.hh> +# include <mln/util/timer.hh> namespace mln { @@ -58,71 +60,242 @@ namespace mln # ifndef MLN_INCLUDE_ONLY - template <typename I, - typename N, typename F, - typename K, typename R> - inline - mln_ch_value(I, bool) - skeleton_constrained(const Image<I>& input_, - const Neighborhood<N>& nbh_, const F& is_simple, - const Image<K>& constraint_, const Image<R>& priority_) + + namespace impl { - trace::entering("morpho::skeleton_constrained"); - const I& input = exact(input_); - const N& nbh = exact(nbh_); - const K& constraint = exact(constraint_); - const R& priority = exact(priority_); + namespace generic + { - mln_precondition(input.is_valid()); - mln_precondition(nbh.is_valid()); - mln_precondition(constraint.is_valid()); - mln_precondition(priority.is_valid()); + template <typename I, + typename N, typename F, + typename K, typename R> + inline + mln_ch_value(I, bool) + skeleton_constrained(const Image<I>& input_, + const Neighborhood<N>& nbh_, const F& is_simple, + const Image<K>& constraint_, const Image<R>& priority_) + { + trace::entering("morpho::skeleton_constrained"); - extension::adjust_duplicate(input, nbh); + const I& input = exact(input_); + const N& nbh = exact(nbh_); + const K& constraint = exact(constraint_); + const R& priority = exact(priority_); - // FIXME: Tests! + mln_precondition(input.is_valid()); + mln_precondition(nbh.is_valid()); + mln_precondition(constraint.is_valid()); + mln_precondition(priority.is_valid()); - typedef mln_psite(I) P; - typedef p_queue_fast<P> Q; - p_priority<mln_value(R), Q> q; + typedef mln_value(I) V; + mlc_is(V, bool)::check(); - mln_ch_value(I, bool) output; + extension::adjust_duplicate(input, nbh); - // Initialization. - { - initialize(output, input); - data::fill(output, input); - extension::adjust_duplicate(output, nbh); - - mln_piter(I) p(input.domain()); - for_all(p) - if (input(p) == false && - is_simple(input, nbh, p)) // p is a simple point of the background. - { - q.push(priority(p), p); - } - } + // FIXME: Tests! - // Propagation. - { - P p; - mln_niter(N) n(nbh, p); - while (! q.is_empty()) + typedef mln_psite(I) P; + typedef p_queue_fast<P> Q; + p_priority<mln_value(R), Q> q; + + mln_concrete(I) output; + + // Initialization. + { + output = duplicate(input); + extension::adjust_duplicate(output, nbh); + + mln_piter(I) p(output.domain()); + for_all(p) + if (output(p) == false && + is_simple.check(input, p)) // <-- is_simple.check + // p is a simple point of the background. + { + q.push(priority(p), p); + } + } + + // Propagation. { - p = q.pop_front(); - for_all(n) - if (output.has(n) && - output(n) == true && - constraint(n) == false && - is_simple(output, nbh, n)) + P p; + mln_niter(N) n(nbh, p); + while (! q.is_empty()) + { + p = q.pop_front(); + for_all(n) + if (output.has(n) && + output(n) == true && + constraint(n) == false && + is_simple.check(output, n)) // <-- is_simple.check { output(n) = false; // Remove n from object. q.push(priority(n), n); } + } + } + + trace::exiting("morpho::skeleton_constrained"); + return output; + } + + } // end of namespace mln::morpho::impl::generic + + + template <typename I, + typename N, typename F, + typename K, typename R> + inline + mln_ch_value(I, bool) + skeleton_constrained_fast(const Image<I>& input_, + const Neighborhood<N>& nbh_, + const F& is_simple, + const Image<K>& constraint_, + const Image<R>& priority_) + { + trace::entering("morpho::skeleton_constrained_fast"); + + const I& input = exact(input_); + const N& nbh = exact(nbh_); + const K& constraint = exact(constraint_); + const R& priority = exact(priority_); + + mln_precondition(input.is_valid()); + mln_precondition(nbh.is_valid()); + mln_precondition(constraint.is_valid()); + mln_precondition(priority.is_valid()); + + typedef mln_value(I) V; + mlc_is(V, bool)::check(); + + // Whatever the value of the extension, results of this fast + // version may differ from the generic one. Indeed, we + // cannot check whether a site belongs to the image or not, + // so we try to not take border site in consideration by + // setting their value to false. + extension::adjust_fill(input, nbh, false); + extension::adjust_fill(constraint, nbh, false); + + // FIXME: Tests! + + typedef p_queue_fast<unsigned> Q; + p_priority<mln_value(R), Q> q; + + mln_concrete(I) output; + + // Initialization. + { + output = duplicate(input); + extension::adjust_fill(output, nbh, false); + + mln_pixter(I) p_out(output); + for_all(p_out) + if (p_out.val() == false && + is_simple.check__(input, p_out)) // <-- is_simple.check + // p is a simple point of the background. + { + q.push(priority.element(p_out.offset()), p_out); + } } + + // Propagation. + { + mln_pixter(I) p(output); + mln_nixter(I, N) n(p, nbh); + + util::array<int> dp = offsets_wrt(input, nbh); + const unsigned n_nbhs = dp.nelements(); + while (! q.is_empty()) + { + unsigned p = q.pop_front(); + + for (unsigned i = 0; i < n_nbhs; ++i) + { + unsigned n = p + dp[i]; + + if (output.element(n) == true && + constraint.element(n) == false && + is_simple.check__(output, n)) // <-- is_simple.check + { + output.element(n) = false; // Remove n from object. + q.push(priority.element(n), n); + } + } + } + } + + trace::exiting("morpho::skeleton_constrained_fast"); + return output; + } + + + } // end of namespace mln::morpho::impl + + + namespace internal + { + + template <typename I, + typename N, typename F, + typename K, typename R> + inline + mln_ch_value(I, bool) + skeleton_constrained_dispatch( + mln::trait::image::value_access::any, + mln::trait::image::value_storage::any, + const Image<I>& input, + const Neighborhood<N>& nbh, + const F& is_simple, + const Image<K>& constraint, + const Image<R>& priority) + { + return impl::generic::skeleton_constrained(input, nbh, + is_simple, + constraint, + priority); } + template <typename I, + typename N, typename F, + typename K, typename R> + inline + mln_ch_value(I, bool) + skeleton_constrained_dispatch( + mln::trait::image::value_access::direct, + mln::trait::image::value_storage::one_block, + const Image<I>& input, + const Neighborhood<N>& nbh, + const F& is_simple, + const Image<K>& constraint, + const Image<R>& priority) + { + return impl::skeleton_constrained_fast(input, nbh, + is_simple, + constraint, + priority); + } + + + } // end of namespace mln::morpho::internal + + + template <typename I, + typename N, typename F, + typename K, typename R> + inline + mln_ch_value(I, bool) + skeleton_constrained(const Image<I>& input, + const Neighborhood<N>& nbh, const F& is_simple, + const Image<K>& constraint, const Image<R>& priority) + { + trace::entering("morpho::skeleton_constrained"); + + mln_ch_value(I, bool) + output = internal::skeleton_constrained_dispatch( + mln_trait_image_value_access(I)(), + mln_trait_image_value_storage(I)(), + input, nbh, is_simple, constraint, priority); + trace::exiting("morpho::skeleton_constrained"); return output; } diff --git a/milena/mln/topo/skeleton/crest.hh b/milena/mln/topo/skeleton/crest.hh index 73a1c66..b4b7b27 100644 --- a/milena/mln/topo/skeleton/crest.hh +++ b/milena/mln/topo/skeleton/crest.hh @@ -1,5 +1,5 @@ -// Copyright (C) 2009, 2010 EPITA Research and Development Laboratory -// (LRDE) +// Copyright (C) 2009, 2010, 2011 EPITA Research and Development +// Laboratory (LRDE) // // This file is part of Olena. // @@ -34,6 +34,8 @@ # include <mln/core/concept/image.hh> # include <mln/core/concept/neighborhood.hh> # include <mln/data/fill.hh> +# include <mln/extension/adjust.hh> +# include <mln/border/equalize.hh> namespace mln @@ -103,55 +105,205 @@ namespace mln # ifndef MLN_INCLUDE_ONLY + // IMPLEMENTATIONS - template <typename I, typename D, typename N> - mln_concrete(I) - crest(const Image<I>& input_, const Image<D>& dist_map_, - const Neighborhood<N>& nbh_, unsigned psi_threshold) + namespace impl { - trace::entering("topo::skeleton::crest"); - const I& input = exact(input_); - const D& dist_map = exact(dist_map_); - const N& nbh = exact(nbh_); - mlc_equal(mln_value(I), bool)::check(); - mln_precondition(input.is_valid()); - mln_precondition(dist_map.is_valid()); - mln_precondition(nbh.is_valid()); + namespace generic + { + + template <typename I, typename D, typename N> + mln_concrete(I) + crest(const Image<I>& input_, const Image<D>& dist_map_, + const Neighborhood<N>& nbh_, unsigned psi_threshold) + { + trace::entering("topo::skeleton::impl::generic::crest"); + const I& input = exact(input_); + const D& dist_map = exact(dist_map_); + const N& nbh = exact(nbh_); + + mlc_equal(mln_value(I), bool)::check(); + mln_precondition(input.is_valid()); + mln_precondition(dist_map.is_valid()); + mln_precondition(nbh.is_valid()); + + mln_concrete(I) is_crest; + initialize(is_crest, input); + data::fill(is_crest, false); + + mln_piter(I) p(input.domain()); + mln_niter(N) n(nbh, p); + for_all(p) + { + if (!input(p) || dist_map(p) < static_cast<mln_value(D)>(0)) + continue; + + unsigned nb_eq = 0; + unsigned nb_lt = 0; + for_all(n) + if (input.domain().has(n) + // We want to only consider sites which are part of + // the skeleton. If this test is removed, sometimes + // edge sites are considered as sites with a high PSI + // which is wrong. + && dist_map(n) > static_cast<mln_value(D)>(0)) + { + if (dist_map(n) == dist_map(p)) + ++nb_eq; + else if (dist_map(n) < dist_map(p)) + ++nb_lt; + } + + if ((nb_lt + nb_eq) >= psi_threshold) // Pixel Superiority index + is_crest(p) = true; + } + + trace::exiting("topo::skeleton::impl::generic::crest"); + return is_crest; + } + + } // end of namespace mln::topo::skeleton::impl::generic - mln_concrete(I) is_crest; - initialize(is_crest, input); - data::fill(is_crest, false); - mln_piter(I) p(input.domain()); - mln_niter(N) n(nbh, p); - for_all(p) + + + template <typename I, typename D, typename N> + mln_concrete(I) + crest_fastest_2d(const Image<I>& input_, const Image<D>& dist_map_, + const Neighborhood<N>& nbh_, unsigned psi_threshold) { - if (!input(p) || dist_map(p) < static_cast<mln_value(D)>(0)) - continue; - - unsigned nb_eq = 0; - unsigned nb_lt = 0; - for_all(n) - if (input.domain().has(n) - // We want to only consider sites which are part of - // the skeleton. If this test is removed, sometimes - // edge sites are considered as sites with a high PSI - // which is wrong. - && dist_map(n) > static_cast<mln_value(D)>(0)) + trace::entering("topo::skeleton::impl::crest_fastest_2d"); + + const I& input = exact(input_); + const D& dist_map = exact(dist_map_); + const N& nbh = exact(nbh_); + + mlc_equal(mln_value(I), bool)::check(); + mln_precondition(input.is_valid()); + mln_precondition(dist_map.is_valid()); + mln_precondition(nbh.is_valid()); + mln_precondition(input.domain() == dist_map.domain()); + + extension::adjust(input, nbh); + border::equalize(input, dist_map, input.border()); + + mln_concrete(I) is_crest; + initialize(is_crest, input); + data::fill(is_crest, false); + + + mln_pixter(const I) p(input); + util::array<int> dp = mln::offsets_wrt(input, nbh); + unsigned n_nbhs = dp.nelements(); + for_all(p) + { + if (!p.val() + || dist_map.element(p) < static_cast<mln_value(D)>(0)) + continue; + + unsigned nb_eq = 0; + unsigned nb_lt = 0; + for (unsigned i = 0; i < n_nbhs; ++i) { - if (dist_map(n) == dist_map(p)) - ++nb_eq; - else if (dist_map(n) < dist_map(p)) - ++nb_lt; + unsigned n = p.offset() + dp[i]; + if (// We want to only consider sites which are part of + // the skeleton. If this test is removed, sometimes + // edge sites are considered as sites with a high PSI + // which is wrong. + dist_map.element(n) > static_cast<mln_value(D)>(0)) + { + if (dist_map.element(n) == dist_map.element(p)) + ++nb_eq; + else if (dist_map.element(n) < dist_map.element(p)) + ++nb_lt; + } + + if ((nb_lt + nb_eq) >= psi_threshold) // Pixel Superiority index + is_crest.element(p) = true; } - if ((nb_lt + nb_eq) >= psi_threshold) // Pixel Superiority index - is_crest(p) = true; + } + + trace::exiting("topo::skeleton::impl::crest_fastest_2d"); + return is_crest; } + } // end of namespace mln::topo::skeleton::impl + + + // DISPATCH + + namespace internal + { + + template <typename I, typename D, typename N> + mln_concrete(I) + crest_dispatch_2d(mln::trait::image::value_storage::any, + mln::trait::image::value_access::any, + mln::trait::image::ext_domain::any, + const Image<I>& input, const Image<D>& dist_map, + const Neighborhood<N>& nbh, unsigned psi_threshold) + { + return skeleton::impl::generic::crest(input, dist_map, + nbh, psi_threshold); + } + + + template <typename I, typename D, typename N> + mln_concrete(I) + crest_dispatch_2d(mln::trait::image::value_storage::one_block, + mln::trait::image::value_access::direct, + mln::trait::image::ext_domain::some, + const Image<I>& input, const Image<D>& dist_map, + const Neighborhood<N>& nbh, unsigned psi_threshold) + { + return skeleton::impl::crest_fastest_2d(input, dist_map, + nbh, psi_threshold); + } + + + template <typename I, typename D, typename N> + mln_concrete(I) + crest_dispatch(const Image<I>& input, const Image<D>& dist_map, + const Neighborhood<N>& nbh, unsigned psi_threshold) + { + unsigned dim = mln_site_(I)::dim; + + if (dim == 2) + return + crest_dispatch_2d(mln_trait_image_value_storage(I)(), + mln_trait_image_value_access(I)(), + mln_trait_image_ext_domain(I)(), + input, dist_map, nbh, psi_threshold); + + return impl::generic::crest(input, dist_map, nbh, psi_threshold); + } + + + } // end of namespace mln::topo::skeleton::internal + + + // FACADES + + template <typename I, typename D, typename N> + mln_concrete(I) + crest(const Image<I>& input, const Image<D>& dist_map, + const Neighborhood<N>& nbh, unsigned psi_threshold) + { + trace::entering("topo::skeleton::crest"); + + mlc_equal(mln_value(I), bool)::check(); + mln_precondition(exact(input).is_valid()); + mln_precondition(exact(dist_map).is_valid()); + mln_precondition(exact(nbh).is_valid()); + + mln_concrete(I) + output = internal::crest_dispatch(input, dist_map, + nbh, psi_threshold); + trace::exiting("topo::skeleton::crest"); - return is_crest; + return output; } diff --git a/milena/mln/topo/skeleton/is_simple_point.hh b/milena/mln/topo/skeleton/is_simple_point.hh index 590bf60..05d82a9 100644 --- a/milena/mln/topo/skeleton/is_simple_point.hh +++ b/milena/mln/topo/skeleton/is_simple_point.hh @@ -1,4 +1,5 @@ -// Copyright (C) 2009 EPITA Research and Development Laboratory (LRDE) +// Copyright (C) 2009, 2011 EPITA Research and Development Laboratory +// (LRDE) // // This file is part of Olena. // @@ -60,20 +61,35 @@ namespace mln \endverbatim */ - template <typename I, typename N> - bool - is_simple_point(const Image<I>& ima, - const Neighborhood<N>& nbh, - const mln_site(I)& p); + template <typename N> + struct is_simple_point + { + + is_simple_point(const Neighborhood<N>& nbh); + + template <typename I> + bool check(const I& ima, const mln_psite(I)& p) const; + template <typename I> + bool check__(const I& ima, unsigned p) const; + + protected: + const N& nbh_; + bool is_c8_; + + template <typename I> + unsigned nb_connexity2d(const I&, bool nbh_c8, + const mln_psite(I)& p, bool object) const; + template <typename I> + unsigned nb_connexity2d__(const I&, bool nbh_c8, + unsigned p, bool object) const; + }; # ifndef MLN_INCLUDE_ONLY namespace internal { - - static const unsigned char nb_connexity_c8[256] = { 0, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 2, 2, 1, 1, @@ -120,157 +136,94 @@ namespace mln 1, 1, 2, 2, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1 }; + } // end of namespace internal + template <typename N> + is_simple_point<N>::is_simple_point(const Neighborhood<N>& nbh) + : nbh_(exact(nbh)), is_c8_(exact(nbh) == c8()) + { + mln_assertion(nbh_ == c4() || nbh_ == c8()); + mln_precondition(nbh_.is_valid()); + } - template <typename I, typename N> - inline - unsigned - nb_connexity2d(const I& ima, - const N& nbh, - const mln_site(I)& p, - bool object) - { - unsigned res = 0; - - mln_bkd_niter(N) n(c8(), p); - for_all(n) - { - res = (res << 1); - if (ima.domain().has(n) && ima(n) == object) - res = res | 1; - } - - if (nbh == c8()) - return nb_connexity_c8[res]; - else - { - mln_assertion(nbh == c4()); - return nb_connexity_c4[res]; - } - } - - - template <typename N> - neighb2d - complement2d(const Neighborhood<N>& nbh_) - { - const N& nbh = exact(nbh_); - mln_precondition(nbh.is_valid()); - mln_precondition(nbh == c4() || nbh == c8()); - - if (nbh == c4()) - return c8(); - else - return c4(); - } - - - // Tests. - - template <typename I, typename N> - inline - void - is_simple_point_tests(const Image<I>& ima_, - const Neighborhood<N>& nbh_, - const mln_site(I)& p) - { - const I& ima = exact(ima_); - const N& nbh = exact(nbh_); - - mln_assertion(nbh == c4() || nbh == c8()); - mln_precondition(ima.is_valid()); - mln_precondition(nbh.is_valid()); - - (void) ima; - (void) nbh; - (void) p; - } - - } // end of namespace mln::topo::skeleton::internal - - - - // Implementations - namespace impl + template <typename N> + template <typename I> + unsigned + is_simple_point<N>::nb_connexity2d(const I& ima, + bool nbh_c8, + const mln_psite(I)& p, + bool object) const { + unsigned res = 0; - template <typename I, typename N> - inline - bool - is_simple_point2d(const Image<I>& ima_, - const Neighborhood<N>& nbh_, - const point2d& p) + mln_bkd_niter(N) n(c8(), p); + for_all(n) { - const I& ima = exact(ima_); - const N& nbh = exact(nbh_); - - internal::is_simple_point_tests(ima, nbh, p); - - bool b = (internal::nb_connexity2d(ima, nbh, p, true) == 1) - && (internal::nb_connexity2d(ima, internal::complement2d(nbh), - p, false) == 1); - - trace::exiting("topo::skeleton::is_simple_point2d"); - return b; + res = (res << 1); + if (ima.domain().has(n) && ima(n) == object) + res = res | 1; } - } // end of namespace mln::topo::skeleton::impl - - - + if (nbh_c8) + return internal::nb_connexity_c8[res]; + else + return internal::nb_connexity_c4[res]; + } - // Dispatch - namespace internal + template <typename N> + template <typename I> + unsigned + is_simple_point<N>::nb_connexity2d__(const I& ima, + bool nbh_c8, + unsigned p, + bool object) const { + unsigned res = 0; - template <typename I, typename N> - inline - bool - is_simple_point_dispatch(const Image<I>& ima, - const Neighborhood<N>& nbh, - const point2d& p) - { - return impl::is_simple_point2d(ima, nbh, p); - } - + static util::array<int> + noffset = mln::offsets_wrt(ima, c8()); - template <typename I, typename N> - inline - bool - is_simple_point_dispatch(const Image<I>& ima, - const Neighborhood<N>& nbh, - const mln_site(I)& p) + for (int i = noffset.nelements() - 1; i >= 0; --i) { - /// Not implemented for that site type yet. - mlc_abort(I)::check(); - return false; + res = (res << 1); + if (ima.element(p + noffset[i]) == object) + res = res | 1; } - } // end of namespace mln::topo::skeleton::internal + if (nbh_c8) + return internal::nb_connexity_c8[res]; + else + return internal::nb_connexity_c4[res]; + } + template <typename N> + template <typename I> + inline + bool + is_simple_point<N>::check(const I& ima, + const mln_psite(I)& p) const + { + mln_precondition(ima.is_valid()); + return (nb_connexity2d(ima, is_c8_, p, true) == 1) // Consider neighbor. + && (nb_connexity2d(ima, !is_c8_, p, false) == 1); // Consider complement neighbor. + } - // Facade - template <typename I, typename N> + template <typename N> + template <typename I> inline bool - is_simple_point(const Image<I>& ima, - const Neighborhood<N>& nbh, - const mln_site(I)& p) + is_simple_point<N>::check__(const I& ima, + unsigned p) const { - trace::entering("topo::skeleton::is_simple_point2d"); - - internal::is_simple_point_tests(ima, nbh, p); - - bool b = internal::is_simple_point_dispatch(ima, nbh, p); - - trace::exiting("topo::skeleton::is_simple_point2d"); - return b; + mln_precondition(ima.is_valid()); + return (nb_connexity2d__(ima, is_c8_, p, true) == 1) // Consider neighbor + && (nb_connexity2d__(ima, !is_c8_, p, false) == 1); // Consider complement neighbor. } diff --git a/milena/tests/topo/skeleton/is_simple_point.cc b/milena/tests/topo/skeleton/is_simple_point.cc index 1989f94..d5ff1e1 100644 --- a/milena/tests/topo/skeleton/is_simple_point.cc +++ b/milena/tests/topo/skeleton/is_simple_point.cc @@ -1,4 +1,5 @@ -// Copyright (C) 2009 EPITA Research and Development Laboratory (LRDE) +// Copyright (C) 2009, 2011 EPITA Research and Development Laboratory +// (LRDE) // // This file is part of Olena. // @@ -27,8 +28,6 @@ #include <mln/topo/skeleton/is_simple_point.hh> #include <mln/make/image.hh> -#include <mln/debug/println.hh> - static const unsigned ref[] = { 1, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0 }; int main() @@ -38,10 +37,17 @@ int main() bool vals[][6] = { { 0, 1, 0, 0, 1, 1 }, { 0, 0, 0, 0, 1, 1 } }; - image2d<bool> ima = make::image(vals); + typedef image2d<bool> I; + I ima = make::image(vals); unsigned i = 0; - mln_piter_(image2d<bool>) p(ima.domain()); - for_all(p) - mln_assertion(ref[i++] == topo::skeleton::is_simple_point(ima, c8(), p)); + topo::skeleton::is_simple_point<neighb2d> is_simple(c8()); + + // Test generic version. + { + mln_piter_(I) p(ima.domain()); + for_all(p) + mln_assertion(ref[i++] == is_simple.check(ima, p)); + } + } -- 1.5.6.5
participants (1)
-
Guillaume Lazzara