https://svn.lrde.epita.fr/svn/oln/trunk/milena
Index: ChangeLog
from Thierry Geraud <thierry.geraud(a)lrde.epita.fr>
Make the fastest version for the algebraic morpho canvas work.
* mln/level/sort_offsets.hh: New.
* mln/level/all.hh: Update.
* mln/morpho/closing_attribute.hh
(closing_attribute_fastest_functor_t): Update.
* mln/canvas/morpho/algebraic_union_find.hh
(algebraic_union_find_fastest): Update.
canvas/morpho/algebraic_union_find.hh | 71 +++----
level/all.hh | 1
level/sort_offsets.hh | 337 ++++++++++++++++++++++++++++++++++
morpho/closing_attribute.hh | 5
4 files changed, 377 insertions(+), 37 deletions(-)
Index: mln/level/all.hh
--- mln/level/all.hh (revision 3229)
+++ mln/level/all.hh (working copy)
@@ -66,6 +66,7 @@
# include <mln/level/replace.hh>
# include <mln/level/saturate.hh>
# include <mln/level/sort_psites.hh>
+# include <mln/level/sort_offsets.hh>
# include <mln/level/stretch.hh>
# include <mln/level/to_enc.hh>
# include <mln/level/transform.hh>
Index: mln/level/sort_offsets.hh
--- mln/level/sort_offsets.hh (revision 0)
+++ mln/level/sort_offsets.hh (revision 0)
@@ -0,0 +1,337 @@
+// 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_LEVEL_SORT_OFFSETS_HH
+# define MLN_LEVEL_SORT_OFFSETS_HH
+
+/// \file mln/level/sort_offsets.hh
+/// \brief Sort_Offsets the contents of an image into another one.
+///
+/// \todo Factor code + optimize.
+
+# include <algorithm>
+
+# include <mln/core/concept/image.hh>
+# include <mln/histo/compute.hh>
+# include <mln/util/array.hh>
+# include <mln/util/ord.hh>
+# include <mln/geom/nsites.hh>
+
+
+namespace mln
+{
+
+ namespace level
+ {
+
+ /// Sort pixel offsets of the image \p input wrt increasing pixel
+ /// values.
+ ///
+ template <typename I>
+ util::array<unsigned>
+ sort_offsets_increasing(const Image<I>& input);
+
+
+ // /// Sort pixel offsets of the image \p input wrt decreasing pixel
+ // /// values.
+ // ///
+ // template <typename I>
+ // util::array<unsigned>
+ // sort_offsets_decreasing(const Image<I>& input);
+
+
+
+# ifndef MLN_INCLUDE_ONLY
+
+ namespace impl
+ {
+
+ namespace generic
+ {
+
+ // increasing
+
+ template <typename I>
+ struct value_offset_less_
+ {
+ const I& ima_;
+ inline value_offset_less_(const I& ima) : ima_(ima) {}
+ inline bool operator()(unsigned lhs, unsigned rhs) const
+ {
+ return util::ord_strict(ima_.element(lhs), ima_.element(rhs))
+ || (ima_.element(lhs) == ima_.element(rhs)
+ &&
+ lhs < rhs);
+ }
+ };
+
+ template <typename I>
+ inline
+ util::array<unsigned>
+ sort_offsets_increasing(const Image<I>& input_)
+ {
+ trace::entering("level::impl::generic::sort_offsets_increasing");
+
+ const I& input = exact(input_);
+
+ util::array<unsigned> v;
+ v.reserve(input.nelements());
+ mln_fwd_pixter(const I) pxl(input);
+ for_all(pxl)
+ v.append(pxl.offset());
+ std::sort(v.hook_std_vector_().begin(), v.hook_std_vector_().end(),
+ value_offset_less_<I>(input));
+
+ trace::exiting("level::impl::generic::sort_offsets_increasing");
+ return v;
+ }
+
+
+ // decreasing
+
+ template <typename I>
+ struct value_offset_greater_
+ {
+ const I& ima_;
+ inline value_offset_greater_(const I& ima) : ima_(ima) {}
+ inline bool operator()(unsigned lhs, unsigned rhs) const
+ {
+ return util::ord_strict(ima_.element(rhs), ima_.element(lhs))
+ || (ima_.element(lhs) == ima_.element(rhs)
+ &&
+ lhs > rhs);
+ }
+ };
+
+ template <typename I>
+ inline
+ util::array<unsigned>
+ sort_offsets_decreasing(const Image<I>& input_)
+ {
+ trace::entering("level::impl::generic::sort_offsets_decreasing");
+
+ const I& input = exact(input_);
+
+ util::array<unsigned> v;
+ v.reserve(input.nelements());
+ mln_fwd_pixter(const I) pxl(input);
+ for_all(pxl)
+ v.append(pxl.offset());
+ std::sort(v.hook_std_vector_().begin(), v.hook_std_vector_().end(),
+ value_offset_greater_<I>(input));
+
+ trace::exiting("level::impl::generic::sort_offsets_decreasing");
+ return v;
+ }
+
+
+ } // end of namespace mln::level::impl::generic
+
+
+
+ // increasing
+
+ template <typename I>
+ inline
+ util::array<unsigned>
+ sort_offsets_increasing_radix(const Image<I>& input_)
+ {
+ trace::entering("level::impl::sort_offsets_increasing_radix");
+
+ const I& input = exact(input_);
+
+ typedef mln_vset(I) S;
+ const S& vset = input.values_eligible();
+ const unsigned n = vset.nvalues();
+
+ // h
+ histo::array<mln_value(I)> h = histo::compute(input);
+
+ // preparing output data
+ std::vector<unsigned> loc(vset.nvalues());
+ loc[0] = 0;
+ for (unsigned i = 1; i != n; ++i)
+ loc[i] = loc[i-1] + h[i-1];
+
+ // computing output data
+ util::array<unsigned> vec(geom::nsites(input));
+ mln_fwd_pixter(const I) pxl(input);
+ for_all(pxl)
+ vec[loc[vset.index_of(pxl.val())]++] = pxl.offset();
+
+ trace::exiting("level::impl::sort_offsets_increasing_radix");
+ return vec;
+ }
+
+
+ // decreasing
+
+ template <typename I>
+ inline
+ util::array<unsigned>
+ sort_offsets_decreasing_radix(const Image<I>& input_)
+ {
+ trace::entering("level::impl::sort_offsets_decreasing_radix");
+
+ const I& input = exact(input_);
+
+ typedef mln_vset(I) S;
+ const S& vset = input.values_eligible();
+ const unsigned n = vset.nvalues();
+
+ // h
+ histo::array<mln_value(I)> h = histo::compute(input);
+
+ // preparing output data
+ std::vector<unsigned> loc(vset.nvalues());
+ loc[n-1] = 0;
+ for (int i = n - 2; i >= 0; --i)
+ loc[i] = loc[i+1] + h[i+1];
+
+ // computing output data
+ util::array<unsigned> vec(geom::nsites(input));
+ mln_fwd_pixter(const I) pxl(input);
+ for_all(pxl)
+ vec[loc[vset.index_of(pxl.val())]++] = pxl.offset();
+
+ trace::exiting("level::impl::sort_offsets_decreasing_radix");
+ return vec;
+ }
+
+
+ } // end of namespace mln::level::impl
+
+
+
+ namespace internal
+ {
+
+ // increasing
+
+ template <typename I>
+ inline
+ util::array<unsigned>
+ sort_offsets_increasing_dispatch(trait::image::quant::any,
+ const Image<I>& input)
+ {
+ return impl::generic::sort_offsets_increasing(input);
+ }
+
+ template <typename I>
+ inline
+ util::array<unsigned>
+ sort_offsets_increasing_dispatch(trait::image::quant::low,
+ const Image<I>& input)
+ {
+ return impl::sort_offsets_increasing_radix(input);
+ }
+
+ template <typename I>
+ inline
+ util::array<unsigned>
+ sort_offsets_increasing_dispatch(const Image<I>& input)
+ {
+ return sort_offsets_increasing_dispatch(mln_trait_image_quant(I)(),
+ input);
+ }
+
+ // decreasing
+
+ template <typename I>
+ inline
+ util::array<unsigned>
+ sort_offsets_decreasing_dispatch(trait::image::quant::any,
+ const Image<I>& input)
+ {
+ return impl::generic::sort_offsets_decreasing(input);
+ }
+
+ template <typename I>
+ inline
+ util::array<unsigned>
+ sort_offsets_decreasing_dispatch(trait::image::quant::low,
+ const Image<I>& input)
+ {
+ return impl::sort_offsets_decreasing_radix(input);
+ }
+
+ template <typename I>
+ inline
+ util::array<unsigned>
+ sort_offsets_decreasing_dispatch(const Image<I>& input)
+ {
+ return sort_offsets_decreasing_dispatch(mln_trait_image_quant(I)(),
+ input);
+ }
+
+ } // end of namespace mln::level::internal
+
+
+
+ // Facades.
+
+ template <typename I>
+ inline
+ util::array<unsigned>
+ sort_offsets_increasing(const Image<I>& input)
+ {
+ trace::entering("level::sort_offsets_increasing");
+ mlc_is(mln_trait_image_speed(I),
+ trait::image::speed::fastest)::check();
+
+ mln_precondition(exact(input).is_valid());
+ util::array<unsigned> output =
internal::sort_offsets_increasing_dispatch(input);
+
+ trace::exiting("level::sort_offsets_increasing");
+ return output;
+ }
+
+ template <typename I>
+ inline
+ util::array<unsigned>
+ sort_offsets_decreasing(const Image<I>& input)
+ {
+ trace::entering("level::sort_offsets_decreasing");
+ mlc_is(mln_trait_image_speed(I),
+ trait::image::speed::fastest)::check();
+
+ mln_precondition(exact(input).is_valid());
+ util::array<unsigned> output =
internal::sort_offsets_decreasing_dispatch(input);
+
+ trace::exiting("level::sort_offsets_decreasing");
+ return output;
+ }
+
+# endif // ! MLN_INCLUDE_ONLY
+
+ } // end of namespace mln::level
+
+} // end of namespace mln
+
+
+#endif // ! MLN_LEVEL_SORT_OFFSETS_HH
Index: mln/morpho/closing_attribute.hh
--- mln/morpho/closing_attribute.hh (revision 3229)
+++ mln/morpho/closing_attribute.hh (working copy)
@@ -40,6 +40,7 @@
# include <mln/morpho/includes.hh>
# include <mln/canvas/morpho/algebraic_union_find.hh>
# include <mln/level/sort_psites.hh>
+# include <mln/level/sort_offsets.hh>
# include <mln/util/pix.hh>
@@ -144,7 +145,7 @@
typedef A_ A;
typedef mln_psite(I) P;
- typedef p_array<P> S;
+ typedef util::array<unsigned> S;
mln_result(A) lambda;
const S s;
@@ -168,7 +169,7 @@
closing_attribute_fastest_functor_t(const Image<I>& input, mln_result(A)
lambda)
: lambda(lambda),
- s(level::sort_psites_increasing(exact(input)))
+ s(level::sort_offsets_increasing(exact(input)))
{
}
Index: mln/canvas/morpho/algebraic_union_find.hh
--- mln/canvas/morpho/algebraic_union_find.hh (revision 3229)
+++ mln/canvas/morpho/algebraic_union_find.hh (working copy)
@@ -214,7 +214,7 @@
if (parent.element(x) == x)
return x;
else
- return parent.element(x) = find_root(parent, parent.element(x));
+ return parent.element(x) = find_root_fastest(parent, parent.element(x));
}
@@ -260,63 +260,64 @@
}
util::array<int> dp = offsets_wrt(input, nbh);
- for (unsigned i = 0; i < dp.nelements(); ++i)
- std::cout << dp[i] << ' ';
- std::cout << std::endl;
+ const unsigned n_nbhs = dp.nelements();
- /*
+ const util::array<unsigned>& s = f.s;
+ const unsigned n_points = s.nelements();
// First pass.
{
- for (unsigned p = 0; p < f.s.size(); ++p)
- mln_niter(N) n(nbh, p);
- for_all(p)
+
+ for (unsigned i = 0; i < n_points; ++i)
{
+ unsigned p = s[i]; // An offset.
+
// Make set.
- {
- parent(p) = p;
- data(p).take_as_init(make::pix(input, p)); // FIXME: algebraic so p!
- }
+ parent.element(p) = p;
+ data.element(p).take_as_init( input.element(p) ); // FIXME: Very bad!!!
- for_all(n)
- if (input.domain().has(n) && deja_vu(n))
+ for (unsigned j = 0; j < n_nbhs; ++j)
{
- P r = find_root(parent, n);
+ unsigned n = p + dp[j];
+ if (! deja_vu.element(n))
+ continue;
+
+ unsigned r = find_root_fastest(parent, n);
if (r != p)
{
- if (input(r) == input(p) || (activity(r) && f.is_active(data(r))))
- {
- data(p).take(data(r));
- parent(r) = p;
- if (activity(r) == false)
- activity(p) = false;
+ if (input.element(r) == input.element(p)
+ || (activity.element(r)
+ && f.is_active(data.element(r))))
+ {
+ data.element(p).take(data.element(r));
+ parent.element(r) = p;
+ if (activity.element(r) == false)
+ activity.element(p) = false;
}
else
{
- activity(p) = false;
- f.inactivate(data(p));
- }
+ activity.element(p) = false;
+ f.inactivate(data.element(p));
}
}
- deja_vu(p) = true;
- }
}
- */
+ deja_vu.element(p) = true;
+ }
- /*
+ }
// Second pass.
{
- mln_bkd_piter(S) p(f.s);
- for_all(p)
- if (parent(p) == p) // p is root.
- output(p) = input(p);
+ for (int i = n_points - 1; i >= 0 ; --i)
+ {
+ unsigned p = s[i];
+ if (parent.element(p) == p) // p is root.
+ output.element(p) = input.element(p);
else
- output(p) = output(parent(p));
+ output.element(p) = output.element(parent.element(p));
+ }
}
-
- */
trace::exiting("canvas::morpho::impl::algebraic_union_find_fastest");
return output;