* mln/topo/skeleton/priority_driven_thinning.hh
(mln::topo::skeleton::priority_driven_thinning): Catch up
with mln::topo::skeleton::breadth_first_thinning.
* mln/topo/detach_point.hh: Turn into a functor to match the new
interface of thinning algorithms.
* tests/topo/skeleton/breadth_first_thinning.cc
* tests/topo/skeleton/breadth_first_thinning_constrained.cc
* tests/topo/skeleton/priority_driven_thinning.cc
* tests/topo/skeleton/priority_driven_thinning_constrained.cc:
Adjust.
---
milena/ChangeLog | 15 +++++
milena/mln/topo/detach_point.hh | 66 +++++++++++++++++---
.../mln/topo/skeleton/priority_driven_thinning.hh | 23 +++++--
.../tests/topo/skeleton/breadth_first_thinning.cc | 6 +-
.../skeleton/breadth_first_thinning_constrained.cc | 6 +-
.../topo/skeleton/priority_driven_thinning.cc | 6 +-
.../priority_driven_thinning_constrained.cc | 6 +-
7 files changed, 104 insertions(+), 24 deletions(-)
diff --git a/milena/ChangeLog b/milena/ChangeLog
index d4d9a23..a4a1345 100644
--- a/milena/ChangeLog
+++ b/milena/ChangeLog
@@ -1,5 +1,20 @@
2011-02-24 Roland Levillain <roland(a)lrde.epita.fr>
+ Make the interface of thinning algorithms uniform w.r.t. functors.
+
+ * mln/topo/skeleton/priority_driven_thinning.hh
+ (mln::topo::skeleton::priority_driven_thinning): Catch up
+ with mln::topo::skeleton::breadth_first_thinning.
+ * mln/topo/detach_point.hh: Turn into a functor to match the new
+ interface of thinning algorithms.
+ * tests/topo/skeleton/breadth_first_thinning.cc
+ * tests/topo/skeleton/breadth_first_thinning_constrained.cc
+ * tests/topo/skeleton/priority_driven_thinning.cc
+ * tests/topo/skeleton/priority_driven_thinning_constrained.cc:
+ Adjust.
+
+2011-02-24 Roland Levillain <roland(a)lrde.epita.fr>
+
State a cell is not simple if it does not correspond to a facet.
* mln/topo/is_simple_cell.hh
diff --git a/milena/mln/topo/detach_point.hh b/milena/mln/topo/detach_point.hh
index 818f7cd..6e4d22d 100644
--- a/milena/mln/topo/detach_point.hh
+++ b/milena/mln/topo/detach_point.hh
@@ -1,4 +1,4 @@
-// Copyright (C) 2010 EPITA Research and Development Laboratory (LRDE)
+// Copyright (C) 2010, 2011 EPITA Research and Development Laboratory (LRDE)
//
// This file is part of Olena.
//
@@ -29,8 +29,7 @@
/// \file
/// \brief Detaching a point from a binary image.
-// FIXME: Not generic. Swap arguments and use Image<I> and
-// mln_psite(I) as types.
+# include <mln/metal/equal.hh>
# include <mln/core/image/image2d.hh>
# include <mln/core/alias/point2d.hh>
@@ -41,19 +40,68 @@ namespace mln
namespace topo
{
- /// \brief Detach a point from a binary image.
- inline
- void
- detach_point(const mln::point2d& p, mln::image2d<bool>& ima);
+ /// \brief Functor detaching a point from a binary image.
+ template <typename I>
+ class detach_point
+ {
+ public:
+ /// Build a functor.
+ detach_point();
+
+ /// Build a functor, and assign an image to it.
+ ///
+ /// \param ima The image.
+ detach_point(Image<I>& ima);
+
+ /// Set the underlying image.
+ void set_image(Image<I>& ima);
+
+ /// \brief Detach point \a p from the image.
+ void operator()(const mln_psite(I)& p) const;
+
+ private:
+ /// The image.
+ I* ima_;
+ };
+
# ifndef MLN_INCLUDE_ONLY
+ template <typename I>
+ inline
+ detach_point<I>::detach_point()
+ : ima_(0)
+ {
+ // Ensure I is a binary image type.
+ /* FIXME: Not compatible with proxy/morphers on values. */
+ mlc_equal(mln_value(I), bool)::check();
+ }
+
+ template <typename I>
+ inline
+ detach_point<I>::detach_point(Image<I>& ima)
+ : ima_(exact(&ima))
+ {
+ // Ensure I is a binary image type.
+ /* FIXME: Not compatible with proxy/morphers on values. */
+ mlc_equal(mln_value(I), bool)::check();
+ }
+
+ template <typename I>
+ inline
+ void
+ detach_point<I>::set_image(Image<I>& ima)
+ {
+ ima_ = exact(&ima);
+ }
+
+ template <typename I>
inline
void
- detach_point(const mln::point2d& p, mln::image2d<bool>& ima)
+ detach_point<I>::operator()(const mln_psite(I)& p) const
{
- ima(p) = false;
+ (*ima_)(p) = false;
}
# endif // MLN_INCLUDE_ONLY
diff --git a/milena/mln/topo/skeleton/priority_driven_thinning.hh b/milena/mln/topo/skeleton/priority_driven_thinning.hh
index e29062f..ad8e63d 100644
--- a/milena/mln/topo/skeleton/priority_driven_thinning.hh
+++ b/milena/mln/topo/skeleton/priority_driven_thinning.hh
@@ -1,4 +1,5 @@
-// Copyright (C) 2009, 2010 EPITA Research and Development Laboratory (LRDE)
+// Copyright (C) 2009, 2010, 2011 EPITA Research and Development
+// Laboratory (LRDE)
//
// This file is part of Olena.
//
@@ -62,10 +63,14 @@ namespace mln
(sites). This functor must provide a method
<tt>void set_image(const Image<I>&)</tt>.
\param detach A function used to detach a cell from \a input.
+ This functor must provide a method
+ <tt>void set_image(const Image<I>&)</tt>.
\param priority A priority function expressed as an image.
\param constraint A constraint on point (site); if it
returns \c false for a point, this point
- will not be removed. */
+ will not be removed.
+
+ Keywords: skeletons, simple points. */
template <typename I, typename N, typename F, typename G, typename J,
typename H>
mln_concrete(I)
@@ -87,9 +92,12 @@ namespace mln
\param is_simple The predicate on the simplicity of points
(sites). This functor must provide a method
<tt>void set_image(const Image<I>&)</tt>.
- \param detach A function used to detach a cell from
- \a input.
- \param priority A priority function expressed as an image. */
+ \param detach A function used to detach a cell from \a input.
+ This functor must provide a method
+ <tt>void set_image(const Image<I>&)</tt>.
+ \param priority A priority function expressed as an image.
+
+ Keywords: skeletons, simple points. */
template <typename I, typename N, typename F, typename G, typename J>
mln_concrete(I)
priority_driven_thinning(const Image<I>& input,
@@ -121,8 +129,9 @@ namespace mln
const H& constraint = exact(constraint_);
mln_concrete(I) output = duplicate(input);
- // Attach the work image to IS_SIMPLE.
+ // Attach the work image to IS_SIMPLE and DETACH.
is_simple.set_image(output);
+ detach.set_image(output);
typedef mln_psite(I) psite;
typedef p_queue_fast<psite> queue_t;
@@ -141,7 +150,7 @@ namespace mln
psite p = queue.pop_front();
if (output(p) && constraint(p) && is_simple(p))
{
- detach(p, output);
+ detach(p);
mln_niter(N) n(nbh, p);
for_all(n)
{
diff --git a/milena/tests/topo/skeleton/breadth_first_thinning.cc b/milena/tests/topo/skeleton/breadth_first_thinning.cc
index e77421a..1ed7260 100644
--- a/milena/tests/topo/skeleton/breadth_first_thinning.cc
+++ b/milena/tests/topo/skeleton/breadth_first_thinning.cc
@@ -1,4 +1,4 @@
-// Copyright (C) 2010 EPITA Research and Development Laboratory (LRDE)
+// Copyright (C) 2010, 2011 EPITA Research and Development Laboratory (LRDE)
//
// This file is part of Olena.
//
@@ -64,9 +64,11 @@ int main()
// Simplicity criterion functor.
topo::is_simple_point2d<I, N> is_simple(nbh_fg, nbh_bg);
+ // Simple point detach procedure.
+ topo::detach_point<I> detach;
I output = topo::skeleton::breadth_first_thinning(input, nbh_fg,
is_simple,
- topo::detach_point);
+ detach);
io::pbm::save(output, "breadth_first_thinning-small.pbm");
}
diff --git a/milena/tests/topo/skeleton/breadth_first_thinning_constrained.cc b/milena/tests/topo/skeleton/breadth_first_thinning_constrained.cc
index 8ec213a..c8fbe52 100644
--- a/milena/tests/topo/skeleton/breadth_first_thinning_constrained.cc
+++ b/milena/tests/topo/skeleton/breadth_first_thinning_constrained.cc
@@ -1,4 +1,4 @@
-// Copyright (C) 2010 EPITA Research and Development Laboratory (LRDE)
+// Copyright (C) 2010, 2011 EPITA Research and Development Laboratory (LRDE)
//
// This file is part of Olena.
//
@@ -65,12 +65,14 @@ int main()
// Simplicity criterion functor.
topo::is_simple_point2d<I, N> is_simple(nbh_fg, nbh_bg);
+ // Simple point detach procedure.
+ topo::detach_point<I> detach;
// Constraint: do not collapse end points.
topo::is_not_end_point<I, N> constraint(nbh_fg, input);
I output = topo::skeleton::breadth_first_thinning(input, nbh_fg,
is_simple,
- topo::detach_point,
+ detach,
constraint);
io::pbm::save(output, "breadth_first_thinning_constrained-small.pbm");
}
diff --git a/milena/tests/topo/skeleton/priority_driven_thinning.cc b/milena/tests/topo/skeleton/priority_driven_thinning.cc
index 36470d1..6cfacae 100644
--- a/milena/tests/topo/skeleton/priority_driven_thinning.cc
+++ b/milena/tests/topo/skeleton/priority_driven_thinning.cc
@@ -1,4 +1,4 @@
-// Copyright (C) 2010 EPITA Research and Development Laboratory (LRDE)
+// Copyright (C) 2010, 2011 EPITA Research and Development Laboratory (LRDE)
//
// This file is part of Olena.
//
@@ -68,6 +68,8 @@ int main()
// Simplicity criterion functor.
topo::is_simple_point2d<I, N> is_simple(nbh_fg, nbh_bg);
+ // Simple point detach procedure.
+ topo::detach_point<I> detach;
// Distance type.
typedef value::int_u8 D;
@@ -84,7 +86,7 @@ int main()
I output = topo::skeleton::priority_driven_thinning(input, nbh_fg,
is_simple,
- topo::detach_point,
+ detach,
priority);
io::pbm::save(output, "priority_driven_thinning-small.pbm");
}
diff --git a/milena/tests/topo/skeleton/priority_driven_thinning_constrained.cc b/milena/tests/topo/skeleton/priority_driven_thinning_constrained.cc
index 822d5cd..32e17a1 100644
--- a/milena/tests/topo/skeleton/priority_driven_thinning_constrained.cc
+++ b/milena/tests/topo/skeleton/priority_driven_thinning_constrained.cc
@@ -1,4 +1,4 @@
-// Copyright (C) 2010 EPITA Research and Development Laboratory (LRDE)
+// Copyright (C) 2010, 2011 EPITA Research and Development Laboratory (LRDE)
//
// This file is part of Olena.
//
@@ -69,6 +69,8 @@ int main()
// Simplicity criterion functor.
topo::is_simple_point2d<I, N> is_simple(nbh_fg, nbh_bg);
+ // Simple point detach procedure.
+ topo::detach_point<I> detach;
// Constraint: do not collapse end points.
topo::is_not_end_point<I, N> constraint(nbh_fg, input);
@@ -87,7 +89,7 @@ int main()
I output = topo::skeleton::priority_driven_thinning(input, nbh_fg,
is_simple,
- topo::detach_point,
+ detach,
priority,
constraint);
io::pbm::save(output, "priority_driven_thinning_constrained-small.pbm");
--
1.5.6.5
* mln/topo/is_simple_cell.hh
(mln::topo::is_simple_cell<I, N, NL, NH>::operator()): Here.
---
milena/ChangeLog | 7 +++++++
milena/mln/make/attachment.hh | 2 ++
milena/mln/make/detachment.hh | 2 ++
milena/mln/topo/detach_cell.hh | 2 ++
milena/mln/topo/is_facet.hh | 2 ++
milena/mln/topo/is_simple_cell.hh | 26 +++++++++++++++++++++++++-
6 files changed, 40 insertions(+), 1 deletions(-)
diff --git a/milena/ChangeLog b/milena/ChangeLog
index 279f0a6..d4d9a23 100644
--- a/milena/ChangeLog
+++ b/milena/ChangeLog
@@ -1,3 +1,10 @@
+2011-02-24 Roland Levillain <roland(a)lrde.epita.fr>
+
+ State a cell is not simple if it does not correspond to a facet.
+
+ * mln/topo/is_simple_cell.hh
+ (mln::topo::is_simple_cell<I, N, NL, NH>::operator()): Here.
+
2010-09-09 Roland Levillain <roland(a)lrde.epita.fr>
Use mln::data::paste to simplify mesh skeleton applications.
diff --git a/milena/mln/make/attachment.hh b/milena/mln/make/attachment.hh
index 3af5332..63eca65 100644
--- a/milena/mln/make/attachment.hh
+++ b/milena/mln/make/attachment.hh
@@ -74,6 +74,8 @@ namespace mln
attachment(const Image<I>& ima_, const mln_psite(I)& f,
const Neighborhood<N>& nbh_)
{
+ // FIXME: The current implementation of topo::is_facet is too
+ // naive: it does not take the values of the image into account.
mln_precondition(topo::is_facet(f));
mlc_equal(mln_value(I), bool)::check();
diff --git a/milena/mln/make/detachment.hh b/milena/mln/make/detachment.hh
index 6cd01ba..88b70a0 100644
--- a/milena/mln/make/detachment.hh
+++ b/milena/mln/make/detachment.hh
@@ -81,6 +81,8 @@ namespace mln
detachment(const Image<I>& ima_, const mln_psite(I)& f,
const Neighborhood<N>& nbh_)
{
+ // FIXME: The current implementation of topo::is_facet is too
+ // naive: it does not take the values of the image into account.
mln_precondition(topo::is_facet(f));
mlc_equal(mln_value(I), bool)::check();
diff --git a/milena/mln/topo/detach_cell.hh b/milena/mln/topo/detach_cell.hh
index 9e2a489..250babf 100644
--- a/milena/mln/topo/detach_cell.hh
+++ b/milena/mln/topo/detach_cell.hh
@@ -131,6 +131,8 @@ namespace mln
detach_cell<I, N>::operator()(const mln_psite(I)& f)
{
mln_precondition(ima_);
+ // FIXME: The current implementation of topo::is_facet is too
+ // naive: it does not take the values of the image into account.
mln_precondition(topo::is_facet(f));
typedef p_set<mln_psite(I)> faces_t;
diff --git a/milena/mln/topo/is_facet.hh b/milena/mln/topo/is_facet.hh
index 0b10040..675126c 100644
--- a/milena/mln/topo/is_facet.hh
+++ b/milena/mln/topo/is_facet.hh
@@ -52,6 +52,8 @@ namespace mln
# ifndef MLN_INCLUDE_ONLY
+ // FIXME: Too naive: this code does not take the values of the
+ // image into account.
template <unsigned D, typename G>
inline
bool
diff --git a/milena/mln/topo/is_simple_cell.hh b/milena/mln/topo/is_simple_cell.hh
index bf60c3d..0cf50fb 100644
--- a/milena/mln/topo/is_simple_cell.hh
+++ b/milena/mln/topo/is_simple_cell.hh
@@ -81,7 +81,12 @@ namespace mln
/// Set the underlying image.
void set_image(const mln::Image<I>& ima);
- /// Based on the algorithm A2 from couprie.08.pami.
+ /** \brief Test whether a face (expected to be facet) is a
+ simple cell.
+
+ If \a p is not a facet, return false.
+
+ Based on the algorithm A2 from couprie.08.pami. */
/* FIXME: We probably broke the compatiblity with g++ 3.3, as it
seems this compiler does not like an indirect type like the
one of the following operator's argument. Check and possibly
@@ -124,6 +129,25 @@ namespace mln
is_simple_cell<I, N, NL, NH>::operator()(const mln_psite(I)& p) const
{
mln_precondition(ima_);
+ // FIXME: Introduce `const I& ima = *ima_;' and use it instead of
+ // `ima_'. Or introduce an `ima()' accessor?
+
+ // FIXME: We should be using topo::is_facet, but this routine is
+ // too naive, and does not take the values of the image into
+ // account.
+ {
+ // This (part of) ``algorithm'' considers that looking for
+ // faces of dimension n+1 is enough (which is the case
+ // if the image is a complex).
+ NH higher_adj_nbh;
+ mln_niter(NH) n(higher_adj_nbh, p);
+ for_all(n)
+ // If the higher-dim-faces neighborhood is not empty, then P
+ // is included in a face of higher dimension.
+ if (ima_->has(n) && (*ima_)(n))
+ return false;
+ // Otherwise, F is a facet; continue.
+ }
typedef p_set<mln_psite(I)> faces_t;
--
1.5.6.5
* apps/mesh-segm-skel/mesh-complex-skel.cc,
* apps/mesh-segm-skel/mesh-complex-max-curv-skel.cc,
* apps/mesh-segm-skel/mesh-complex-pinv-curv-skel.cc:
Catch up with the new interface of breadth-first thinning and
auxiliary routines.
---
milena/ChangeLog | 10 +++
.../mesh-segm-skel/mesh-complex-max-curv-skel.cc | 82 ++++++++++++++++----
.../mesh-segm-skel/mesh-complex-pinv-curv-skel.cc | 82 ++++++++++++++++----
milena/apps/mesh-segm-skel/mesh-complex-skel.cc | 82 ++++++++++++++++----
4 files changed, 205 insertions(+), 51 deletions(-)
diff --git a/milena/ChangeLog b/milena/ChangeLog
index bff25d3..40e876c 100644
--- a/milena/ChangeLog
+++ b/milena/ChangeLog
@@ -1,5 +1,15 @@
2010-09-09 Roland Levillain <roland(a)lrde.epita.fr>
+ Update mesh skeleton applications.
+
+ * apps/mesh-segm-skel/mesh-complex-skel.cc,
+ * apps/mesh-segm-skel/mesh-complex-max-curv-skel.cc,
+ * apps/mesh-segm-skel/mesh-complex-pinv-curv-skel.cc:
+ Catch up with the new interface of breadth-first thinning and
+ auxiliary routines.
+
+2010-09-09 Roland Levillain <roland(a)lrde.epita.fr>
+
More generic breadth-first-thinning-based skeleton transformations.
* mln/topo/is_simple_cell.hh: Make this functor more generic.
diff --git a/milena/apps/mesh-segm-skel/mesh-complex-max-curv-skel.cc b/milena/apps/mesh-segm-skel/mesh-complex-max-curv-skel.cc
index edb943e..641b0b4 100644
--- a/milena/apps/mesh-segm-skel/mesh-complex-max-curv-skel.cc
+++ b/milena/apps/mesh-segm-skel/mesh-complex-max-curv-skel.cc
@@ -39,7 +39,9 @@
#include <mln/core/image/complex_image.hh>
#include <mln/core/image/complex_neighborhoods.hh>
-#include <mln/core/site_set/p_set.hh>
+#include <mln/core/image/dmorph/image_if.hh>
+#include <mln/core/image/dmorph/mutable_extension_ima.hh>
+#include <mln/core/routine/mutable_extend.hh>
#include <mln/value/label_16.hh>
@@ -252,31 +254,77 @@ main(int argc, char* argv[])
| Skeleton. |
`-----------*/
- mln::topo::is_simple_cell<bin_ima_t> is_simple_p;
- /* FIXME: Cheat! We'd like to iterate on cells of highest
- dimension (2-cells) only, but we cannot constrain the domain of
- the input using image_if (yet) like this
+ // ---------------- //
+ // Skeleton image. //
+ // ---------------- //
+
+ // Predicate type: is a face a triangle (2-face)?
+ typedef mln::topo::is_n_face<mln_psite_(bin_ima_t), D> is_a_triangle_t;
+ is_a_triangle_t is_a_triangle;
+ // Surface image type, of which domain is restricted to triangles.
+ typedef mln::image_if<bin_ima_t, is_a_triangle_t> bin_triangle_only_ima_t;
+ // Surface image type, of which iteration (not domain) is restricted
+ // to triangles.
+ typedef mln::mutable_extension_ima<bin_triangle_only_ima_t, bin_ima_t>
+ bin_triangle_ima_t;
+ // FIXME: Find a shorter name (skel_ima ? Careful, there is already a `skel' image below).
+ bin_triangle_ima_t bin_triangle_ima =
+ mln::mutable_extend((surface | is_a_triangle).rw(), surface);
+
+ // ------------------------ //
+ // Simple point predicate. //
+ // ------------------------ //
+
+ // Neighborhood type returning the set of (n-1)- and (n+1)-faces
+ // adjacent to a an n-face.
+ typedef mln::complex_lower_higher_neighborhood<D, G> adj_nbh_t;
+ // Neighborhood type returning the set of (n-1)-faces adjacent to a
+ // an n-face.
+ typedef mln::complex_lower_neighborhood<D, G> lower_adj_nbh_t;
+ // Neighborhood type returning the set of (n+1)-faces adjacent to a
+ // an n-face.
+ typedef mln::complex_higher_neighborhood<D, G> higher_adj_nbh_t;
+ // Predicate type: is a triangle (2-face) simple?
+ typedef mln::topo::is_simple_cell< bin_triangle_ima_t,
+ adj_nbh_t,
+ lower_adj_nbh_t,
+ higher_adj_nbh_t >
+ is_simple_triangle_t;
+ is_simple_triangle_t is_simple_triangle;
+
+ // ------------------------------- //
+ // Simple point detach procedure. //
+ // ------------------------------- //
+
+ // Type of adjacency relationships between faces of immediately
+ // lower and higher dimensions.
+ adj_nbh_t adj_nbh;
+ // Functor detaching a cell.
+ mln::topo::detach_cell<bin_triangle_ima_t, adj_nbh_t> detach(adj_nbh);
+
+ mln_concrete_(bin_triangle_ima_t) skel =
+ mln::topo::skeleton::breadth_first_thinning(bin_triangle_ima,
+ nbh,
+ is_simple_triangle,
+ detach);
- breadth_first_thinning(surface | is_n_face<2>, nbh, is_simple_p);
-
- As a workaround, we use the constraint predicate of the
- skeleton routine to restrict the iteration to 2-cells. */
- mln::topo::is_n_face<mln_psite_(bin_ima_t), bin_ima_t::dim> constraint_p;
- bin_ima_t skel =
- mln::topo::skeleton::breadth_first_thinning(surface, nbh,
- is_simple_p,
- mln::topo::detach_cell<D, G>,
- constraint_p);
/*---------.
| Output. |
`---------*/
/* FIXME: This does not work (yet).
- Use workaround mln::io::off::save_bin_alt instead (bad!) */
+ Use workaround mln::io::off::save_bin_alt instead (bad!)
+
+ Moreover, even if it worked, it would not have the same meaning
+ as mln::io::off::save_bin_alt. Maybe the latter is useful, after
+ all. But we need to factor it with the code of
+ mln::io::off::save, anyway. */
#if 0
mln::io::off::save(skel | mln::pw::value(skel) == mln::pw::cst(true),
output_filename);
#endif
- mln::io::off::save_bin_alt(skel, output_filename);
+ // FIXME: We have to ``unmorph'' (twice!) SKEL first, since save_bin_alt only
+ // handles complex_image's.
+ mln::io::off::save_bin_alt(skel.unmorph_().unmorph_(), output_filename);
}
diff --git a/milena/apps/mesh-segm-skel/mesh-complex-pinv-curv-skel.cc b/milena/apps/mesh-segm-skel/mesh-complex-pinv-curv-skel.cc
index e2bdf45..5096efa 100644
--- a/milena/apps/mesh-segm-skel/mesh-complex-pinv-curv-skel.cc
+++ b/milena/apps/mesh-segm-skel/mesh-complex-pinv-curv-skel.cc
@@ -39,7 +39,9 @@
#include <mln/core/image/complex_image.hh>
#include <mln/core/image/complex_neighborhoods.hh>
-#include <mln/core/site_set/p_set.hh>
+#include <mln/core/image/dmorph/image_if.hh>
+#include <mln/core/image/dmorph/mutable_extension_ima.hh>
+#include <mln/core/routine/mutable_extend.hh>
#include <mln/value/label_16.hh>
@@ -257,31 +259,77 @@ main(int argc, char* argv[])
| Skeleton. |
`-----------*/
- mln::topo::is_simple_cell<bin_ima_t> is_simple_p;
- /* FIXME: Cheat! We'd like to iterate on cells of highest
- dimension (2-cells) only, but we cannot constrain the domain of
- the input using image_if (yet) like this
+ // ---------------- //
+ // Skeleton image. //
+ // ---------------- //
+
+ // Predicate type: is a face a triangle (2-face)?
+ typedef mln::topo::is_n_face<mln_psite_(bin_ima_t), D> is_a_triangle_t;
+ is_a_triangle_t is_a_triangle;
+ // Surface image type, of which domain is restricted to triangles.
+ typedef mln::image_if<bin_ima_t, is_a_triangle_t> bin_triangle_only_ima_t;
+ // Surface image type, of which iteration (not domain) is restricted
+ // to triangles.
+ typedef mln::mutable_extension_ima<bin_triangle_only_ima_t, bin_ima_t>
+ bin_triangle_ima_t;
+ // FIXME: Find a shorter name (skel_ima ? Careful, there is already a `skel' image below).
+ bin_triangle_ima_t bin_triangle_ima =
+ mln::mutable_extend((surface | is_a_triangle).rw(), surface);
+
+ // ------------------------ //
+ // Simple point predicate. //
+ // ------------------------ //
+
+ // Neighborhood type returning the set of (n-1)- and (n+1)-faces
+ // adjacent to a an n-face.
+ typedef mln::complex_lower_higher_neighborhood<D, G> adj_nbh_t;
+ // Neighborhood type returning the set of (n-1)-faces adjacent to a
+ // an n-face.
+ typedef mln::complex_lower_neighborhood<D, G> lower_adj_nbh_t;
+ // Neighborhood type returning the set of (n+1)-faces adjacent to a
+ // an n-face.
+ typedef mln::complex_higher_neighborhood<D, G> higher_adj_nbh_t;
+ // Predicate type: is a triangle (2-face) simple?
+ typedef mln::topo::is_simple_cell< bin_triangle_ima_t,
+ adj_nbh_t,
+ lower_adj_nbh_t,
+ higher_adj_nbh_t >
+ is_simple_triangle_t;
+ is_simple_triangle_t is_simple_triangle;
+
+ // ------------------------------- //
+ // Simple point detach procedure. //
+ // ------------------------------- //
+
+ // Type of adjacency relationships between faces of immediately
+ // lower and higher dimensions.
+ adj_nbh_t adj_nbh;
+ // Functor detaching a cell.
+ mln::topo::detach_cell<bin_triangle_ima_t, adj_nbh_t> detach(adj_nbh);
+
+ mln_concrete_(bin_triangle_ima_t) skel =
+ mln::topo::skeleton::breadth_first_thinning(bin_triangle_ima,
+ nbh,
+ is_simple_triangle,
+ detach);
- breadth_first_thinning(surface | is_n_face<2>, nbh, is_simple_p);
-
- As a workaround, we use the constraint predicate of the
- skeleton routine to restrict the iteration to 2-cells. */
- mln::topo::is_n_face<mln_psite_(bin_ima_t), bin_ima_t::dim> constraint_p;
- bin_ima_t skel =
- mln::topo::skeleton::breadth_first_thinning(surface, nbh,
- is_simple_p,
- mln::topo::detach_cell<D, G>,
- constraint_p);
/*---------.
| Output. |
`---------*/
/* FIXME: This does not work (yet).
- Use workaround mln::io::off::save_bin_alt instead (bad!) */
+ Use workaround mln::io::off::save_bin_alt instead (bad!)
+
+ Moreover, even if it worked, it would not have the same meaning
+ as mln::io::off::save_bin_alt. Maybe the latter is useful, after
+ all. But we need to factor it with the code of
+ mln::io::off::save, anyway. */
#if 0
mln::io::off::save(skel | mln::pw::value(skel) == mln::pw::cst(true),
output_filename);
#endif
- mln::io::off::save_bin_alt(skel, output_filename);
+ // FIXME: We have to ``unmorph'' (twice!) SKEL first, since save_bin_alt only
+ // handles complex_image's.
+ mln::io::off::save_bin_alt(skel.unmorph_().unmorph_(), output_filename);
}
diff --git a/milena/apps/mesh-segm-skel/mesh-complex-skel.cc b/milena/apps/mesh-segm-skel/mesh-complex-skel.cc
index b8b7da8..4f5ca78 100644
--- a/milena/apps/mesh-segm-skel/mesh-complex-skel.cc
+++ b/milena/apps/mesh-segm-skel/mesh-complex-skel.cc
@@ -36,7 +36,9 @@
#include <mln/core/image/complex_image.hh>
#include <mln/core/image/complex_neighborhoods.hh>
-#include <mln/core/site_set/p_set.hh>
+#include <mln/core/image/dmorph/image_if.hh>
+#include <mln/core/image/dmorph/mutable_extension_ima.hh>
+#include <mln/core/routine/mutable_extend.hh>
#include <mln/value/label_16.hh>
@@ -210,31 +212,77 @@ main(int argc, char* argv[])
| Skeleton. |
`-----------*/
- mln::topo::is_simple_cell<bin_ima_t> is_simple_p;
- /* FIXME: Cheat! We'd like to iterate on cells of highest
- dimension (2-cells) only, but we cannot constrain the domain of
- the input using image_if (yet) like this
+ // ---------------- //
+ // Skeleton image. //
+ // ---------------- //
+
+ // Predicate type: is a face a triangle (2-face)?
+ typedef mln::topo::is_n_face<mln_psite_(bin_ima_t), D> is_a_triangle_t;
+ is_a_triangle_t is_a_triangle;
+ // Surface image type, of which domain is restricted to triangles.
+ typedef mln::image_if<bin_ima_t, is_a_triangle_t> bin_triangle_only_ima_t;
+ // Surface image type, of which iteration (not domain) is restricted
+ // to triangles.
+ typedef mln::mutable_extension_ima<bin_triangle_only_ima_t, bin_ima_t>
+ bin_triangle_ima_t;
+ // FIXME: Find a shorter name (skel_ima ? Careful, there is already a `skel' image below).
+ bin_triangle_ima_t bin_triangle_ima =
+ mln::mutable_extend((surface | is_a_triangle).rw(), surface);
+
+ // ------------------------ //
+ // Simple point predicate. //
+ // ------------------------ //
+
+ // Neighborhood type returning the set of (n-1)- and (n+1)-faces
+ // adjacent to a an n-face.
+ typedef mln::complex_lower_higher_neighborhood<D, G> adj_nbh_t;
+ // Neighborhood type returning the set of (n-1)-faces adjacent to a
+ // an n-face.
+ typedef mln::complex_lower_neighborhood<D, G> lower_adj_nbh_t;
+ // Neighborhood type returning the set of (n+1)-faces adjacent to a
+ // an n-face.
+ typedef mln::complex_higher_neighborhood<D, G> higher_adj_nbh_t;
+ // Predicate type: is a triangle (2-face) simple?
+ typedef mln::topo::is_simple_cell< bin_triangle_ima_t,
+ adj_nbh_t,
+ lower_adj_nbh_t,
+ higher_adj_nbh_t >
+ is_simple_triangle_t;
+ is_simple_triangle_t is_simple_triangle;
+
+ // ------------------------------- //
+ // Simple point detach procedure. //
+ // ------------------------------- //
+
+ // Type of adjacency relationships between faces of immediately
+ // lower and higher dimensions.
+ adj_nbh_t adj_nbh;
+ // Functor detaching a cell.
+ mln::topo::detach_cell<bin_triangle_ima_t, adj_nbh_t> detach(adj_nbh);
+
+ mln_concrete_(bin_triangle_ima_t) skel =
+ mln::topo::skeleton::breadth_first_thinning(bin_triangle_ima,
+ nbh,
+ is_simple_triangle,
+ detach);
- breadth_first_thinning(surface | is_n_face<2>, nbh, is_simple_p);
-
- As a workaround, we use the constraint predicate of the
- skeleton routine to restrict the iteration to 2-cells. */
- mln::topo::is_n_face<mln_psite_(bin_ima_t), bin_ima_t::dim> constraint_p;
- bin_ima_t skel =
- mln::topo::skeleton::breadth_first_thinning(surface, nbh,
- is_simple_p,
- mln::topo::detach_cell<D, G>,
- constraint_p);
/*---------.
| Output. |
`---------*/
/* FIXME: This does not work (yet).
- Use workaround mln::io::off::save_bin_alt instead (bad!) */
+ Use workaround mln::io::off::save_bin_alt instead (bad!)
+
+ Moreover, even if it worked, it would not have the same meaning
+ as mln::io::off::save_bin_alt. Maybe the latter is useful, after
+ all. But we need to factor it with the code of
+ mln::io::off::save, anyway. */
#if 0
mln::io::off::save(skel | mln::pw::value(skel) == mln::pw::cst(true),
output_filename);
#endif
- mln::io::off::save_bin_alt(skel, output_filename);
+ // FIXME: We have to ``unmorph'' (twice!) SKEL first, since save_bin_alt only
+ // handles complex_image's.
+ mln::io::off::save_bin_alt(skel.unmorph_().unmorph_(), output_filename);
}
--
1.5.6.5
* mln/topo/is_simple_cell.hh: Make this functor more generic.
* mln/topo/detach_cell.hh (detach): Turn this function into a
more generic functor.
* mln/make/attachment.hh (mln::make::attachment)
* mln/make/detachment.hh (mln::make::detachment):
Make these routines more generic.
* mln/topo/skeleton/breadth_first_thinning.hh
(mln::topo::skeleton::breadth_first_thinning):
Adjust.
* headers.mk: Regen.
---
milena/ChangeLog | 15 +++
milena/mln/make/attachment.hh | 48 +++++----
milena/mln/make/detachment.hh | 41 +++++---
milena/mln/topo/detach_cell.hh | 107 ++++++++++++++++---
milena/mln/topo/is_simple_cell.hh | 81 ++++++++-------
milena/mln/topo/skeleton/breadth_first_thinning.hh | 18 +++-
6 files changed, 213 insertions(+), 97 deletions(-)
diff --git a/milena/ChangeLog b/milena/ChangeLog
index c0a7088..bff25d3 100644
--- a/milena/ChangeLog
+++ b/milena/ChangeLog
@@ -1,5 +1,20 @@
2010-09-09 Roland Levillain <roland(a)lrde.epita.fr>
+ More generic breadth-first-thinning-based skeleton transformations.
+
+ * mln/topo/is_simple_cell.hh: Make this functor more generic.
+ * mln/topo/detach_cell.hh (detach): Turn this function into a
+ more generic functor.
+ * mln/make/attachment.hh (mln::make::attachment)
+ * mln/make/detachment.hh (mln::make::detachment):
+ Make these routines more generic.
+ * mln/topo/skeleton/breadth_first_thinning.hh
+ (mln::topo::skeleton::breadth_first_thinning):
+ Adjust.
+ * headers.mk: Regen.
+
+2010-09-09 Roland Levillain <roland(a)lrde.epita.fr>
+
Introduce a helper to build an mln::mutable_extension_ima.
* mln/core/routine/mutable_extend.hh: New.
diff --git a/milena/mln/make/attachment.hh b/milena/mln/make/attachment.hh
index 088f9df..3af5332 100644
--- a/milena/mln/make/attachment.hh
+++ b/milena/mln/make/attachment.hh
@@ -1,4 +1,4 @@
-// Copyright (C) 2009 EPITA Research and Development Laboratory (LRDE)
+// Copyright (C) 2009, 2010 EPITA Research and Development Laboratory (LRDE)
//
// This file is part of Olena.
//
@@ -43,52 +43,58 @@ namespace mln
/** \brief Compute the attachment of the cell corresponding to the
facet \a f to the image \a ima.
+ \param ima The input image to which the facet is attached.
+ \param f The psite corresponding to the attached facet.
+ \param nbh An adjacency relationship between faces
+ (should return the set of (n-1)- and (n+1)-faces
+ adjacent to an n-face).
+
+ \return A set of faces containing the attachment.
+
+ \pre ima is an image of Boolean values.
\pre \a f is a facet (it does not belong to any face of higher
dimension).
- \pre ima is an image of Boolean values.
-
- \return a set of faces containing the attachment.
We do not use the fomal definition of the attachment here (see
couprie.08.pami). We use the following (equivalent) definition:
an N-face F in CELL is in the attachment of CELL to IMA if it is
adjacent to at least an (N-1)-face or an (N+1)-face that does not
belong to CELL. */
- template <unsigned D, typename G, typename V>
- p_set< complex_psite<D, G> >
- attachment(const complex_psite<D, G>& f,
- const complex_image<D, G, V>& ima);
+ template <typename I, typename N>
+ p_set<mln_psite(I)>
+ attachment(const Image<I>& ima, const mln_psite(I)& f,
+ const Neighborhood<N>& nbh);
# ifndef MLN_INCLUDE_ONLY
- template <unsigned D, typename G, typename V>
+ template <typename I, typename N>
inline
- p_set< complex_psite<D, G> >
- attachment(const complex_psite<D, G>& f,
- const complex_image<D, G, V>& ima)
+ p_set<mln_psite(I)>
+ attachment(const Image<I>& ima_, const mln_psite(I)& f,
+ const Neighborhood<N>& nbh_)
{
mln_precondition(topo::is_facet(f));
- mlc_equal(V, bool)::check();
+ mlc_equal(mln_value(I), bool)::check();
+
+ I ima = exact(ima_);
+ N nbh = exact(nbh_);
- typedef complex_psite<D, G> psite;
- typedef p_set<psite> faces_t;
+ typedef p_set<mln_psite(I)> faces_t;
faces_t f_hat = make::cell(f);
- faces_t att_f;
+ faces_t attach_f;
- typedef complex_lower_higher_neighborhood<D, G> adj_nbh_t;
- adj_nbh_t adj_nbh;
mln_piter(faces_t) g(f_hat);
- mln_niter(adj_nbh_t) n(adj_nbh, g);
+ mln_niter(N) n(nbh, g);
for_all(g)
for_all(n)
if (ima(n) && !f_hat.has(n))
{
- att_f.insert(g);
+ attach_f.insert(g);
break;
}
- return att_f;
+ return attach_f;
}
# endif // MLN_INCLUDE_ONLY
diff --git a/milena/mln/make/detachment.hh b/milena/mln/make/detachment.hh
index 16a8c92..6cd01ba 100644
--- a/milena/mln/make/detachment.hh
+++ b/milena/mln/make/detachment.hh
@@ -1,4 +1,4 @@
-// Copyright (C) 2009 EPITA Research and Development Laboratory (LRDE)
+// Copyright (C) 2009, 2010 EPITA Research and Development Laboratory (LRDE)
//
// This file is part of Olena.
//
@@ -43,12 +43,19 @@ namespace mln
/** \brief Compute the detachment of the cell corresponding to the
facet \a f from the image \a ima.
+ \param ima The input image from which the facet is to be
+ detached.
+ \param f The psite corresponding to the facet to detach.
+ \param nbh An adjacency relationship between faces
+ (should return the set of (n-1)- and (n+1)-faces
+ adjacent to an n-face).
+
+ \return A set of faces containing the detachment.
+
\pre \a f is a facet (it does not belong to any face of higher
dimension).
\pre \a ima is an image of Boolean values.
- \return a set of faces containing the detachment.
-
We do not use the fomal definition of the detachment here (see
couprie.08.pami). We use the following (equivalent) definition:
an N-face F in CELL is not in the detachment of CELL from IMA if
@@ -60,34 +67,34 @@ namespace mln
the part that is removed, i.e., the detached part CELL -
ATTACHMENT. It would be wise to rename this routine to
something else. */
- template <unsigned D, typename G, typename V>
- p_set< complex_psite<D, G> >
- detachment(const complex_psite<D, G>& f,
- const complex_image<D, G, V>& ima);
+ template <typename I, typename N>
+ p_set<mln_psite(I)>
+ detachment(const Image<I>& ima, const mln_psite(I)& f,
+ const Neighborhood<N>& nbh);
# ifndef MLN_INCLUDE_ONLY
- template <unsigned D, typename G, typename V>
+ template <typename I, typename N>
inline
- p_set< complex_psite<D, G> >
- detachment(const complex_psite<D, G>& f,
- const complex_image<D, G, V>& ima)
+ p_set<mln_psite(I)>
+ detachment(const Image<I>& ima_, const mln_psite(I)& f,
+ const Neighborhood<N>& nbh_)
{
mln_precondition(topo::is_facet(f));
- mlc_equal(V, bool)::check();
+ mlc_equal(mln_value(I), bool)::check();
+
+ I ima = exact(ima_);
+ N nbh = exact(nbh_);
- typedef complex_psite<D, G> psite;
- typedef p_set<psite> faces_t;
+ typedef p_set<mln_psite(I)> faces_t;
faces_t f_hat = make::cell(f);
// Initialize DETACH_F to F_HAT.
faces_t detach_f = f_hat;
- typedef complex_lower_higher_neighborhood<D, G> adj_nbh_t;
- adj_nbh_t adj_nbh;
mln_piter(faces_t) g(f_hat);
- mln_niter(adj_nbh_t) n(adj_nbh, g);
+ mln_niter(N) n(nbh, g);
for_all(g)
for_all(n)
if (ima(n) && !f_hat.has(n))
diff --git a/milena/mln/topo/detach_cell.hh b/milena/mln/topo/detach_cell.hh
index dfc4fb5..9e2a489 100644
--- a/milena/mln/topo/detach_cell.hh
+++ b/milena/mln/topo/detach_cell.hh
@@ -27,7 +27,7 @@
# define MLN_TOPO_DETACH_CELL_HH
/// \file
-/// \brief Detaching a cell from a binary complex-based image.
+/// \brief Detaching a cell from a binary (probably complex-based) image.
# include <mln/core/site_set/p_set.hh>
# include <mln/core/image/complex_image.hh>
@@ -40,38 +40,111 @@ namespace mln
namespace topo
{
- /** Detach the cell corresponding to \a f from \a ima.
+ /** A functor detaching a cell from a binary (probably
+ complex-based) image.
- \pre \a f is a facet (it does not belong to any face of higher
- dimension).
- \pre \a ima is an image of Boolean values. */
- template <unsigned D, typename G>
- void
- detach_cell(const complex_psite<D, G>& f, complex_image<D, G, bool>& ima);
+ \tparam I The type of the image.
+ \tparam N An neighborhood type corresponding to (directly)
+ adjacent faces (should return the set of (n-1)- and
+ (n+1)-faces adjacent to an n-face). */
+ template <typename I, typename N>
+ class detach_cell
+ {
+ public:
+ /// Constructors.
+ /// \{
+ /** Construct an mln::topo::detach_cell from a neighborhood.
+
+ \param nbh An adjacency relationship between faces
+ (should return the set of (n-1)- and (n+1)-faces
+ adjacent to an n-face). */
+ detach_cell(const Neighborhood<N>& nbh);
+
+ /** Construct an mln::topo::detach_cell from an image and a
+ neighborhood.
+
+ \pre \a ima is an image of Boolean values.
+
+ \param ima The input image from which the facet is to be
+ detached.
+ \param nbh An adjacency relationship between faces
+ (should return the set of (n-1)- and (n+1)-faces
+ adjacent to an n-face). */
+ detach_cell(mln::Image<I>& ima, const Neighborhood<N>& nbh);
+ /// \}
+
+ /* FIXME: Rename as init() or something like this? See how other
+ functors are written. */
+ /** Set the underlying image.
+
+ \pre \a ima is an image of Boolean values. */
+ void set_image(mln::Image<I>& ima);
+
+ /** Detach the cell corresponding to \a f from \a ima.
+
+ \pre \a f is a facet (it does not belong to any face of
+ higher dimension).
+
+ \param f The psite corresponding to the facet to detach.
+ \param nbh An adjacency relationship between faces
+ (should return the set of (n-1)- and (n+1)-faces
+ adjacent to an n-face). */
+ void
+ operator()(const mln_psite(I)& f);
+
+ private:
+ I* ima_;
+ const N& nbh_;
+ };
# ifndef MLN_INCLUDE_ONLY
- template <unsigned D, typename G>
+ template <typename I, typename N>
+ inline
+ detach_cell<I, N>::detach_cell(const Neighborhood<N>& nbh)
+ : ima_(0), nbh_(exact(nbh))
+ {
+ }
+
+ template <typename I, typename N>
+ inline
+ detach_cell<I, N>::detach_cell(mln::Image<I>& ima,
+ const Neighborhood<N>& nbh)
+ : ima_(exact(&ima)), nbh_(exact(nbh))
+ {
+ mlc_equal(mln_value(I), bool)::check();
+ }
+
+ template <typename I, typename N>
+ inline
+ void
+ detach_cell<I, N>::set_image(mln::Image<I>& ima)
+ {
+ mlc_equal(mln_value(I), bool)::check();
+ ima_ = exact(&ima);
+ }
+
+ template <typename I, typename N>
inline
void
- detach_cell(const complex_psite<D, G>& f, complex_image<D, G, bool>& ima)
+ detach_cell<I, N>::operator()(const mln_psite(I)& f)
{
+ mln_precondition(ima_);
mln_precondition(topo::is_facet(f));
- typedef complex_psite<D, G> psite;
- typedef p_set<psite> faces_t;
+ typedef p_set<mln_psite(I)> faces_t;
- // Compute the detachment of P from IMA.
- faces_t detach = make::detachment(f, ima);
- // Detach all its faces from IMA.
+ // Compute the detachment of P from *IMA_.
+ faces_t detach = make::detachment(*ima_, f, nbh_);
+ // Detach all its faces from *IMA_.
# if 0
// FIXME: Does not work yet? Check again.
- data::fill(ima | detach, false);
+ data::fill(*ima_ | detach, false);
# endif
mln_piter(faces_t) p(detach);
for_all(p)
- ima(p) = false;
+ (*ima_)(p) = false;
}
# endif // MLN_INCLUDE_ONLY
diff --git a/milena/mln/topo/is_simple_cell.hh b/milena/mln/topo/is_simple_cell.hh
index a86a8fa..bf60c3d 100644
--- a/milena/mln/topo/is_simple_cell.hh
+++ b/milena/mln/topo/is_simple_cell.hh
@@ -1,4 +1,4 @@
-// Copyright (C) 2009 EPITA Research and Development Laboratory (LRDE)
+// Copyright (C) 2009, 2010 EPITA Research and Development Laboratory (LRDE)
//
// This file is part of Olena.
//
@@ -27,7 +27,6 @@
# define MLN_TOPO_IS_SIMPLE_CELL_HH
/// \file
-///
/// \brief Testing whether a facet is a simple cell.
# include <mln/core/concept/function.hh>
@@ -48,22 +47,29 @@ namespace mln
namespace topo
{
+ /* FIXME: Maybe we could add traits to deduce N from NL and NH (or
+ the converse). Anyway, the part of the code where neighborhood
+ are used should be moved into another functor
+ (`is_collapsible', see below), thus pushing away this
+ issue. */
+
/** \brief A predicate for the simplicity of a point based on the
collapse property of the attachment.
The functor does not actually take a cell as input, but a face
- that is expected to be a D-facet. */
- template <typename I>
- class is_simple_cell : public mln::Function_v2b< is_simple_cell<I> >
+ that is expected to be a D-facet.
+
+ \tparam I The type of the image.
+ \tparam N The neighborhood type returning the set of
+ (n-1)- and (n+1)-faces adjacent to a an n-face.
+ \tparam NL The neighborhood type returning the set of
+ (n-1)-faces adjacent to a an n-face.
+ \tparam NH The neighborhood type returning the set of
+ (n+1)-faces adjacent to a an n-face. */
+ template <typename I, typename N, typename NL, typename NH>
+ class is_simple_cell : public mln::Function_v2b< is_simple_cell<I, N, NL, NH> >
{
public:
- /// Dimension of the image (and therefore of the complex).
- static const unsigned D = I::dim;
- /// Geometry of the image.
- typedef mln_geom(I) G;
- /// Psite type.
- typedef mln::complex_psite<D, G> psite;
-
/// Result type of the functor.
typedef bool result;
@@ -76,8 +82,11 @@ namespace mln
void set_image(const mln::Image<I>& ima);
/// Based on the algorithm A2 from couprie.08.pami.
- bool operator()(const mln::complex_psite<I::dim,mln_geom(I)>& p) const;
- // Tech note: The argument type above is explicit to help g++-3.3.
+ /* FIXME: We probably broke the compatiblity with g++ 3.3, as it
+ seems this compiler does not like an indirect type like the
+ one of the following operator's argument. Check and possibly
+ improve this. */
+ bool operator()(const mln_psite(I)& p) const;
private:
const I* ima_;
@@ -87,44 +96,44 @@ namespace mln
# ifndef MLN_INCLUDE_ONLY
- template <typename I>
+ template <typename I, typename N, typename NL, typename NH>
inline
- is_simple_cell<I>::is_simple_cell()
+ is_simple_cell<I, N, NL, NH>::is_simple_cell()
: ima_(0)
{
}
- template <typename I>
+ template <typename I, typename N, typename NL, typename NH>
inline
- is_simple_cell<I>::is_simple_cell(const mln::Image<I>& ima)
- : ima_(mln::exact(&ima))
+ is_simple_cell<I, N, NL, NH>::is_simple_cell(const mln::Image<I>& ima)
+ : ima_(exact(&ima))
{
}
- template <typename I>
+ template <typename I, typename N, typename NL, typename NH>
inline
void
- is_simple_cell<I>::set_image(const mln::Image<I>& ima)
+ is_simple_cell<I, N, NL, NH>::set_image(const mln::Image<I>& ima)
{
- ima_ = mln::exact(&ima);
+ ima_ = exact(&ima);
}
- template <typename I>
+ template <typename I, typename N, typename NL, typename NH>
inline
bool
- is_simple_cell<I>::operator()(const mln::complex_psite<I::dim,mln_geom(I)>& p) const
- // Tech note: The argument type above is explicit to help g++-3.3.
+ is_simple_cell<I, N, NL, NH>::operator()(const mln_psite(I)& p) const
{
mln_precondition(ima_);
- typedef p_set<psite> faces_t;
+ typedef p_set<mln_psite(I)> faces_t;
- // Compute the attachment of the cell corresponding to P to he
+ // Compute the attachment of the cell corresponding to P to the
// domain of *IMA_.
- faces_t att = make::attachment(p, *ima_);
+ N adj_nbh;
+ faces_t att = make::attachment(*ima_, p, adj_nbh);
// A cell with an empty attachment is not simple.
- /* FIXME: Why does p_set not provide an empty() predicate? */
+ /* FIXME: Why p_set does not provide an empty() predicate? */
if (att.nsites() == 0)
return false;
@@ -134,10 +143,8 @@ namespace mln
routine. */
// Try to collapse the attachment (to a single point).
{
- typedef complex_lower_neighborhood<D, G> lower_adj_nbh_t;
- typedef complex_higher_neighborhood<D, G> higher_adj_nbh_t;
- lower_adj_nbh_t lower_adj_nbh;
- higher_adj_nbh_t higher_adj_nbh;
+ NL lower_adj_nbh;
+ NH higher_adj_nbh;
while (att.nsites() > 1)
{
@@ -149,11 +156,11 @@ namespace mln
for_all(g)
/* G cannot have dimension 0, since we later look for an
adjacent face H of lower dimension. */
- if (static_cast<psite>(g).n() > 0)
+ if (static_cast<mln_psite(I)>(g).n() > 0)
{
// Check whether G is a facet within ATT.
bool g_is_facet = true;
- mln_niter(higher_adj_nbh_t) f(higher_adj_nbh, g);
+ mln_niter(NH) f(higher_adj_nbh, g);
for_all(f)
if (att.has(f))
{
@@ -165,13 +172,13 @@ namespace mln
// Look for a face H stricly included in G.
bool gh_is_simple_pair = false;
- mln_niter(lower_adj_nbh_t) h(lower_adj_nbh, g);
+ mln_niter(NL) h(lower_adj_nbh, g);
for_all(h)
{
bool h_strictly_in_g = true;
if (att.has(h))
{
- mln_niter(higher_adj_nbh_t) i(higher_adj_nbh, h);
+ mln_niter(NH) i(higher_adj_nbh, h);
for_all(i)
if (i != g && att.has(i))
{
diff --git a/milena/mln/topo/skeleton/breadth_first_thinning.hh b/milena/mln/topo/skeleton/breadth_first_thinning.hh
index 7401bae..121c159 100644
--- a/milena/mln/topo/skeleton/breadth_first_thinning.hh
+++ b/milena/mln/topo/skeleton/breadth_first_thinning.hh
@@ -61,9 +61,13 @@ namespace mln
(sites). This functor must provide a method
<tt>void set_image(const Image<I>&)</tt>.
\param detach A function used to detach a cell from \a input.
+ This functor must provide a method
+ <tt>void set_image(const Image<I>&)</tt>.
\param constraint A constraint on point (site); if it
returns \c false for a point, this point
- will not be removed. */
+ will not be removed.
+
+ Keywords: skeletons, simple points. */
template <typename I, typename N, typename F, typename G, typename H>
mln_concrete(I)
breadth_first_thinning(const Image<I>& input,
@@ -83,8 +87,11 @@ namespace mln
\param is_simple The predicate on the simplicity of points
(sites). This functor must provide a method
<tt>void set_image(const Image<I>&)</tt>.
- \param detach A function used to detach a cell from
- \a input. */
+ \param detach A function used to detach a cell from \a input.
+ This functor must provide a method
+ <tt>void set_image(const Image<I>&)</tt>.
+
+ Keywords: skeletons, simple points. */
template <typename I, typename N, typename F, typename G>
mln_concrete(I)
breadth_first_thinning(const Image<I>& input,
@@ -112,8 +119,9 @@ namespace mln
const H& constraint = exact(constraint_);
mln_concrete(I) output = duplicate(input);
- // Attach the work image to IS_SIMPLE.
+ // Attach the work image to IS_SIMPLE and DETACH.
is_simple.set_image(output);
+ detach.set_image(output);
typedef mln_psite(I) psite;
typedef p_queue_fast<psite> queue_t;
@@ -131,7 +139,7 @@ namespace mln
psite p = queue.pop_front();
if (output(p) && constraint(p) && is_simple(p))
{
- detach(p, output);
+ detach(p);
mln_niter(N) n(nbh, p);
for_all(n)
{
--
1.5.6.5