https://svn.lrde.epita.fr/svn/oln/trunk/milena
Index: ChangeLog
from Thierry Geraud <thierry.geraud(a)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