
* lazzara/irm/hsl_grad_and_wst.cc: perform a gradient on a HSL image and compute the watershed. * lazzara/irm/wst_rag.cc: Improve output and add a usage. * lazzara/irm/wst_rag_hsl.cc: new. Similar code to wst_rag.cc but the graph values are computed thanks to the HSL image. --- milena/sandbox/ChangeLog | 12 ++ milena/sandbox/lazzara/irm/hsl_grad_and_wst.cc | 97 ++++++++++++++ milena/sandbox/lazzara/irm/wst_rag.cc | 70 +++++++--- .../lazzara/irm/{wst_rag.cc => wst_rag_hsl.cc} | 140 +++++++++++++------- 4 files changed, 254 insertions(+), 65 deletions(-) create mode 100644 milena/sandbox/lazzara/irm/hsl_grad_and_wst.cc copy milena/sandbox/lazzara/irm/{wst_rag.cc => wst_rag_hsl.cc} (72%) diff --git a/milena/sandbox/ChangeLog b/milena/sandbox/ChangeLog index b90be00..d96c70e 100644 --- a/milena/sandbox/ChangeLog +++ b/milena/sandbox/ChangeLog @@ -1,3 +1,15 @@ +2009-02-12 Guillaume Lazzara <z@lrde.epita.fr> + + Update code related to Region Adjacency Graph. + + * lazzara/irm/hsl_grad_and_wst.cc: perform a gradient on a HSL image + and compute the watershed. + + * lazzara/irm/wst_rag.cc: Improve output and add a usage. + + * lazzara/irm/wst_rag_hsl.cc: new. Similar code to wst_rag.cc but + the graph values are computed thanks to the HSL image. + 2009-02-11 Thierry Geraud <thierry.geraud@lrde.epita.fr> Cleanup pseudo-tree computation. diff --git a/milena/sandbox/lazzara/irm/hsl_grad_and_wst.cc b/milena/sandbox/lazzara/irm/hsl_grad_and_wst.cc new file mode 100644 index 0000000..f7b0335 --- /dev/null +++ b/milena/sandbox/lazzara/irm/hsl_grad_and_wst.cc @@ -0,0 +1,97 @@ +#include <mln/essential/2d.hh> +#include <mln/value/hsl.hh> +#include <mln/core/image/violent_cast_image.hh> +#include <mln/extract/all.hh> +#include <mln/value/label_16.hh> +#include <mln/value/int_u8.hh> +#include <mln/morpho/closing_area.hh> +#include <mln/io/dump/save.hh> + +mln::value::int_u8 foo(unsigned u) +{ + return u == 0 ? + 0 : // wshed line + 1 + (u - 1) % 255; // basin +} + + +namespace mln +{ + + struct hsl2rgb : Function_v2v<hsl2rgb> + { + typedef value::rgb8 result; + + value::rgb8 operator()(const value::hsl_f& v) const + { + value::rgb8 res((v.hue() / 360.0f) * 255.0f, + v.sat() * 255.0f, + v.lum()); + return res; + } + }; + +} + + + +int main(int, char *argv[]) +{ + using namespace mln; + + using value::rgb8; + using value::hsl_f; + using value::int_u8; + using value::label_16; + + typedef value::hsl_<short, short, short> hsl_s; + typedef image2d<rgb8> I; + typedef image2d<hsl_f> J; + + I input_; + io::ppm::load(input_, argv[1]); + J input = level::convert(hsl_f(), input_); + + std::cout << "input_rgb(p) = " << input_(point2d(310,0)) << " - input_hsl(p) = " << input(point2d(310,0)) + << " hsl2rgb(p) = " << hsl2rgb()(input(point2d(310,0))) + << std::endl; + std::cout << "input_rgb(p) = " << input_(point2d(311,0)) << " - input_hsl(p) = " << input(point2d(311,0)) + << " hsl2rgb(p) = " << hsl2rgb()(input(point2d(311,0))) + << std::endl; + + /// Compute the gradient on each component of the HSL image. + /// Then keep the max values in the three images. + image2d<float> grad_hue; + initialize(grad_hue, input); + data::fill(grad_hue, extract::hue(input)); + image2d<float> grad_sat; + initialize(grad_sat, input); + data::fill(grad_sat, extract::sat(input)); + image2d<float> grad_lum; + initialize(grad_lum, input); + data::fill(grad_lum, extract::lum(input)); + grad_hue = morpho::gradient(grad_hue, win_c4p()); + grad_sat = morpho::gradient(grad_sat, win_c4p()); + grad_lum = morpho::gradient(grad_lum, win_c4p()); + + image2d<value::int_u8> grad; + initialize(grad, grad_hue); + mln_piter_(image2d<value::int_u8>) p(grad.domain()); + for_all(p) + grad(p) = math::max(grad_hue(p), math::max(grad_sat(p), grad_lum(p))); + io::pgm::save(grad, "hsl2rgb_grad.pgm"); + + image2d<int_u8> clo = morpho::closing_area(grad, c4(), 10); + io::pgm::save(clo, "hsl2rgb_clo_a100.pgm"); + + label_16 nbasins; + image2d<label_16> wshed = morpho::meyer_wst(clo, c4(), nbasins); + io::dump::save(wshed, "hsl2rgb_wshed.dump"); + std::cout << "nbasins = " << nbasins << std::endl; + io::pgm::save(level::transform(wshed, convert::to_fun(foo)), + "hsl2rgb_wshed.pgm"); + + I out = level::transform(input, hsl2rgb()); + io::ppm::save(out, "hsl2rgb_out.ppm"); + +} diff --git a/milena/sandbox/lazzara/irm/wst_rag.cc b/milena/sandbox/lazzara/irm/wst_rag.cc index 3aa0935..e397ba7 100644 --- a/milena/sandbox/lazzara/irm/wst_rag.cc +++ b/milena/sandbox/lazzara/irm/wst_rag.cc @@ -20,6 +20,10 @@ #include <mln/extract/all.hh> + +// Given a color image and a wshed image, computes the component graph. +// Vertex values are computed thanks to a RGB image. + namespace mln { @@ -92,12 +96,13 @@ namespace mln } + // ima_v, image on graph vertices; value = mean color per vertex (watershed basin) 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) + 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) { - // edge sites. typedef fun::i2v::array<mln_site(I)> edge_site_t; edge_site_t edge_site(g.e_nmax(), literal::origin); @@ -129,9 +134,9 @@ namespace mln // 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); + input, // input color image + w, // watershed labeling + nbasins); m_3f[0] = literal::zero; util::array<mln_value(I)> m; @@ -145,14 +150,17 @@ namespace mln 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)> > > + 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); + 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; @@ -165,7 +173,8 @@ namespace mln 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); + convert::from_to(mean_color_values(input, w, nbasins), + vertex_values); mln_VAR(ima_v, (vertex_values | pv)); @@ -207,7 +216,9 @@ namespace mln 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) + 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); @@ -233,7 +244,7 @@ namespace mln } -int main(int, char *argv[]) +int main(int argc, char *argv[]) { using namespace mln; @@ -247,7 +258,19 @@ int main(int, char *argv[]) typedef image2d<rgb8> I; typedef image2d<label_16> J; - unsigned box_size = atoi(argv[3]); + if (argc < 5) + { + std::cout << argv[0] << " <input.ppm> <wsh-label16.dump> <nbasins> <box_size> <dist_max>" + << std::endl << std::endl; + + std::cout << "box_size: size of the component mean color box." << std::endl; + std::cout << "dist_max: merge two vertices if the associted edge value <= dist_max" + << std::endl; + + return 1; + } + + unsigned box_size = atoi(argv[4]); I input; io::ppm::load(input, argv[1]); @@ -256,16 +279,18 @@ int main(int, char *argv[]) J vol; io::dump::load(vol, argv[2]); - label_16 nbasins = 898; + label_16 nbasins = atoi(argv[3]); std::cout << "nbasins = " << nbasins << std::endl; util::graph g = make_graph(vol, c4(), nbasins); + // Compute value distances with a RGB image. 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"); +// 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()); @@ -277,7 +302,7 @@ int main(int, char *argv[]) { unsigned v1 = e.element().v1(); unsigned v2 = e.element().v2(); - if (ima_e(e) <= (unsigned)(atoi(argv[4])) + if (ima_e(e) <= (unsigned)(atoi(argv[5])) && find_root(parent, v1) != find_root(parent, v2)) parent[find_root(parent, v1)] = find_root(parent, v2); } @@ -298,10 +323,19 @@ int main(int, char *argv[]) J vol2 = level::transform(vol, f); util::graph g2 = make_graph(vol2, c4(), nbasins2); + // Compute value distances with a RGB image. 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"); + mln_VAR(vol2_, + morpho::elementary::dilation(extend(vol2 | (pw::value(vol2) == 0u), + vol2), + c8())); + + data::fill((vol2 | (pw::value(vol2) == 0u)).rw(), vol2_); + + 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"); } diff --git a/milena/sandbox/lazzara/irm/wst_rag.cc b/milena/sandbox/lazzara/irm/wst_rag_hsl.cc similarity index 72% copy from milena/sandbox/lazzara/irm/wst_rag.cc copy to milena/sandbox/lazzara/irm/wst_rag_hsl.cc index 3aa0935..156f1b3 100644 --- a/milena/sandbox/lazzara/irm/wst_rag.cc +++ b/milena/sandbox/lazzara/irm/wst_rag_hsl.cc @@ -1,24 +1,44 @@ #include <mln/essential/2d.hh> + + +#include <mln/core/alias/dpoint2d.hh> #include <mln/core/alias/vec3d.hh> -#include <mln/debug/draw_graph.hh> -#include <mln/util/graph.hh> +#include <mln/core/image/line_graph_elt_neighborhood.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/debug/draw_graph.hh> + +#include <mln/draw/box.hh> + +#include <mln/extract/all.hh> + #include <mln/fun/v2v/id.hh> -#include <mln/core/image/line_graph_elt_neighborhood.hh> -#include <mln/morpho/elementary/dilation.hh> + +#include <mln/io/dump/all.hh> + #include <mln/labeling/mean_values.hh> -#include <mln/extract/all.hh> +#include <mln/level/stretch.hh> + +#include <mln/morpho/elementary/dilation.hh> + +#include <mln/util/graph.hh> + +#include <mln/value/label_16.hh> +#include <mln/value/label_8.hh> +#include <mln/value/rgb16.hh> +#include <mln/value/rgb8.hh> + +#include <mln/value/hsl.hh> + + +// Given a color image and a wshed image, computes the component graph. +// Vertex values are computed thanks to a HSL image. + namespace mln { @@ -77,25 +97,24 @@ namespace mln } - - - template <typename V> - value::int_u8 dist(const V& c1, const V& c2) + value::int_u8 dist(const value::hsl_f& c1, const value::hsl_f& 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; + d += (math::diff_abs(c1.hue(), c2.hue()) + 2) / 3; + d += (math::diff_abs(c1.sat(), c2.sat()) + 2) / 3; + d += (math::diff_abs(c1.lum(), c2.lum()) + 2) / 3; if (d > 255) d = 255; return d; } + // ima_v, image on graph vertices; value = mean color per vertex (watershed basin) 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) + 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) { // edge sites. @@ -128,31 +147,29 @@ namespace mln { // 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<value::hsl_f> m_3f = labeling::compute(accu::mean<mln_value(I)>(), + input, // input color image + w, // watershed labeling + nbasins); + m_3f[0] = value::hsl_f(0,0,0);; 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"); + m[0] = value::hsl_f(360,0.5,255); 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)> > > + 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); + 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; @@ -207,7 +224,9 @@ namespace mln 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) + 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); @@ -233,7 +252,7 @@ namespace mln } -int main(int, char *argv[]) +int main(int argc, char *argv[]) { using namespace mln; @@ -243,20 +262,35 @@ int main(int, char *argv[]) using value::label_8; using value::rgb16; using value::rgb8; + using value::hsl_f; - typedef image2d<rgb8> I; +// typedef image2d<rgb8> I; + typedef image2d<rgb8> K; + typedef image2d<hsl_f> I; typedef image2d<label_16> J; - unsigned box_size = atoi(argv[3]); + if (argc < 5) + { + std::cout << argv[0] << " <input.ppm> <wsh-label16.dump> <nbasins> <box_size> <dist_max>" + << std::endl << std::endl; + + std::cout << "box_size: size of the component mean color box." << std::endl; + std::cout << "dist_max: merge two vertices if the associted edge value <= dist_max" + << std::endl; - I input; - io::ppm::load(input, argv[1]); -// image2d<rgb16> input = level::convert(rgb16(), input_); + return 1; + } + + unsigned box_size = atoi(argv[4]); + + K input_; + io::ppm::load(input_, argv[1]); + I input = level::convert(hsl_f(), input_); J vol; io::dump::load(vol, argv[2]); - label_16 nbasins = 898; + label_16 nbasins = atoi(argv[3]); std::cout << "nbasins = " << nbasins << std::endl; util::graph g = make_graph(vol, c4(), nbasins); @@ -265,7 +299,8 @@ int main(int, char *argv[]) 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"); + 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()); @@ -277,7 +312,7 @@ int main(int, char *argv[]) { unsigned v1 = e.element().v1(); unsigned v2 = e.element().v2(); - if (ima_e(e) <= (unsigned)(atoi(argv[4])) + if (ima_e(e) <= (unsigned)(atoi(argv[5])) && find_root(parent, v1) != find_root(parent, v2)) parent[find_root(parent, v1)] = find_root(parent, v2); } @@ -298,10 +333,21 @@ int main(int, char *argv[]) J vol2 = level::transform(vol, f); util::graph g2 = make_graph(vol2, c4(), nbasins2); + + // Compute values distance on the HSL Image. 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"); + mln_VAR(vol2_, + morpho::elementary::dilation(extend(vol2 | (pw::value(vol2) == 0u), + vol2), + c8())); + + data::fill((vol2 | (pw::value(vol2) == 0u)).rw(), vol2_); + + 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