* apps/morphers/recorder-bft.cc: New.
* apps/morphers/image2d-skel.hh: New.
* apps/morphers/Makefile.am (noinst_PROGRAMS): Add recorder-bft.
(recorder_wst_SOURCES): New.
(recorder_SOURCES, recorder_wst_SOURCES, mask_recorder_SOURCES):
Move recorder.hh...
(noinst_HEADERS): ...here (new variable).
(MOSTLYCLEANFILES): Add lena-bft??????.pbm.
---
milena/ChangeLog | 13 +++
milena/apps/morphers/Makefile.am | 11 ++-
milena/apps/morphers/image2d-skel.hh | 137 ++++++++++++++++++++++++++++++++++
milena/apps/morphers/recorder-bft.cc | 114 ++++++++++++++++++++++++++++
4 files changed, 272 insertions(+), 3 deletions(-)
create mode 100644 milena/apps/morphers/image2d-skel.hh
create mode 100644 milena/apps/morphers/recorder-bft.cc
diff --git a/milena/ChangeLog b/milena/ChangeLog
index 2b98497..5d791e6 100644
--- a/milena/ChangeLog
+++ b/milena/ChangeLog
@@ -1,3 +1,16 @@
+2011-11-28 Roland Levillain <roland(a)lrde.epita.fr>
+
+ New morpher example: recording a breadth-first thinning.
+
+ * apps/morphers/recorder-bft.cc: New.
+ * apps/morphers/image2d-skel.hh: New.
+ * apps/morphers/Makefile.am (noinst_PROGRAMS): Add recorder-bft.
+ (recorder_wst_SOURCES): New.
+ (recorder_SOURCES, recorder_wst_SOURCES, mask_recorder_SOURCES):
+ Move recorder.hh...
+ (noinst_HEADERS): ...here (new variable).
+ (MOSTLYCLEANFILES): Add lena-bft??????.pbm.
+
2011-11-24 Roland Levillain <roland(a)lrde.epita.fr>
New morpher example: recording a watershed transform.
diff --git a/milena/apps/morphers/Makefile.am b/milena/apps/morphers/Makefile.am
index a3b9a41..8633933 100644
--- a/milena/apps/morphers/Makefile.am
+++ b/milena/apps/morphers/Makefile.am
@@ -25,17 +25,22 @@ AM_CXXFLAGS = $(APPS_CXXFLAGS)
noinst_PROGRAMS = \
mask+channel \
recorder \
+ recorder-bft \
recorder-wst \
mask+recorder
+noinst_HEADERS = recorder.hh
+
mask_channel_SOURCES = mask+channel.cc
-recorder_SOURCES = recorder.cc recorder.hh
-recorder_wst_SOURCES = recorder-wst.cc recorder.hh
-mask_recorder_SOURCES = mask+recorder.cc recorder.hh
+recorder_SOURCES = recorder.cc
+recorder_bft_SOURCES = recorder-bft.cc image2d-skel.hh
+recorder_wst_SOURCES = recorder-wst.cc
+mask_recorder_SOURCES = mask+recorder.cc
MOSTLYCLEANFILES = \
lena-mask-channel.ppm \
lena-fill??????.ppm \
+ lena-bft??????.pbm \
lena-wst??????.ppm \
lena-roi-fill??????.ppm
diff --git a/milena/apps/morphers/image2d-skel.hh b/milena/apps/morphers/image2d-skel.hh
new file mode 100644
index 0000000..392122c
--- /dev/null
+++ b/milena/apps/morphers/image2d-skel.hh
@@ -0,0 +1,137 @@
+// Copyright (C) 2010, 2011 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/>.
+//
+// As a special exception, you may use this file as part of a free
+// software project 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_MORPHERS_IMAGE2D_SKEL_HH
+# define APPS_MORPHERS_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.
+
+/* FIXME: Remove this file as soon as patches from the mesh-segm-skel
+ branch have been merged into the current branch. */
+
+# include <mln/topo/is_simple_2d.hh>
+
+
+/** \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_t
+ does not fit (yet) in the canvas of
+ mln::topo::skeleton::breadth_first_thinning. */
+template <typename I, typename N>
+class is_simple_2d : public mln::Function_v2b< is_simple_2d<I, N> >,
+ private mln::topo::is_simple_2d_t<N>
+{
+public:
+ typedef mln::topo::is_simple_2d_t<N> super;
+
+ /// 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)
+ : super(mln::exact(nbh_fg)),
+ 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::Image<I>& ima)
+ : super(mln::exact(nbh_fg)),
+ 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 check(*ima_, p);
+ }
+
+private:
+ /// The image.
+ const I* ima_;
+};
+
+
+template <typename I>
+void
+detach(const mln_psite(I)& p, mln::Image<I>& ima)
+{
+ mln::exact(ima)(p) = false;
+}
+
+
+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_MORPHERS_IMAGE2D_SKEL_HH
diff --git a/milena/apps/morphers/recorder-bft.cc b/milena/apps/morphers/recorder-bft.cc
new file mode 100644
index 0000000..5ca0e9e
--- /dev/null
+++ b/milena/apps/morphers/recorder-bft.cc
@@ -0,0 +1,114 @@
+// Copyright (C) 2011 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/>.
+//
+// As a special exception, you may use this file as part of a free
+// software project 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
+/// \brief Exercise a morpher recording every change in the morphed
+/// image with the breadth-first thinning.
+///
+/// To produce an AVI movie from the `lena-bft*.pbm' files, use:
+///
+/// for f in lena-bft*pbm; convert $f -define png:bit-depth=8 -scale 2500% $(basename
$f .pbm).png
+/// mencoder "mf://lena-bft*.png" -o lena-bft.avi -ovc lavc -lavcopts
gray:vcodec=mjpeg
+///
+/// Note: the `-define png:bit-depth=8' option prevents convert from
+/// creating an image with 1-bit channels (since the image is binary)
+/// and forces it to use 8-bit channels. Indeed mencoder is unable to
+/// process PNG images with 1-bit channel(s).
+///
+/// The output `lena-bft.avi' can be embedded in a PDF file. */
+
+/* FIXME: Modernize this program as soon as patches from the
+ mesh-segm-skel branch have been merged into the current branch. */
+
+#include <string>
+
+#include <mln/core/image/image2d.hh>
+#include <mln/core/alias/neighb2d.hh>
+
+#include <mln/win/multiple_size.hh>
+#include <mln/make/dual_neighb.hh>
+
+#include <mln/data/compare.hh>
+
+#include <mln/topo/skeleton/breadth_first_thinning.hh>
+
+#include <mln/test/predicate.hh>
+#include <mln/pw/value.hh>
+
+#include <mln/labeling/colorize.hh>
+
+#include <mln/io/pbm/load.hh>
+#include <mln/io/pbm/save.hh>
+
+#include "apps/morphers/recorder.hh"
+/* FIXME: Temporarily reuse an old file from apps/generic-skel instead
+ of newer files integrated into the library (but not merged in). */
+#include "apps/morphers/image2d-skel.hh"
+
+#include "apps/data.hh"
+
+
+int main()
+{
+ using namespace mln;
+
+ typedef image2d<bool> I;
+ I lena = io::pbm::load(MLN_IMG_DIR "/tiny.pbm");
+ // Attach recorder to input image.
+ typedef decorated_image< I, recorder<I> > J;
+ J lena_rec = record(lena);
+
+ // Dual neighborhood.
+ typedef neighb< win::multiple_size<2, window2d, pw::value_<I> > > N;
+ N nbh = make::dual_neighb(lena, c4(), c8());
+ // Simplicity criterion functor.
+ ::is_simple_2d<J, N> is_simple(nbh);
+ // Constraint.
+ ::is_not_end_point<J, neighb2d> constraint(c4(), lena_rec);
+
+ J bft_rec = topo::skeleton::breadth_first_thinning(lena_rec, nbh,
+ is_simple, ::detach<J>,
+ constraint);
+
+ // Dump recorded frames.
+ /* FIXME: Hand-made (it partly duplicates ppm::save() (or more
+ precisely pbm::save()) for decorated_image's). We should be able
+ to process sequences of images. */
+ bool output_initialized_p = false;
+ for (size_t i = 0; i < bft_rec.decoration().sequence.size(); ++i)
+ {
+ I frame = bft_rec.decoration().sequence[i];
+
+ // Skip frames until the inital image has been seen.
+ if (frame == lena)
+ output_initialized_p = true;
+ if (!output_initialized_p)
+ continue;
+
+ std::stringstream s;
+ s << std::setfill ('0') << std::setw (6) << i;
+ io::pbm::save(frame, std::string("lena-bft") + s.str() +
".pbm");
+ }
+}
--
1.7.2.5