* apps/generic-skel/image2d-skel-unconstrained.cc,
* apps/generic-skel/image2d-skel-with-end-points.cc,
* apps/generic-skel/image2d-skel.hh:
New.
* apps/generic-skel/test-image2d-skel-unconstrained.in,
* apps/generic-skel/test-image2d-skel-with-end-points.in:
New tests.
* apps/generic-skel/Makefile.am: New.
* apps/Makefile.am (SUBDIRS): Add generic-skel.
---
milena/ChangeLog | 14 ++
milena/apps/Makefile.am | 6 +-
milena/apps/generic-skel/Makefile.am | 54 ++++++
.../image2d-skel-unconstrained.cc} | 53 +++++--
.../image2d-skel-with-end-points.cc} | 52 +++++--
milena/apps/generic-skel/image2d-skel.hh | 174 ++++++++++++++++++++
.../test-image2d-skel-unconstrained.in} | 7 +-
.../test-image2d-skel-with-end-points.in} | 7 +-
8 files changed, 330 insertions(+), 37 deletions(-)
create mode 100644 milena/apps/generic-skel/Makefile.am
copy milena/apps/{mesh-segm-skel/off-to-vtk-bin.cc =>
generic-skel/image2d-skel-unconstrained.cc} (53%)
copy milena/apps/{mesh-segm-skel/off-to-vtk-bin.cc =>
generic-skel/image2d-skel-with-end-points.cc} (53%)
create mode 100644 milena/apps/generic-skel/image2d-skel.hh
copy milena/apps/{mesh-segm-skel/test-mesh-complex-2-collapse.in =>
generic-skel/test-image2d-skel-unconstrained.in} (71%)
copy milena/apps/{mesh-segm-skel/test-mesh-complex-2-collapse.in =>
generic-skel/test-image2d-skel-with-end-points.in} (70%)
diff --git a/milena/ChangeLog b/milena/ChangeLog
index f567ea8..16b07b7 100644
--- a/milena/ChangeLog
+++ b/milena/ChangeLog
@@ -1,3 +1,17 @@
+2010-08-20 Roland Levillain <roland(a)lrde.epita.fr>
+
+ New apps on generic skeletonization.
+
+ * apps/generic-skel/image2d-skel-unconstrained.cc,
+ * apps/generic-skel/image2d-skel-with-end-points.cc,
+ * apps/generic-skel/image2d-skel.hh:
+ New.
+ * apps/generic-skel/test-image2d-skel-unconstrained.in,
+ * apps/generic-skel/test-image2d-skel-with-end-points.in:
+ New tests.
+ * apps/generic-skel/Makefile.am: New.
+ * apps/Makefile.am (SUBDIRS): Add generic-skel.
+
2011-04-12 Roland Levillain <roland(a)lrde.epita.fr>
apps/graph-morpho: Catch up with current mln::topo::is_n_face.
diff --git a/milena/apps/Makefile.am b/milena/apps/Makefile.am
index c42ffd7..c15569b 100644
--- a/milena/apps/Makefile.am
+++ b/milena/apps/Makefile.am
@@ -1,4 +1,5 @@
-# Copyright (C) 2008, 2009 EPITA Research and Development Laboratory (LRDE).
+# Copyright (C) 2008, 2009, 2010 EPITA Research and Development
+# Laboratory (LRDE).
#
# This file is part of Olena.
#
@@ -13,10 +14,9 @@
#
# You should have received a copy of the GNU General Public License
# along with Olena. If not, see <http://www.gnu.org/licenses/>.
-#
# Applied examples of Milena.
-SUBDIRS = mesh-segm-skel graph-morpho constrained-connectivity
+SUBDIRS = mesh-segm-skel generic-skel graph-morpho constrained-connectivity
# Examples from papers.
SUBDIRS += papers
diff --git a/milena/apps/generic-skel/Makefile.am b/milena/apps/generic-skel/Makefile.am
new file mode 100644
index 0000000..5ae65f5
--- /dev/null
+++ b/milena/apps/generic-skel/Makefile.am
@@ -0,0 +1,54 @@
+# Copyright (C) 2010 EPITA Research and Development Laboratory (LRDE).
+#
+# This file is part of Olena.
+#
+# Olena is free software: you can redistribute it and/or modify it under
+# the terms of the GNU General Public License as published by the Free
+# Software Foundation, version 2 of the License.
+#
+# Olena 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 Olena. If not, see <http://www.gnu.org/licenses/>.
+
+# Find Milena and trimesh headers.
+AM_CPPFLAGS = -I$(top_srcdir)/milena
+# Produce fast code.
+APPS_CXXFLAGS = @APPS_CXXFLAGS@
+AM_CXXFLAGS = $(APPS_CXXFLAGS)
+
+
+bin_PROGRAMS = image2d-skel-unconstrained image2d-skel-with-end-points
+image2d_skel_unconstrained_SOURCES = image2d-skel-unconstrained.cc image2d-skel.hh
+image2d_skel_with_end_points_SOURCES = image2d-skel-with-end-points.cc image2d-skel.hh
+
+EXTRA_DIST = test-image2d-skel-unconstrained.in test-image2d-skel-with-end-points.in
+
+# Use Make to generate Doxyfile instead of `configure', as advised by
+# Autoconf's manual (see section ``Installation Directory
+# Variables'').
+edit = sed -e 's|@top_srcdir[@]|$(top_srcdir)|g'
+
+test-image2d-skel-unconstrained test-image2d-skel-with-end-points: Makefile
+ rm -f $@ $@.tmp
+ srcdir=''; \
+ test -f ./$@.in || srcdir=$(srcdir)/; \
+ $(edit) $${srcdir}$@.in >$@.tmp
+ chmod +x $@.tmp
+ chmod a-w $@.tmp
+ mv $@.tmp $@
+
+test-image2d-skel-unconstrained: $(srcdir)/test-image2d-skel-unconstrained.in
+test-image2d-skel-with-end-points: $(srcdir)/test-image2d-skel-with-end-points.in
+
+TESTS = test-image2d-skel-unconstrained test-image2d-skel-with-end-points
+CLEANFILES = test-image2d-skel-unconstrained test-image2d-skel-with-end-points
+
+MOSTLYCLEANFILES = \
+ picasso-skel-unconstrained.pbm \
+ picasso-skel-with-end-points.pbm \
+ tiny-skel-unconstrained.pbm \
+ tiny-skel-with-end-points.pbm
diff --git a/milena/apps/mesh-segm-skel/off-to-vtk-bin.cc
b/milena/apps/generic-skel/image2d-skel-unconstrained.cc
similarity index 53%
copy from milena/apps/mesh-segm-skel/off-to-vtk-bin.cc
copy to milena/apps/generic-skel/image2d-skel-unconstrained.cc
index 926da7d..4459ba4 100644
--- a/milena/apps/mesh-segm-skel/off-to-vtk-bin.cc
+++ b/milena/apps/generic-skel/image2d-skel-unconstrained.cc
@@ -1,4 +1,4 @@
-// Copyright (C) 2011 EPITA Research and Development Laboratory (LRDE)
+// Copyright (C) 2010 EPITA Research and Development Laboratory (LRDE)
//
// This file is part of the Milena Library. This library is free
// software; you can redistribute it and/or modify it under the terms
@@ -26,22 +26,26 @@
// Public License.
/// \file
+/// \brief A program computing an unconstrained skeleton of a 2D image.
-/// \brief A program converting a binary OFF file (e.g. no value
-/// attached to faces) into a VTK file.
+#include <mln/core/image/image2d.hh>
+#include <mln/core/alias/neighb2d.hh>
-#include <iostream>
+#include <mln/topo/skeleton/breadth_first_thinning.hh>
-#include <mln/io/off/load.hh>
-#include <mln/io/vtk/save.hh>
+#include <mln/io/pbm/all.hh>
+
+#include "image2d-skel.hh"
int
main(int argc, char* argv[])
{
+ using namespace mln;
+
if (argc != 3)
{
- std::cerr << "usage: " << argv[0] << " input.off
output.vtk"
+ std::cerr << "usage: " << argv[0] << " input.pbm
output.pbm"
<< std::endl;
std::exit(1);
}
@@ -49,12 +53,33 @@ main(int argc, char* argv[])
std::string input_filename = argv[1];
std::string output_filename = argv[2];
- typedef mln::bin_2complex_image3df ima_t;
- ima_t ima;
+ typedef image2d<bool> I;
+ typedef neighb2d N;
+
+ // Add a border of (at least) 1 pixel, to a guarantee a meaningful
+ // result of the computation of connectivity numbers (called within
+ // is_simple_2d); indeed, this computation always expects each pixel
+ // to have 8 neighboring sites.
+ border::thickness = 1;
+
+ I input = io::pbm::load(input_filename);
+
+ // FIXME: Use a dual neighborhood instead?
+
+ // Foreground neighborhood.
+ neighb2d nbh_fg = c4();
+ // Background neighborhood.
+ neighb2d nbh_bg = c8();
+
+ // Simplicity criterion functor.
+ ::is_simple_2d<I, N> is_simple(nbh_fg, nbh_bg);
+ // Detach procedure.
+ ::detach<I> detach;
+ // (Lack of) constraint.
+ fun::p2b::tautology constraint;
- // FIXME: Converting bunny-holefilled.off to VTK took 30 sec, which
- // is awfully slow. Time the load and save operations and find
- // where is (are) the issue(s).
- mln::io::off::load(ima, input_filename);
- mln::io::vtk::save(ima, output_filename);
+ I output = topo::skeleton::breadth_first_thinning(input, nbh_fg,
+ is_simple, detach,
+ constraint);
+ io::pbm::save(output, output_filename);
}
diff --git a/milena/apps/mesh-segm-skel/off-to-vtk-bin.cc
b/milena/apps/generic-skel/image2d-skel-with-end-points.cc
similarity index 53%
copy from milena/apps/mesh-segm-skel/off-to-vtk-bin.cc
copy to milena/apps/generic-skel/image2d-skel-with-end-points.cc
index 926da7d..604b065 100644
--- a/milena/apps/mesh-segm-skel/off-to-vtk-bin.cc
+++ b/milena/apps/generic-skel/image2d-skel-with-end-points.cc
@@ -1,4 +1,4 @@
-// Copyright (C) 2011 EPITA Research and Development Laboratory (LRDE)
+// Copyright (C) 2010 EPITA Research and Development Laboratory (LRDE)
//
// This file is part of the Milena Library. This library is free
// software; you can redistribute it and/or modify it under the terms
@@ -26,22 +26,27 @@
// Public License.
/// \file
+/// \brief A program computing a skeleton of a 2D image, preserving
+/// end points.
-/// \brief A program converting a binary OFF file (e.g. no value
-/// attached to faces) into a VTK file.
+#include <mln/core/image/image2d.hh>
+#include <mln/core/alias/neighb2d.hh>
-#include <iostream>
+#include <mln/topo/skeleton/breadth_first_thinning.hh>
-#include <mln/io/off/load.hh>
-#include <mln/io/vtk/save.hh>
+#include <mln/io/pbm/all.hh>
+
+#include "image2d-skel.hh"
int
main(int argc, char* argv[])
{
+ using namespace mln;
+
if (argc != 3)
{
- std::cerr << "usage: " << argv[0] << " input.off
output.vtk"
+ std::cerr << "usage: " << argv[0] << " input.pbm
output.pbm"
<< std::endl;
std::exit(1);
}
@@ -49,12 +54,31 @@ main(int argc, char* argv[])
std::string input_filename = argv[1];
std::string output_filename = argv[2];
- typedef mln::bin_2complex_image3df ima_t;
- ima_t ima;
+ typedef image2d<bool> I;
+ typedef neighb2d N;
+
+ // Add a border of (at least) 1 pixel, to a guarantee a meaningful
+ // result of the computation of connectivity numbers (called within
+ // is_simple_2d); indeed, this computation always expects each pixel
+ // to have 8 neighboring sites.
+ border::thickness = 1;
+
+ I input = io::pbm::load(input_filename);
+
+ // Foreground neighborhood.
+ neighb2d nbh_fg = c4();
+ // Background neighborhood.
+ neighb2d nbh_bg = c8();
+
+ // Simplicity criterion functor.
+ ::is_simple_2d<I, N> is_simple(nbh_fg, nbh_bg);
+ // Detach procedure.
+ ::detach<I> detach;
+ // Constraint: do not remove end points.
+ is_not_end_point<I, N> constraint(nbh_fg, input);
- // FIXME: Converting bunny-holefilled.off to VTK took 30 sec, which
- // is awfully slow. Time the load and save operations and find
- // where is (are) the issue(s).
- mln::io::off::load(ima, input_filename);
- mln::io::vtk::save(ima, output_filename);
+ I output = topo::skeleton::breadth_first_thinning(input, nbh_fg,
+ is_simple, detach,
+ constraint);
+ io::pbm::save(output, output_filename);
}
diff --git a/milena/apps/generic-skel/image2d-skel.hh
b/milena/apps/generic-skel/image2d-skel.hh
new file mode 100644
index 0000000..6cd8c50
--- /dev/null
+++ b/milena/apps/generic-skel/image2d-skel.hh
@@ -0,0 +1,174 @@
+// Copyright (C) 2010 EPITA Research and Development Laboratory (LRDE)
+//
+// This file is part of the Milena 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 APPS_GENERIC_SKEL_IMAGE2D_SKEL_HH
+# define APPS_GENERIC_SKEL_IMAGE2D_SKEL_HH
+
+/// \file
+/// \brief Definitions for a simplicity criterion and a constraint
+/// to be used in the breadth-first thinning of a 2D regular image.
+
+# include <mln/topo/is_simple_2d.hh>
+
+
+// FIXME: Split this file?
+
+
+/** \brief An equivalent (for mln::image2d) of the
+ mln::topo::is_simple_cell functor, based on the mask-based
+ criterion mln::topo::is_simple_2d.
+
+ This functor acts as an adapter, since mln::topo::is_simple_2d
+ does not fit (yet) in the canvas of
+ mln::topo::skeleton::breadth_first_thinning. Moreover, this code
+ is a bit easier to read since it does not make use of a dual
+ neighborhood (having a long and complex type). */
+template <typename I, typename N>
+class is_simple_2d : public mln::Function_v2b< is_simple_2d<I, N> >
+{
+public:
+ /// Result type of the functor.
+ typedef bool result;
+
+ /// Build a functor.
+ ///
+ /// \param nbh_fg The foreground neighborhood.
+ /// \param nbh_bg The background neighborhood.
+ is_simple_2d(const mln::Neighborhood<N>& nbh_fg,
+ const mln::Neighborhood<N>& nbh_bg)
+ : nbh_fg_(mln::exact(nbh_fg)), nbh_bg_(mln::exact(nbh_bg)),
+ ima_(0)
+ {
+ }
+
+ /// Build a functor, and assign an image to it.
+ ///
+ /// \param nbh_fg The foreground neighborhood.
+ /// \param nbh_bg The background neighborhood.
+ /// \apram ima The image.
+ is_simple_2d(const mln::Neighborhood<N>& nbh_fg,
+ const mln::Neighborhood<N>& nbh_bg,
+ const mln::Image<I>& ima)
+ : nbh_fg_(mln::exact(nbh_fg)), nbh_bg_(mln::exact(nbh_bg)),
+ ima_(mln::exact(&ima))
+ {
+ }
+
+ /// Set the underlying image.
+ void set_image(const mln::Image<I>& ima)
+ {
+ ima_ = mln::exact(&ima);
+ }
+
+ /// Based on connectivity numbers.
+ bool operator()(const mln_psite(I)& p) const
+ {
+ return
+ mln::connectivity_number_2d(*ima_, nbh_fg_, p, true ) == 1 &&
+ mln::connectivity_number_2d(*ima_, nbh_bg_, p, false) == 1;
+ }
+
+private:
+ /// The foreground neighborhood.
+ const N& nbh_fg_;
+ /// The background neighborhood.
+ const N& nbh_bg_;
+ /// The image.
+ const I* ima_;
+};
+
+
+template <typename I>
+class detach
+{
+public:
+ /// Build a functor.
+ detach()
+ : ima_(0)
+ {
+ }
+
+ /// Build a functor, and assign an image to it.
+ ///
+ /// \apram ima The image.
+ detach(mln::Image<I>& ima)
+ : ima_(mln::exact(&ima))
+ {
+ }
+
+ /// Set the underlying image.
+ void set_image(mln::Image<I>& ima)
+ {
+ ima_ = mln::exact(&ima);
+ }
+
+ void operator()(const mln_psite(I)& p) const
+ {
+ (*ima_)(p) = false;
+ }
+
+private:
+ /// The image.
+ I* ima_;
+};
+
+
+template <typename I, typename N>
+struct is_not_end_point : public mln::Function_v2b< is_not_end_point<I, N> >
+{
+ /// Build a functor, and assign an image to it.
+ ///
+ /// \param nbh_fg The foreground neighborhood.
+ /// \apram ima The image.
+ is_not_end_point(const mln::Neighborhood<N>& nbh,
+ const mln::Image<I>& ima)
+ : nbh_(mln::exact(nbh)),
+ ima_(mln::exact(ima))
+ {
+ }
+
+ // Is \a p not a end point?
+ bool operator()(const mln_psite(I)& p) const
+ {
+ // Number of foreground neighbors pixels.
+ unsigned nneighbs = 0;
+ mln_niter(N) n(nbh_, p);
+ for_all(n)
+ if (ima_.has(n) && ima_(n))
+ ++nneighbs;
+ return nneighbs != 1;
+ }
+
+private:
+ /// The foreground neighborhood.
+ const N& nbh_;
+ /// The image.
+ const I& ima_;
+};
+
+
+#endif // ! APPS_GENERIC_SKEL_IMAGE2D_SKEL_HH
diff --git a/milena/apps/mesh-segm-skel/test-mesh-complex-2-collapse.in
b/milena/apps/generic-skel/test-image2d-skel-unconstrained.in
similarity index 71%
copy from milena/apps/mesh-segm-skel/test-mesh-complex-2-collapse.in
copy to milena/apps/generic-skel/test-image2d-skel-unconstrained.in
index d2a286b..b9f6b44 100644
--- a/milena/apps/mesh-segm-skel/test-mesh-complex-2-collapse.in
+++ b/milena/apps/generic-skel/test-image2d-skel-unconstrained.in
@@ -1,6 +1,6 @@
#! /bin/sh
-# Copyright (C) 2011 EPITA Research and Development Laboratory (LRDE).
+# Copyright (C) 2010 EPITA Research and Development Laboratory (LRDE).
#
# This file is part of Olena.
#
@@ -18,6 +18,7 @@
set -ex
-mesh_dir=@top_srcdir@/milena/mesh
+img_dir=@top_srcdir@/milena/img
-time ./mesh-complex-2-collapse $mesh_dir/pseudo-manifold.vtk
pseudo-manifold-2-collapse.vtk
+./image2d-skel-unconstrained $img_dir/tiny.pbm tiny-skel-unconstrained.pbm
+./image2d-skel-unconstrained $img_dir/picasso.pbm picasso-skel-unconstrained.pbm
diff --git a/milena/apps/mesh-segm-skel/test-mesh-complex-2-collapse.in
b/milena/apps/generic-skel/test-image2d-skel-with-end-points.in
similarity index 70%
copy from milena/apps/mesh-segm-skel/test-mesh-complex-2-collapse.in
copy to milena/apps/generic-skel/test-image2d-skel-with-end-points.in
index d2a286b..946e8fd 100644
--- a/milena/apps/mesh-segm-skel/test-mesh-complex-2-collapse.in
+++ b/milena/apps/generic-skel/test-image2d-skel-with-end-points.in
@@ -1,6 +1,6 @@
#! /bin/sh
-# Copyright (C) 2011 EPITA Research and Development Laboratory (LRDE).
+# Copyright (C) 2010 EPITA Research and Development Laboratory (LRDE).
#
# This file is part of Olena.
#
@@ -18,6 +18,7 @@
set -ex
-mesh_dir=@top_srcdir@/milena/mesh
+img_dir=@top_srcdir@/milena/img
-time ./mesh-complex-2-collapse $mesh_dir/pseudo-manifold.vtk
pseudo-manifold-2-collapse.vtk
+./image2d-skel-with-end-points $img_dir/tiny.pbm tiny-skel-with-end-points.pbm
+./image2d-skel-with-end-points $img_dir/picasso.pbm picasso-skel-with-end-points.pbm
--
1.5.6.5