breadth_first_thinning.hh 6.19 KB
Newer Older
1
// Copyright (C) 2009, 2010, 2011, 2013 EPITA Research and Development
2
// Laboratory (LRDE)
3
//
4
// This file is part of Olena.
5
//
6
7
8
9
10
// 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,
11
12
13
14
15
// 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
16
// along with Olena.  If not, see <http://www.gnu.org/licenses/>.
17
18
//
// As a special exception, you may use this file as part of a free
19
// software project without restriction.  Specifically, if other files
20
// instantiate templates or use macros or inline functions from this
21
22
23
24
25
// 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.
26
27
28
29

#ifndef MLN_TOPO_SKELETON_BREADTH_FIRST_THINNING_HH
# define MLN_TOPO_SKELETON_BREADTH_FIRST_THINNING_HH

30
/// \file
31
32
/// \brief Computing a skeleton by using breadth-first thinning on a
/// binary image.
33
34
35
36
37
///
/// Careful: The meaning of the `constraint' is inversed with respect
/// to the definitions used in
///
///   Gilles Bertrand and Michel Couprie: Transformations topologiques
Roland Levillain's avatar
Roland Levillain committed
38
39
///   discrètes.  In David Coeurjolly, Annick Montanvert and Jean-Marc
///   Chassery, eds.: Géométrie discrète et images numériques.  Hermes
40
///   Sciences Publications (2007), pages 187--209.
41
42
43

# include <mln/core/routine/duplicate.hh>

44
45
46
# include <mln/core/concept/image.hh>
# include <mln/core/concept/neighborhood.hh>

47
# include <mln/core/site_set/p_queue_fast.hh>
48

49
# include <mln/topo/no_constraint.hh>
50

51
52
53
# include <mln/data/fill.hh>


54
55
56
57
58
59
60
61
62
namespace mln
{

  namespace topo
  {

    namespace skeleton
    {

63
      /** \brief Skeleton by Breadth-First Thinning.
64

65
	  A generic implementation of the computation of a skeleton
66
	  using a breadth-first thinning on a binary image.
67

68
69
70
71
72
	  \param input      The input image.
	  \param nbh        The adjacency relation between triangles.
	  \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>.
73
	  \param detach     A function used to detach a cell from \a input.
74
75
			    This functor must provide a method
			    <tt>void set_image(const Image<I>&)</tt>.
76
77
	  \param constraint A constraint on point (site); if it
			    returns \c false for a point, this point
78
79
80
			    will not be removed.

	  Keywords: skeletons, simple points.  */
81
82
83
      template <typename I, typename N, typename F, typename G, typename H>
      mln_concrete(I)
      breadth_first_thinning(const Image<I>& input,
84
			     const Neighborhood<N>& nbh,
85
			     Function_v2b<F>& is_simple,
86
			     G& detach,
87
88
89
90
91
92
			     const Function_v2b<H>& constraint);


      /** \brief Skeleton by Breadth-First Thinning with no constraint.

	  A generic implementation of the computation of a skeleton
93
	  using a breadth-first thinning on a binary image.
94

95
96
97
98
99
	  \param input      The input image.
	  \param nbh        The adjacency relation between triangles.
	  \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>.
100
101
102
103
104
	  \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.  */
105
106
107
108
109
      template <typename I, typename N, typename F, typename G>
      mln_concrete(I)
      breadth_first_thinning(const Image<I>& input,
			     const Neighborhood<N>& nbh,
			     Function_v2b<F>& is_simple,
110
			     G& detach);
111
112
113
114


# ifndef MLN_INCLUDE_ONLY

115
      template <typename I, typename N, typename F, typename G, typename H>
116
      inline
117
118
      mln_concrete(I)
      breadth_first_thinning(const Image<I>& input_,
119
			     const Neighborhood<N>& nbh_,
120
			     Function_v2b<F>& is_simple_,
121
			     G& detach,
122
			     const Function_v2b<H>& constraint_)
123
      {
124
	mln_trace("topo::skeleton::breadth_first_thinning");
125

126
	const I& input = exact(input_);
127
128
	const N& nbh = exact(nbh_);
	F& is_simple = exact(is_simple_);
129
	const H& constraint = exact(constraint_);
130

131
	mln_concrete(I) output = duplicate(input);
132
	// Attach the work image to IS_SIMPLE and DETACH.
133
	is_simple.set_image(output);
134
	detach.set_image(output);
135

136
	// FIFO queue.
137
	typedef mln_psite(I) psite;
138
139
	typedef p_queue_fast<psite> queue_t;
	queue_t queue;
140
141
142
143
144
	// Image showing whether a site has been inserted into the queue.
	mln_ch_value(I, bool) in_queue;
	initialize(in_queue, input);
	data::fill(in_queue, false);

145
	// Populate QUEUE with candidate simple points.
146
147
	mln_piter(I) p(output.domain());
	for_all(p)
148
149
	{
	  if (output(p) && constraint(p) && is_simple(p))
150
151
152
153
	    {
	      queue.push(p);
	      in_queue(p) = true;
	    }
154
155
	}

156
	while (!queue.is_empty())
157
	  {
158
	    psite p = queue.pop_front();
159
 	    in_queue(p) = false;
160
161
	    if (output(p) && constraint(p) && is_simple(p))
	      {
162
		detach(p);
163
164
		mln_niter(N) n(nbh, p);
		for_all(n)
165
		{
166
		  if (output.domain().has(n)
167
168
169
170
171
172
		      && output(n) && constraint(n) && is_simple(n)
		      && !in_queue(n))
		    {
		      queue.push(n);
		      in_queue(n) = true;
		    }
173
		}
174
	      }
175
	  }
176

177
178
179
	return output;
      }

180
181
182
183
184
185
186

      template <typename I, typename N, typename F, typename G>
      inline
      mln_concrete(I)
      breadth_first_thinning(const Image<I>& input,
			     const Neighborhood<N>& nbh,
			     Function_v2b<F>& is_simple,
187
			     G& detach)
188
      {
189
190
191
	// mln::topo::no_constraint is a dummy functor always
	// returning `true'.
	no_constraint constraint;
192
	return breadth_first_thinning(input, nbh, is_simple, detach,
193
				      constraint);
194
195
      }

196
197
198
199
200
201
202
203
204
# endif // MLN_INCLUDE_ONLY

    } // end of namespace mln::topo::skeleton

  } // end of namespace mln::topo

} // end of namespace mln

#endif // ! MLN_TOPO_SKELETON_BREADTH_FIRST_THINNING_HH