Commit dd929eb8 authored by Guillaume Lazzara's avatar Guillaume Lazzara
Browse files

Fix genericity in skeleton computation.

	* mln/morpho/skeleton_constrained.hh,
	* mln/topo/skeleton/is_simple_point.hh: Expect a double
	neighborhood.

	* mln/topo/is_simple_2d.hh: Add a fast implementation.
parent 4be527e9
2011-08-08 Guillaume Lazzara <z@lrde.epita.fr>
Fix genericity in skeleton computation.
* mln/morpho/skeleton_constrained.hh,
* mln/topo/skeleton/is_simple_point.hh: Expect a double
neighborhood.
* mln/topo/is_simple_2d.hh: Add a fast implementation.
2011-08-08 Guillaume Lazzara <z@lrde.epita.fr>
 
Small fixes.
......@@ -120,7 +120,7 @@ namespace mln
// Propagation.
{
P p;
mln_niter(N) n(nbh, p);
mln_niter(N) n(nbh.foreground(), p);
while (! q.is_empty())
{
p = q.pop_front();
......@@ -201,10 +201,7 @@ namespace mln
// Propagation.
{
mln_pixter(I) p(output);
mln_nixter(I, N) n(p, nbh);
util::array<int> dp = offsets_wrt(input, nbh);
util::array<int> dp = offsets_wrt(input, nbh.foreground());
const unsigned n_nbhs = dp.nelements();
while (! q.is_empty())
{
......
// Copyright (C) 2008, 2009 EPITA Research and Development Laboratory (LRDE)
// Copyright (C) 2008, 2009, 2011 EPITA Research and Development
// Laboratory (LRDE)
//
// This file is part of Olena.
//
......@@ -31,6 +32,11 @@
/// Define the function is_simple_2d which tests if a point is simple
/// or not (Cf bertrand.07.chap).
/// \fixme Merge with mln/topo/skeleton/is_simple_point.hh
/// \fixme The fastest version give an approximation of the result. Do
/// we want it to be exact?
#include <mln/core/concept/image.hh>
#include <mln/core/concept/neighborhood.hh>
......@@ -41,138 +47,210 @@
namespace mln
{
/// Test if a point is simple or not. A point of an object is simple
/// if in its c8 neiborhood, there is exactly one connected component of the
/// object, and only one connected component of the background
/// Examples : ( | == object, - = background)
///
/// - - |
/// | P | Here p is simple in the c4 and c8 case.
/// | | |
///
/// - | -
/// | P | Here p is never simple.
/// | | |
namespace topo
{
template<typename I, typename N>
bool
is_simple_2d(const Image<I>& ima, const Neighborhood<N>& nbh, const mln_psite(I)& p);
/// Test if a point is simple or not. A point of an object is simple
/// if in its c8 neiborhood, there is exactly one connected component of the
/// object, and only one connected component of the background
/// Examples : ( | == object, - = background)
///
/// - - |
/// | P | Here p is simple in the c4 and c8 case.
/// | | |
///
/// - | -
/// | P | Here p is never simple.
/// | | |
template <typename N>
struct is_simple_2d_t
{
is_simple_2d_t(const Neighborhood<N>& nbh);
template <typename I>
bool check(const I& ima, const mln_psite(I)& p) const;
struct is_simple_2d_t
{
template<typename I, typename N>
bool operator()(const Image<I>& ima,
const Neighborhood<N>& nbh,
const mln_psite(I)& p) const
{
return is_simple_2d(ima, nbh, p);
}
};
template <typename I>
bool check__(const I& ima, unsigned p) const;
template <typename I, typename N2>
unsigned nb_connectivity2d(const I&, const N2& nbh,
const mln_psite(I)& p, bool object) const;
template <typename I, typename N2>
unsigned nb_connectivity2d__(const I&, const N2& nbh,
unsigned p, bool object) const;
protected:
const N& nbh_;
};
# ifndef MLN_INCLUDE_ONLY
static const unsigned char connectivity_number_c8[256] =
namespace internal
{
0, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 2, 2, 1, 1,
1, 2, 1, 1, 1, 2, 1, 1, 2, 2, 1, 1, 2, 2, 1, 1,
1, 2, 2, 2, 2, 3, 2, 2, 1, 1, 1, 1, 2, 2, 1, 1,
2, 3, 2, 2, 2, 3, 2, 2, 2, 2, 1, 1, 2, 2, 1, 1,
1, 2, 2, 2, 2, 3, 2, 2, 1, 1, 1, 1, 2, 2, 1, 1,
1, 2, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 2, 2, 2, 2, 3, 2, 2, 1, 1, 1, 1, 2, 2, 1, 1,
1, 2, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 3, 3, 2, 2,
1, 2, 1, 1, 1, 2, 1, 1, 2, 2, 1, 1, 2, 2, 1, 1,
2, 3, 3, 3, 3, 4, 3, 3, 2, 2, 2, 2, 3, 3, 2, 2,
2, 3, 2, 2, 2, 3, 2, 2, 2, 2, 1, 1, 2, 2, 1, 1,
1, 2, 2, 2, 2, 3, 2, 2, 1, 1, 1, 1, 2, 2, 1, 1,
1, 2, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 2, 2, 2, 2, 3, 2, 2, 1, 1, 1, 1, 2, 2, 1, 1,
1, 2, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
};
static const unsigned char connectivity_number_c8[256] =
{
0, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 2, 2, 1, 1,
1, 2, 1, 1, 1, 2, 1, 1, 2, 2, 1, 1, 2, 2, 1, 1,
1, 2, 2, 2, 2, 3, 2, 2, 1, 1, 1, 1, 2, 2, 1, 1,
2, 3, 2, 2, 2, 3, 2, 2, 2, 2, 1, 1, 2, 2, 1, 1,
1, 2, 2, 2, 2, 3, 2, 2, 1, 1, 1, 1, 2, 2, 1, 1,
1, 2, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 2, 2, 2, 2, 3, 2, 2, 1, 1, 1, 1, 2, 2, 1, 1,
1, 2, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
static const unsigned char connectivity_number_c4[256] =
1, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 3, 3, 2, 2,
1, 2, 1, 1, 1, 2, 1, 1, 2, 2, 1, 1, 2, 2, 1, 1,
2, 3, 3, 3, 3, 4, 3, 3, 2, 2, 2, 2, 3, 3, 2, 2,
2, 3, 2, 2, 2, 3, 2, 2, 2, 2, 1, 1, 2, 2, 1, 1,
1, 2, 2, 2, 2, 3, 2, 2, 1, 1, 1, 1, 2, 2, 1, 1,
1, 2, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 2, 2, 2, 2, 3, 2, 2, 1, 1, 1, 1, 2, 2, 1, 1,
1, 2, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
};
static const unsigned char connectivity_number_c4[256] =
{
0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 2, 1, 1, 1, 2, 1,
1, 1, 2, 2, 1, 1, 1, 1, 2, 2, 3, 2, 2, 2, 2, 1,
0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 2, 1, 1, 1, 2, 1,
1, 1, 2, 2, 1, 1, 1, 1, 2, 2, 3, 2, 2, 2, 2, 1,
1, 1, 2, 2, 1, 1, 2, 2, 2, 2, 3, 2, 2, 2, 3, 2,
2, 2, 3, 3, 2, 2, 2, 2, 3, 3, 4, 3, 3, 3, 3, 2,
1, 1, 2, 2, 1, 1, 2, 2, 1, 1, 2, 1, 1, 1, 2, 1,
2, 2, 3, 3, 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 1,
0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 2, 1, 1, 1, 2, 1,
1, 1, 2, 2, 1, 1, 1, 1, 2, 2, 3, 2, 2, 2, 2, 1,
0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 2, 1, 1, 1, 2, 1,
1, 1, 2, 2, 1, 1, 1, 1, 2, 2, 3, 2, 2, 2, 2, 1,
1, 1, 2, 2, 1, 1, 2, 2, 2, 2, 3, 2, 2, 2, 3, 2,
1, 1, 2, 2, 1, 1, 1, 1, 2, 2, 3, 2, 2, 2, 2, 1,
1, 1, 2, 2, 1, 1, 2, 2, 1, 1, 2, 1, 1, 1, 2, 1,
1, 1, 2, 2, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1
};
} // end of namespace mln::topo::internal
template <typename N>
is_simple_2d_t<N>::is_simple_2d_t(const Neighborhood<N>& nbh)
: nbh_(exact(nbh))
{
0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 2, 1, 1, 1, 2, 1,
1, 1, 2, 2, 1, 1, 1, 1, 2, 2, 3, 2, 2, 2, 2, 1,
0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 2, 1, 1, 1, 2, 1,
1, 1, 2, 2, 1, 1, 1, 1, 2, 2, 3, 2, 2, 2, 2, 1,
1, 1, 2, 2, 1, 1, 2, 2, 2, 2, 3, 2, 2, 2, 3, 2,
2, 2, 3, 3, 2, 2, 2, 2, 3, 3, 4, 3, 3, 3, 3, 2,
1, 1, 2, 2, 1, 1, 2, 2, 1, 1, 2, 1, 1, 1, 2, 1,
2, 2, 3, 3, 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 1,
0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 2, 1, 1, 1, 2, 1,
1, 1, 2, 2, 1, 1, 1, 1, 2, 2, 3, 2, 2, 2, 2, 1,
0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 2, 1, 1, 1, 2, 1,
1, 1, 2, 2, 1, 1, 1, 1, 2, 2, 3, 2, 2, 2, 2, 1,
1, 1, 2, 2, 1, 1, 2, 2, 2, 2, 3, 2, 2, 2, 3, 2,
1, 1, 2, 2, 1, 1, 1, 1, 2, 2, 3, 2, 2, 2, 2, 1,
1, 1, 2, 2, 1, 1, 2, 2, 1, 1, 2, 1, 1, 1, 2, 1,
1, 1, 2, 2, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1
};
mln_precondition(nbh_.is_valid());
}
template<typename I, typename N>
inline
unsigned
connectivity_number_2d(const Image<I>& ima_, const Neighborhood<N>& nbh_,
const mln_psite(I)& p, bool b)
{
const I& ima = exact(ima_);
const N& nbh = exact(nbh_);
unsigned res = 0;
template <typename N>
template <typename I, typename N2>
unsigned
is_simple_2d_t<N>::nb_connectivity2d(const I& ima, const N2& nbh,
const mln_psite(I)& p, bool b) const
{
mln_precondition(ima.is_valid());
mln_precondition(nbh.is_valid());
unsigned res = 0;
mln_fwd_niter(neighb2d) n(c8(), p);
for_all(n)
mln_fwd_niter(N2) n(c8(), p);
for_all(n)
{
res = (res << 1);
if (ima.has(n) && ima(n) == b)
res = res | 1;
}
unsigned number;
switch (nbh.size())
{
case 4: // C4
return internal::connectivity_number_c4[res];
case 8: // C8
return internal::connectivity_number_c8[res];
default:
mln_assertion(0);
}
switch (nbh.size())
return 0;
}
template <typename N>
template <typename I, typename N2>
unsigned
is_simple_2d_t<N>::nb_connectivity2d__(const I& ima, const N2& nbh,
unsigned p, bool b) const
{
mln_precondition(ima.is_valid());
mln_precondition(nbh.is_valid());
unsigned res = 0;
static util::array<int>
noffset = mln::offsets_wrt(ima, c8());
for (unsigned i = 0; i < noffset.nelements(); ++i)
{
case 4:
number = connectivity_number_c4[res];
break;
case 8:
number = connectivity_number_c8[res];
break;
default:
mln_assertion(0);
res = (res << 1);
if (ima.element(p + noffset[i]) == b)
res = res | 1;
}
return number;
}
switch (nbh.size())
{
case 4: // C4
return internal::connectivity_number_c4[res];
case 8: // C8
return internal::connectivity_number_c8[res];
default:
mln_assertion(0);
}
return 0;
}
template <typename N>
template <typename I>
inline
bool
is_simple_2d_t<N>::check(const I& ima, const mln_psite(I)& p) const
{
mln_precondition(ima.is_valid());
return (nb_connectivity2d(ima, nbh_.foreground(), p, true) == 1) // Consider neighbor.
&& (nb_connectivity2d(ima, nbh_.background(), p, false) == 1); // Consider complement neighbor.
}
template <typename N>
template <typename I>
inline
bool
is_simple_2d_t<N>::check__(const I& ima, unsigned p) const
{
mln_precondition(ima.is_valid());
return (nb_connectivity2d__(ima, nbh_.foreground(), p, true) == 1) // Consider neighbor
&& (nb_connectivity2d__(ima, nbh_.background(), p, false) == 1); // Consider complement neighbor.
}
template<typename I, typename N>
inline
bool
is_simple_2d(const Image<I>& ima, const Neighborhood<N>& nbh_, const mln_psite(I)& p)
{
const N& nbh = exact(nbh_);
return
connectivity_number_2d(ima, nbh.foreground(), p, true ) == 1 &&
connectivity_number_2d(ima, nbh.background(), p, false) == 1;
}
# endif // MLN_INCLUDE_ONLY
} // end of namespace mln::topo
} // end of namespace mln
#endif // ! MLN_TOPO_IS_SIMPLE_2D_HH
......@@ -31,6 +31,9 @@
///
/// is_simple_point tells if a point is simple or not.
/// For more information refer to bertrand.07.chap.
///
/// \fixme The fastest version give an approximation of the result. Do
/// we want it to be exact?
# include <mln/core/concept/image.hh>
# include <mln/core/alias/point2d.hh>
......@@ -76,11 +79,11 @@ namespace mln
const N& nbh_;
bool is_c8_;
template <typename I>
unsigned nb_connexity2d(const I&, bool nbh_c8,
template <typename I, typename N2>
unsigned nb_connexity2d(const I&, const N2 nbh,
const mln_psite(I)& p, bool object) const;
template <typename I>
unsigned nb_connexity2d__(const I&, bool nbh_c8,
template <typename I, typename N2>
unsigned nb_connexity2d__(const I&, const N2 nbh,
unsigned p, bool object) const;
};
......@@ -140,18 +143,17 @@ namespace mln
template <typename N>
is_simple_point<N>::is_simple_point(const Neighborhood<N>& nbh)
: nbh_(exact(nbh)), is_c8_(exact(nbh) == c8())
: nbh_(exact(nbh))
{
mln_assertion(nbh_ == c4() || nbh_ == c8());
mln_precondition(nbh_.is_valid());
}
template <typename N>
template <typename I>
template <typename I, typename N2>
unsigned
is_simple_point<N>::nb_connexity2d(const I& ima,
bool nbh_c8,
const N2 nbh,
const mln_psite(I)& p,
bool object) const
{
......@@ -165,18 +167,24 @@ namespace mln
res = res | 1;
}
if (nbh_c8)
return internal::nb_connexity_c8[res];
else
return internal::nb_connexity_c4[res];
switch (nbh.size())
{
case 4: // C4
return internal::nb_connexity_c4[res];
case 8: // C8
return internal::nb_connexity_c8[res];
default:
mln_assertion(0);
}
}
template <typename N>
template <typename I>
template <typename I, typename N2>
unsigned
is_simple_point<N>::nb_connexity2d__(const I& ima,
bool nbh_c8,
const N2 nbh,
unsigned p,
bool object) const
{
......@@ -192,10 +200,17 @@ namespace mln
res = res | 1;
}
if (nbh_c8)
return internal::nb_connexity_c8[res];
else
return internal::nb_connexity_c4[res];
switch (nbh.size())
{
case 4: // C4
return internal::nb_connexity_c4[res];
case 8: // C8
return internal::nb_connexity_c8[res];
default:
mln_assertion(0);
}
return 0;
}
......@@ -207,8 +222,8 @@ namespace mln
const mln_psite(I)& p) const
{
mln_precondition(ima.is_valid());
return (nb_connexity2d(ima, is_c8_, p, true) == 1) // Consider neighbor.
&& (nb_connexity2d(ima, !is_c8_, p, false) == 1); // Consider complement neighbor.
return (nb_connexity2d(ima, nbh_.foreground(), p, true) == 1) // Consider neighbor.
&& (nb_connexity2d(ima, nbh_.background(), p, false) == 1); // Consider complement neighbor.
}
......@@ -222,8 +237,8 @@ namespace mln
unsigned p) const
{
mln_precondition(ima.is_valid());
return (nb_connexity2d__(ima, is_c8_, p, true) == 1) // Consider neighbor
&& (nb_connexity2d__(ima, !is_c8_, p, false) == 1); // Consider complement neighbor.
return (nb_connexity2d__(ima, nbh_.foreground(), p, true) == 1) // Consider neighbor
&& (nb_connexity2d__(ima, nbh_.background(), p, false) == 1); // Consider complement neighbor.
}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment