1061: Add morphological complementation.

https://svn.lrde.epita.fr/svn/oln/trunk/milena Index: ChangeLog from Thierry Geraud <thierry.geraud@lrde.epita.fr> Add morphological complementation. * tests/morpho_contrast.cc: Augment. * mln/core/concept/value.hh (cast): New. * mln/fun/v2v/saturate.hh: Update. * mln/morpho/minus.hh: Move assertions. * mln/logical/and.hh, * mln/logical/and_not.hh, * mln/logical/or.hh: Fix doc. * mln/value/int_s.hh (operator=): New. * mln/value/int_u.hh: Likewise. * mln/morpho/complementation.hh: New. * mln/morpho/includes.hh: Update. * mln/arith/revert.hh: New. * mln/logical/not.hh: New. mln/arith/revert.hh | 127 ++++++++++++++++++++++++++++++++++++++++++ mln/core/concept/value.hh | 46 +++++++++++++++ mln/fun/v2v/saturate.hh | 10 +-- mln/logical/and.hh | 2 mln/logical/and_not.hh | 2 mln/logical/not.hh | 120 +++++++++++++++++++++++++++++++++++++++ mln/logical/or.hh | 2 mln/morpho/complementation.hh | 105 ++++++++++++++++++++++++++++++++++ mln/morpho/includes.hh | 1 mln/morpho/minus.hh | 7 -- mln/value/int_s.hh | 13 ++++ mln/value/int_u.hh | 13 ++++ tests/morpho_contrast.cc | 22 ++++++- 13 files changed, 455 insertions(+), 15 deletions(-) Index: tests/morpho_contrast.cc --- tests/morpho_contrast.cc (revision 1060) +++ tests/morpho_contrast.cc (working copy) @@ -37,7 +37,11 @@ #include <mln/io/save_pgm.hh> #include <mln/value/int_u8.hh> +#include <mln/value/int_s.hh> + #include <mln/morpho/contrast.hh> + +#include <mln/level/fill.hh> #include <mln/level/saturate.hh> @@ -53,9 +57,23 @@ lena = io::load_pgm("../img/tiny.pgm"), out(lena.domain()); - image2d_b<int> tmp(lena.domain()); - morpho::contrast(lena, rect, tmp); + image2d_b< value::int_s<10> > + in(lena.domain()), + tmp(lena.domain()); + + level::fill(in, lena); + morpho::contrast(in, rect, tmp); level::saturate(tmp, out); io::save_pgm(out, "out.pgm"); + + { + // self-duality test: + morpho::complementation_inplace(in); + image2d_b< value::int_s<10> > tmp_(lena.domain()); + morpho::contrast(in, rect, tmp_); + morpho::complementation_inplace(tmp_); + mln_assertion(tmp_ = tmp); + } + } Index: mln/core/concept/value.hh --- mln/core/concept/value.hh (revision 1060) +++ mln/core/concept/value.hh (working copy) @@ -62,6 +62,18 @@ }; + + namespace value + { + + /// Cast a value \p src from type \c Src to type \c Dest. + template <typename Dest, typename Src> + Dest cast(const Src& src); + + } // end of namespace mln::value + + + # ifndef MLN_INCLUDE_ONLY template <typename E> @@ -87,6 +99,40 @@ return exact(*this); } + + namespace value + { + + namespace internal + { + + template <typename S> + const S& + cast_(const S& src, ...) + { + return src; + } + + template <typename T, typename S> + typename S::equiv + cast_(const T& dummy, const Value<S>& src) + { + return exact(src); + } + + } // end of namespace mln::value::internal + + + template <typename Dest, typename Src> + Dest cast(const Src& src) + { + return internal::cast_(src, src); + } + + + } // end of namespace mln::value + + # endif // ! MLN_INCLUDE_ONLY } // end of namespace mln Index: mln/fun/v2v/saturate.hh --- mln/fun/v2v/saturate.hh (revision 1060) +++ mln/fun/v2v/saturate.hh (working copy) @@ -57,7 +57,7 @@ typedef V result; template <typename W> - V operator()(const W& v) const; + V operator()(const W& w) const; protected: V min_, max_; @@ -84,13 +84,13 @@ template <typename V> template <typename W> V - saturate<V>::operator()(const W& v) const + saturate<V>::operator()(const W& w) const { - if (v < min_) + if (w < min_) return min_; - if (v > max_) + if (w > max_) return max_; - return v; + return mln::value::cast<V>(w); } # endif // ! MLN_INCLUDE_ONLY Index: mln/morpho/includes.hh --- mln/morpho/includes.hh (revision 1060) +++ mln/morpho/includes.hh (working copy) @@ -53,6 +53,7 @@ # include <mln/morpho/minus.hh> # include <mln/morpho/plus.hh> +# include <mln/morpho/complementation.hh> #endif // ! MLN_MORPHO_INCLUDES_HH Index: mln/morpho/minus.hh --- mln/morpho/minus.hh (revision 1060) +++ mln/morpho/minus.hh (working copy) @@ -64,7 +64,9 @@ const Image<I>& lhs, const Image<J>& rhs, Image<O>& output) { + // FIXME: mln_precondition(rhs <= lhs); return logical::and_not(lhs, rhs, output); + // FIXME: mln_postcondition(output <= lhs); } template <typename K, typename I, typename J, typename O> @@ -85,19 +87,14 @@ { mln_precondition(exact(rhs).domain() = exact(lhs).domain()); mln_precondition(exact(output).domain() = exact(lhs).domain()); - mln_precondition(rhs <= lhs); impl::minus_(mln_value_kind(I)(), exact(lhs), exact(rhs), output); - - mln_postcondition(output <= lhs); } template <typename I, typename J> void minus_inplace(Image<I>& lhs, const Image<J>& rhs) { mln_precondition(exact(rhs).domain() = exact(lhs).domain()); - mln_precondition(rhs <= lhs); - morpho::minus(lhs, rhs, lhs); // Calls the previous version. } Index: mln/morpho/complementation.hh --- mln/morpho/complementation.hh (revision 0) +++ mln/morpho/complementation.hh (revision 0) @@ -0,0 +1,105 @@ +// 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_MORPHO_COMPLEMENTATION_HH +# define MLN_MORPHO_COMPLEMENTATION_HH + +# include <mln/level/compare.hh> +# include <mln/logical/not.hh> +# include <mln/arith/revert.hh> + + +namespace mln +{ + + namespace morpho + { + + /*! Morphological complementation: either a logical "not" (if + * morpho on sets) or an arithmetical complementation (if morpho + * on functions). + */ + template <typename I, typename O> + void complementation(const Image<I>& input, Image<O>& output); + + + /*! Morphological complementation, inplace version: either a + * logical "not" (if morpho on sets) or an arithmetical + * complementation (if morpho on functions). + */ + template <typename I> + void complementation_inplace(Image<I>& input); + + +# ifndef MLN_INCLUDE_ONLY + + namespace impl + { + + template <typename I, typename O> + void complementation_(value::binary_kind, // binary => morphology on sets + const Image<I>& input, + Image<O>& output) + { + return logical::not_(input, output); + } + + template <typename K, typename I, typename O> + void complementation_(K, // otherwise => morphology on functions + const Image<I>& input, + Image<O>& output) + { + return arith::revert(input, output); + } + + } // end of namespace mln::morpho::impl + + + // Facades. + + template <typename I, typename O> + void complementation(const Image<I>& input, Image<O>& output) + { + mln_precondition(exact(output).domain() = exact(input).domain()); + impl::complementation_(mln_value_kind(I)(), exact(input), output); + } + + template <typename I> + void complementation_inplace(Image<I>& input) + { + mln_precondition(exact(input).has_data()); + morpho::complementation(input, input); // Calls the previous version. + } + +# endif // ! MLN_INCLUDE_ONLY + + } // end of namespace mln::morpho + +} // end of namespace mln + + +#endif // ! MLN_MORPHO_COMPLEMENTATION_HH Index: mln/arith/revert.hh --- mln/arith/revert.hh (revision 0) +++ mln/arith/revert.hh (revision 0) @@ -0,0 +1,127 @@ +// 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_ARITH_REVERT_HH +# define MLN_ARITH_REVERT_HH + +/*! \file mln/arith/revert.hh + * + * \brief Point-wise revert (min -> max and max -> min) of images. + * + * \todo Add static assertion and save one iterator in in-place version. + */ + +# include <mln/core/concept/image.hh> +# include <mln/value/props.hh> + +// FIXME: Rely instead on mln/fun/v2v/revert.hh. +// FIXME: Revert on int value 0 does not give 0 (since min != - max; idem for float etc.) + + + +namespace mln +{ + + namespace arith + { + + /*! Point-wise reversion of image \p input. + * + * \param[in] input the input image. + * \param[out] output The result image. + * + * \pre \p output.domain = \p input.domain + */ + template <typename I, typename O> + void revert(const Image<I>& input, Image<O>& output); + + + /*! Point-wise in-place reversion of image \p input. + * + * \param[in,out] input The target image. + * + * It performs: \n + * for all p of input.domain \n + * input(p) = min + (max - input(p)) + */ + template <typename I> + void revert_inplace(Image<I>& input); + + +# ifndef MLN_INCLUDE_ONLY + + namespace impl + { + + template <typename I, typename O> + void revert_(const Image<I>& input_, Image<O>& output_) + { + const I& input = exact(input_); + O& output = exact(output_); + typedef mln_value(I) V; + mln_piter(I) p(input.domain()); + for_all(p) + output(p) = mln_min(V) + (mln_max(V) - input(p)); + } + + template <typename I, typename O> + void revert_(const Fast_Image<I>& input, Fast_Image<O>& output) + { + typedef mln_value(I) V; + mln_pixter(const I) ip(exact(input)); + mln_pixter(O) op(exact(output)); + for_all_2(ip, op) + op.val() = mln_min(V) + (mln_max(V) - op.val()); + } + + } // end of namespace mln::arith::impl + + + // Facades. + + template <typename I, typename O> + void revert(const Image<I>& input, Image<O>& output) + { + mln_precondition(exact(output).domain() = exact(input).domain()); + impl::revert_(exact(input), exact(output)); + } + + template <typename I> + void revert_inplace(Image<I>& input) + { + mln_precondition(exact(input).has_data()); + impl::revert_(exact(input), exact(input)); + } + +# endif // ! MLN_INCLUDE_ONLY + + } // end of namespace mln::arith + +} // end of namespace mln + + +#endif // ! MLN_ARITH_REVERT_HH Index: mln/logical/and.hh --- mln/logical/and.hh (revision 1060) +++ mln/logical/and.hh (working copy) @@ -61,7 +61,7 @@ * \param[in] lhs First operand image. * \param[in,out] rhs Second operand image. * - * This addition performs: \n + * It performs: \n * for all p of rhs.domain \n * lhs(p) = lhs(p) and rhs(p) * Index: mln/logical/and_not.hh --- mln/logical/and_not.hh (revision 1060) +++ mln/logical/and_not.hh (working copy) @@ -61,7 +61,7 @@ * \param[in] lhs First operand image. * \param[in,out] rhs Second operand image. * - * This addition performs: \n + * It performs: \n * for all p of rhs.domain \n * lhs(p) = lhs(p) and not rhs(p) * Index: mln/logical/or.hh --- mln/logical/or.hh (revision 1060) +++ mln/logical/or.hh (working copy) @@ -61,7 +61,7 @@ * \param[in] lhs First operand image. * \param[in,out] rhs Second operand image. * - * This addition performs: \n + * It performs: \n * for all p of rhs.domain \n * lhs(p) = lhs(p) or rhs(p) * Index: mln/logical/not.hh --- mln/logical/not.hh (revision 0) +++ mln/logical/not.hh (revision 0) @@ -0,0 +1,120 @@ +// 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_LOGICAL_NOT_HH +# define MLN_LOGICAL_NOT_HH + +/*! \file mln/logical/not.hh + * + * \brief Point-wise "logical not" of a binary image. + * + * \todo Add static assertion and save one iterator in in-place version. + */ + +# include <mln/core/concept/image.hh> + + +namespace mln +{ + + namespace logical + { + + /*! Point-wise "logical not" of image \p input. + * + * \param[in] input the input image. + * \param[out] output The result image. + * + * \pre \p output.domain = \p input.domain + */ + template <typename I, typename O> + void not_(const Image<I>& input, Image<O>& output); + + + /*! Point-wise in-place "logical not" of image \p input. + * + * \param[in,out] input The target image. + * + * It performs: \n + * for all p of input.domain \n + * input(p) = not input(p) + */ + template <typename I> + void not_inplace(Image<I>& input); + + +# ifndef MLN_INCLUDE_ONLY + + namespace impl + { + + template <typename I, typename O> + void not__(const Image<I>& input_, Image<O>& output_) + { + const I& input = exact(input_); + O& output = exact(output_); + mln_piter(I) p(input.domain()); + for_all(p) + output(p) = ! input(p); + } + + template <typename I, typename O> + void not__(const Fast_Image<I>& input, Fast_Image<O>& output) + { + mln_pixter(const I) ip(exact(input)); + mln_pixter(O) op(exact(output)); + for_all_2(ip, op) + op.val() = ! ip.val(); + } + + } // end of namespace mln::logical::impl + + + // Facades. + + template <typename I, typename O> + void not_(const Image<I>& input, Image<O>& output) + { + mln_precondition(exact(output).domain() = exact(input).domain()); + impl::not__(exact(input), exact(output)); + } + + template <typename I> + void not_inplace(Image<I>& input) + { + mln_precondition(exact(input).has_data()); + impl::not__(exact(input), exact(input)); + } + +# endif // ! MLN_INCLUDE_ONLY + + } // end of namespace mln::logical + +} // end of namespace mln + + +#endif // ! MLN_LOGICAL_NOT_HH Index: mln/value/int_s.hh --- mln/value/int_s.hh (revision 1060) +++ mln/value/int_s.hh (working copy) @@ -71,6 +71,9 @@ /// Constructor from an integer. int_s(int i); + /// Assignment from an integer. + int_s<n>& operator=(int i); + /// Negation. int_s<n> operator-() const; @@ -135,6 +138,16 @@ } template <unsigned n> + int_s<n>& + int_s<n>::operator=(int i) + { + mln_precondition(i >= mln_min(enc)); + mln_precondition(i <= mln_max(enc)); + this->v_ = i; + return *this; + } + + template <unsigned n> int_s<n> int_s<n>::operator-() const { Index: mln/value/int_u.hh --- mln/value/int_u.hh (revision 1060) +++ mln/value/int_u.hh (working copy) @@ -71,6 +71,9 @@ /// Constructor from an integer. int_u(int i); + /// Assignment from an integer. + int_u<n>& operator=(int i); + /// Zero value. static const int_u<n> zero; @@ -132,6 +135,16 @@ template <unsigned n> int_u<n>& + int_u<n>::operator=(int i) + { + mln_precondition(i >= 0); + mln_precondition(i <= mln_max(enc)); + this->v_ = i; + return *this; + } + + template <unsigned n> + int_u<n>& int_u<n>::operator+=(int i) { mln_precondition(long(this->v_) + i >= 0);
participants (1)
-
Thierry Geraud