
https://svn.lrde.epita.fr/svn/oln/trunk/milena/sandbox Index: ChangeLog from Thierry Geraud <thierry.geraud@lrde.epita.fr> Update color segmentation. * theo/color/segment.cc: Update. * theo/color/change_attributes.hh: New. change_attributes.hh | 203 ++++++++++++++++++++++++++++++++++++++++++++++++++ segment.cc | 206 +++++++++++++++++++++++++++++++++------------------ 2 files changed, 340 insertions(+), 69 deletions(-) Index: theo/color/segment.cc --- theo/color/segment.cc (revision 3207) +++ theo/color/segment.cc (working copy) @@ -8,6 +8,8 @@ #include <mln/core/alias/neighb2d.hh> #include <mln/make/double_neighb2d.hh> +#include <mln/value/label_8.hh> + #include <mln/core/image/image_if.hh> #include <mln/pw/all.hh> #include <mln/core/routine/extend.hh> @@ -38,6 +40,8 @@ #include <mln/accu/volume.hh> #include "sum_pix.hh" +#include "change_attributes.hh" + namespace mln @@ -327,34 +331,6 @@ } - template <typename A, typename T> - inline - mln_ch_value(typename T::function, mln_result(A)) - compute_rand_attribute_on_nodes(const A& a, const T& t) - { - typedef typename T::function I; - - mln_ch_value(I, mln_result(A)) attr; - initialize(attr, t.f()); - - // Initialize every attribute with the corresponding pixel. - { - mln_piter(I) p(t.f().domain()); - for_all(p) - attr(p) = float(std::rand() % 10000) / 1000.f; - } - - // Propagate attribute from a site to its parent. - { - mln_fwd_piter(T) p(t.domain()); - for_all(p) - if (! t.is_root(p)) - attr(t.parent(p)) += attr(p); - } - - return attr; - } - // Tree -> nchildren (on nodes). @@ -393,6 +369,7 @@ mln_concrete(typename T::function) filter(const A& a, const T& t, const N& nbh, unsigned n_objects, + unsigned& less, mln_value(A)& lambda, bool echo = false) { @@ -411,28 +388,38 @@ if (n_objects >= n_regmins_f) { std::cout << "warning: number of expected objects is greater than number of regmins!" << std::endl; - std::cout << "aborting..." << std::endl; - return duplicate(t.f()); + std::cout << "aborting!" << std::endl; + std::abort(); } lambda = mln_max(mln_value(A)); - mln_ch_value(typename T::function, unsigned) nchildren = compute_nchildren(t); + mln_ch_value(I, unsigned) nchildren = compute_nchildren(t); + if (echo) + debug::println("nchildren (before) =", nchildren | t.nodes()); typedef p_array<mln_site(I)> S; S s = my_sort_increasing(a, t.nodes()); const typename T::parent_t& par = t.parent_image(); - unsigned - count = n_regmins_f, + unsigned count = n_regmins_f; less = 0; + + // For display only. + mln_ch_value(I, bool) filtered; + initialize(filtered, t.f()); + data::fill(filtered, false); + mln_fwd_piter(S) p(s); for_all(p) { if (a(p) < lambda && par(p) != p) { mln_assertion(nchildren(par(p)) > 0); + + filtered(p) = true; // For display only. + --nchildren(par(p)); if (nchildren(par(p)) != 0) { @@ -446,18 +433,26 @@ lambda = a(p) + 1; std::cout << "lambda = " << lambda << std::endl << std::endl; - // break; // Stop iterations. + break; // Stop iterations. + } } } } + + if (echo) + { + back_propagate(filtered, t); + debug::println("filtered =", filtered); + debug::println("a < lambda = ", (pw::value(a) < pw::cst(lambda)) | a.domain()); } + if (less != 0) std::cerr << "WARNING: less objects (" << less << ") than expected..." << std::endl << std::endl; if (echo) - debug::println("nchildren =", nchildren | t.nodes()); + debug::println("nchildren (after) =", nchildren | t.nodes()); // Filtering. mln_concrete(I) g; @@ -477,45 +472,107 @@ if (echo) { unsigned n_regmins_g; - debug::println( "regmin(g)", labeling::regional_minima(g, nbh, n_regmins_g) ); + mln_VAR(regmin_g, labeling::regional_minima(g, nbh, n_regmins_g)); + debug::println( "regmin(g)", regmin_g); + debug::println("a | regmin(g) = ", a | (pw::value(regmin_g) != 0)); + } return g; } + template <typename A, typename I, typename N> void test_filter(A a, mln_result(A) lambda, const I& f, const I& g, const N& nbh, + unsigned n_objects, unsigned less, bool echo = false) { mln_concrete(I) g_ref = morpho::closing_attribute<A>(f, nbh, lambda); - if (echo) - debug::println("g_ref =", g_ref); unsigned n_regmins_g_ref; - mln_ch_value(I, unsigned) regmin_g = labeling::regional_minima(g_ref, nbh, n_regmins_g_ref); -// if (echo) - std::cout << "n_regmins(g_ref) = " << n_regmins_g_ref << std::endl - << std::endl; + mln_ch_value(I, unsigned) regmin_g_ref = labeling::regional_minima(g_ref, nbh, n_regmins_g_ref); + bool consistency = (n_regmins_g_ref + less == n_objects); if (g != g_ref) { std::cerr << "OOPS: g DIFFERS FROM ref!" << std::endl << std::endl; -// debug::println("diff", (pw::value(g_ref) == pw::value(g)) | g.domain()); + debug::println("diff = ", (pw::value(g_ref) == pw::value(g)) | g.domain()); -// debug::println("g_ref", g_ref); -// debug::println("g", g); -// debug::println("regmin_g", regmin_g); + debug::println("g_ref =", g_ref); + debug::println("regmin(g_ref) =", regmin_g_ref); + std::cout << "n_regmins(g_ref) = " << n_regmins_g_ref << std::endl + << std::endl; } -// bool consistency = (n_regmins_g_ref + less == n_objects); -// if (consistency == false) -// std::cerr << "OOPS: INCONSISTENCY (BUG...)!" << std::endl -// << std::endl; + if (consistency == false) + { + std::cerr << "OOPS: INCONSISTENCY (BUG...)!" << std::endl + << " n_regmins(g_ref) = " << n_regmins_g_ref << std::endl + << " n_less = " << less << std::endl + << " n_objects = " << n_objects << std::endl + << std::endl; + + debug::println("diff = ", (pw::value(g_ref) == pw::value(g)) | g.domain()); + + debug::println("g_ref =", g_ref); + debug::println("regmin(g_ref) =", regmin_g_ref); + std::cout << "n_regmins(g_ref) = " << n_regmins_g_ref << std::endl + << std::endl; + + } + } + + + + // Filter facade. + + template <typename F, typename N, typename A> + inline + mln_concrete(F) + filter_color(const F& f, // a "gradient" of color image + const N& nbh, + const A& a_, // an attribute + bool do_extinction, + unsigned n_objects, + bool echo = false) + { + typedef p_array<mln_psite(F)> S; + S s = level::sort_psites_decreasing(f); + + typedef morpho::tree::data<F,S> tree_t; + tree_t t(f, s, nbh); + + mln_VAR(a, compute_attribute_on_nodes(a_, t)); + back_propagate(a, t); + + if (echo) + { + debug::println("par =", t.parent_image() | t.nodes()); + debug::println("a =", a | t.nodes()); + debug::println("a = ", a); + } + if (do_extinction) + extinct_attributes(t, a); + if (echo) + debug::println("a' =", a | t.nodes()); + + + mln_value(a_t) lambda; + unsigned less; + mln_concrete(F) g = filter(a, t, nbh, n_objects, // input + less, lambda, // output + echo); + + test_filter(a_, lambda, f, g, nbh, + n_objects, less, + echo); + + return g; } @@ -526,8 +583,10 @@ void usage(char* argv[]) { - std::cerr << "usage: " << argv[0] << " input.ppm n output.ppm" << std::endl; + std::cerr << "usage: " << argv[0] << " input.ppm n extinction output.ppm echo" << std::endl; std::cerr << " n >= 2" << std::endl; + std::cerr << " extinction = 0 (none) or 1 (effective)" << std::endl; + std::cerr << " echo = 0 (mute) or 1 (verbose)" << std::endl; abort(); } @@ -539,7 +598,7 @@ using value::int_u8; using value::rgb8; - if (argc != 4) + if (argc != 6) usage(argv); @@ -554,6 +613,9 @@ unsigned n_objects = atoi(argv[2]); + bool do_extinction = atoi(argv[3]); + bool echo = atoi(argv[5]); + // Changing input into 'f on edges'. @@ -567,14 +629,6 @@ typedef f_t I; - // Filtering f -> g. - - typedef p_array<point2d> S; - S s = level::sort_psites_decreasing(f); - - typedef morpho::tree::data<I,S> tree_t; - tree_t t(f, s, e2e()); - // accu::count< util::pix<I> > a_; // accu::volume<I> a_; // accu::sum_pix< util::pix<I> > a_; @@ -582,22 +636,36 @@ blen_image = input_; accu::blen_pix<I> a_; - mln_VAR(a, compute_attribute_on_nodes(a_, t)); + f_t g = filter_color(f, e2e(), + a_, do_extinction, + n_objects, + echo); - mln_value_(a_t) lambda; - f_t g = filter(a, t, e2e(), n_objects, lambda); + if (echo) + debug::println("activity (g != f) = ", (pw::value(g) != pw::value(f)) | f.domain()); - test_filter(a_, lambda, f, g, e2e()); + // Watershed transform. + typedef value::label_8 L; + L nbasins; + mln_ch_value_(f_t, L) w = morpho::meyer_wst(g, e2e(), nbasins); - // Watershed transform. + // io::pgm::save(display_edge(w.unmorph_(), 0, 3), "temp_w.pgm"); - int_u8 nbasins; - mln_ch_value_(f_t, int_u8) w_edges = morpho::meyer_wst(g, e2e(), nbasins); + if (echo) + { + image2d<int_u8> g_(f_.domain()); - // io::pgm::save(display_edge(w_edges.unmorph_(), 0, 3), "temp_w_edges.pgm"); + data::fill(g_, 0); + data::paste(g | (pw::value(w) != 0), g_); + debug::println("g | basins = ", g_ | is_edge); + + data::fill(g_, 0); + data::paste(g | (pw::value(w) == 0), g_); + debug::println("g | w line = ", g_ | is_edge); + } - image2d<int_u8> w_all = w_edges.unmorph_(); + image2d<L> w_all = w.unmorph_(); { // edges -> squares mln_VAR(w_squares, w_all | is_square); Index: theo/color/change_attributes.hh --- theo/color/change_attributes.hh (revision 0) +++ theo/color/change_attributes.hh (revision 0) @@ -0,0 +1,203 @@ +namespace mln +{ + + + // Display. + // -------- + + + template <typename T, typename I> + void display_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; + } + + + + // Back-propagate values from nodes to component sites. + // ---------------------------------------------------- + + template <typename A, typename T> + void + back_propagate(A& a, const T& t) + { + mln_fwd_piter(T) p(t.domain()); + for_all(p) + if (! t.is_a_node(p)) + { + mln_assertion(t.is_a_node(t.parent(p))); + a(p) = a(t.parent(p)); + } + } + + + + + // Attribute Extinction. + // --------------------- + + namespace internal + { + + 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, typename M> + inline + mln_value(I) + extinct_rec(const T& t, // tree + I& a, // 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(p); + return a(p) = extinct_rec(t, a, mark, t.parent(p)); + } + + } // end of internal + + + + 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); + + 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, mark, p); + } + + // debug::println(mark | t.nodes()); + } + + + + // Move down. + // ---------- + + template <typename A, typename T> + inline + void + move_down_attributes(A& a, const T& t) + { + typedef typename T::nodes_t N; + mln_fwd_piter(N) n(t.nodes()); + for_all(n) + a(n) = a(t.parent(n)); + + for_all(n) + mln_invariant(a(n) <= a(t.parent(n))); + } + + + + + // Fuse down. + // ---------- + + template <typename A, typename T> + inline + void + fuse_down_attributes(A& a, const T& t) + { + typedef typename T::nodes_t N; + mln_fwd_piter(N) n(t.nodes()); + for_all(n) + a(n) = (a(n) + a(t.parent(n))) / 2; + + for_all(n) + mln_invariant(a(n) <= a(t.parent(n))); + } + + + + // Rand. + // ----- + + template <typename A, typename T> + inline + mln_ch_value(typename T::function, mln_result(A)) + compute_rand_attribute_on_nodes(const A& a, const T& t) + { + typedef typename T::function I; + + mln_ch_value(I, mln_result(A)) attr; + initialize(attr, t.f()); + + // Initialize every attribute with the corresponding pixel. + { + mln_piter(I) p(t.f().domain()); + for_all(p) + attr(p) = float(std::rand() % 10000) / 1000.f; + } + + // Propagate attribute from a site to its parent. + { + mln_fwd_piter(T) p(t.domain()); + for_all(p) + if (! t.is_root(p)) + attr(t.parent(p)) += attr(p); + } + + return attr; + } + + + +} // end of namespace mln
participants (1)
-
Thierry Geraud