r3503: Implement 3D watershed and various tools

URL: https://svn.lrde.epita.fr/svn/oln/trunk/milena/sandbox ChangeLog: 2009-03-10 Fabien Freling <fabien.freling@lrde.epita.fr> Implement 3D watershed and various tools. * fabien/bin/dicom2pgm.cc: New tool. * fabien/bin/dump2pgm.cc: New tool. * fabien/bin/dump2pgm8b.cc: New tool. * fabien/bin/dump_mask.cc: New tool. * fabien/bin/filetype.hh: New. * fabien/bin/pnms2dump.cc: New tool. * fabien/igr/Makefile: Update. * fabien/igr/check2d_wsd.sh: Shell script for testing. * fabien/igr/check3d_wsd.sh: Shell script for testing. * fabien/igr/watershed.cc: Rename this... * fabien/igr/watershed.hh: ...into this. * fabien/igr/watershed2d.cc: Implement 2D watershed. * fabien/igr/watershed3d.cc: Implement 3D watershed. --- TODO | 7 - bin/dicom2pgm.cc | 34 +++++ bin/dump2pgm.cc | 37 +++++ bin/dump2pgm8b.cc | 38 ++++++ bin/dump_mask.cc | 86 +++++++++++++ bin/filetype.hh | 54 ++++++++ bin/pnms2dump.cc | 97 +++++++++++++++ igr/Makefile | 9 - igr/check2d_wsd.sh | 32 +++++ igr/check3d_wsd.sh | 34 +++++ igr/watershed.hh | 331 ++++++++++++++++++++++++++++++++++++++++++++++++++++ igr/watershed2d.cc | 331 ++++++++++++++++++++++++++++++++++++++++++++++++++++ igr/watershed3d.cc | 334 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 13 files changed, 1419 insertions(+), 5 deletions(-) Index: trunk/milena/sandbox/fabien/igr/watershed.cc (deleted) =================================================================== Index: trunk/milena/sandbox/fabien/igr/watershed2d.cc =================================================================== --- trunk/milena/sandbox/fabien/igr/watershed2d.cc (revision 0) +++ trunk/milena/sandbox/fabien/igr/watershed2d.cc (revision 3503) @@ -0,0 +1,331 @@ +#include <iostream> +#include <mln/core/image/image2d.hh> + +#include <mln/core/alias/neighb2d.hh> +#include <mln/core/alias/window2d.hh> +#include <mln/core/image/image_if.hh> + +#include <mln/io/ppm/save.hh> +#include <mln/io/ppm/load.hh> +#include <mln/io/pgm/load.hh> +#include <mln/io/dicom/load.hh> +#include <mln/io/pgm/save.hh> +#include <mln/io/dump/save.hh> + +#include <mln/value/rgb8.hh> +#include <mln/value/int_u8.hh> +#include <mln/value/int_u12.hh> +#include <mln/value/label_16.hh> + +#include <mln/level/transform.hh> +#include <mln/level/stretch.hh> + +#include <mln/labeling/mean_values.hh> + +#include <mln/convert/to_fun.hh> + +#include <mln/make/graph.hh> + +#include <mln/morpho/gradient.hh> +#include <mln/morpho/closing/area.hh> +#include <mln/morpho/meyer_wst.hh> + +#include <mln/fun/l2l/wrap.hh> + +#include <mln/core/var.hh> +#include <mln/morpho/elementary/dilation.hh> + +#include <mln/core/routine/extend.hh> + +#include <mln/util/graph.hh> + +#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_8.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/fun/v2v/id.hh> +#include <mln/fun/l2l/wrap.hh> +#include <mln/core/image/line_graph_elt_neighborhood.hh> +#include <mln/morpho/elementary/dilation.hh> +#include <mln/labeling/mean_values.hh> +#include <mln/extension/adjust_fill.hh> +#include <mln/extract/all.hh> +#include <mln/make/region_adjacency_graph.hh> + + + +// Given a color image and a wshed image, computes the component graph. +// Vertex values are computed thanks to a RGB image. + +namespace mln +{ + + template <typename V> + value::int_u8 dist(const V& c1, const V& c2) + { + unsigned d = math::diff_abs(c1.red(), c2.red()); + unsigned d_; + d_ = math::diff_abs(c1.green(), c2.green()); + + if (d_ > d) + d = d_; + + d_ = math::diff_abs(c1.blue(), c2.blue()); + + if (d_ > d) + d = d_; + 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) + { + // 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) = math::diff_abs(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<float> 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] = 150u; + + /*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, const value::int_u12& bg) + { + image2d<mln_value(I)> ima; + initialize(ima, input); + + data::fill(ima, bg); + debug::draw_graph(ima, ima_v.domain(), + pw::cst(150u), + 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; + } + +} + + +/////////////////// +// // +// Main Function // +// // +/////////////////// + + +int main(int argc, char *argv[]) +{ + using namespace mln; + using value::int_u8; + using value::int_u12; + using value::rgb8; + using value::label_16; + + if (argc < 4) + { + std::cout << "Usage: " << argv[0] << " <ima.dcm> <closure_lambda> <box_size> <dist_max>" + << std::endl; + return 1; + } + + unsigned closure_lambda = atoi(argv[2]); + unsigned box_size = atoi(argv[3]); + unsigned dist_max = atoi(argv[4]); + + image2d<int_u12> dcm; + io::dicom::load(dcm, argv[1]); + + io::pgm::save(level::stretch(int_u8(), dcm), "wsd_01_src.pgm"); + + image2d<int_u12> grad = morpho::gradient(dcm, win_c4p()); + image2d<int_u12> clo = morpho::closing::area(grad, c4(), closure_lambda); + + label_16 nbasins; + image2d<label_16> wshed = morpho::meyer_wst(clo, c4(), nbasins); + + io::pgm::save(level::stretch(int_u8(), clo), "wsd_02.pgm"); + io::pgm::save(level::transform(wshed, fun::l2l::wrap<int_u8>()), "wsd_03.pgm"); + + mln_VAR(vol2_, morpho::elementary::dilation(extend(wshed | (pw::value(wshed) == 0u), wshed), c8())); + + data::fill((wshed | (pw::value(wshed) == 0u)).rw(), vol2_); + + io::pgm::save(level::transform(wshed, fun::l2l::wrap<int_u8>()), "wsd_04.pgm"); + + /// Build graph + util::graph g = make::graph(wshed, c4(), nbasins); + // Build graph images and compute distance values with a RGB image. + mln_VAR(ima_v, make_vertex_graph_image(g, dcm, wshed, nbasins)); + mln_VAR(ima_e, make_edge_graph_image(ima_v, g)); + + /// Try to merge vertices. + 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) <= dist_max && 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); + mln_assertion(parent[p] == find_root(parent, i)); + if (new_label[p] == 0) + new_label[p] = nbasins2++; + f(i) = new_label[p]; + } + mln_invariant(f(0) == 0u); + --nbasins2; // nbasins2 does not count the basin with label 0. + image2d<label_16> wsd2 = level::transform(wshed, f); + + io::pgm::save(level::transform(wsd2, fun::l2l::wrap<int_u8>()), "wsd_05.pgm"); + + /// Reconstruct a graph from the simplified image. + util::graph g2 = make::graph(wsd2, c4(), nbasins2); + + // Compute distance values with a RGB image. + mln_VAR(ima_v2, make_vertex_graph_image(g2, dcm, wsd2, nbasins2)); + mln_VAR(ima_e2, make_edge_graph_image(ima_v2, g2)); + + mln_VAR(wsd2_, morpho::elementary::dilation(extend(wsd2 | (pw::value(wsd2) == 0u), wsd2), c8())); + + data::fill((wsd2 | (pw::value(wsd2) == 0u)).rw(), wsd2_); + + io::pgm::save(level::transform(labeling::mean_values(dcm, wsd2, nbasins2), fun::l2l::wrap<int_u8>()), "wsd_06_mean_colors.pgm"); + io::pgm::save(level::stretch(int_u8(), make_debug_graph_image(dcm, ima_v2, ima_e2, box_size, 4095)), "wsd_07_graph_image2_white.pgm"); + io::pgm::save(level::stretch(int_u8(), make_debug_graph_image(dcm, ima_v2, ima_e2, box_size, 0)), "wsd_08_graph_image2_black.pgm"); + io::pgm::save(level::transform(wsd2, fun::l2l::wrap<int_u8>()), "wsd_99_result.pgm"); +} Index: trunk/milena/sandbox/fabien/igr/watershed3d.cc =================================================================== --- trunk/milena/sandbox/fabien/igr/watershed3d.cc (revision 0) +++ trunk/milena/sandbox/fabien/igr/watershed3d.cc (revision 3503) @@ -0,0 +1,334 @@ +#include <iostream> +#include <mln/core/image/image2d.hh> +#include <mln/core/image/image3d.hh> + +#include <mln/core/alias/neighb2d.hh> +#include <mln/core/alias/window2d.hh> +#include <mln/core/alias/neighb3d.hh> +#include <mln/core/alias/window3d.hh> +#include <mln/core/image/image_if.hh> + +#include <mln/io/ppm/save.hh> +#include <mln/io/ppm/load.hh> +#include <mln/io/pgm/load.hh> +#include <mln/io/dicom/load.hh> +#include <mln/io/pgm/save.hh> +#include <mln/io/dump/save.hh> + +#include <mln/value/rgb8.hh> +#include <mln/value/int_u8.hh> +#include <mln/value/int_u12.hh> +#include <mln/value/label_16.hh> + +#include <mln/level/transform.hh> +#include <mln/level/stretch.hh> + +#include <mln/labeling/mean_values.hh> + +#include <mln/convert/to_fun.hh> + +#include <mln/make/graph.hh> + +#include <mln/morpho/gradient.hh> +#include <mln/morpho/closing/area.hh> +#include <mln/morpho/meyer_wst.hh> + +#include <mln/fun/l2l/wrap.hh> + +#include <mln/core/var.hh> +#include <mln/morpho/elementary/dilation.hh> + +#include <mln/core/routine/extend.hh> + +#include <mln/util/graph.hh> + +#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_8.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/fun/v2v/id.hh> +#include <mln/fun/l2l/wrap.hh> +#include <mln/core/image/line_graph_elt_neighborhood.hh> +#include <mln/morpho/elementary/dilation.hh> +#include <mln/labeling/mean_values.hh> +#include <mln/extension/adjust_fill.hh> +#include <mln/extract/all.hh> +#include <mln/make/region_adjacency_graph.hh> + + + +// Given a color image and a wshed image, computes the component graph. +// Vertex values are computed thanks to a RGB image. + +namespace mln +{ + + template <typename V> + value::int_u8 dist(const V& c1, const V& c2) + { + unsigned d = math::diff_abs(c1.red(), c2.red()); + unsigned d_; + d_ = math::diff_abs(c1.green(), c2.green()); + + if (d_ > d) + d = d_; + + d_ = math::diff_abs(c1.blue(), c2.blue()); + + if (d_ > d) + d = d_; + 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) + { + // 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) = math::diff_abs(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<float> 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] = 150u; + + /*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 + image3d<mln_value(I)> + make_debug_graph_image(const I& input, + const V& ima_v, const E& ima_e, + unsigned box_size, const value::int_u12& bg) + { + image3d<mln_value(I)> ima; + initialize(ima, input); + + data::fill(ima, bg); + debug::draw_graph(ima, ima_v.domain(), + pw::cst(150u), + edge_to_color<E, mln_value(I)>(ima_e)); + + dpoint3d tl(-box_size,-box_size, -box_size); + dpoint3d br(box_size,box_size, -box_size); + mln_piter(V) p(ima_v.domain()); + for_all(p) + { + box3d 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; + } + +} + + +/////////////////// +// // +// Main Function // +// // +/////////////////// + + +int main(int argc, char *argv[]) +{ + using namespace mln; + using value::int_u8; + using value::int_u12; + using value::rgb8; + using value::label_16; + + if (argc < 4) + { + std::cout << "Usage: " << argv[0] << " <ima.dcm> <closure_lambda> <box_size> <dist_max>" + << std::endl; + return 1; + } + + unsigned closure_lambda = atoi(argv[2]); + unsigned box_size = atoi(argv[3]); + unsigned dist_max = atoi(argv[4]); + + image3d<int_u12> dcm; + io::dicom::load(dcm, argv[1]); + + io::dump::save(level::stretch(int_u8(), dcm), "wsd_01_src.dump"); + + image3d<int_u12> grad = morpho::gradient(dcm, win_c4p_3d()); + image3d<int_u12> clo = morpho::closing::area(grad, c6(), closure_lambda); + + label_16 nbasins; + image3d<label_16> wshed = morpho::meyer_wst(clo, c6(), nbasins); + + io::dump::save(level::stretch(int_u8(), clo), "wsd_02.dump"); + io::dump::save(level::transform(wshed, fun::l2l::wrap<int_u8>()), "wsd_03.dump"); + + mln_VAR(vol2_, morpho::elementary::dilation(extend(wshed | (pw::value(wshed) == 0u), wshed), c26())); + + data::fill((wshed | (pw::value(wshed) == 0u)).rw(), vol2_); + + io::dump::save(level::transform(wshed, fun::l2l::wrap<int_u8>()), "wsd_04.dump"); + + /// Build graph + util::graph g = make::graph(wshed, c6(), nbasins); + // Build graph images and compute distance values with a RGB image. + mln_VAR(ima_v, make_vertex_graph_image(g, dcm, wshed, nbasins)); + mln_VAR(ima_e, make_edge_graph_image(ima_v, g)); + + /// Try to merge vertices. + 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) <= dist_max && 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); + mln_assertion(parent[p] == find_root(parent, i)); + if (new_label[p] == 0) + new_label[p] = nbasins2++; + f(i) = new_label[p]; + } + mln_invariant(f(0) == 0u); + --nbasins2; // nbasins2 does not count the basin with label 0. + image3d<label_16> wsd2 = level::transform(wshed, f); + + io::dump::save(level::transform(wsd2, fun::l2l::wrap<int_u8>()), "wsd_05.dump"); + + /// Reconstruct a graph from the simplified image. + util::graph g2 = make::graph(wsd2, c6(), nbasins2); + + // Compute distance values with a RGB image. + mln_VAR(ima_v2, make_vertex_graph_image(g2, dcm, wsd2, nbasins2)); + mln_VAR(ima_e2, make_edge_graph_image(ima_v2, g2)); + + mln_VAR(wsd2_, morpho::elementary::dilation(extend(wsd2 | (pw::value(wsd2) == 0u), wsd2), c26())); + + data::fill((wsd2 | (pw::value(wsd2) == 0u)).rw(), wsd2_); + + io::dump::save(level::transform(labeling::mean_values(dcm, wsd2, nbasins2), fun::l2l::wrap<int_u8>()), "wsd_06_mean_colors.dump"); + //io::dump::save(level::stretch(int_u8(), make_debug_graph_image(dcm, ima_v2, ima_e2, box_size, 4095)), "wsd_07_graph_image2_white.dump"); + //io::dump::save(level::stretch(int_u8(), make_debug_graph_image(dcm, ima_v2, ima_e2, box_size, 0)), "wsd_08_graph_image2_black.dump"); + io::dump::save(level::transform(wsd2, fun::l2l::wrap<int_u8>()), "wsd_99_result.dump"); +} Index: trunk/milena/sandbox/fabien/igr/watershed.hh =================================================================== --- trunk/milena/sandbox/fabien/igr/watershed.hh (revision 0) +++ trunk/milena/sandbox/fabien/igr/watershed.hh (revision 3503) @@ -0,0 +1,331 @@ +#include <iostream> +#include <mln/core/image/image2d.hh> + +#include <mln/core/alias/neighb2d.hh> +#include <mln/core/alias/window2d.hh> +#include <mln/core/image/image_if.hh> + +#include <mln/io/ppm/save.hh> +#include <mln/io/ppm/load.hh> +#include <mln/io/pgm/load.hh> +#include <mln/io/dicom/load.hh> +#include <mln/io/pgm/save.hh> +#include <mln/io/dump/save.hh> + +#include <mln/value/rgb8.hh> +#include <mln/value/int_u8.hh> +#include <mln/value/int_u12.hh> +#include <mln/value/label_16.hh> + +#include <mln/level/transform.hh> +#include <mln/level/stretch.hh> + +#include <mln/labeling/mean_values.hh> + +#include <mln/convert/to_fun.hh> + +#include <mln/make/graph.hh> + +#include <mln/morpho/gradient.hh> +#include <mln/morpho/closing/area.hh> +#include <mln/morpho/meyer_wst.hh> + +#include <mln/fun/l2l/wrap.hh> + +#include <mln/core/var.hh> +#include <mln/morpho/elementary/dilation.hh> + +#include <mln/core/routine/extend.hh> + +#include <mln/util/graph.hh> + +#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_8.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/fun/v2v/id.hh> +#include <mln/fun/l2l/wrap.hh> +#include <mln/core/image/line_graph_elt_neighborhood.hh> +#include <mln/morpho/elementary/dilation.hh> +#include <mln/labeling/mean_values.hh> +#include <mln/extension/adjust_fill.hh> +#include <mln/extract/all.hh> +#include <mln/make/region_adjacency_graph.hh> + + + +// Given a color image and a wshed image, computes the component graph. +// Vertex values are computed thanks to a RGB image. + +namespace mln +{ + + template <typename V> + value::int_u8 dist(const V& c1, const V& c2) + { + unsigned d = math::diff_abs(c1.red(), c2.red()); + unsigned d_; + d_ = math::diff_abs(c1.green(), c2.green()); + + if (d_ > d) + d = d_; + + d_ = math::diff_abs(c1.blue(), c2.blue()); + + if (d_ > d) + d = d_; + 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) + { + // 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) = math::diff_abs(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<float> 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] = 150u; + + /*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, const value::int_u12& bg) + { + image2d<mln_value(I)> ima; + initialize(ima, input); + + data::fill(ima, bg); + debug::draw_graph(ima, ima_v.domain(), + pw::cst(150u), + 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; + } + +} + + +/////////////////// +// // +// Main Function // +// // +/////////////////// + + +int main(int argc, char *argv[]) +{ + using namespace mln; + using value::int_u8; + using value::int_u12; + using value::rgb8; + using value::label_16; + + if (argc < 4) + { + std::cout << "Usage: " << argv[0] << " <ima.dcm> <closure_lambda> <box_size> <dist_max>" + << std::endl; + return 1; + } + + unsigned closure_lambda = atoi(argv[2]); + unsigned box_size = atoi(argv[3]); + unsigned dist_max = atoi(argv[4]); + + image2d<int_u12> dcm; + io::dicom::load(dcm, argv[1]); + + io::pgm::save(level::stretch(int_u8(), dcm), "wsd_01_src.pgm"); + + image2d<int_u12> grad = morpho::gradient(dcm, win_c4p()); + image2d<int_u12> clo = morpho::closing::area(grad, c4(), closure_lambda); + + label_16 nbasins; + image2d<label_16> wshed = morpho::meyer_wst(clo, c4(), nbasins); + + io::pgm::save(level::stretch(int_u8(), clo), "wsd_02.pgm"); + io::pgm::save(level::transform(wshed, fun::l2l::wrap<int_u8>()), "wsd_03.pgm"); + + mln_VAR(vol2_, morpho::elementary::dilation(extend(wshed | (pw::value(wshed) == 0u), wshed), c8())); + + data::fill((wshed | (pw::value(wshed) == 0u)).rw(), vol2_); + + io::pgm::save(level::transform(wshed, fun::l2l::wrap<int_u8>()), "wsd_04.pgm"); + + /// Build graph + util::graph g = make::graph(wshed, c4(), nbasins); + // Build graph images and compute distance values with a RGB image. + mln_VAR(ima_v, make_vertex_graph_image(g, dcm, wshed, nbasins)); + mln_VAR(ima_e, make_edge_graph_image(ima_v, g)); + + /// Try to merge vertices. + 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) <= dist_max && 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); + mln_assertion(parent[p] == find_root(parent, i)); + if (new_label[p] == 0) + new_label[p] = nbasins2++; + f(i) = new_label[p]; + } + mln_invariant(f(0) == 0u); + --nbasins2; // nbasins2 does not count the basin with label 0. + image2d<label_16> wsd2 = level::transform(wshed, f); + + io::pgm::save(level::transform(wsd2, fun::l2l::wrap<int_u8>()), "wsd_05.pgm"); + + /// Reconstruct a graph from the simplified image. + util::graph g2 = make::graph(wsd2, c4(), nbasins2); + + // Compute distance values with a RGB image. + mln_VAR(ima_v2, make_vertex_graph_image(g2, dcm, wsd2, nbasins2)); + mln_VAR(ima_e2, make_edge_graph_image(ima_v2, g2)); + + mln_VAR(wsd2_, morpho::elementary::dilation(extend(wsd2 | (pw::value(wsd2) == 0u), wsd2), c8())); + + data::fill((wsd2 | (pw::value(wsd2) == 0u)).rw(), wsd2_); + + io::pgm::save(level::transform(labeling::mean_values(dcm, wsd2, nbasins2), fun::l2l::wrap<int_u8>()), "wsd_06_mean_colors.pgm"); + io::pgm::save(level::stretch(int_u8(), make_debug_graph_image(dcm, ima_v2, ima_e2, box_size, 4095)), "wsd_07_graph_image2_white.pgm"); + io::pgm::save(level::stretch(int_u8(), make_debug_graph_image(dcm, ima_v2, ima_e2, box_size, 0)), "wsd_08_graph_image2_black.pgm"); + io::pgm::save(level::transform(wsd2, fun::l2l::wrap<int_u8>()), "wsd_99_result.pgm"); +} Index: trunk/milena/sandbox/fabien/igr/check2d_wsd.sh =================================================================== --- trunk/milena/sandbox/fabien/igr/check2d_wsd.sh (revision 0) +++ trunk/milena/sandbox/fabien/igr/check2d_wsd.sh (revision 3503) @@ -0,0 +1,32 @@ +#!/bin/zsh + +process_file () +{ + echo "Processing $2..." + box_size=2 + + for lambda_closure in 10 50 100 500 1000; do + echo " for lambda_closure = ${lambda_closure}"; + + for dist_max in 5 10 50 100 500; do + echo " for lambda_dist = ${dist_max}"; + + ./wsd2d $1 $lambda_closure $box_size $dist_max + + mv wsd_01_src.pgm results/${2}_${lambda_closure}_${dist_max}_01.pgm + mv wsd_02.pgm results/${2}_${lambda_closure}_${dist_max}_02.pgm + mv wsd_03.pgm results/${2}_${lambda_closure}_${dist_max}_03.pgm + mv wsd_04.pgm results/${2}_${lambda_closure}_${dist_max}_04.pgm + mv wsd_05.pgm results/${2}_${lambda_closure}_${dist_max}_05.pgm + mv wsd_06_mean_colors.pgm results/${2}_${lambda_closure}_${dist_max}_06.pgm + mv wsd_07_graph_image2_white.pgm results/${2}_${lambda_closure}_${dist_max}_07.pgm + mv wsd_08_graph_image2_black.pgm results/${2}_${lambda_closure}_${dist_max}_08.pgm + mv wsd_99_result.pgm results/${2}_${lambda_closure}_${dist_max}_99.pgm + + done; + done +} + +process_file "/Users/HiSoKa/Work/IGR/souris18/irm/IM_0049.dcm" "49" +process_file "/Users/HiSoKa/Work/IGR/souris18/irm/IM_0055.dcm" "55" +process_file "/Users/HiSoKa/Work/IGR/souris18/irm/IM_0058.dcm" "58" Property changes on: trunk/milena/sandbox/fabien/igr/check2d_wsd.sh ___________________________________________________________________ Name: svn:executable + * Index: trunk/milena/sandbox/fabien/igr/check3d_wsd.sh =================================================================== --- trunk/milena/sandbox/fabien/igr/check3d_wsd.sh (revision 0) +++ trunk/milena/sandbox/fabien/igr/check3d_wsd.sh (revision 3503) @@ -0,0 +1,34 @@ +#!/bin/zsh + +process_file () +{ + echo "Processing $2..." + box_size=2 + + for lambda_closure in 10 50 100 500 1000; do + echo " for lambda_closure = ${lambda_closure}"; + + for dist_max in 5 10 50 100 500; do + echo " for lambda_dist = ${dist_max}"; + + ./wsd3d $1 $lambda_closure $box_size $dist_max + + ../bin/dump2pgm8b wsd_01_src.dump results/${2}_${lambda_closure}_${dist_max}_01.pgm + ../bin/dump2pgm8b wsd_02.dump results/${2}_${lambda_closure}_${dist_max}_02.pgm + ../bin/dump2pgm8b wsd_03.dump results/${2}_${lambda_closure}_${dist_max}_03.pgm + ../bin/dump2pgm8b wsd_04.dump results/${2}_${lambda_closure}_${dist_max}_04.pgm + ../bin/dump2pgm8b wsd_05.dump results/${2}_${lambda_closure}_${dist_max}_05.pgm + ../bin/dump2pgm8b wsd_06_mean_colors.dump results/${2}_${lambda_closure}_${dist_max}_06.pgm +#../bin/dump2pgm8b wsd_07_graph_image2_white.dump results/${2}_${lambda_closure}_${dist_max}_07.pgm +#../bin/dump2pgm8b wsd_08_graph_image2_black.dump results/${2}_${lambda_closure}_${dist_max}_08.pgm + ../bin/dump2pgm8b wsd_99_result.dump results/${2}_${lambda_closure}_${dist_max}_99.pgm + + rm *.dump + + done; + done +} + +process_file "/Users/HiSoKa/Work/IGR/souris18/irm/IM_0052.dcm" "52" +process_file "/Users/HiSoKa/Work/IGR/souris18/irm/IM_0061.dcm" "61" +process_file "/Users/HiSoKa/Work/IGR/souris18/irm/IM_0064.dcm" "64" Property changes on: trunk/milena/sandbox/fabien/igr/check3d_wsd.sh ___________________________________________________________________ Name: svn:executable + * Index: trunk/milena/sandbox/fabien/igr/Makefile =================================================================== --- trunk/milena/sandbox/fabien/igr/Makefile (revision 3502) +++ trunk/milena/sandbox/fabien/igr/Makefile (revision 3503) @@ -8,7 +8,7 @@ -framework CoreFoundation CXXFLAGS = -DNDEBUG -O1 -all: 2d 3d wsd +all: 2d 3d wsd2d wsd3d 2d: seg_vol_irm.hh seg2d.cc g++ -I../../../ ${DICOM_INC} ${DICOM_LIB} ${CXXFLAGS} seg2d.cc -o seg2d @@ -16,8 +16,11 @@ 3d: seg_vol_irm.hh seg3d.cc g++ -I../../../ ${DICOM_INC} ${DICOM_LIB} ${CXXFLAGS} seg3d.cc -o seg3d -wsd: watershed.cc - g++ -I../../../ ${DICOM_INC} ${DICOM_LIB} ${CXXFLAGS} $^ -o wsd +wsd2d: watershed.hh watershed2d.cc + g++ -I../../../ ${DICOM_INC} ${DICOM_LIB} ${CXXFLAGS} $^ -o wsd2d + +wsd3d: watershed.hh watershed3d.cc + g++ -I../../../ ${DICOM_INC} ${DICOM_LIB} ${CXXFLAGS} $^ -o wsd3d clean: rm -rf *.dump *.p?m *.plot *.log *.csv Index: trunk/milena/sandbox/fabien/TODO =================================================================== --- trunk/milena/sandbox/fabien/TODO (revision 3502) +++ trunk/milena/sandbox/fabien/TODO (revision 3503) @@ -13,7 +13,7 @@ [X] Generate histograms (normal, bg, obj, p_bg, p_obj) [ ] Test processing chain on US [X] Create README file for special images -[ ] Implement watershed +[X] Implement watershed [X] Create tool for dicom mask [X] Check conversion for mask (everything except int_u12(0)) [ ] Extract ROI (projection or fill holes) @@ -22,4 +22,7 @@ [ ] After threshold, take biggest object and then erode, dilate [ ] Fix n_max [ ] Create routine for binary images (keep n big bg & m big objects) -[ ] US: projection of internal gradient +[X] US: projection of internal gradient +[X] Create 3D US morpho with 2D stack +[ ] Create macro for_all_slice +[ ] Batch process watershed with 2D, 3D and any combination of parameters Index: trunk/milena/sandbox/fabien/bin/dump2pgm.cc =================================================================== --- trunk/milena/sandbox/fabien/bin/dump2pgm.cc (revision 0) +++ trunk/milena/sandbox/fabien/bin/dump2pgm.cc (revision 3503) @@ -0,0 +1,37 @@ +#include <mln/core/image/image2d.hh> +#include <mln/make/image3d.hh> +#include <mln/debug/slices_2d.hh> + +#include <mln/value/int_u8.hh> +#include <mln/value/int_u12.hh> +#include <mln/io/dump/load.hh> +#include <mln/io/pgm/save.hh> + +#include <mln/literal/colors.hh> + + +int usage(char* argv[]) +{ + std::cerr << "usage: " << argv[0] << " input.dump output.pgm" << std::endl; + return 1; +} + + + +int main(int argc, char* argv[]) +{ + using namespace mln; + using value::rgb8; + + if (argc != 3) + return usage(argv); + + image3d<int_u12> vol; + io::dump::load(vol, argv[1]); + + rgb8 bg = literal::black; + image2d<int_u8> ima = debug::slices_2d(vol, 1.f, bg); + io::pgm::save(ima, argv[2]); + + return 0; +} Index: trunk/milena/sandbox/fabien/bin/filetype.hh =================================================================== --- trunk/milena/sandbox/fabien/bin/filetype.hh (revision 0) +++ trunk/milena/sandbox/fabien/bin/filetype.hh (revision 3503) @@ -0,0 +1,54 @@ +#include <string> + +// 2d +#include <mln/core/image/image2d.hh> +#include <mln/core/alias/neighb2d.hh> + +// 3d +#include <mln/core/image/image3d.hh> +#include <mln/core/alias/neighb3d.hh> + + +// pbm +#include <mln/io/pbm/load.hh> +#include <mln/io/pbm/save.hh> + +// pgm +#include <mln/io/pgm/load.hh> +#include <mln/io/pgm/save.hh> + +// ppm +#include <mln/io/ppm/load.hh> +#include <mln/io/ppm/save.hh> + + +//dump +#include <mln/io/dump/load.hh> +#include <mln/io/dump/save.hh> + + +namespace mln +{ + + namespace filetype + { + enum id { pbm, pgm, ppm, dump, unknown }; + } + + filetype::id + get_filetype(const std::string& filename) + { + if (filename.find(".pbm") == filename.length() - 4) + return filetype::pbm; + if (filename.find(".pgm") == filename.length() - 4) + return filetype::pgm; + if (filename.find(".ppm") == filename.length() - 4) + return filetype::ppm; + if (filename.find(".dump") == filename.length() - 5) + return filetype::dump; + return filetype::unknown; + } + +} // mln + + Index: trunk/milena/sandbox/fabien/bin/dump_mask.cc =================================================================== --- trunk/milena/sandbox/fabien/bin/dump_mask.cc (revision 0) +++ trunk/milena/sandbox/fabien/bin/dump_mask.cc (revision 3503) @@ -0,0 +1,86 @@ +#include <mln/core/concept/image.hh> +#include <mln/core/image/image2d.hh> +#include <mln/core/image/image3d.hh> +#include <mln/core/image/slice_image.hh> +#include <mln/core/alias/neighb2d.hh> +#include <mln/core/alias/neighb3d.hh> +#include <mln/core/var.hh> + +#include <mln/geom/ncols.hh> +#include <mln/geom/nrows.hh> + +#include <mln/value/int_u8.hh> +#include <mln/io/dump/load.hh> +#include <mln/io/pbm/save.hh> + +#include <mln/literal/colors.hh> +#include <mln/morpho/elementary/gradient_internal.hh> + +#include <mln/level/transform.hh> +#include <mln/fun/v2b/threshold.hh> + +#include <mln/data/fill.hh> +#include <mln/pw/all.hh> + + +int usage(char* argv[]) +{ + std::cerr << "usage: " << argv[0] << " input.dump" << std::endl; + return 1; +} + + + +int main(int argc, char* argv[]) +{ + using namespace mln; + using value::int_u8; + + if (argc != 2) + return usage(argv); + + image3d<int_u8> input; + io::dump::load(input, argv[1]); + + image3d<bool> ima = level::transform(input, fun::v2b::threshold<int_u8>(1)); + mln_VAR(grad_int, morpho::elementary::gradient_internal(ima, c6())); + + util::array<unsigned> xproj(ima.nrows(), 0); + util::array<unsigned> yproj(ima.ncols(), 0); + util::array<unsigned> xgradproj(grad_int.nrows(), 0); + util::array<unsigned> ygradproj(grad_int.ncols(), 0); + + mln_piter_(image3d<bool>) p(ima.domain()); + for_all(p) + { + if (ima(p)) + { + ++xproj[p.row()]; + ++yproj[p.col()]; + } + if (grad_int(p)) + { + ++xgradproj[p.row()]; + ++ygradproj[p.col()]; + } + } + + // Plot files + std::ofstream fout_x("x.plot"); + std::ofstream fout_xgrad("xgrad.plot"); + for (unsigned int i = 0; i < xproj.nelements(); ++i) + { + fout_x << i << " " << xproj[i] << std::endl; + fout_xgrad << i << " " << xgradproj[i] << std::endl; + } + + std::ofstream fout_y("y.plot"); + std::ofstream fout_ygrad("ygrad.plot"); + for (unsigned int i = 0; i < yproj.nelements(); ++i) + { + fout_y << i << " " << yproj[i] << std::endl; + fout_ygrad << i << " " << ygradproj[i] << std::endl; + } + + return 0; +} Index: trunk/milena/sandbox/fabien/bin/dicom2pgm.cc =================================================================== --- trunk/milena/sandbox/fabien/bin/dicom2pgm.cc (revision 0) +++ trunk/milena/sandbox/fabien/bin/dicom2pgm.cc (revision 3503) @@ -0,0 +1,34 @@ +#include <mln/core/concept/image.hh> +#include <mln/core/image/image2d.hh> +#include <mln/core/image/image3d.hh> + +#include <mln/value/int_u8.hh> +#include <mln/value/int_u12.hh> +#include <mln/io/dicom/load.hh> +#include <mln/io/pgm/save.hh> + + + +int usage(char* argv[]) +{ + std::cerr << "usage: " << argv[0] << " input.dcm output.dump" << std::endl; + std::cerr << "\t work for 2D images encoded in int_u8" << std::endl; + return 1; +} + + +int main(int argc, char* argv[]) +{ + using namespace mln; + using value::int_u8; + using value::int_u12; + + if (argc != 3) + return usage(argv); + + image2d<int_u8> ima; + io::dicom::load(ima, argv[1]); + io::pgm::save(ima, argv[2]); + + return 0; +} Index: trunk/milena/sandbox/fabien/bin/dump2pgm8b.cc =================================================================== --- trunk/milena/sandbox/fabien/bin/dump2pgm8b.cc (revision 0) +++ trunk/milena/sandbox/fabien/bin/dump2pgm8b.cc (revision 3503) @@ -0,0 +1,38 @@ +#include <mln/core/image/image2d.hh> +#include <mln/make/image3d.hh> +#include <mln/debug/slices_2d.hh> + +#include <mln/value/int_u8.hh> +#include <mln/value/int_u12.hh> +#include <mln/io/dump/load.hh> +#include <mln/io/pgm/save.hh> + +#include <mln/literal/colors.hh> + + +int usage(char* argv[]) +{ + std::cerr << "usage: " << argv[0] << " input.dump output.pgm" << std::endl; + return 1; +} + + + +int main(int argc, char* argv[]) +{ + using namespace mln; + using value::rgb8; + using value::int_u8; + + if (argc != 3) + return usage(argv); + + image3d<int_u8> vol; + io::dump::load(vol, argv[1]); + + rgb8 bg = literal::black; + image2d<int_u8> ima = debug::slices_2d(vol, 1.f, 0); + io::pgm::save(ima, argv[2]); + + return 0; +} Index: trunk/milena/sandbox/fabien/bin/pnms2dump.cc =================================================================== --- trunk/milena/sandbox/fabien/bin/pnms2dump.cc (revision 0) +++ trunk/milena/sandbox/fabien/bin/pnms2dump.cc (revision 3503) @@ -0,0 +1,97 @@ +#include "filetype.hh" + +#include <mln/make/image3d.hh> + + + + +void usage(char* argv[]) +{ + std::cerr << "usage: " << argv[0] << " output.dump input1.xxx .. inputn.xxx" << std::endl; + std::cerr << " It works with binary (pbm), gray-level (int_u8), and color (rgb8) images." << std::endl; + abort(); +} + + + +int main(int argc, char* argv[]) +{ + using namespace mln; + using value::int_u8; + + if (argc < 3) + usage(argv); + + trace::entering("main"); + + std::string filename = argv[2]; + + switch (get_filetype(argv[2])) + { + case filetype::pbm: + { + typedef image2d<bool> I; + util::array<I> arr; + for (int i = 2; i < argc; ++i) + { + I ima; + io::pbm::load(ima, argv[i]); + arr.append(ima); + } + image3d<bool> vol = make::image3d(arr); + io::dump::save(vol, argv[1]); + } + break; + + case filetype::pgm: + { + using value::int_u8; + typedef image2d<int_u8> I; + util::array<I> arr; + for (int i = 2; i < argc; ++i) + { + I ima; + io::pgm::load(ima, argv[i]); + arr.append(ima); + } + image3d<int_u8> vol = make::image3d(arr); + io::dump::save(vol, argv[1]); + } + break; + + case filetype::ppm: + { + using value::rgb8; + typedef image2d<rgb8> I; + util::array<I> arr; + for (int i = 2; i < argc; ++i) + { + I ima; + io::ppm::load(ima, argv[i]); + arr.append(ima); + } + image3d<rgb8> vol = make::image3d(arr); + io::dump::save(vol, argv[1]); + } + break; + + case filetype::dump: + { + std::cerr << "Output shall not be a dump file!" << std::endl; + usage(argv); + } + break; + + case filetype::unknown: + std::cerr << "unknown filename extension!" << std::endl; + usage(argv); + break; + + default: + std::cerr << "file type not handled!" << std::endl; + usage(argv); + } + + trace::exiting("main"); + +}
participants (1)
-
Fabien Freling