* mln/core/image/all.hh: Update.
* mln/morpho/tree/all.hh: Update.
* mln/tag/skeleton.hh: Update.
* mln/morpho/tree/component_tree.hh:
Routines to build component trees.
* mln/morpho/tree/compute_attribute_image.hh:
Routines to compute attribute images.
* mln/morpho/tree/dual_input_tree.hh:
Routines to build dual-input trees.
* mln/morpho/tree/filter/direct.hh,
* mln/morpho/tree/filter/max.hh,
* mln/morpho/tree/filter/min.hh,
* mln/morpho/tree/filter/subtractive.hh:
Filtering routines.
* mln/morpho/tree/impl/hqueue.hh,
* mln/morpho/tree/impl/hqueue_fast.hh,
* mln/morpho/tree/impl/union_find.hh,
* mln/morpho/tree/impl/union_find_fast.hh:
Tree computation algorithms.
* mln/morpho/tree/leaf_last.hh,
* mln/morpho/tree/propagate_node.hh:
Tree management routines.
---
milena/mln/core/image/all.hh | 1 +
milena/mln/morpho/tree/all.hh | 16 +-
milena/mln/morpho/tree/component_tree.hh | 86 +++-
milena/mln/morpho/tree/compute_attribute_image.hh | 281 ++++------
milena/mln/morpho/tree/dual_input_tree.hh | 79 +---
milena/mln/morpho/tree/filter/direct.hh | 35 +-
milena/mln/morpho/tree/filter/max.hh | 62 ++-
milena/mln/morpho/tree/filter/min.hh | 59 ++-
milena/mln/morpho/tree/filter/subtractive.hh | 52 ++-
milena/mln/morpho/tree/impl/dual_hqueue.hh | 604 ++++++++++++--------
milena/mln/morpho/tree/impl/hqueue.hh | 428 ++++++++++++++
milena/mln/morpho/tree/impl/hqueue_fast.hh | 391 +++++++++++++
.../edwin => }/mln/morpho/tree/impl/union_find.hh | 2 +
milena/mln/morpho/tree/impl/union_find_fast.hh | 396 +++++++++++++
milena/mln/morpho/tree/leaf_last.hh | 111 ++++
milena/mln/morpho/tree/propagate_node.hh | 189 ++-----
milena/mln/tag/skeleton.hh | 1 +
milena/mln/util/hqueues.hh | 32 +-
18 files changed, 2050 insertions(+), 775 deletions(-)
create mode 100644 milena/mln/morpho/tree/impl/hqueue.hh
create mode 100644 milena/mln/morpho/tree/impl/hqueue_fast.hh
copy milena/{sandbox/edwin => }/mln/morpho/tree/impl/union_find.hh (99%)
create mode 100644 milena/mln/morpho/tree/impl/union_find_fast.hh
create mode 100644 milena/mln/morpho/tree/leaf_last.hh
diff --git a/milena/mln/core/image/all.hh b/milena/mln/core/image/all.hh
index ee6a15e..1cd2773 100644
--- a/milena/mln/core/image/all.hh
+++ b/milena/mln/core/image/all.hh
@@ -40,6 +40,7 @@
// Files.
+# include <mln/core/image/attribute_image.hh>
# include <mln/core/image/ch_piter.hh>
# include <mln/core/image/complex_image.hh>
# include <mln/core/image/complex_neighborhood_piter.hh>
diff --git a/milena/mln/morpho/tree/all.hh b/milena/mln/morpho/tree/all.hh
index d088ea0..c6d93ee 100644
--- a/milena/mln/morpho/tree/all.hh
+++ b/milena/mln/morpho/tree/all.hh
@@ -30,7 +30,6 @@
///
/// File that includes all morphological tree-related routines.
-
namespace mln
{
@@ -46,11 +45,14 @@ namespace mln
} // end of namespace mln
-# include <mln/morpho/tree/compute_attribute_image.hh>
-# include <mln/morpho/tree/compute_parent.hh>
# include <mln/morpho/tree/dual_input_tree.hh>
-# include <mln/morpho/tree/data.hh>
-# include <mln/morpho/tree/max.hh>
-# include <mln/morpho/tree/utils.hh>
+# include <mln/morpho/tree/component_tree.hh>
+# include <mln/morpho/tree/compute_parent.hh
+# include <mln/morpho/tree/compute_attribute_image.hh>
+# include <mln/morpho/tree/leaf_last.hh>
+# include <mln/morpho/tree/propagate_node.hh>
+
+# include <mln/morpho/tree/filter/all.hh>
+
-#endif // ! MLN_MORPHO_TREE_ALL_HH
+#endif // !MLN_MORPHO_TREE_ALL_HH
diff --git a/milena/mln/morpho/tree/component_tree.hh
b/milena/mln/morpho/tree/component_tree.hh
index f45986d..dc9063d 100644
--- a/milena/mln/morpho/tree/component_tree.hh
+++ b/milena/mln/morpho/tree/component_tree.hh
@@ -32,8 +32,10 @@
#ifndef MLN_MORPHO_TREE_COMPONENT_TREE_HH
# define MLN_MORPHO_TREE_COMPONENT_TREE_HH
-# include <mln/data/sort_psites.hh>
-# include <mln/morpho/tree/data.hh>
+# include <mln/tag/tree.hh>
+# include <mln/util/ctree/ctree.hh>
+# include <mln/morpho/tree/impl/union_find_fast.hh>
+# include <mln/morpho/tree/impl/hqueue_fast.hh>
namespace mln
{
@@ -53,7 +55,7 @@ namespace mln
///
template <typename I, typename N>
inline
- data< I, p_array<mln_psite(I)> >
+ util::ctree::ctree<I>
min_tree(const Image<I>& f, const Neighborhood<N>& nbh);
/// Compute a canonized max-tree.
@@ -65,15 +67,73 @@ namespace mln
///
template <typename I, typename N>
inline
- data< I, p_array<mln_psite(I)> >
+ util::ctree::ctree<I>
max_tree(const Image<I>& f, const Neighborhood<N>& nbh);
# ifndef MLN_INCLUDE_ONLY
+ namespace internal
+ {
+
+ template <typename I, typename N>
+ inline
+ util::ctree::ctree<I>
+ max_tree_dispatch(trait::image::quant::any,
+ const I& f,
+ const N& nbh)
+ {
+ util::ctree::ctree<I> tree =
+ morpho::tree::impl::generic::union_find_fast(tag::tree::max, f, nbh);
+
+ return tree;
+ }
+
+ template <typename I, typename N>
+ inline
+ util::ctree::ctree<I>
+ min_tree_dispatch(trait::image::quant::any,
+ const I& f,
+ const N& nbh)
+ {
+ util::ctree::ctree<I> tree =
+ morpho::tree::impl::generic::union_find_fast(tag::tree::min, f, nbh);
+
+ return tree;
+ }
+
+
+ template <typename I, typename N>
+ inline
+ util::ctree::ctree<I>
+ max_tree_dispatch(trait::image::quant::low,
+ const I& f,
+ const N& nbh)
+ {
+ util::ctree::ctree<I> tree =
+ morpho::tree::impl::hqueue_fast(tag::tree::max, f, nbh);
+
+ return tree;
+ }
+
+ template <typename I, typename N>
+ inline
+ util::ctree::ctree<I>
+ min_tree_dispatch(trait::image::quant::low,
+ const I& f,
+ const N& nbh)
+ {
+ util::ctree::ctree<I> tree =
+ morpho::tree::impl::hqueue_fast(tag::tree::min, f, nbh);
+
+ return tree;
+ }
+
+ }
+
template <typename I, typename N>
inline
- data< I, p_array<mln_psite(I)> >
+ util::ctree::ctree<I>
min_tree(const Image<I>& f_, const Neighborhood<N>& nbh_)
{
trace::entering("morpho::tree::min_tree");
@@ -84,11 +144,8 @@ namespace mln
mln_precondition(f.is_valid());
mln_precondition(nbh.is_valid());
- typedef p_array<mln_psite(I)> S;
- typedef data<I,S> tree_t;
-
- S s = mln::data::sort_psites_decreasing(f);
- tree_t tree(f, s, nbh);
+ util::ctree::ctree<I> tree =
+ internal::min_tree_dispatch(mln_trait_image_quant(I)(), f, nbh);
trace::exiting("morpho::tree::min_tree");
return tree;
@@ -96,7 +153,7 @@ namespace mln
template <typename I, typename N>
inline
- data< I, p_array<mln_psite(I)> >
+ util::ctree::ctree<I>
max_tree(const Image<I>& f_, const Neighborhood<N>& nbh_)
{
trace::entering("morpho::tree::max_tree");
@@ -107,11 +164,8 @@ namespace mln
mln_precondition(f.is_valid());
mln_precondition(nbh.is_valid());
- typedef p_array<mln_psite(I)> S;
- typedef data<I,S> tree_t;
-
- S s = mln::data::sort_psites_increasing(f);
- tree_t tree(f, s, nbh);
+ util::ctree::ctree<I> tree =
+ internal::max_tree_dispatch(mln_trait_image_quant(I)(), f, nbh);
trace::exiting("morpho::tree::max_tree");
return tree;
diff --git a/milena/mln/morpho/tree/compute_attribute_image.hh
b/milena/mln/morpho/tree/compute_attribute_image.hh
index 9126bf1..6e5e891 100644
--- a/milena/mln/morpho/tree/compute_attribute_image.hh
+++ b/milena/mln/morpho/tree/compute_attribute_image.hh
@@ -23,22 +23,20 @@
// exception does not however invalidate any other reasons why the
// executable file might be covered by the GNU General Public License.
-#ifndef MLN_MORPHO_TREE_COMPUTE_ATTRIBUTE_IMAGE_HH
-# define MLN_MORPHO_TREE_COMPUTE_ATTRIBUTE_IMAGE_HH
-
-/// \file
+#ifndef COMPUTE_ATTRIBUTE_IMAGE_HH
+# define COMPUTE_ATTRIBUTE_IMAGE_HH
+///
+///
+/// \brief Compute an attribute on a morphological tree.
///
-/// Compute a canonized tree from an image.
+/// \todo Specialize for fast image.
///
-/// \todo Specialize for low quant (and try fastest).
-# include <mln/core/routine/duplicate.hh>
-# include <mln/core/concept/image.hh>
-# include <mln/morpho/tree/data.hh>
-# include <mln/trait/accumulators.hh>
-# include <mln/util/pix.hh>
-# include <mln/data/fill.hh>
+# include <mln/core/concept/tree.hh>
+# include <mln/core/concept/accumulator.hh>
+# include <mln/core/image/attribute_image.hh>
+# include <mln/data/fill.hh>
namespace mln
{
@@ -49,213 +47,132 @@ namespace mln
namespace tree
{
- /**
- ** Compute an attribute image using tree with a parent
- ** relationship between sites. In the attribute image, the
- ** resulting value at a node is the 'sum' of its sub-components
- ** value + the attribute value at this node.
- **
- ** Warning: \p s translates the ordering related to the
- ** "natural" childhood relationship. The parenthood is thus
- ** inverted w.r.t. to \p s.
- **
- ** It is very convenient since all processing upon the parent
- ** tree are performed following \p s (in the default "forward"
- ** way).
- **
- ** FIXME: Put it more clearly...
- **
- ** The parent result image verifies: \n
- ** - p is root iff parent(p) == p \n
- ** - p is a node iff either p is root or f(parent(p)) != f(p).
- **
- ** \param[in] a Attribute.
- ** \param[in] t Component tree.
- ** \param[out] accu_image Optional argument used to store image
- ** of attribute accumulator.
- **
- ** \return The attribute image.
- */
- template <typename A, typename T>
- mln_ch_value(typename T::function, mln_result(A))
- compute_attribute_image(const Accumulator<A>& a,
- const T& t,
- mln_ch_value(typename T::function, A)* accu_image = 0);
-
-
-
- /** The same as compute_attribute_image but uses the values
- ** stored by \p values image instead.
- **
- ** \param[in] a Attribute.
- ** \param[in] t Component tree.
- ** \param[in] values Value image.
- ** \param[out] accu_image Optional argument used to store image.
- **
- ** \return
- */
- template <typename A, typename T, typename V>
- mln_ch_value(typename T::function, mln_result(A))
- compute_attribute_image_from(const Accumulator<A>& a,
- const T& t,
- const Image<V>& values,
- mln_ch_value(typename T::function, A)* accu_image = 0);
-
+ template <typename T, typename A>
+ attribute_image<T, mln_result(A)>
+ compute_attribute_image(const Tree<T>& tree,
+ const Accumulator<A>& accu);
# ifndef MLN_INCLUDE_ONLY
- // Take_as_init specialization
namespace internal
{
- template <typename A, typename I, typename P>
- void take_as_init (trait::accumulator::when_pix::use_none, A& accu,
- const I& input, const P& p)
- {
- (void)input;
- (void)p;
- accu.take_as_init();
- }
- template <typename A, typename I, typename P>
- void take_as_init (trait::accumulator::when_pix::use_pix, A& accu,
- const I& input, const P& p)
+ template <typename T, typename A>
+ inline
+ void
+ take_as_init(trait::accumulator::when_pix::use_none,
+ const T&, A& accu,
+ const mln_psite(T)&)
{
- accu.take_as_init(make::pix(input, p));
+ accu.take();
}
- template <typename A, typename I, typename P>
- void take_as_init (trait::accumulator::when_pix::use_v, A& accu,
- const I& input, const P& p)
+ template <typename T, typename A>
+ inline
+ void
+ take_as_init(trait::accumulator::when_pix::use_pix,
+ const T& tree, A& accu,
+ const mln_psite(T)& p)
{
- accu.take_as_init(input(p));
+ accu.take(make::pix(p, tree.f(p)));
}
- template <typename A, typename I, typename P>
- void take_as_init (trait::accumulator::when_pix::use_p, A& accu,
- const I& input, const P& p)
+
+ template <typename T, typename A>
+ inline
+ void
+ take_as_init(trait::accumulator::when_pix::use_v,
+ const T& tree, A& accu,
+ const mln_psite(T)& p)
{
- (void) input;
- accu.take_as_init(p);
+ accu.take(tree.f(p));
}
-
- template <typename A, typename I, typename P>
- void take_as_init (A& accu, const I& input, const P& p)
+ template <typename T, typename A>
+ inline
+ void
+ take_as_init(trait::accumulator::when_pix::use_p,
+ const T&, A& accu,
+ const mln_psite(T)& p)
{
- take_as_init (mln_trait_accumulator_when_pix(A)(), accu, input, p);
+ accu.take(p);
}
-
- template <typename A, typename T, typename V>
- inline
- mln_ch_value(typename T::function, mln_result(A))
- compute_attribute_image(const A& a,
- const T& t,
- const V& values,
- mln_ch_value(typename T::function, A)* accu_image = 0)
+ template <typename T, typename A>
+ void
+ take_as_init(const T& tree, A& a, const mln_psite(T)& p)
{
+ take_as_init(mln_trait_accumulator_when_pix(A)(), tree, a, p);
+ }
- typedef typename T::function I;
- mln_ch_value(I, A) acc;
- initialize(acc, t.f());
+ } // end of namespace namespace mln::morpho::tree::internal
- {
- // Transmit "dynamic data" (state) of 'a' to every values of
- // 'acc'. It is usually a no-op (so useless) except for a
- // few accumulators, e.g., for accu::stat::rank which has the 'k'
- // attribute.
- mln::data::fill(acc, a);
- }
+ namespace impl
+ {
- {
- // Initialize every attribute with the corresponding pixel.
- mln_site_piter(T) p(t);
- for_all(p)
- take_as_init(acc(p), values, p);
- }
+ namespace generic
+ {
+ template <typename T, typename A>
+ attribute_image<T, mln_result(A)>
+ compute_attribute_image(const T& tree, const A& accu, attribute_image<T,
A>* accu_img = 0)
{
- mln_up_site_piter(T) p(t);
- // Propagate attribute from a site to its parent.
- for_all(p)
- if (! t.is_root(p))
- acc(t.parent(p)).take(acc(p));
-
- // Back-propagate attribute from a node to sites of its
- // component. Below, p is a non-node component site and
- // parent(p) is a node, that is, the site representative of
- // the component p belongs to.
- for_all(p)
- if (! t.is_a_node(p))
- {
- mln_assertion(t.is_a_node(t.parent(p)));
- acc(p) = acc(t.parent(p));
- }
+ typedef attribute_image<T, A> I;
+ attribute_image<T, A> a(tree);
+ (void) accu_img;
+
+ // Transmit dynamic data of accumulator (ex: rank filter).
+ data::fill(a, accu);
+
+ // Initialize. Each node takes its content.
+ {
+ mln_fwd_piter(T::domain_t) p(tree.domain());
+ for_all(p)
+ internal::take_as_init(tree, a.element(tree.node_at_(p)), p);
+ }
+
+ // Transmit to parent.
+ for (unsigned i = tree.n_nodes() - 1; i > 0; --i)
+ {
+ unsigned q = tree.parent_at_(i);
+ if (q != i) // The current node is not a root.
+ a.element(q).take(a.element(i));
+ }
+
+ attribute_image<T, mln_result(A)> out(tree);
+ for (int i = 0; i < tree.n_nodes(); i++)
+ out.element(i) = a.element(i).to_result();
+
+ return out;
}
+ } // end of namespace mln::morpho::tree::impl::generic
- // Store accumulator image.
- if (accu_image)
- *accu_image = duplicate(acc);
-
- typedef typename T::function I;
- mln_ch_value(I, mln_result(A)) output;
- initialize(output, acc);
- mln::data::fill(output, acc);
-
- return output;
- }
- }
-
- // Facade.
-
- template <typename A, typename T>
- inline
- mln_ch_value(typename T::function, mln_result(A))
- compute_attribute_image(const Accumulator<A>& a_,
- const T& t,
- mln_ch_value(typename T::function, A)* accu_image = 0)
- {
- trace::entering("morpho::tree::compute_attribute_image");
+ } // end of namespace mln::morpho::tree::impl
- mln_ch_value(typename T::function, mln_result(A)) output;
- output = internal::compute_attribute_image(exact(a_), t, t.f(),
- accu_image);
- trace::exiting("morpho::tree::compute_attribute_image");
- return (output);
- }
-
- template <typename A, typename T, typename V>
- inline
- mln_ch_value(typename T::function, mln_result(A))
- compute_attribute_image_from(const Accumulator<A>& a_,
- const T& t,
- const Image<V>& values,
- mln_ch_value(typename T::function, A)* accu_image = 0)
+ // Facades
+ template <typename T, typename A>
+ attribute_image<T, mln_result(A)>
+ compute_attribute_image(const Tree<T>& tree_, const
Accumulator<A>& acc)
{
- trace::entering("morpho::tree::compute_attribute_image_from");
-
+ trace::entering("mln::morpho::tree::compute_attribute_image");
+ const T& tree = exact(tree_);
+ const A& accu = exact(acc);
- mln_ch_value(typename T::function, mln_result(A)) output;
- output = internal::compute_attribute_image(exact(a_), t, exact(values),
- accu_image);
+ mln_precondition(tree.is_valid());
- trace::exiting("morpho::tree::compute_attribute_image_from");
- return output;
+ return impl::generic::compute_attribute_image(tree, accu);
+ trace::exiting("mln::morpho::tree::compute_attribute_image");
}
-
-
-
# endif // ! MLN_INCLUDE_ONLY
- } // end of namespace mln::morpho::tree
-
- } // end of namespace mln::morpho
+ } // end of namespace mln::morpho::tree
-} // end of namespace mln
+ } // end of namespace mln::morpho
+} // end of namespace mln
-#endif // ! MLN_MORPHO_TREE_COMPUTE_ATTRIBUTE_IMAGE_HH
+#endif // !COMPUTE_ATTRIBUTE_IMAGE_HH
diff --git a/milena/mln/morpho/tree/dual_input_tree.hh
b/milena/mln/morpho/tree/dual_input_tree.hh
index 08e6553..b4d4839 100644
--- a/milena/mln/morpho/tree/dual_input_tree.hh
+++ b/milena/mln/morpho/tree/dual_input_tree.hh
@@ -23,17 +23,12 @@
// exception does not however invalidate any other reasons why the
// executable file might be covered by the GNU General Public License.
-/// \file
-///
-/// Compute a canonized component tree from a dual input.
-
#ifndef MLN_MORPHO_TREE_DUAL_INPUT_TREE_HH
# define MLN_MORPHO_TREE_DUAL_INPUT_TREE_HH
-# include <mln/data/sort_psites.hh>
-
-# include <mln/morpho/tree/data.hh>
-# include <mln/morpho/tree/impl/dual_union_find.hh>
+# include <mln/tag/tree.hh>
+# include <mln/util/ctree/ctree.hh>
+# include <mln/morpho/tree/impl/union_find_fast.hh>
# include <mln/morpho/tree/impl/dual_hqueue.hh>
namespace mln
@@ -45,67 +40,25 @@ namespace mln
namespace tree
{
- /// Compute the dual input max tree using mask-based connectivity.
+ /// Compute a canonized max-tree.
///
- /// \param[in] f The original image.
- /// \param[in] m The connectivity mask.
- /// \param[in] nbh The neighborhood of the mask.
+ /// \param[in] f The input image.
+ /// \param[in] nbh The neighborhood.
///
- /// \return The computed tree.
+ /// \return The corresponding max-tree structure.
///
template <typename I, typename N>
inline
- data< I, p_array<mln_psite(I)> >
+ util::ctree::ctree<I>
dual_input_max_tree(const Image<I>& f,
const Image<I>& m,
const Neighborhood<N>& nbh);
-
# ifndef MLN_INCLUDE_ONLY
- namespace internal
- {
-
- template <typename I, typename N>
- inline
- data< I, p_array<mln_psite(I)> >
- dual_input_max_tree_dispatch(trait::image::quant::any,
- const I& f,
- const I& m,
- const N& nbh)
- {
- typedef p_array<mln_psite(I)> S;
- typedef data<I,S> tree_t;
-
- S s_f = mln::data::sort_psites_increasing(f);
- S s_m = mln::data::sort_psites_increasing(m);
-
- tree_t tree = impl::generic::dual_union_find(f, m, s_f, s_m, nbh);
- return tree;
- }
-
- template <typename I, typename N>
- inline
- data< I, p_array<mln_psite(I)> >
- dual_input_max_tree_dispatch(trait::image::quant::low,
- const I& f,
- const I& m,
- const N& nbh)
- {
- typedef p_array<mln_psite(I)> S;
- typedef data<I,S> tree_t;
-
- tree_t tree = impl::dual_hqueue(f, m, nbh);
- return tree;
- }
-
- } // end of namespace mln::morpho::tree::internal
-
-
- // Facades.
template <typename I, typename N>
inline
- morpho::tree::data< I, p_array<mln_psite(I)> >
+ util::ctree::ctree<I>
dual_input_max_tree(const Image<I>& f_,
const Image<I>& m_,
const Neighborhood<N>& nbh_)
@@ -117,23 +70,16 @@ namespace mln
const N& nbh = exact(nbh_);
mln_precondition(f.is_valid());
- mln_precondition(m.is_valid());
mln_precondition(nbh.is_valid());
- mln_precondition(f.domain() == m.domain());
- typedef p_array<mln_psite(I)> S;
- typedef data<I,S> tree_t;
+ util::ctree::ctree<I> tree =
+ morpho::tree::impl::dual_hqueue(tag::tree::max, f, m, nbh);
- tree_t tree = internal::dual_input_max_tree_dispatch(mln_trait_image_quant(I)(), f, m,
nbh);
-
- trace::exiting("morpho::tree::dual_input_max_tree");
+ trace::exiting("morpho::tree::max_tree");
return tree;
}
-
-
-
# endif // ! MLN_INCLUDE_ONLY
} // end of namespace mln::morpho::tree
@@ -142,5 +88,4 @@ namespace mln
} // end of namespace mln
-
#endif // !MLN_MORPHO_TREE_DUAL_INPUT_TREE_HH
diff --git a/milena/mln/morpho/tree/filter/direct.hh
b/milena/mln/morpho/tree/filter/direct.hh
index 1835e07..0fdb01c 100644
--- a/milena/mln/morpho/tree/filter/direct.hh
+++ b/milena/mln/morpho/tree/filter/direct.hh
@@ -27,7 +27,9 @@
# define MLN_MORPHO_TREE_FILTER_DIRECT_HH
# include <mln/core/concept/function.hh>
-# include <mln/morpho/tree/data.hh>
+# include <mln/core/image/attribute_image.hh>
+# include <mln/morpho/tree/propagate_node.hh>
+
/**
** \file mln/morpho/tree/filter/direct.hh
@@ -51,36 +53,39 @@ namespace mln
/**
** Direct non-pruning strategy. A node is removed if it does
- ** not verify the predicate. The sub-components remain intact.
+ ** not verify the predicate. Its pixels are lowered in gray
+ ** level to the highest ancestor which meets the criterion,
+ ** and while its descendants are unaffected.
**
- ** \param[in] tree Component tree.
- ** \param[out] f_ Image to filter.
+ ** \param[in,out] attr The attribute image.
** \param[in] pred_ Filtering criterion.
*/
- template <typename T, typename F, typename P>
+ template <typename T, typename V, typename P>
inline
void
- direct(const T& tree, Image<F>& f_, const Function_v2b<P>&
pred_);
+ direct(attribute_image<T,V>& attr, const Function_v2b<P>& pred_);
# ifndef MLN_INCLUDE_ONLY
- template <typename T, typename F, typename P>
+ template <typename T, typename V, typename F>
inline
void
- direct(const T& tree, Image<F>& f_, const Function_v2b<P>&
pred_)
+ direct(attribute_image<T,V>& attr, const Function_v2b<F>& pred_)
{
- F& f = exact(f_);
- const P& pred = exact(pred_);
-
trace::entering("mln::morpho::tree::filter::direct");
- mln_dn_node_piter(T) n(tree);
- for_all(n)
- if (!pred(n))
- f(n) = f(tree.parent(n));
+ typedef attribute_image<T,V> A;
+
+ const F& pred = exact(pred_);
+ const T& tree = attr.tree();
+
+ mln_fwd_piter(A) node(attr.domain());
+ for_all(node)
+ if (!pred(node))
+ attr(node) = attr(tree.parent(node));
trace::exiting("mln::morpho::tree::filter::direct");
}
diff --git a/milena/mln/morpho/tree/filter/max.hh b/milena/mln/morpho/tree/filter/max.hh
index fb0c580..96c2928 100644
--- a/milena/mln/morpho/tree/filter/max.hh
+++ b/milena/mln/morpho/tree/filter/max.hh
@@ -27,14 +27,16 @@
# define MLN_MORPHO_TREE_FILTER_MAX_HH
# include <mln/core/concept/function.hh>
-# include <mln/morpho/tree/data.hh>
+# include <mln/core/image/attribute_image.hh>
+# include <mln/morpho/tree/propagate_node.hh>
/**
** \file mln/morpho/tree/filter/max.hh
**
** \brief Filtering with max strategy.
**
-**
+** See comments in min filter documentation.
+** FIXME: it is possible to make it in one pass !
*/
namespace mln
@@ -54,51 +56,59 @@ namespace mln
** children are removed or if it does not verify the predicate
** \p pred_.
**
- ** \param[in] tree Component tree.
- ** \param[out] f_ Image to filter.
+ ** \param[in,out] attr The attribute image.
** \param[in] pred_ Filtering criterion.
*/
- template <typename T, typename F, typename P>
+ template <typename T, typename V, typename P>
inline
void
- max(const T& tree, Image<F>& f_, const Function_v2b<P>& pred_);
-
+ max(attribute_image<T,V>& attr, const Function_v2b<P>& pred_);
# ifndef MLN_INCLUDE_ONLY
- template <typename T, typename F, typename P>
+ template <typename T, typename V, typename P>
inline
void
- max(const T& tree, Image<F>& f_, const Function_v2b<P>& pred_)
+ max(attribute_image<T,V>& attr, const Function_v2b<P>& pred_)
{
- F& f = exact(f_);
- const P& pred = exact(pred_);
-
trace::entering("mln::morpho::tree::filter::max");
- mln_ch_value(F, bool) mark;
- initialize(mark, f);
- mln::data::fill(mark, true);
+ typedef attribute_image<T,V> A;
+ const P& pred = exact(pred_);
+ const T& tree = attr.tree();
+
+ typedef mln_ch_value(A, char) M;
+ M marker;
+ initialize(marker, attr);
+ mln::data::fill(marker, true);
+ // 1st pass up.
{
- mln_up_node_piter(T) n(tree);
- for_all(n)
- if (!mark(n))
- mark(tree.parent(n)) = false;
- else if (pred(n))
+ mln_bkd_piter(M) node(marker.domain());
+ for_all(node)
+ if (!marker(node))
+ marker(tree.parent(node)) = false;
+ else if (pred(node))
{
- mark(tree.parent(n)) = false;
- mark(n) = false;
+ marker(tree.parent(node)) = false;
+ marker(node) = false;
}
}
+ // 2nd pass down: propagation.
{
- mln_dn_node_piter(T) n(tree);
- for_all(n)
- if (mark(n))
- f(n) = f(tree.parent(n));
+ for (int i = 0; i < tree.n_nodes(); ++i)
+ {
+ mln_invariant(tree.has_index(i));
+ mln_psite(A) n(tree, i);
+ if (marker(n))
+ {
+ attr(n) = attr(tree.parent(n));
+ i += propagate_node_to_descendants(attr, n, attr(n));
+ }
+ }
}
trace::exiting("mln::morpho::tree::filter::max");
diff --git a/milena/mln/morpho/tree/filter/min.hh b/milena/mln/morpho/tree/filter/min.hh
index db46243..16d2224 100644
--- a/milena/mln/morpho/tree/filter/min.hh
+++ b/milena/mln/morpho/tree/filter/min.hh
@@ -27,7 +27,8 @@
# define MLN_MORPHO_TREE_FILTER_MIN_HH
# include <mln/core/concept/function.hh>
-# include <mln/morpho/tree/data.hh>
+# include <mln/core/image/attribute_image.hh>
+# include <mln/morpho/tree/propagate_node.hh>
/**
@@ -52,45 +53,57 @@ namespace mln
/**
- ** Min pruning strategy. A node is removed iif its parent is
+ ** Min pruning strategy. A node is removed iff its parent is
** removed or if it does not verify the predicate \p pred_.
**
- ** \param[in] tree Component tree.
- ** \param[out] f_ Image to filter.
+ ** \param[in,out] attr The attribute image.
** \param[in] pred_ Filtering criterion.
*/
- template <typename T, typename F, typename P>
+ template <typename T, typename V, typename F>
inline
void
- min(const T& tree, Image<F>& f_, const Function_v2b<P>& pred_);
+ min(attribute_image<T,V>& attr, const Function_v2b<F>& pred);
# ifndef MLN_INCLUDE_ONLY
- template <typename T, typename F, typename P>
+ template <typename T, typename V, typename F>
inline
void
- min(const T& tree, Image<F>& f_, const Function_v2b<P>& pred_)
+ min(attribute_image<T,V>& attr, const Function_v2b<F>& pred_)
{
- F& f = exact(f_);
- const P& pred = exact(pred_);
-
trace::entering("mln::morpho::tree::filter::min");
- mln_ch_value(F, bool) mark;
- initialize(mark, f);
- mln::data::fill(mark, false);
-
- mln_dn_node_piter(T) n(tree);
- for_all(n)
- if (mark(tree.parent(n)) || !pred(n))
- {
- f(n) = f(tree.parent(n));
- mark(n) = true;
- }
-
+ typedef attribute_image<T,V> A;
+
+ //mlc_is(mln_psite(A), mln_argument(F))::check();
+
+ const F& pred = exact(pred_);
+ const T& tree = attr.tree();
+
+ // Ce qui devrait être !
+ // mln_fwd_piter(A) n(attr);
+ // for_all(n)
+ // if (!pred(n))
+ // {
+ // data::fill_with_value(attr | tree.desc(n), attr(n));
+ // n.go_to_brother();
+ // }
+
+ // En attendant que le morpher subimage soit spécialisé,
+ // on joue avec les indexes.
+ for (int i = 0; i < tree.n_nodes(); ++i)
+ {
+ mln_invariant(tree.has_index(i));
+ mln_psite(A) n(tree, i);
+ if (!pred(n))
+ {
+ attr(n) = attr(tree.parent(n));
+ i += propagate_node_to_descendants(attr, n, attr(n));
+ }
+ }
trace::exiting("mln::morpho::tree::filter::min");
}
diff --git a/milena/mln/morpho/tree/filter/subtractive.hh
b/milena/mln/morpho/tree/filter/subtractive.hh
index 10d3043..b905f15 100644
--- a/milena/mln/morpho/tree/filter/subtractive.hh
+++ b/milena/mln/morpho/tree/filter/subtractive.hh
@@ -27,10 +27,8 @@
# define MLN_MORPHO_TREE_FILTER_SUBTRACTIVE_HH
# include <mln/core/concept/function.hh>
-# include <mln/fun/ops.hh>
-
-# include <mln/morpho/tree/data.hh>
-# include <mln/morpho/tree/propagate_if.hh>
+# include <mln/core/image/attribute_image.hh>
+# include <mln/morpho/tree/propagate_node.hh>
/**
** \file mln/morpho/tree/filter/subtractive.hh
@@ -57,45 +55,61 @@ namespace mln
** does not verify the predicate. The sub-components values
** are set to the value of the removed component.
**
- ** \param[in] tree Component tree.
- ** \param[out] f_ Image to filter.
+ ** \param[in] ori The values as an attribute image.
** \param[in] pred_ Filtering criterion.
+ ** \return A copy of \p ori filtered with the subtractive strategy.
*/
- template <typename T, typename F, typename P>
+ template <typename T, typename V, typename P>
inline
- void
- subtractive(const T& tree, Image<F>& f_, const Function_v2b<P>&
pred_);
-
-
+ attribute_image<T, V>
+ subtractive(const attribute_image<T,V>& ori, const Function_v2b<P>&
pred_);
# ifndef MLN_INCLUDE_ONLY
- template <typename T, typename F, typename P>
+ template <typename T, typename V, typename F>
inline
- void
- subtractive(const T& tree, Image<F>& f_, const Function_v2b<P>&
pred_)
+ attribute_image<T, V>
+ subtractive(const attribute_image<T,V>& ori, const Function_v2b<F>&
pred_)
{
- F& f = exact(f_);
- const P& pred = exact(pred_);
-
trace::entering("mln::morpho::tree::filter::subtractive");
- morpho::tree::propagate_if(tree, f, morpho::tree::desc_propagation (), !pred);
+ typedef attribute_image<T,V> A;
+
+ const F& pred = exact(pred_);
+ const T& tree = ori.tree();
+
+ mln_precondition(ori.is_valid());
- mln_up_node_piter(T) n(tree);
+ A f;
+ initialize(f, ori);
+
+ // Fixme: introduce mln_root_piter...
+ // and traverse all roots, not just the first one.
+ mln_psite(A) root = util::ctree::node<T>(tree, 0);
+ f(root) = ori(root);
+ std::cout << "Root value: " << ori(root) << std::endl;
+
+ mln_piter(A) n(ori.domain());
for_all(n)
if (!pred(n))
f(n) = f(tree.parent(n));
+ else
+ f(n) = f(tree.parent(n)) + ori(n) - ori(tree.parent(n));
trace::exiting("mln::morpho::tree::filter::subtractive");
+
+ return f;
}
# endif // ! MLN_INCLUDE_ONLY
} // end of namespace mln::morpho::tree::filter
+
} // end of namespace mln::morpho::tree
+
} // end of namespace mln::morpho
+
} // end of namespace mln
#endif // ! MLN_MORPHO_TREE_FILTER_SUBTRACTIVE_HH
diff --git a/milena/mln/morpho/tree/impl/dual_hqueue.hh
b/milena/mln/morpho/tree/impl/dual_hqueue.hh
index 41334f0..f00642f 100644
--- a/milena/mln/morpho/tree/impl/dual_hqueue.hh
+++ b/milena/mln/morpho/tree/impl/dual_hqueue.hh
@@ -32,31 +32,19 @@
/// This implementation is based on P. Salembier algorithm using
/// hierachical queues. This implies a low-quantized input image so
/// that the number of queues is limited.
-///
-/// TODO: Think about how to extend f domain in a more
-/// generic way. The actual implementation doubles the size of the
-/// first dimension. It implies a boxed domain.
-///
-/// TODO: Use the less functor. The actual implementation is for max-tree.
-///
-/// TODO: During the canonization pass, we build the tree site set
-/// from the sorted site set of f, so that we compute twice f
-/// histogram (can be avoided).
-# include <mln/data/sort_psites.hh>
+# include <mln/util/ctree/ctree.hh>
# include <mln/data/fill.hh>
+# include <mln/extension/fill.hh>
+# include <mln/extension/adjust.hh>
# include <mln/geom/nsites.hh>
-# include <mln/geom/translate.hh>
-# include <mln/morpho/tree/data.hh>
# include <mln/util/hqueues.hh>
-# include <mln/util/ord.hh>
# include <mln/value/value_array.hh>
# include <mln/value/set.hh>
-
# include <mln/util/timer.hh>
namespace mln
@@ -79,320 +67,430 @@ namespace mln
///
/// \return The tree structure.
///
- template <typename I, typename N>
- inline
- data<I, p_array<mln_psite(I)> >
- dual_hqueue(const Image<I>& f,
+ template <typename T, typename I, typename N>
+ util::ctree::ctree<I>
+ dual_hqueue(const tag::tree::tree_t<T>&,
+ const Image<I>& f,
const Image<I>& m,
const Neighborhood<N>& nbh);
+
} // end of namespace mln::morpho::tree::impl
# ifndef MLN_INCLUDE_ONLY
- namespace internal
+ namespace impl
{
- template <typename I, typename N, class E>
- struct shared_flood_args
+
+ template <typename I, typename N, typename E>
+ struct flooder_base_ : Object<E>
{
- typedef mln_psite(I) P;
+ typedef unsigned P;
typedef mln_value(I) V;
- typedef p_array<P> S;
+ // Constructor.
+ flooder_base_(const I& f_, const I& m_, const N& nbh_);
+
+ // Returned values.
+ mln_ch_value(I, unsigned) map;
+ std::vector<P> location;
+ std::vector<V> values;
+ std::vector<P> parent;
+ std::vector<unsigned> area;
+ unsigned nnode;
+
+
+ protected:
+ enum {
+ nvalues = mln_card(mln_value(I))
+ };
+
+
+ // Recursive function that floods. Canevas function.
+ int flood(int h_idx);
+
+ // HLevel comparaison. To be specialized for min/max tree.
+ bool hlevel_less(int h_idx1, int h_idx2);
+
+ // Parent attachment function. To be specialized for min/max tree.
+ int attach_parent(int h_idx);
+
+ // Data.
+ // \{
const I& f;
const I& m;
const N& nbh;
- mln_ch_value(I, P)& parent;
- // Aux data
- util::hqueues<P, V>& hqueues;
- const E& extend; // site -> site functor.
+ // Auxiliary data.
+ util::hqueues<unsigned, V> hqueues;
+ value::set<V> vset;
+ util::array<int> dp;
+ unsigned n_nbhs;
+
+ mln_ch_value(I, bool) deja_vu;
value::value_array<V, bool> is_node_at_level;
value::value_array<V, P> node_at_level;
- mln_ch_value(I, bool) deja_vu;
- const value::set<V>& vset;
-
- shared_flood_args(const I& f_,
- const I& m_,
- const N& neigb_,
- mln_ch_value(I, P)& parent_,
- util::hqueues<mln_psite(I), V>& hqueues_,
- const E& extend_)
- : f (f_),
- m (m_),
- nbh (neigb_),
- parent (parent_),
- hqueues (hqueues_),
- extend (extend_),
- is_node_at_level (false),
- vset (hqueues.vset())
- {
- initialize(deja_vu, f);
- mln::data::fill(deja_vu, false);
- }
+ unsigned loc;
+ // \}
};
- template <typename I>
- inline
- histo::array<mln_value(I)>
- compute_histo(const I& f, const I& m, mln_value(I)& hmin, mln_psite(I)&
pmin)
+ template <typename T, typename I, typename N>
+ struct flooder;
+
+ template <typename I, typename N>
+ struct flooder<tag::tree::max_t, I, N> :
+ flooder_base_< I, N, flooder<tag::tree::max_t, I, N> >
{
- histo::array<mln_value(I)> hm = histo::compute(m);
- const histo::array<mln_value(I)> hf = histo::compute(f);
-
- { // Retrieve hmin.
- unsigned i = 0;
- while (hm[i] == 0)
- ++i;
- hmin = hm.vset()[i];
- }
+ typedef mln_value(I) V;
+ typedef flooder_base_< I, N, flooder<tag::tree::max_t, I, N> > super_;
- // Merge histograms.
- for (unsigned i = 0; i < hm.nvalues(); ++i)
- hm[i] += hf[i];
+ // Constructor.
+ flooder(const I& f, const I& m, const N& nbh);
- // Retrieve pmin.
- mln_piter(I) p(m.domain());
- for (p.start(); m(p) != hmin; p.next())
- ;
- mln_assertion(p.is_valid());
- pmin = p;
+ // HLevel comparaison.
+ bool hlevel_less_(int h_idx1, int h_idx2);
- return hm;
- }
+ // Parent attachment function.
+ int attach_parent_(int h_idx);
+
+ public:
+ using super_::parent;
+ using super_::area;
+ using super_::location;
- // Site -> site functor: give for all p in Domain(f), its
- // equivalence in the extended domain.
- // TODO: make it generic. It works only on boxed domain.
- template <typename I>
- struct extend
+ protected:
+ using super_::is_node_at_level;
+ using super_::node_at_level;
+ using super_::vset;
+ using super_::loc;
+ using super_::hqueues;
+ };
+
+ template <typename I, typename N>
+ struct flooder<tag::tree::min_t, I, N> :
+ flooder_base_< I, N, flooder<tag::tree::min_t, I, N> >
{
- extend(const mln_psite(I)::delta& dp)
- : dp_ (dp)
- {
- }
+ typedef mln_value(I) V;
+ typedef flooder_base_< I, N, flooder<tag::tree::min_t, I, N> > super_;
- mln_psite(I) operator() (const mln_psite(I)& p) const
- {
- return p + dp_;
- }
+ // Constructor.
+ flooder(const I& f, const I& m, const N& nbh);
- private:
- const mln_psite(I)::delta dp_;
+ // HLevel comparaison.
+ bool hlevel_less_(int h_idx1, int h_idx2);
+
+ // Parent attachment function.
+ unsigned attach_parent_(int h_idx);
+
+ public:
+ using super_::parent;
+ using super_::area;
+ using super_::location;
+
+ protected:
+ using super_::is_node_at_level;
+ using super_::node_at_level;
+ using super_::vset;
+ using super_::loc;
+ using super_::hqueues;
};
- } // end of namespace mln::morpho::tree::internal
- namespace impl
- {
+ template <typename I, typename N, typename E>
+ inline
+ bool
+ flooder_base_<I, N, E>::hlevel_less(int h_idx1, int h_idx2)
+ {
+ E& obj = exact(*this);
+ return obj.hlevel_less_(h_idx1, h_idx2);
+ }
template <typename I, typename N, typename E>
- unsigned
- flood(internal::shared_flood_args<I, N, E>& args, const unsigned h_idx)
+ inline
+ int
+ flooder_base_<I, N, E>::attach_parent(int h_idx)
{
- mln_assertion(args.is_node_at_level[h_idx]);
+ E& obj = exact(*this);
+ return obj.attach_parent_(h_idx);
+ }
- while (!args.hqueues[h_idx].empty())
- {
- mln_psite(I) p = args.hqueues[h_idx].pop_front();
- unsigned p_idx = args.vset.index_of(args.f(p));
-
- if (p_idx != h_idx)
- { // Intensity mismatch: irregular case.
- mln_psite(I) pext = args.extend(p);
- args.parent(pext) = args.node_at_level[h_idx];
-
- if (p_idx > h_idx) // Singleton with parent at h.
- args.parent(p) = args.node_at_level[h_idx];
- else
- {
- if (!args.is_node_at_level[p_idx])
- {
- args.is_node_at_level[p_idx] = true;
- args.node_at_level[p_idx] = p;
- }
- }
- }
+ template <typename I, typename N>
+ inline
+ flooder<tag::tree::max_t, I, N>::flooder(const I& f_, const I& m_, const
N& nbh_)
+ : flooder_base_<I, N, flooder<tag::tree::max_t, I, N> >(f_, m_, nbh_)
+ {
+ }
- if (p_idx <= h_idx)
- {
- if (!args.f.domain().has(args.node_at_level[p_idx]) ||
- util::ord_strict(p, args.node_at_level[p_idx]))
- { // Regular case but a representative provided by the extension.
- args.parent(args.node_at_level[p_idx]) = p;
- args.node_at_level[p_idx] = p;
- //args.parent(p) = p;
- }
- args.parent(p) = args.node_at_level[p_idx];
- }
+ template <typename I, typename N>
+ inline
+ flooder<tag::tree::min_t, I, N>::flooder(const I& f_, const I& m_, const
N& nbh_)
+ : flooder_base_<I, N, flooder<tag::tree::min_t, I, N> >(f_, m_, nbh_)
+ {
+ }
+ template <typename I, typename N>
+ inline
+ bool
+ flooder<tag::tree::max_t, I, N>::hlevel_less_(int h_idx1, int h_idx2)
+ {
+ return h_idx1 < h_idx2;
+ }
- // Process the neighbors
- mln_niter(N) n(args.nbh, p);
- for_all(n)
- if (args.f.domain().has(n) && !args.deja_vu(n))
- {
- unsigned mn = args.vset.index_of(args.m(n));
- unsigned fn = args.vset.index_of(args.f(n));
- args.hqueues[mn].push(n);
- args.deja_vu(n) = true;
-
- mln_psite(I) ext = args.extend(n);
- // Create a node at c.
- {
- mln_psite(I) node = (fn == mn) ? n : ext;
- if (!args.is_node_at_level[mn])
- {
- args.is_node_at_level[mn] = true;
- args.node_at_level[mn] = node;
- }
- }
-
- while (mn > h_idx)
- mn = flood(args, mn);
- }
- }
+ template <typename I, typename N>
+ inline
+ bool
+ flooder<tag::tree::min_t, I, N>::hlevel_less_(int h_idx1, int h_idx2)
+ {
+ return h_idx2 < h_idx1;
+ }
- // Retrieve dad.
- args.is_node_at_level[h_idx] = false;
- unsigned c = h_idx;
- while (c > 0 && !args.is_node_at_level[c])
+ template <typename I, typename N>
+ inline
+ int
+ flooder<tag::tree::max_t, I, N>::attach_parent_(int h_idx)
+ {
+ mln_assertion(h_idx >= 0);
+ mln_assertion(is_node_at_level[h_idx]);
+
+
+ unsigned x = node_at_level[h_idx];
+ int c = h_idx - 1;
+
+ is_node_at_level[h_idx] = false;
+ while (c >= 0 && !is_node_at_level[c])
--c;
- mln_psite(I) x = args.node_at_level[h_idx];
- if (c > 0)
- args.parent(x) = args.node_at_level[c];
- else
- args.parent(x) = x;
+ if (c >= 0)
+ {
+ unsigned p = node_at_level[c];
+ parent[x] = p;
+ area[p] += area[x] + 1;
+ }
+ else // root case.
+ parent[x] = x;
+ location[x] = loc++;
return c;
}
- template <typename I, typename N>
- inline
- data< I, p_array<mln_psite(I)> >
- dual_hqueue(const Image<I>& f_,
- const Image<I>& m_,
- const Neighborhood<N>& neibh_)
- {
- trace::entering("mln::morpho::tree::impl::dual_hqueue");
+ // template <typename I, typename N>
+ // inline
+ // unsigned
+ // flooder<tag::tree::min_t, I, N>::attach_parent_(unsigned h_idx)
+ // {
+ // unsigned nv = vset.nvalues() - 1;
+ // unsigned c = h_idx;
- const I& f = exact(f_);
- const I& m = exact(m_);
- const N& nbh = exact(neibh_);
+ // while (c < nv && !is_node_at_level[c])
+ // ++c;
- typedef mln_psite(I) P;
- typedef p_array<mln_psite(I)> S;
+ // unsigned x = node_at_level[h_idx];
+ // if (is_node_at_level[c])
+ // {
+ // unsigned p = node_at_level[c];
+ // parent[x] = p;
+ // area[p] += area[x] + 1;
+ // }
+ // else
+ // parent[x] = x;
- util::timer tm;
- tm.start();
+ // location[x] = loc++;
+ // return c;
+ // }
- // Histo.
- mln_psite(I) pmin;
- mln_value(I) hmin;
- const histo::array<mln_value(I)> histo = internal::compute_histo(f, m, hmin,
pmin);
- util::hqueues<P, mln_value(I)> hqueues(histo);
- mln_psite(I)::delta dp(literal::zero);
- mln_domain(I) d_ext = f.domain();
- mln_domain(I) d = f.domain();
+ template <typename I, typename N, typename E>
+ flooder_base_<I, N, E>::flooder_base_(const I& f_, const I& m_, const
N& nbh_)
+ : f (f_), m(m_), nbh (nbh_), is_node_at_level (false)
+ {
+ typedef mln_value(I) V;
- // Extend the domain.
- dp[0] = d.pmax()[0] - d.pmin()[0] + 1;
- d.pmax() += dp;
- d_ext.pmin() += dp;
- d_ext.pmax() += dp;
+ unsigned pmin_offset;
+ V vmin;
- // Data.
- mln_concrete(I) fext;
- mln_ch_value(I, P) parent;
- p_array<mln_psite(I)> s;
-
- // Initialization.
- fext = geom::translate(m, dp.to_vec(), f, d);
- initialize(parent, fext);
- s.reserve(geom::nsites(fext));
-
- // Process.
- internal::extend<I> extend(dp);
- internal::shared_flood_args< I, N, internal::extend<I> >
- args(f, m, nbh, parent, hqueues, extend);
-
- unsigned r = args.vset.index_of(hmin);
- args.deja_vu(pmin) = true;
- args.hqueues[r].push(pmin);
- args.node_at_level[r] = (f(pmin) == hmin) ? pmin : extend(pmin);
- args.is_node_at_level[r] = true;
- flood(args, r);
-
- // Attach the nodes under hmin.
- unsigned i = r;
- do
+ // Allocate hierarchical queues and retrieve the starting point
{
- if (args.is_node_at_level[i])
- {
- parent(args.node_at_level[r]) = args.node_at_level[i];
- r = i;
- }
+ util::array< unsigned > h(nvalues, 0);
+
+ pmin_offset = m.index_of_point(m.domain().pmin());
+ vmin = m.element(pmin_offset);
+
+ mln_fwd_pixter(const I) pxl(m);
+ for_all(pxl)
+ {
+ ++h[pxl.val()];
+ if (hlevel_less(pxl.val(), vmin))
+ {
+ vmin = pxl.val();
+ pmin_offset = pxl.offset();
+ }
+ }
+
+ for (unsigned i = 0; i < nvalues; ++i)
+ hqueues[i].reserve(h[i]);
}
- while (i-- > 0);
- parent(args.node_at_level[r]) = args.node_at_level[r]; //root
- // Canonization and make tree site set.
- {
- mln_ch_value(I, bool) deja_vu(d_ext);
- mln::data::fill(deja_vu, false);
+ // Initialize aux data
+ {
+ dp = offsets_wrt(f, nbh);
+ n_nbhs = dp.nelements();
+ vset = value::set<V>::the();
+
+ extension::adjust(f, nbh);
+ extension::adjust(m, nbh);
+
+ initialize(deja_vu, f);
+ initialize(map, f);
+ data::fill(deja_vu, false);
+ extension::fill(deja_vu, true);
+
+ unsigned nsites = geom::nsites(f);
+ parent.resize(2 * nsites);
+ location.resize(2 * nsites);
+ area.resize(2 * nsites, 0);
+ values.resize(2 * nsites);
+
+ nnode = 0;
+ loc = 0;
+ }
+
+ // Start flooding
+ unsigned hmin = vset.index_of(vmin);
+ unsigned fmin = vset.index_of(f.element(pmin_offset));
+ std::cout << vmin << std::endl;
+ hqueues[hmin].push(pmin_offset);
+ deja_vu.element(pmin_offset) = true;
+ values[nnode] = vmin;
+ node_at_level[fmin] = nnode++;
+ is_node_at_level[fmin] = true;
+ if (hmin != fmin)
+ {
+ values[nnode] = f.element(pmin_offset);
+ node_at_level[hmin] = nnode++;
+ is_node_at_level[hmin] = true;
+ }
+ int c = flood(hmin);
+ while (c != -1) // There still are nodes under minimal mask level.
+ c = attach_parent(c);
+ mln_assertion(c == -1);
+ }
- p_array<mln_psite(I)> s_f = mln::data::sort_psites_increasing(f);
- mln_fwd_piter(S) p(s_f); // Forward.
- for_all(p)
+ template <typename I, typename N, typename E>
+ int
+ flooder_base_<I, N, E>::flood(int h_idx)
+ {
+ mln_assertion(h_idx >= 0);
+ mln_assertion(is_node_at_level[h_idx]);
+
+ while (!hqueues[h_idx].empty())
{
- P x = p;
- P q = parent(p);
+ unsigned p = hqueues[h_idx].pop_front();
+ int p_idx = vset.index_of(f.element(p));
+ mln_assertion(vset.index_of(m.element(p)) == (unsigned)h_idx);
+ //mln_assertion(is_node_at_level[p_idx]);
- // Case: l: m <---- m <---- f
- // Or
- // Case l1: m <----- f impossible.
- // |
- // l2: m
- mln_assertion(!(d_ext.has(q) && fext(p) == fext(q) &&
d_ext.has(parent(q)) && q != parent(q)));
- while (d_ext.has(q) && !deja_vu(q) && (fext(q) != fext(parent(q))
|| q == parent(q)))
+ if (h_idx < p_idx) // FIXME: max tree only
{
- s.append(q);
- deja_vu(q) = true;
- x = q;
- q = parent(q);
+ // Singleton
+ int par_i = node_at_level[h_idx];
+ int self_i = nnode++; // Create the node.
+ map.element(p) = self_i;
+ values[self_i] = m.element(p);
+ area[self_i] = 1;
+ parent[self_i] = par_i;
+ location[self_i] = loc++;
+ area[par_i]++;
}
+ else
+ map.element(p) = node_at_level[p_idx];
- if (d_ext.has(q) && fext(q) == fext(parent(q)) && q != parent(q))
+ // Process the neighbors
+ for (unsigned j = 0; j < n_nbhs; ++j)
{
- q = (parent(x) = parent(q));
- mln_assertion(f.domain().has(q));
+ unsigned n = p + dp[j];
+
+ if (!deja_vu.element(n))
+ {
+ unsigned n_hidx = vset.index_of(m.element(n));
+ unsigned n_fidx = vset.index_of(f.element(n));
+ hqueues[n_hidx].push(n);
+ deja_vu.element(n) = true;
+
+ if (!is_node_at_level[n_hidx])
+ {
+ values[nnode] = (m.element(n));
+ node_at_level[n_hidx] = nnode++;
+ is_node_at_level[n_hidx] = true;
+ }
+ if (!is_node_at_level[n_fidx] && n_fidx < n_hidx)
+ {
+ values[nnode] = (f.element(n));
+ node_at_level[n_fidx] = nnode++;
+ is_node_at_level[n_fidx] = true;
+ }
+
+ while (hlevel_less(h_idx, n_hidx))
+ n_hidx = flood(n_hidx);
+ }
}
+ }
- if (fext(q) == fext(parent(q)))
- parent(x) = parent(q);
+ return attach_parent(h_idx);
+ }
+
+ template <typename T, typename I, typename N>
+ inline
+ util::ctree::ctree<I>
+ dual_hqueue(const tag::tree::tree_t<T>&,
+ const Image<I>& f_,
+ const Image<I>& m_,
+ const Neighborhood<N>& nbh_)
+ {
+ trace::entering("mln::morpho::tree::impl::hqueue");
+ const I& f = exact(f_);
+ const I& m = exact(m_);
+ const N& nbh = exact(nbh_);
- s.append(p);
+ mln_precondition(f.is_valid());
+ mln_precondition(m.is_valid());
+ mln_precondition(nbh.is_valid());
- mln_assertion((q = parent(p)) == parent(q) || fext(q) != fext(parent(q)));
- }
+ // Process
+ impl::flooder<T, I, N> args(f, m, nbh);
- }
+ // Reserve
+ util::ctree::ctree<I> tree;
+ tree.reserve(f, args.nnode);
- std::cout << "Construction de l'arbre en " << tm <<
" s." << std::endl;
+ // Set values
+ {
+ mln_piter(I) p(f.domain());
+ for_all(p)
+ {
+ unsigned idx = args.map(p);
+ unsigned loc = args.nnode - args.location[idx] - 1;
+ tree.node_at_(p) = loc;
+ }
- data<I, S> tree(fext, parent, s);
+ for (int idx = 0; idx < args.nnode; ++idx)
+ {
+ unsigned loc = args.nnode - args.location[idx] - 1;
- trace::exiting("mln::morpho::tree::impl::dual_hqueue");
+ tree.parent_at_(loc) = args.nnode - args.location[args.parent[idx]] - 1;
+ tree.f_at_(loc) = args.values[idx];
+ tree.length_at_(loc) = args.area[idx];
+ }
+ }
+ trace::exiting("mln::morpho::tree::impl::hqueue");
return tree;
}
- } // end of namespace mln::morpho::tree::impl
+ } // end of namespace mln::morpho::tree::impl
+
# endif // ! MLN_INCLUDE_ONLY
diff --git a/milena/mln/morpho/tree/impl/hqueue.hh
b/milena/mln/morpho/tree/impl/hqueue.hh
new file mode 100644
index 0000000..cfe0f4b
--- /dev/null
+++ b/milena/mln/morpho/tree/impl/hqueue.hh
@@ -0,0 +1,428 @@
+// Copyright (C) 2008, 2009 EPITA Research and Development Laboratory (LRDE)
+//
+// This file is part of Olena.
+//
+// Olena is free software: you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation, version 2 of the License.
+//
+// Olena 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 Olena. If not, see <http://www.gnu.org/licenses/>.
+//
+// As a special exception, you may use this file as part of a free
+// software project 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_MORPHO_TREE_IMPL_HQUEUE_HH
+# define MLN_MORPHO_TREE_IMPL_HQUEUE_HH
+
+# include <mln/util/ctree/ctree.hh>
+# include <mln/util/hqueues.hh>
+# include <mln/value/value_array.hh>
+# include <mln/geom/nsites.hh>
+
+# include <mln/histo/array.hh>
+# include <mln/histo/compute.hh>
+# include <mln/data/fill.hh>
+
+namespace mln
+{
+
+ namespace morpho
+ {
+
+ namespace tree
+ {
+
+ namespace impl
+ {
+
+ template <typename T, typename I, typename N>
+ inline
+ util::ctree::ctree<I>
+ hqueue(const tag::tree::tree_t<T>&, const Image<I>& f, const
Neighborhood<N>& nbh);
+
+ } // end of namespace mln::morpho::tree::impl
+
+# ifndef MLN_INCLUDE_ONLY
+
+ namespace internal
+ {
+
+ template <typename T, typename I>
+ struct op_psite_less;
+
+ template <typename I>
+ struct op_psite_less< tag::tree::max_t, I>
+ {
+ op_psite_less(const I& f) : f_(f) {}
+
+ bool operator() (const mln_psite(I)& lhs, const mln_psite(I)& rhs) const
+ {
+ return util::ord_strict(f_(lhs), f_(rhs));
+ }
+
+ private:
+ const I& f_;
+ };
+
+ template <typename I>
+ struct op_psite_less< tag::tree::min_t, I>
+ {
+ op_psite_less(const I& f) : f_(f) {}
+
+ bool operator() (const mln_psite(I)& lhs, const mln_psite(I)& rhs) const
+ {
+ return util::ord_strict(f_(rhs), f_(lhs));
+ }
+
+ private:
+ const I& f_;
+ };
+
+ }
+
+
+ namespace impl
+ {
+
+
+ template <typename I, typename N, typename E>
+ struct flooder_base_ : Object<E>
+ {
+ typedef unsigned P;
+ typedef mln_value(I) V;
+
+ // Constructor.
+ flooder_base_(const I& f_, const N& nbh_);
+
+ // Returned values.
+ mln_ch_value(I, unsigned) map;
+ std::vector<P> location;
+ std::vector<P> parent;
+ std::vector<unsigned> area;
+ unsigned n_node;
+
+
+ protected:
+ // Recursive function that floods. Canevas function.
+ unsigned flood(const unsigned h_idx);
+
+ // HLevel comparaison. To be specialized for min/max tree.
+ bool hlevel_less(unsigned h_idx1, unsigned h_idx2);
+
+ // Parent attachment function. To be specialized for min/max tree.
+ unsigned attach_parent(unsigned h_idx);
+
+ // Data.
+ // \{
+ const I& f;
+ const N& nbh;
+
+ // Auxiliary data.
+ util::hqueues<mln_psite(I), V> hqueues;
+ value::set<V> vset;
+
+ mln_ch_value(I, bool) deja_vu;
+ value::value_array<V, bool> is_node_at_level;
+ value::value_array<V, P> node_at_level;
+ unsigned loc;
+ // \}
+ };
+
+ template <typename T, typename I, typename N>
+ struct flooder;
+
+ template <typename I, typename N>
+ struct flooder<tag::tree::max_t, I, N> :
+ flooder_base_< I, N, flooder<tag::tree::max_t, I, N> >
+ {
+ typedef mln_value(I) V;
+ typedef flooder_base_< I, N, flooder<tag::tree::max_t, I, N> > super_;
+
+ // Constructor.
+ flooder(const I& f_, const N& nbh_);
+
+ // HLevel comparaison.
+ bool hlevel_less_(unsigned h_idx1, unsigned h_idx2);
+
+ // Parent attachment function.
+ unsigned attach_parent_(unsigned h_idx);
+
+ public:
+ using super_::parent;
+ using super_::area;
+ using super_::location;
+
+ protected:
+ using super_::is_node_at_level;
+ using super_::node_at_level;
+ using super_::vset;
+ using super_::loc;
+ };
+
+ template <typename I, typename N>
+ struct flooder<tag::tree::min_t, I, N> :
+ flooder_base_< I, N, flooder<tag::tree::min_t, I, N> >
+ {
+ typedef mln_value(I) V;
+ typedef flooder_base_< I, N, flooder<tag::tree::min_t, I, N> > super_;
+
+ // Constructor.
+ flooder(const I& f_, const N& nbh_);
+
+ // HLevel comparaison.
+ bool hlevel_less_(unsigned h_idx1, unsigned h_idx2);
+
+ // Parent attachment function.
+ unsigned attach_parent_(unsigned h_idx);
+
+ public:
+ using super_::parent;
+ using super_::area;
+ using super_::location;
+
+ protected:
+ using super_::is_node_at_level;
+ using super_::node_at_level;
+ using super_::vset;
+ using super_::loc;
+ };
+
+
+ template <typename I, typename N, typename E>
+ inline
+ bool
+ flooder_base_<I, N, E>::hlevel_less(unsigned h_idx1, unsigned h_idx2)
+ {
+ E& obj = exact(*this);
+ return obj.hlevel_less_(h_idx1, h_idx2);
+ }
+
+ template <typename I, typename N, typename E>
+ inline
+ unsigned
+ flooder_base_<I, N, E>::attach_parent(unsigned h_idx)
+ {
+ E& obj = exact(*this);
+ return obj.attach_parent_(h_idx);
+ }
+
+ template <typename I, typename N>
+ inline
+ flooder<tag::tree::max_t, I, N>::flooder(const I& f_, const N& nbh_,
+ const histo::array< mln_value(I) >& histo_)
+ : flooder_base_<I, N, flooder<tag::tree::max_t, I, N> >(f_, nbh_, histo_)
+ {
+ }
+
+ template <typename I, typename N>
+ inline
+ flooder<tag::tree::min_t, I, N>::flooder(const I& f_, const N& nbh_,
+ const histo::array<mln_value(I)>& histo_)
+ : flooder_base_<I, N, flooder<tag::tree::min_t, I, N> >(f_, nbh_, histo_)
+ {
+ }
+
+ template <typename I, typename N>
+ inline
+ bool
+ flooder<tag::tree::max_t, I, N>::hlevel_less_(unsigned h_idx1, unsigned h_idx2)
+ {
+ return h_idx1 < h_idx2;
+ }
+
+ template <typename I, typename N>
+ inline
+ bool
+ flooder<tag::tree::min_t, I, N>::hlevel_less_(unsigned h_idx1, unsigned h_idx2)
+ {
+ return h_idx2 < h_idx1;
+ }
+
+ template <typename I, typename N>
+ inline
+ unsigned
+ flooder<tag::tree::max_t, I, N>::attach_parent_(unsigned h_idx)
+ {
+ unsigned c = h_idx;
+ while (c > 0 && !is_node_at_level[c])
+ --c;
+
+ unsigned x = node_at_level[h_idx];
+ if (is_node_at_level[c]) // || c > 0
+ {
+ unsigned p = node_at_level[c];
+ parent[x] = p;
+ area[p] += area[x] + 1;
+ }
+ else
+ parent[x] = x;
+
+ location[x] = loc++;
+ return c;
+ }
+
+ template <typename I, typename N>
+ inline
+ unsigned
+ flooder<tag::tree::min_t, I, N>::attach_parent_(unsigned h_idx)
+ {
+ unsigned nv = vset.nvalues() - 1;
+ unsigned c = h_idx;
+
+ while (c < nv && !is_node_at_level[c])
+ ++c;
+
+ unsigned x = node_at_level[h_idx];
+ if (is_node_at_level[c]) // || c < nv
+ {
+ unsigned p = node_at_level[c];
+ parent[x] = p;
+ area[p] += area[x] + 1;
+ }
+ else
+ parent[x] = x;
+
+ location[x] = loc++;
+ return c;
+ }
+
+
+ template <typename I, typename N, typename E>
+ flooder_base_<I, N, E>::flooder_base_(const I& f_, const N& nbh_,
+ const histo::array< mln_value(I) >& histo_)
+ : f (f_), nbh (nbh_), is_node_at_level (false)
+ {
+ // Initialization
+ {
+ unsigned nsites = geom::nsites(f);
+ initialize(map, f);
+ initialize(deja_vu, f);
+
+ parent.resize(nsites);
+ location.resize(nsites);
+ area.resize(nsites, 0);
+ data::fill(deja_vu, false);
+
+ vset = value::set< mln_value(I) >::the();
+
+ n_node = 0;
+ loc = 0;
+ }
+
+ // Get start value
+ mln_psite(I) pstart = f.domain().pmin();
+ mln_value(I) hstart = f(pstart);
+ {
+ mln_piter(I) p(f.domain());
+ for_all(p)
+ {
+ mln_value(I) v = f(p);
+ ++h[v];
+ if (hlevel_less(v, hstart))
+ {
+ hstart = v;
+ pstart = p;
+ }
+ }
+
+ for (unsigned i = 0; i < nvalues; ++i)
+ hqueues[i].reserve(h[i]);
+ }
+
+ // Start flooding
+ unsigned r = vset.index_of(hstart);
+ deja_vu(pstart) = true;
+ hqueues[r].push(pstart);
+ node_at_level[r] = n_node++;
+ is_node_at_level[r] = true;
+
+ flood(r);
+ }
+
+ template <typename I, typename N, typename E>
+ unsigned
+ flooder_base_<I, N, E>::flood(const unsigned h_idx)
+ {
+ mln_assertion(is_node_at_level[h_idx]);
+
+ while (!hqueues[h_idx].empty())
+ {
+ mln_psite(I) p = hqueues[h_idx].pop_front();
+ mln_assertion(vset.index_of(f(p)) == h_idx);
+
+ map(p) = node_at_level[h_idx];
+
+ // Process the neighbors
+ mln_niter(N) n(nbh, p);
+ for_all(n)
+ if (f.domain().has(n) && !deja_vu(n))
+ {
+ unsigned n_idx = vset.index_of(f(n));
+ hqueues[n_idx].push(n);
+ deja_vu(n) = true;
+
+ if (!is_node_at_level[n_idx])
+ {
+ node_at_level[n_idx] = n_node++;
+ is_node_at_level[n_idx] = true;
+ }
+
+ while (hlevel_less(h_idx, n_idx))
+ n_idx = flood(n_idx);
+ }
+ }
+
+ is_node_at_level[h_idx] = false;
+ return attach_parent(h_idx);
+ }
+
+ template <typename T, typename I, typename N>
+ inline
+ util::ctree::ctree<I>
+ hqueue(const tag::tree::tree_t<T>&, const Image<I>& f_, const
Neighborhood<N>& nbh_)
+ {
+ trace::entering("mln::morpho::tree::impl::hqueue");
+ const I& f = exact(f_);
+ const N& nbh = exact(nbh_);
+
+ mln_precondition(f.is_valid());
+ mln_precondition(nbh.is_valid());
+
+ // Process
+ impl::flooder<T, I, N> args(f, nbh);
+ // \todo handles here discontinous domains: so multi-roots trees.
+
+ args.parent.resize(args.n_node);
+ args.area.resize(args.n_node);
+ args.location.resize(args.n_node);
+
+ util::ctree::ctree<I> tree(f, args.map, args.location, args.parent,
+ args.area);
+
+ trace::exiting("mln::morpho::tree::impl::hqueue");
+ return tree;
+ }
+
+ } // end of namespace mln::morpho::tree::impl
+
+# endif // ! MLN_INCLUDE_ONLY
+
+ } // end of namespace mln::morpho::tree
+
+ } // end of namespace mln::morpho
+
+} // end of namespace mln
+
+#endif // !MLN_MORPHO_TREE_IMPL_HQUEUE_HH
diff --git a/milena/mln/morpho/tree/impl/hqueue_fast.hh
b/milena/mln/morpho/tree/impl/hqueue_fast.hh
new file mode 100644
index 0000000..645bbc4
--- /dev/null
+++ b/milena/mln/morpho/tree/impl/hqueue_fast.hh
@@ -0,0 +1,391 @@
+#ifndef MLN_MORPHO_TREE_IMPL_HQUEUE_FASTHH
+# define MLN_MORPHO_TREE_IMPL_HQUEUE_FASTHH
+
+# include <mln/extension/adjust.hh>
+# include <mln/extension/fill.hh>
+# include <mln/util/ctree/ctree.hh>
+# include <mln/util/hqueues.hh>
+# include <mln/value/value_array.hh>
+# include <mln/geom/nsites.hh>
+# include <mln/data/fill.hh>
+
+namespace mln
+{
+
+ namespace morpho
+ {
+
+ namespace tree
+ {
+
+ namespace impl
+ {
+
+ template <typename T, typename I, typename N>
+ util::ctree::ctree<I>
+ hqueue_fast(const tag::tree::tree_t<T>&, const Image<I>& f, const
Neighborhood<N>& nbh);
+
+ } // end of namespace mln::morpho::tree::impl
+
+# ifndef MLN_INCLUDE_ONLY
+
+ namespace impl
+ {
+
+ template <typename I, typename N, typename E>
+ struct flooder_base_ : Object<E>
+ {
+ typedef unsigned P;
+ typedef mln_value(I) V;
+
+ // Constructor.
+ flooder_base_(const I& f_, const N& nbh_);
+
+ mln_ch_value(I, unsigned) map;
+ std::vector<P> location;
+ std::vector<P> parent;
+ std::vector<unsigned> area;
+ unsigned n_node;
+
+ protected:
+ enum {
+ nvalues = mln_card(mln_value(I))
+ };
+
+ // Recursive function that floods. Canevas function.
+ unsigned flood(const unsigned h_idx);
+
+ // HLevel comparaison. To be specialized for min/max tree.
+ bool hlevel_less(unsigned h_idx1, unsigned h_idx2);
+
+ // Parent attachment function. To be specialized for min/max tree.
+ unsigned attach_parent(unsigned h_idx);
+
+
+ // Data.
+ // \{
+ const I& f;
+ const N& nbh;
+
+ // Auxiliary data.
+ util::hqueues<unsigned, V> hqueues;
+ value::set<V> vset;
+ util::array<int> dp;
+ unsigned n_nbhs;
+
+ mln_ch_value(I, bool) deja_vu;
+ value::value_array<V, bool> is_node_at_level;
+ value::value_array<V, P> node_at_level;
+ unsigned loc;
+ // \}
+ };
+
+ template <typename T, typename I, typename N>
+ struct flooder;
+
+ template <typename I, typename N>
+ struct flooder<tag::tree::max_t, I, N> :
+ flooder_base_< I, N, flooder<tag::tree::max_t, I, N> >
+ {
+ typedef mln_value(I) V;
+ typedef flooder_base_< I, N, flooder<tag::tree::max_t, I, N> > super_;
+
+ // Constructor.
+ flooder(const I& f_, const N& nbh_);
+
+ // HLevel comparaison.
+ bool hlevel_less_(unsigned h_idx1, unsigned h_idx2);
+
+ // Parent attachment function.
+ unsigned attach_parent_(unsigned h_idx);
+
+ public:
+ using super_::parent;
+ using super_::area;
+ using super_::location;
+
+ protected:
+ using super_::is_node_at_level;
+ using super_::node_at_level;
+ using super_::vset;
+ using super_::loc;
+ };
+
+ template <typename I, typename N>
+ struct flooder<tag::tree::min_t, I, N> :
+ flooder_base_< I, N, flooder<tag::tree::min_t, I, N> >
+ {
+ typedef mln_value(I) V;
+ typedef flooder_base_< I, N, flooder<tag::tree::min_t, I, N> > super_;
+
+ // Constructor.
+ flooder(const I& f_, const N& nbh_);
+
+ // HLevel comparaison.
+ bool hlevel_less_(unsigned h_idx1, unsigned h_idx2);
+
+ // Parent attachment function.
+ unsigned attach_parent_(unsigned h_idx);
+
+ public:
+ using super_::parent;
+ using super_::area;
+ using super_::location;
+
+ protected:
+ using super_::is_node_at_level;
+ using super_::node_at_level;
+ using super_::vset;
+ using super_::loc;
+ };
+
+ template <typename I, typename N, typename E>
+ inline
+ bool
+ flooder_base_<I, N, E>::hlevel_less(unsigned h_idx1, unsigned h_idx2)
+ {
+ E& obj = exact(*this);
+ return obj.hlevel_less_(h_idx1, h_idx2);
+ }
+
+ template <typename I, typename N, typename E>
+ inline
+ unsigned
+ flooder_base_<I, N, E>::attach_parent(unsigned h_idx)
+ {
+ E& obj = exact(*this);
+ return obj.attach_parent_(h_idx);
+ }
+
+ template <typename I, typename N>
+ inline
+ flooder<tag::tree::max_t, I, N>::flooder(const I& f_, const N& nbh_)
+ : flooder_base_<I, N, flooder<tag::tree::max_t, I, N> >(f_, nbh_)
+ {
+ }
+
+ template <typename I, typename N>
+ inline
+ flooder<tag::tree::min_t, I, N>::flooder(const I& f_, const N& nbh_)
+ : flooder_base_<I, N, flooder<tag::tree::min_t, I, N> >(f_, nbh_)
+ {
+ }
+
+ template <typename I, typename N>
+ inline
+ bool
+ flooder<tag::tree::max_t, I, N>::hlevel_less_(unsigned h_idx1, unsigned h_idx2)
+ {
+ return h_idx1 < h_idx2;
+ }
+
+ template <typename I, typename N>
+ inline
+ bool
+ flooder<tag::tree::min_t, I, N>::hlevel_less_(unsigned h_idx1, unsigned h_idx2)
+ {
+ return h_idx2 < h_idx1;
+ }
+
+ template <typename I, typename N>
+ inline
+ unsigned
+ flooder<tag::tree::max_t, I, N>::attach_parent_(unsigned h_idx)
+ {
+ unsigned c = h_idx;
+ while (c > 0 && !is_node_at_level[c])
+ --c;
+
+ unsigned x = node_at_level[h_idx];
+ if (is_node_at_level[c]) // || c > 0
+ {
+ unsigned p = node_at_level[c];
+ parent[x] = p;
+ area[p] += area[x] + 1;
+ }
+ else
+ parent[x] = x;
+
+ location[x] = loc++;
+ return c;
+ }
+
+ template <typename I, typename N>
+ inline
+ unsigned
+ flooder<tag::tree::min_t, I, N>::attach_parent_(unsigned h_idx)
+ {
+ unsigned nv = vset.nvalues() - 1;
+ unsigned c = h_idx;
+
+ while (c < nv && !is_node_at_level[c])
+ ++c;
+
+ unsigned x = node_at_level[h_idx];
+ if (is_node_at_level[c]) // || c < nv
+ {
+ unsigned p = node_at_level[c];
+ parent[x] = p;
+ area[p] += area[x] + 1;
+ }
+ else
+ parent[x] = x;
+
+ location[x] = loc++;
+ return c;
+ }
+
+
+ template <typename I, typename N, typename E>
+ flooder_base_<I, N, E>::flooder_base_(const I& f_, const N& nbh_)
+ : f (f_), nbh (nbh_), is_node_at_level(false)
+ {
+ // Prepare hierarchical queues and retrieve start point.
+ unsigned pmin;
+ mln_value(I) vmin;
+ {
+ util::array< unsigned > h(nvalues, 0);
+
+ pmin = f.index_of_point(f.domain().pmin());
+ vmin = f.element(pmin);
+
+ mln_fwd_pixter(const I) pxl(f);
+ for_all(pxl)
+ {
+ ++h[pxl.val()];
+ if (hlevel_less(pxl.val(), vmin))
+ {
+ vmin = pxl.val();
+ pmin = pxl.offset();
+ }
+ }
+
+ for (unsigned i = 0; i < nvalues; ++i)
+ hqueues[i].reserve(h[i]);
+ }
+
+ // Initialize aux data
+ {
+ dp = offsets_wrt(f, nbh);
+ n_nbhs = dp.nelements();
+ vset = value::set< mln_value(I) >::the();
+
+ extension::adjust(f, nbh);
+
+ initialize(deja_vu, f);
+ initialize(map, f);
+ data::fill(deja_vu, false);
+ extension::fill(deja_vu, true);
+
+ unsigned nsites = geom::nsites(f);
+ parent.resize(nsites);
+ location.resize(nsites);
+ area.resize(nsites, 0);
+
+ n_node = 0;
+ loc = 0;
+ }
+
+ // Start flooding
+ unsigned hmin = vset.index_of(vmin);
+ deja_vu.element(pmin) = true;
+ hqueues[hmin].push(pmin);
+ node_at_level[hmin] = n_node++;
+ is_node_at_level[hmin] = true;
+
+ flood(hmin);
+ }
+
+ template <typename I, typename N, typename E>
+ unsigned
+ flooder_base_<I, N, E>::flood(const unsigned h_idx)
+ {
+ mln_assertion(is_node_at_level[h_idx]);
+
+ while (!hqueues[h_idx].empty())
+ {
+ unsigned p = hqueues[h_idx].pop_front();
+ mln_assertion(vset.index_of(f.element(p)) == h_idx);
+
+ map.element(p) = node_at_level[h_idx];
+
+ // Process the neighbors
+ for (unsigned j = 0; j < n_nbhs; ++j)
+ {
+ unsigned n = p + dp[j];
+
+ if (!deja_vu.element(n))
+ {
+ unsigned n_idx = vset.index_of(f.element(n));
+ hqueues[n_idx].push(n);
+ deja_vu.element(n) = true;
+
+ if (!is_node_at_level[n_idx])
+ {
+ node_at_level[n_idx] = n_node++;
+ is_node_at_level[n_idx] = true;
+ }
+
+ while (hlevel_less(h_idx, n_idx))
+ n_idx = flood(n_idx);
+ }
+ }
+ }
+
+ is_node_at_level[h_idx] = false;
+ return attach_parent(h_idx);
+ }
+
+ template <typename T, typename I, typename N>
+ inline
+ util::ctree::ctree<I>
+ hqueue_fast(const tag::tree::tree_t<T>&, const Image<I>& f_, const
Neighborhood<N>& nbh_)
+ {
+ trace::entering("mln::morpho::tree::impl::hqueue_fast");
+ const I& f = exact(f_);
+ const N& nbh = exact(nbh_);
+
+ mln_precondition(f.is_valid());
+ mln_precondition(nbh.is_valid());
+
+ // Process
+ impl::flooder<T, I, N> args(f, nbh);
+ // \todo handles here discontinous domains: so multi-roots trees.
+
+ // Create tree and fill it.
+ util::ctree::ctree<I> tree;
+ {
+ tree.reserve(f, args.n_node);
+
+ mln_pixter(const I) pix(f);
+ for_all(pix)
+ {
+ int idx = args.map.element(pix.offset());
+ int loc = args.n_node - args.location[idx] - 1;
+ tree.data_->map_.element(pix.offset()) = loc;
+ tree.data_->values_[loc] = pix.val();
+ }
+
+ for (unsigned idx = 0; idx < args.n_node; ++idx)
+ {
+ int loc = args.n_node - args.location[idx] - 1;
+ tree.data_->parent_[loc] = args.n_node - args.location[args.parent[idx]] - 1;
+ tree.data_->length_[loc] = args.area[idx];
+ }
+ }
+
+ trace::exiting("mln::morpho::tree::impl::hqueue_fast");
+ return tree;
+ }
+
+ } // end of namespace mln::morpho::tree::impl
+
+# endif // ! MLN_INCLUDE_ONLY
+
+ } // end of namespace mln::morpho::tree
+
+ } // end of namespace mln::morpho
+
+} // end of namespace mln
+
+#endif // !MLN_MORPHO_TREE_IMPL_HQUEUE_FAST_HH
diff --git a/milena/sandbox/edwin/mln/morpho/tree/impl/union_find.hh
b/milena/mln/morpho/tree/impl/union_find.hh
similarity index 99%
copy from milena/sandbox/edwin/mln/morpho/tree/impl/union_find.hh
copy to milena/mln/morpho/tree/impl/union_find.hh
index f2aee82..8485727 100644
--- a/milena/sandbox/edwin/mln/morpho/tree/impl/union_find.hh
+++ b/milena/mln/morpho/tree/impl/union_find.hh
@@ -163,7 +163,9 @@ namespace mln
}
}
+
# endif // ! MLN_INCLUDE_ONLY
+
}
}
diff --git a/milena/mln/morpho/tree/impl/union_find_fast.hh
b/milena/mln/morpho/tree/impl/union_find_fast.hh
new file mode 100644
index 0000000..80a521d
--- /dev/null
+++ b/milena/mln/morpho/tree/impl/union_find_fast.hh
@@ -0,0 +1,396 @@
+// Copyright (C) 2008, 2009 EPITA Research and Development Laboratory (LRDE)
+//
+// This file is part of Olena.
+//
+// Olena is free software: you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation, version 2 of the License.
+//
+// Olena 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 Olena. If not, see <http://www.gnu.org/licenses/>.
+//
+// As a special exception, you may use this file as part of a free
+// software project 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_MORPHO_TREE_IMPL_UNION_FIND_FAST_HH
+# define MLN_MORPHO_TREE_IMPL_UNION_FIND_FAST_HH
+
+///
+///
+
+
+namespace mln
+{
+
+ namespace morpho
+ {
+
+ namespace tree
+ {
+
+ namespace impl
+ {
+
+ namespace generic
+ {
+
+ /// The fast version of union-find algorithm.
+ /// \pre The image \p f must be fastest
+ ///
+ /// \param tree_tag The type of tree to build (min or max-tree).
+ /// \param f Source image used to build the component tree.
+ /// \param nbh Neighborhood used to build the component tree.
+ ///
+ /// \return A component tree object.
+ ///
+ template <typename T, typename I, typename N>
+ util::ctree::ctree<I>
+ union_find_fast(const tag::tree::tree_t<T>& tree_tag,
+ const Image<I>& f,
+ const Neighborhood<N>& nbh);
+ }
+
+ }
+
+# ifndef MLN_INCLUDE_ONLY
+
+ namespace internal
+ {
+
+ template <typename I>
+ inline
+ void
+ sort_sites_set_radix(const tag::tree::max_t&, const I& f,
util::array<unsigned>& s, util::array<unsigned>& levels)
+ {
+ typedef mln_value(I) V;
+ static const value::set<V>& vset = value::set<V>::the();
+ static const int n = mln_card(V);
+
+ util::array<unsigned> h(n, 0);
+ s.resize(f.domain().nsites());
+ levels.resize(n + 1);
+
+ mln_fwd_pixter(const I) pxl(f);
+ for_all(pxl)
+ ++h[vset.index_of(pxl.val())];
+
+ for (int i = 1; i <= n; ++i)
+ {
+ levels[i] = levels[i - 1] + h[i - 1];
+ h[i - 1] = levels[i - 1];
+ }
+
+ // computing output data
+ for_all(pxl)
+ {
+ int i = vset.index_of(pxl.val());
+ s[h[i]++] = pxl.offset();
+ }
+ }
+
+ template <typename I>
+ static inline
+ void
+ sort_sites_set_radix(const tag::tree::min_t&, const I& f,
util::array<unsigned>& s, util::array<unsigned>& levels)
+ {
+ typedef mln_value(I) V;
+ static const value::set<V>& vset = value::set<V>::the();
+ static const int n = mln_card(V);
+
+ util::array<unsigned> h(n, 0);
+ s.resize(f.domain().nsites());
+ levels.resize(n + 1);
+
+ mln_fwd_pixter(const I) pxl(f);
+ for_all(pxl)
+ ++h[n - 1 - vset.index_of(pxl.val())];
+
+ for (int i = 1; i <= n; ++i)
+ {
+ levels[i] = levels[i - 1] + h[i - 1];
+ h[i - 1] = levels[i - 1];
+ }
+
+ // computing output data
+ for_all(pxl)
+ {
+ int i = vset.index_of(pxl.val());
+ s[h[n - 1 - i]++] = pxl.offset();
+ }
+ }
+
+ template <typename T, typename I>
+ struct sort_op_less_;
+
+ template <typename I>
+ struct sort_op_less_<tag::tree::max_t, I>
+ {
+ sort_op_less_ (const I& f_) : f(f_) {}
+
+ bool operator() (unsigned e1, unsigned e2)
+ {
+ return f.element(e1) < f.element(e2) || (f.element(e1) == f.element(e2)
&& e1 < e2);
+ }
+
+ private:
+ const I& f;
+ };
+
+ template <typename I>
+ struct sort_op_less_<tag::tree::min_t, I>
+ {
+ sort_op_less_ (const I& f_) : f(f_) {}
+
+ bool operator() (unsigned e1, unsigned e2)
+ {
+ return f.element(e2) < f.element(e1) || (f.element(e1) == f.element(e2)
&& e2 < e1);
+ }
+
+ private:
+ const I& f;
+ };
+
+ template <typename T, typename I>
+ inline
+ void
+ sort_sites_set_std(const T&, const I& f, util::array<unsigned>& s)
+ {
+ s.reserve(f.domain().nsites());
+
+ mln_pixter(const I) pix(f);
+ for_all(pix)
+ s.append(pix.offset());
+
+ std::vector<unsigned>& v = s.hook_std_vector_();
+ std::sort(v.begin(), v.end(), sort_op_less_<T, I>(f));
+ }
+
+ template <typename T, typename I>
+ static inline
+ void
+ sort_sites_set_dispatch(const mln::trait::value::quant::low&, const T& tree_,
const I& f, util::array<unsigned>& s, util::array<unsigned>&
levels)
+ {
+ trace::entering("morpho::tree::internal::sort_sites_set_radix");
+ sort_sites_set_radix(tree_, f, s, levels);
+ trace::exiting("morpho::tree::internal::sort_sites_set_radix");
+ }
+
+ template <typename T, typename I>
+ static inline
+ void
+ sort_sites_set_dispatch(const mln::trait::value::quant::any&, const T& tree_,
const I& f, util::array<unsigned>& s, util::array<unsigned>&
levels)
+ {
+ (void) levels;
+ trace::entering("morpho::tree::internal::sort_sites_set_std");
+ sort_sites_set_std(tree_, f, s);
+ trace::exiting("morpho::tree::internal::sort_sites_set_std");
+ }
+
+
+ template <typename T, typename I>
+ static inline
+ void
+ sort_sites_set(const T& tree_, const I& f, util::array<unsigned>& s,
util::array<unsigned>& levels)
+ {
+ sort_sites_set_dispatch(mln_trait_value_quant(mln_value(I)) (), tree_, f, s, levels);
+ }
+
+ template <typename T>
+ static inline
+ unsigned
+ zfind_root(T& zpar, unsigned x)
+ {
+ mlc_equal(mln_value(T), unsigned)::check();
+ if (zpar.element(x) == x)
+ return x;
+ else
+ return zpar.element(x) = zfind_root(zpar, zpar.element(x));
+ }
+
+
+ } // end of namespace mln::morpho::tree::internal
+
+ namespace impl
+ {
+
+ namespace generic
+ {
+
+ template <typename I, typename F>
+ static inline
+ void
+ union_find_fast_process2_(const I& f, const util::array<int>& dp,
+ F& parent, F& area, F& zpar,
+ unsigned& nnodes, unsigned p)
+ {
+ // Make set.
+ const unsigned n_nbhs = dp.nelements();
+
+ parent.element(p) = p;
+ zpar.element(p) = p;
+
+ for (unsigned j = 0; j < n_nbhs; ++j)
+ {
+ unsigned n = p + dp[j];
+
+ if (zpar.element(n) == 0) // not deja-vu
+ continue;
+
+ unsigned r = internal::zfind_root(zpar, n);
+ if (r != p)
+ {
+ parent.element(r) = p;
+ zpar.element(r) = p;
+ area.element(p) += area.element(r);
+ if (f.element(r) != f.element(p))
+ ++area.element(p);
+ else
+ --nnodes;
+ }
+ }
+ }
+
+
+ template <typename I, typename F>
+ static inline
+ unsigned
+ union_find_fast_process(const mln::trait::value::quant::low&, const I& f,
const util::array<int>& dp,
+ F& parent, F& area, F& zpar,
+ const util::array<unsigned>& s, const util::array<unsigned>&
levels)
+ {
+ trace::entering("morpho::tree::impl::union_find_fast_process_low");
+ static const unsigned nvalues = mln_card(mln_value(I));
+
+ unsigned nnodes = f.domain().nsites();
+
+ for (int v = nvalues - 1; v >= 0; --v) // Reverse
+ {
+ for (int i = levels[v + 1] - 1; i >= (int)levels[v]; --i) // Reverse
+ union_find_fast_process2_(f, dp, parent, area, zpar, nnodes, s[i]);
+
+ // Fast root compression
+ for (unsigned i = levels[v]; i < levels[v + 1]; ++i) // Direct
+ {
+ unsigned p = s[i];
+ zpar.element(p) = zpar.element(zpar.element(p));
+ }
+ }
+
+ trace::exiting("morpho::tree::impl::union_find_fast_process_low");
+ return nnodes;
+ }
+
+ template <typename I, typename F>
+ static inline
+ unsigned
+ union_find_fast_process(const trait::value::quant::any&, const I& f, const
util::array<int>& dp,
+ F& parent, F& area, F& zpar,
+ const util::array<unsigned>& s, const util::array<unsigned>&)
+ {
+ trace::entering("morpho::tree::impl::union_find_fast_process_any");
+
+ unsigned nnodes = f.domain().nsites();
+ for (int i = s.size() - 1; i >= 0; --i) // Reverse
+ union_find_fast_process2_(f, dp, parent, area, zpar, nnodes, s[i]);
+
+ trace::exiting("morpho::tree::impl::union_find_fast_process_any");
+ return nnodes;
+ }
+
+
+ template <typename T, typename I, typename N>
+ util::ctree::ctree<I>
+ union_find_fast(const tag::tree::tree_t<T>&,
+ const Image<I>& f_,
+ const Neighborhood<N>& nbh_)
+ {
+ trace::entering("morpho::tree::impl::generic::union_find_fast");
+
+ typedef p_array<mln_psite(I)> S;
+ typedef mln_value(I) V;
+
+ const I& f = exact(f_);
+ const N& nbh = exact(nbh_);
+ util::array< unsigned > s;
+ util::array< unsigned > levels;
+ internal::sort_sites_set(T (), f, s, levels);
+
+ util::array<int> dp = offsets_wrt(f, nbh);
+
+ // Auxiliary data.
+ mln_ch_value(I, unsigned) parent;
+ mln_ch_value(I, unsigned) area;
+ mln_ch_value(I, unsigned) zpar;
+
+ initialize(parent, f);
+ initialize(area, f);
+ initialize(zpar, f);
+
+ // Initialization.
+ data::fill(zpar, 0);
+ data::fill(area, 0);
+
+ unsigned nnodes =
+ union_find_fast_process(mln_trait_value_quant(V) (), f, dp, parent, area, zpar, s,
levels);
+
+ util::ctree::ctree<I> tree;
+ tree.reserve(f, nnodes);
+
+ unsigned root_offset = 0;
+ for (unsigned i = 0; i < s.size(); ++i) // Forward
+ {
+ unsigned p = s[i];
+ unsigned q = parent.element(p);
+
+ if (f.element(parent.element(q)) == f.element(q)) // Canonization
+ q = (parent.element(p) = parent.element(q));
+
+ if (f.element(p) == f.element(q) && p != q) // Not a node.
+ {
+ mln_assertion(q == parent.element(p));
+ tree.data_->map_.element(p) =
+ tree.data_->map_.element(q);
+ }
+ else
+ {
+ unsigned& offset = (p == q) ? root_offset : area.element(q);
+
+ // Insert Node.
+ mln_assertion(offset < nnodes);
+ tree.data_->map_.element(p) = offset;
+ tree.data_->parent_[offset] = tree.data_->map_.element(q);
+ tree.data_->values_[offset] = f.element(p);
+ tree.data_->length_[offset] = area.element(p);
+ area.element(p) = offset + 1;
+ offset += tree.data_->length_[offset] + 1;
+ }
+ }
+
+ trace::exiting("morpho::tree::impl::generic::union_find_fast");
+ return tree;
+ }
+
+ } // end of namespace mln::morpho::tree::impl::generic
+
+ } // end of namespace mln::morpho::tree::impl
+
+# endif // ! MLN_INCLUDE_ONLY
+
+ } // end of namespace mln::morpho::tree
+
+ } // end of namespace mln::morpho
+
+} // end of namespace mln
+
+#endif // !MLN_MORPHO_TREE_IMPL_UNION_FIND_FAST_HH
diff --git a/milena/mln/morpho/tree/leaf_last.hh b/milena/mln/morpho/tree/leaf_last.hh
new file mode 100644
index 0000000..2f283d5
--- /dev/null
+++ b/milena/mln/morpho/tree/leaf_last.hh
@@ -0,0 +1,111 @@
+// Copyright (C) 2008, 2009 EPITA Research and Development Laboratory (LRDE)
+//
+// This file is part of Olena.
+//
+// Olena is free software: you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation, version 2 of the License.
+//
+// Olena 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 Olena. If not, see <http://www.gnu.org/licenses/>.
+//
+// As a special exception, you may use this file as part of a free
+// software project 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_MORPHO_TREE_LEAF_LAST_HH
+# define MLN_MORPHO_TREE_LEAF_LAST_HH
+
+# include <mln/accu/stat/max.hh>
+# include <mln/util/ctree/ctree.hh>
+# include <mln/morpho/tree/propagate_node.hh>
+# include <mln/convert/to_p_array.hh>
+
+namespace mln
+{
+
+ namespace morpho
+ {
+
+ namespace tree
+ {
+
+ template <typename T, typename V>
+ util::array<typename T::node_t>
+ leaf_last(const attribute_image<T, V>& ima);
+
+# ifndef MLN_INCLUDE_ONLY
+
+ namespace internal
+ {
+
+ template <typename T, typename V>
+ struct less_
+ {
+ typedef typename T::node_t node_t;
+
+ less_(const attribute_image<T, V>& img) :
+ f_ (img)
+ {
+ }
+
+ bool operator() (const node_t& lhs, const node_t& rhs)
+ {
+ return f_(lhs) > f_(rhs);
+ }
+
+ private:
+ const attribute_image<T, V>& f_;
+ };
+ }
+
+ template <typename T, typename V>
+ util::array<typename T::node_t>
+ leaf_last(const attribute_image<T, V>& ima)
+ {
+ typedef attribute_image<T, V> A;
+ typedef typename T::node_t node_t;
+
+ p_array<node_t> sorted_sites = convert::to_p_array(ima);
+ std::vector<node_t>& hook = sorted_sites.hook_std_vector_();
+ std::sort(hook.begin(), hook.end(), internal::less_<T, V> (ima));
+
+ mln_ch_value(A, char) deja_vu;
+ initialize(deja_vu, ima);
+ data::fill(deja_vu, 0);
+
+ util::array<node_t> result;
+
+ mln_piter(p_array<node_t>) n(sorted_sites);
+ for_all(n)
+ {
+ if (deja_vu(n))
+ continue;
+ result.append(n);
+ deja_vu(n) = true; // useless
+ propagate_node_to_descendants<T, char>(deja_vu, n, 1);
+ propagate_node_to_ancestors<T, char>(deja_vu, n, 1);
+ }
+
+ return result;
+ }
+
+# endif // ! MLN_INCLUDE_ONLY
+
+ } // end of namespace mln::morpho::tree
+
+ } // end of namespace mln::morpho
+
+} // end of namespace mln
+
+#endif // !MLN_MORPHO_TREE_LEAF_LAST_HH
diff --git a/milena/mln/morpho/tree/propagate_node.hh
b/milena/mln/morpho/tree/propagate_node.hh
index 7778905..76f2410 100644
--- a/milena/mln/morpho/tree/propagate_node.hh
+++ b/milena/mln/morpho/tree/propagate_node.hh
@@ -26,14 +26,27 @@
#ifndef MLN_MORPHO_TREE_PROPAGATE_NODE_HH
# define MLN_MORPHO_TREE_PROPAGATE_NODE_HH
-# include <mln/core/concept/image.hh>
-# include <mln/core/macros.hh>
-# include <mln/morpho/tree/data.hh>
-
/// \file
///
/// Functions to propagate node in the tree.
+///
+/// \todo: The new implementation permits: + to propagate toward
+/// subcomponents very fast (data::fill)\ + to propagate toward
+/// supernodes as fast as the previous component\ + the attribute
+/// image is still valid without the use of propagate_representative
+/// that does not make sense any more.
+///
+/// We are able in both cases to do something like:
+/// + data::fill(attr_img | asc(n), v)
+/// + data::fill(attr_img | desc(n), v)
+///
+/// However the subimage morpher is not specialized for fast image and
+/// does not take benefits in the fact that:
+/// + desc(n) is a p_run (so can be memseté)
+/// + attr_img can accessed by indexed (element() method for fast-image)
+# include <mln/core/image/attribute_image.hh>
+# include <algorithm>
namespace mln
{
@@ -44,166 +57,52 @@ namespace mln
namespace tree
{
- /*!
- ** Propagate a value \p v from a node \p n to its descendants.
- **
- ** \param[in] n Node to propagate.
- ** \param[in] t Component tree used for propagation.
- ** \param[in] a_ Attribute image where values are propagated.
- ** \param[in] v Value to propagate.
- ** \param[out] nb_leaves Optional. Store the number of leaves in
- ** the component.
- */
- template <typename T, typename A>
- void
- propagate_node_to_descendants(mln_psite(A) n,
- const T& t,
- Image<A>& a_,
- const mln_value(A)& v,
- unsigned* nb_leaves = 0);
-
- /*!
- ** Propagate the node's value to its descendants.
- **
- ** \param[in] n Node to propagate.
- ** \param[in] t Component tree used for propagation.
- ** \param[in] a_ Attribute image where values are propagated.
- ** \param[out] nb_leaves Optional. Store the number of leaves in
- ** the component.
- */
- template <typename T, typename A>
- inline
- void
- propagate_node_to_descendants(mln_psite(A)& n,
- const T& t,
- Image<A>& a_,
- unsigned* nb_leaves = 0);
-
-
- /*!
- ** Propagate a value \p v from a node \p n to its ancestors.
- **
- ** \param[in] n Node to propagate.
- ** \param[in] t Component tree used for propagation.
- ** \param[in] a_ Attribute image where values are propagated.
- ** \param[in] v Value to propagate.
- */
- template <typename T, typename A>
- void
- propagate_node_to_ancestors(mln_psite(A) n,
- const T& t,
- Image<A>& a_,
- const mln_value(A)& v);
-
- /*!
- ** Propagate the node's value to its ancestors.
- **
- ** \param[in] n Node to propagate.
- ** \param[in] t Component tree used for propagation.
- ** \param[in,out] a_ Attribute image where values are propagated.
- */
- template <typename T, typename A>
- inline
- void
- propagate_node_to_ancestors(mln_psite(A) n,
- const T& t,
- Image<A>& a_);
-
-
-# ifndef MLN_INCLUDE_ONLY
-
- /* Descendants propagation */
-
- template <typename T, typename A>
+ template <typename T, typename V>
inline
- void
- propagate_node_to_descendants(mln_psite(A) n,
- const T& t,
- Image<A>& a_,
- const mln_value(A)& v,
- unsigned* nb_leaves = 0)
+ unsigned
+ propagate_node_to_descendants(attribute_image<T, V>& a,
+ const typename T::node_t& n,
+ const V& value)
{
- A& a = exact(a_);
+ typedef typename T::nodes_t desc_t;
mln_precondition(a.is_valid());
- mln_precondition(a.domain() == t.f().domain());
- mln_precondition(a.domain().has(n));
-
-
- if (!t.is_a_node(n)) // Get the representant.
- n = t.parent(n);
- mln_assertion(t.is_a_node(n));
-
- typename T::depth1st_piter pp(t, n);
-
- pp.start(); // We don't set n to v.
+ mln_precondition(a.has(n));
- if (nb_leaves)
- *nb_leaves += t.is_a_leaf(pp);
+ // (n € desc(n)) but we don't set its value.
+ unsigned i = a.tree().desc(n).nsites();
- for (pp.next(); pp.is_valid(); pp.next())
+ if (i > 1)
{
- a(pp) = v;
- if (nb_leaves && t.is_a_leaf(pp))
- ++(*nb_leaves);
+ mln_assertion(a.tree().has_index(n.index() + i));
+ V* v = a.buffer() + n.index();
+ std::fill(v + 1, v + i, value);
}
+ return i - 1;
}
-
- template <typename T, typename A>
+ template <typename T, typename V>
inline
- void
- propagate_node_to_descendants(mln_psite(A) n,
- const T& t,
- Image<A>& a_,
- unsigned* nb_leaves = 0)
-
- {
- A& a = exact(a_);
- propagate_node_to_descendants(n, t, a, a(n), nb_leaves);
- }
-
-
- /* Ancestors propagation */
-
- template <typename T, typename A>
- void
- propagate_node_to_ancestors(mln_psite(A) n,
- const T& t,
- Image<A>& a_,
- const mln_value(A)& v)
+ unsigned
+ propagate_node_to_ancestors(attribute_image<T, V>& a,
+ typename T::node_t n,
+ const V& v)
{
- A& a = exact(a_);
mln_precondition(a.is_valid());
- mln_precondition(a.domain() == t.f().domain());
- mln_precondition(a.domain().has(n));
+ mln_precondition(a.has(n));
- if (!t.is_a_node(n)) // Get the representant.
- n = t.parent(n);
- mln_assertion(t.is_a_node(n));
-
- if (t.is_root(n))
- return;
+ if (a.tree().is_a_root(n))
+ return 0;
+ unsigned i = 0;
do {
- n = t.parent(n);
+ n = a.tree().parent(n);
a(n) = v;
- } while (!t.is_root(n));
-
- }
+ ++i;
+ } while (!a.tree().is_a_root(n));
- template <typename T, typename A>
- inline
- void
- propagate_node_to_ancestors(mln_psite(A) n,
- const T& t,
- Image<A>& a_)
- {
- A& a = exact(a_);
- propagate_node_to_ancestors(n, t, a, a(n));
+ return i;
}
-# endif // ! MLN_INCLUDE_ONLY
-
} // end of namespace mln::morpho::tree
} // end of namespace mln::morpho
diff --git a/milena/mln/tag/skeleton.hh b/milena/mln/tag/skeleton.hh
index f446317..bca9b4f 100644
--- a/milena/mln/tag/skeleton.hh
+++ b/milena/mln/tag/skeleton.hh
@@ -44,6 +44,7 @@ namespace mln
template <typename F> struct function_ { typedef F param; };
template <typename G> struct graph_ { typedef G param; };
template <typename I> struct image_ { typedef I param; };
+ template <typename T> struct tree_ { typedef T param; };
template <typename N> struct neighb_ { typedef N param; };
template <typename P> struct psite_ { typedef P param; };
template <typename S> struct domain_ { typedef S param; };
diff --git a/milena/mln/util/hqueues.hh b/milena/mln/util/hqueues.hh
index 151c71c..35c7a50 100644
--- a/milena/mln/util/hqueues.hh
+++ b/milena/mln/util/hqueues.hh
@@ -55,6 +55,7 @@ namespace mln
nvalues = mln_card(T)
};
+ hqueues();
hqueues(const histo::array<T>& h);
const p_queue_fast<P>& operator[](unsigned i) const;
@@ -66,38 +67,29 @@ namespace mln
const mln::value::set<T>& vset() const;
protected:
- void pre_allocate_(unsigned i);
-
- const histo::array<T>& h_;
const mln::value::set<T>& s_;
- std::vector<bool> allocated_;
std::vector< p_queue_fast<P> >queues_;
};
# ifndef MLN_INCLUDE_ONLY
-
template <typename P, typename T>
inline
- hqueues<P,T>::hqueues(const histo::array<T>& h)
- : h_ (h),
- s_ (mln::value::set<T>::the()),
- allocated_ (nvalues, false),
- queues_ (nvalues)
+ hqueues<P,T>::hqueues()
+ : s_ (mln::value::set<T>::the())
{
+ queues_.resize(nvalues);
}
+
template <typename P, typename T>
inline
- void
- hqueues<P,T>::pre_allocate_(unsigned i)
+ hqueues<P,T>::hqueues(const histo::array<T>& h)
+ : s_ (mln::value::set<T>::the())
{
- mln_precondition(i < nvalues);
- if (!allocated_[i])
- {
- queues_[i].reserve(h_[i]);
- allocated_[i] = true;
- }
+ queues_.resize(nvalues);
+ for (unsigned i = 0; i < nvalues; ++i)
+ queues_[i].reserve(h[i]);
}
@@ -107,7 +99,6 @@ namespace mln
hqueues<P,T>::operator[](unsigned i) const
{
mln_precondition(i < nvalues);
- pre_allocate_(i);
return queues_[i];
}
@@ -117,7 +108,6 @@ namespace mln
hqueues<P,T>::operator[](unsigned i)
{
mln_precondition(i < nvalues);
- pre_allocate_(i);
return queues_[i];
}
@@ -127,7 +117,6 @@ namespace mln
hqueues<P,T>::operator()(const T& v) const
{
unsigned i = s_.index_of(v);
- pre_allocate_(i);
return queues_[i];
}
@@ -137,7 +126,6 @@ namespace mln
hqueues<P,T>::operator()(const T& v)
{
unsigned i = s_.index_of(v);
- pre_allocate_(i);
return queues_[i];
}
--
1.5.6.5