https://svn.lrde.epita.fr/svn/oln/branches/cleanup-2008/milena/sandbox
Index: ChangeLog
from Thierry Geraud <thierry.geraud(a)lrde.epita.fr>
Add kruskal algorithm in a sample morphological chain.
* geraud/cs2d/kruskal.cc: New.
kruskal.cc | 357 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 357 insertions(+)
Index: geraud/cs2d/kruskal.cc
--- geraud/cs2d/kruskal.cc (revision 0)
+++ geraud/cs2d/kruskal.cc (revision 0)
@@ -0,0 +1,357 @@
+# include <vector>
+
+# include <mln/core/image2d.hh>
+# include <mln/core/sub_image.hh>
+# include <mln/core/image_if.hh>
+# include <mln/core/image_if_value.hh>
+
+# include <mln/core/neighb2d.hh>
+# include <mln/core/window2d.hh>
+# include <mln/convert/to_window.hh>
+
+# include <mln/debug/println.hh>
+# include <mln/debug/iota.hh>
+# include <mln/fun/p2v/iota.hh>
+# include <mln/level/paste.hh>
+# include <mln/level/fill.hh>
+# include <mln/morpho/gradient.hh>
+# include <mln/morpho/meyer_wst.hh>
+
+# include <mln/level/sort_points.hh>
+
+# include <mln/io/pgm/load.hh>
+# include <mln/io/ppm/save.hh>
+# include <mln/value/int_u8.hh>
+# include <mln/pw/all.hh>
+# include <mln/win/rectangle2d.hh>
+
+# include <mln/value/rgb8.hh>
+# include <mln/literal/black.hh>
+# include <mln/literal/white.hh>
+# include <mln/literal/colors.hh>
+
+# include <mln/labeling/regional_minima.hh>
+
+# include "dbl_neighb.hh"
+
+
+
+// KRUSKAL-MST(G, w)
+// T := Ø
+// for each vertex u in V
+// MAKE-SET(DS, u)
+// end for
+// for each edge (u,v) in E in order of nondecreasing weight
+// if FIND-SET(DS, u) != FIND-SET(DS, v)
+// UNION-SET(DS, u, v)
+// T := T U {(u,v)}
+// end for
+// return T
+
+
+
+struct is_cell_t : mln::Function_p2b<is_cell_t>
+{
+ typedef bool result;
+ bool operator()(const mln::point2d& p) const
+ {
+ return p.row() % 2 == 0 && p.col() % 2 == 0;
+ }
+}
+ is_cell;
+
+struct is_edge_t : mln::Function_p2b<is_edge_t>
+{
+ typedef bool result;
+ bool operator()(const mln::point2d& p) const
+ {
+ return p.row() % 2 + p.col() % 2 == 1;
+ }
+}
+ is_edge;
+
+struct is_point_t : mln::Function_p2b<is_point_t>
+{
+ typedef bool result;
+ bool operator()(const mln::point2d& p) const
+ {
+ return p.row() % 2 && p.col() % 2;
+ }
+}
+ is_point;
+
+
+struct is_row_odd_t
+ {
+ bool operator()(const mln::point2d& p) const
+ {
+ return p.row() % 2;
+ }
+ } is_row_odd;
+
+
+template<typename T_t>
+struct is_tree_t : mln::Function_p2b< is_tree_t<T_t> >
+{
+ typedef bool result;
+ bool operator()(const mln::point2d& p) const
+ {
+ return p.row() % 2 + p.col() % 2 == 1 && T(p) == true;
+ }
+ T_t T;
+};
+
+namespace mln
+{
+
+ template <typename E>
+ image2d<value::rgb8> show_edge(const E& edge,
+ unsigned nrows,unsigned ncols,
+ unsigned clen)
+ {
+ mln_precondition(clen % 2); // oddity
+
+ typedef win::hline2d H;
+ H hline(clen);
+
+ typedef win::vline2d V;
+ V vline(clen);
+
+ box2d b(nrows * clen + 3 * (nrows - 1),
+ ncols * clen + 3 * (ncols - 1));
+ image2d<value::rgb8> output(b);
+ level::fill(output, literal::black);
+
+
+ // 0 1 2 3 4
+ // 0 c e c e c
+ // 1 e x e x e
+ // 2 c e c e c
+
+ // 0 1 2 3 4 5 6 7 8 9 10
+
+ // 0 c c c . e . c c c . e . c c c
+ // 1 c c c . e . c c c . e . c c c
+ // 2 c c c . e . c c c . e . c c c
+ // 3 . . . . . . . . . . . . . . .
+ // 4 e e e . x . e e e . x . e e e
+ // 5 . . . . . . . . . . . . . . .
+ // 6 c c c . e . c c c . e . c c c
+ // 7 c c c . e . c c c . e . c c c
+ // 8 c c c . e . c c c . e . c c c
+
+ // Edges.
+ mln_piter(E) e(edge.domain());
+ for_all(e)
+ {
+ value::rgb8 v;
+ if (edge(e))
+ v = literal::red;
+ else
+ v = literal::black;
+ point2d e_ = e, p_;
+ if (e_.row() % 2) // Odd => horizontal.
+ {
+ p_.row() = clen + 1 + (clen + 3) * (e_.row() / 2); // vertex-like
+ p_.col() = clen / 2 + (clen + 3) * (e_.col() / 2); // cell-like
+ mln_qiter(V) q(hline, p_);
+ for_all(q) if (output.has(q))
+ output(q) = v;
+ }
+ else // Even => vertical.
+ {
+ p_.row() = clen / 2 + (clen + 3) * (e_.row() / 2); // cell-like
+ p_.col() = clen + 1 + (clen + 3) * (e_.col() / 2); // vertex-like
+ mln_qiter(H) q(vline, p_);
+ for_all(q) if (output.has(q))
+ output(q) = v;
+ }
+ }
+
+ return output;
+ }
+
+} // mln
+
+
+#define mln_alias(Var, Expr) typeof(Expr) Var = Expr;
+
+
+template <typename DS_t, typename U>
+void make_set(DS_t& DS, const U& u)
+{
+ DS(u) = u;
+}
+
+
+template <typename DS_t, typename U>
+U find_set(DS_t& DS, U u)
+{
+ if (DS(u) == u) // is root
+ return u;
+ return DS(u) = find_set(DS, DS(u));
+}
+
+
+template <typename DS_t, typename U>
+void union_set(DS_t& DS, const U& u, const U& v)
+{
+ U ru = find_set(DS, u),
+ rv = find_set(DS, v);
+ mln_precondition(ru != rv);
+ if (rv > ru)
+ DS(ru) = rv;
+ else
+ DS(rv) = ru;
+}
+
+
+
+int main()
+{
+ using namespace mln;
+ using value::int_u8;
+
+ window2d c4 = convert::to_window(mln::c4());
+
+
+ typedef dbl_neighb_<dpoint2d, is_row_odd_t> nbh_t;
+ nbh_t nbh_e2c, win_p_e2c, nbh_e2e;
+
+ {
+ bool e2c_h[] = { 0, 1, 0,
+ 0, 0, 0,
+ 0, 1, 0 };
+
+ bool e2c_v[] = { 0, 0, 0,
+ 1, 0, 1,
+ 0, 0, 0 };
+ nbh_e2c
+ .when_true (make::neighb2d(e2c_h))
+ .when_false(make::neighb2d(e2c_v));
+
+ win_p_e2c = nbh_e2c;
+ win_p_e2c
+ .insert_true(make::dpoint2d(0,0))
+ .insert_false(make::dpoint2d(0,0));
+
+ 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 };
+
+ 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 };
+ nbh_e2e
+ .when_true (make::neighb2d(e2e_h))
+ .when_false(make::neighb2d(e2e_v));
+ }
+
+ typedef image2d<int_u8> I;
+
+ image2d<int_u8> input;
+ io::pgm::load(input, "fly.pgm");
+
+ image2d<int_u8> ima(input.nrows() * 2 - 1,
+ input.ncols() * 2 - 1, 0);
+
+ mln_alias(cell, ima | is_cell);
+ typedef typeof(cell) cell_t;
+ debug::println(cell);
+
+ {
+ mln_fwd_piter_(I) pi(input.domain());
+ mln_fwd_piter_(cell_t) pc(cell.domain());
+ for_all_2(pi, pc)
+ cell(pc) = input(pi);
+ }
+
+ mln_alias(edge, ima | is_edge);
+ level::paste(morpho::gradient(edge, nbh_e2c), edge);
+ // ^^^^^^^
+ // edge -> neighboring cells
+
+ debug::println(edge);
+
+ typedef typeof(edge) edge_t;
+
+ typedef p_array<point2d> Arr;
+ Arr E = level::sort_points_increasing(edge);
+
+ // Aux data.
+ mln_ch_value_(edge_t, bool) T;
+ initialize(T, edge);
+ level::fill(T, false);
+
+ mln_ch_value_(cell_t, point2d) DS;
+ initialize(DS, cell);
+
+ {
+ mln_piter_(cell_t) u(cell.domain());
+ for_all(u) // in V
+ make_set(DS, u);
+ }
+
+ {
+ mln_fwd_piter_(Arr) uv(E);
+ for_all(uv)
+ {
+ point2d
+ uv_ = uv.to_point(),
+ u, v;
+ if (uv_.row() % 2)
+ u = uv_ + up, v = uv_ + down;
+ else
+ u = uv_ + left, v = uv_ + right;
+ if (find_set(DS, u) != find_set(DS, v))
+ {
+ union_set(DS, u, v);
+ T(uv) = true;
+ }
+ }
+ }
+
+ debug::println(T);
+
+ mln_alias(is_T, pw::value(T) == pw::cst(true));
+
+ mln_alias(dom, (T | is_T).domain());
+ typedef typeof(dom) dom_t;
+
+ io::ppm::save(show_edge(T, input.nrows(), input.ncols(), 7),
+ "edge.ppm");
+
+
+ typedef typeof(T) T_t;
+ is_tree_t<T_t> is_tree;
+ is_tree.T = T;
+ // [*] See EOF.
+
+ unsigned nbasins;
+ mln_alias(wst, morpho::meyer_wst(ima | is_tree, nbh_e2e, nbasins) );
+ std::cout << "nbasins : " << nbasins << std::endl;
+
+ {
+ mln_piter_(dom_t) e(dom);
+ mln_niter_(nbh_t) n(nbh_e2c, e);
+ for_all(e)
+ if (wst(e) != 0)
+ for_all(n)
+ cell(n) = wst(e);
+ debug::println(cell);
+ }
+
+}
+
+// [*] FIXME: "edge | is_T" does not properly work because of
+// initialization failure of the predicate function (pw expr do not
+// have ctor without arg so the init cannot be delayed). As a
+// consequence, we cannot have the following code:
+//
+// mln_alias(tree, edge | is_T);
+// typedef typeof(tree) tree_t;
+// morpho::meyer_wst(tree, nbh_e2e, nbasins);