https://svn.lrde.epita.fr/svn/oln/trunk/milena
Index: ChangeLog
from Roland Levillain <roland(a)lrde.epita.fr>
Add an extra test on Meyer's WST on a synthetic line graph image.
* tests/morpho/artificial_line_graph_image_wst.cc: New test.
* tests/morpho/Makefile.am (check_PROGRAMS): Add
artificial_line_graph_image_wst.
(artificial_line_graph_image_wst_SOURCES)
(artificial_line_graph_image_wst_CXXFLAGS):
New.
(lena_line_graph_image_wst2_CXXFLAGS): Typo.
Makefile.am | 6 -
artificial_line_graph_image_wst.cc | 222 +++++++++++++++++++++++++++++++++++++
2 files changed, 227 insertions(+), 1 deletion(-)
Index: tests/morpho/artificial_line_graph_image_wst.cc
--- tests/morpho/artificial_line_graph_image_wst.cc (revision 0)
+++ tests/morpho/artificial_line_graph_image_wst.cc (revision 0)
@@ -0,0 +1,222 @@
+// Copyright (C) 2008 EPITA Research and Development Laboratory (LRDE)
+//
+// This file is part of the Olena Library. This library is free
+// software; you can redistribute it and/or modify it under the terms
+// of the GNU General Public License version 2 as published by the
+// Free Software Foundation.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this library; see the file COPYING. If not, write to
+// the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+// Boston, MA 02111-1307, USA.
+//
+// As a special exception, you may use this file as part of a free
+// software library without restriction. Specifically, if other files
+// instantiate templates or use macros or inline functions from this
+// file, or you compile this file and link it with other files to
+// produce an executable, this file does not by itself cause the
+// resulting executable to be covered by the GNU General Public
+// License. This exception does not however invalidate any other
+// reasons why the executable file might be covered by the GNU General
+// Public License.
+
+/* FIXME: We should factor as much things as possible between
+ tests/morpho/lena_line_graph_image_wst1.cc,
+ tests/morpho/lena_line_graph_image_wst2.cc and this file, starting
+ with conversion routines. */
+
+/** \file tests/morpho/artificial_line_graph_image_wst.cc
+ \brief Tests on the Watershed Transform (WST) on an artificial
+ mln::line_graph_image.
+
+ The scenario is as follows:
+ \li create an artificial (checkboard) 2-D image ;
+ \li convert this 2-D image into a line graph-based one, where values
+ on edges are computed as the absolute value of the difference
+ between the values on the nodes adjacent to the edge, so as to
+ create a (norm of the) gradient ``between the pixels'' of the
+ input image;
+ \li perform a WST on this line graph image;
+ \li create a 2-D, color output image with height and width double
+ the size the original one, and copy the data of the input image
+ in it, interpolating inter-pixel points;
+ \li print the watershed on lines into that same image, and save it. */
+
+#include <vector>
+
+#include <mln/core/image2d.hh>
+#include <mln/core/point2d.hh>
+#include <mln/core/window2d.hh>
+#include <mln/core/neighb2d.hh>
+
+#include <mln/core/line_graph_image.hh>
+#include <mln/core/line_graph_elt_neighborhood.hh>
+#include <mln/core/line_graph_neighborhood_piter.hh>
+
+#include <mln/morpho/line_gradient.hh>
+#include <mln/morpho/closing_area_on_vertices.hh>
+#include <mln/morpho/meyer_wst.hh>
+#include <mln/level/stretch.hh>
+
+#include <mln/value/int_u8.hh>
+#include <mln/value/int_u16.hh>
+#include <mln/value/rgb8.hh>
+#include <mln/literal/black.hh>
+#include <mln/literal/colors.hh>
+
+#include <mln/io/pgm/load.hh>
+#include <mln/io/pgm/save.hh>
+#include <mln/io/ppm/save.hh>
+
+#include <mln/math/max.hh>
+#include <mln/math/abs.hh>
+
+#include "tests/data.hh"
+
+
+
+int main()
+{
+ using namespace mln;
+ using value::int_u8;
+ using value::int_u16;
+ using value::rgb8;
+
+ /*--------.
+ | Input. |
+ `--------*/
+
+ // Dimensions.
+ const unsigned nrows = 100;
+ const unsigned ncols = 100;
+ const unsigned square_length = 3;
+ typedef int_u8 input_val_t;
+ // Create a checkboard image.
+ image2d<input_val_t> input (nrows, ncols);
+ for (unsigned r = 0; r < nrows; ++r)
+ for (unsigned c = 0; c < ncols; ++c)
+ input.at(r,c) =
+ ((r / square_length) % 2 == (c / square_length) % 2)
+ ? mln_min(input_val_t)
+ : mln_max(input_val_t);
+ std::cout << "nvertices = " << nrows * ncols << std::endl
+ << "nedges = " << 2 * nrows * ncols - (nrows + ncols) <<
std::endl;
+
+ /*----------------.
+ | Line gradient. |
+ `----------------*/
+
+ // Line graph image.
+ typedef line_graph_image<point2d, input_val_t> ima_t;
+ ima_t lg_ima = morpho::line_gradient(input);
+
+ /*------.
+ | WST. |
+ `------*/
+
+ typedef line_graph_elt_neighborhood<point2d> nbh_t;
+ nbh_t nbh;
+
+ // Perform a Watershed Transform.
+ typedef unsigned wst_val_t;
+ wst_val_t nbasins;
+ typedef line_graph_image<point2d, wst_val_t> wst_ima_t;
+ wst_ima_t wshed = morpho::meyer_wst(lg_ima, nbh, nbasins);
+ std::cout << "nbasins = " << nbasins << std::endl;
+
+ /*---------.
+ | Output. |
+ `---------*/
+
+ // FIXME: Inlined conversion, to be reifed into a routine.
+
+ // Save the result in gray levels (data) + color (wshed).
+
+ // Data.
+ typedef rgb8 output_val_t;
+ typedef image2d<output_val_t> output_t;
+ point2d output_pmin = input.domain().pmin();
+ point2d output_pmax(input.domain().pmax()[0] * 2,
+ input.domain().pmax()[1] * 2);
+ output_t output(box2d(output_pmin, output_pmax));
+ level::fill(output, literal::black);
+ mln_fwd_piter_(image2d<input_val_t>) p(input.domain());
+ for_all(p)
+ {
+ // Equivalent of P in OUTPUT.
+ point2d q(p[0] * 2, p[1] * 2);
+ input_val_t v = input(p);
+ /* FIXME: Use a conversion function from input_val_t to
+ output_val_t instead of an explicit construction. */
+ output(q) = output_val_t(v, v, v);
+ }
+ // Interpolate missing points in OUTPUT.
+ mln_piter_(output_t) p_out(output.domain());
+ for_all(p_out)
+ {
+ // Process points on even rows and odd columns
+ if (p_out[0] % 2 == 0 && p_out[1] % 2 == 1)
+ output(p_out) = (output(p_out + left) + output(p_out + right)) / 2;
+ // Process points on odd rows and even columns
+ if (p_out[0] % 2 == 1 && p_out[1] % 2 == 0)
+ output(p_out) = (output(p_out + up) + output(p_out + down)) / 2;
+ // Process points on odd rows and odd columns
+ if (p_out[0] % 2 == 1 && p_out[1] % 2 == 1)
+ output(p_out) =
+ (output(p_out + make::dpoint2d(-1, -1)) +
+ output(p_out + make::dpoint2d(-1, +1)) +
+ output(p_out + make::dpoint2d(+1, -1)) +
+ output(p_out + make::dpoint2d(+1, +1))) / 4;
+ }
+ // Draw the watershed.
+ /* FIXME: We should draw the watershed on another image and
+ superimpose it on OUTPUT instead of drawing it directly into
+ OUTPUT. */
+ mln_piter_(wst_ima_t) pw(wshed.domain());
+ for_all(pw)
+ {
+ if (wshed(pw) == 0)
+ {
+ mln_psite_(wst_ima_t) pp(pw);
+ // Equivalent of the line (edge) PP in OUTPUT.
+ int row1 = pp.first()[0] * 2;
+ int col1 = pp.first()[1] * 2;
+ int row2 = pp.second()[0] * 2;
+ int col2 = pp.second()[1] * 2;
+ point2d q((row1 + row2) / 2, (col1 + col2) / 2);
+ // Print the watershed in red.
+ output(q) = literal::red;
+ }
+ }
+ // Fill the holes, so that the watershed looks connected.
+ /* FIXME: This approach is bad: it creates thick lines of watershed.
+ We should probably solve this when we ``paint'' the watershed
+ over the ``doubled'' image.
+
+ A better approach is probably to iterate over the set of nodes,
+ and ``connect'' edges according to patterns (vertically or
+ horizontally connected egdes member of the watershed, etc.). */
+ // Reuse the piter on OUTPUT.
+ for_all (p_out)
+ // Only handle points on odd rows and columns.
+ if (p_out[0] % 2 == 1 && p_out[1] % 2 == 1)
+ {
+ // Count the number of adjacent watershed points. If there are
+ // two or more, consider, create a watershed point.
+ /* FIXME: Iterating over a c4 window would be more elegant, of
+ course. */
+ unsigned nwsheds =
+ (output.has(p_out + up ) && output(p_out + up ) == literal::red) +
+ (output.has(p_out + down ) && output(p_out + down ) == literal::red) +
+ (output.has(p_out + left ) && output(p_out + right) == literal::red) +
+ (output.has(p_out + right) && output(p_out + left ) == literal::red);
+ if (nwsheds >= 2)
+ output(p_out) = literal::red;
+ }
+ io::ppm::save(output, "out.ppm");
+}
Index: tests/morpho/Makefile.am
--- tests/morpho/Makefile.am (revision 1985)
+++ tests/morpho/Makefile.am (working copy)
@@ -3,6 +3,7 @@
include $(top_srcdir)/milena/tests/tests.mk
check_PROGRAMS = \
+ artificial_line_graph_image_wst \
closing_area \
combined \
contrast \
@@ -47,6 +48,9 @@
# Complex tests. #
# --------------- #
+artificial_line_graph_image_wst_SOURCES = artificial_line_graph_image_wst.cc
+artificial_line_graph_image_wst_CXXFLAGS = $(TESTS_CXXFLAGS_SPEED)
+
dilation_SOURCES = dilation.cc
dilation_CXXFLAGS = $(TESTS_CXXFLAGS_SPEED)
@@ -54,7 +58,7 @@
lena_line_graph_image_wst1_CXXFLAGS = $(TESTS_CXXFLAGS_SPEED)
lena_line_graph_image_wst2_SOURCES = lena_line_graph_image_wst2.cc
-lena_line_graph_image_wst2_CXXFLAGS = $(TESTSCXXFLAGS_SPEED)
+lena_line_graph_image_wst2_CXXFLAGS = $(TESTS_CXXFLAGS_SPEED)
meyer_wst_long_SOURCES = meyer_wst_long.cc
meyer_wst_long_CXXFLAGS = $(TESTS_CXXFLAGS_SPEED)