1986: Add an extra test on Meyer's WST on a synthetic line graph image.

https://svn.lrde.epita.fr/svn/oln/trunk/milena Index: ChangeLog from Roland Levillain <roland@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)
participants (1)
-
Roland Levillain