https://svn.lrde.epita.fr/svn/oln/trunk/milena/sandbox
Index: ChangeLog
from Thierry Geraud <thierry.geraud(a)lrde.epita.fr>
Clean-up Laurent's code.
* theo/esiee/laurent/ismm09/main.cc
(p1_from, p2_from, e_to_labels_t): Move...
* theo/esiee/laurent/ismm09/trash.hh: ...here.
* theo/esiee/laurent/ismm09/main.cc
(data__paste_values, cplx2d): Move...
* theo/esiee/laurent/ismm09/cplx2d.hh: ...in this new file.
* theo/esiee/laurent/ismm09/main.cc
(compute_pseudo_tree): Move...
* theo/esiee/laurent/ismm09/pseudo_tree.hh: ...in this new file.
* theo/esiee/laurent/ismm09/main.cc (include): Dispatch...
* theo/esiee/laurent/ismm09/util.hh,
* theo/esiee/laurent/ismm09/cplx2d.hh,
* theo/esiee/laurent/ismm09/pseudo_tree.hh: ...in those files.
* theo/color/change_attributes.hh
(extinct_rec__, extinct_attributes__): New.
color/change_attributes.hh | 62 +++
esiee/laurent/ismm09/cplx2d.hh | 148 +++++++
esiee/laurent/ismm09/main.cc | 671 +-----------------------------------
esiee/laurent/ismm09/pseudo_tree.hh | 449 ++++++++++++++++++++++++
esiee/laurent/ismm09/trash.hh | 44 ++
esiee/laurent/ismm09/util.hh | 10
6 files changed, 745 insertions(+), 639 deletions(-)
Index: theo/esiee/laurent/ismm09/trash.hh
--- theo/esiee/laurent/ismm09/trash.hh (revision 3285)
+++ theo/esiee/laurent/ismm09/trash.hh (working copy)
@@ -36,6 +36,50 @@
}
+ inline
+ point2d p1_from_e(const point2d& e)
+ {
+ return e + (is_row_odd(e) ? up : left);
+ }
+
+ inline
+ point2d p2_from_e(const point2d& e)
+ {
+ return e + (is_row_odd(e) ? down : right);
+ }
+
+
+
+ struct e_to_labels_t
+ {
+ template <typename W, typename L>
+ inline
+ void
+ operator()(const W& w, const point2d& e, L& l1, L& l2) const
+ {
+ mln_precondition(w(e) == 0);
+ l1 = 0;
+ l2 = 0;
+ mln_niter(dbl_neighb2d) n(e2e(), e);
+ for_all(n)
+ if (w.has(n) && w(n) != 0)
+ {
+ if (l1 == 0) // First label to be stored.
+ l1 = w(n);
+ else
+ if (w(n) != l1 && l2 == 0) // Second label to be stored.
+ l2 = w(n);
+ else
+ mln_invariant(w(n) == l1 || w(n) == l2);
+ }
+ mln_invariant(l1 != 0 && l2 != 0);
+ if (l1 > l2)
+ std::swap(l1, l2);
+ mln_postcondition(l2 >= l1);
+ }
+ };
+
+
} // end of namespace mln
Index: theo/esiee/laurent/ismm09/main.cc
--- theo/esiee/laurent/ismm09/main.cc (revision 3285)
+++ theo/esiee/laurent/ismm09/main.cc (working copy)
@@ -1,620 +1,20 @@
#include <mln/core/var.hh>
-#include <mln/core/image/image2d.hh>
-#include <mln/core/alias/neighb2d.hh>
-#include <mln/make/double_neighb2d.hh>
-
-#include <mln/core/image/image_if.hh>
-#include <mln/core/routine/extend.hh>
-
#include <mln/value/label_16.hh>
#include <mln/value/int_u8.hh>
#include <mln/io/pgm/load.hh>
#include <mln/io/pgm/save.hh>
#include <mln/debug/println.hh>
-#include <mln/data/fill.hh>
-#include <mln/data/paste.hh>
-#include <mln/labeling/compute.hh>
-#include <mln/level/sort_psites.hh>
-
-#include <mln/core/site_set/p_queue.hh>
-#include <mln/core/site_set/p_priority.hh>
-
-#include <mln/morpho/gradient.hh>
#include <mln/morpho/meyer_wst.hh>
-#include <mln/morpho/tree/data.hh>
-#include <mln/morpho/tree/compute_attribute_image.hh>
-
+#include <mln/labeling/compute.hh>
#include <mln/accu/count.hh>
+#include "pseudo_tree.hh"
+#include "cplx2d.hh"
-namespace mln
-{
-
-
-
- template <typename I, typename J>
- void data__paste_values(const Image<I>& input_, Image<J>& output_)
- {
- const I& input = exact(input_);
- J& output = exact(output_);
-
- mln_fwd_piter(I) pi(input.domain());
- mln_fwd_piter(J) po(output.domain());
- for_all_2(pi, po)
- output(po) = input(pi);
- }
-
-
-
- namespace cplx2d
- {
-
- // Neighborhoods.
-
- typedef neighb< win::multiple<window2d, bool(*)(const point2d&)> >
dbl_neighb2d;
-
- inline
- bool is_row_odd(const point2d& p)
- {
- return p.row() % 2;
- }
-
- // Edge to (the couple of) pixels.
- const dbl_neighb2d& e2p()
- {
- static bool e2p_h[] = { 0, 1, 0,
- 0, 0, 0,
- 0, 1, 0 };
- static bool e2p_v[] = { 0, 0, 0,
- 1, 0, 1,
- 0, 0, 0 };
- static dbl_neighb2d nbh = make::double_neighb2d(is_row_odd, e2p_h, e2p_v);
- return nbh;
- }
-
-
- // Edge to neighboring edges.
- const dbl_neighb2d& e2e()
- {
- static bool e2e_h[] = { 0, 0, 1, 0, 0,
- 0, 1, 0, 1, 0,
- 0, 0, 0, 0, 0,
- 0, 1, 0, 1, 0,
- 0, 0, 1, 0, 0 };
- static bool e2e_v[] = { 0, 0, 0, 0, 0,
- 0, 1, 0, 1, 0,
- 1, 0, 0, 0, 1,
- 0, 1, 0, 1, 0,
- 0, 0, 0, 0, 0 };
- static dbl_neighb2d nbh = make::double_neighb2d(is_row_odd, e2e_h, e2e_v);
- return nbh;
- }
-
-
- // Predicates.
-
- typedef fun::C<bool (*)(const mln::point2d&)> predicate_t;
-
- inline
- bool is_pixel(const point2d& p)
- {
- // Original pixels.
- return p.row() % 2 == 0 && p.col() % 2 == 0;
- }
-
- inline
- bool is_edge(const point2d& p)
- {
- // Edges between pixels.
- return p.row() % 2 + p.col() % 2 == 1;
- }
-
- inline
- bool is_point(const point2d& p)
- {
- // Points in-between pixels.
- return p.row() % 2 && p.col() % 2;
- }
-
-
-
- image_if< image2d<value::int_u8>, predicate_t >
- f_to_g(const image2d<value::int_u8>& f)
- {
-
- image2d<value::int_u8> f_(2 * f.nrows() - 1, 2 * f.ncols() - 1);
- data::fill(f_, 0); // Useless but for display!
-
- data__paste_values(f, (f_ | is_pixel).rw());
-
- mln_VAR(g, f_ | is_edge);
- data::paste(morpho::gradient(extend(g, f_),
- e2p().win()),
- g);
-
- return g;
- }
-
-
- template <typename W>
- image2d<mln_value(W)>
- extend_w_edges_to_all_faces(W& w)
- {
- mln_VAR(w_ext, w.unmorph_());
-
- // edges (1D-faces) -> pixels (2D-faces)
- data::paste(morpho::dilation(extend(w_ext | is_pixel,
- pw::value(w_ext)),
- c4().win()),
- w_ext);
-
- // edges (1D-faces) -> points (0D-faces)
- data::paste(morpho::erosion(extend(w_ext | is_point,
- pw::value(w_ext)),
- c4().win()),
- w_ext);
-
- return w_ext;
- }
-
-
- inline
- point2d p1_from_e(const point2d& e)
- {
- return e + (is_row_odd(e) ? up : left);
- }
-
- inline
- point2d p2_from_e(const point2d& e)
- {
- 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
- operator()(const W& w, const point2d& e, L& l1, L& l2) const
- {
- mln_precondition(w(e) == 0);
- l1 = 0;
- l2 = 0;
- mln_niter(dbl_neighb2d) n(e2e(), e);
- for_all(n)
- if (w.has(n) && w(n) != 0)
- {
- if (l1 == 0) // First label to be stored.
- l1 = w(n);
- else
- if (w(n) != l1 && l2 == 0) // Second label to be stored.
- l2 = w(n);
- else
- mln_invariant(w(n) == l1 || w(n) == l2);
- }
- mln_invariant(l1 != 0 && l2 != 0);
- if (l1 > l2)
- std::swap(l1, l2);
- mln_postcondition(l2 >= l1);
- }
- };
-
-
- } // end of namespace mln::cplx2d
-
-
-
- template <typename A, typename L>
- util::array<L>
- 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(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> 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;
- }
- }
-
-
-
- }
-
-
-
-} // end of namespace mln
-
void usage(char* argv[])
@@ -642,8 +42,6 @@
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) );
@@ -653,30 +51,37 @@
typedef mln_psite_(g_t) E; // <--- Type of edges.
- mln_VAR(nbh_g, cplx2d::e2e()); // Neighborhood between edges.
-
-
// w: watershed labeling on edges.
typedef label_16 L; // <--- Type of labels.
L l_max;
- mln_VAR( w, morpho::meyer_wst(g, nbh_g, l_max) );
+ mln_VAR( w, morpho::meyer_wst(g, cplx2d::e2e(), l_max) );
debug::println("w:", w);
- mln_VAR( w_line, pw::value(w) == pw::cst(0) );
- mln_VAR( g_line, g | w_line );
+ mln_VAR( is_w_line, pw::value(w) == pw::cst(0) );
+ mln_VAR( g_line, g | is_w_line );
debug::println("g | line:", g_line);
-
- {
- /*
- // debug::println("w | line:", w | w_line);
mln_VAR(w_ext, cplx2d::extend_w_edges_to_all_faces(w));
debug::println("w_ext:", w_ext);
- // debug::println("w_ext | line:", w_ext | (pw::value(w_ext) ==
pw::cst(0)));
- */
- }
+
+
+ // e -> (l1, l2)
+ mln_VAR( e_to_l1_l2, function_e_to_l1_l2(w_ext, cplx2d::e2p()) );
+
+// {
+// // Test adjacency "e -> (l1, l2)".
+// L l1, l2;
+// mln_piter_(g_t) e(g.domain());
+// for_all(e)
+// if (w(e) == 0)
+// {
+// e_to_l1_l2(e, l1, l2);
+// std::cout << e << "=" << l1 << '|'
<< l2 << " ";
+// }
+// std::cout << std::endl;
+// }
@@ -691,30 +96,18 @@
util::array<L> ls = sort_by_increasing_attributes(a, l_max);
-
- {
- 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;
- }
-
-
- // {
- // // Test adjacency "e -> (l1, l2)".
- // L l1, l2;
- // mln_piter_(g_t) e(g.domain());
- // for_all(e)
- // if (w(e) == 0)
// {
- // e_to_labels(w, e, l1, l2);
- // std::cout << e << ':' << l1 << ','
<< l2 << 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;
// }
- compute_pseudo_tree(w, g, ls, a,
- e_to_labels);
+
+ // -> pseudo-tree
+
+ compute_pseudo_tree(w, g, ls, a, e_to_l1_l2);
}
Index: theo/esiee/laurent/ismm09/cplx2d.hh
--- theo/esiee/laurent/ismm09/cplx2d.hh (revision 0)
+++ theo/esiee/laurent/ismm09/cplx2d.hh (revision 0)
@@ -0,0 +1,148 @@
+
+#include <mln/core/image/image2d.hh>
+#include <mln/core/alias/neighb2d.hh>
+#include <mln/make/double_neighb2d.hh>
+
+#include <mln/pw/all.hh>
+#include <mln/core/image/image_if.hh>
+#include <mln/core/routine/extend.hh>
+
+#include <mln/data/paste.hh>
+
+#include <mln/morpho/gradient.hh>
+
+
+namespace mln
+{
+
+
+
+ template <typename I, typename J>
+ void data__paste_values(const Image<I>& input_, Image<J>& output_)
+ {
+ const I& input = exact(input_);
+ J& output = exact(output_);
+
+ mln_fwd_piter(I) pi(input.domain());
+ mln_fwd_piter(J) po(output.domain());
+ for_all_2(pi, po)
+ output(po) = input(pi);
+ }
+
+
+
+ namespace cplx2d
+ {
+
+ // Neighborhoods.
+
+ typedef neighb< win::multiple<window2d, bool(*)(const point2d&)> >
dbl_neighb2d;
+
+ inline
+ bool is_row_odd(const point2d& p)
+ {
+ return p.row() % 2;
+ }
+
+ // Edge to (the couple of) pixels.
+ const dbl_neighb2d& e2p()
+ {
+ static bool e2p_h[] = { 0, 1, 0,
+ 0, 0, 0,
+ 0, 1, 0 };
+ static bool e2p_v[] = { 0, 0, 0,
+ 1, 0, 1,
+ 0, 0, 0 };
+ static dbl_neighb2d nbh = make::double_neighb2d(is_row_odd, e2p_h, e2p_v);
+ return nbh;
+ }
+
+
+ // Edge to neighboring edges.
+ const dbl_neighb2d& e2e()
+ {
+ static bool e2e_h[] = { 0, 0, 1, 0, 0,
+ 0, 1, 0, 1, 0,
+ 0, 0, 0, 0, 0,
+ 0, 1, 0, 1, 0,
+ 0, 0, 1, 0, 0 };
+ static bool e2e_v[] = { 0, 0, 0, 0, 0,
+ 0, 1, 0, 1, 0,
+ 1, 0, 0, 0, 1,
+ 0, 1, 0, 1, 0,
+ 0, 0, 0, 0, 0 };
+ static dbl_neighb2d nbh = make::double_neighb2d(is_row_odd, e2e_h, e2e_v);
+ return nbh;
+ }
+
+
+ // Predicates.
+
+ typedef fun::C<bool (*)(const mln::point2d&)> predicate_t;
+
+ inline
+ bool is_pixel(const point2d& p)
+ {
+ // Original pixels.
+ return p.row() % 2 == 0 && p.col() % 2 == 0;
+ }
+
+ inline
+ bool is_edge(const point2d& p)
+ {
+ // Edges between pixels.
+ return p.row() % 2 + p.col() % 2 == 1;
+ }
+
+ inline
+ bool is_point(const point2d& p)
+ {
+ // Points in-between pixels.
+ return p.row() % 2 && p.col() % 2;
+ }
+
+
+
+ image_if< image2d<value::int_u8>, predicate_t >
+ f_to_g(const image2d<value::int_u8>& f)
+ {
+ image2d<value::int_u8> f_(2 * f.nrows() - 1, 2 * f.ncols() - 1);
+ data::fill(f_, 0); // Useless but for display!
+
+ data__paste_values(f, (f_ | is_pixel).rw());
+
+ mln_VAR(g, f_ | is_edge);
+ data::paste(morpho::gradient(extend(g, f_),
+ e2p().win()),
+ g);
+
+ return g;
+ }
+
+
+ template <typename W>
+ image2d<mln_value(W)>
+ extend_w_edges_to_all_faces(W& w)
+ {
+ mln_VAR(w_ext, w.unmorph_());
+
+ // edges (1D-faces) -> pixels (2D-faces)
+ data::paste(morpho::dilation(extend(w_ext | is_pixel,
+ pw::value(w_ext)),
+ c4().win()),
+ w_ext);
+
+ // edges (1D-faces) -> points (0D-faces)
+ data::paste(morpho::erosion(extend(w_ext | is_point,
+ pw::value(w_ext)),
+ c4().win()),
+ w_ext);
+
+ return w_ext;
+ }
+
+
+
+ } // end of namespace mln::cplx2d
+
+} // end of namespace mln
Index: theo/esiee/laurent/ismm09/util.hh
--- theo/esiee/laurent/ismm09/util.hh (revision 3285)
+++ theo/esiee/laurent/ismm09/util.hh (working copy)
@@ -1,4 +1,14 @@
+#include <mln/core/concept/function.hh>
+#include <mln/core/site_set/p_array.hh>
+
+#include <mln/level/sort_psites.hh>
+
+#include <mln/morpho/tree/data.hh>
+#include <mln/morpho/tree/compute_attribute_image.hh>
+
+
+
namespace mln
{
Index: theo/esiee/laurent/ismm09/pseudo_tree.hh
--- theo/esiee/laurent/ismm09/pseudo_tree.hh (revision 0)
+++ theo/esiee/laurent/ismm09/pseudo_tree.hh (revision 0)
@@ -0,0 +1,449 @@
+
+#include <mln/core/concept/image.hh>
+#include <mln/core/site_set/p_queue.hh>
+#include <mln/core/site_set/p_priority.hh>
+#include <mln/data/fill.hh>
+#include <mln/util/array.hh>
+
+
+
+namespace mln
+{
+
+
+ // Function-Object "e -> (l1, l2)".
+
+ template <typename W, typename N>
+ struct e_to_l1_l2_t
+ {
+ const W& w;
+ const N& nbh;
+ typedef mln_value(W) L;
+
+ e_to_l1_l2_t(const W& w, const N& nbh)
+ : w(w), nbh(nbh)
+ {
+ }
+
+ template <typename E>
+ void operator()(const E& e, // in
+ L& l1, // out
+ L& l2 // out
+ ) const
+ {
+ mln_niter(N) n(nbh, e);
+ n.start();
+ l1 = w(n);
+ n.next();
+ l2 = w(n);
+ mln_invariant(l2 != l1);
+ if (l1 > l2)
+ std::swap(l1, l2);
+ }
+ };
+
+ template <typename W, typename N>
+ e_to_l1_l2_t<W, N>
+ function_e_to_l1_l2(const W& w, const N& nbh)
+ {
+ e_to_l1_l2_t<W, N> tmp(w, nbh);
+ return tmp;
+ }
+
+
+
+ template <typename A, typename L>
+ util::array<L>
+ 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(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> 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_l1_l2, //
in
+ E& e, L& l1, L& l2) // 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();
+
+ e_to_l1_l2(e, l1, l2);
+
+ 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_l1_l2)
+ {
+
+ 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_l1_l2(e, l1, l2);
+ 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.
+ L l1, l2;
+ E e;
+ get_smallest_edge(q, // in-out
+ l, w, lpar, e_to_l1_l2, // in
+ e, l1, l2); // out
+
+ 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;
+ }
+ }
+
+ }
+
+} // end of namespace mln
+
Index: theo/color/change_attributes.hh
--- theo/color/change_attributes.hh (revision 3285)
+++ theo/color/change_attributes.hh (working copy)
@@ -77,6 +77,9 @@
const T* t;
};
+
+ // Vachier's version.
+
template <typename T, typename I, typename M>
inline
mln_value(I)
@@ -92,9 +95,30 @@
return a(p) = extinct_rec(t, a, mark, t.parent(p));
}
+
+ // Modified version.
+
+ template <typename T, typename I, typename M>
+ inline
+ mln_value(I)
+ extinct_rec__(const T& t, // tree
+ const I& a, // original attribute image
+ I& ea, // extincted attribute image
+ M& mark,
+ const mln_psite(I)& p)
+ {
+ mln_invariant(mark(p) == false);
+ mark(p) = true;
+ if (t.parent(p) == p || mark(t.parent(p)) == true) // Stop.
+ return a(t.parent(p)); // The parent attribute!
+ return ea(p) = extinct_rec__(t, a, ea, mark, t.parent(p));
+ }
+
+
} // end of internal
+ // Vachier's version.
template <typename T, typename I>
void
@@ -128,6 +152,44 @@
+ // Modified version.
+
+ template <typename T, typename I>
+ void
+ extinct_attributes__(const T& t, // Tree.
+ I& a) // Attribute image.
+ {
+ typedef mln_site(I) P;
+ typedef mln_value(I) A; // Type of attributes.
+
+ mln_ch_value(I, bool) mark;
+ initialize(mark, a);
+ data::fill(mark, false);
+
+ mln_concrete(I) ea = duplicate(a);
+
+ internal::node_pred<T> node_only;
+ node_only.t = &t;
+
+ typedef p_array<P> S;
+ S s = level::sort_psites_increasing(a | node_only);
+ mln_invariant(geom::nsites(a | t.nodes()) == s.nsites());
+
+ mln_fwd_piter(S) p(s);
+ for_all(p)
+ {
+ if (mark(p) == true)
+ continue;
+ internal::extinct_rec__(t, a, ea, mark, p);
+ }
+
+ data::fill(a, ea);
+
+ // debug::println(mark | t.nodes());
+ }
+
+
+
// Move down.
// ----------