3346: Add code to merge components thanks to a graph.

* lazzara/irm/wst_rag.cc: New. Related to IGR. --- milena/sandbox/ChangeLog | 6 + milena/sandbox/lazzara/irm/wst_rag.cc | 307 +++++++++++++++++++++++++++++++++ 2 files changed, 313 insertions(+), 0 deletions(-) create mode 100644 milena/sandbox/lazzara/irm/wst_rag.cc diff --git a/milena/sandbox/ChangeLog b/milena/sandbox/ChangeLog index a223445..0fbfa8b 100644 --- a/milena/sandbox/ChangeLog +++ b/milena/sandbox/ChangeLog @@ -1,3 +1,9 @@ +2009-02-09 Guillaume Lazzara <z@lrde.epita.fr> + + Add code to merge components thanks to a graph. + + * lazzara/irm/wst_rag.cc: New. Related to IGR. + 2009-02-10 Edwin Carlinet <carlinet@lrde.epita.fr> Make leveling filter and mean accumulator clean. diff --git a/milena/sandbox/lazzara/irm/wst_rag.cc b/milena/sandbox/lazzara/irm/wst_rag.cc new file mode 100644 index 0000000..3aa0935 --- /dev/null +++ b/milena/sandbox/lazzara/irm/wst_rag.cc @@ -0,0 +1,307 @@ +#include <mln/essential/2d.hh> +#include <mln/core/alias/vec3d.hh> +#include <mln/debug/draw_graph.hh> +#include <mln/util/graph.hh> +#include <mln/accu/center.hh> +#include <mln/io/dump/all.hh> +#include <mln/value/label_16.hh> +#include <mln/value/label_8.hh> +#include <mln/value/rgb8.hh> +#include <mln/value/rgb16.hh> +#include <mln/accu/compute.hh> +#include <mln/core/alias/dpoint2d.hh> +#include <mln/draw/box.hh> +#include <mln/level/stretch.hh> +#include <mln/canvas/morpho/algebraic_union_find.hh> +#include <mln/fun/v2v/id.hh> +#include <mln/core/image/line_graph_elt_neighborhood.hh> +#include <mln/morpho/elementary/dilation.hh> +#include <mln/labeling/mean_values.hh> + +#include <mln/extract/all.hh> + +namespace mln +{ + + + template <typename I, typename N> + util::graph + make_graph(const I& w, const N& nbh, const mln_value(I)& nbasins) + { + + image2d<bool> adj(box2d(nbasins.next(), nbasins.next())); + data::fill(adj, false); + + typedef mln_value(I) L; + L l1, l2; + mln_piter(I) p(w.domain()); + mln_niter(N) n(nbh, p); + for_all(p) + { + if (w(p) != 0u) + continue; + // p is in the watershed line. + l1 = l2 = 0; + for_all(n) + if (w.has(n) && w(n) != 0u) + { + if (l1 == 0u) // First label to be stored. + l1 = w(n); + else + if (w(n) != l1) // Useless: && l2 == 0) + { // Second label to be stored. + mln_invariant(l2 == 0u); + l2 = w(n); + break; + } + } + if (l2 == 0u || l1 == 0u) + continue; + if (l2 < l1) + std::swap(l1, l2); + + // adjacency l1 l2 + adj(point2d(l1,l2)) = true; + adj(point2d(l2,l1)) = true; + } + + // Construct graph. + util::graph g; + g.add_vertices(nbasins.next()); + for (unsigned i = 1; i < geom::nrows(adj); ++i) + for (unsigned j = 1; j < i; ++j) + if (adj(point2d(i,j))) + g.add_edge(i, j); + + return g; + } + + + + + template <typename V> + value::int_u8 dist(const V& c1, const V& c2) + { + unsigned d = 0; + d += (math::diff_abs(c1.red(), c2.red()) + 2) / 3; + d += (math::diff_abs(c1.green(), c2.green()) + 2) / 3; + d += (math::diff_abs(c1.blue(), c2.blue()) + 2) / 3; + if (d > 255) + d = 255; + return d; + } + + + template <typename I> + inline + pw::image<fun::i2v::array<value::int_u8>, p_edges<util::graph, fun::i2v::array<mln_site(I)> > > + make_edge_graph_image(const I& ima_v, const util::graph& g) // image on graph vertices; value = mean color per vertex (watershed basin) + { + + // edge sites. + typedef fun::i2v::array<mln_site(I)> edge_site_t; + edge_site_t edge_site(g.e_nmax(), literal::origin); + typedef p_edges<util::graph, edge_site_t > pe_t; + pe_t pe(g, edge_site); + + // edge values + typedef fun::i2v::array<value::int_u8> edge_values_t; + edge_values_t edge_values(g.e_nmax()); + + // image on graph edges + typedef pw::image<edge_values_t, pe_t> ima_e_t; + ima_e_t ima_e = (edge_values | pe); + + mln_piter(ima_e_t) e(ima_e.domain()); + for_all(e) // in ima_e + ima_e(e) = dist(ima_v.function()(e.element().v1()), + ima_v.function()(e.element().v2())); + + return ima_e; + } + + + template <typename I, typename J> + inline + util::array<mln_value(I)> + mean_color_values(const I& input, const J& w, mln_value(J) nbasins) + { + // Cf. sandbox/theo/color/segment_rgb_pixels.cc + + util::array<vec3d_f> m_3f = labeling::compute(accu::mean<mln_value(I)>(), + input, // input color image + w, // watershed labeling + nbasins); + m_3f[0] = literal::zero; + + util::array<mln_value(I)> m; + convert::from_to(m_3f, m); + m[0] = literal::yellow; + + io::ppm::save(level::transform(w, + convert::to< fun::i2v::array<mln_value(I)> >(m)), + "wst_rag_wshd_color.ppm"); + + return m; + } + + template <typename I, typename J> + pw::image<fun::i2v::array<mln_value(I)>, p_vertices<util::graph, fun::i2v::array<mln_site(I)> > > + make_vertex_graph_image(const util::graph& g, const I&input, + const J& w, const mln_value(J)& nbasins) + { + typedef util::array<mln_site(I)> vertex_sites_t; + vertex_sites_t site_values; + convert::from_to(labeling::compute(accu::center<mln_site(I)>(), w, nbasins), site_values); + + typedef fun::i2v::array<mln_site(J)> f_sites_t; + f_sites_t sites; + convert::from_to(site_values, sites); + + // p_vertices + typedef p_vertices<util::graph, f_sites_t> S; + S pv(g, sites); + + + typedef fun::i2v::array<mln_value(I)> vertex_values_t; + vertex_values_t vertex_values; + convert::from_to(mean_color_values(input, w, nbasins), vertex_values); + + mln_VAR(ima_v, (vertex_values | pv)); + + return ima_v; + } + + + template <typename I, typename V> + struct edge_to_color : Function_p2v< edge_to_color<I,V> > + { + typedef V result; + + edge_to_color(const I& ima) + : ima_(ima) + { + } + + V + operator()(const unsigned& e) const + { + return convert::to<V>(ima_.function()(e)); + } + + const I& ima_; + }; + + template <typename V> + inline + unsigned + find_root(util::array<V>& parent, const unsigned& x) + { + if (parent[x] == x) + return x; + else + return parent[x] = find_root(parent, parent[x]); + } + + + template <typename I, typename V, typename E> + inline + image2d<mln_value(I)> + make_debug_graph_image(const I& input, const V& ima_v, const E& ima_e, unsigned box_size) + { + image2d<mln_value(I)> ima; + initialize(ima, input); + + data::fill(ima, literal::white); + debug::draw_graph(ima, ima_v.domain(), + pw::cst(mln_value(I)(literal::green)), + edge_to_color<E, mln_value(I)>(ima_e)); + + dpoint2d tl(-box_size,-box_size); + dpoint2d br(box_size,box_size); + mln_piter(V) p(ima_v.domain()); + for_all(p) + { + box2d b(p + tl, p + br); + b.crop_wrt(ima.domain()); + data::fill((ima | b).rw(), convert::to<mln_value(I)>(ima_v(p))); + } + + return ima; + } + +} + + +int main(int, char *argv[]) +{ + using namespace mln; + + using value::int_u16; + using value::int_u8; + using value::label_16; + using value::label_8; + using value::rgb16; + using value::rgb8; + + typedef image2d<rgb8> I; + typedef image2d<label_16> J; + + unsigned box_size = atoi(argv[3]); + + I input; + io::ppm::load(input, argv[1]); +// image2d<rgb16> input = level::convert(rgb16(), input_); + + J vol; + io::dump::load(vol, argv[2]); + + label_16 nbasins = 898; + std::cout << "nbasins = " << nbasins << std::endl; + + util::graph g = make_graph(vol, c4(), nbasins); + + mln_VAR(ima_v, make_vertex_graph_image(g, input, vol, nbasins)); + mln_VAR(ima_e, make_edge_graph_image(ima_v, g)); + + //DEBUG +// io::ppm::save(make_debug_graph_image(input, ima_v, ima_e, box_size), "wst_rag_graph_image.ppm"); + + + mln_piter_(ima_e_t) e(ima_e.domain()); + util::array<label_16> parent(g.v_nmax()); + for (unsigned i = 0; i < parent.nelements(); ++i) + parent[i] = i; + + for_all(e) + { + unsigned v1 = e.element().v1(); + unsigned v2 = e.element().v2(); + if (ima_e(e) <= (unsigned)(atoi(argv[4])) + && find_root(parent, v1) != find_root(parent, v2)) + parent[find_root(parent, v1)] = find_root(parent, v2); + } + + fun::i2v::array<label_16> f(parent.nelements()); + std::vector<unsigned> new_label(parent.nelements(), 0); + unsigned nbasins2 = 0; + for (unsigned i = 0; i < parent.nelements(); ++i) + { + unsigned p = find_root(parent, i); + if (new_label[p] == 0) + new_label[p] = nbasins2++; + f(i) = new_label[p]; + } + mln_invariant(f(0) == 0); + --nbasins2; //nbasins2 does not count the basin with label 0. + std::cout << "nbasins2 = " << nbasins2 << std::endl; + + J vol2 = level::transform(vol, f); + util::graph g2 = make_graph(vol2, c4(), nbasins2); + mln_VAR(ima_v2, make_vertex_graph_image(g2, input, vol2, nbasins2)); + mln_VAR(ima_e2, make_edge_graph_image(ima_v2, g2)); + + J vol2_ = morpho::elementary::dilation(vol2, c4()); + io::ppm::save(labeling::mean_values(input, vol2_, nbasins2), "wst_rag_mean_colors.ppm"); + io::ppm::save(make_debug_graph_image(input, ima_v2, ima_e2, box_size), "wst_rag_graph_image2.ppm"); +} -- 1.5.6.5
participants (1)
-
Guillaume Lazzara