https://svn.lrde.epita.fr/svn/oln/branches/cleanup-2008/milena
Index: ChangeLog
from Thierry Geraud <thierry.geraud(a)lrde.epita.fr>
Revamp linear convolution.
* mln/linear/convolve.hh: Re-vamp.
* tests/linear/convolve.cc: Update.
* mln/core/routine/primary.hh: New; not completed yet.
* mln/core/routine/all.hh: Update.
* mln/core/concept/window.hh (todo): New.
* mln/morpho/erosion.hh (tests): New.
mln/core/concept/window.hh | 3
mln/core/routine/all.hh | 7 -
mln/core/routine/primary.hh | 100 ++++++++++++++++++++++
mln/linear/convolve.hh | 198 +++++++++++++++++++++++++-------------------
mln/morpho/erosion.hh | 21 ++++
tests/linear/convolve.cc | 8 -
6 files changed, 245 insertions(+), 92 deletions(-)
Index: tests/linear/convolve.cc
--- tests/linear/convolve.cc (revision 2743)
+++ tests/linear/convolve.cc (working copy)
@@ -54,7 +54,6 @@
image2d<int_u8> lena;
io::pgm::load(lena, MLN_IMG_DIR "/lena.pgm");
- image2d<int_u8> out(lena.domain());
float ws[] = { .04, .04, .04, .04, .04,
.04, .04, .04, .04, .04,
@@ -63,9 +62,10 @@
.04, .04, .04, .04, .04 };
w_window2d_float w = make::w_window2d(ws);
- image2d<float> tmp(lena.domain());
- linear::convolve(lena, w, tmp);
- level::transform(tmp, math::round<int_u8>(), out);
+// image2d<float> tmp = linear::convolve(lena, w);
+// image2d<int_u8> out = level::transform(tmp, math::round<int_u8>());
+
+ image2d<int_u8> out = linear::convolve(lena, w);
io::pgm::save(out, "out.pgm");
}
Index: mln/core/routine/primary.hh
--- mln/core/routine/primary.hh (revision 0)
+++ mln/core/routine/primary.hh (revision 0)
@@ -0,0 +1,100 @@
+// Copyright (C) 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
+// 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_ROUTINE_PRIMARY_HH
+# define MLN_CORE_ROUTINE_PRIMARY_HH
+
+/*! \file mln/core/routine/primary.hh
+ *
+ * \brief FIXME
+ *
+ * \todo We also need to get the extension image to handle border
+ * routines.
+ */
+
+# include <mln/core/concept/image.hh>
+
+
+namespace mln
+{
+
+ /// FIXME: Doc!
+ template <typename I>
+ void primary(const Image<I>& ima);
+
+
+# ifndef MLN_INCLUDE_ONLY
+
+
+ namespace internal
+ {
+
+ // Primary_type.
+
+ template <typename I> struct primary_type;
+
+ template <typename I, typename C>
+ struct primary_type_helper
+ {
+ typedef typename primary_type<mln_delegatee(I)>::ret ret;
+ };
+
+ template <typename I>
+ struct primary_type_helper< I, mln::trait::image::category::primary >
+ {
+ typedef I ret;
+ };
+
+ template <typename I>
+ struct primary_type
+ {
+ typedef mln_trait_image_category(I) Cat;
+ typedef typename primary_type_helper<I, Cat>::ret ret;
+ };
+
+
+ // Routine.
+
+ } // end of namespace mln::internal
+
+
+
+ // Facade.
+
+ template <typename I>
+ inline
+ void primary(const Image<I>&)
+ {
+ }
+
+
+# endif // ! MLN_INCLUDE_ONLY
+
+} // end of namespace mln
+
+
+#endif // ! MLN_CORE_ROUTINE_PRIMARY_HH
Index: mln/core/routine/all.hh
--- mln/core/routine/all.hh (revision 2743)
+++ mln/core/routine/all.hh (working copy)
@@ -36,10 +36,11 @@
*/
-// # include <mln/core/routine/clone.hh>
-// # include <mln/core/routine/exact.hh>
+# include <mln/core/routine/clone.hh>
+# include <mln/core/routine/exact.hh>
# include <mln/core/routine/extend.hh>
-// # include <mln/core/routine/initialize.hh>
+# include <mln/core/routine/initialize.hh>
+# include <mln/core/routine/primary.hh>
#endif // ! MLN_CORE_ROUTINE_ALL_HH
Index: mln/core/concept/window.hh
--- mln/core/concept/window.hh (revision 2743)
+++ mln/core/concept/window.hh (working copy)
@@ -34,6 +34,9 @@
* \todo Operator== should test if the cmp is possible.
*
* \todo Add an is_valid() method.
+ *
+ * \todo The is_centered() method could also exist when the window is
+ * not regular...
*/
# include <mln/core/concept/object.hh>
Index: mln/linear/convolve.hh
--- mln/linear/convolve.hh (revision 2743)
+++ mln/linear/convolve.hh (working copy)
@@ -31,6 +31,8 @@
/*! \file mln/linear/convolve.hh
*
* \brief Convolution.
+ *
+ * \todo Introduce an accumulator.
*/
# include <mln/core/concept/image.hh>
@@ -56,107 +58,90 @@
*
* \pre output.domain = input.domain
*/
- template <typename I, typename W, typename O>
- void convolve(const Image<I>& input, const Weighted_Window<W>&
w_win,
- Image<O>& output);
+ template <typename I, typename W>
+ mln_concrete(I)
+ convolve(const Image<I>& input, const Weighted_Window<W>&
w_win);
+
# ifndef MLN_INCLUDE_ONLY
- namespace impl
+ // Tests.
+
+ namespace internal
+ {
+
+ template <typename I, typename W>
+ void
+ convolve_tests(const Image<I>& input,
+ const Weighted_Window<W>& w_win)
{
- /* FIXME: We must clean up the interface of
- mln::linear::impl::convolve_:
+ mln_precondition(exact(input).has_data());
+ // mln_precondition(exact(w_win).is_valid());
+ }
- - either allow certain patterns of speed traits (e.g.,
- any/any, fastest/fastest, fastest/any, etc.). In this
- case, the generic version should abort at compile time;
+ } // end of namespace mln::linear::internal
- - or accept all combinations (which is the current case), and
- default to the slowest one (presumably any/any).
- */
- // Fwd decl.
- template <typename I, typename W, typename O>
- inline
- void convolve_(const I& input,
- const Weighted_Window<W>& w_win_,
- O& output);
-
- /// Default version, delegating to the generic version.
- template <typename Speed_I, typename I, typename W,
- typename Speed_O, typename O>
- inline
- void convolve_(Speed_I, const I& input,
- const Weighted_Window<W>& w_win_,
- Speed_O, O& output)
- {
- /* Don't delegate using such a call:
-
- \code
- impl::convolve_(trait::image::speed::any(), input,
- w_win_,
- trait::image::speed::any(), output);
- \endcode
-
- since it would end up with infinite recursion. The reason
- is that the compiler would select this function (in which
- you read this very comment), instead of the next one (with
- input and output speed traits set to `any'), to resolve the
- call. This is because C++ overloading rules favor the
- generic function over the more specialized one. And we
- cannot use explicit partial specialization, since it just
- doesn't exist for functions.
-
- Hence the chosen solution: create and call another
- overloading for mln::linear::impl::convolve_, with no
- unnatural selection behavior. */
- impl::convolve_(input, w_win_, output);
- }
-
- template <typename I, typename W, typename O>
- inline
- void convolve_(trait::image::speed::any, const I& input,
- const Weighted_Window<W>& w_win_,
- trait::image::speed::any, O& output)
- {
- // Delegate the call to the generic version.
- impl::convolve_(input, w_win_, output);
- }
-
- /// A factored implementation of the most generic version of
- /// mln::linear::impl::convolve_.
- template <typename I, typename W, typename O>
- inline
- void convolve_(const I& input,
- const Weighted_Window<W>& w_win_,
- O& output)
+ // Implementation.
+
+ namespace impl
+ {
+
+ namespace generic
{
+
+ template <typename I, typename W>
+ mln_concrete(I)
+ convolve(const Image<I>& input_,
+ const Weighted_Window<W>& w_win_)
+ {
+ trace::entering("linear::impl::generic::convolve");
+
+ const I& input = exact(input_);
const W& w_win = exact(w_win_);
+ internal::convolve_tests(input, w_win);
+
+ // extension::adjust_duplicate(input, w_win);
+
+ typedef mln_concrete(I) O;
+ O output;
+ initialize(output, input);
mln_piter(I) p(input.domain());
mln_qiter(W) q(w_win, p);
for_all(p)
{
- mln_value(O) v = 0;
+ mln_value(O) v = literal::zero;
for_all(q) if (input.has(q))
v += input(q) * q.w();
output(p) = v;
}
+
+ trace::exiting("linear::impl::generic::convolve");
+ return output;
}
- template <typename I, typename W, typename O>
- inline
- void convolve_(trait::image::speed::fastest, const I& input,
- const Weighted_Window<W>& w_win_,
- trait::image::speed::fastest, O& output)
+ } // end of namespace mln::linear::impl::generic
+
+
+ template <typename I, typename W>
+ mln_concrete(I)
+ convolve_fastest(const Image<I>& input_,
+ const Weighted_Window<W>& w_win_)
{
+ trace::entering("linear::impl::convolve_fastest");
+
+ const I& input = exact(input_);
const W& w_win = exact(w_win_);
+ internal::convolve_tests(input, w_win);
- border::resize(input, w_win.delta());
- border::duplicate(input);
+ // extension::adjust_duplicate(input, w_win);
+ typedef mln_concrete(I) O;
+ O output;
+ initialize(output, input);
mln_pixter(O) p_out(output);
mln_pixter(const I) p(input);
@@ -164,28 +149,71 @@
for_all_2(p, p_out)
{
- mln_value(O) v = 0;
+ mln_value(O) v = literal::zero;
unsigned i = 0;
for_all(q)
v += w_win.w(i++) * q.val();
p_out.val() = v;
}
+
+ trace::exiting("linear::impl::convolve_fastest");
+ return output;
}
} // end of namespace mln::linear::impl
+ // Dispatch.
+
+ namespace internal
+ {
+
+ template <typename I, typename W>
+ mln_concrete(I)
+ convolve_dispatch(trait::image::speed::any,
+ const Image<I>& input,
+ const Weighted_Window<W>& w_win)
+ {
+ return impl::generic::convolve(input, w_win);
+ }
+
+ template <typename I, typename W>
+ mln_concrete(I)
+ convolve_dispatch(trait::image::speed::fastest,
+ const Image<I>& input,
+ const Weighted_Window<W>& w_win)
+ {
+ return impl::convolve_fastest(input, w_win);
+ }
+
+ template <typename I, typename W>
+ mln_concrete(I)
+ convolve_dispatch(const Image<I>& input,
+ const Weighted_Window<W>& w_win)
+ {
+ return convolve_dispatch(mln_trait_image_speed(I)(),
+ input, w_win);
+ }
+
+ } // end of namespace mln::linear::internal
+
+
// Facade.
- template <typename I, typename W, typename O>
- inline
- void convolve(const Image<I>& input, const Weighted_Window<W>&
w_win,
- Image<O>& output)
- {
- mln_precondition(exact(output).domain() == exact(input).domain());
- impl::convolve_(mln_trait_image_speed(I)(), exact(input),
- exact(w_win),
- mln_trait_image_speed(O)(), exact(output));
+ template <typename I, typename W>
+ mln_concrete(I)
+ convolve(const Image<I>& input, const Weighted_Window<W>& w_win)
+ {
+ trace::entering("linear::convolve");
+
+ internal::convolve_tests(input, w_win);
+
+ mln_concrete(I) output;
+ output = internal::convolve_dispatch(mln_trait_image_speed(I)(),
+ input, w_win);
+
+ trace::exiting("linear::convolve");
+ return output;
}
# endif // ! MLN_INCLUDE_ONLY
Index: mln/morpho/erosion.hh
--- mln/morpho/erosion.hh (revision 2743)
+++ mln/morpho/erosion.hh (working copy)
@@ -52,6 +52,25 @@
# ifndef MLN_INCLUDE_ONLY
+
+ namespace internal
+ {
+
+ template <typename I, typename W>
+ inline
+ void
+ erosion_tests(const Image<I>& input_, const Window<W>& win_)
+ {
+ const I& input = exact(input_);
+ const W& win = exact(win_);
+
+ mln_precondition(exact(input).has_data());
+ mln_precondition(! exact(win).is_empty());
+ }
+
+ } // end of mln::morpho::internal
+
+
namespace impl
{
@@ -69,6 +88,7 @@
const I& input = exact(input_);
const W& win = exact(win_);
+ internal::erosion_tests(input, win);
extension::adjust_fill(input, win, mln_max(mln_value(I)));
@@ -139,6 +159,7 @@
mln_precondition(exact(input).has_data());
mln_precondition(! exact(win).is_empty());
+ internal::erosion_tests(input, win);
mln_concrete(I) output = internal::erosion_dispatch(input, win);
if (exact(win).is_centered())