* mln/topo/is_not_end_point.hh: s/nbh/nbh_fg/. (is_not_end_point<I, N>::is_not_end_point(const Neighborhood<N>&)): New ctor. (is_not_end_point<I, N>::set_image): New method. (is_not_end_point<I, N>::ima_): Turn this reference into a pointer. Adjust. * mln/topo/is_simple_point2d.hh (mln::topo::is_simple_point2d<I, N>::operator()) * mln/topo/detach_point.hh (mln::topo::detach_point<I>::operator()): Add preconditions. * apps/generic-skel/image2d-skel-with-end-points.cc: Use `mln::topo::is_simple_point2d' and `mln:: topo::detach_point' from mln/topo/, instead of `is_simple_2d' and `detach' from image2d-skel.hh * apps/generic-skel/image2d-skel-unconstrained.cc: Likewise. Remove the (lack of) constraint, as mln::topo::skeleton::breadth_first_thinning already takes care of this. * apps/generic-skel/image2d-skel.hh: Remove. * apps/generic-skel/Makefile.am (image2d_skel_unconstrained_SOURCES) (image2d_skel_with_end_points_SOURCES): Remove image2d-skel.hh. --- milena/ChangeLog | 29 ++++ milena/apps/generic-skel/Makefile.am | 4 +- .../generic-skel/image2d-skel-unconstrained.cc | 19 +- .../generic-skel/image2d-skel-with-end-points.cc | 14 +- milena/apps/generic-skel/image2d-skel.hh | 174 -------------------- milena/mln/topo/detach_point.hh | 1 + milena/mln/topo/is_not_end_point.hh | 42 ++++- milena/mln/topo/is_simple_point2d.hh | 1 + 8 files changed, 84 insertions(+), 200 deletions(-) delete mode 100644 milena/apps/generic-skel/image2d-skel.hh diff --git a/milena/ChangeLog b/milena/ChangeLog index 95a51a4..d5db5e7 100644 --- a/milena/ChangeLog +++ b/milena/ChangeLog @@ -1,5 +1,34 @@ 2011-07-13 Roland Levillain <roland@lrde.epita.fr> + Factor code of 2D skeletonizations in apps/generic-skel/. + + * mln/topo/is_not_end_point.hh: s/nbh/nbh_fg/. + (is_not_end_point<I, N>::is_not_end_point(const Neighborhood<N>&)): + New ctor. + (is_not_end_point<I, N>::set_image): New method. + (is_not_end_point<I, N>::ima_): Turn this reference into a pointer. + Adjust. + * mln/topo/is_simple_point2d.hh + (mln::topo::is_simple_point2d<I, N>::operator()) + * mln/topo/detach_point.hh + (mln::topo::detach_point<I>::operator()): + Add preconditions. + * apps/generic-skel/image2d-skel-with-end-points.cc: + Use `mln::topo::is_simple_point2d' and `mln:: topo::detach_point' + from mln/topo/, instead of `is_simple_2d' and `detach' from + image2d-skel.hh + * apps/generic-skel/image2d-skel-unconstrained.cc: Likewise. + Remove the (lack of) constraint, as + mln::topo::skeleton::breadth_first_thinning already takes care of + this. + * apps/generic-skel/image2d-skel.hh: Remove. + * apps/generic-skel/Makefile.am + (image2d_skel_unconstrained_SOURCES) + (image2d_skel_with_end_points_SOURCES): + Remove image2d-skel.hh. + +2011-07-13 Roland Levillain <roland@lrde.epita.fr> + Misc changes in apps/generic-skel/ and tools/. * apps/generic-skel/image3d-skel-unconstrained.cc: diff --git a/milena/apps/generic-skel/Makefile.am b/milena/apps/generic-skel/Makefile.am index 961fef2..fd9febc 100644 --- a/milena/apps/generic-skel/Makefile.am +++ b/milena/apps/generic-skel/Makefile.am @@ -33,8 +33,8 @@ bin_PROGRAMS = \ image3d-skel-with-1d-isthmuses # 2D cases. -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 +image2d_skel_unconstrained_SOURCES = image2d-skel-unconstrained.cc +image2d_skel_with_end_points_SOURCES = image2d-skel-with-end-points.cc # 3D cases, slow versions. noinst_HEADERS = image3d-skel.hh diff --git a/milena/apps/generic-skel/image2d-skel-unconstrained.cc b/milena/apps/generic-skel/image2d-skel-unconstrained.cc index 4459ba4..7a33334 100644 --- a/milena/apps/generic-skel/image2d-skel-unconstrained.cc +++ b/milena/apps/generic-skel/image2d-skel-unconstrained.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 the Milena Library. This library is free // software; you can redistribute it and/or modify it under the terms @@ -33,9 +33,10 @@ #include <mln/topo/skeleton/breadth_first_thinning.hh> -#include <mln/io/pbm/all.hh> +#include <mln/topo/is_simple_point2d.hh> +#include <mln/topo/detach_point.hh> -#include "image2d-skel.hh" +#include <mln/io/pbm/all.hh> int @@ -72,14 +73,12 @@ main(int argc, char* argv[]) 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; + 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, detach, - constraint); + is_simple, + detach); io::pbm::save(output, output_filename); } diff --git a/milena/apps/generic-skel/image2d-skel-with-end-points.cc b/milena/apps/generic-skel/image2d-skel-with-end-points.cc index 604b065..d22f281 100644 --- a/milena/apps/generic-skel/image2d-skel-with-end-points.cc +++ b/milena/apps/generic-skel/image2d-skel-with-end-points.cc @@ -34,9 +34,11 @@ #include <mln/topo/skeleton/breadth_first_thinning.hh> -#include <mln/io/pbm/all.hh> +#include <mln/topo/is_simple_point2d.hh> +#include <mln/topo/detach_point.hh> +#include <mln/topo/is_not_end_point.hh> -#include "image2d-skel.hh" +#include <mln/io/pbm/all.hh> int @@ -71,11 +73,11 @@ main(int argc, char* argv[]) neighb2d nbh_bg = c8(); // Simplicity criterion functor. - ::is_simple_2d<I, N> is_simple(nbh_fg, nbh_bg); - // Detach procedure. - ::detach<I> detach; + topo::is_simple_point2d<I, N> is_simple(nbh_fg, nbh_bg); + // Simple point detach procedure. + topo::detach_point<I> detach; // Constraint: do not remove end points. - is_not_end_point<I, N> constraint(nbh_fg, input); + topo::is_not_end_point<I, N> constraint(nbh_fg, input); I output = topo::skeleton::breadth_first_thinning(input, nbh_fg, is_simple, detach, diff --git a/milena/apps/generic-skel/image2d-skel.hh b/milena/apps/generic-skel/image2d-skel.hh deleted file mode 100644 index 6cd8c50..0000000 --- a/milena/apps/generic-skel/image2d-skel.hh +++ /dev/null @@ -1,174 +0,0 @@ -// 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/mln/topo/detach_point.hh b/milena/mln/topo/detach_point.hh index 6e4d22d..c361e11 100644 --- a/milena/mln/topo/detach_point.hh +++ b/milena/mln/topo/detach_point.hh @@ -101,6 +101,7 @@ namespace mln void detach_point<I>::operator()(const mln_psite(I)& p) const { + mln_precondition(ima_); (*ima_)(p) = false; } diff --git a/milena/mln/topo/is_not_end_point.hh b/milena/mln/topo/is_not_end_point.hh index 62561fa..f958a59 100644 --- a/milena/mln/topo/is_not_end_point.hh +++ b/milena/mln/topo/is_not_end_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 the Milena Library. This library is free // software; you can redistribute it and/or modify it under the terms @@ -45,20 +45,28 @@ namespace mln template <typename I, typename N> struct is_not_end_point : public Function_v2b< is_not_end_point<I, N> > { + /// Build a functor. + /// + /// \param nbh The (foreground) neighborhood. + is_not_end_point(const Neighborhood<N>& nbh); + /// Build a functor, and assign an image to it. /// - /// \param nbh_fg The foreground neighborhood. - /// \apram ima The image. + /// \param nbh The (foreground) neighborhood. + /// \apram ima The image. is_not_end_point(const Neighborhood<N>& nbh, const Image<I>& ima); - // Is \a p not an end point? + /// Set the underlying image. + void set_image(const Image<I>& ima); + + /// Is \a p not an end point? bool operator()(const mln_psite(I)& p) const; private: - /// The foreground neighborhood. + /// The (foreground) neighborhood. const N& nbh_; /// The image. - const I& ima_; + const I* ima_; }; @@ -67,11 +75,27 @@ namespace mln template <typename I, typename N> inline + is_not_end_point<I, N>::is_not_end_point(const Neighborhood<N>& nbh) + : nbh_(exact(nbh)), + ima_(0) + { + } + + template <typename I, typename N> + inline is_not_end_point<I, N>::is_not_end_point(const Neighborhood<N>& nbh, const Image<I>& ima) : nbh_(exact(nbh)), - ima_(exact(ima)) + ima_(exact(&ima)) + { + } + + template <typename I, typename N> + inline + void + is_not_end_point<I, N>::set_image(const Image<I>& ima) { + ima_ = exact(&ima); } template <typename I, typename N> @@ -79,11 +103,13 @@ namespace mln bool is_not_end_point<I, N>::operator()(const mln_psite(I)& p) const { + mln_precondition(ima_); + const I& ima = *ima_; // Number of foreground neighbors pixels. unsigned nneighbs = 0; mln_niter(N) n(nbh_, p); for_all(n) - if (ima_.has(n) && ima_(n)) + if (ima.has(n) && ima(n)) ++nneighbs; return nneighbs != 1; } diff --git a/milena/mln/topo/is_simple_point2d.hh b/milena/mln/topo/is_simple_point2d.hh index 8d0d7dd..1f9683c 100644 --- a/milena/mln/topo/is_simple_point2d.hh +++ b/milena/mln/topo/is_simple_point2d.hh @@ -126,6 +126,7 @@ namespace mln bool is_simple_point2d<I, N>::operator()(const mln_psite(I)& p) const { + mln_precondition(ima_); return connectivity_number_2d(*ima_, nbh_fg_, p, true ) == 1 && connectivity_number_2d(*ima_, nbh_bg_, p, false) == 1; -- 1.7.2.5