URL:
https://svn.lrde.epita.fr/svn/oln/trunk/milena
ChangeLog:
2009-09-25 Edwin Carlinet <carlinet(a)lrde.epita.fr>
Add fast version of dual input max tree computation and fix.
* morpho/tree/all.hh: Update.
* morpho/tree/compute_parent_dual_input.hh: Remove.
* morpho/tree/data.hh: Fix constructors.
* morpho/tree/dual_input_tree.hh: Add dispatches for
generic / low quantized algorithms.
* morpho/tree/impl/dual_hqueue.hh: New.
* morpho/tree/impl/dual_union_find.hh: New.
* morpho/tree/impl: New.
---
all.hh | 1
data.hh | 105 ++++--------
dual_input_tree.hh | 75 +++++++-
impl/dual_hqueue.hh | 408 ++++++++++++++++++++++++++++++++++++++++++++++++
impl/dual_union_find.hh | 361 ++++++++++++++++++++++++++++++++++++++++++
5 files changed, 874 insertions(+), 76 deletions(-)
Index: trunk/milena/mln/morpho/tree/compute_parent_dual_input.hh (deleted)
===================================================================
Index: trunk/milena/mln/morpho/tree/dual_input_tree.hh
===================================================================
--- trunk/milena/mln/morpho/tree/dual_input_tree.hh (revision 4553)
+++ trunk/milena/mln/morpho/tree/dual_input_tree.hh (revision 4554)
@@ -25,14 +25,16 @@
/// \file
///
-/// Compute a canonized (parenthood) component tree from a dual input.
-
+/// 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/morpho/tree/impl/dual_hqueue.hh>
namespace mln
{
@@ -43,44 +45,95 @@
namespace tree
{
- template <typename I, typename M, typename N>
+ /// Compute the dual input max tree using mask-based connectivity.
+ ///
+ /// \param[in] f The original image.
+ /// \param[in] m The connectivity mask.
+ /// \param[in] nbh The neighborhood of the mask.
+ ///
+ /// \return The computed tree.
+ ///
+ template <typename I, typename N>
inline
- morpho::tree::data< I, p_array<mln_psite(I)> >
+ data< I, p_array<mln_psite(I)> >
dual_input_max_tree(const Image<I>& f,
- const Image<M>& m,
+ const Image<I>& m,
const Neighborhood<N>& nbh);
# ifndef MLN_INCLUDE_ONLY
- template <typename I, typename M, typename N>
+ 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)> >
dual_input_max_tree(const Image<I>& f_,
- const Image<M>& m_,
+ const Image<I>& m_,
const Neighborhood<N>& nbh_)
{
trace::entering("morpho::tree::dual_input_max_tree");
const I& f = exact(f_);
- const M& m = exact(m_);
+ const I& m = exact(m_);
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;
- S s_f = mln::data::sort_psites_increasing(f);
- S s_m = mln::data::sort_psites_increasing(m);
- tree_t tree(f, m, s_f, s_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");
return tree;
}
+
+
+
+
# endif // ! MLN_INCLUDE_ONLY
} // end of namespace mln::morpho::tree
Index: trunk/milena/mln/morpho/tree/impl/dual_hqueue.hh
===================================================================
--- trunk/milena/mln/morpho/tree/impl/dual_hqueue.hh (revision 0)
+++ trunk/milena/mln/morpho/tree/impl/dual_hqueue.hh (revision 4554)
@@ -0,0 +1,408 @@
+// 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_COMPUTE_PARENT_DUAL_HQUEUE_HH
+# define MLN_MORPHO_TREE_IMPL_COMPUTE_PARENT_DUAL_HQUEUE_HH
+
+///
+/// \brief The dual input tree algorithm specialized for low quantized image.
+///
+/// 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/data/fill.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
+{
+
+ namespace morpho
+ {
+
+ namespace tree
+ {
+
+ namespace impl
+ {
+
+ /// Compute a tree using hqueues.
+ ///
+ /// \param f The original image.
+ /// \param m The connectivity mask.
+ /// \param nbh The neighborhood of the mask.
+ ///
+ /// \return The tree structure.
+ ///
+ 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>& nbh);
+
+ } // end of namespace mln::morpho::tree::impl
+
+
+# ifndef MLN_INCLUDE_ONLY
+
+ namespace internal
+ {
+
+ template <typename I, typename N, class E>
+ struct shared_flood_args
+ {
+ typedef mln_psite(I) P;
+ typedef mln_value(I) V;
+ typedef p_array<P> S;
+
+ 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.
+ 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);
+ }
+ };
+
+ 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)
+ {
+ 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];
+ }
+
+ // Merge histograms.
+ for (unsigned i = 0; i < hm.nvalues(); ++i)
+ hm[i] += hf[i];
+
+ // Retrieve pmin.
+ mln_piter(I) p(m.domain());
+ for (p.start(); m(p) != hmin; p.next())
+ ;
+ mln_assertion(p.is_valid());
+ pmin = p;
+
+ return hm;
+ }
+
+ // 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
+ {
+ extend(const mln_psite(I)::delta& dp)
+ : dp_ (dp)
+ {
+ }
+
+ mln_psite(I) operator() (const mln_psite(I)& p) const
+ {
+ return p + dp_;
+ }
+
+ private:
+ const mln_psite(I)::delta dp_;
+ };
+
+ } // end of namespace mln::morpho::tree::internal
+
+ namespace impl
+ {
+
+ template <typename I, typename N, typename E>
+ unsigned
+ flood(internal::shared_flood_args<I, N, E>& args, const unsigned h_idx)
+ {
+ mln_assertion(args.is_node_at_level[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;
+ }
+ }
+ }
+
+ 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];
+ }
+
+
+ // 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);
+ }
+ }
+
+ // Retrieve dad.
+ args.is_node_at_level[h_idx] = false;
+ unsigned c = h_idx;
+ while (c > 0 && !args.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;
+
+ 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");
+
+ const I& f = exact(f_);
+ const I& m = exact(m_);
+ const N& nbh = exact(neibh_);
+
+ typedef mln_psite(I) P;
+ typedef p_array<mln_psite(I)> S;
+
+ util::timer tm;
+ tm.start();
+
+ // 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();
+
+ // Extend the domain.
+ dp[0] = d.pmax()[0] - d.pmin()[0] + 1;
+ d.pmax() += dp;
+ d_ext.pmin() += dp;
+ d_ext.pmax() += dp;
+
+ // 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
+ {
+ if (args.is_node_at_level[i])
+ {
+ parent(args.node_at_level[r]) = args.node_at_level[i];
+ r = 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);
+
+ p_array<mln_psite(I)> s_f = mln::data::sort_psites_increasing(f);
+ mln_fwd_piter(S) p(s_f); // Forward.
+ for_all(p)
+ {
+ P x = p;
+ P q = parent(p);
+
+ // 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)))
+ {
+ s.append(q);
+ deja_vu(q) = true;
+ x = q;
+ q = parent(q);
+ }
+
+ if (d_ext.has(q) && fext(q) == fext(parent(q)) && q != parent(q))
+ {
+ q = (parent(x) = parent(q));
+ mln_assertion(f.domain().has(q));
+ }
+
+ if (fext(q) == fext(parent(q)))
+ parent(x) = parent(q);
+
+ s.append(p);
+
+ mln_assertion((q = parent(p)) == parent(q) || fext(q) != fext(parent(q)));
+ }
+
+ }
+
+ std::cout << "Construction de l'arbre en " << tm <<
" s." << std::endl;
+
+ data<I, S> tree(fext, parent, s);
+
+ trace::exiting("mln::morpho::tree::impl::dual_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_COMPUTE_PARENT_DUAL_HQUEUE_HH
+
+
+
Index: trunk/milena/mln/morpho/tree/impl/dual_union_find.hh
===================================================================
--- trunk/milena/mln/morpho/tree/impl/dual_union_find.hh (revision 0)
+++ trunk/milena/mln/morpho/tree/impl/dual_union_find.hh (revision 4554)
@@ -0,0 +1,361 @@
+// 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_IMLP_DUAL_UNION_FIND_HH
+# define MLN_MORPHO_TREE_IMLP_DUAL_UNION_FIND_HH
+
+///
+/// \brief The generic dual input tree algorithm for high quantized image.
+///
+/// This implementation is based on tarjan's union method, so that
+/// image quantization does not impact on the computation time.
+///
+/// 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.
+
+# include <mln/data/fill.hh>
+
+# include <mln/geom/nsites.hh>
+# include <mln/geom/translate.hh>
+
+# include <mln/morpho/tree/data.hh>
+
+# include <mln/util/timer.hh>
+
+namespace mln
+{
+
+ namespace morpho
+ {
+
+ namespace tree
+ {
+
+ namespace impl
+ {
+
+ namespace generic
+ {
+
+ /// Compute a tree using union-find method.
+ ///
+ /// \param f The original image.
+ /// \param m The connectivity mask.
+ /// \param s_f The sorted site set of \p f
+ /// \param s_m The sorted site set of \p m.
+ /// \param nbh The neighborhood of the mask.
+ ///
+ /// \return The tree structure.
+ ///
+ template <typename I, typename S, typename N>
+ data< I, p_array<mln_psite(I)> >
+ dual_union_find(const Image<I>& f,
+ const Image<I>& m,
+ const Site_Set<S>& s_f,
+ const Site_Set<S>& s_m,
+ const Neighborhood<N>& nbh);
+
+ } // end of namespace mln::morpho::tree::impl::generic
+
+ } // end of namespace mln::morpho::tree::impl
+
+# ifndef MLN_INCLUDE_ONLY
+
+ namespace internal
+ {
+ // For benchmark purpose. More than 50% of the time is spent
+ // in find_root function.
+ static util::timer t_prop;
+
+
+ template <typename I>
+ inline
+ mln_psite(I) find_root(I& zpar,
+ const mln_psite(I)& p)
+ {
+ if (zpar(p) == p)
+ return p;
+
+ t_prop.resume();
+ mln_psite(I) x = zpar(p);
+ while (zpar(x) != x)
+ x = zpar(x);
+
+ mln_psite(I) tmp;
+ for (mln_psite(I) y = p; y != x; y = tmp)
+ {
+ tmp = zpar(y);
+ zpar(y) = x;
+ }
+ t_prop.stop();
+
+ return x;
+ }
+
+ template <typename I>
+ inline
+ void
+ update_m_parent(const I& f,
+ mln_ch_value(I, mln_psite(I))& parent,
+ mln_ch_value(I, bool)& deja_vu,
+ p_array< mln_psite(I) >& sset,
+ const mln_domain(I)& d_ext,
+ const mln_psite(I)& p)
+ {
+ typedef mln_psite(I) P;
+
+ P q = parent(p);
+ P x = parent(q);
+
+ mln_assertion(d_ext.has(q));
+
+ while (d_ext.has(x) && f(q) == f(x) && q != x)
+ {
+ q = x;
+ x = parent(q);
+ }
+
+ if (!d_ext.has(x))
+ {
+ if (f(x) == f(parent(x)))
+ x = (parent(q) = parent(x));
+ if (f(q) != f(x))
+ {
+ x = q;
+ if (!deja_vu(q))
+ {
+ deja_vu(q) = true;
+ sset.append(q);
+ }
+ }
+
+ }
+ else
+ {
+ if (x != q)
+ {
+ update_m_parent(f, parent, deja_vu, sset, d_ext, q);
+ x = q;
+ }
+ if (!deja_vu(q))
+ {
+ deja_vu(q) = true;
+ sset.append(q);
+ }
+ }
+
+ for (P i = p, tmp = parent(i); i != q; i = tmp, tmp = parent(i))
+ parent(i) = x;
+ }
+
+ } // end of namespace mln::morpho::tree::internal
+
+ namespace impl
+ {
+
+ namespace generic
+ {
+
+
+ template <typename I, typename S, typename N>
+ data< I, p_array<mln_psite(I)> >
+ dual_union_find(const Image<I>& f_,
+ const Image<I>& m_,
+ const Site_Set<S>& s_f_,
+ const Site_Set<S>& s_m_,
+ const Neighborhood<N>& nbh_)
+ {
+ trace::entering("morpho::tree::impl::generic::dual_union_find");
+
+ util::timer tm;
+ tm.start();
+ internal::t_prop.reset();
+
+ typedef mln_psite(I) P;
+ typedef unsigned L;
+
+ const I& f = exact(f_);
+ const I& m = exact(m_);
+ const S& s_f = exact(s_f_);
+ const S& s_m = exact(s_m_);
+ const N& nbh = exact(nbh_);
+
+ // Aux data.
+ mln_psite(I)::delta dp(literal::zero);
+ mln_domain(I) d_f = f.domain();
+ mln_domain(I) d_ext = f.domain(); // translate dp
+ mln_domain(I) d = f.domain();
+
+ // Extend the domain.
+ dp[0] = d.pmax()[0] - d.pmin()[0] + 1;
+ d.pmax() += dp;
+ d_ext.pmin() += dp;
+ d_ext.pmax() += dp;
+
+ // 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
+ {
+ // Aux data.
+ mln_ch_value(I, bool) deja_vu;
+ mln_ch_value(I, P) zpar;
+
+ initialize(deja_vu, fext);
+ initialize(zpar, fext);
+ mln::data::fill(deja_vu, false);
+
+ mln_bkd_piter(S) p_f(s_f); // Backward.
+ mln_bkd_piter(S) p_m(s_m); // Backward.
+ p_f.start();
+ p_m.start();
+
+ // Main loop.
+ while (p_m.is_valid() || p_f.is_valid())
+ {
+ mln_bkd_piter(S)& it = (!p_f.is_valid() || (p_m.is_valid() && f(p_f)
<= m(p_m))) ? p_m : p_f;
+
+ P p = it;
+ P ext = p + dp;
+
+ // std::cout << "-------------------" << std::endl;
+ // std::cout << "Take " << p << " of value "
<< (&it == &p_m ? m(p) : f(p))
+ // << " from " << (&it == &p_m ? "mask"
: "f") << std::endl;
+ // debug::println("Parent: ", parent);
+ // debug::println("Zpar: ", zpar);
+
+ mln_assertion(!(deja_vu(p) && deja_vu(ext)));
+ if (deja_vu(ext)) // Seen by mask before f.
+ {
+ mln_assertion(m(p) >= f(p));
+ // Make set.
+ parent(p) = p;
+ zpar(p) = p;
+
+ P r = internal::find_root(zpar, ext);
+ zpar(r) = p;
+ parent(r) = p;
+
+ deja_vu(p) = true;
+ }
+ else if (deja_vu(p)) // Seen by f before mask.
+ {
+ mln_assertion(f(p) > m(p));
+ parent(p) = ext;
+ zpar(p) = ext;
+ parent(ext) = ext;
+ zpar(ext) = ext;
+
+ mln_niter(N) n(nbh, ext);
+ for_all(n)
+ if (d_ext.has(n) && deja_vu(n))
+ {
+ P r = internal::find_root(zpar, n);
+ //std::cout << "Root: " << r << std::endl;
+ if (r != ext)
+ {
+ parent(r) = ext;
+ zpar(r) = ext;
+ }
+ }
+ deja_vu(ext) = true;
+ }
+ else if (f(p) <= m(p)) // First time p encountered.
+ {
+ zpar(ext) = ext;
+ mln_niter(N) n(nbh, ext);
+ for_all(n)
+ if (d_ext.has(n) && deja_vu(n))
+ {
+ P r = internal::find_root(zpar, n);
+ if (r != ext)
+ {
+ zpar(r) = ext;
+ parent(r) = ext;
+ }
+ }
+ deja_vu(ext) = true;
+ }
+ else
+ {
+ deja_vu(p) = true;
+ }
+ it.next();
+ }
+ }
+ std::cout << ">> MAJ zpar: " << internal::t_prop
<< " s" << std::endl;
+ std::cout << "Parent construction: " << tm << "
s" << std::endl;
+ tm.restart();
+
+ // Canonization
+ {
+ mln_ch_value(I, bool) deja_vu(d_ext);
+ mln::data::fill(deja_vu, false);
+ mln_fwd_piter(S) p(s_f); // Forward.
+ for_all(p)
+ {
+ P q = parent(p);
+ if (!f.domain().has(q))
+ internal::update_m_parent(fext, parent, deja_vu, s, d_ext, p);
+ else if (fext(parent(q)) == f(q))
+ parent(p) = parent(q);
+ s.append(p);
+
+ mln_assertion((q = parent(p)) == parent(q) || fext(q) != fext(parent(q)));
+ }
+ }
+ std::cout << "Canonization: " << tm << " s"
<< std::endl;
+
+ //mln_postcondition(internal::compute_parent_postconditions(fext, s, parent));
+
+ tree::data<I, p_array<mln_psite(I)> > tree(fext, parent, s);
+ trace::exiting("morpho::tree::impl::generic::dual_union_find");
+
+ 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_IMLP_DUAL_UNION_FIND_HH
Index: trunk/milena/mln/morpho/tree/all.hh
===================================================================
--- trunk/milena/mln/morpho/tree/all.hh (revision 4553)
+++ trunk/milena/mln/morpho/tree/all.hh (revision 4554)
@@ -48,6 +48,7 @@
# 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>
Index: trunk/milena/mln/morpho/tree/data.hh
===================================================================
--- trunk/milena/mln/morpho/tree/data.hh (revision 4553)
+++ trunk/milena/mln/morpho/tree/data.hh (revision 4554)
@@ -32,7 +32,6 @@
/// of S container iterator) to go faster.
# include <mln/morpho/tree/compute_parent.hh>
-# include <mln/morpho/tree/compute_parent_dual_input.hh>
# include <mln/core/site_set/p_array.hh>
# include <mln/core/internal/site_set_iterator_base.hh>
# include <mln/core/internal/piter_identity.hh>
@@ -138,18 +137,18 @@
typedef mln::morpho::tree::depth1st_piter<self_> depth1st_piter;
- /// Constructor.
+ /// Standard constructor.
template <typename N>
- data(const Image<I>& f, const Site_Set<S>& s, const
Neighborhood<N>& nbh);
-
- /// Constructor.
- template <typename N, typename M>
data(const Image<I>& f,
- const Image<M>& m,
- const Site_Set<S>& s_f,
- const Site_Set<S>& s_m,
+ const Site_Set<S>& s,
const Neighborhood<N>& nbh);
+ /// Special constructor where the parent computation has
+ /// delegated to an external function. (To handle special case
+ /// of connectivity for example).
+ data(const Image<I>& f,
+ const parent_t& parent,
+ const Site_Set<S>& s);
/// \{ Base function-related materials
@@ -205,13 +204,18 @@
unsigned nroots() const;
protected:
- const function& f_;
- const sites_t s_;
+ void compute_children_();
+
+ protected:
mln_ch_value(I, mln_psite(I)) parent_; // Parent image.
mln_ch_value(I, nodes_t) children_; // Children image.
- nodes_t nodes_;
- leaves_t leaves_;
- unsigned nroots_;
+
+ function f_; // f image containing values of the tree nodes.
+ sites_t s_; // Sorted site set of the tree sites. (domain(f_) includes s_).
+
+ nodes_t nodes_; // Sorted node set.
+ leaves_t leaves_; // Sorted leaf set.
+ unsigned nroots_; // For non-contigous domain image purpose.
};
@@ -403,43 +407,15 @@
{
template <typename I, typename S>
- template <typename N, typename M>
inline
data<I, S>::data(const Image<I>& f,
- const Image<M>& m,
- const Site_Set<S>& s_f,
- const Site_Set<S>& s_m,
- const Neighborhood<N>& nbh)
- : f_(exact(f)),
- s_(exact(s_f))
- {
- const N& nbh_ = exact(nbh);
-
- // Compute parent image.
- parent_ = morpho::tree::compute_parent_dual_input(f_, m, nbh_, s_, s_m);
- initialize(children_, f);
-
- // Store tree nodes.
- nroots_ = 0;
- mln_bkd_piter(S) p(s_);
- for_all(p)
- {
- if (f_(parent_(p)) != f_(p))
- {
- nodes_.insert(p);
- children_(parent_(p)).insert(p);
- if (is_a_leaf(p))
- leaves_.insert(p);
- }
- else if (parent_(p) == p) //it's a root.
+ const mln_ch_value(I, mln_psite(I))& parent,
+ const Site_Set<S>& s)
+ : parent_ (parent),
+ f_ (exact(f)),
+ s_ (exact(s))
{
- nodes_.insert(p);
- if (is_a_leaf(p)) // One pixel image...
- leaves_.insert(p);
- ++nroots_;
- }
- }
- mln_assertion(leaves_.nsites() > 0);
+ compute_children_();
}
@@ -447,15 +423,25 @@
template <typename I, typename S>
template <typename N>
inline
- data<I,S>::data(const Image<I>& f, const Site_Set<S>& s,
const Neighborhood<N>& nbh)
+ data<I,S>::data(const Image<I>& f,
+ const Site_Set<S>& s,
+ const Neighborhood<N>& nbh)
: f_(exact(f)),
s_(exact(s))
{
- const N& nbh_ = exact(nbh);
-
// Compute parent image.
+ const N& nbh_ = exact(nbh);
parent_ = morpho::tree::compute_parent(f_, nbh_, s_);
- initialize(children_, f);
+
+ compute_children_();
+ }
+
+ template <typename I, typename S>
+ inline
+ void
+ data<I, S>::compute_children_()
+ {
+ initialize(children_, f_);
// Store tree nodes.
nroots_ = 0;
@@ -480,24 +466,13 @@
mln_assertion(leaves_.nsites() > 0);
}
+
template <typename I, typename S>
inline
mln_rvalue_(mln_ch_value(I, mln_psite(I)))
data<I,S>::parent(const mln_psite(I)& p) const
{
- // HERE
-
-// mln_precondition(is_valid());
-// mln_rvalue(parent_t) tmp;
-// if (! parent_.domain().has(p))
-// {
-// std::cout << "KO next" << std::endl;
-// std::cout << p << std::endl;
-// std::cout << parent_.domain() << std::endl;
-// }
-// else
-// std::cout << "ok next" << std::endl;
-// mln_precondition(parent_.domain().has(p));
+ mln_precondition(parent_.domain().has(p));
return parent_(p);
}