https://svn.lrde.epita.fr/svn/oln/trunk/milena
I know I should probably move the tests related to the WST to
tests/morpho. Please recall this to me if I forget to do it. TIA.
Index: ChangeLog
from Roland Levillain <roland(a)lrde.epita.fr>
Add a test applying a full WST-based segmentation chain on a line
graph.
* tests/core/lena_line_graph_image_wst.cc: New test.
* tests/core/graph_image_wst.cc: Fix Doxygen header.
* tests/core/Makefile.am (check_PROGRAMS): Add
lena_line_graph_image_wst.
(lena_line_graph_image_wst_SOURCES)
(lena_line_graph_image_wst_CXXFLAGS):
New.
* tests/morpho/Makefile.am (meyer_wst_long_CXXFLAGS): Append
-ggdb.
core/Makefile.am | 5
core/graph_image_wst.cc | 4
core/lena_line_graph_image_wst.cc | 249 ++++++++++++++++++++++++++++++++++++++
morpho/Makefile.am | 2
4 files changed, 257 insertions(+), 3 deletions(-)
Index: tests/core/lena_line_graph_image_wst.cc
--- tests/core/lena_line_graph_image_wst.cc (revision 0)
+++ tests/core/lena_line_graph_image_wst.cc (revision 0)
@@ -0,0 +1,249 @@
+// 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.
+
+/// \file tests/core/line_graph_image.cc
+/// \brief Tests on the Watershed Transform on a mln::line_graph_image.
+
+#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/gradient.hh>
+#include <mln/morpho/closing_area.hh>
+#include <mln/morpho/meyer_wst.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/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. |
+ `--------*/
+
+ typedef int_u8 input_val_t;
+ image2d<input_val_t> input;
+// io::pgm::load(input, MLN_IMG_DIR "/small.pgm");
+ io::pgm::load(input, MLN_IMG_DIR "/tiny.pgm");
+
+ /* FIXME: Don't compute a gradient on the image2d input. Instead,
+ have the values of the line graph image /behaves/ as the gradient
+ of the input, i.e., edges should hold the absolute difference
+ between gray levels.
+ */
+ image2d<input_val_t> gradient =
+ morpho::gradient (input, convert::to_window(c4()));
+
+ // Simplify the input image.
+ image2d<input_val_t> work(input.domain());
+// morpho::closing_area(gradient, c4(), 50, work);
+ morpho::closing_area(gradient, c4(), 10, work);
+
+ /*-------------.
+ | Line graph. |
+ `-------------*/
+
+ // FIXME: Inlined conversion, to be reifed into a routine.
+
+ util::graph<point2d> g;
+
+ // Points.
+ /* FIXME: The need for such a structure during the conversion
+ exhibits the lack of a service from util::graph (or a another,
+ missing tool) regarding the retrieval of node ids from
+ points. */
+ std::map<point2d, util::node_id> points;
+ util::node_id id = 0;
+
+ // Nodes.
+ std::vector<int> node_values;
+ mln_fwd_piter_(image2d<input_val_t>) p(work.domain());
+ for_all (p)
+ {
+ g.add_node (p);
+ node_values.push_back (work(p));
+ /* FIXME: ``Guessing'' the id of the point just being inserted
+ is bad. utill:graph<N,E>::add_node should return this
+ id. */
+ points[p] = id;
+ ++id;
+ }
+
+ // Edges.
+ window2d next_c4_win;
+ next_c4_win.insert(0, 1).insert(1, 0);
+ std::vector<int> edge_values;
+ mln_fwd_qiter_(window2d) q(next_c4_win, p);
+ for_all (p)
+ for_all (q)
+ if (work.has(q))
+ {
+ g.add_edge(points[p], points[q]);
+ // FIXME: Keep this valuation function?
+ edge_values.push_back(math::max(work(p), work(q)));
+ }
+
+ // Line graph point set.
+ p_line_graph<point2d> plg(g);
+
+ // Line graph image.
+ /* FIXME: Shouldn't we use `input_val_t' instead of plain `int' as value
+ type here? */
+ typedef line_graph_image<point2d, int> ima_t;
+ ima_t lg_ima(plg, node_values, edge_values);
+
+ /*------.
+ | WST. |
+ `------*/
+
+ typedef line_graph_elt_neighborhood<point2d> nbh_t;
+ nbh_t nbh;
+
+ // Perform a Watershed Transform.
+ typedef int_u8 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);
+ // Reuse the piter on INPUT.
+ 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());
+// mln_niter_(neighb2d) n_out(c4(), p_out);
+ 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_point_(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/core/graph_image_wst.cc
--- tests/core/graph_image_wst.cc (revision 1719)
+++ tests/core/graph_image_wst.cc (working copy)
@@ -25,8 +25,8 @@
// reasons why the executable file might be covered by the GNU General
// Public License.
-/// \file tests/core/graph_image.cc
-/// \brief Tests on mln::graph_image.
+/// \file tests/core/graph_image_wst.cc
+/// \brief Tests on the Watershed Transform on a mln::graph_image.
#include <vector>
Index: tests/core/Makefile.am
--- tests/core/Makefile.am (revision 1731)
+++ tests/core/Makefile.am (working copy)
@@ -10,6 +10,7 @@
initialize \
graph_elt_window \
graph_image \
+ lena_line_graph_image_wst \
line_graph_elt_window \
line_graph_image \
line_graph_image_wst \
@@ -51,4 +52,8 @@
t_image_SOURCES = t_image.cc
tr_image_SOURCES = tr_image.cc
+# FIXME: We should isolate this test, as it takes a long time.
+lena_line_graph_image_wst_SOURCES = lena_line_graph_image_wst.cc
+lena_line_graph_image_wst_CXXFLAGS = -O3 -ggdb
+
TESTS = $(check_PROGRAMS)
Index: tests/morpho/Makefile.am
--- tests/morpho/Makefile.am (revision 1731)
+++ tests/morpho/Makefile.am (working copy)
@@ -35,6 +35,6 @@
meyer_wst_SOURCES = meyer_wst.cc
# FIXME: We should isolate this test, as it takes a long time.
meyer_wst_long_SOURCES = meyer_wst_long.cc
-meyer_wst_long_CXXFLAGS = -O3
+meyer_wst_long_CXXFLAGS = -O3 -ggdb
TESTS = $(check_PROGRAMS)