
https://svn.lrde.epita.fr/svn/oln/trunk/milena Index: ChangeLog from Thierry Geraud <thierry.geraud@lrde.epita.fr> Update level median filter with directional cases. * mln/core/point.hh (operator+=): New. * tests/dpoint2d.cc: Update. * mln/canvas/browsing/snake_fwd.hh: Fix missing namespace. * sandbox/nivault/dirbrowsing.hh: Rename as... * mln/canvas/dirbrowsing.hh: ...this. * mln/level/median.hh: Update. * sandbox/nivault/median.hh: Update. mln/canvas/browsing/snake_fwd.hh | 5 mln/canvas/dirbrowsing.hh | 2 mln/core/point.hh | 11 + mln/level/median.hh | 198 ++++++++++++++++++-------- sandbox/nivault/median.hh | 294 +++++++++++---------------------------- tests/dpoint2d.cc | 3 6 files changed, 250 insertions(+), 263 deletions(-) Index: tests/dpoint2d.cc --- tests/dpoint2d.cc (revision 1091) +++ tests/dpoint2d.cc (working copy) @@ -50,4 +50,7 @@ const int (&vec)[2] = dp.to_vec(); mln_assertion(vec[0] = 3); + + p += dp; + mln_assertion(q = p); } Index: mln/core/point.hh --- mln/core/point.hh (revision 1091) +++ mln/core/point.hh (working copy) @@ -96,6 +96,8 @@ /// Origin point (all coordinates are 0). static const point_<n,C> zero; + /// Shifting by \p dp. + point_<n, C>& operator+=(const dpoint& dp); /// Type of the array of coordinates. typedef const C (&vec_t)[n]; @@ -148,6 +150,15 @@ template <unsigned n, typename C> const point_<n,C> point_<n,C>::zero = all(0); + template <unsigned n, typename C> + point_<n, C>& + point_<n,C>::operator+=(const dpoint& dp) + { + for (unsigned i = 0; i < n; ++i) + coord_[i] += dp[i]; + return *this; + } + # endif // ! MLN_INCLUDE_ONLY } // end of namespace mln Index: mln/level/median.hh --- mln/level/median.hh (revision 1091) +++ mln/level/median.hh (working copy) @@ -31,21 +31,19 @@ /*! \file mln/level/median.hh * * \brief Median filtering of an image. + * + * \todo Add Fast_Image versions. */ # include <mln/core/concept/image.hh> -# include <mln/geom/size2d.hh> - -# include <mln/core/window2d.hh> -# include <mln/core/win/hline2d.hh> -# include <mln/core/t_image.hh> - -# include <mln/accu/median.hh> -# include <mln/canvas/browsing/snake_fwd.hh> - +# include <mln/core/window.hh> # include <mln/geom/shift.hh> # include <mln/set/diff.hh> +# include <mln/canvas/browsing/snake_fwd.hh> +# include <mln/canvas/dirbrowsing.hh> +# include <mln/accu/median.hh> + namespace mln { @@ -58,7 +56,7 @@ * * \param[in] input The image to be filtered. * \param[in] win The window. - * \param[in,out] output The output image. + * \param[out] output The output image. * * \pre \p input and \p output have to be initialized. */ @@ -67,16 +65,40 @@ Image<O>& output); -# ifndef MLN_INCLUDE_ONLY + + /*! Compute in \p output the median filter of image \p input in + * the direction \p dir with strength \p length. + * + * \param[in] input The image to be filtered. + * \param[in] dir The filtering direction. + * \param[in] length The filtering strength. + * \param[out] output The output image. + * + * \pre \p input and \p output have to be initialized. + * \pre \p dir is between 0 and less than the image dimension. + * \pre \p length has to be odd. + */ + template <typename I, typename O> + void median_dir(const Image<I>& input, unsigned dir, unsigned length, + Image<O>& output); + +# ifndef MLN_INCLUDE_ONLY + namespace impl { + // Functors. + + template <typename I, typename W, typename O> - struct median_functor + struct median_t { + typedef mln_point(I) P; + typedef mln_dpoint(I) D; + // i/o const I& input; @@ -86,13 +108,13 @@ // aux data accu::median<mln_vset(I)> med; - mln_point(I) p; - window2d win_fp, win_fm, win_bp, win_bm, win_dp, win_dm; + P p; + window<D> win_fp, win_fm, win_bp, win_bm, win_dp, win_dm; mln_qiter(W) q_fp, q_fm, q_bp, q_bm, q_dp, q_dm; // ctor - median_functor(const I& input_, const W& win_, O& output_) + median_t(const I& input_, const W& win_, O& output_) : // i/o input(exact(input_)), @@ -150,99 +172,163 @@ output(p) = med.to_value(); } - }; // end of median_functor + }; // end of median_t - - template <typename I, typename W, typename O> - void median(const I& input, const Window<W>& win, O& output) - { - // FIXME: resize border! - impl::median_functor<I,W,O> f(input, exact(win), output); - canvas::browsing::snake_fwd(f); - } - - template <typename I, typename O> - void median(const I& input, const win::hline2d& win, O& output) + struct median_dir_t { - typedef mln_coord(I) coord; - const coord - min_row = geom::min_row(input), - max_row = geom::max_row(input), - min_col = geom::min_col(input), - max_col = geom::max_col(input); - const coord half = win.length() / 2; + typedef mln_point(I) point; + enum { dim = point::dim }; - point2d p; - coord& row = p.row(); - coord& col = p.col(); + // i/o + const I& input; + const unsigned dir; + const unsigned length; + O& output; - point2d pt; - coord& ct = pt.col(); + // aux data + const mln_point(I) + pmin, pmax; + const mln_coord(I) + pmin_dir, pmax_dir, + pmin_dir_plus, pmax_dir_minus; + accu::median<mln_vset(I)> med; - point2d pu; - coord& cu = pu.col(); + // ctor + median_dir_t(const I& input, unsigned dir, unsigned length, O& output) + : // i/o + input(input), + dir(dir), + length(length), + output(exact(output)), + // aux data + pmin(input.domain().pmin()), + pmax(input.domain().pmax()), + pmin_dir(pmin[dir]), + pmax_dir(pmax[dir]), + pmin_dir_plus (pmin[dir] + length / 2), + pmax_dir_minus(pmax[dir] - length / 2), + med(input.values()) + { + } - accu::median<mln_vset(I)> med(input.values()); + void init() + { + } - for (row = min_row; row <= max_row; ++row) + void process(const mln_point(I)& p_) { - pt.row() = pu.row() = row; + mln_point(I) + p = p_, + pt = p, + pu = p; + + typedef mln_coord(I)& coord_ref; + coord_ref + ct = pt[dir], + cu = pu[dir], + p_dir = p[dir]; // initialization (before first point of the row) med.init(); - for (ct = min_col; ct < min_col + half; ++ct) + for (ct = pmin_dir; ct < pmin_dir_plus; ++ct) + if (input.has(pt)) med.take(input(pt)); // left columns (just take new points) - for (col = min_col; col <= min_col + half; ++col, ++ct) + for (p_dir = pmin_dir; p_dir <= pmin_dir_plus; ++p_dir, ++ct) { + if (input.has(pt)) med.take(input(pt)); + if (output.has(p)) output(p) = med.to_value(); } // middle columns (both take and untake) - cu = min_col; - for (; col <= max_col - half; ++cu, ++col, ++ct) + cu = pmin[dir]; + for (; p_dir <= pmax_dir_minus; ++cu, ++p_dir, ++ct) { + if (input.has(pt)) med.take(input(pt)); + if (input.has(pu)) med.untake(input(pu)); + if (output.has(p)) output(p) = med.to_value(); } // right columns (now just untake old points) - for (; col <= max_col; ++cu, ++col) + for (; p_dir <= pmax_dir; ++cu, ++p_dir) { + if (input.has(pu)) med.untake(input(pu)); + if (output.has(p)) output(p) = med.to_value(); } } + + }; // end of median_dir_t + + + + template <typename I, typename O> + void median_dir_(const Image<I>& input, unsigned dir, unsigned length, O& output) + { + median_dir_t<I,O> f(exact(input), dir, length, output); + canvas::dirbrowsing(f); } + template <typename I, typename W, typename O> + void median_(const Image<I>& input, const Window<W>& win, O& output) + { + // FIXME: resize border! + median_t<I,W,O> f(exact(input), exact(win), output); + canvas::browsing::snake_fwd(f); + } + + +# ifdef MLN_CORE_WIN_HLINE2D_HH + template <typename I, typename O> + void median_(const Image<I>& input, const win::hline2d& win, O& output) + { + median_dir(input, 1, win.length(), output); // FIXME: Make 1 explicit! + } +# endif + +# ifdef MLN_CORE_WIN_VLINE2D_HH template <typename I, typename O> - void median(const I& input, const win::vline2d& win, O& output) + void median_(const Image<I>& input, const win::vline2d& win, O& output) { - t_image<O> swap_output = swap_coords(output, 0, 1); - impl::median(swap_coords(input, 0, 1), - win::hline2d(win.length()), - swap_output); + median_dir(input, 0, win.length(), output); } +# endif } // end of namespace mln::level::impl - // facade + + // Facades. template <typename I, typename W, typename O> 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)); + impl::median_(exact(input), exact(win), exact(output)); + } + + template <typename I, typename O> + void median_dir(const Image<I>& input, unsigned dir, unsigned length, + Image<O>& output) + { + mln_precondition(exact(output).domain() = exact(input).domain()); + typedef mln_point(I) P; + mln_precondition(dir < P::dim); + mln_precondition(length % 2 = 1); + impl::median_dir_(exact(input), dir, length, exact(output)); } # endif // ! MLN_INCLUDE_ONLY Index: mln/canvas/dirbrowsing.hh --- mln/canvas/dirbrowsing.hh (revision 1090) +++ mln/canvas/dirbrowsing.hh (working copy) @@ -75,7 +75,7 @@ { f.process(p); - for (int c = f.dim - 1; c >= 0; --c) + for (int c = F::dim - 1; c >= 0; --c) { if (c = f.dir) continue; Index: mln/canvas/browsing/snake_fwd.hh --- mln/canvas/browsing/snake_fwd.hh (revision 1091) +++ mln/canvas/browsing/snake_fwd.hh (working copy) @@ -43,6 +43,9 @@ namespace canvas { + namespace browsing + { + /*! FIXME: Doc! * * @@ -109,6 +112,8 @@ # endif // ! MLN_INCLUDE_ONLY + } // end of namespace mln::canvas::browsing + } // end of namespace mln::canvas } // end of namespace mln Index: sandbox/nivault/median.hh --- sandbox/nivault/median.hh (revision 1091) +++ sandbox/nivault/median.hh (working copy) @@ -73,296 +73,178 @@ Image<O>& output); -# ifndef MLN_INCLUDE_ONLY + // FIXME: Doc! + template <typename I, typename O> + void median_dir(const Image<I>& input, unsigned dir, unsigned length, + Image<O>& output); + +# ifndef MLN_INCLUDE_ONLY + namespace impl { + // Directional median. + template <typename I, typename O> - struct median_dir_functor + struct median_dir_t { - // type typedef mln_point(I) point; + enum { dim = point::dim }; // i/o const I& input; + const unsigned dir; + const unsigned length; O& output; - int dir; - int dim; - const win::hline2d& win; + + // aux data + const mln_point(I) + pmin = input.domain().pmin(), + pmax = input.domain().pmax(); + const mln_coord(I) + pmin_dir = pmin[dir], + pmax_dir = pmax[dir], + pmin_dir_plus = pmin[dir] + length / 2, + pmax_dir_minus = pmax[dir] - length / 2; accu::median<mln_vset(I)> med; // ctor - median_dir_functor(const Image<I>& input_, const win::hline2d& win_, int dir_, O& output_) - : - input(exact(input_)), - output(exact(output_)), - dir(dir_), - dim(I::point::dim), - win(win_), + median_dir_t(const I& input, unsigned dir, unsigned length, O& output) + : // i/o + input(exact(input)), + dir(dir), + length(length), + output(exact(output)), + // aux data + pmin(input.domain().pmin()), + pmax(input.domain().pmax()), + pmin_dir(pmin[dir]), + pmax_dir(pmax[dir]), + pmin_dir_plus (pmin[dir] + length / 2), + pmax_dir_minus(pmax[dir] - length / 2), med(input.values()) { } - //parts void init() { } - void process(mln_point(I) p) + void process(const mln_point(I)& p_) { mln_point(I) - pmin = input.domain().pmin(), - pmax = input.domain().pmax(), + p = p_, pt = p, pu = p; - mln_coord(I)& ct = pt[dir]; - mln_coord(I)& cu = pu[dir]; + typedef mln_coord(I)& coord_ref; + coord_ref + ct = pt[dir], + cu = pu[dir], + p_dir = p[dir]; // initialization (before first point of the row) med.init(); - for (ct = pmin[dir]; ct < pmin[dir] + (win.length() / 2); ++ct) + for (ct = pmin_dir; ct < pmin_dir_plus; ++ct) + if (input.has(pt)) med.take(input(pt)); // left columns (just take new points) - for (p[dir] = pmin[dir]; p[dir] <= pmin[dir] + (win.length() / 2); ++p[dir], ++ct) + for (p_dir = pmin_dir; p_dir <= pmin_dir_plus; ++p_dir, ++ct) { + if (input.has(pt)) med.take(input(pt)); + if (output.has(p)) output(p) = med.to_value(); } // middle columns (both take and untake) cu = pmin[dir]; - for (; p[dir] <= pmax[dir] - (win.length() / 2); ++cu, ++p[dir], ++ct) + for (; p_dir <= pmax_dir_minus; ++cu, ++p_dir, ++ct) { + if (input.has(pt)) med.take(input(pt)); + if (input.has(pu)) med.untake(input(pu)); + if (output.has(p)) output(p) = med.to_value(); } // right columns (now just untake old points) - for (; p[dir] <= pmax[dir]; ++cu, ++p[dir]) + for (; p_dir <= pmax_dir; ++cu, ++p_dir) { + if (input.has(pu)) med.untake(input(pu)); + if (output.has(p)) output(p) = med.to_value(); } } }; - template <typename I, typename O> - void median_dir(const Image<I>& input_, const win::hline2d& win, unsigned dir, O& output) - { - struct median_dir_functor<I,O> func(input_, win, dir, output); - canvas::dirbrowsing(func); - } - - -// // median_dir monolythique - -// template <typename I, typename O> -// void median_dir(const Image<I>& input_, const win::hline2d& win, int dir, O& output) -// { -// const unsigned dim = I::point::dim; -// mln_precondition(dir < dim); -// const I& input = exact(input_); -// mln_point(I) -// pmin = input.domain().pmin(), -// pmax = input.domain().pmax(); - -// const unsigned half = win.length() / 2; - -// mln_point(I) p; -// mln_point(I) pt; -// mln_point(I) pu; - -// mln_coord(I)& ct = pt[dir]; -// mln_coord(I)& cu = pu[dir]; - -// accu::median<mln_vset(I)> med(input.values()); - -// p = pmin; -// do -// { -// //traitement -// pt = pu = p; - -// // initialization (before first point of the row) -// med.init(); -// for (ct = pmin[dir]; ct < pmin[dir] + half; ++ct) -// med.take(input(pt)); - -// // left columns (just take new points) -// for (p[dir] = pmin[dir]; p[dir] <= pmin[dir] + half; ++p[dir], ++ct) -// { -// med.take(input(pt)); -// output(p) = med.to_value(); -// } - -// // middle columns (both take and untake) -// cu = pmin[dir]; -// for (; p[dir] <= pmax[dir] - half; ++cu, ++p[dir], ++ct) -// { -// med.take(input(pt)); -// med.untake(input(pu)); -// output(p) = med.to_value(); -// } - -// // right columns (now just untake old points) -// for (; p[dir] <= pmax[dir]; ++cu, ++p[dir]) -// { -// med.untake(input(pu)); -// output(p) = med.to_value(); -// } - -// // next line -// for (int c = dim - 1; c >= 0; --c) -// { -// if (c = dir) -// continue; -// if (p[c] != pmax[c]) -// { -// ++p[c]; -// break; -// } -// p[c] = pmin[c]; -// } -// p[dir] = pmin[dir]; -// } while (p != pmin); -// } template <typename I, typename O> - void median(const Image<I>& input_, const win::hline2d& win, O& output) + void median_dir_(const Image<I>& input_, unsigned dir, unsigned length, O& output) { + median_dir_t<I,O> f(input_, win, dir, output); + canvas::dirbrowsing(f); + } - I& input = exact(input_); - typedef mln_coord(I) coord; - const coord - min_row = geom::min_row(input), - max_row = geom::max_row(input), - min_col = geom::min_col(input), - max_col = geom::max_col(input); - const coord half = win.length() / 2; - - point2d p; - coord& row = p.row(); - coord& col = p.col(); - - point2d pt; - coord& ct = pt.col(); - - point2d pu; - coord& cu = pu.col(); - accu::median<mln_vset(I)> med(input.values()); - for (row = min_row; row <= max_row; ++row) - { - pt.row() = pu.row() = row; + // General median. - // initialization (before first point of the row) - med.init(); - for (ct = min_col; ct < min_col + half; ++ct) - med.take(input(pt)); - - // left columns (just take new points) - for (col = min_col; col <= min_col + half; ++col, ++ct) + template <typename I, typename W, typename O> + void median_(const I& input, const Window<W>& win, O& output) { - med.take(input(pt)); - output(p) = med.to_value(); + impl::median_t<I,W,O> f(input, exact(win), output); + canvas::browsing::snake_fwd(f); } - // middle columns (both take and untake) - cu = min_col; - for (; col <= max_col - half; ++cu, ++col, ++ct) - { - med.take(input(pt)); - med.untake(input(pu)); - output(p) = med.to_value(); - } - // right columns (now just untake old points) - for (; col <= max_col; ++cu, ++col) - { - med.untake(input(pu)); - output(p) = med.to_value(); - } - } - } +# ifdef MLN_CORE_WIN_HLINE2D_HH template <typename I, typename O> - void median(const Fast_Image<I>& input_, const win::hline2d& win, O& output) - { - - I& input = exact(input_); - border::resize(input, win.delta());; - border::duplicate(input); - - typedef mln_coord(I) coord; - const coord - min_row = geom::min_row(input), - max_row = geom::max_row(input), - min_col = geom::min_col(input), - max_col = geom::max_col(input); - const coord half = win.length() / 2; - - point2d p; - coord& row = p.row(); - coord& col = p.col(); - - point2d pt; - coord& ct = pt.col(); - - point2d pu; - coord& cu = pu.col(); - - accu::median<mln_vset(I)> med(input.values()); - - for (row = min_row; row <= max_row; ++row) - { - pt.row() = pu.row() = row; - - // initialization (before first point of the row) - med.init(); - for (ct = min_col - half; ct < min_col + half; ++ct) - med.take(input(pt)); - - // middle columns (both take and untake) - cu = min_col; - for (col = min_col; col <= max_col; ++cu, ++col, ++ct) + void median_(const Image<I>& input, const win::hline2d& win, O& output) { - med.take(input(pt)); - med.untake(input(pu)); - output(p) = med.to_value(); + median_dir(input, 0, win.length(), output); } - } - } +# endif + +# ifdef MLN_CORE_WIN_VLINE2D_HH template <typename I, typename O> - void median(const I& input, - const win::vline2d& win, - O& output) - { - t_image<O> swap_output = swap_coords(output, 0, 1); - impl::median(swap_coords(input, 0, 1), - win::hline2d(win.length()), - swap_output); + void median_(const Image<I>& input, const win::vline2d& win, O& output) + { + median_dir(input, 1, win.length(), output); } +# endif } // end of namespace mln::level::impl - // facade + // Facades. template <typename I, typename W, typename O> 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)); + mln_precondition(exact(output).domain() = exact(input).domain()); + impl::median_(exact(input), exact(win), exact(output)); + } + + template <typename I, typename O> + void median_dir(const Image<I>& input, unsigned dir, unsigned length, + Image<O>& output) + { + mln_precondition(exact(output).domain() = exact(input).domain()); + typedef mln_point(I) P; + mln_precondition(dir < P::dim); + mln_precondition(length % 2 = 1); + impl::median_dir_(exact(input), exact(win), exact(output)); } # endif // ! MLN_INCLUDE_ONLY