3173: Augment Laurent's ISMM code.

https://svn.lrde.epita.fr/svn/oln/trunk/milena/sandbox Index: ChangeLog from Thierry Geraud <thierry.geraud@lrde.epita.fr> Augment Laurent's ISMM code. * laurent/playing_with_attributes.cc: Augment. * laurent/ismm2009.cc: Memorize as... * laurent/ismm2009.v2.cc: ...this new file. * laurent/ismm2009.cc: Augment. ismm2009.cc | 67 ++++++++----- ismm2009.v2.cc | 67 ++++++++----- playing_with_attributes.cc | 224 +++++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 299 insertions(+), 59 deletions(-) Index: laurent/ismm2009.cc --- laurent/ismm2009.cc (revision 3172) +++ laurent/ismm2009.cc (working copy) @@ -1,10 +1,13 @@ #include "ismm2009.hh" #include <mln/value/int_u8.hh> + +#include <mln/io/pgm/load.hh> +#include <mln/io/pgm/save.hh> + #include <mln/value/label_8.hh> #include <mln/value/label_16.hh> -#include <mln/io/pgm/load.hh> #include <mln/util/ord_pair.hh> #include <mln/debug/println.hh> #include <mln/core/routine/duplicate.hh> @@ -18,14 +21,9 @@ /* - TO-DO list: - ----------- - - - having a heap for every lr (support merge) - handling adjacency on the fly (instead of having an image) - */ @@ -266,7 +264,7 @@ typename N_e2e, typename L > mln_ch_value(G, L) - f_to_wst_unique_g(F& f, // On pixels. + compute_wst_g_from_f(F& f, // On pixels. G& g, // On edges. const N_e2p& e2p, const N_e2e& e2e, @@ -277,7 +275,7 @@ e2p.win()), g); - // FIXME: Here, we want a unique value per edge! +# ifdef MAKE_UNIQUE if (echo) debug::println("g (before):", g); @@ -311,6 +309,9 @@ } } +# endif // MAKE_UNIQUE + + mln_VAR( wst_g, morpho::meyer_wst(g, e2e, n_basins) ); @@ -333,8 +334,9 @@ void usage(char* argv[]) { - std::cerr << "usage: " << argv[0] << " input.pgm" << std::endl; - std::cerr << "Laurent ISMM 2009 scheme." << std::endl; + 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; abort(); } @@ -347,14 +349,20 @@ using value::int_u8; using value::label_16; - bool echo = true; - - if (argc != 2) + if (argc != 4) usage(argv); image2d<int_u8> raw_f; io::pgm::load(raw_f, argv[1]); + bool echo; + { + int echo_ = std::atoi(argv[2]); + if (echo_ != 0 && echo_ != 1) + usage(argv); + echo = bool(echo_); + } + typedef image2d<int_u8> Complex; typedef mln_pset_(Complex) full_D; @@ -372,15 +380,9 @@ L n_basins; - mln_VAR( wst_g, - f_to_wst_g(f, g, e2p(), e2e(), n_basins) ); - - /* - UNIQUE: mln_VAR( wst_g, - f_to_wst_unique_g(f, g, e2p(), e2e(), n_basins, echo) ); - */ + compute_wst_g_from_f(f, g, e2p(), e2e(), n_basins, echo) ); if (echo) @@ -501,11 +503,12 @@ std::vector<pair_t> v = sort_attributes(a, n_basins); // Sort regions. + // Optional code (for testing purpose): change attributes + // so that they are all different. - // Maybe activate to test purpose: - /* +# ifdef MAKE_UNIQUE make_unique_attribute(a, v, n_basins, echo); - */ +# endif // Display attributes. @@ -796,13 +799,13 @@ // +---------------------------------------------------------------+ - { - // Dealing with the watershed line. mln_VAR(aa_line, aa | is_line); { + + { // First, processing the 1D-faces (edges) of the watershed line. std::vector< std::vector<E> > lca; @@ -886,16 +889,26 @@ } if (echo) - debug::println("aa | basins", aa_basins); + debug::println("aa | basins:", aa_basins); } - if (echo) debug::println("aa:", aa); + + // Output is salency map. + { + + image2d<int_u8> output(f_.domain()); + data::fill(output, 0); + data::paste(aa_line, output); + io::pgm::save(output, argv[3]); + } + + } // end of main Index: laurent/playing_with_attributes.cc --- laurent/playing_with_attributes.cc (revision 3172) +++ laurent/playing_with_attributes.cc (working copy) @@ -13,6 +13,10 @@ #include <mln/morpho/tree/compute_attribute_image.hh> #include <mln/labeling/regional_minima.hh> +#include <mln/core/site_set/p_array.hh> +#include <mln/level/sort_psites.hh> +#include <mln/geom/nsites.hh> + #include <mln/accu/count.hh> @@ -26,6 +30,200 @@ +namespace mln +{ + + + template <typename T> + struct node_pred : Function_p2b< node_pred<T> > + { + typedef bool result; + + template <typename P> + bool operator()(const P& p) const + { + return t->is_a_node(p); + } + + const T* t; + }; + + + + template <typename T, typename I> + void depict_tree_attributes(const T& t, // Tree. + const I& a) // Attribute image. + { + typedef mln_site(I) P; + + mln_ch_value(I, bool) deja_vu; + initialize(deja_vu, a); + data::fill(deja_vu, false); + + typedef typename T::nodes_t nodes_t; + mln_fwd_piter(nodes_t) p(t.nodes()); + for_all(p) + { + if (deja_vu(p)) + continue; + + P e = p; + do + { + std::cout << a(e) << ':' << e << " -> "; + deja_vu(e) = true; + e = t.parent(e); + } + while (! deja_vu(e)); + std::cout << a(e) << ':' << e << std::endl; + } + std::cout << std::endl; + } + + + template <typename T, typename I> + mln_concrete(I) + change_tree_attributes(const T& t, // Tree. + const I& a, // Attribute image. + bool echo = false) + { + typedef mln_site(I) P; + typedef mln_value(I) A; // Type of attributes. + + // Test that attributes increase with parenthood. + mln_fwd_piter(T) p(t.domain()); + for_all(p) + if (t.is_a_non_root_node(p)) + { + mln_assertion(t.is_a_node(t.parent(p))); + mln_invariant(a(t.parent(p)) >= a(p)); + } + + + if (echo) + depict_tree_attributes(t, a); + + + 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_ch_value(I, bool) mark; + initialize(mark, a); + data::fill(mark, false); + + + // Modify attributes. + + mln_concrete(I) aa; + initialize(aa, a); + data::fill(aa, 0); + + { + + P e, par_e; + A v; + bool found; + + mln_fwd_piter(S) p(s); + + // Initialization. + for_all(p) + { + if (mark(p) == true) + continue; + + // First, fetch the attribute value v from p; + e = p; + found = false; + while (mark(e) == false && e != t.parent(e)) + { + par_e = t.parent(e); + if (mark(par_e) == true) + { + v = a(e); + found = true; + break; + } + e = par_e; + }; + + if (! found && e == t.parent(e)) + { + // e is a root node; we get its value: + v = a(e); + + if (echo) + std::cout << "from p = " << p + << " to root e = " << e + << " v = " << v + << std::endl; + + // we set aa from p to the root node + e = p; + do + { + aa(e) = v; + mln_invariant(mark(e) == false); + mark(e) = true; + e = t.parent(e); + } + while (e != t.parent(e)); + // handle the root node 'e': + aa(e) = v; + mln_invariant(mark(e) == false); + mark(e) = true; + mln_invariant(a(e) == v); + } + else if (found) + { + e = p; + + P last_e = P(0,0); + + while (mark(e) == false) + { + aa(e) = v; + mark(e) = true; + last_e = e; + e = t.parent(e); + }; + + if (echo) + { + if (last_e == p) + std::cout << "p = " << p + << " par(e) = " << par_e + << " so keep v = " << v + << std::endl; + else + std::cout << "from p = " << p + << " to e = " << last_e + << " with par(e) = " << par_e + << " v = " << v + << std::endl; + } + } + } + + if (echo) + depict_tree_attributes(t, aa); + + } // end of Modify attributes. + + return aa; + } + + + +} // mln + + + template <typename I, typename N, typename L> void do_it(const I& g, const N& nbh, L& n_labels) { @@ -34,7 +232,7 @@ // regional minima mln_ch_value(I,L) regmin = labeling::regional_minima(g, nbh, n_labels); - debug::println("regmin(g):", regmin); + // debug::println("regmin(g):", regmin); // watershed @@ -42,7 +240,7 @@ L n_basins; mln_ch_value(I,L) w = morpho::meyer_wst(g, nbh, n_basins); mln_invariant(n_basins == n_labels); - debug::println("w(g):", w); + // debug::println("w(g):", w); { @@ -55,12 +253,28 @@ accu::count< util::pix<I> > a_; // Kind of attribute. mln_ch_value(I,unsigned) a = morpho::tree::compute_attribute_image(a_, t); - debug::println("a:", a); + debug::println("a | nodes:", a | t.nodes()); + + mln_ch_value(I,unsigned) aa = change_tree_attributes(t, a); + debug::println("aa | nodes:", aa | t.nodes()); + + // Back-propagation from nodes to components. + { + mln_fwd_piter(tree_t) p(t.domain()); + for_all(p) + if (! t.is_a_node(p)) + { + mln_assertion(t.is_a_node(t.parent(p))); + aa(p) = aa(t.parent(p)); + } + } debug::println("a | w line:", a | (pw::value(w) == pw::cst(0))); - debug::println("a | w basins:", a | (pw::value(w) != pw::cst(0))); + debug::println("aa | w line:", aa | (pw::value(w) == pw::cst(0))); + +// debug::println("a | w basins:", a | (pw::value(w) != pw::cst(0))); +// debug::println("a | regmin:", a | (pw::value(regmin) != pw::cst(0))); - debug::println("a | regmin:", a | (pw::value(regmin) != pw::cst(0))); } } // end of do_it Index: laurent/ismm2009.v2.cc --- laurent/ismm2009.v2.cc (revision 3172) +++ laurent/ismm2009.v2.cc (working copy) @@ -1,10 +1,13 @@ #include "ismm2009.hh" #include <mln/value/int_u8.hh> + +#include <mln/io/pgm/load.hh> +#include <mln/io/pgm/save.hh> + #include <mln/value/label_8.hh> #include <mln/value/label_16.hh> -#include <mln/io/pgm/load.hh> #include <mln/util/ord_pair.hh> #include <mln/debug/println.hh> #include <mln/core/routine/duplicate.hh> @@ -18,14 +21,9 @@ /* - TO-DO list: - ----------- - - - having a heap for every lr (support merge) - handling adjacency on the fly (instead of having an image) - */ @@ -266,7 +264,7 @@ typename N_e2e, typename L > mln_ch_value(G, L) - f_to_wst_unique_g(F& f, // On pixels. + compute_wst_g_from_f(F& f, // On pixels. G& g, // On edges. const N_e2p& e2p, const N_e2e& e2e, @@ -277,7 +275,7 @@ e2p.win()), g); - // FIXME: Here, we want a unique value per edge! +# ifdef MAKE_UNIQUE if (echo) debug::println("g (before):", g); @@ -311,6 +309,9 @@ } } +# endif // MAKE_UNIQUE + + mln_VAR( wst_g, morpho::meyer_wst(g, e2e, n_basins) ); @@ -333,8 +334,9 @@ void usage(char* argv[]) { - std::cerr << "usage: " << argv[0] << " input.pgm" << std::endl; - std::cerr << "Laurent ISMM 2009 scheme." << std::endl; + 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; abort(); } @@ -347,14 +349,20 @@ using value::int_u8; using value::label_16; - bool echo = true; - - if (argc != 2) + if (argc != 4) usage(argv); image2d<int_u8> raw_f; io::pgm::load(raw_f, argv[1]); + bool echo; + { + int echo_ = std::atoi(argv[2]); + if (echo_ != 0 && echo_ != 1) + usage(argv); + echo = bool(echo_); + } + typedef image2d<int_u8> Complex; typedef mln_pset_(Complex) full_D; @@ -372,15 +380,9 @@ L n_basins; - mln_VAR( wst_g, - f_to_wst_g(f, g, e2p(), e2e(), n_basins) ); - - /* - UNIQUE: mln_VAR( wst_g, - f_to_wst_unique_g(f, g, e2p(), e2e(), n_basins, echo) ); - */ + compute_wst_g_from_f(f, g, e2p(), e2e(), n_basins, echo) ); if (echo) @@ -501,11 +503,12 @@ std::vector<pair_t> v = sort_attributes(a, n_basins); // Sort regions. + // Optional code (for testing purpose): change attributes + // so that they are all different. - // Maybe activate to test purpose: - /* +# ifdef MAKE_UNIQUE make_unique_attribute(a, v, n_basins, echo); - */ +# endif // Display attributes. @@ -796,13 +799,13 @@ // +---------------------------------------------------------------+ - { - // Dealing with the watershed line. mln_VAR(aa_line, aa | is_line); { + + { // First, processing the 1D-faces (edges) of the watershed line. std::vector< std::vector<E> > lca; @@ -886,16 +889,26 @@ } if (echo) - debug::println("aa | basins", aa_basins); + debug::println("aa | basins:", aa_basins); } - if (echo) debug::println("aa:", aa); + + // Output is salency map. + { + + image2d<int_u8> output(f_.domain()); + data::fill(output, 0); + data::paste(aa_line, output); + io::pgm::save(output, argv[3]); + } + + } // end of main
participants (1)
-
Thierry Geraud