https://svn.lrde.epita.fr/svn/oln/branches/cleanup-2008/milena
Index: ChangeLog
from Thierry Geraud <thierry.geraud(a)lrde.epita.fr>
Import skeleton from matthieu's sandbox.
* mln/topo/is_simple_2d.hh: New.
* mln/morpho/skeleton_constrained.hh: New.
* tests/morpho/skeleton_constrained.cc: New.
* tests/morpho/Makefile.am: Update.
* img/small.pbm: New.
* img/fly.pbm: New.
* mln/win/multiple_size.hh (i_): Change type to signed.
(size_): Change return type to int to prevent warning.
(is_valid_, invalidate_): Fix the case of the iterator
construction is deferred.
img/fly.pbm | 5
mln/morpho/skeleton_constrained.hh | 177 +++++++++++------------------------
mln/topo/is_simple_2d.hh | 167 +++++++++++++--------------------
mln/win/multiple_size.hh | 12 +-
tests/morpho/Makefile.am | 3
tests/morpho/skeleton_constrained.cc | 104 ++++++++++++++++++++
6 files changed, 246 insertions(+), 222 deletions(-)
Index: tests/morpho/skeleton_constrained.cc
--- tests/morpho/skeleton_constrained.cc (revision 0)
+++ tests/morpho/skeleton_constrained.cc (revision 0)
@@ -0,0 +1,104 @@
+// Copyright (C) 2008 EPITA Research and Development Laboratory (LRDE)
+//
+// 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.
+
+/// \file tests/morpho/skeleton_constrained.cc
+///
+/// Test on mln::morpho::skeleton_constrained.
+///
+
+#include <mln/core/image/image2d.hh>
+#include <mln/core/alias/neighb2d.hh>
+#include <mln/core/var.hh>
+#include <mln/value/int_u8.hh>
+
+#include <mln/make/dual_neighb.hh>
+#include <mln/topo/is_simple_2d.hh>
+#include <mln/morpho/skeleton_constrained.hh>
+
+#include <mln/io/pbm/load.hh>
+#include <mln/io/pbm/save.hh>
+#include <mln/level/fill.hh>
+#include <mln/debug/println.hh>
+#include <mln/debug/println_with_border.hh>
+
+#include <mln/pw/value.hh>
+#include <mln/core/image/image_if.hh>
+
+#include "tests/data.hh"
+
+
+namespace mln
+{
+
+ template <typename N>
+ void show_connectivity_numbers(const image2d<bool>& ima,
+ const N& nbh)
+ {
+ extension::adjust_fill(ima, nbh, false);
+
+ image2d<unsigned> when_true(ima.domain()), when_false(ima.domain());
+ mln_piter(box2d) p(ima.domain());
+ for_all(p)
+ {
+ when_true(p) = connectivity_number_2d(ima, nbh.foreground(), p, true);
+ when_false(p) = connectivity_number_2d(ima, nbh.background(), p, false);
+ }
+ debug::println("when true = ", when_true | pw::value(ima));
+ debug::println("when false = ", when_false | pw::value(ima));
+ }
+
+} // mln
+
+
+int main()
+{
+ using namespace mln;
+ using value::int_u8;
+
+ image2d<bool> pic;
+ io::pbm::load(pic, MLN_IMG_DIR "/tiny.pbm");
+
+ mln_VAR( nbh,
+ make::dual_neighb(pic, c4(), c8()) );
+
+ show_connectivity_numbers(pic, nbh);
+
+
+ image2d<bool> K(pic.domain());
+ level::fill(K, false);
+
+ image2d<int_u8> prior(pic.domain());
+ level::fill(prior, 1);
+
+ mln_VAR( skl,
+ morpho::skeleton_constrained(pic,
+ nbh, is_simple_2d_t(),
+ K, prior) );
+
+ debug::println("pic =", pic);
+ debug::println("skl =", skl);
+}
Index: tests/morpho/Makefile.am
--- tests/morpho/Makefile.am (revision 2895)
+++ tests/morpho/Makefile.am (working copy)
@@ -31,6 +31,7 @@
opening_area \
opening_height \
opening_volume \
+ skeleton_constrained \
thinning
# -------------- #
@@ -67,6 +68,8 @@
meyer_wst_SOURCES = meyer_wst.cc
+skeleton_constrained_SOURCES = skeleton_constrained.cc
+
combined_SOURCES = combined.cc
# --------------- #
Index: mln/topo/is_simple_2d.hh
--- mln/topo/is_simple_2d.hh (revision 2893)
+++ mln/topo/is_simple_2d.hh (working copy)
@@ -1,4 +1,4 @@
-// Copyright (C) 2007, 2008 EPITA Research and Development Laboratory
+// Copyright (C) 2008 EPITA Research and Development Laboratory (LRDE)
//
// This file is part of the Olena Library. This library is free
// software; you can redistribute it and/or modify it under the terms
@@ -25,47 +25,59 @@
// reasons why the executable file might be covered by the GNU General
// Public License.
-#ifndef MLN_SIMPLE_POINT_HH
-# define MLN_SIMPLE_POINT_HH
+#ifndef MLN_TOPO_IS_SIMPLE_2D_HH
+# define MLN_TOPO_IS_SIMPLE_2D_HH
-/*! \file simple_point.hh
- *
- * \brief is_simple_point tell if a point is simple or not (Cf
- * bertrand.07.chap).
- *
- */
+/// \file mln/topo/is_simple_2d.hh
+///
+/// Define the function is_simple_2d which tests if a point is simple
+/// or not (Cf bertrand.07.chap).
+
+#include <mln/core/concept/image.hh>
+#include <mln/core/concept/neighborhood.hh>
#include <mln/core/alias/point2d.hh>
-#include <mln/core/image/image2d.hh>
#include <mln/core/alias/neighb2d.hh>
+
namespace mln
{
-/*! Tell 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.
- * | | |
- *
- */
+ /// 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 I, typename N>
+ bool
+ is_simple_2d(const Image<I>& ima, const Neighborhood<N>& nbh, const
mln_psite(I)& p);
+
+
- bool is_simple_point(const image2d<bool>& ima, const neighb2d& nbh, const
point2d& p);
+ 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);
+ }
+ };
- unsigned nb_connexity2d(const image2d<bool>& ima, const neighb2d& nbh,
const point2d& p);
- bool is_curve_extremum(const image2d<bool>& ima, unsigned nbh, const
point2d& p);
# ifndef MLN_INCLUDE_ONLY
- static const unsigned char nb_connexity_c8[256] =
+ 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,
@@ -88,7 +100,7 @@
1, 2, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
};
- static const unsigned char nb_connexity_c4[256] =
+ static const unsigned char connectivity_number_c4[256] =
{
0, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, 1, 2, 2, 2, 1,
1, 2, 2, 2, 1, 2, 1, 1, 2, 2, 3, 2, 2, 2, 2, 1,
@@ -111,96 +123,57 @@
1, 2, 2, 2, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1
};
- neighb2d int_to_neighb(unsigned i)
- {
- if (i == 8)
- return c8();
- if (i == 4)
- return c4();
- mln_assertion(0);
- return c4();
- }
- unsigned complement_neighb(unsigned i)
+ 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)
{
- if (i == 8)
- return 4;
- if (i == 4)
- return 8;
- mln_assertion(0);
- return 0;
- }
+ const I& ima = exact(ima_);
+ const N& nbh = exact(nbh_);
- unsigned nb_connexity2d(const image2d<bool>& ima, unsigned nbh, const
point2d& p, bool object)
- {
unsigned res = 0;
- mln_bkd_niter_(neighb2d) n(c8() , p);
+ mln_bkd_niter(neighb2d) n(c8(), p);
for_all(n)
{
res = (res << 1);
- if (ima.domain().has(n) && ima(n) == object)
+ if (ima.domain().has(n) && ima(n) == b)
res = res | 1;
}
- if (nbh == 8)
- return nb_connexity_c8[res];
- else
- {
- mln_assertion(nbh == 4);
- return nb_connexity_c4[res];
- }
- }
-
- bool is_curve_extremum(const image2d<bool>& ima, unsigned nbh_i, const
point2d& p_, unsigned deep)
- {
-// return false;
- unsigned cpt = 0;
- mln_site_(image2d<bool>) next = p_;
- mln_site_(image2d<bool>) p = next;
- mln_niter_(neighb2d) n(int_to_neighb(nbh_i) , p);
+ unsigned number;
- p = next;
- for_all(n)
+ switch (nbh.size())
{
- if (ima.domain().has(n) && ima(n) == true)
- {
- next = n;
- cpt++;
- }
+ case 4:
+ number = connectivity_number_c4[res];
+ break;
+ case 8:
+ number = connectivity_number_c8[res];
+ break;
+ default:
+ mln_assertion(0);
}
- if (cpt != 1)
- return false;
- for (unsigned i = 0; i < deep - 1; i++)
- {
- cpt = 0;
- p = next;
- for_all(n)
- {
- if (ima.domain().has(n) && ima(n) == true)
- {
- next = n;
- cpt++;
- }
- }
- if (cpt != 2)
- return false;
+ return number;
}
- return true;
- }
- bool is_simple_point2d(const image2d<bool>& ima, unsigned nbh, const
point2d& p)
+ template<typename I, typename N>
+ inline
+ bool
+ is_simple_2d(const Image<I>& ima, const Neighborhood<N>& nbh_,
const mln_psite(I)& p)
{
- mln_assertion(nbh == 4 || nbh == 8);
-
- return (nb_connexity2d(ima, nbh, p, true) == 1) &&
- (nb_connexity2d(ima, complement_neighb(nbh), p, false) == 1);
+ 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
-#endif // ! MLN_SIMPLE_POINT_HH
+#endif // ! MLN_TOPO_IS_SIMPLE_2D_HH
Index: mln/win/multiple_size.hh
--- mln/win/multiple_size.hh (revision 2895)
+++ mln/win/multiple_size.hh (working copy)
@@ -159,8 +159,8 @@
mln_psite(W) compute_p_() const;
private:
- unsigned i_;
- unsigned size_() const;
+ int i_;
+ int size_() const;
};
@@ -321,7 +321,7 @@
bool
multiple_size_qiter<n,W,F>::is_valid_() const
{
- return i_ < size_();
+ return i_ != -1 && i_ < size_();
}
template <unsigned n, typename W, typename F>
@@ -329,7 +329,7 @@
void
multiple_size_qiter<n,W,F>::invalidate_()
{
- i_ = size_();
+ i_ = -1;
}
template <unsigned n, typename W, typename F>
@@ -358,10 +358,10 @@
template <unsigned n, typename W, typename F>
inline
- unsigned
+ int
multiple_size_qiter<n,W,F>::size_() const
{
- return this->s_->size_around(*this->c_);
+ return int(this->s_->size_around(*this->c_));
}
# endif // ! MLN_INCLUDE_ONLY
Index: mln/morpho/skeleton_constrained.hh
--- mln/morpho/skeleton_constrained.hh (revision 2893)
+++ mln/morpho/skeleton_constrained.hh (working copy)
@@ -1,4 +1,4 @@
-// Copyright (C) 2007, 2008 EPITA Research and Development Laboratory
+// Copyright (C) 2008 EPITA Research and Development Laboratory (LRDE)
//
// This file is part of the Olena Library. This library is free
// software; you can redistribute it and/or modify it under the terms
@@ -25,137 +25,97 @@
// reasons why the executable file might be covered by the GNU General
// Public License.
-#ifndef MLN_SKELETON_HH
-# define MLN_SKELETON_HH
+#ifndef MLN_MORPHO_SKELETON_CONSTRAINED_HH
+# define MLN_MORPHO_SKELETON_CONSTRAINED_HH
-# include <iomanip>
-# include <iostream>
-# include <sstream>
-
-# include <mln/core/var.hh>
-
-# include <mln/core/image/image2d.hh>
-# include <mln/core/image/cast_image.hh>
-# include <mln/core/alias/neighb2d.hh>
+/// \file mln/morpho/skeleton_constrained.hh
+///
+/// Compute a skeleton under constraints.
+
+# include <mln/core/concept/image.hh>
+# include <mln/core/concept/neighborhood.hh>
# include <mln/core/site_set/p_queue_fast.hh>
# include <mln/core/site_set/p_priority.hh>
-
-# include <mln/value/int_u8.hh>
-# include <mln/arith/revert.hh>
-# include <mln/transform/distance.hh>
-
-# include <mln/make/w_window2d_int.hh>
-
+# include <mln/extension/adjust_fill.hh>
# include <mln/level/fill.hh>
-# include <mln/debug/println.hh>
-
-# include <mln/logical/not.hh>
-
-# include "simple_point.hh"
-
-#include <mln/make/w_window2d_int.hh>
-
-# include <mln/io/pgm/save.hh>
-# include <mln/io/pbm/save.hh>
namespace mln
{
- template <typename V>
- void save_state(const image2d<V>& ima)
+ namespace morpho
{
- static int id = 0;
- std::stringstream filename;
- std::cout << id << std::endl;
- filename << "skel_trace_" << std::setw(5) <<
std::setfill('0')
- << std::right << id++ << ".ppm";
+ template <typename I,
+ typename N, typename F,
+ typename K, typename R>
+ mln_ch_value(I, bool)
+ skeleton_constrained(const Image<I>& input,
+ const Neighborhood<N>& nbh, const F& is_simple,
+ const Image<K>& constraint, const Image<R>& priority);
- io::pbm::save(ima, filename.str());
- }
- image2d<bool> crest(const image2d<bool>& input,
- const image2d<value::int_u8>& dist_map,
- const neighb2d& nbh)
- {
- image2d<bool> is_crest;
- initialize(is_crest, input);
- level::fill(is_crest, false);
- mln_piter_(image2d<bool>) p(input.domain());
- mln_niter_(neighb2d) n(nbh, p);
- for_all(p)
- {
- if (!input(p) || dist_map(p) < 0)
- continue;
+# ifndef MLN_INCLUDE_ONLY
- unsigned nb_eq = 0;
- unsigned nb_gt = 0;
- for_all(n)
- if (input.domain().has(n))
+ template <typename I,
+ typename N, typename F,
+ typename K, typename R>
+ inline
+ mln_ch_value(I, bool)
+ skeleton_constrained(const Image<I>& input_,
+ const Neighborhood<N>& nbh_, const F& is_simple,
+ const Image<K>& constraint_, const Image<R>& priority_)
{
- if (dist_map(n) == dist_map(p))
- nb_eq++;
- else if (dist_map(n) > dist_map(p))
- nb_gt++;
- }
-
- if ((nb_gt == 1 && nb_eq == 0) ||
- (nb_gt == 0))
- is_crest(p) = true;
- }
- return is_crest;
- }
+ const I& input = exact(input_);
+ const N& nbh = exact(nbh_);
+ const K& constraint = exact(constraint_);
+ const R& priority = exact(priority_);
+ extension::adjust_fill(input, nbh, false);
- image2d<bool>
- skeleton_with_constraint(const image2d<bool>& input,
- unsigned nbh_i,
- const image2d<bool>& K,
- const image2d<value::int_u8>& priority)
- {
- mln_assertion(nbh_i == 4 || nbh_i == 8);
+ // FIXME: Tests!
- neighb2d nbh = int_to_neighb(nbh_i);
- image2d<bool> output;
- initialize(output, input);
+ typedef mln_psite(I) P;
+ typedef p_queue_fast<P> Q;
+ p_priority<mln_value(R), Q> q;
- typedef mln_site_(image2d<bool>) P;
- p_priority<value::int_u8, p_queue_fast<P> > q;
+ mln_ch_value(I, bool) output;
// Initialization.
{
- p_priority<value::int_u8, p_queue_fast<P> > q_tmp;
-
+ initialize(output, input);
level::fill(output, input);
- mln_piter_(image2d<bool>) p(input.domain());
+
+ mln_piter(I) p(input.domain());
for_all(p)
- if (!input(p) &&
- is_simple_point2d(input, nbh_i, p)) // p is a simple point of background
+ if ( input(p) == false )
+// if ( input(p) == false &&
+// is_simple(input, nbh, p) ) // p is a simple point of the background.
+ {
q.push(priority(p), p);
+ // std::cout << "push " << p << std::endl;
+ }
}
+ // std::cout << std::endl << "propagation..." <<
std::endl;
+
// Propagation.
{
P p;
- mln_niter_(neighb2d) n(nbh, p);
+ mln_niter(N) n(nbh, p);
while (! q.is_empty())
{
p = q.pop_front();
-
for_all(n)
if (output.domain().has(n) &&
- output(n) &&
- K(n) == false &&
- is_simple_point2d(output, nbh_i, n)
- // && // n is simple
- // !is_curve_extremum(output, nbh_i, n, 1)
- )
+ output(n) == true &&
+ constraint(n) == false &&
+ is_simple(output, nbh, n) )
{
- output(n) = false; // Remove n from object
- // save_state(output);
+ output(n) = false; // Remove n from object.
q.push(priority(n), n);
+ // std::cout << "push " << n << std::endl;
}
}
}
@@ -163,32 +123,11 @@
return output;
}
+# endif // ! MLN_INCLUDE_ONLY
- image2d<bool>
- skeleton(const image2d<bool>& input, unsigned nbh_i)
- {
- mln_assertion(nbh_i == 4 || nbh_i == 8);
- neighb2d nbh = int_to_neighb(nbh_i);
-
- int vals[] = { 0, 9, 0, 9, 0,
- 9, 6, 4, 6, 9,
- 0, 4, 0, 4, 0, // Values of distances.
- 9, 6, 4, 6, 9,
- 0, 9, 0, 9, 0 };
-
- image2d<value::int_u8> dist_map_n = transform::distance(value::int_u8(),
logical::not_(input), nbh, make::w_window2d_int(vals));
- image2d<value::int_u8> dist_map = arith::revert(dist_map_n);
-
- io::pgm::save(dist_map, "distance.pgm");
- io::pgm::save(dist_map_n, "distance_n.pgm");
-
- // Make K
- image2d<bool> K = crest(input, dist_map_n, nbh);
- io::pbm::save(K, "K.pbm");
-
- return skeleton_with_constraint(input, nbh_i, K, dist_map);
- }
+ } // end of namespace mln::morpho
} // end of namespace mln
-#endif
+
+#endif // ! MLN_MORPHO_SKELETON_CONSTRAINED_HH
Index: img/small.pbm
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes on: img/small.pbm
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Index: img/fly.pbm
--- img/fly.pbm (revision 0)
+++ img/fly.pbm (revision 0)
@@ -0,0 +1,5 @@
+P4
+# CREATOR: XV version 3.10a-jumboFix+Enh of 20050501
+
+5 6
+����X�
\ No newline at end of file