Commit 45f9259e authored by Thierry Geraud's avatar Thierry Geraud
Browse files

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.


git-svn-id: https://svn.lrde.epita.fr/svn/oln/trunk@1061 4aad255d-cdde-0310-9447-f3009e2ae8c0
parent 8acba43d
2007-08-29 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.
2007-08-29 Thierry Geraud <thierry.geraud@lrde.epita.fr>
Add morphology plus and minus.
......
// 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
......@@ -62,6 +62,18 @@ namespace mln
};
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 @@ namespace mln
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
......
......@@ -57,7 +57,7 @@ namespace mln
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 @@ namespace mln
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
......
......@@ -61,7 +61,7 @@ namespace mln
* \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)
*
......
......@@ -61,7 +61,7 @@ namespace mln
* \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)
*
......
// 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
......@@ -61,7 +61,7 @@ namespace mln
* \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)
*
......
// 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
......@@ -53,6 +53,7 @@
# include <mln/morpho/minus.hh>
# include <mln/morpho/plus.hh>
# include <mln/morpho/complementation.hh>
#endif // ! MLN_MORPHO_INCLUDES_HH
......@@ -64,7 +64,9 @@ namespace mln
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 @@ namespace mln
{
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.
}
......
......@@ -71,6 +71,9 @@ namespace mln
/// Constructor from an integer.
int_s(int i);
/// Assignment from an integer.
int_s<n>& operator=(int i);
/// Negation.
int_s<n> operator-() const;
......@@ -134,6 +137,16 @@ namespace mln
this->v_ = enc(i);
}
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
......
......@@ -71,6 +71,9 @@ namespace mln
/// 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;
......@@ -130,6 +133,16 @@ namespace mln
this->v_ = enc(i);
}
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)
......
......@@ -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 @@ int main()
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);
}
}