https://svn.lrde.epita.fr/svn/oln/trunk/milena/sandbox
Index: ChangeLog
from Thierry Geraud <thierry.geraud(a)lrde.epita.fr>
Add some experimental code.
* icdar/2009/pscomp: New directory.
* icdar/2009/pscomp/iz.cc: New.
Compute an IZ image along with distances between objects.
* icdar/2009/pscomp/rect_filter.cc: New.
Algebraic filtering with a combinaison of bounding box width
and height.
* theo/experimental/depeche: New directory.
* theo/experimental/depeche/homogen.cc: New.
* theo/experimental/depeche/col.cc: New.
* theo/experimental/depeche/row_mm.cc: New.
* theo/experimental/depeche/row.cc: New.
icdar/2009/pscomp/iz.cc | 174 +++++++++++++++++++++
icdar/2009/pscomp/rect_filter.cc | 165 ++++++++++++++++++++
theo/experimental/depeche/col.cc | 286 +++++++++++++++++++++++++++++++++++
theo/experimental/depeche/homogen.cc | 43 +++++
theo/experimental/depeche/row.cc | 117 ++++++++++++++
theo/experimental/depeche/row_mm.cc | 96 +++++++++++
6 files changed, 881 insertions(+)
Index: icdar/2009/pscomp/iz.cc
--- icdar/2009/pscomp/iz.cc (revision 0)
+++ icdar/2009/pscomp/iz.cc (revision 0)
@@ -0,0 +1,174 @@
+
+// From mln/canvas/distance_geodesic.hh
+
+# include <mln/core/concept/image.hh>
+# include <mln/core/concept/neighborhood.hh>
+# include <mln/core/routine/duplicate.hh>
+# include <mln/core/site_set/p_queue_fast.hh>
+# include <queue>
+# include <mln/data/fill.hh>
+# include <mln/extension/adjust_fill.hh>
+
+
+// Local.
+
+#include <map>
+#include <mln/core/image/image2d.hh>
+#include <mln/core/alias/neighb2d.hh>
+#include <mln/value/int_u8.hh>
+#include <mln/io/pbm/load.hh>
+#include <mln/io/pgm/save.hh>
+#include <mln/debug/println.hh>
+#include <mln/data/saturate.hh>
+
+#include <mln/labeling/blobs.hh>
+#include <mln/labeling/value.hh>
+
+
+
+
+namespace mln
+{
+
+
+ // From mln/canvas/distance_geodesic.hh
+ // and mln/transform/internal/influence_zone_functor.hh
+ // and mln/transform/influence_zone_geodesic.hh
+
+
+ template <typename I, typename N>
+ std::map< std::pair<mln_value(I),mln_value(I)>, unsigned >
+ distances(// in:
+ const I& input, const N& nbh,
+ // out:
+ mln_ch_value(I, unsigned)& dmap,
+ mln_concrete(I)& iz)
+ {
+ trace::entering("canvas::impl::generic::distance_geodesic");
+
+ typedef mln_value(I) L;
+ std::map< std::pair<L,L>, unsigned > dist; // NEW
+
+ const unsigned max = mln_max(unsigned);
+ typedef mln_site(I) P;
+ p_queue_fast<P> q;
+
+ // Initialization.
+ {
+ iz = duplicate(input); // <-- init
+
+ data::fill(dmap, max);
+
+ mln_piter(I) p(input.domain());
+ mln_niter(N) n(nbh, p);
+ for_all(p)
+ if (input(p) != 0) // <-- inqueue_p_wrt_input_p
+ {
+ ; // <-- init_p
+ dmap(p) = 0;
+ for_all(n)
+ if (input.domain().has(n) &&
+ input(n) == 0) // <-- inqueue_p_wrt_input_n
+ {
+ q.push(p);
+ break;
+ }
+ }
+ }
+
+ // Propagation.
+ {
+ P p;
+ mln_niter(N) n(nbh, p);
+ while (! q.is_empty())
+ {
+ p = q.pop_front();
+ if (dmap(p) == max)
+ {
+ // Saturation so stop.
+ q.clear();
+ break;
+ }
+ for_all(n)
+ {
+ if (! input.domain().has(n))
+ continue;
+ if (dmap(n) == max)
+ {
+ dmap(n) = dmap(p) + 1;
+ iz(n) = iz(p); // <- process
+ q.push(n);
+ }
+ else
+ {
+ if (iz(n) != iz(p))
+ {
+ L l1 = iz(n), l2 = iz(p);
+ if (l1 > l2)
+ std::swap(l1, l2);
+ unsigned& d_ = dist[std::make_pair(l1,l2)];
+ unsigned d12 = dmap(p) + dmap(n) + 1;
+ if (d_ == 0 || d12 < d_)
+ d_ = d12;
+ }
+ }
+ }
+ }
+ }
+
+ return dist;
+ }
+
+
+} // mln
+
+
+
+int main(int argc, char* argv[])
+{
+ using namespace mln;
+
+ typedef unsigned L;
+
+ image2d<bool> input;
+ io::pbm::load(input, argv[1]);
+
+ L n_labels;
+ image2d<L> lab = labeling::value(input, true, c8(), n_labels);
+ std::cout << "n labels = " << n_labels << std::endl;
+
+
+ image2d<unsigned> dmap(input.domain());
+ image2d<L> iz(input.domain());
+
+ typedef std::map< std::pair<L,L>, unsigned > map_t;
+ map_t d = distances(lab, c8(), dmap, iz);
+
+ io::pgm::save(data::saturate(value::int_u8(), dmap), "dmap.pgm");
+
+ // debug::println("lab = ", lab);
+ std::cout << "map size = " << d.size() << std::endl;
+
+
+// {
+// // Compute statistics.
+// std::map<unsigned, unsigned> h;
+// for (map_t::const_iterator i = d.begin();
+// i != d.end(); ++i)
+// ++h[i->second];
+
+// for (std::map<unsigned, unsigned>::const_iterator i = h.begin();
+// i != h.end(); ++i)
+// std::cout << i->first << " " << i->second
<< std::endl;
+// }
+
+
+// {
+// // Print: d(label1, label2) = shortest distance
+// for (map_t::const_iterator i = d.begin();
+// i != d.end(); ++i)
+// std::cout << "d(" << i->first.first << ",
" << i->first.second << ") = "
+// << i->second << std::endl;
+// }
+
+}
Index: icdar/2009/pscomp/rect_filter.cc
--- icdar/2009/pscomp/rect_filter.cc (revision 0)
+++ icdar/2009/pscomp/rect_filter.cc (revision 0)
@@ -0,0 +1,165 @@
+#include <mln/core/image/image2d.hh>
+#include <mln/core/alias/neighb2d.hh>
+#include <mln/value/int_u8.hh>
+#include <mln/io/pbm/load.hh>
+#include <mln/io/pgm/save.hh>
+#include <mln/debug/println.hh>
+
+#include <mln/transform/distance_geodesic.hh>
+#include <mln/accu/shape/bbox.hh>
+#include <mln/morpho/closing/algebraic.hh>
+#include <mln/morpho/watershed/flooding.hh>
+#include <mln/morpho/watershed/superpose.hh>
+
+#include <mln/core/routine/duplicate.hh>
+#include <mln/data/convert.hh>
+#include <mln/pw/all.hh>
+#include <mln/io/pbm/save.hh>
+#include <mln/io/ppm/save.hh>
+
+
+
+
+namespace mln
+{
+
+ struct pair_and
+ {
+ pair_and()
+ {}
+ pair_and(unsigned first, unsigned second)
+ : first(first),
+ second(second)
+ {}
+// bool operator<(const pair_and& other) const
+// {
+// return first < other.first && second < other.second;
+// }
+ unsigned first, second;
+ };
+
+
+ bool operator<(const pair_and& lhs, const pair_and& rhs)
+ {
+ return lhs.first < rhs.first || lhs.second < rhs.second;
+ }
+
+
+ struct rectangle_and;
+
+
+ namespace trait
+ {
+
+ template <>
+ struct accumulator_< rectangle_and >
+ {
+ typedef accumulator::has_untake::no has_untake;
+ typedef accumulator::has_set_value::no has_set_value;
+ typedef accumulator::has_stop::no has_stop;
+ typedef accumulator::when_pix::use_p when_pix;
+ };
+
+ } // end of namespace mln::trait
+
+
+ struct rectangle_and : public accu::internal::base< pair_and, rectangle_and >
+ {
+ typedef point2d argument;
+
+ rectangle_and()
+ {
+ }
+
+ void init()
+ {
+ bb_.init();
+ }
+ void take_as_init_(const point2d& p)
+ {
+ bb_.take_as_init_(p);
+ }
+ void take(const point2d& p)
+ {
+ bb_.take(p);
+ }
+ void take(const rectangle_and& other)
+ {
+ bb_.take(other.bb_);
+ }
+
+ pair_and to_result() const
+ {
+ pair_and tmp(bb_.to_result().len(0),
+ bb_.to_result().len(1));
+ return tmp;
+ }
+
+ bool is_valid() const
+ {
+ return true;
+ }
+
+ protected:
+ accu::shape::bbox<point2d> bb_;
+ };
+
+
+} // mln
+
+
+void usage(char* argv[])
+{
+ std::cerr << "usage: " << argv[0] << " input.pgm w h
output.ppm" << std::endl;
+ std::abort();
+}
+
+
+int main(int argc, char* argv[])
+{
+ using namespace mln;
+ using value::int_u8;
+ using value::rgb8;
+
+ if (argc != 5)
+ usage(argv);
+
+ image2d<bool> input;
+ io::pbm::load(input, argv[1]);
+
+ typedef value::int_u8 D;
+
+ image2d<D> dmap;
+ dmap = transform::distance_geodesic(input,
+ c8(),
+ mln_max(D));
+ io::pgm::save(dmap, "temp_dmap.pgm");
+
+ int w = std::atoi(argv[2]), h = std::atoi(argv[3]);
+
+ pair_and lambda(w, h);
+ image2d<D> clo = morpho::closing::algebraic(dmap,
+ c8(),
+ rectangle_and(),
+ lambda);
+
+ io::pgm::save(clo, "temp_clo.pgm");
+
+ typedef unsigned L;
+ L n_basins;
+ image2d<L> ws = morpho::watershed::flooding(clo, c8(), n_basins);
+ std::cout << "n basins = " << n_basins<< std::endl;
+
+ {
+ image2d<rgb8> out = data::convert(rgb8(), dmap);
+ out = morpho::watershed::superpose(out, ws, rgb8(255,0,0));
+ io::ppm::save(out, argv[4]);
+ }
+
+// {
+// image2d<bool> out(input.domain());
+// out = duplicate((pw::value(ws) == pw::cst(0)) | input.domain());
+// io::pbm::save(out, argv[2]);
+// }
+
+}
Index: theo/experimental/depeche/homogen.cc
--- theo/experimental/depeche/homogen.cc (revision 0)
+++ theo/experimental/depeche/homogen.cc (revision 0)
@@ -0,0 +1,43 @@
+#include <mln/core/image/image2d.hh>
+#include <mln/core/alias/neighb2d.hh>
+#include <mln/morpho/attribute/height.hh>
+#include <mln/morpho/closing/leveling.hh>
+
+#include <mln/arith/minus.hh>
+
+#include <mln/value/int_u8.hh>
+#include <mln/io/pgm/load.hh>
+#include <mln/io/pgm/save.hh>
+
+
+
+void usage(char* argv[])
+{
+ std::cerr << "usage: " << argv[0] << " input.pgm h
output.pgm" << std::endl;
+ abort();
+}
+
+
+
+int main(int argc, char* argv[])
+{
+ using namespace mln;
+ using value::int_u8;
+
+ if (argc != 4)
+ usage(argv);
+
+ image2d<int_u8> input;
+ io::pgm::load(input, argv[1]);
+
+ int i = std::atoi(argv[2]);
+ int_u8 h = i;
+
+ morpho::attribute::height< image2d<int_u8> > acc;
+ image2d<int_u8> clo = morpho::closing::leveling(input, c4(),
+ acc, h);
+ io::pgm::save(clo, "tmp.pgm");
+ arith::minus_inplace(clo, input);
+
+ io::pgm::save(clo, argv[3]);
+}
Index: theo/experimental/depeche/col.cc
--- theo/experimental/depeche/col.cc (revision 0)
+++ theo/experimental/depeche/col.cc (revision 0)
@@ -0,0 +1,286 @@
+#include <mln/core/image/image2d.hh>
+#include <mln/core/alias/neighb2d.hh>
+
+#include <mln/core/image/image1d.hh>
+#include <mln/core/alias/neighb1d.hh>
+
+#include <mln/fun/v2v/projection.hh>
+#include <mln/core/image/dmorph/unproject_image.hh>
+#include <mln/core/image/dmorph/image_if.hh>
+#include <mln/pw/value.hh>
+
+#include <mln/accu/stat/mean.hh>
+#include <mln/accu/image/init.hh>
+#include <mln/accu/image/take.hh>
+#include <mln/accu/image/to_result.hh>
+
+#include <mln/value/int_u8.hh>
+#include <mln/io/pgm/load.hh>
+#include <mln/io/plot/save.hh>
+
+#include <mln/linear/gaussian_1d.hh>
+#include <mln/labeling/regional_maxima.hh>
+#include <mln/data/convert.hh>
+#include <mln/io/ppm/save.hh>
+
+#include <mln/data/fill.hh>
+#include <mln/debug/println.hh>
+#include <mln/accu/stat/median_h.hh>
+
+#include <mln/morpho/closing/volume.hh>
+
+
+
+namespace mln
+{
+
+
+ float get_approx_gap(const util::array<unsigned>& line, unsigned delta)
+ {
+ accu::stat::median_h< value::int_u<12> > med;
+ const unsigned n = line.nelements() - delta;
+ for (unsigned i = 0; i < n; ++i)
+ med.take(line[i + delta] - line[i]);
+
+ std::cout << "delta = " << delta << std::endl;
+ std::cout << med.histo() << std::endl;
+ std::cout << "med = " << med.to_result() << std::endl;
+
+ return float(med.to_result()) / delta;
+ }
+
+
+ void refine_gap(const util::array<unsigned>& line, unsigned delta, float&
gap)
+ {
+ std::cout << "gap = " << gap << std::endl;
+ unsigned count = 0;
+
+ accu::stat::mean<float> mean;
+ const unsigned n = line.nelements() - delta;
+ for (unsigned i = 0; i < n; ++i)
+ {
+ float g = line[i + delta] - line[i];
+ if (g / delta > gap - .2 && g / delta < gap + .2)
+ {
+ mean.take(g);
+ ++count;
+ }
+ }
+ std::cout << "count = " << count << " total =
" << n << std::endl;
+
+ gap = mean.to_result() / delta;
+ std::cout << "gap = " << gap << std::endl;
+ }
+
+
+ util::array<unsigned>
+ select_lines(const util::array<unsigned>& line, float gap)
+ {
+ std::set<unsigned> s;
+ const unsigned n = line.nelements() - 1;
+ for (unsigned i = 0; i < n; ++i)
+ {
+ float g = line[i + 1] - line[i];
+ if (g > gap - 2 && g < gap + 2)
+ {
+ s.insert(line[i]);
+ s.insert(line[i + 1]);
+ }
+ }
+
+ std::vector<unsigned> v(s.begin(), s.end());
+ util::array<unsigned> out;
+ out.hook_std_vector_() = v;
+
+ return out;
+ }
+
+
+ util::array<unsigned>
+ image_2_line(const image1d<double>& input)
+ {
+ image1d<bool> is_max(input.domain());
+ unsigned n;
+ data::fill(is_max,
+ pw::value(labeling::regional_maxima(input, c2(), n)) | input.domain());
+ std::cout << "n = " << n << std::endl;
+
+ util::array<unsigned> line;
+ {
+ mln_piter_(box1d) p(input.domain());
+ for_all(p)
+ if (is_max(p))
+ line.append(p.ind());
+ }
+
+ return line;
+ }
+
+
+ util::array<unsigned>
+ analyze(const util::array<unsigned>& line, float& gap, bool& ok)
+ {
+ // FIXME: The value of delta in 'get_approx_gap' and in
+ // 'refine_gap' should change w.r.t. to the nature of input data.
+ gap = get_approx_gap(line, 10); // FIXME: 10 / 3
+ float rough_gap = gap;
+ refine_gap(line, 20, gap); // FIXME: 20 / 4
+ float finer_gap = gap;
+
+ ok = std::abs(finer_gap - rough_gap) < 1;
+
+ return select_lines(line, gap);
+ }
+
+
+ void draw(const image2d<value::int_u8>& input,
+ const util::array<unsigned>& line,
+ value::rgb8 color,
+ const std::string& filename)
+ {
+ image2d<value::rgb8> output = data::convert(value::rgb8(), input);
+ const int nrows = input.nrows();
+
+ for (unsigned i = 0; i < line.nelements(); ++i)
+ {
+ int col = line[i];
+ for (int row = 0; row < nrows; ++row)
+ output.at_(row, col) = color;
+ }
+
+ io::ppm::save(output, filename);
+}
+
+
+} // mln
+
+
+
+void usage(char* argv[])
+{
+ std::cerr << "usage: " << argv[0] << " input.pgm
lambda h.txt output.ppm" << std::endl;
+ std::cerr << "hint: lambda = 50; delta = 10 / 20 otherwise 3 / 4"
<< std::endl;
+ abort();
+}
+
+
+
+int main(int argc, char* argv[])
+{
+ using namespace mln;
+ using value::int_u8;
+ using value::rgb8;
+
+ if (argc != 5)
+ usage(argv);
+
+ image2d<int_u8> input;
+ io::pgm::load(input, argv[1]);
+ box2d b = input.domain();
+
+
+ // h computing
+
+ typedef accu::stat::mean<int_u8, unsigned, double> A;
+
+ image1d<A> hmean(b.ncols());
+ accu::image::init(hmean);
+
+ fun::v2v::projection<point2d, 0> hproj;
+ accu::image::take(unproject(hmean, b, hproj).rw(), input);
+
+ image1d<double> h = accu::image::to_result(hmean);
+ io::plot::save(h, argv[3]);
+
+
+ // h cleaning
+
+ h = linear::gaussian_1d(h, 1.0, 255);
+ io::plot::save(h, "h_g.txt");
+
+ int lambda = std::atoi(argv[2]);
+ h = morpho::closing::volume(h, c2(), lambda);
+ io::plot::save(h, "h_gc.txt");
+
+
+
+ // analyzing
+
+ util::array<unsigned> line = image_2_line(h);
+ draw(input, line, value::rgb8(255,0,0), "temp_h.ppm");
+
+ float gap;
+ bool ok;
+ line = analyze(line, gap, ok);
+
+ draw(input, line, value::rgb8(255,0,0), "temp_h_sel.ppm");
+
+ if (! ok)
+ {
+ std::cerr << "analyze failed: abort!" << std::endl;
+ std::abort();
+ }
+
+
+
+ // getting a math model
+ float o;
+
+ {
+ accu::stat::mean<float> me;
+ // col = r * gap where r = o + i (with offset o and integer i)
+ // col = gap * i + orig (orig = o * gap)
+ for (unsigned l = 0; l < line.nelements(); ++l)
+ {
+ float r = float(line[l]) / gap;
+ int i = int(r + 0.49999);
+ float o = r - float(i);
+ me.take(o);
+ std::cout << line[l] << " = " << (gap * o) << " +
" << i << " * " << gap << std::endl;
+ }
+ o = me.to_result();
+
+ std::cout << "gap = " << gap << " offset = "
<< (gap * o) << std::endl;
+
+ // verif
+ util::array<unsigned> line_;
+ for (unsigned l = 0; l < line.nelements(); ++l)
+ {
+ int i = int(float(line[l]) / gap - o + 0.49999);
+ line_.append(int((o + i) * gap + 0.49999));
+ }
+
+ std::cout << std::endl;
+
+ // over-display
+ draw(input, line, value::rgb8(255,0,0), "temp_h_found.ppm");
+
+ }
+
+
+ // drawing matrix
+
+ {
+ image2d<rgb8> output = data::convert(rgb8(), input);
+ const int nrows = input.nrows();
+ int ncols = input.ncols();
+
+ int n_max = int(float(ncols) / gap - o + 3);
+ for (int i = 0; i < n_max; ++i)
+ {
+ float col_ = (o + i) * gap;
+ int col = int(col_ + 0.49999);
+ if (col < 0)
+ continue;
+ if (col > ncols - 1)
+ break;
+ for (int row = 0; row < nrows; ++row)
+ output.at_(row, col) = rgb8(0,255,0);
+ }
+
+ io::ppm::save(output, argv[4]);
+ }
+
+
+
+}
Index: theo/experimental/depeche/row_mm.cc
--- theo/experimental/depeche/row_mm.cc (revision 0)
+++ theo/experimental/depeche/row_mm.cc (revision 0)
@@ -0,0 +1,96 @@
+#include <mln/core/image/image2d.hh>
+#include <mln/core/alias/neighb2d.hh>
+
+#include <mln/core/image/image1d.hh>
+#include <mln/core/alias/neighb1d.hh>
+
+#include <mln/fun/v2v/projection.hh>
+#include <mln/core/image/dmorph/unproject_image.hh>
+#include <mln/core/image/dmorph/image_if.hh>
+#include <mln/pw/value.hh>
+
+#include <mln/accu/stat/mean.hh>
+#include <mln/accu/image/init.hh>
+#include <mln/accu/image/take.hh>
+#include <mln/accu/image/to_result.hh>
+
+#include <mln/value/int_u8.hh>
+#include <mln/io/pgm/load.hh>
+#include <mln/io/pgm/save.hh>
+#include <mln/io/plot/save.hh>
+
+#include <mln/value/rgb8.hh>
+#include <mln/io/ppm/save.hh>
+// #include <mln/draw/line.hh>
+// #include <mln/literal/colors.hh>
+
+#include <mln/morpho/closing/volume.hh>
+#include <mln/morpho/opening/volume.hh>
+
+#include <mln/labeling/regional_minima.hh>
+#include <mln/labeling/regional_maxima.hh>
+#include <mln/data/convert.hh>
+
+
+
+void usage(char* argv[])
+{
+ std::cerr << "usage: " << argv[0] << " input.pgm
lambda output.pgm" << std::endl;
+ abort();
+}
+
+
+
+int main(int argc, char* argv[])
+{
+ using namespace mln;
+ using value::int_u8;
+ using value::rgb8;
+
+ if (argc != 4)
+ usage(argv);
+
+ image2d<int_u8> input;
+ io::pgm::load(input, argv[1]);
+ box2d b = input.domain();
+
+ int lambda = std::atoi(argv[2]);
+
+ typedef accu::stat::mean<int_u8, unsigned, int_u8> A;
+
+ image1d<A> hmean(b.nrows());
+ accu::image::init(hmean);
+
+ fun::v2v::projection<point2d, 1> hproj;
+ accu::image::take(unproject(hmean, b, hproj).rw(), input);
+
+ image1d<int_u8> h = accu::image::to_result(hmean);
+ io::plot::save(h, "temp_h0.txt");
+
+ h = morpho::closing::volume(h, c2(), lambda);
+ io::plot::save(h, "temp_h1.txt");
+
+ h = morpho::opening::volume(h, c2(), lambda);
+ io::plot::save(h, "temp_h2.txt");
+
+
+ {
+ int_u8 n;
+ image1d<int_u8>
+ lab_bg = labeling::regional_maxima(h, c2(), n),
+ lab_fg = labeling::regional_minima(h, c2(), n);
+
+ image2d<rgb8> cool = data::convert(rgb8(), input);
+ mln_piter_(box2d) p(cool.domain());
+ for_all(p)
+ {
+ if (lab_bg.at_(p.row()) != 0)
+ cool(p).red() = 255;
+ if (lab_fg.at_(p.row()) != 0)
+ cool(p).green() = 255;
+ }
+ io::ppm::save(cool, "temp_cool.ppm");
+ }
+
+ // io::pgm::save(output, argv[2]);
+}
Index: theo/experimental/depeche/row.cc
--- theo/experimental/depeche/row.cc (revision 0)
+++ theo/experimental/depeche/row.cc (revision 0)
@@ -0,0 +1,117 @@
+#include <mln/core/image/image2d.hh>
+#include <mln/core/alias/neighb2d.hh>
+
+#include <mln/core/image/image1d.hh>
+#include <mln/core/alias/neighb1d.hh>
+
+#include <mln/fun/v2v/projection.hh>
+#include <mln/core/image/dmorph/unproject_image.hh>
+#include <mln/core/image/dmorph/image_if.hh>
+#include <mln/pw/value.hh>
+
+#include <mln/accu/stat/mean.hh>
+#include <mln/accu/image/init.hh>
+#include <mln/accu/image/take.hh>
+#include <mln/accu/image/to_result.hh>
+
+#include <mln/value/int_u8.hh>
+#include <mln/io/pgm/load.hh>
+#include <mln/io/pgm/save.hh>
+#include <mln/io/plot/save.hh>
+
+#include <mln/value/rgb8.hh>
+#include <mln/io/ppm/save.hh>
+
+#include <mln/linear/gaussian_1d.hh>
+#include <mln/data/fill.hh>
+#include <mln/data/convert.hh>
+
+#include <mln/labeling/regional_minima.hh>
+#include <mln/draw/line.hh>
+#include <mln/literal/colors.hh>
+
+#include <mln/accu/stat/median_h.hh>
+
+
+
+void usage(char* argv[])
+{
+ std::cerr << "usage: " << argv[0] << " input.pgm
output.ppm" << std::endl;
+ abort();
+}
+
+
+
+int main(int argc, char* argv[])
+{
+ using namespace mln;
+ using value::int_u8;
+ using value::rgb8;
+
+ if (argc != 3)
+ usage(argv);
+
+ image2d<int_u8> input;
+ io::pgm::load(input, argv[1]);
+ box2d b = input.domain();
+
+ typedef accu::stat::mean<int_u8, unsigned, double> A;
+
+ image1d<A> hmean(b.nrows());
+ accu::image::init(hmean);
+
+ fun::v2v::projection<point2d, 1> hproj;
+ accu::image::take(unproject(hmean, b, hproj).rw(), input);
+
+ image1d<double> hmean_d = accu::image::to_result(hmean);
+ io::plot::save(hmean_d, "temp_h.txt");
+
+ hmean_d = linear::gaussian_1d(hmean_d, 5, 255);
+ io::plot::save(hmean_d, "temp_hg.txt");
+
+ io::plot::save(hmean, argv[2]);
+
+ int_u8 n;
+ image1d<int_u8> lab = labeling::regional_minima(hmean_d, c2(), n);
+ // io::plot::save(lab, "temp_lab.txt");
+
+
+ {
+ image2d<rgb8> cool = data::convert(rgb8(), input);
+ mln_piter_(box1d) p(lab.domain());
+ for_all(p)
+ if (lab(p) != 0)
+ draw::line(cool,
+ point2d(p.ind(), 0),
+ point2d(p.ind(), b.ncols() -1),
+ literal::red);
+ io::ppm::save(cool, argv[2]);
+ }
+
+// accu::stat::median_h<int_u8> med;
+// {
+// double min = 255;
+// unsigned row_min;
+// int last = -1;
+// mln_piter_(box1d) p(lab.domain());
+// for_all(p)
+// {
+// if (lab(p) == 0)
+// continue;
+// if (hmean_d(p) < min)
+// {
+// min = hmean_d(p);
+// row_min = p.ind();
+// }
+// if (last == -1)
+// last = p.ind();
+// else
+// {
+// med.take(p.ind() - last);
+// last = p.ind();
+// }
+// }
+// std::cout << med << ' ' << row_min << std::endl;
+// }
+
+}