1021: New 2D window types in mln.

https://svn.lrde.epita.fr/svn/oln/trunk/milena Index: ChangeLog from Thierry Geraud <thierry.geraud@lrde.epita.fr> New 2D window types in mln. * tests/median.cc: Clean up. * tests/hmedian.cc: New. * tests/erosion.cc: Clean up. * tests/rectangle2d.cc: Update. * mln/core/hline2d.hh: New. * mln/core/rectangle2d.hh (half_width_, half_height_): Change to... (width_, height_): ...these. Update. * mln/core/vline2d.hh: New. * mln/morpho/erosion.hh (erosion_wrt_win): New overload. * mln/level/was.median.hh: New. * mln/level/approx: New. * mln/level/approx/median.hh: New. * mln/level/median.hh (median_as_procedure): Move into... * mln/level/was.hmedian.hh: ...this new file. mln/core/hline2d.hh | 176 ++++++++++++++++++++++++++++++++++++++++++++ mln/core/rectangle2d.hh | 48 ++++++------ mln/core/vline2d.hh | 178 +++++++++++++++++++++++++++++++++++++++++++++ mln/level/approx/median.hh | 90 ++++++++++++++++++++++ mln/level/median.hh | 157 +++++++++++++++++---------------------- mln/level/was.hmedian.hh | 102 +++++++++++++++++++++++++ mln/level/was.median.hh | 136 ++++++++++++++++++++++++++++++++++ mln/morpho/erosion.hh | 31 ++++++- tests/erosion.cc | 8 +- tests/hmedian.cc | 64 ++++++++++++++++ tests/median.cc | 15 ++- tests/rectangle2d.cc | 4 - 12 files changed, 883 insertions(+), 126 deletions(-) Index: tests/median.cc --- tests/median.cc (revision 1020) +++ tests/median.cc (working copy) @@ -38,21 +38,26 @@ #include <mln/value/int_u.hh> #include <mln/level/median.hh> +#include <mln/level/approx/median.hh> -using namespace mln; -using namespace mln::value; int main() { - rectangle2d rec(64, 64); - border::thickness = 66; + using namespace mln; + using value::int_u8; + + rectangle2d rect(51, 51); + border::thickness = 52; image2d_b<int_u8> lena = io::load_pgm("../img/lena.pgm"), out(lena.domain()); - level::median(lena, rec, out); + level::median(lena, rect, out); io::save_pgm(out, "out.pgm"); + +// level::approx::median(lena, rec, out); +// io::save_pgm(out, "outa.pgm"); } Index: tests/hmedian.cc --- tests/hmedian.cc (revision 0) +++ tests/hmedian.cc (revision 0) @@ -0,0 +1,64 @@ +// Copyright (C) 2007 EPITA Research and Development Laboratory +// +// 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/hmedian.cc + * + * \brief Test on the hline2d version of mln::level::median. + */ + +#include <mln/core/image2d_b.hh> +#include <mln/core/rectangle2d.hh> + +#include <mln/io/load_pgm.hh> +#include <mln/io/save_pgm.hh> + +#include <mln/value/int_u.hh> +#include <mln/level/median.hh> +#include <mln/level/compare.hh> + + + + +int main() +{ + using namespace mln; + using value::int_u8; + + border::thickness = 0; + + image2d_b<int_u8> + lena = io::load_pgm("../img/lena.pgm"), + out(lena.domain()), + ref(lena.domain()); + + level::median(lena, rectangle2d(1, 101), ref); + + level::median(lena, hline2d(101), out); + io::save_pgm(out, "out.pgm"); + + // FIXME: mln_assertion(out = ref); +} Index: tests/erosion.cc --- tests/erosion.cc (revision 1020) +++ tests/erosion.cc (working copy) @@ -45,13 +45,13 @@ #include <mln/fun/ops.hh> -using namespace mln; -using namespace mln::value; - int main() { - rectangle2d rec(4, 4);//64, 64); + using namespace mln; + using value::int_u8; + + rectangle2d rec(21, 21); border::thickness = 66; image2d_b<int_u8> Index: tests/rectangle2d.cc --- tests/rectangle2d.cc (revision 1020) +++ tests/rectangle2d.cc (working copy) @@ -38,12 +38,12 @@ { using namespace mln; - const unsigned h = 3, w = 4; + const unsigned h = 3, w = 5; rectangle2d rec(h, w); mln_assertion(rec.is_centered()); mln_assertion(rec.is_symmetric()); mln_assertion(rec = -rec); - mln_assertion(rec.nelements() = (2*h+1) * (2*w+1)); + mln_assertion(rec.nelements() = h * w); } Index: mln/core/hline2d.hh --- mln/core/hline2d.hh (revision 0) +++ mln/core/hline2d.hh (revision 0) @@ -0,0 +1,176 @@ +// Copyright (C) 2007 EPITA Research and Development Laboratory +// +// 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. + +#ifndef MLN_CORE_HLINE2D_HH +# define MLN_CORE_HLINE2D_HH + +/*! \file mln/core/hline2d.hh + * + * \brief Definition of the mln::hline2d window. + */ + +# include <mln/core/concept/window.hh> +# include <mln/core/internal/set_of.hh> +# include <mln/core/dpoint2d.hh> +# include <mln/core/dpoints_piter.hh> + + +namespace mln +{ + + /*! \brief Horizontal line window defined on the 2D square grid. + * + * An hline2d is centered and symmetrical; so its height is 1 and + * its width (length) is odd. + * + * For instance: \n + * o o x o o \n + * is defined with length = 5. + */ + struct hline2d : public Window< hline2d >, + public internal::set_of_<dpoint2d> + { + /// Point associated type. + typedef point2d point; + + /// Dpoint associated type. + typedef dpoint2d dpoint; + + /*! \brief Piter type to browse a hline such as: "for each row + * (increasing), for each column (increasing)." + */ + typedef dpoints_fwd_piter<dpoint2d> fwd_qiter; + + /*! \brief Piter type to browse a hline such as: "for each row + * (decreasing), for each column (decreasing)." + */ + typedef dpoints_fwd_piter<dpoint2d> bkd_qiter; // FIXME: bkd!!! + + /*! \brief Same as fwd_qiter. + */ + typedef fwd_qiter qiter; + + /*! \brief Constructor. + * + * \param[in] length Length, thus width, of the horizontal line. + * + * \pre \p length is odd. + */ + hline2d(unsigned length); + + /*! \brief Test if the window is centered. + * + * \return True. + */ + bool is_centered() const; + + /*! \brief Test if the window is symmetric. + * + * \return true. + */ + bool is_symmetric() const; + + /*! \brief Give the hline length, that is, its width. + */ + unsigned length() const; + + /*! \brief Give the maximum coordinate gap between the window + * center and a window point. + */ + unsigned delta() const; + + /// Get the symmetrical window. + hline2d sym_() const; + + protected: + unsigned length_; + }; + + + /*! \brief Print an horizontal 2D line window \p win into the output + * stream \p ostr. + * + * \param[in,out] ostr An output stream. + * \param[in] win An horizontal 2D line window. + * + * \return The modified output stream \p ostr. + * + * \relates mln::hline2d + */ + std::ostream& operator<<(std::ostream& ostr, const hline2d& win); + + + +# ifndef MLN_INCLUDE_ONLY + + hline2d::hline2d(unsigned length) + : length_(length) + { + mln_precondition(length % 2 = 1); + const int dcol = length / 2; + for (int col = - dcol; col <= dcol; ++col) + insert(make::dpoint2d(0, col)); + } + + bool hline2d::is_centered() const + { + return true; + } + + bool hline2d::is_symmetric() const + { + return true; + } + + unsigned hline2d::length() const + { + return length_; + } + + unsigned hline2d::delta() const + { + return length_ / 2; + } + + hline2d hline2d::sym_() const + { + return *this; + } + + std::ostream& operator<<(std::ostream& ostr, const hline2d& win) + { + ostr << "[line2d: length=" << win.length() << ']'; + return ostr; + } + +# endif // ! MLN_INCLUDE_ONLY + +} // end of namespace mln + + + +#endif // ! MLN_CORE_HLINE2D_HH Index: mln/core/rectangle2d.hh --- mln/core/rectangle2d.hh (revision 1020) +++ mln/core/rectangle2d.hh (working copy) @@ -47,13 +47,11 @@ * A rectangle2d is a 2D window with rectangular shape. It is * centered and symmetrical. * - * For instance: - * o o o o o - * o o x o o - * o o o o o - * is defined with half_height = 1 and half_width = 2. - * - * \todo Consider width instead of half_width (same for height). + * For instance: \n + * o o o o o \n + * o o x o o \n + * o o o o o \n + * is defined with height = 3 and width = 5. */ struct rectangle2d : public Window< rectangle2d >, public internal::set_of_<dpoint2d> @@ -80,12 +78,12 @@ /*! \brief Constructor. * - * \param[in] half_height sic - * \param[in] half_width sic + * \param[in] height sic + * \param[in] width sic * - * \pre half_height != 0 and half_width != 0 + * \pre Height and width are odd. */ - rectangle2d(unsigned half_height, unsigned half_width); + rectangle2d(unsigned height, unsigned width); /*! \brief Test if the window is centered. * @@ -116,7 +114,7 @@ rectangle2d sym_() const; protected: - unsigned half_height_, half_width_; + unsigned height_, width_; }; @@ -136,12 +134,12 @@ # ifndef MLN_INCLUDE_ONLY - rectangle2d::rectangle2d(unsigned half_height, unsigned half_width) - : half_height_(half_height), - half_width_(half_width) + rectangle2d::rectangle2d(unsigned height, unsigned width) + : height_(height), + width_(width) { - mln_precondition(half_height != 0 && half_width != 0); - const int drow = half_height, dcol = half_width; + mln_precondition(height % 2 = 1 && width % 2 = 1); + const int drow = height / 2, dcol = width / 2; for (int row = - drow; row <= drow; ++row) for (int col = - dcol; col <= dcol; ++col) insert(make::dpoint2d(row, col)); @@ -159,17 +157,17 @@ unsigned rectangle2d::height() const { - return 2 * half_height_ + 1; + return height_; } unsigned rectangle2d::width() const { - return 2 * half_width_ + 1; + return width_; } unsigned rectangle2d::delta() const { - return half_width_ > half_height_ ? half_width_ : half_height_; + return width_ > height_ ? width_ / 2 : height_ / 2; } rectangle2d rectangle2d::sym_() const @@ -177,10 +175,9 @@ return *this; } - std::ostream& operator<<(std::ostream& ostr, - const rectangle2d& win) + std::ostream& operator<<(std::ostream& ostr, const rectangle2d& win) { - ostr << "[width=" << win.width() << ", height=" << win.height() << ']'; + ostr << "[rectangle2d: width=" << win.width() << ", height=" << win.height() << ']'; return ostr; } @@ -190,4 +187,9 @@ +// when rectangle2d is involved, one surely also wants: +# include <mln/core/hline2d.hh> +# include <mln/core/vline2d.hh> + + #endif // ! MLN_CORE_RECTANGLE2D_HH Index: mln/core/vline2d.hh --- mln/core/vline2d.hh (revision 0) +++ mln/core/vline2d.hh (revision 0) @@ -0,0 +1,178 @@ +// Copyright (C) 2007 EPITA Research and Development Laboratory +// +// 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. + +#ifndef MLN_CORE_VLINE2D_HH +# define MLN_CORE_VLINE2D_HH + +/*! \file mln/core/vline2d.hh + * + * \brief Definition of the mln::vline2d window. + */ + +# include <mln/core/concept/window.hh> +# include <mln/core/internal/set_of.hh> +# include <mln/core/dpoint2d.hh> +# include <mln/core/dpoints_piter.hh> + + +namespace mln +{ + + /*! \brief Vertical line window defined on the 2D square grid. + * + * An vline2d is centered and symmetrical; so its width is 1 and + * its height (length) is odd. + * + * For instance: \n + * o \n + * x \n + * o \n + * is defined with length = 5. + */ + struct vline2d : public Window< vline2d >, + public internal::set_of_<dpoint2d> + { + /// Point associated type. + typedef point2d point; + + /// Dpoint associated type. + typedef dpoint2d dpoint; + + /*! \brief Piter type to browse a vline such as: "for each row + * (increasing), for each column (increasing)." + */ + typedef dpoints_fwd_piter<dpoint2d> fwd_qiter; + + /*! \brief Piter type to browse a vline such as: "for each row + * (decreasing), for each column (decreasing)." + */ + typedef dpoints_fwd_piter<dpoint2d> bkd_qiter; // FIXME: bkd!!! + + /*! \brief Same as fwd_qiter. + */ + typedef fwd_qiter qiter; + + /*! \brief Constructor. + * + * \param[in] length Length, thus height, of the vertical line. + * + * \pre \p length is odd. + */ + vline2d(unsigned length); + + /*! \brief Test if the window is centered. + * + * \return True. + */ + bool is_centered() const; + + /*! \brief Test if the window is symmetric. + * + * \return true. + */ + bool is_symmetric() const; + + /*! \brief Give the vline length, that is, its height. + */ + unsigned length() const; + + /*! \brief Give the maximum coordinate gap between the window + * center and a window point. + */ + unsigned delta() const; + + /// Get the symmetrical window. + vline2d sym_() const; + + protected: + unsigned length_; + }; + + + /*! \brief Print a vertical 2D line window \p win into the output + * stream \p ostr. + * + * \param[in,out] ostr An output stream. + * \param[in] win A vertical 2D line window. + * + * \return The modified output stream \p ostr. + * + * \relates mln::vline2d + */ + std::ostream& operator<<(std::ostream& ostr, const vline2d& win); + + + +# ifndef MLN_INCLUDE_ONLY + + vline2d::vline2d(unsigned length) + : length_(length) + { + mln_precondition(length % 2 = 1); + const int drow = length / 2; + for (int row = - drow; row <= drow; ++row) + insert(make::dpoint2d(row, 0)); + } + + bool vline2d::is_centered() const + { + return true; + } + + bool vline2d::is_symmetric() const + { + return true; + } + + unsigned vline2d::length() const + { + return length_; + } + + unsigned vline2d::delta() const + { + return length_ / 2; + } + + vline2d vline2d::sym_() const + { + return *this; + } + + std::ostream& operator<<(std::ostream& ostr, const vline2d& win) + { + ostr << "[line2d: length=" << win.length() << ']'; + return ostr; + } + +# endif // ! MLN_INCLUDE_ONLY + +} // end of namespace mln + + + +#endif // ! MLN_CORE_VLINE2D_HH Index: mln/morpho/erosion.hh --- mln/morpho/erosion.hh (revision 1020) +++ mln/morpho/erosion.hh (working copy) @@ -106,6 +106,7 @@ // FIXME: stage 3: dispatch w.r.t. fast property + // stage 2: dispatch w.r.t. the value kind template <typename I, typename W, typename O> @@ -123,19 +124,34 @@ } + // stage 1: dispatch w.r.t. the window type + // | + // V - template <typename I, typename W, typename O> // general case + template <typename I, typename W, typename O> void erosion_wrt_win(const Image<I>& input, const Window<W>& win, Image<O>& output) { erosion_wrt_value(mln_kind(I)(), exact(input), exact(win), output); + // | + // --> call stage 2: dispatch w.r.t. the value kind } -// template <typename I, typename O> // rectangle2d -// void erosion_wrt_win(const Image<I>& input, const rectangle2d& win, Image<O>& output) -// { -// return FIXME; -// } +# ifdef MLN_CORE_RECTANGLE2D_HH + + template <typename I, typename O> + void erosion_wrt_win(const Image<I>& input, const rectangle2d& win, Image<O>& output) + { + O tmp(exact(output).domain()); + morpho::erosion(input, hline2d(win.width()), tmp); + morpho::erosion(tmp, vline2d(win.height()), output); + } + +# endif // MLN_CORE_RECTANGLE2D_HH + + // ^ + // | + // end of stage1 (dispatch w.r.t. the window type) } // end of namespace mln::morpho::impl @@ -146,6 +162,9 @@ template <typename I, typename W, typename O> void erosion(const Image<I>& input, const Window<W>& win, Image<O>& output) { + mln_precondition(exact(output).domain() = exact(input).domain()); + mln_precondition(! exact(win).is_empty()); + impl::erosion_wrt_win(input, exact(win), output); if (exact(win).is_centered()) mln_postcondition(output <= input); Index: mln/level/was.median.hh --- mln/level/was.median.hh (revision 0) +++ mln/level/was.median.hh (revision 0) @@ -0,0 +1,136 @@ +// Copyright (C) 2007 EPITA Research and Development Laboratory +// +// 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. + +#ifndef MLN_LEVEL_WAS_MEDIAN_HH +# define MLN_LEVEL_WAS_MEDIAN_HH + +/*! \file mln/level/was.median.hh + * + * \brief Obsolete routine for the median filter. + */ + + +namespace mln +{ + + namespace level + { + + namespace impl + { + + template <typename I, typename W, typename O> + void median_as_procedure(const I& input, + const W& win, + O& output) + { + mln_precondition(input.has_data()); + mln_precondition(output.has_data()); + + int + min_row = input.min_row(), max_row = input.max_row(), + min_col = input.min_col(), max_col = input.max_col(); + + window2d + win_fwd_plus = win - (win + left), + win_fwd_minus = (win + left) - win, + win_bkd_plus = win - (win + right), + win_bkd_minus = (win + right) - win, + win_bot = win - (win + up), + win_top = (win + up) - win; + + point2d p; + mln_qiter(W) + q_fp(win_fwd_plus, p), q_fm(win_fwd_minus, p), + q_bp(win_bkd_plus, p), q_bm(win_bkd_minus, p), + q_top(win_top, p), q_bot(win_bot, p); + + accu::median_on<mln_value(I)> med; + + // initialization + + p = input.domain().pmin() + up; + med.init(); + { + mln_qiter(W) q(win, p); + for_all(q) if (input.has(q)) + med.take(input(q)); + } + + int& row = p.row(); + int& col = p.col(); + bool fwd = true; + + mln_assertion(p.col() = min_col); + mln_assertion(p.row() = min_row - 1); + + for (row = min_row; row <= max_row; ++row) + { + // "go down" + for_all(q_top) if (input.has(q_top)) + med.untake(input(q_top)); + for_all(q_bot) if (input.has(q_bot)) + med.take(input(q_bot)); + output(p) = med; + + if (fwd) + // browse line fwd + while (col < max_col) + { + ++col; + for_all(q_fm) if (input.has(q_fm)) + med.untake(input(q_fm)); + for_all(q_fp) if (input.has(q_fp)) + med.take(input(q_fp)); + output(p) = med; + } + else + // browse line bkd + while (col > min_col) + { + --col; + for_all(q_bm) if (input.has(q_bm)) + med.untake(input(q_bm)); + for_all(q_bp) if (input.has(q_bp)) + med.take(input(q_bp)); + output(p) = med; + } + + // change browsing + fwd = ! fwd; + } + } + + + } // end of namespace mln::level::impl + + } // end of namespace mln::level + +} // end of namespace mln + + +#endif // ! MLN_LEVEL_WAS_MEDIAN_HH Index: mln/level/approx/median.hh --- mln/level/approx/median.hh (revision 0) +++ mln/level/approx/median.hh (revision 0) @@ -0,0 +1,90 @@ +// Copyright (C) 2007 EPITA Research and Development Laboratory +// +// 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. + +#ifndef MLN_LEVEL_APPROX_MEDIAN_HH +# define MLN_LEVEL_APPROX_MEDIAN_HH + +/*! \file mln/level/median.hh + * + * \brief Approximates of some median filters of an image. + */ + +# include <mln/level/median.hh> +# include <mln/core/rectangle2d.hh> + + +namespace mln +{ + + namespace level + { + + namespace approx + { + + /*! Compute in \p output an approximate of the median filter of + * image \p input by the 2D rectangle \p win. + * + * \param[in] input The image to be filtered. + * \param[in] win The rectangle. + * \param[in,out] output The output image. + * + * The approximation is based on a vertical median ran after + * an horizontal median. + * + * \pre \p input and \p output have to be initialized. + */ + template <typename I, typename O> + void median(const Image<I>& input, const rectangle2d& win, + Image<O>& output); + + +# ifndef MLN_INCLUDE_ONLY + + template <typename I, typename O> + void median(const Image<I>& input_, const rectangle2d& win, + Image<O>& output_) + { + const I& input = exact(input_); + O& output = exact(output_); + mln_assertion(output.domain() = input.domain()); + + O tmp(output.domain()); + level::median(input, hline2d(win.width()), tmp); + level::median(tmp, vline2d(win.height()), output); + } + +# endif // ! MLN_INCLUDE_ONLY + + } // end of namespace mln::level::approx + + } // end of namespace mln::level + +} // end of namespace mln + + +#endif // ! MLN_LEVEL_APPROX_MEDIAN_HH Index: mln/level/median.hh --- mln/level/median.hh (revision 1020) +++ mln/level/median.hh (working copy) @@ -34,9 +34,11 @@ */ # include <mln/core/concept/image.hh> + # include <mln/core/window2d.hh> -# include <mln/accu/median.hh> +# include <mln/core/hline2d.hh> +# include <mln/accu/median.hh> # include <mln/canvas/sbrowsing.hh> @@ -66,88 +68,6 @@ namespace impl { - template <typename I, typename W, typename O> - void median_as_procedure(const I& input, - const W& win, - O& output) - { - mln_precondition(input.has_data()); - mln_precondition(output.has_data()); - - int - min_row = input.min_row(), max_row = input.max_row(), - min_col = input.min_col(), max_col = input.max_col(); - - window2d - win_fwd_plus = win - (win + left), - win_fwd_minus = (win + left) - win, - win_bkd_plus = win - (win + right), - win_bkd_minus = (win + right) - win, - win_bot = win - (win + up), - win_top = (win + up) - win; - - point2d p; - mln_qiter(W) - q_fp(win_fwd_plus, p), q_fm(win_fwd_minus, p), - q_bp(win_bkd_plus, p), q_bm(win_bkd_minus, p), - q_top(win_top, p), q_bot(win_bot, p); - - accu::median_on<mln_value(I)> med; - - // initialization - - p = input.domain().pmin() + up; - med.init(); - { - mln_qiter(W) q(win, p); - for_all(q) if (input.has(q)) - med.take(input(q)); - } - - int& row = p.row(); - int& col = p.col(); - bool fwd = true; - - mln_assertion(p.col() = min_col); - mln_assertion(p.row() = min_row - 1); - - for (row = min_row; row <= max_row; ++row) - { - // "go down" - for_all(q_top) if (input.has(q_top)) - med.untake(input(q_top)); - for_all(q_bot) if (input.has(q_bot)) - med.take(input(q_bot)); - output(p) = med; - - if (fwd) - // browse line fwd - while (col < max_col) - { - ++col; - for_all(q_fm) if (input.has(q_fm)) - med.untake(input(q_fm)); - for_all(q_fp) if (input.has(q_fp)) - med.take(input(q_fp)); - output(p) = med; - } - else - // browse line bkd - while (col > min_col) - { - --col; - for_all(q_bm) if (input.has(q_bm)) - med.untake(input(q_bm)); - for_all(q_bp) if (input.has(q_bp)) - med.take(input(q_bp)); - output(p) = med; - } - - // change browsing - fwd = ! fwd; - } - } - template <typename I, typename W, typename O> struct median_functor @@ -167,7 +87,7 @@ // ctor - median_functor(I& input_, const W& win_, O& output_) + median_functor(const I& input_, const W& win_, O& output_) : // i/o input(exact(input_)), @@ -224,15 +144,79 @@ }; // end of median_functor + + template <typename I, typename W, typename O> - void median(I& input, const W& win, O& output) + void median(const I& input, const Window<W>& win, O& output) { // FIXME: resize border! - impl::median_functor<I,W,O> f(input, win, output); + impl::median_functor<I,W,O> f(input, exact(win), output); canvas::sbrowsing(f); } + + + template <typename I, typename O> + void median(const I& input, const hline2d& win, O& output) + { + const int + max_row = input.max_row(), + min_col = input.min_col(), + max_col = input.max_col(); + const unsigned half = win.length() / 2; + + point2d p; + int& row = p.row(); + int& col = p.col(); + + accu::median_on<mln_value(I)> med; + + for (row = input.min_row(); row <= max_row; ++row) + { + int ct, cu; + + // initialization (before first point of the row) + med.init(); + for (ct = min_col; ct < min_col + half; ++ct) + med.take(input.at(row, ct)); + + // left columns (just take new points) + for (col = min_col; col <= min_col + half; ++col, ++ct) + { + med.take(input.at(row, ct)); + output(p) = med; + } + + // middle columns (both take and untake) + cu = min_col; + for (; col <= max_col - half; ++cu, ++col, ++ct) + { + med.take(input.at(row, ct)); + med.untake(input.at(row, cu)); + output(p) = med; + } + + // right columns (now just untake old points) + for (; col <= max_col; ++cu, ++col) + { + med.untake(input.at(row, cu)); + output(p) = med; + } + } + } + + + // FIXME: Use transpose. + +// template <typename I, typename O> +// void median(const I& input, const vline2d& win, O& output) +// { + +// median(, hline2d(win.length()), output); +// } + + } // end of namespace mln::level::impl @@ -242,6 +226,7 @@ void median(const Image<I>& input, const Window<W>& win, Image<O>& output) { + mln_assertion(exact(output).domain() = exact(input).domain()); impl::median(exact(input), exact(win), exact(output)); } Index: mln/level/was.hmedian.hh --- mln/level/was.hmedian.hh (revision 0) +++ mln/level/was.hmedian.hh (revision 0) @@ -0,0 +1,102 @@ +// Copyright (C) 2007 EPITA Research and Development Laboratory +// +// 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. + +#ifndef MLN_LEVEL_WAS_HMEDIAN_HH +# define MLN_LEVEL_WAS_HMEDIAN_HH + +/*! \file mln/level/was.hmedian.hh + * + * \brief Median filtering of an image. + */ + + +namespace mln +{ + + namespace level + { + + namespace impl + { + + template <typename I, typename O> + void hmedian(const I& input, const hline2d& win, O& output) + { + const int + max_row = input.max_row(), + min_col = input.min_col(), + max_col = input.max_col(); + const unsigned half = win.length() / 2; + + point2d p; + int& row = p.row(); + int& col = p.col(); + + accu::median_on<mln_value(I)> med; + + for (row = input.min_row(); row <= max_row; ++row) + { + int ct, cu; + + // initialization (before first point of the row) + med.init(); + for (ct = min_col; ct < min_col + half; ++ct) + med.take(input.at(row, ct)); + + // left columns (just take new points) + for (col = min_col; col <= min_col + half; ++col, ++ct) + { + med.take(input.at(row, ct)); + output(p) = med; + } + + // middle columns (both take and untake) + cu = min_col; + for (; col <= max_col - half; ++cu, ++col, ++ct) + { + med.take(input.at(row, ct)); + med.untake(input.at(row, cu)); + output(p) = med; + } + + // right columns (now just untake old points) + for (; col <= max_col; ++cu, ++col) + { + med.untake(input.at(row, cu)); + output(p) = med; + } + } + } + + } // end of namespace mln::level::impl + + } // end of namespace mln::level + +} // end of namespace mln + + +#endif // ! MLN_LEVEL_WAS_HMEDIAN_HH
participants (1)
-
Thierry Geraud