Commit 0a4b69cd authored by Edwin Carlinet's avatar Edwin Carlinet
Browse files

Implement morphological operations with the new kernel impl.

        * mln/core/algorithm/transpose.hpp: New.
 	* mln/morpho/canvas/dilation_like.hpp,
	* mln/morpho/canvas/dilation_like.spe.hpp: New.
	* mln/morpho/dilate.hpp,
	* mln/morpho/erode.hpp,
	* mln/morpho/gradient.hpp,
	* mln/morpho/opening.hpp: Moved and modified to...
	* mln/morpho/structural/closing.hpp,
	* mln/morpho/structural/dilate.hpp,
	* mln/morpho/structural/erode.hpp,
	* mln/morpho/structural/gradient.hpp,
	* mln/morpho/structural/opening.hpp: ... these files.
	* tests/morpho/CMakeLists.txt,
	* tests/morpho/dilate.cpp,
	* tests/morpho/erode.cpp,
	* tests/morpho/gradient.cpp,
	* tests/morpho/opening.cpp,
parent 503ee852
......@@ -75,7 +75,7 @@ namespace mln
: m_inf(value_traits<T>::sup()),
m_sup(value_traits<T>::inf()),
m_count (0),
m_hist {0,}
m_hist {{0,}}
{
}
......
#ifndef MLN_CORE_ALGORITHM_TRANSPOSE_HPP
# define MLN_CORE_ALGORITHM_TRANSPOSE_HPP
# include <mln/core/image/image2d.hpp>
# include <mln/core/trace.hpp>
namespace mln
{
template <class I, class J>
void
transpose(const Image<I>& ima,
Image<J>& out);
template <class I>
image2d<mln_value(I)>
transpose(const Image<I>& ima);
/******************************************/
/**** Implementation ****/
/******************************************/
template <class I, class J>
void
transpose(const Image<I>& ima_,
Image<J>& out_)
{
mln_entering("mln::transpose");
const I& ima = exact(ima_);
J& out = exact(out_);
mln_foreach(point2d p, ima.domain())
out(point2d{p[1],p[0]}) = ima(p);
mln_exiting();
}
template <class I>
image2d<mln_value(I)>
transpose(const Image<I>& ima_)
{
const I& ima = exact(ima_);
box2d dom = ima.domain();
box2d dom2 = {{dom.pmin[1], dom.pmin[0]},
{dom.pmax[1], dom.pmax[0]}};
image2d<mln_value(I)> out(dom2);
transpose(ima, out);
return out;
}
} // end of namespace mln
#endif //!MLN_CORE_ALGORITHM_TRANSPOSE_HPP
#ifndef MLN_MORPHO_CANVAS_DILATION_LIKE_HPP
# define MLN_MORPHO_CANVAS_DILATION_LIKE_HPP
# include <mln/core/image/image.hpp>
# include <mln/morpho/se/se.hpp>
# include <mln/kernelv2/kernel.hpp>
# include <mln/core/extension/extension.hpp>
# include <mln/core/extension/fill.hpp>
namespace mln
{
namespace morpho
{
namespace canvas
{
//
// struct dilation_like_operations_traits
// {
// typedef ... support_incremental;
// typedef ... aggregate_type;
// typedef ... incremental_aggregate_type;
// ... zero() constexpr;
// };
template <class I, class SE, class Compare, class J, class OpTraits>
void
dilation_like(const Image<I>& ima,
const StructuringElement<SE>& nbh,
Compare cmp,
Image<J>& output,
OpTraits __op__);
/******************************************/
/**** Implementation ****/
/******************************************/
namespace impl
{
/// \brief Incremental implementation that enables the dilation to be in
/// a complexity that does not depend on the SE size.
/// This specialization is used when:
/// * The SE is incremental
/// * The feature has the `untake` method
template <class I, class SE, class Compare, class J, class OpTraits>
void
dilate_like_1(const I& ima, const SE& nbh, Compare cmp, J& out,
OpTraits __op__,
std::true_type __is_incremental__)
{
namespace ker = mln::kernel;
(void) __is_incremental__;
(void) __op__;
ker::Aggregate<typename OpTraits::incremental_aggregate_type> A;
ker::Point p;
ker::Neighbor n;
auto f = ker::make_image_expr<0>(ima);
auto g = ker::make_image_expr<1>(out);
auto expr = kernel::declare(g(p) = A (f(n)));
ker::execute_incremental(expr, nbh);
}
/// \brief Basic implementation
/// This specialization is used when:
/// * Either the SE is not incremental or nor the feature has the `untake` method.
template <class I, class SE, class Compare, class J, class OpTraits>
void
dilate_like_1(const I& ima, const SE& nbh, Compare cmp, J& out,
OpTraits __op__,
std::false_type __is_incremental__)
{
namespace ker = mln::kernel;
(void) __is_incremental__;
(void) __op__;
ker::Aggregate<typename OpTraits::aggregate_type> A(cmp);
ker::Point p;
ker::Neighbor n;
auto f = ker::make_image_expr<0>(ima);
auto g = ker::make_image_expr<1>(out);
auto expr = kernel::declare(g(p) = A (f(n)));
ker::execute(expr, nbh);
}
template <class I, class SE, class Compare, class J, class OpTraits>
void
dilate_like_0(const I& ima, const SE& nbh, Compare cmp, J& out,
OpTraits __op__,
std::true_type __has_extension__)
{
(void) __has_extension__;
mln_value(I) v = __op__.zero();
using is_se_incremental = typename neighborhood_traits<SE>::is_incremental;
using is_accu_incremental = typename OpTraits::support_incremental;
using is_image_incremental = typename iterator_traits<mln_pxter(I)>::has_NL;
using is_incremental = std::integral_constant<
bool, is_se_incremental::value and is_accu_incremental::value and
is_image_incremental::value>;
if (not is_se_incremental::value)
mln::trace::warn("Slow because SE is not incremental");
else if (not is_accu_incremental::value)
mln::trace::warn("Slow because the accu is not incremental with this image");
else if (not is_image_incremental::value)
mln::trace::warn("Slow because the image has no New Line Support");
if (extension::need_adjust(ima, nbh)) {
mln::trace::warn("Slow version because input image extension is not wide enough.");
dilate_like_1(extension::add_value_extension(ima, v), nbh, cmp,
out, __op__, is_incremental ());
} else {
extension::fill(ima, v);
dilate_like_1(ima, nbh, cmp, out, __op__, is_incremental ());
}
}
template <class I, class SE, class Compare, class J, class OpTraits>
void
dilate_like_0(const I& ima, const SE& nbh, Compare cmp, J& out,
OpTraits __op__,
std::false_type __has_extension__)
{
(void) __has_extension__;
mln::trace::warn("Slow version because input image has no extension.");
using is_se_incremental = typename neighborhood_traits<SE>::is_incremental;
using is_accu_incremental = typename OpTraits::support_incremental;
using is_image_incremental = typename iterator_traits<mln_pxter(I)>::has_NL;
using is_incremental = std::integral_constant<
bool, is_se_incremental::value and is_accu_incremental::value and
is_image_incremental::value>;
if (not is_se_incremental::value)
mln::trace::warn("Slow because SE is not incremental");
else if (not is_accu_incremental::value)
mln::trace::warn("Slow because the accu is not incremental with this image");
else if (not is_image_incremental::value)
mln::trace::warn("Slow because the image has no New Line Support");
mln_value(I) v = __op__.zero();
dilate_like_1(extension::add_value_extension(ima, v), nbh, cmp, out,
__op__,
is_incremental () );
}
} // end of namespace mln::morpho::canvas::impl
namespace overload
{
// Generic implementation
template <class I, class SE, class Compare, class J, class OpTraits>
void
dilation_like(const Image<I>& ima,
const StructuringElement<SE>& nbh,
Compare cmp,
Image<J>& output,
OpTraits __op__)
{
impl::dilate_like_0(exact(ima),
exact(nbh),
cmp,
exact(output),
__op__,
typename image_has_extension<I>::type ());
}
}
} // end of namespace mln::morpho::canvas
} // end of namespace mln::morpho
} // end of namespace mln
# include <mln/morpho/canvas/dilation_like.spe.hpp>
namespace mln
{
namespace morpho
{
namespace canvas
{
template <class I, class SE, class Compare, class J, class OpTraits>
void
dilation_like(const Image<I>& ima,
const StructuringElement<SE>& nbh,
Compare cmp,
Image<J>& output,
OpTraits __op__)
{
overload::dilation_like(exact(ima),
exact(nbh),
cmp,
exact(output),
__op__);
}
} // end of namespace mln::morpho::canvas
} // end of namespace mln::morpho
} // end of namespace mln
#endif //!MLN_MORPHO_CANVAS_DILATION_LIKE_HPP
#ifndef MLN_MORPHO_CANVAS_DILATION_LIKE_SPE_HPP
# define MLN_MORPHO_CANVAS_DILATION_LIKE_SPE_HPP
# include <mln/core/win2d.hpp>
# include <mln/core/algorithm/transpose.hpp>
namespace mln
{
namespace morpho
{
namespace canvas
{
namespace overload
{
// Special case when the SE is a rectangle (seperable)
// Question ? Should we transpose the image to improve
// data locality given than inplace transposition
// might be costly due to cycle detection.
template <class I, class Compare, class J, class OpTraits>
typename
std::enable_if<std::is_same<typename I::domain_type, box2d>::value>::type
dilation_like(const Image<I>& ima,
const rect2d& nbh,
Compare cmp,
Image<J>& output,
OpTraits __op__)
{
box2d r = nbh.dpoints;
if (r.shape()[0] == 1 or r.shape()[1] == 1) {
impl::dilate_like_0(exact(ima),
nbh,
cmp,
exact(output),
__op__,
typename image_has_extension<I>::type ());
} else {
rect2d h0 { box2d {{0, r.pmin[0]}, {1, r.pmax[0]}} };
rect2d h1 { box2d {{0, r.pmin[1]}, {1, r.pmax[1]}} };
image2d<mln_value(I)> f;
{
mln_concrete(I) tmp = imconcretize(exact(ima));
morpho::canvas::dilation_like(exact(ima), h1, cmp, tmp, __op__);
f = transpose(tmp);
}
{
mln_concrete(I) tmp = imconcretize(exact(f));
morpho::canvas::dilation_like(f, h0, cmp, tmp, __op__);
transpose(tmp, output);
}
}
}
} // end of namespace mln::morpho::canvas::overload
} // end of namespace mln::morpho::canvas
} // end of namespace mln::morpho
} // end of namespace mln
#endif //!MLN_MORPHO_CANVAS_DILATION_LIKE_SPE_HPP
#ifndef MLN_MORPHO_DILATE_HPP
# define MLN_MORPHO_DILATE_HPP
# include <mln/core/image/image.hpp>
# include <mln/core/extension/extension.hpp>
# include <mln/core/extension/fill.hpp>
# include <mln/core/trace.hpp>
# include <mln/morpho/se/se.hpp>
# include <mln/kernel/kernel.hpp>
# include <mln/kernel/aggregate/sup.hpp>
namespace mln
{
namespace morpho
{
template <class I, class SE, class Compare = std::less<mln_value(I)> >
mln_concrete(I)
dilate(const Image<I>& ima,
const StructuringElement<SE>& nbh,
Compare cmp = Compare ());
template <class I, class SE, class OutputImage, class Compare = std::less<mln_value(I)> >
OutputImage&
dilate(const Image<I>& ima,
const StructuringElement<SE>& nbh,
Image<OutputImage>& output,
Compare cmp = Compare ());
/******************************************/
/**** Implementation ****/
/******************************************/
namespace impl
{
template <class I, class SE, class Compare, class J>
void
dilate_1(const I& ima, const SE& nbh, Compare cmp, J& out)
{
namespace ker = mln::kernel;
using namespace mln::kernel::placeholders;
ker::aggregate::Sup_t<Compare> Sup(cmp);
auto expr = (g(p) = Sup (f(n)));
ker::execute(expr, nbh, ima, out);
}
template <class I, class SE, class Compare, class J>
void
dilate_0(const I& ima, const SE& nbh, Compare cmp, J& out, std::true_type has_extension)
{
(void) has_extension;
mln_value(I) v = value_traits<mln_value(I), Compare>::inf();
if (extension::need_adjust(ima, nbh)) {
mln::trace::warn("Slow version because input image extension is not wide enough.");
dilate_1(extension::add_value_extension(ima, v), nbh, cmp,
out);
} else {
extension::fill(ima, v);
dilate_1(ima, nbh, cmp, out);
}
}
template <class I, class SE, class Compare, class J>
void
dilate_0(const I& ima, const SE& nbh, Compare cmp, J& out, std::false_type has_extension)
{
(void) has_extension;
mln::trace::warn("Slow version because input image has no extension.");
mln_value(I) v = value_traits<mln_value(I), Compare>::inf();
dilate_1(extension::add_value_extension(ima, v), nbh, cmp, out);
}
}
template <class I, class SE, class O, class Compare>
O&
dilate(const Image<I>& ima_, const StructuringElement<SE>& nbh_,
Image<O>& output, Compare cmp)
{
mln::trace::entering("mln::morpho::dilate");
const I& ima = exact(ima_);
const SE& nbh = exact(nbh_);
O& out = exact(output);
mln::morpho::impl::dilate_0(ima, nbh, cmp, out, typename image_has_extension<I>::type ());
mln::trace::exiting();
return out;
}
template <class I, class SE, class Compare>
mln_concrete(I)
dilate(const Image<I>& ima_, const StructuringElement<SE>& nbh_, Compare cmp)
{
const I& ima = exact(ima_);
mln_concrete(I) out = imconcretize(ima);
dilate(ima, nbh_, out, cmp);
return out;
}
} // end of namespace mln::morpho
} // end of namespace mln
#endif //!MLN_MORPHO_DILATE_HPP
#ifndef MLN_MORPHO_ERODE_HPP
# define MLN_MORPHO_ERODE_HPP
# include <mln/core/image/image.hpp>
# include <mln/core/extension/extension.hpp>
# include <mln/core/extension/fill.hpp>
# include <mln/core/trace.hpp>
# include <mln/morpho/se/se.hpp>
# include <mln/kernel/kernel.hpp>
# include <mln/kernel/aggregate/inf.hpp>
namespace mln
{
namespace morpho
{
template <class I, class SE, class Compare = std::less<mln_value(I)> >
mln_concrete(I)
erode(const Image<I>& ima,
const StructuringElement<SE>& nbh,
Compare cmp = Compare ());
template <class I, class SE, class OutputImage, class Compare = std::less<mln_value(I)> >
OutputImage&
erode(const Image<I>& ima,
const StructuringElement<SE>& nbh,
Image<OutputImage>& output,
Compare cmp = Compare ());
/******************************************/
/**** Implementation ****/
/******************************************/
namespace impl
{
template <class I, class SE, class Compare, class J>
void
erode_1(const I& ima, const SE& nbh, Compare cmp, J& out)
{
namespace ker = mln::kernel;
using namespace mln::kernel::placeholders;
ker::aggregate::Inf_t<Compare> Inf(cmp);
auto expr = (g(p) = Inf (f(n)));
ker::execute(expr, nbh, ima, out);
}
template <class I, class SE, class Compare, class J>
void
erode_0(const I& ima, const SE& nbh, Compare cmp, J& out, std::true_type has_extension)
{
(void) has_extension;
mln_value(I) v = value_traits<mln_value(I), Compare>::sup();
if (extension::need_adjust(ima, nbh)) {
mln::trace::warn("Slow version because input image extension is not wide enough.");
erode_1(extension::add_value_extension(ima, v), nbh, cmp,
out);
} else {
extension::fill(ima, v);
erode_1(ima, nbh, cmp, out);
}
}
template <class I, class SE, class Compare, class J>
void
erode_0(const I& ima, const SE& nbh, Compare cmp, J& out, std::false_type has_extension)
{
(void) has_extension;
mln::trace::warn("Slow version because input image has no extension.");
mln_value(I) v = value_traits<mln_value(I), Compare>::sup();
erode_1(extension::add_value_extension(ima, v), nbh, cmp, out);
}
}
template <class I, class SE, class O, class Compare>
O&
erode(const Image<I>& ima_, const StructuringElement<SE>& nbh_,
Image<O>& output, Compare cmp)
{
mln::trace::entering("mln::morpho::erode");
const I& ima = exact(ima_);
const SE& nbh = exact(nbh_);
O& out = exact(output);
mln::morpho::impl::erode_0(ima, nbh, cmp, out, typename image_has_extension<I>::type ());
mln::trace::exiting();
return out;
}
template <class I, class SE, class Compare>
mln_concrete(I)
erode(const Image<I>& ima_, const StructuringElement<SE>& nbh_, Compare cmp)
{
const I& ima = exact(ima_);
mln_concrete(I) out = imconcretize(ima);
erode(ima, nbh_, out, cmp);
return out;
}
} // end of namespace mln::morpho
} // end of namespace mln
#endif //!MLN_MORPHO_ERODE_HPP
#ifndef MLN_MORPHO_GRADIENT_HPP
# define MLN_MORPHO_GRADIENT_HPP
# include <mln/core/image/image.hpp>
# include <mln/core/algorithm/transform.hpp>
# include <mln/core/extension/extension.hpp>
# include <mln/core/extension/mirror.hpp>