https://svn.lrde.epita.fr/svn/oln/trunk/milena/sandbox
Index: ChangeLog
from Thierry Geraud <thierry.geraud(a)lrde.epita.fr>
Start a code to segment color images.
* geraud/color: New directory.
* geraud/color/segment.cc: New.
* geraud/wst_edge.cc: Move...
* geraud/laurent/wst_edge.cc: ...here.
segment.cc | 254 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 254 insertions(+)
Property changes on: geraud/laurent/wst_edge.cc
___________________________________________________________________
Added: svn:mergeinfo
Index: geraud/color/segment.cc
--- geraud/color/segment.cc (revision 0)
+++ geraud/color/segment.cc (revision 0)
@@ -0,0 +1,254 @@
+# include <mln/core/var.hh>
+
+# include <mln/core/image/image2d.hh>
+# include <mln/core/alias/neighb2d.hh>
+
+# include <mln/core/image/image_if.hh>
+# include <mln/core/routine/extend.hh>
+# include <mln/pw/all.hh>
+
+# include <mln/io/ppm/load.hh>
+# include <mln/io/pgm/save.hh>
+# include <mln/io/ppm/save.hh>
+# include <mln/math/diff_abs.hh>
+
+# include <mln/make/double_neighb2d.hh>
+# include <mln/data/paste.hh>
+# include <mln/morpho/closing_volume.hh>
+# include <mln/morpho/meyer_wst.hh>
+# include <mln/morpho/dilation.hh>
+# include <mln/morpho/erosion.hh>
+
+# include <mln/debug/println.hh>
+
+
+namespace mln
+{
+
+ // Functions.
+
+ inline
+ bool is_row_odd(const point2d& p)
+ {
+ return p.row() % 2;
+ }
+
+ inline
+ bool is_square(const point2d& p)
+ {
+ return p.row() % 2 == 0 && p.col() % 2 == 0;
+ }
+
+ inline
+ bool is_edge(const point2d& p)
+ {
+ return p.row() % 2 + p.col() % 2 == 1;
+ }
+
+ inline
+ bool is_point(const point2d& p)
+ {
+ return p.row() % 2 && p.col() % 2;
+ }
+
+
+ // Transforms.
+
+ template <typename I>
+ I display_edge(const I& ima, mln_value(I) bg, unsigned zoom)
+ {
+ unsigned nrows = ima.nrows() / 2 + 1;
+ unsigned ncols = ima.ncols() / 2 + 1;
+ I output(nrows * (zoom + 1) - 1,
+ ncols * (zoom + 1) - 1);
+ data::fill(output, bg);
+ mln_VAR( edge, ima | is_edge );
+ mln_piter(edge_t) p(edge.domain());
+ for_all(p)
+ if (p.row() % 2) // horizontal edge
+ {
+ unsigned row = (p.row() / 2 + 1) * (zoom + 1) - 1;
+ unsigned col = (p.col() / 2) * (zoom + 1);
+ for (unsigned i = 0; i < zoom; ++i)
+ opt::at(output, row, col + i) = ima(p);
+ }
+ else // vertical edge
+ {
+ unsigned row = (p.row() / 2) * (zoom + 1);
+ unsigned col = (p.col() / 2 + 1) * (zoom + 1) - 1;
+ for (unsigned i = 0; i < zoom; ++i)
+ opt::at(output, row + i, col) = ima(p);
+ }
+ return output;
+ }
+
+ template <typename T>
+ image2d<T>
+ image2squares(const image2d<T>& input)
+ {
+ image2d<T> output(2 * input.nrows() - 1,
+ 2 * input.ncols() - 1);
+ for (int row = 0; row < input.nrows(); ++row)
+ for (int col = 0; col < input.ncols(); ++col)
+ opt::at(output, 2 * row, 2 * col) = opt::at(input, row, col);
+ return output;
+ }
+
+ template <typename T>
+ image2d<T>
+ squares2image(const image2d<T>& input)
+ {
+ image2d<T> output((input.nrows() + 1) / 2,
+ (input.ncols() + 1) / 2);
+ for (int row = 0; row < input.nrows(); row += 2)
+ for (int col = 0; col < input.ncols(); col += 2)
+ opt::at(output, row / 2, col / 2) =
+ opt::at(input, row, col);
+ return output;
+ }
+
+
+
+ // Distance.
+
+ value::int_u8 dist(const value::rgb8& c1, const value::rgb8& 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, typename N>
+ image2d<value::int_u8>
+ dist(const I& input, const N& nbh)
+ {
+ image2d<value::int_u8> output;
+ initialize(output, input);
+ data::fill(output, 0);
+
+ mln_piter(I) p(input.domain());
+ mln_niter(N) n(nbh, p);
+ for_all(p)
+ {
+ n.start();
+ value::rgb8 c1 = input(n);
+ n.next();
+ value::rgb8 c2 = input(n);
+ output(p) = dist(c1, c2);
+ }
+
+ return output;
+ }
+
+
+} // mln
+
+
+
+void usage(char* argv[])
+{
+ std::cerr << "usage: " << argv[0] << " input.ppm n
output.ppm" << std::endl;
+ std::cerr << " n >= 2" << 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<rgb8> raw_input, input;
+
+ io::ppm::load(raw_input, argv[1]);
+ input = image2squares(raw_input);
+
+ // e2c
+
+ bool e2c_h[] = { 0, 1, 0,
+ 0, 0, 0,
+ 0, 1, 0 };
+
+ bool e2c_v[] = { 0, 0, 0,
+ 1, 0, 1,
+ 0, 0, 0 };
+
+ mln_VAR( e2c, make::double_neighb2d(is_row_odd, e2c_h, e2c_v) );
+
+
+
+ image2d<int_u8> G = dist(extend(input | is_edge, pw::value(input)),
+ e2c);
+
+ mln_VAR(G_edges, G | is_edge);
+
+ /*
+ {
+ io::pgm::save(display_edge(G, 0, 3),
+ "temp_G.pgm");
+ }
+ */
+
+ // e2e
+
+ bool e2e_h[] = { 0, 0, 1, 0, 0,
+ 0, 1, 0, 1, 0,
+ 0, 0, 0, 0, 0,
+ 0, 1, 0, 1, 0,
+ 0, 0, 1, 0, 0 };
+
+ bool e2e_v[] = { 0, 0, 0, 0, 0,
+ 0, 1, 0, 1, 0,
+ 1, 0, 0, 0, 1,
+ 0, 1, 0, 1, 0,
+ 0, 0, 0, 0, 0 };
+
+ mln_VAR( e2e, make::double_neighb2d(is_row_odd, e2e_h, e2e_v) );
+
+ data::paste( morpho::closing_volume(G_edges, e2e, 50), G_edges );
+
+ /*
+ {
+ io::pgm::save(display_edge(G_edges.unmorph_(), 0, 3),
+ "temp_G_closed.pgm");
+ }
+ */
+
+ int_u8 nbasins;
+ mln_VAR(W_edges, morpho::meyer_wst(G_edges, e2e, nbasins));
+
+ /*
+ {
+ io::pgm::save(display_edge(W_edges.unmorph_(), 0, 3),
+ "temp_W_edges.pgm");
+ }
+ */
+
+ mln_VAR(W_all, W_edges.unmorph_());
+
+
+ mln_VAR(W_squares, W_all | is_square);
+ data::paste(morpho::dilation(extend(W_squares, pw::value(W_all)),
+ c4().win()),
+ W_all);
+
+ mln_VAR(W_points, W_all | is_point);
+ data::paste(morpho::erosion(extend(W_points, pw::value(W_all)),
+ c4().win()),
+ W_all);
+
+
+ {
+ io::pgm::save(W_all, "temp_W_all.pgm");
+ }
+
+}