milena r3319: Implement fastest versions of labeling

URL: https://svn.lrde.epita.fr/svn/oln/trunk/milena ChangeLog: 2009-02-09 Fabien Freling <freling@lrde.epita.fr> Implement fastest versions of labeling. * mln/canvas/labeling.hh: Change labeling() to labeling_video() and * labeling_sorted(). * mln/labeling/flat_zones.hh: Implement fastest version. * mln/labeling/level.hh: Implement fastest version. * mln/labeling/regional_maxima.hh: Implement fastest version. * mln/labeling/regional_minima.hh: Implement fastest version. --- canvas/labeling.hh | 419 ++++++++++++++++++++++++++++++++++++++++---- labeling/flat_zones.hh | 61 ++---- labeling/level.hh | 102 ++-------- labeling/regional_maxima.hh | 70 ++----- labeling/regional_minima.hh | 76 +++---- 5 files changed, 498 insertions(+), 230 deletions(-) Index: trunk/milena/mln/canvas/labeling.hh =================================================================== --- trunk/milena/mln/canvas/labeling.hh (revision 3318) +++ trunk/milena/mln/canvas/labeling.hh (revision 3319) @@ -1,5 +1,5 @@ -// Copyright (C) 2007, 2008, 2009 EPITA Research and Development -// Laboratory (LRDE) +// Copyright (C) 2007, 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 @@ -39,6 +39,10 @@ # include <mln/data/fill.hh> # include <mln/literal/zero.hh> # include <mln/convert/to_upper_window.hh> +# include <mln/extension/adjust_fill.hh> + +# include <mln/level/sort_psites.hh> +# include <mln/level/sort_offsets.hh> namespace mln @@ -47,11 +51,20 @@ namespace canvas { - // General version. - template <typename I, typename N, typename F, typename L> + template <typename I, typename N, typename L, + typename F> + mln_ch_value(I, L) + labeling_video(const Image<I>& input, const Neighborhood<N>& nbh, L& nlabels, + F& functor); + + + template <typename I, typename N, typename L, + typename F> mln_ch_value(I, L) - labeling(const Image<I>& input, const Neighborhood<N>& nbh, - F& functor, L& nlabels); + labeling_sorted(const Image<I>& input, const Neighborhood<N>& nbh, L& nlabels, + F& functor, bool increasing); + + # ifndef MLN_INCLUDE_ONLY @@ -61,21 +74,22 @@ namespace internal { - template <typename I, typename N, typename F, typename L> + template <typename I, typename N, typename L, + typename F> void - labeling_tests(const Image<I>& input_, const Neighborhood<N>& nbh_, - const F& f, const L& nlabels) + labeling_tests(const Image<I>& input_, const Neighborhood<N>& nbh_, const L& nlabels, + const F& f) { const I& input = exact(input_); const N& nbh = exact(nbh_); mln_precondition(input.is_valid()); - mln_precondition(nbh.is_valid()); + // mln_precondition(nbh.is_valid()); (void) input; (void) nbh; - (void) f; (void) nlabels; + (void) f; } } // end of namespace mln::canvas::internal @@ -101,10 +115,11 @@ return parent(x) = find_root(parent, parent(x)); } - template <typename I, typename N, typename F, typename L> + template <typename I, typename N, typename L, + typename S, typename F> mln_ch_value(I, L) - labeling(const Image<I>& input_, const Neighborhood<N>& nbh_, - F& f, L& nlabels) + labeling(const Image<I>& input_, const Neighborhood<N>& nbh_, L& nlabels, + const S& s, F& f) { trace::entering("canvas::impl::generic::labeling"); @@ -113,8 +128,6 @@ const I& input = exact(input_); const N& nbh = exact(nbh_); - typedef typename F::S S; - // Local type. typedef mln_psite(I) P; @@ -124,6 +137,7 @@ // Output. mln_ch_value(I, L) output; + bool status; // Initialization. { @@ -141,7 +155,7 @@ // First Pass. { - mln_fwd_piter(S) p(f.s); + mln_fwd_piter(S) p(s); mln_niter(N) n(nbh, p); for_all(p) if (f.handles(p)) { @@ -171,7 +185,7 @@ // Second Pass. { - mln_bkd_piter(S) p(f.s); + mln_bkd_piter(S) p(s); for_all(p) if (f.handles(p)) { if (parent(p) == p) // if p is root @@ -180,7 +194,7 @@ { if (nlabels == mln_max(L)) { - trace::warning("labeling aborted!"); + status = false; return output; } output(p) = ++nlabels; @@ -189,6 +203,7 @@ else output(p) = output(parent(p)); } + status = true; } trace::exiting("canvas::impl::generic::labeling"); @@ -197,6 +212,244 @@ } // end of namespace mln::canvas::impl::generic + + + // Fastest video version. + + template <typename I> + static inline + unsigned + find_root_fastest(I& parent, unsigned x) + { + if (parent.element(x) == x) + return x; + else + return parent.element(x) = find_root_fastest(parent, parent.element(x)); + } + + + template <typename I, typename N, typename L, + typename F> + mln_ch_value(I, L) + labeling_video_fastest(const Image<I>& input_, const Neighborhood<N>& nbh_, + L& nlabels, F& f) + { + trace::entering("canvas::impl::labeling_video_fastest"); + + // FIXME: Test?! + + const I& input = exact(input_); + const N& nbh = exact(nbh_); + + extension::adjust(input, nbh); + + // Auxiliary data. + mln_ch_value(I, bool) deja_vu; + mln_ch_value(I, unsigned) parent; + + // Output. + mln_ch_value(I, L) output; + bool status; + + // Initialization. + { + initialize(deja_vu, input); + mln::data::fill(deja_vu, false); + extension::fill(deja_vu, false); // So that the extension is ignored. + + initialize(parent, input); + + initialize(output, input); + mln::data::fill(output, L(literal::zero)); + nlabels = 0; + + f.init_(); // Client initialization. + } + + // First Pass. + { + mln_pixter(const I) px(input); + mln_nixter(const I, N) nx(px, nbh); + for_all(px) + { + unsigned p = px.offset(); + if (! f.handles_(p)) + continue; + + // Make-Set. + parent.element(p) = p; + f.init_attr_(p); + for_all(nx) + { + unsigned n = nx.offset(); + if (deja_vu.element(n)) + { + if (f.equiv_(n, p)) + { + // Do-Union. + unsigned r = find_root_fastest(parent, n); + if (r != p) + { + parent.element(r) = p; + f.merge_attr_(r, p); + } + } + else + f.do_no_union_(n, p); + } + } + + deja_vu.element(p) = true; + } + } + + // Second Pass. + { + mln_bkd_pixter(const I) px(input); + for_all(px) + { + unsigned p = px.offset(); + if (! f.handles_(p)) + continue; + if (parent.element(p) == p) // if p is root + { + if (f.labels_(p)) + { + if (nlabels == mln_max(L)) + { + status = false; + return output; + } + output.element(p) = ++nlabels; + } + } + else + output.element(p) = output.element(parent.element(p)); + } + status = true; + } + + trace::exiting("canvas::impl::labeling_video_fastest"); + return output; + } + + + + // Fastest sorted version + + template <typename I, typename N, typename L, + typename S, typename F> + mln_ch_value(I, L) + labeling_sorted_fastest(const Image<I>& input_, const Neighborhood<N>& nbh_, L& nlabels, + const S& s, F& f) + { + trace::entering("canvas::impl::labeling_sorted_fastest"); + + // FIXME: Test?! + + const I& input = exact(input_); + const N& nbh = exact(nbh_); + + extension::adjust(input, nbh); + + // Local type. + typedef mln_psite(I) P; + + // Auxiliary data. + mln_ch_value(I, bool) deja_vu; + mln_ch_value(I, unsigned) parent; + + // Output. + mln_ch_value(I, L) output; + bool status; + + // Initialization. + { + initialize(deja_vu, input); + mln::data::fill(deja_vu, false); + extension::fill(deja_vu, false); // So that the extension is ignored. + + initialize(parent, input); + + initialize(output, input); + mln::data::fill(output, L(literal::zero)); + nlabels = 0; + + f.init_(); // Client initialization. + } + + util::array<int> dp = offsets_wrt(input, nbh); + const unsigned n_nbhs = dp.nelements(); + + const unsigned n_points = s.nelements(); + + // First Pass. + { + + for (unsigned i = 0; i < n_points; ++i) + { + unsigned p = s[i]; + if (! f.handles_(p)) + continue; + + // Make-Set. + parent.element(p) = p; + f.init_attr_(p); + + for (unsigned j = 0; j < n_nbhs; ++j) + { + unsigned n = p + dp[j]; + if (! deja_vu.element(n)) + continue; + + if (f.equiv_(n, p)) + { + // Do-Union. + unsigned r = find_root_fastest(parent, n); + if (r != p) + { + parent.element(r) = p; + f.merge_attr_(r, p); + } + } + else + f.do_no_union_(n, p); + } + deja_vu.element(p) = true; + + } + } + + // Second Pass. + { + for (int i = n_points - 1; i >=0; --i) + { + unsigned p = s[i]; + if (! f.handles_(p)) + continue; + + if (parent.element(p) == p) // if p is root + { + if (f.labels_(p)) + { + if (nlabels == mln_max(L)) + { + status = false; + return output; + } + output.element(p) = ++nlabels; + } + } + else + output.element(p) = output.element(parent.element(p)); + } + status = true; + } + + trace::exiting("canvas::impl::labeling_sorted_fastest"); + return output; + } + } // end of namespace mln::canvas::impl @@ -206,39 +459,143 @@ namespace internal { - template <typename I, typename N, typename F, typename L> + // Video + + template <typename I, typename N, typename L, + typename F> inline mln_ch_value(I, L) - labeling_dispatch(const Image<I>& input, const Neighborhood<N>& nbh, - F& functor, L& nlabels) + labeling_video(metal::false_, const Image<I>& input, + const Neighborhood<N>& nbh, L& nlabels, F& functor) { - return impl::generic::labeling(input, nbh, functor, nlabels); + return impl::generic::labeling(input, nbh, input.domain(), + nlabels, functor); } + template <typename I, typename N, typename L, + typename F> + inline + mln_ch_value(I, L) + labeling_video(metal::true_, const Image<I>& input, + const Neighborhood<N>& nbh, L& nlabels, F& functor) + { + return impl::labeling_video_fastest(input, nbh, nlabels, functor); + } + + template <typename I, typename N, typename L, + typename F> + inline + mln_ch_value(I, L) + labeling_video_dispatch(const Image<I>& input, const Neighborhood<N>& nbh, + L& nlabels, F& functor) + { + enum { + test = mlc_equal(mln_trait_image_speed(I), + trait::image::speed::fastest)::value + && + mln_is_simple_neighborhood(N)::value + }; + return labeling_video(metal::bool_<test>(), input, + nbh, nlabels, functor); + } + + + // Sorted dispatch. + + template <typename I, typename N, typename L, typename F> + inline + mln_ch_value(I, L) + labeling_sorted_dispatch(metal::false_, + const Image<I>& input, const Neighborhood<N>& nbh, L& nlabels, + F& functor, bool increasing) + { + p_array<mln_psite(I)> s = + increasing ? + level::sort_psites_increasing(input) : + level::sort_psites_decreasing(input); + return impl::generic::labeling(input, nbh, nlabels, + s, functor); + } + + template <typename I, typename N, typename L, typename F> + inline + mln_ch_value(I, L) + labeling_sorted_dispatch(metal::true_, + const Image<I>& input, const Neighborhood<N>& nbh, L& nlabels, + F& functor, bool increasing) + { + util::array<unsigned> s = + increasing ? + level::sort_offsets_increasing(input) : + level::sort_offsets_decreasing(input); + return impl::labeling_sorted_fastest(input, nbh, nlabels, + s, functor); + } + + template <typename I, typename N, typename L, typename F> + inline + mln_ch_value(I, L) + labeling_sorted_dispatch(const Image<I>& input, const Neighborhood<N>& nbh, L& nlabels, + F& functor, bool increasing) + { + enum { + test = mlc_equal(mln_trait_image_speed(I), + trait::image::speed::fastest)::value + && + mln_is_simple_neighborhood(N)::value + }; + return labeling_sorted_dispatch(metal::bool_<test>(), + input, nbh, nlabels, + functor, increasing); + } + + } // end of namespace mln::canvas::internal - // Facade. + // Facades. + - template <typename I, typename N, typename F, typename L> + template <typename I, typename N, typename L, + typename F> inline mln_ch_value(I, L) - labeling(const Image<I>& input, const Neighborhood<N>& nbh, - F& functor, L& nlabels) + labeling_video(const Image<I>& input, const Neighborhood<N>& nbh, L& nlabels, + F& functor) { - trace::entering("canvas::labeling"); + trace::entering("canvas::labeling_video"); - internal::labeling_tests(input, nbh, functor, nlabels); + internal::labeling_tests(input, nbh, nlabels, functor); mln_ch_value(I, L) output; - output = internal::labeling_dispatch(input, nbh, functor, nlabels); + output = internal::labeling_video_dispatch(input, nbh, nlabels, + functor); - trace::exiting("canvas::labeling"); + trace::exiting("canvas::labeling_video"); return output; } + template <typename I, typename N, typename L, + typename F> + inline + mln_ch_value(I, L) + labeling_sorted(const Image<I>& input, const Neighborhood<N>& nbh, L& nlabels, + F& functor, bool increasing) + { + trace::entering("canvas::labeling_sorted"); + + internal::labeling_tests(input, nbh, nlabels, functor); + + mln_ch_value(I, L) output; + output = internal::labeling_sorted_dispatch(input, nbh, nlabels, + functor, increasing); + + trace::exiting("canvas::labeling_sorted"); + return output; + } + # endif // ! MLN_INCLUDE_ONLY } // end of namespace mln::canvas Index: trunk/milena/mln/labeling/flat_zones.hh =================================================================== --- trunk/milena/mln/labeling/flat_zones.hh (revision 3318) +++ trunk/milena/mln/labeling/flat_zones.hh (revision 3319) @@ -64,64 +64,47 @@ // Flat zone functor for the labeling canvas. - template <typename I_, typename N_, typename L_> + template <typename I> struct flat_zones_functor { - typedef mln_psite(I_) P; + typedef mln_psite(I) P; - // requirements from mln::canvas::labeling: + // Requirements from mln::canvas::labeling: - typedef I_ I; - typedef N_ N; - typedef L_ L; typedef mln_pset(I) S; const I& input; - const N& nbh; - const S& s; + // Generic implementation. + + void init() {} bool handles(const P&) const { return true; } bool equiv(const P& n, const P& p) const { return input(n) == input(p); } - - void init() {} bool labels(const P&) const { return true; } void do_no_union(const P&, const P&) {} void init_attr(const P&) {} void merge_attr(const P&, const P&) {} - // end of requirements + // Fastest implementation. + + void init_() {} + bool handles_(unsigned) const { return true; } + bool equiv_(unsigned n, unsigned p) const { return input.element(n) == + input.element(p); } + bool labels_(unsigned) const { return true; } + void do_no_union_(unsigned, unsigned) {} + void init_attr_(unsigned) {} + void merge_attr_(unsigned, unsigned) {} + + // end of requirements. flat_zones_functor(const I& input, const N& nbh) - : input(input), - nbh(nbh), - s(input.domain()) + : input(input) {} }; - // Generic implementation. - - namespace generic - { - - template <typename I, typename N, typename L> - mln_ch_value(I, L) - flat_zones(const Image<I>& input, const Neighborhood<N>& nbh, L& nlabels) - { - trace::entering("labeling::impl::generic::flat_zones"); - - typedef flat_zones_functor<I,N,L> F; - F f(exact(input), exact(nbh)); - mln_ch_value(I, L) output = canvas::labeling(input, nbh, f, nlabels); - - trace::exiting("labeling::impl::generic::flat_zones"); - return output; - } - - } // end of namespace mln::labeling::impl::generic - - } // end of namespace mln::labeling::impl @@ -139,8 +122,10 @@ const N& nbh = exact(nbh_); mln_precondition(input.is_valid()); - // Calls the only (generic) impl. - mln_ch_value(I, L) output = impl::generic::flat_zones(input, nbh, nlabels); + // Calls the only implementation. + typedef flat_zones_functor<I,N,L> F; + F f(exact(input), exact(nbh)); + mln_ch_value(I, L) output = canvas::labeling_video(input, nbh, nlabels, f); trace::exiting("labeling::flat_zones"); return output; Index: trunk/milena/mln/labeling/level.hh =================================================================== --- trunk/milena/mln/labeling/level.hh (revision 3318) +++ trunk/milena/mln/labeling/level.hh (revision 3319) @@ -36,11 +36,10 @@ # include <mln/core/concept/image.hh> # include <mln/core/concept/neighborhood.hh> -# include <mln/canvas/labeling.hh> -# include <mln/data/fill.hh> -// The 'fastest' specialization is in: -# include <mln/labeling/level.spe.hh> +# include "labeling.hh" + +# include <mln/data/fill.hh> @@ -79,7 +78,7 @@ L& nlabels) { mln_precondition(exact(input).is_valid()); - mln_precondition(exact(nbh).is_valid()); + // mln_precondition(exact(nbh).is_valid()); (void) input; (void) val; @@ -91,40 +90,13 @@ - // Generic implementation. - namespace impl { - - struct labeling_functor_base - { - void init() {} - - template <typename P> - bool handles(const P&) const { return true; } - - template <typename L, typename R> - bool equiv(const L&, const R&) const { return false; } - - template <typename P> - bool labels(const P&) const { return true; } - - template <typename L, typename R> - void do_no_union(const L&, const R&) {} - - template <typename P> - void init_attr(const P&) {} - - template <typename L, typename R> - void merge_attr(const L&, const R&) {} - }; - - // Generic functor. template <typename I> - struct level_functor : labeling_functor_base + struct level_functor { typedef mln_psite(I) P; @@ -134,68 +106,39 @@ // Requirements from mln::canvas::labeling. typedef mln_pset(I) S; - const S& s; + + // Generic implementation void init() {} bool handles(const P& p) const { return input(p) == val; } bool equiv(const P& n, const P&) const { return input(n) == val; } bool labels(const P&) const { return true; } + void do_no_union(const P& n, const P& p) {} + void init_attr(const P&) {} + void merge_attr(const P& r, const P& p) {} + + // Fastest implementation + + void init_() {} + bool handles_(unsigned p) const { return input.element(p) == val; } + bool equiv_(unsigned n, unsigned) const { return input.element(n) == val; } + bool labels_(unsigned) const { return true; } + void do_no_union_(unsigned n, unsigned p) {} + void init_attr_(unsigned) {} + void merge_attr_(unsigned r, unsigned p) {} // end of Requirements. level_functor(const Image<I>& input_, const mln_value(I)& val) : input(exact(input_)), - val(val), - s(input.domain()) + val(val) { } }; - - - // Generic implementation. - - namespace generic - { - - template <typename I, typename N, typename L> - mln_ch_value(I, L) - level(const Image<I>& input, const mln_value(I)& val, - const Neighborhood<N>& nbh, - L& nlabels) - { - trace::entering("labeling::impl::generic::level"); - - internal::level_tests(input, val, nbh, nlabels); - - level_functor<I> f(input, val); - mln_ch_value(I, L) output = canvas::labeling(input, nbh, f, nlabels); - - trace::exiting("labeling::impl::generic::level"); - return output; - } - - } // end of namespace mln::labeling::impl::generic - - } // end of namespace mln::labeling::impl - // Dispatch. - - namespace internal - { - - template <typename I, typename N, typename L> - mln_ch_value(I, L) - level_dispatch(const Image<I>& input, const mln_value(I)& val, const Neighborhood<N>& nbh, - L& nlabels) - { - return impl::generic::level(input, val, nbh, nlabels); - } - - } // end of namespace mln::labeling::internal - // Facade. @@ -210,7 +153,8 @@ internal::level_tests(input, val, nbh, nlabels); mln_ch_value(I, L) output; - output = internal::level_dispatch(input, val, nbh, nlabels); + impl::level_functor<I> f(input, val); + output = canvas::labeling_video(input, nbh, nlabels, f); trace::exiting("labeling::level"); return output; Index: trunk/milena/mln/labeling/regional_minima.hh =================================================================== --- trunk/milena/mln/labeling/regional_minima.hh (revision 3318) +++ trunk/milena/mln/labeling/regional_minima.hh (revision 3319) @@ -35,7 +35,9 @@ # include <mln/core/concept/image.hh> # include <mln/core/concept/neighborhood.hh> -# include <mln/canvas/labeling.hh> + +# include "labeling.hh" + # include <mln/data/fill.hh> # include <mln/level/sort_psites.hh> @@ -68,21 +70,16 @@ // Generic functor. - template <typename I_, typename N_, typename L_> + template <typename I> struct regional_minima_functor { - typedef mln_psite(I_) P; + typedef mln_psite(I) P; // requirements from mln::canvas::labeling: - typedef I_ I; - typedef N_ N; - typedef L_ L; - typedef p_array<P> S; - const I& input; - const N& nbh; - S s; + + // Generic implementation void init() { data::fill(attr, true); } bool handles(const P&) const { return true; } @@ -103,43 +100,37 @@ void merge_attr(const P& r, const P& p) { attr(p) = attr(p) && attr(r); } - // end of requirements - - mln_ch_value(I, bool) attr; + // Fastest implementation - regional_minima_functor(const I_& input, const N_& nbh) - : input(input), - nbh(nbh), - s(level::sort_psites_increasing(input)) + void init_() { data::fill(attr, true); } + bool handles_(unsigned p) const { return true; } + bool labels_(unsigned p) const { return attr.element(p); } + bool equiv_(unsigned n, unsigned p) const { return input.element(n) == + input.element(p); } + void do_no_union_(unsigned n, unsigned p) { - initialize(attr, input); + // Avoid a warning about an undefined variable when NDEBUG + // is not defined. + (void)n; + + mln_invariant(input.element(n) < input.element(p)); + attr.element(p) = false; } - }; + void init_attr_(unsigned) {} + void merge_attr_(unsigned r, unsigned p) { attr.element(p) = attr.element(p) && + attr.element(r); } - // Generic implementation. + // end of requirements - namespace generic - { + mln_ch_value(I, bool) attr; - template <typename I, typename N, typename L> - mln_ch_value(I, L) - regional_minima(const I& input, const N& nbh, L& nlabels) + regional_minima_functor(const I& input) + : input(input) { - trace::entering("labeling::impl::generic::regional_minima"); - - // FIXME: abort if L is not wide enough to encode the set of - // minima. - - typedef impl::regional_minima_functor<I,N,L> F; - F f(exact(input), exact(nbh)); - mln_ch_value(I, L) output = canvas::labeling(input, nbh, f, nlabels); - - trace::exiting("labeling::impl::generic::regional_minima"); - return output; + initialize(attr, input); } - - } // end of namespace mln::labeling::impl::generic + }; } // end of namespace mln::labeling::impl @@ -159,8 +150,13 @@ const N& nbh = exact(nbh_); mln_precondition(input.is_valid()); - // Calls the only (generic) impl. - mln_ch_value(I, L) output = impl::generic::regional_minima(input, nbh, nlabels); + // FIXME: abort if L is not wide enough to encode the set of + // minima. + + typedef impl::regional_minima_functor<I> F; + F f(exact(input)); + mln_ch_value(I, L) output = canvas::labeling_sorted(input, nbh, nlabels, + f, true); trace::exiting("labeling::regional_minima"); return output; Index: trunk/milena/mln/labeling/regional_maxima.hh =================================================================== --- trunk/milena/mln/labeling/regional_maxima.hh (revision 3318) +++ trunk/milena/mln/labeling/regional_maxima.hh (revision 3319) @@ -35,7 +35,9 @@ # include <mln/core/concept/image.hh> # include <mln/core/concept/neighborhood.hh> -# include <mln/canvas/labeling.hh> + +# include "labeling.hh" + # include <mln/data/fill.hh> # include <mln/level/sort_psites.hh> @@ -69,21 +71,16 @@ // Generic functor. - template <typename I_, typename N_, typename L_> + template <typename I> struct regional_maxima_functor { - typedef mln_psite(I_) P; + typedef mln_psite(I) P; // requirements from mln::canvas::labeling: - typedef I_ I; - typedef N_ N; - typedef L_ L; - typedef p_array<P> S; - const I& input; - const N& nbh; - S s; + + // Generic implementation void init() { data::fill(attr, true); } bool handles(const P&) const { return true; } @@ -97,50 +94,37 @@ void merge_attr(const P& r, const P& p) { attr(p) = attr(p) && attr(r); } + // Fastest implementation + + void init_() { data::fill(attr, true); } + bool handles_(unsigned p) const { return true; } + bool labels_(unsigned p) const { return attr.element(p); } + bool equiv_(unsigned n, unsigned p) const { return input.element(n) == + input.element(p); } + void do_no_union_(unsigned n, unsigned p) { mln_invariant(input.element(n) > + input.element(p)); + attr.element(p) = false; } + void init_attr_(unsigned) {} + void merge_attr_(unsigned r, unsigned p) { attr.element(p) = attr.element(p) && + attr.element(r); } + // end of requirements mln_ch_value(I, bool) attr; - regional_maxima_functor(const I_& input, const N_& nbh) - : input(input), - nbh(nbh), - s(level::sort_psites_decreasing(input)) + regional_maxima_functor(const I& input) + : input(input) { initialize(attr, input); } }; - // Generic implementation. - - namespace generic - { - - template <typename I, typename N, typename L> - mln_ch_value(I, L) - regional_maxima(const I& input, const N& nbh, - L& nlabels) - { - trace::entering("labeling::impl::generic::regional_maxima"); - - // FIXME: abort if L is not wide enough to encode the set of - // maxima. - - typedef impl::regional_maxima_functor<I,N,L> F; - F f(exact(input), exact(nbh)); - mln_ch_value(I, L) output = canvas::labeling(input, nbh, f, nlabels); - - trace::exiting("labeling::impl::generic::regional_maxima"); - return output; - } - - } // end of namespace mln::labeling::impl::generic - - } // end of namespace mln::labeling::impl + // Facade. template <typename I, typename N, typename L> @@ -154,8 +138,10 @@ const N& nbh = exact(nbh_); mln_precondition(input.is_valid()); - // Calls the only (generic) impl. - mln_ch_value(I, L) output = impl::generic::regional_maxima(input, nbh, nlabels); + typedef impl::regional_maxima_functor<I> F; + F f(exact(input)); + mln_ch_value(I, L) output = canvas::labeling_sorted(input, nbh, nlabels, + f, false); trace::exiting("labeling::regional_maxima"); return output;
participants (1)
-
Fabien Freling