https://svn.lrde.epita.fr/svn/oln/trunk/milena
Index: ChangeLog from Roland Levillain roland@lrde.epita.fr
Convert Meyer's WST implementation to neighborhood-based.
* mln/morpho/meyer_wst.hh: Use neighborhoods instead of windows to express the connexity of the markers. Use mln::labeling::regional_minima instead of mln::morpho::minima_components. * tests/morpho/meyer_wst.cc, * tests/morpho/meyer_wst_long.cc: Adjust tests.
mln/morpho/meyer_wst.hh | 91 ++++++++++++++++++++++++++--------------- tests/morpho/meyer_wst.cc | 10 +--- tests/morpho/meyer_wst_long.cc | 15 ++++-- 3 files changed, 70 insertions(+), 46 deletions(-)
Index: mln/morpho/meyer_wst.hh --- mln/morpho/meyer_wst.hh (revision 1698) +++ mln/morpho/meyer_wst.hh (working copy) @@ -45,7 +45,8 @@
# include <mln/util/greater_point.hh> # include <mln/morpho/includes.hh> -# include <mln/morpho/extrema_components.hh> +# include <mln/labeling/regional_minima.hh> +
namespace mln @@ -61,34 +62,58 @@ processing it. Then, add a reference to mln/morpho/lower_completion.hh. */
- /* FIXME: More doc. */ + /** \brief Meyer's Watershed Transform (WST) algorithm.
- /// Meyer's Watershed Transform (WST) algorithm. - template <typename DestValue, typename I, typename W> - mln_ch_value(I, DestValue) - meyer_wst(const Image<I>& input, const Window<W>& win, unsigned& nbasins); - - /// Meyer's Watershed Transform (WST) algorithm, with no count of - /// basins. - template <typename DestValue, typename I, typename W> - mln_ch_value(I, DestValue) - meyer_wst(const Image<I>& input, const Window<W>& win); + \param[in] input The input image. + \param[in] nbh The connexity of markers. + \param[out] nbasins The number of basins. + + \li \p L is the type of labels, used to number the watershed + itself (with the minimal value), and the basins. + \li \p I is the exact type of the input image. + \li \p N is the exact type of the neighborhood used to express + \a input's connexity. */ + template <typename L, typename I, typename N> + mln_ch_value(I, L) + meyer_wst(const Image<I>& input, const Neighborhood<N>& nbh, + L& nbasins); + + /** \brief Meyer's Watershed Transform (WST) algorithm, with no + count of basins. + + \param[in] input The input image. + \param[in] nbh The connexity of markers. + + \li \p L is the type of labels, used to number the watershed + itself (with the minimal value), and the basins. + \li \p I is the exact type of the input image. + \li \p N is the exact type of the neighborhood used to express + \a input's connexity. + + Note that the first parameter, \p L, is not automatically + valued from the type of the actual argument during implicit + instantiation: you have to explicitly pass this parameter at + call sites. */ + template <typename L, typename I, typename N> + mln_ch_value(I, L) + meyer_wst(const Image<I>& input, const Neighborhood<N>& nbh);
# ifndef MLN_INCLUDE_ONLY
- template <typename DestValue, typename I, typename W> - mln_ch_value(I, DestValue) - meyer_wst(const Image<I>& input, const Window<W>& win, unsigned& nbasins) + template <typename L, typename I, typename N> + mln_ch_value(I, L) + meyer_wst(const Image<I>& input, const Neighborhood<N>& nbh, + L& nbasins) { /* FIXME: Ensure the input image has scalar values. */
- typedef DestValue marker; + typedef L marker; const marker unmarked = mln_min(marker);
// Initialize the output with the markers (minima components). mln_ch_value(I, marker) markers = - minima_components<marker>(input, win, nbasins); + labeling::regional_minima (input, nbh, nbasins);
// Ordered queue. typedef mln_point(I) point; @@ -101,11 +126,11 @@ // hierarchical queue, with a priority level corresponding to // the grey level input(P). mln_piter(I) p(markers.domain()); - mln_qiter(W) q(win, p); + mln_niter(N) n(nbh, p); for_all (p) if (markers(p) == unmarked) - for_all(q) - if (markers.has(q) && markers(q) != unmarked) + for_all(n) + if (markers.has(n) && markers(n) != unmarked) { queue.push(p); break; @@ -122,16 +147,16 @@ marker adjacent_marker = unmarked; // Has P a single adjacent marker? bool single_adjacent_marker_p = true; - mln_qiter(W) q(win, p); - for_all(q) - if (markers.has(q) && markers(q) != unmarked) + mln_niter(N) n(nbh, p); + for_all(n) + if (markers.has(n) && markers(n) != unmarked) if (adjacent_marker == unmarked) { - adjacent_marker = markers(q); + adjacent_marker = markers(n); single_adjacent_marker_p = true; } else - if (adjacent_marker != markers(q)) + if (adjacent_marker != markers(n)) { single_adjacent_marker_p = false; break; @@ -143,20 +168,20 @@ if (single_adjacent_marker_p) { markers(p) = adjacent_marker; - for_all(q) - if (markers.has(q) && markers(q) == unmarked) - queue.push(q); + for_all(n) + if (markers.has(n) && markers(n) == unmarked) + queue.push(n); } } return markers; }
- template <typename DestValue, typename I, typename W> - mln_ch_value(I, DestValue) - meyer_wst(const Image<I>& input, const Window<W>& win) + template <typename L, typename I, typename N> + mln_ch_value(I, L) + meyer_wst(const Image<I>& input, const Neighborhood<N>& nbh) { - unsigned nbasins; - return meyer_wst<DestValue>(input, nbasins); + L nbasins; + return meyer_wst<L>(input, nbh, nbasins); }
# endif // ! MLN_INCLUDE_ONLY Index: tests/morpho/meyer_wst.cc --- tests/morpho/meyer_wst.cc (revision 1698) +++ tests/morpho/meyer_wst.cc (working copy) @@ -34,8 +34,6 @@ #include <mln/core/window2d.hh> #include <mln/core/neighb2d.hh>
-#include <mln/convert/to_window.hh> - #include <mln/value/int_u8.hh>
#include <mln/morpho/meyer_wst.hh> @@ -54,11 +52,9 @@ image2d<int_u8> input; io::pgm::load(input, MLN_IMG_DIR "/squares.pgm");
- typedef int_u8 output_val; - unsigned nbasins; - // FIXME: Do we really need to use a neighborood to express a 4-c window? - image2d<int_u8> output = - morpho::meyer_wst<output_val>(input, convert::to_window(c4()), nbasins); + typedef int_u8 wst_val; + wst_val nbasins; + image2d<int_u8> output = morpho::meyer_wst(input, c4(), nbasins); std::cout << "nbasins = " << nbasins << std::endl; io::pgm::save(output, "out.pgm"); } Index: tests/morpho/meyer_wst_long.cc --- tests/morpho/meyer_wst_long.cc (revision 1698) +++ tests/morpho/meyer_wst_long.cc (working copy) @@ -35,15 +35,17 @@ #include <mln/core/window2d.hh> #include <mln/core/neighb2d.hh>
-#include <mln/convert/to_window.hh> #include <mln/level/stretch.hh>
#include <mln/value/int_u8.hh> #include <mln/value/int_u16.hh>
+#include <mln/morpho/gradient.hh> #include <mln/morpho/closing_area.hh> #include <mln/morpho/meyer_wst.hh>
+#include <mln/convert/to_window.hh> + #include <mln/pw/cst.hh> #include <mln/pw/value.hh>
@@ -63,16 +65,17 @@ image2d<int_u8> input; io::pgm::load(input, MLN_IMG_DIR "/lena.pgm");
+ image2d<int_u8> gradient = + morpho::gradient (input, convert::to_window(c4())); + // Simplify the input image. image2d<int_u8> work(input.domain()); - morpho::closing_area(input, c4(), 200, work); + morpho::closing_area(gradient, c4(), 200, work);
// Perform a Watershed Transform. typedef int_u16 wst_val; - unsigned nbasins; - // FIXME: Do we really need to use a neighborood to express a 4-c window? - image2d<wst_val> ws = - morpho::meyer_wst<wst_val>(work, convert::to_window(c4()), nbasins); + wst_val nbasins; + image2d<wst_val> ws = morpho::meyer_wst(work, c4(), nbasins); std::cout << "nbasins = " << nbasins << std::endl;
// Save the image in color.