r3285: Implement fastest versions of canvas::labeling

URL: https://svn.lrde.epita.fr/svn/oln/trunk/milena/sandbox ChangeLog: 2009-02-04 Fabien Freling <freling@lrde.epita.fr> Implement fastest versions of canvas::labeling. * fabien/regional_maxima.hh: New. --- labeling.hh | 199 +++++++++++++++++++++++++++++++++++++++++++++++++---- regional_maxima.hh | 171 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 357 insertions(+), 13 deletions(-) Index: trunk/milena/sandbox/fabien/regional_maxima.hh =================================================================== --- trunk/milena/sandbox/fabien/regional_maxima.hh (revision 0) +++ trunk/milena/sandbox/fabien/regional_maxima.hh (revision 3285) @@ -0,0 +1,171 @@ +// 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 +// 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_LABELING_REGIONAL_MAXIMA_HH +# define MLN_LABELING_REGIONAL_MAXIMA_HH + +/// \file mln/labeling/regional_maxima.hh +/// +/// Connected component labeling of the regional maxima of an image. + +# include <mln/core/concept/image.hh> +# include <mln/core/concept/neighborhood.hh> +# include <mln/canvas/labeling.hh> +# include <mln/data/fill.hh> +# include <mln/level/sort_psites.hh> + + +namespace mln +{ + + namespace labeling + { + + /*! Connected component labeling of the regional maxima of an + * image. + * + * \param[in] input The input image. + * \param[in] nbh The connexity of the regional maxima. + * \param[out] nlabels The number of labeled regions. + * \return The label image. + * + */ + template <typename I, typename N, typename L> + mln_ch_value(I, L) + regional_maxima(const Image<I>& input, const Neighborhood<N>& nbh, + L& nlabels); + + + +# ifndef MLN_INCLUDE_ONLY + + namespace impl + { + + // Generic functor. + + template <typename I_, typename N_, typename L_> + struct regional_maxima_functor + { + 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; + + void init() { data::fill(attr, true); } + bool handles(const P&) const { return true; } + bool labels(const P& p) const { return attr(p); } + bool equiv(const P& n, const P& p) const { return input(n) == + input(p); } + void do_no_union(const P& n, const P& p) { mln_invariant(input(n) > + input(p)); + attr(p) = false; } + void init_attr(const P&) {} + void merge_attr(const P& r, const P& p) { attr(p) = attr(p) && + attr(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)) + { + 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> + mln_ch_value(I, L) + regional_maxima(const Image<I>& input_, const Neighborhood<N>& nbh_, + L& nlabels) + { + trace::entering("labeling::regional_maxima"); + + const I& input = exact(input_); + 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); + + trace::exiting("labeling::regional_maxima"); + return output; + } + +# endif // ! MLN_INCLUDE_ONLY + + } // end of namespace mln::labeling + +} // end of namespace mln + + +#endif // ! MLN_LABELING_REGIONAL_MAXIMA_HH Index: trunk/milena/sandbox/fabien/labeling.hh =================================================================== --- trunk/milena/sandbox/fabien/labeling.hh (revision 3284) +++ trunk/milena/sandbox/fabien/labeling.hh (revision 3285) @@ -201,7 +201,7 @@ - // Fastest version + // Fastest video version template <typename I> static inline @@ -214,9 +214,11 @@ return parent.element(x) = find_root(parent, parent.element(x)); } + // FIXME: Use the same functer for the generic and the fastest versions + template <typename I, typename N, typename F, typename L> mln_ch_value(I, L) - labeling_fastest(const Image<I>& input_, const Neighborhood<N>& nbh_, + labeling_fastest_video(const Image<I>& input_, const Neighborhood<N>& nbh_, F& f, L& nlabels) { trace::entering("canvas::impl::labeling"); @@ -269,7 +271,7 @@ if (f.equiv(n, p)) { // Do-Union. - P r = find_root(parent, n); + unsigned r = find_root_fastest(parent, n); if (r != p) { parent.element(r) = p; @@ -278,8 +280,7 @@ } else f.do_no_union(n, p); - } - deja_vu(p) = true; + (p) = true; } } @@ -310,6 +311,121 @@ return output; } + + + // Fastest sorted version + + template <typename I, typename N, typename F, typename L> + mln_ch_value(I, L) + labeling_fastest_sorted(const Image<I>& input_, + const Neighborhood<N>& nbh_, + S& s, F& f, L& nlabels) + { + trace::entering("canvas::impl::labeling"); + + // FIXME: Test?! + + const I& input = exact(input_); + const N& nbh = exact(nbh_); + + typedef typename F::S S; + + // Local type. + typedef mln_psite(I) P; + + // Auxiliary data. + mln_ch_value(I, bool) deja_vu; + mln_ch_value(I, P) parent; + + // Output. + mln_ch_value(I, L) output; + bool status; + + // Initialization. + { + initialize(deja_vu, input); + mln::data::fill(deja_vu, false); + + initialize(parent, input); + + initialize(output, input); + mln::data::fill(output, L(literal::zero)); + nlabels = 0; + + f.init(); // Client initialization. + } + + util::array<int> dp = offsers_wrt(input, nbh); + const unsigned n_nbhs = dp.nelements(); + + const unsigned n_points = s.elements(); + + // 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[n]) + continue; + + if (f.equiv(n, p)) + { + // Do-Union. + unsigned r = find_root_fastest(parent, n); + if (input.element(r) != input.element(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(parent.element(p)); + } + status = true; + } + + trace::exiting("canvas::impl::labeling"); + return output; + } + } // end of namespace mln::canvas::impl @@ -319,10 +435,50 @@ namespace internal { + // Video + + template <typename I, typename N, typename F, typename L> + inline + mln_ch_value(I, L) + labeling_video(metal::false_, const Image<I>& input, + const Neighborhood<N>& nbh, F& functor, L& nlabels) + { + // FIXME:s = input.domain() + return impl::generic::labeling(input, nbh, functor, nlabels); + } + + template <typename I, typename N, typename F, typename L> + inline + mln_ch_value(I, L) + labeling_video(metal::true_, const Image<I>& input, + const Neighborhood<N>& nbh, F& functor, L& nlabels) + { + return impl::labeling_fastest_video(input, nbh, functor, nlabels); + } + template <typename I, typename N, typename F, typename L> inline mln_ch_value(I, L) - labeling(metal::false_, const Image<I>& input, + labeling_video_dispatch(const Image<I>& input, const Neighborhood<N>& nbh, + F& functor, L& nlabels) + { + enum { + test = mlc_equal(mln_trait_image_speed(I), + trait::image::speed::fastest)::value + && + mln_is_simple_neighborhood(N)::value + }; + return impl::generic::labeling_video(metal::bool_<test>(), input, nbh, + functor, nlabels); + } + + + // Sorted + + template <typename I, typename N, typename F, typename L> + inline + mln_ch_value(I, L) + labeling_sorted(metal::false_, const Image<I>& input, const Neighborhood<N>& nbh, F& functor, L& nlabels) { return impl::generic::labeling(input, nbh, functor, nlabels); @@ -331,16 +487,16 @@ template <typename I, typename N, typename F, typename L> inline mln_ch_value(I, L) - labeling(metal::true_, const Image<I>& input, + labeling_sorted(metal::true_, const Image<I>& input, const Neighborhood<N>& nbh, F& functor, L& nlabels) { - return impl::labeling_fastest(input, nbh, functor, nlabels); + return impl::labeling_fastest_sorted(input, nbh, functor, nlabels); } template <typename I, typename N, typename F, typename L> inline mln_ch_value(I, L) - labeling_dispatch(const Image<I>& input, const Neighborhood<N>& nbh, + labeling_sorted_dispatch(const Image<I>& input, const Neighborhood<N>& nbh, F& functor, L& nlabels) { enum { @@ -349,10 +505,11 @@ && mln_is_simple_neighborhood(N)::value }; - return impl::generic::labeling(metal::bool_<test>(), input, nbh, + return impl::generic::labeling_video(metal::bool_<test>(), input, nbh, functor, nlabels); } + } // end of namespace mln::canvas::internal @@ -362,20 +519,36 @@ template <typename I, typename N, typename F, typename L> inline mln_ch_value(I, L) - labeling(const Image<I>& input, const Neighborhood<N>& nbh, + labeling_video(const Image<I>& input, const Neighborhood<N>& nbh, F& functor, L& nlabels) { - trace::entering("canvas::labeling"); + trace::entering("canvas::labeling_video"); internal::labeling_tests(input, nbh, functor, nlabels); mln_ch_value(I, L) output; output = internal::labeling_dispatch(input, nbh, functor, nlabels); - trace::exiting("canvas::labeling"); + trace::exiting("canvas::labeling_video"); return output; } + template <typename I, typename N, typename F, typename L> + inline + mln_ch_value(I, L) + labeling_sorted(const Image<I>& input, const Neighborhood<N>& nbh, + F& functor, L& nlabels) + { + trace::entering("canvas::labeling_sorted"); + + internal::labeling_tests(input, nbh, functor, nlabels); + + mln_ch_value(I, L) output; + output = internal::labeling_dispatch(input, nbh, functor, nlabels); + + trace::exiting("canvas::labeling_sorted"); + return output; + } # endif // ! MLN_INCLUDE_ONLY
participants (1)
-
Fabien Freling