
https://svn.lrde.epita.fr/svn/oln/trunk/milena/sandbox Index: ChangeLog from Thierry Geraud <thierry.geraud@lrde.epita.fr> Update segmentation scheme. * theo/color/segment.cc: Move some contents into... * theo/color/segment.hh: ...this new file. * theo/color/segment_debase.cc: New. segment.cc | 355 -------------------------------------------- segment.hh | 431 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ segment_debase.cc | 103 ++++++++++++ 3 files changed, 537 insertions(+), 352 deletions(-) Index: theo/color/segment.hh --- theo/color/segment.hh (revision 0) +++ theo/color/segment.hh (revision 0) @@ -0,0 +1,431 @@ +#include <cstdlib> + +#include <mln/core/var.hh> +#include <mln/core/site_set/p_array.hh> + +#include <mln/data/fill.hh> +#include <mln/util/ord.hh> +#include <mln/make/pix.hh> +#include <mln/debug/println.hh> + +#include <mln/level/sort_psites.hh> +#include <mln/labeling/regional_minima.hh> +#include <mln/pw/all.hh> + +#include <mln/morpho/tree/data.hh> +#include <mln/morpho/closing_attribute.hh> + +#include "change_attributes.hh" + + + +namespace mln +{ + + + // Sorting. + + + template <typename I> + struct my_less_ + { + const I& ima_; + + inline + my_less_(const I& ima) + : ima_(ima) + { + } + + inline + bool operator()(const mln_site(I)& lhs, + const mln_site(I)& rhs) const + { + return util::ord_strict(ima_(lhs), ima_(rhs)) + || (ima_(lhs) == ima_(rhs) + && + util::ord_strict(lhs, rhs)); + } + }; + + + template <typename I, typename S> + p_array<mln_site(I)> my_sort_increasing(const I& ima, const S& s) + { + p_array<mln_site(I)> v; + convert::from_to(s, v); + std::sort(v.hook_std_vector_().begin(), v.hook_std_vector_().end(), + my_less_<I>(ima)); + return v; + } + + + + + // Tree -> attributes (on nodes only). + // ----------------------------------- + + + + template <typename A, typename T> + inline + mln_ch_value(typename T::function, mln_result(A)) + compute_attribute_on_nodes(const A& a, const T& t) + { + typedef typename T::function I; + + mln_ch_value(I, A) acc; + mln_ch_value(I, mln_result(A)) attr; + + // Initialization of 'acc'. + { + initialize(acc, t.f()); + data::fill(acc, a); // Transfer "dynamic data" (state) of 'a'. + } + + // Initialize every attribute with the corresponding pixel. + { + mln_piter(I) p(t.f().domain()); + for_all(p) + acc(p).take_as_init(make::pix(t.f(), p)); + } + + // Propagate attribute from a site to its parent. + { + mln_fwd_piter(T) p(t.domain()); + for_all(p) + if (! t.is_root(p)) + acc(t.parent(p)).take(acc(p)); + // No back-propagation to non-node sites. + } + + + // Change accumulator into its result. + { + initialize(attr, acc); + typedef typename T::nodes_t N; + mln_piter(N) p(t.nodes()); + for_all(p) + { + mln_invariant(t.is_a_node(p)); + attr(p) = acc(p).to_result(); + } + } + + return attr; + } + + + + + // Tree -> nchildren (on nodes). + // ----------------------------- + + + template <typename T> + inline + mln_ch_value(typename T::function, unsigned) + compute_nchildren(const T& t) + { + typedef typename T::function I; + mln_ch_value(I, unsigned) nchildren; + initialize(nchildren, t.f()); + data::fill(nchildren, 0); + + { + mln_fwd_piter(T) p(t.domain()); + // Propagate attribute from a site to its parent. + for_all(p) + if (t.is_a_non_root_node(p)) + { + mln_invariant(t.is_a_node(t.parent(p))); + ++nchildren(t.parent(p)); // so parent(p) is a node + } + } + + return nchildren; + } + + + + + template <typename A, typename T, typename N> + inline + mln_concrete(typename T::function) + run_filter(const A& a, const T& t, const N& nbh, + unsigned n_objects, + unsigned& less, + mln_value(A)& lambda, + bool echo = false) + { + typedef typename T::function I; + + unsigned n_regmins_f; // This value can be obtained while computing the attributes! + mln_ch_value(I, unsigned) regmins_f = labeling::regional_minima(t.f(), nbh, n_regmins_f); + if (echo) + { + debug::println("f =", t.f()); + debug::println("regmins(f) =", regmins_f); + // debug::println("par on nodes = ", t.parent_image() | t.nodes()); + std::cout << "n regmins(f) = " << n_regmins_f << std::endl + << std::endl; + } + 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; + std::abort(); + } + + lambda = mln_max(mln_value(A)); + + 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; + 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) + break; + + 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) + { + if (count <= n_objects) + { + ++less; // minus 1 object wrt the expected number! + } + --count; + if (count == n_objects) + { + lambda = a(p) + 1; + std::cout << "lambda = " << lambda << std::endl + << std::endl; + } + } + } + } + + 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 (after) =", nchildren | t.nodes()); + + // Filtering. + mln_concrete(I) g; + { + initialize(g, t.f()); + mln_bkd_piter(T) p(t.domain()); + for_all(p) + if (t.is_a_node(p) && a(p) >= lambda) + g(p) = t.f(p); + else + g(p) = g(par(p)); + + if (echo) + debug::println("g =", g); + } + + if (echo) + { + unsigned 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); + + unsigned n_regmins_g_ref; + 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); + + bool wrong_filtering = (g != g_ref); + + if (wrong_filtering) + { + std::cerr << "OOPS: g DIFFERS FROM ref!" << std::endl + << std::endl; + if (echo) + { + 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; + } + } + + 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; + + if (echo && ! wrong_filtering) + { + 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(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 = run_filter(a, t, nbh, n_objects, // input + less, lambda, // output + echo); + + if (do_extinction == false) + test_filter(a_, lambda, f, g, nbh, + n_objects, less, + echo); + + return g; + } + + + + // Granulometry. + + template <typename F, typename N, typename A> + inline + void + gran_filter(const F& f, const N& nbh, const A& a_) + { + typedef p_array<mln_psite(F)> S; + S s = level::sort_psites_decreasing(f); + + typedef morpho::tree::data<F,S> T; + T t(f, s, nbh); + + mln_VAR(a, compute_attribute_on_nodes(a_, t)); + back_propagate(a, t); + + + unsigned n_regmins_f; // This value can be obtained while computing the attributes! + mln_ch_value(F, unsigned) regmins_f = labeling::regional_minima(t.f(), nbh, n_regmins_f); + + mln_ch_value(F, unsigned) nchildren = compute_nchildren(t); + + { + + typedef p_array<mln_site(F)> S; + S s = my_sort_increasing(a, t.nodes()); + + const typename T::parent_t& par = t.parent_image(); + unsigned count = n_regmins_f; + + mln_fwd_piter(S) p(s); + p.start(); + std::ofstream file("gran.txt"); + file << a(p) << ' ' << count << std::endl; + + for_all(p) + { + if (par(p) != p) + { + mln_assertion(nchildren(par(p)) > 0); + --nchildren(par(p)); + if (nchildren(par(p)) != 0) + { + --count; + file << a(p) << ' ' << count << std::endl; + } + } + } + file.close(); + + } + + } + + + +} // end of namespace mln Index: theo/color/segment.cc --- theo/color/segment.cc (revision 3210) +++ theo/color/segment.cc (working copy) @@ -1,6 +1,3 @@ -#include <cstdlib> - -#include <mln/core/var.hh> #include <mln/core/image/image2d.hh> #include <mln/core/alias/box3d.hh> @@ -11,7 +8,6 @@ #include <mln/value/label_8.hh> #include <mln/core/image/image_if.hh> -#include <mln/pw/all.hh> #include <mln/core/routine/extend.hh> #include <mln/core/routine/duplicate.hh> #include <mln/data/paste.hh> @@ -23,26 +19,19 @@ #include <mln/math/diff_abs.hh> -#include <mln/debug/println.hh> - #include <mln/morpho/dilation.hh> #include <mln/morpho/erosion.hh> -#include <mln/morpho/tree/data.hh> #include <mln/morpho/meyer_wst.hh> -#include <mln/morpho/closing_attribute.hh> - -#include <mln/core/site_set/p_array.hh> -#include <mln/level/sort_psites.hh> -#include <mln/labeling/regional_minima.hh> #include <mln/accu/count.hh> #include <mln/accu/volume.hh> #include "sum_pix.hh" -#include "change_attributes.hh" +#include "segment.hh" + namespace mln { @@ -238,344 +227,6 @@ } - // Sorting. - - - template <typename I> - struct my_less_ - { - const I& ima_; - - inline - my_less_(const I& ima) - : ima_(ima) - { - } - - inline - bool operator()(const mln_site(I)& lhs, - const mln_site(I)& rhs) const - { - return util::ord_strict(ima_(lhs), ima_(rhs)) - || (ima_(lhs) == ima_(rhs) - && - util::ord_strict(lhs, rhs)); - } - }; - - - template <typename I, typename S> - p_array<mln_site(I)> my_sort_increasing(const I& ima, const S& s) - { - p_array<mln_site(I)> v; - convert::from_to(s, v); - std::sort(v.hook_std_vector_().begin(), v.hook_std_vector_().end(), - my_less_<I>(ima)); - return v; - } - - - - - // Tree -> attributes (on nodes only). - // ----------------------------------- - - - - template <typename A, typename T> - inline - mln_ch_value(typename T::function, mln_result(A)) - compute_attribute_on_nodes(const A& a, const T& t) - { - typedef typename T::function I; - - mln_ch_value(I, A) acc; - mln_ch_value(I, mln_result(A)) attr; - - // Initialization of 'acc'. - { - initialize(acc, t.f()); - data::fill(acc, a); // Transfer "dynamic data" (state) of 'a'. - } - - // Initialize every attribute with the corresponding pixel. - { - mln_piter(I) p(t.f().domain()); - for_all(p) - acc(p).take_as_init(make::pix(t.f(), p)); - } - - // Propagate attribute from a site to its parent. - { - mln_fwd_piter(T) p(t.domain()); - for_all(p) - if (! t.is_root(p)) - acc(t.parent(p)).take(acc(p)); - // No back-propagation to non-node sites. - } - - - // Change accumulator into its result. - { - initialize(attr, acc); - typedef typename T::nodes_t N; - mln_piter(N) p(t.nodes()); - for_all(p) - { - mln_invariant(t.is_a_node(p)); - attr(p) = acc(p).to_result(); - } - } - - return attr; - } - - - - - // Tree -> nchildren (on nodes). - // ----------------------------- - - - template <typename T> - inline - mln_ch_value(typename T::function, unsigned) - compute_nchildren(const T& t) - { - typedef typename T::function I; - mln_ch_value(I, unsigned) nchildren; - initialize(nchildren, t.f()); - data::fill(nchildren, 0); - - { - mln_fwd_piter(T) p(t.domain()); - // Propagate attribute from a site to its parent. - for_all(p) - if (t.is_a_non_root_node(p)) - { - mln_invariant(t.is_a_node(t.parent(p))); - ++nchildren(t.parent(p)); // so parent(p) is a node - } - } - - return nchildren; - } - - - - - template <typename A, typename T, typename N> - inline - 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) - { - typedef typename T::function I; - - unsigned n_regmins_f; // This value can be obtained while computing the attributes! - mln_ch_value(I, unsigned) regmins_f = labeling::regional_minima(t.f(), nbh, n_regmins_f); - if (echo) - { - debug::println("f =", t.f()); - debug::println("regmins(f) =", regmins_f); - // debug::println("par on nodes = ", t.parent_image() | t.nodes()); - std::cout << "n regmins(f) = " << n_regmins_f << std::endl - << std::endl; - } - 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; - std::abort(); - } - - lambda = mln_max(mln_value(A)); - - 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; - 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) - { - if (count <= n_objects) - { - ++less; // minus 1 object wrt the expected number! - } - --count; - if (count == n_objects) - { - lambda = a(p) + 1; - std::cout << "lambda = " << lambda << std::endl - << std::endl; - 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 (after) =", nchildren | t.nodes()); - - // Filtering. - mln_concrete(I) g; - { - initialize(g, t.f()); - mln_bkd_piter(T) p(t.domain()); - for_all(p) - if (t.is_a_node(p) && a(p) >= lambda) - g(p) = t.f(p); - else - g(p) = g(par(p)); - - if (echo) - debug::println("g =", g); - } - - if (echo) - { - unsigned 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); - - unsigned n_regmins_g_ref; - 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("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; - } - - 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; - } - - } // mln @@ -636,7 +287,7 @@ blen_image = input_; accu::blen_pix<I> a_; - f_t g = filter_color(f, e2e(), + f_t g = filter(f, e2e(), a_, do_extinction, n_objects, echo); Index: theo/color/segment_debase.cc --- theo/color/segment_debase.cc (revision 0) +++ theo/color/segment_debase.cc (revision 0) @@ -0,0 +1,103 @@ + +#include <mln/core/image/image2d.hh> +#include <mln/core/image/image_if.hh> +#include <mln/core/alias/neighb2d.hh> + +#include <mln/value/int_u8.hh> +#include <mln/value/label_8.hh> +#include <mln/value/rgb8.hh> +#include <mln/literal/colors.hh> + +#include <mln/io/pgm/load.hh> +#include <mln/io/ppm/save.hh> +#include <mln/io/pgm/save.hh> + +#include <mln/level/convert.hh> + +#include <mln/morpho/elementary/gradient.hh> +#include <mln/morpho/meyer_wst.hh> + +#include <mln/accu/volume.hh> +#include "sum_pix.hh" + +#include "segment.hh" + + + + + +void usage(char* argv[]) +{ + std::cerr << "usage: " << argv[0] << " input.pgm 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(); +} + + + +int main(int argc, char* argv[]) +{ + using namespace mln; + + using value::int_u8; + using value::rgb8; + + + if (argc != 6) + usage(argv); + + + // Gray-level debase version. + // -------------------------- + + typedef image2d<int_u8> I; + + I input; + io::pgm::load(input, argv[1]); + + unsigned n_objects = atoi(argv[2]); + bool do_extinction = atoi(argv[3]); + bool echo = atoi(argv[5]); + + + // Neighborhood. + mln_VAR(nbh, c4()); + + + // Changing input into 'f'. + + I f = morpho::elementary::gradient(input, c4()); + io::pgm::save(f, "temp_f.pgm"); + + + // // granulometry: + // gran_filter(f, c4(), a_); + + + + // accu::count< util::pix<I> > a_; + // accu::sum_pix< util::pix<I> > a_; + accu::volume<I> a_; + + I g = filter(f, c4(), + a_, do_extinction, + n_objects, + echo); + + if (echo) + debug::println("activity (g != f) = ", (pw::value(g) != pw::value(f)) | f.domain()); + + + // Watershed transform. + + typedef value::label_8 L; + L nbasins; + mln_ch_value_(I, L) w = morpho::meyer_wst(g, c4(), nbasins); + + image2d<rgb8> output = level::convert(rgb8(), input); + data::fill((output | (pw::value(w) == 0)).rw(), literal::red); + + io::ppm::save(output, argv[4]); +}