https://svn.lrde.epita.fr/svn/oln/trunk/milena/sandbox
Index: ChangeLog
from Thierry Geraud <thierry.geraud(a)lrde.epita.fr>
Update Laurent's code.
* theo/esiee/laurent/ismm09/main.cc: Augment.
* theo/esiee/laurent/ismm09/lca.hh: New.
* theo/color/segment.cc: Use 16bit labels.
color/segment.cc | 12 -
esiee/laurent/ismm09/lca.hh | 173 +++++++++++++++
esiee/laurent/ismm09/main.cc | 489 ++++++++++++++++++++++++++++++++++++-------
3 files changed, 595 insertions(+), 79 deletions(-)
Index: theo/esiee/laurent/ismm09/main.cc
--- theo/esiee/laurent/ismm09/main.cc (revision 3256)
+++ theo/esiee/laurent/ismm09/main.cc (working copy)
@@ -174,10 +174,15 @@
return e + (is_row_odd(e) ? down : right);
}
+
+ // Function-Object "e -> (l1, l2)".
+
+ struct e_to_labels_t
+ {
template <typename W, typename L>
inline
void
- e_to_labels(const W& w, const point2d& e, L& l1, L& l2)
+ operator()(const W& w, const point2d& e, L& l1, L& l2) const
{
mln_precondition(w(e) == 0);
l1 = 0;
@@ -199,6 +204,7 @@
std::swap(l1, l2);
mln_postcondition(l2 >= l1);
}
+ };
} // end of namespace mln::cplx2d
@@ -207,21 +213,402 @@
template <typename A, typename L>
util::array<L>
- sort_by_increasing_attributes(const util::array<A>& a, L n_basins)
+ sort_by_increasing_attributes(const util::array<A>& a, L l_max)
{
typedef std::pair<A,L> pair_t;
std::vector<pair_t> v;
- v.reserve(n_basins);
- for (L l = 1; l <= n_basins; ++l)
+ v.reserve(l_max.next());
+
+ v.push_back(pair_t(mln_min(A), 0)); // First elt, even after sorting.
+ for (L l = 1; l <= l_max; ++l)
v.push_back(pair_t(a[l], l));
std::sort(v.begin(), v.end());
- util::array<L> l(n_basins);
- for (unsigned i = 0; i < n_basins; ++i)
- l[i] = v[i].second;
+ util::array<L> ls(l_max.next());
+ for (unsigned i = 1; i <= l_max; ++i)
+ ls[i] = v[i].second;
+
+ return ls;
+ }
+
+
+ // Find-Root for a region labeled with 'l'.
+
+ template <typename L>
+ inline
+ L find_root_l(util::array<L>& lpar, L l)
+ {
+ if (lpar[l] == l)
return l;
+ else
+ return lpar[l] = find_root_l(lpar, lpar[l]);
+ }
+
+
+
+ template <typename I>
+ inline
+ mln_psite(I)
+ find_root_e(I& z_epar, mln_psite(I) e)
+ {
+ if (z_epar(e) == e)
+ return e;
+ else
+ return z_epar(e) = find_root_e(z_epar, z_epar(e));
+ }
+
+
+
+ // Test emptiness of the queue of a set of regions.
+
+ template <typename Qs, typename L>
+ bool test_q_emptiness(const Qs& qs, L l, util::array<L>& lpar)
+ {
+ L l_ = l;
+ while (lpar[l_] != l_)
+ {
+ if (! qs[l_].is_empty())
+ return false;
+ l_ = lpar[l_];
+ }
+ return true;
+ }
+
+
+ // Get smallest edge.
+
+ template <typename Q_,
+ typename W, typename L, typename F,
+ typename E>
+ void
+ get_smallest_edge(Q_& q_, // in-out
+ L l, const W& w, util::array<L>& lpar, const F& e_to_labels, //
in
+ E& e) // out
+ {
+ typedef mln_element(Q_) Q; // q_ is an array of queues with type Q.
+
+ // Test that, when a region has merged, its edge queue has been
+ // emptied.
+ mln_invariant(test_q_emptiness(q_, l, lpar));
+
+ L lr = find_root_l(lpar, l);
+ Q& q = q_[lr];
+
+ while (! q.is_empty())
+ {
+ e = q.pop_front();
+
+ L l1, l2;
+ e_to_labels(w, e, // input
+ l1, l2); // output
+
+ mln_invariant(l1 != l2);
+
+ L l1r = find_root_l(lpar, l1),
+ l2r = find_root_l(lpar, l2);
+
+ mln_invariant(l1r == lr || l2r == lr);
+
+ if (l1r == l2r)
+ // 'e' is an internal edge => forget it.
+ continue;
+
+ // Otherwise 'e' has been found.
+ return;
+ }
+
+ mln_invariant(0); // We should not be here!
+ }
+
+
+
+
+ // ###################################################################
+ // ###################################################################
+ // ###################################################################
+ // ###################################################################
+ // ###################################################################
+
+
+
+ template <typename W,
+ typename G,
+ typename L, typename A,
+ typename F>
+ void
+ compute_pseudo_tree(const W& w,
+ const G& g,
+ const util::array<L>& ls,
+ const A& a,
+ const F& e_to_labels)
+ {
+
+ typedef mln_value(G) T; // <--- Type of edge values.
+ typedef mln_psite(G) E; // <--- Type of edges.
+
+ const L l_max = ls.nelements() - 1;
+
+ mln_VAR( g_line, g | (pw::value(w) == 0) );
+
+
+ // Edges -> Priority queue.
+
+ typedef p_priority< T, p_queue<E> > Q;
+ util::array<Q> q(l_max.next());
+
+ {
+ L l1, l2;
+
+ mln_piter(g_line_t) e(g_line.domain());
+ for_all(e)
+ {
+ mln_invariant(w(e) == 0);
+ e_to_labels(w, e, // input
+ l1, l2); // output
+ q[l1].push(mln_max(T) - g(e), e);
+ q[l2].push(mln_max(T) - g(e), e);
+ }
+ }
+
+
+
+ // Initialization.
+ // -----------------------------------
+
+
+
+ // Information "label l -> edge e".
+
+ E null = E(0,0); // Impossible value. FIXME: lack of genericity.
+
+
+ util::array<E> edge(l_max.next());
+ for (L l = 0; l <= l_max; ++l)
+ edge[l] = null;
+
+
+ util::array<L> lpar(l_max.next());
+ for (L l = 0; l <= l_max; ++l)
+ lpar[l] = l; // Make-Set.
+
+
+ // To know if an edge is out of a given region (label l), we
+ // maintain the information about region merging using an
+ // union-find structure named "lpar".
+ //
+ // In the following "lpar[l]" is shortly denoted by lr, meaning
+ // l-root.
+
+
+ // Given a region R with label l and an edge e = (l1, l2) from the
+ // priority queue, we get know if that edge is out of the set of
+ // regions containing l: we shall have l1r = lr or l2r = lr.
+
+ // Please note that an edge (l1, l2) is internal to a set of
+ // regions if l1r = l2r.
+
+
+
+
+ mln_ch_value(g_line_t, E)
+ epar, // Edge forest.
+ z_epar; // Auxiliary data: edge forest with compression and balancing.
+
+ {
+ initialize(epar, g_line);
+ initialize(z_epar, g_line);
+ mln_piter(g_line_t) e(g_line.domain());
+ for_all(e)
+ {
+ // Make-Set.
+ epar(e) = e;
+ z_epar(e) = e;
+ }
+ debug::println("epar (init):", epar); // epar(e) == e so we depict the
edges!
+ }
+
+
+
+ // GO GO GO !!!
+
+
+ for (unsigned i = 1; i < l_max; ++i)
+ {
+ L l = ls[i]; // Region label.
+ E e;
+ get_smallest_edge(q, // in-out
+ l, w, lpar, e_to_labels, // in
+ e); // out
+ // FIXME: the call below is performed above!!!
+ L l1, l2;
+ e_to_labels(w, e, l1, l2);
+
+ L l1r = find_root_l(lpar, l1),
+ l2r = find_root_l(lpar, l2);
+
+ // Consistency tests.
+ {
+ if (i > 1)
+ {
+ L former_l = ls[i-1];
+ mln_invariant(a[l] >= a[former_l]);
+ }
+ mln_invariant(epar(e) == e); // 'e' has not been processed yet.
+ mln_invariant(l1 != l2); // It is a valid edge, i.e., between 2 different
regions...
+ mln_invariant(l1r != l2r); // ...that are not already merged.
+
+ L lr = find_root_l(lpar, l);
+ mln_invariant(lr == l // Either l is not deja-vu
+ || ((lr == l1r && lr != l2r) || // or l belongs to l1r xor l2r.
+ (lr == l2r && lr != l1r)));
+ }
+
+
+
+ // aa(e) = a[l]; // FIXME: Re-activate.
+
+
+
+ /*
+ std::cout << "l = " << l
+ << " e = " << e
+ << " (l1, l2) = (" << l1 << ", " << l2
<< ") => "
+ << " merging R" << l1r << " and R" << l2r
+ << std::endl;
+ */
+
+
+ // Merging both regions.
+ {
+ if (l2r < l1r)
+ std::swap(l1r, l2r);
+ mln_invariant(l2r > l1r);
+ lpar[l1r] = l2r;
+
+ /*
+ std::cout << "q[l1r] = " << q[l1r] << std::endl;
+ std::cout << "q[l2r] = " << q[l2r] << std::endl;
+ */
+
+
+ q[l2r].insert(q[l1r]);
+ q[l1r].clear();
+
+
+ /*
+ std::cout << "q[l2r] = " << q[l2r] << std::endl
+ << std::endl;
+ */
+
+
+ /*
+ // Displaying lpar.
+ {
+ std::cout << "lpar = ";
+ for (unsigned i = 1; i <= l_max; ++i)
+ {
+ L l = v[i].second;
+ std::cout << l << "->" << lpar[l] << "
";
+ }
+ std::cout << std::endl;
+ }
+ */
+ }
+
+ E e1 = edge[l1],
+ e2 = edge[l2];
+
+ if (e1 == null && e2 == null)
+ {
+ // New edge-component (singleton)
+ // Put differently: new edge-node!
+ edge[l1] = e;
+ edge[l2] = e;
+ // after:
+ // e
+ // / \
+ // l1 l2
+ }
+ else if (e1 != null && e2 != null)
+ {
+ // Two trees shall merge.
+ E e1r = find_root_e(z_epar, e1),
+ e2r = find_root_e(z_epar, e2);
+ mln_invariant(e1r != e2r); // Otherwise, there's a bug!
+ // before:
+ // e1r e2r
+ // |... |...
+ // e1 e2
+ // / \ / \
+ // l1 . l2 .
+ epar(e1r) = e; z_epar(e1r) = e;
+ epar(e2r) = e; z_epar(e2r) = e;
+ // after:
+ // e
+ // / \
+ // e1r e2r
+ // |... |...
+ // e1 e2
+ // / \ / \
+ // l1 . l2 .
+ }
+ else if (e1 != null && e2 == null)
+ {
+ E e1r = find_root_e(z_epar, e1);
+ // before:
+ // e1r
+ // |...
+ // e1 null
+ // / \ /
+ // l1 . l2
+ epar(e1r) = e; z_epar(e1r) = e;
+ edge[l2] = e;
+ // after:
+ // e
+ // / \
+ // e1r l2
+ // |...
+ // e1
+ // / \
+ // l1 .
+ }
+ else
+ {
+ mln_invariant(e1 == null && e2 != null);
+ E e2r = find_root_e(z_epar, e2);
+ epar(e2r) = e; z_epar(e2r) = e;
+ edge[l1] = e;
+ }
+
+ } // end of "for every region with increasing attribute"
+
+
+ {
+ // Display edge tree.
+
+ mln_ch_value(g_line_t, bool) deja_vu;
+ initialize(deja_vu, g_line);
+ data::fill(deja_vu, false);
+
+ std::cout << "edge tree: " << std::endl;
+ for (L l = 1; l <= l_max; ++l)
+ {
+ std::cout << l << ": ";
+ E e = edge[l];
+ while (! deja_vu(e))
+ {
+ std::cout << e << " -> ";
+ deja_vu(e) = true;
+ e = epar(e);
+ }
+ std::cout << e << std::endl;
+ }
+ }
+
+
+
}
@@ -232,9 +619,8 @@
void usage(char* argv[])
{
- std::cerr << "usage: " << argv[0] << " input.pgm echo
output.pgm" << std::endl;
- std::cerr << "Laurent ISMM 2009 scheme with saliency map as output."
<< std::endl;
- std::cerr << " echo = 0 or 1." << std::endl;
+ std::cerr << "usage: " << argv[0] << " input.pgm"
<< std::endl;
+ std::cerr << "Laurent ISMM 2009 scheme." << std::endl;
abort();
}
@@ -247,7 +633,7 @@
using value::int_u8;
using value::label_16;
- if (argc != 4)
+ if (argc != 2)
usage(argv);
// f: regular image.
@@ -256,6 +642,8 @@
io::pgm::load(f, argv[1]);
+ cplx2d::e_to_labels_t e_to_labels;
+
// g: weights on edges.
mln_VAR(g, cplx2d::f_to_g(f) );
@@ -271,8 +659,8 @@
// w: watershed labeling on edges.
typedef label_16 L; // <--- Type of labels.
- L n_basins;
- mln_VAR( w, morpho::meyer_wst(g, nbh_g, n_basins) );
+ L l_max;
+ mln_VAR( w, morpho::meyer_wst(g, nbh_g, l_max) );
debug::println("w:", w);
@@ -299,17 +687,17 @@
util::array<A> a = labeling::compute(accu::meta::count(),
g, // image of values
w, // image of labels
- n_basins);
+ l_max);
+
+ util::array<L> ls = sort_by_increasing_attributes(a, l_max);
- util::array<L> l = sort_by_increasing_attributes(a, n_basins);
{
- /*
- std::cout << "l:" << std::endl;
- for (unsigned i = 0; i < l.nelements(); ++i)
- std::cout << l[i] << "(" << a[l[i]] << ")
";
- std::cout << std::endl;
- */
+ std::cout << "ls:" << std::endl;
+ for (unsigned i = 1; i <= l_max; ++i)
+ std::cout << ls[i] << "(" << a[ls[i]] << ")
";
+ std::cout << std::endl
+ << std::endl;
}
@@ -320,66 +708,13 @@
// for_all(e)
// if (w(e) == 0)
// {
-// cplx2d::e_to_labels(w, e, l1, l2);
+ // e_to_labels(w, e, l1, l2);
// std::cout << e << ':' << l1 << ',' <<
l2 << std::endl;
// }
// }
-
- // Edges -> Priority queue.
-
- typedef p_priority< T, p_queue<E> > Q;
- util::array<Q> q(n_basins.next());
-
- {
- L l1, l2;
- mln_piter_(g_t) e(g.domain());
- for_all(e)
- if (w(e) == 0)
- {
- cplx2d::e_to_labels(w, e, // input
- l1, l2); // output
- q[l1].push(mln_max(T) - g(e), e);
- q[l2].push(mln_max(T) - g(e), e);
- }
- }
-
-
- // Information "label l -> edge e".
-
- E null = E(0,0); // Impossible value.
-
- util::array<E> edge(n_basins.next());
- for (L l = 0; l <= n_basins; ++l)
- edge[l] = null;
-
-
- // Initialization.
-
- util::array<L> lpar(n_basins.next());
- for (L l = 0; l <= n_basins; ++l)
- lpar[l] = l; // Make-Set.
-
-
-
- mln_ch_value_(g_line_t, E)
- epar, // Edge forest.
- z_epar; // Auxiliary data: edge forest with compression and balancing.
-
- {
- initialize(epar, g_line);
- initialize(z_epar, g_line);
- mln_piter_(g_line_t) e(g_line.domain());
- for_all(e)
- {
- // Make-Set.
- epar(e) = e;
- z_epar(e) = e;
- }
- debug::println("all edges:", epar); // epar(e) == e so we depict the
edges!
- }
-
-
+ compute_pseudo_tree(w, g, ls, a,
+ e_to_labels);
}
Index: theo/esiee/laurent/ismm09/lca.hh
--- theo/esiee/laurent/ismm09/lca.hh (revision 0)
+++ theo/esiee/laurent/ismm09/lca.hh (revision 0)
@@ -0,0 +1,173 @@
+
+namespace mln
+{
+
+
+ // From parent image to children image.
+
+ template <typename I, typename E, typename L>
+ mln_ch_value(I, std::vector<mln_psite(I)>)
+ compute_children(const I& epar, const std::vector<E>& edge, L l_max,
std::vector<E>& roots)
+ {
+ typedef std::vector<mln_psite(I)> C; // Children.
+ mln_ch_value(I,C) chl;
+ initialize(chl, epar);
+
+ mln_ch_value(I,bool) deja_vu;
+ initialize(deja_vu, epar);
+ data::fill(deja_vu, false);
+
+ for (L l = 1; l <= l_max; ++l)
+ {
+ E e = edge[l];
+ while (deja_vu(e) == false)
+ {
+ deja_vu(e) = true;
+ if (epar(e) != e)
+ {
+ chl(epar(e)).push_back(e);
+ e = epar(e);
+ }
+ else
+ roots.push_back(e);
+ }
+ }
+
+ return chl;
+ }
+
+
+ /// Compute an LCA
+ /// Reference article: The LCA Problem Revisited, M. A. Bender and M.
+ /// Farach-Colton, May 2000
+ ///
+ /// See also Topological Watershed, Alexandre Abraham, LRDE CSI report
+ /// 0821, June 2008
+ ///
+ template <typename L, typename I, typename E>
+ class lca_t
+ {
+
+ public:
+
+ /// Constructor
+ lca_t(const L& l_max_,
+ const I& edge_children,
+ const std::vector<E>& roots)
+ {
+ unsigned l_max = l_max_.next();
+ euler_tour_edge_.resize(2 * l_max + 1);
+ euler_tour_depth_.resize(2 * l_max + 1);
+ initialize (euler_position_, edge_children);
+
+ // BUILD EULER TOUR
+ std::stack<E> to_treat;
+ for (unsigned i = 0; i < roots.size(); ++i)
+ to_treat.push(roots[i]);
+
+ unsigned euler_edge = 0;
+ mln_ch_value(I, bool) deja_vu;
+ initialize(deja_vu, edge_children);
+ data::fill(deja_vu, false);
+
+ while (!to_treat.empty())
+ {
+ E e = to_treat.top();
+ to_treat.pop();
+
+ euler_tour_edge_[euler_edge] = e;
+ if (deja_vu(e))
+ euler_tour_depth_[euler_edge] = euler_tour_depth_[euler_edge - 1] - 1;
+ else
+ euler_tour_depth_[euler_edge] = euler_tour_depth_[euler_edge - 1] + 1;
+
+ if (!deja_vu(e))
+ {
+ for (int j = edge_children(e).size() - 1; j >= 0; --j)
+ {
+ to_treat.push(e);
+ to_treat.push(edge_children(e)[j]);
+ }
+ deja_vu(e) = true;
+ euler_position_(e) = euler_edge;
+ }
+
+ ++euler_edge;
+ }
+
+ // BUILD MINIMAS
+ int size = 2 * l_max - 1;
+ int logn = (int)(ceil(log((double)(size))/log(2.0)));
+
+ minim_ = new int [logn * size]; // FIXME : Think about freeing this
+ Minim_ = new int* [logn];
+
+ Minim_[0] = minim_;
+
+ // Init
+ for (unsigned i = 0; i < size - 1; ++i)
+ if (euler_tour_depth_[i] < euler_tour_depth_[i+1])
+ {
+ Minim_[0][i] = i;
+ } else {
+ Minim_[0][i] = i+1;
+ }
+
+ int k;
+ for (int j = 1; j < logn; j++)
+ {
+ k = 1 << (j - 1);
+ Minim_[j] = &minim_[j * size];
+ for (int i = 0; i < size; i++)
+ {
+ if ((i + (k << 1)) < size)
+ {
+ if (euler_tour_depth_[Minim_[j - 1][i]] <= euler_tour_depth_[Minim_[j - 1][i +
k]])
+ Minim_[j][i] = Minim_[j - 1][i];
+ else
+ Minim_[j][i] = Minim_[j - 1][i + k];
+ }
+ }
+ }
+ }
+
+
+ /// Destructor
+ ~lca_t()
+ {
+ delete[] Minim_;
+ delete[] minim_;
+ }
+
+
+ const E& operator() (const E& a, const E& b)
+ {
+ if (a == b)
+ return a;
+
+ int m = euler_position_(a),
+ n = euler_position_(b),
+ k;
+
+ if (m > n)
+ std::swap(m, n);
+
+ k = (int)(log((double)(n - m))/log(2.));
+
+ if (euler_tour_depth_[Minim_[k][m]]
+ < euler_tour_depth_[Minim_[k][n - (1 << k)]])
+ return euler_tour_edge_[Minim_[k][m]];
+ else
+ return euler_tour_edge_[Minim_[k][n - (1 << k)]];
+ }
+
+ private:
+ int *minim_;
+ int **Minim_;
+ std::vector<E> euler_tour_edge_;
+ std::vector<unsigned> euler_tour_depth_;
+ mln_ch_value(I, unsigned) euler_position_;
+ };
+
+
+} // mln
Index: theo/color/segment.cc
--- theo/color/segment.cc (revision 3256)
+++ theo/color/segment.cc (working copy)
@@ -227,6 +227,13 @@
}
+ value::int_u8 L_to_int_u8(unsigned l)
+ {
+ return l == 0 ?
+ 0 : // wshed line
+ 1 + (l - 1) % 255; // basin
+ }
+
} // mln
@@ -297,7 +304,7 @@
// Watershed transform.
- typedef value::label_8 L;
+ typedef value::label_16 L;
L nbasins;
mln_ch_value_(f_t, L) w = morpho::meyer_wst(g, e2e(), nbasins);
@@ -330,7 +337,8 @@
w_all);
}
- io::pgm::save(w_all, "temp_w_all.pgm");
+ io::pgm::save( level::transform(w_all, convert::to_fun(L_to_int_u8)),
+ "temp_w_all.pgm" );
}