
* mln/accu/rank_bool.hh: Add untake() and remove unnecessary attributes. * mln/morpho/rank_filter.hh: Add rank_filter_directional. It is used with win::line. * mln/morpho/rank_filter.hh: Add rank_filter_directional. It is used with win::line. * mln/accu/rank.hh: update constructor and add untake(accu::rank). * tests/accu/rank.cc, * tests/morpho/rank_filter.cc: fix tests. * tests/morpho/Makefile.am: add rank_filter test. --- milena/ChangeLog | 17 +++++ milena/mln/accu/rank.hh | 60 ++++++++++++------- milena/mln/accu/rank_bool.hh | 43 ++++++++++---- milena/mln/morpho/rank_filter.hh | 115 ++++++++++++++++++++++++++++-------- milena/tests/accu/rank.cc | 22 ++++---- milena/tests/morpho/Makefile.am | 3 + milena/tests/morpho/rank_filter.cc | 19 ++---- 7 files changed, 197 insertions(+), 82 deletions(-) diff --git a/milena/ChangeLog b/milena/ChangeLog index 2170ada..d149788 100644 --- a/milena/ChangeLog +++ b/milena/ChangeLog @@ -1,3 +1,20 @@ +2008-11-24 Guillaume Lazzara <z@lrde.epita.fr> + + Update rank_filter. + + * mln/accu/rank_bool.hh: Add untake() and remove unnecessary + attributes. + + * mln/morpho/rank_filter.hh: Add rank_filter_directional. It is used + with win::line. + + * mln/accu/rank.hh: update constructor and add untake(accu::rank). + + * tests/accu/rank.cc, + * tests/morpho/rank_filter.cc: fix tests. + + * tests/morpho/Makefile.am: add rank_filter test. + 2008-11-21 Guillaume Lazzara <z@lrde.epita.fr> Add reference files for example outputs used in the tutorial. diff --git a/milena/mln/accu/rank.hh b/milena/mln/accu/rank.hh index bdd4df0..bd1999d 100644 --- a/milena/mln/accu/rank.hh +++ b/milena/mln/accu/rank.hh @@ -51,16 +51,16 @@ namespace mln /// Generic rank accumulator class. - /*! - * The parameter \c T is the type of values. - */ + /// + /// The parameter \c T is the type of values. template <typename T> struct rank : public mln::accu::internal::base< const T&, rank<T> > { typedef T argument; typedef mln::value::set<T> S; - rank(unsigned k, unsigned n); + rank(); + explicit rank(unsigned k); /// Manipulators. /// \{ @@ -68,6 +68,7 @@ namespace mln void take(const argument& t); void take(const rank<T>& other); void untake(const argument& t); + void untake(const rank<T>& other); /// \} unsigned card() const { return h_.sum(); } @@ -82,13 +83,9 @@ namespace mln /// Give the rank. unsigned k() const; - /// Give the total number of elements. - unsigned n() const; - protected: unsigned k_; // 0 <= k_ < n - unsigned n_; mutable accu::histo<T> h_; const S& s_; // derived from h_ @@ -97,7 +94,7 @@ namespace mln mutable bool valid_; mutable unsigned i_; // the median index - mutable argument t_; // the median value + mutable argument t_; // the median value // Auxiliary methods void update_() const; @@ -116,7 +113,7 @@ namespace mln struct rank : public Meta_Accumulator< rank > { - rank(unsigned k_, unsigned n_) : k(k_), n(n_) {} + rank(unsigned k_) : k(k_) {} template <typename T> struct with @@ -125,7 +122,6 @@ namespace mln }; unsigned k; - unsigned n; }; } // end of namespace mln::accu::meta @@ -134,7 +130,7 @@ namespace mln template <typename T> rank<T> unmeta(const meta::rank& m, T) { - rank<T> a(m.k, m.n); + rank<T> a(m.k); return a; } @@ -143,32 +139,32 @@ namespace mln # ifndef MLN_INCLUDE_ONLY + template <typename T> inline - rank<T>::rank(unsigned k, unsigned n) - : k_(k), - n_(n), - h_(), + rank<T>::rank() + : h_(), s_(h_.vset()) { - mln_assertion(k_ < n_); init(); } template <typename T> inline - unsigned - rank<T>::k() const + rank<T>::rank(unsigned k) + : k_(k), + h_(), + s_(h_.vset()) { - return k_; + init(); } template <typename T> inline unsigned - rank<T>::n() const + rank<T>::k() const { - return n_; + return k_; } template <typename T> @@ -227,6 +223,26 @@ namespace mln template <typename T> inline void + rank<T>::untake(const rank<T>& other) + { + // h_ + h_.untake(other.h_); + + // sum_minus_ + for (unsigned i = 0; i < i_; ++i) + sum_minus_ -= other.h_[i]; + + // sum_plus_ + for (unsigned i = i_ + 1; i < h_.nvalues(); ++i) + sum_plus_ -= other.h_[i]; + + if (valid_) + valid_ = false; + } + + template <typename T> + inline + void rank<T>::update_() const { valid_ = true; diff --git a/milena/mln/accu/rank_bool.hh b/milena/mln/accu/rank_bool.hh index f5e9b07..597e078 100644 --- a/milena/mln/accu/rank_bool.hh +++ b/milena/mln/accu/rank_bool.hh @@ -56,7 +56,8 @@ namespace mln { typedef bool argument; - rank(unsigned k, unsigned n); + rank(); + rank(unsigned k); /// Manipulators. /// \{ @@ -64,6 +65,8 @@ namespace mln void take_as_init(const argument& t); void take(const argument& t); void take(const rank<bool>& other); + void untake(const argument& t); + void untake(const rank<bool>& other); /// \} /// Get the value of the accumulator. @@ -75,22 +78,24 @@ namespace mln protected: unsigned nfalse_; - unsigned k_; // 0 <= k_ < n - unsigned n_; + unsigned k_; // 0 <= k_ }; # ifndef MLN_INCLUDE_ONLY inline - rank<bool>::rank(unsigned k, unsigned n) - : k_(k), - n_(n) + rank<bool>::rank() { - mln_assertion(k_ < n_); init(); } + inline + rank<bool>::rank(unsigned k) + : k_(k) + { + init(); + } inline void @@ -99,20 +104,28 @@ namespace mln nfalse_ = 0; } - inline void rank<bool>::take_as_init(const argument& t) { nfalse_ = t ? 0 : 1; } - inline void rank<bool>::take(const argument& t) { - nfalse_ += !t; + if (t == false) + ++nfalse_; } + inline + void rank<bool>::untake(const argument& t) + { + if (t == false) + { + mln_assertion(nfalse_ > 0); + --nfalse_; + } + } inline void @@ -121,12 +134,18 @@ namespace mln nfalse_ += other.nfalse_; } + inline + void + rank<bool>::untake(const rank<bool>& other) + { + mln_precondition(other.nfalse_ <= nfalse_); + nfalse_ -= other.nfalse_; + } inline bool rank<bool>::to_result() const { - mln_assertion(nfalse_ <= n_); return k_ >= nfalse_; } @@ -134,7 +153,7 @@ namespace mln bool rank<bool>::is_valid() const { - return nfalse_ <= n_; + return true; } # endif // ! MLN_INCLUDE_ONLY diff --git a/milena/mln/morpho/rank_filter.hh b/milena/mln/morpho/rank_filter.hh index 94a0a27..eb24567 100644 --- a/milena/mln/morpho/rank_filter.hh +++ b/milena/mln/morpho/rank_filter.hh @@ -1,4 +1,4 @@ -// Copyright (C) 2007, 2008 EPITA Research and Development Laboratory +// Copyright (C) 2007, 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 @@ -28,10 +28,9 @@ #ifndef MLN_MORPHO_RANK_FILTER_HH # define MLN_MORPHO_RANK_FILTER_HH -/*! \file mln/morpho/rank_filter.hh - * - * \brief Morphological rank_filter. - */ +/// \file mln/morpho/rank_filter.hh +/// +/// Morphological rank_filter. # include <mln/morpho/includes.hh> # include <mln/convert/to_p_array.hh> @@ -42,8 +41,7 @@ namespace mln namespace morpho { - /*! Morphological rank_filter. - */ + /// Morphological rank_filter. template <typename I, typename W> mln_concrete(I) rank_filter(const Image<I>& input, const Window<W>& win); @@ -51,47 +49,116 @@ namespace mln # ifndef MLN_INCLUDE_ONLY + + + namespace internal + { + + template <typename I, typename W> + inline + void + rank_filter_tests(const Image<I>& input_, const Window<W>& win_, unsigned k) + { + const I& input = exact(input_); + const W& win = exact(win_); + + mln_precondition(input.has_data()); + mln_precondition(! win.is_empty()); + (void) input; + (void) win; + (void) k; + } + + } // end of namespace mln::morpho::internal + + namespace impl { namespace generic { - // On function. - template <typename I, typename W> inline mln_concrete(I) - rank_filter_(const I& input, const W& win, unsigned k) + rank_filter(const Image<I>& input_, const Window<W>& win_, unsigned k) { - trace::entering("morpho::impl::generic::rank_filter_"); + trace::entering("morpho::impl::generic::rank_filter"); + + internal::rank_filter_tests(input_, win_, k); + + const I& input = exact(input_); + const W& win = exact(win_); mln_concrete(I) output; initialize(output, input); - accu::rank<mln_value(I)> accu(k, convert::to_p_array(win, mln_psite(I)()).nsites()); + accu::rank<mln_value(I)> accu(k); + extension::adjust_fill(input, geom::delta(win) + 1, accu); mln_piter(I) p(input.domain()); mln_qiter(W) q(win, p); for_all(p) - { - accu.init(); - for_all(q) - if (input.has(q)) - accu.take(input(q)); -// else -// accu.take(mln_value(I)(literal::zero)); - output(p) = accu; - } - - trace::exiting("morpho::impl::generic::rank_filter_"); + { + accu.init(); + for_all(q) + if (input.has(q)) + accu.take(input(q)); + //else + // accu.take(mln_value(I)(literal::zero)); + output(p) = accu; + } + + trace::exiting("morpho::impl::generic::rank_filter"); return output; } } // end of namespace mln::morpho::impl::generic + + template <typename I, typename W> + inline + mln_concrete(I) + rank_filter_directional(const Image<I>& input, const Window<W>& win, unsigned k, unsigned dir) + { + trace::entering("morpho::impl::generic::rank_filter_directional"); + + internal::rank_filter_tests(input, win, k); + + accu::rank<mln_value(I)> accu(k); + extension::adjust_fill(input, geom::delta(win) + 1, accu); + mln_concrete(I) output = accu::transform_directional(accu, input, win, dir); + + trace::exiting("morpho::impl::generic::rank_filter_directional"); + return output; + } + } // end of namespace mln::morpho::impl + namespace internal + { + + template <typename I, typename M, unsigned i, typename C> + inline + mln_concrete(I) + rank_filter_dispatch(const Image<I>& input, const win::line<M, i, C> & win, unsigned k) + { + return impl::rank_filter_directional(input, win, k, i); + } + + + + template <typename I, typename W> + inline + mln_concrete(I) + rank_filter_dispatch(const Image<I>& input, const Window<W>& win, unsigned k) + { + return impl::generic::rank_filter(input, win, k); + } + + } // end of namespace mln::morpho::internal + + // Facades. @@ -104,7 +171,7 @@ namespace mln mln_precondition(exact(input).has_data()); mln_precondition(! exact(win).is_empty()); - mln_concrete(I) output = impl::generic::rank_filter_(exact(input), exact(win), k); + mln_concrete(I) output = internal::rank_filter_dispatch(exact(input), exact(win), k); trace::exiting("morpho::rank_filter"); return output; diff --git a/milena/tests/accu/rank.cc b/milena/tests/accu/rank.cc index 9c334a9..0e9b6c8 100644 --- a/milena/tests/accu/rank.cc +++ b/milena/tests/accu/rank.cc @@ -55,55 +55,55 @@ int main() using value::int_u8; { - accu::meta::rank r(4, 9); + accu::meta::rank r(4); accu::rank<int_u8> a = accu::unmeta(r, int_u8()); - mln_assertion(a.k() == 4 && a.n() == 9); + mln_assertion(a.k() == 4); // Meta_Accumulator<accu::meta::rank>& R = r; // accu::unmeta(R, int_u8()); } { - accu::rank<int_u8> accu(0, 8); + accu::rank<int_u8> accu(0); fill(accu); mln_assertion(accu.to_result() == 1u); } { - accu::rank<int_u8> accu(1, 8); + accu::rank<int_u8> accu(1); fill(accu); mln_assertion(accu.to_result() == 2u); } { - accu::rank<int_u8> accu(2, 8); + accu::rank<int_u8> accu(2); fill(accu); mln_assertion(accu.to_result() == 2u); } { - accu::rank<int_u8> accu(3, 8); + accu::rank<int_u8> accu(3); fill(accu); mln_assertion(accu.to_result() == 3u); } { - accu::rank<int_u8> accu(4, 8); + accu::rank<int_u8> accu(4); fill(accu); mln_assertion(accu.to_result() == 4u); } { - accu::rank<int_u8> accu(5, 8); + accu::rank<int_u8> accu(5); fill(accu); mln_assertion(accu.to_result() == 5u); } { - accu::rank<int_u8> accu(6, 8); + accu::rank<int_u8> accu(6); fill(accu); mln_assertion(accu.to_result() == 5u); } { - accu::rank<int_u8> accu(7, 8); + accu::rank<int_u8> accu(7); fill(accu); mln_assertion(accu.to_result() == 5u); } { - accu::rank<bool> accu_bool(1, 5); + accu::rank<bool> accu_bool(1); accu_bool.take(true); accu_bool.take(true); accu_bool.take(true); diff --git a/milena/tests/morpho/Makefile.am b/milena/tests/morpho/Makefile.am index 734aef5..fd5cc00 100644 --- a/milena/tests/morpho/Makefile.am +++ b/milena/tests/morpho/Makefile.am @@ -33,6 +33,7 @@ check_PROGRAMS = \ opening_area \ opening_height \ opening_volume \ + rank_filter \ skeleton_constrained \ thinning @@ -70,6 +71,8 @@ complex_image_wst_SOURCES = complex_image_wst.cc meyer_wst_SOURCES = meyer_wst.cc +rank_filter_SOURCES = rank_filter.cc + skeleton_constrained_SOURCES = skeleton_constrained.cc combined_SOURCES = combined.cc diff --git a/milena/tests/morpho/rank_filter.cc b/milena/tests/morpho/rank_filter.cc index 597dccd..9550876 100644 --- a/milena/tests/morpho/rank_filter.cc +++ b/milena/tests/morpho/rank_filter.cc @@ -25,16 +25,12 @@ // reasons why the executable file might be covered by the GNU General // Public License. -/*! \file tests/morpho/rank_filter.cc - * - * \brief Test on mln::morpho::rank_filter. - */ +/// \file tests/morpho/rank_filter.cc +/// +/// Test on mln::morpho::rank_filter. #include <mln/core/image/image2d.hh> #include <mln/win/rectangle2d.hh> -#include <mln/win/octagon2d.hh> -#include <mln/win/diag2d.hh> -#include <mln/win/backdiag2d.hh> #include <mln/core/alias/window2d.hh> #include <mln/io/pgm/load.hh> @@ -52,9 +48,6 @@ #include <mln/pw/cst.hh> #include <mln/fun/ops.hh> -#include <mln/convert/to_p_array.hh> -#include <mln/convert/to_window.hh> - #include "tests/data.hh" @@ -70,23 +63,23 @@ int main() io::pgm::load(lena, MLN_IMG_DIR "/small.pgm"); { - win::octagon2d oct(31); image2d<int_u8> out; out = morpho::rank_filter(lena, rec, 0); image2d<int_u8> ref(lena.domain()); ref = morpho::erosion(lena, rec); + mln_assertion(ref == out); } { - win::octagon2d oct(31); image2d<int_u8> out; - out = morpho::rank_filter(lena, rec, 21 * 21 - 1); + out = morpho::rank_filter(lena, rec, 21 * 21); image2d<int_u8> ref(lena.domain()); ref = morpho::dilation(lena, rec); + mln_assertion(ref == out); } -- 1.5.6.5