Milena (Olena)  User documentation 2.0a Id
 All Classes Namespaces Functions Variables Typedefs Enumerator Groups Pages
canvas/distance_geodesic.hh
1 // Copyright (C) 2008, 2009 EPITA Research and Development Laboratory
2 // (LRDE)
3 //
4 // This file is part of Olena.
5 //
6 // Olena is free software: you can redistribute it and/or modify it under
7 // the terms of the GNU General Public License as published by the Free
8 // Software Foundation, version 2 of the License.
9 //
10 // Olena is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 // General Public License for more details.
14 //
15 // 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 // file, or you compile this file and link it with other files to produce
22 // an executable, this file does not by itself cause the resulting
23 // executable to be covered by the GNU General Public License. This
24 // exception does not however invalidate any other reasons why the
25 // executable file might be covered by the GNU General Public License.
26 
27 #ifndef MLN_CANVAS_DISTANCE_GEODESIC_HH
28 # define MLN_CANVAS_DISTANCE_GEODESIC_HH
29 
33 
34 # include <mln/core/concept/image.hh>
35 # include <mln/core/concept/neighborhood.hh>
36 # include <mln/core/routine/duplicate.hh>
37 
38 # include <mln/core/site_set/p_queue_fast.hh>
39 # include <queue>
40 
41 # include <mln/data/fill.hh>
42 # include <mln/extension/adjust_fill.hh>
43 
44 
45 namespace mln
46 {
47 
48  namespace canvas
49  {
50 
52  template <typename I, typename N, typename D,
53  typename F>
54  mln_ch_value(I, D)
55  distance_geodesic(const Image<I>& input, const Neighborhood<N>& nbh,
56  D max, F& functor);
57 
58 
59 
60 # ifndef MLN_INCLUDE_ONLY
61 
62 
63  // Tests.
64 
65  namespace internal
66  {
67 
68  template <typename I, typename N, typename D,
69  typename F>
70  void
71  distance_geodesic_tests(const Image<I>& input_,
72  const Neighborhood<N>& nbh_, D max,
73  F& functor)
74  {
75  const I& input = exact(input_);
76  const N& nbh = exact(nbh_);
77 
78  mln_precondition(input.is_valid());
79  mln_precondition(nbh.is_valid());
80 
81  (void) input;
82  (void) nbh;
83  (void) max;
84  (void) functor;
85  }
86 
87 
88  } // of namespace mln::canvas::internal
89 
90 
91 
92  // Implementations.
93 
94  namespace impl
95  {
96 
97  namespace generic
98  {
99 
100  template <typename I, typename N, typename D,
101  typename F>
102  mln_ch_value(I, D)
103  distance_geodesic(const Image<I>& input_, const Neighborhood<N>& nbh_,
104  D max, F& functor)
105  {
106  trace::entering("canvas::impl::generic::distance_geodesic");
107 
108  const I& input = exact(input_);
109  const N& nbh = exact(nbh_);
110 
111  internal::distance_geodesic_tests(input, nbh, max, functor);
112 
113  mln_precondition(input.is_valid());
114  mln_precondition(nbh.is_valid());
115 
116  mln_ch_value(I, D) dmap; // Distance map is aux data.
117  initialize(dmap, input);
118 
119  typedef mln_site(I) P;
120  p_queue_fast<P> q;
121 
122  // Initialization.
123  {
124  functor.init(input); // <-- init
125  data::fill(dmap, max);
126 
127  mln_piter(I) p(input.domain());
128  mln_niter(N) n(nbh, p);
129  for_all(p)
130  if (functor.inqueue_p_wrt_input_p(input(p))) // <-- inqueue_p_wrt_input_p
131  {
132  functor.init_p(p); // <-- init_p
133  dmap(p) = 0;
134  for_all(n)
135  if (input.domain().has(n) &&
136  functor.inqueue_p_wrt_input_n(input(n))) // <-- inqueue_p_wrt_input_n
137  {
138  q.push(p);
139  break;
140  }
141  }
142  }
143 
144  // Propagation.
145  {
146  P p;
147  mln_niter(N) n(nbh, p);
148  while (! q.is_empty())
149  {
150  p = q.pop_front();
151  if (dmap(p) == max)
152  {
153  // Saturation so stop.
154  q.clear();
155  break;
156  }
157  for_all(n)
158  if (input.domain().has(n) && dmap(n) == max)
159  {
160  dmap(n) = dmap(p) + 1;
161  functor.process(p, n); // <- process
162  q.push(n);
163  }
164  }
165  }
166 
167  trace::exiting("canvas::impl::generic::distance_geodesic");
168  return dmap;
169  }
170 
171  } // of namespace mln::canvas::impl::generic
172 
173 
174 
175  // Fastest version.
176 
177  template <typename I, typename N, typename D,
178  typename F>
179  mln_ch_value(I, D)
180  distance_geodesic_fastest(const Image<I>& input_,
181  const Neighborhood<N>& nbh_,
182  D max,
183  F& functor)
184  {
185  trace::entering("canvas::impl::distance_geodesic_fastest");
186 
187  const I& input = exact(input_);
188  const N& nbh = exact(nbh_);
189 
190  internal::distance_geodesic_tests(input, nbh, max, functor);
191 
192  extension::adjust(input, nbh);
193 
194  mln_ch_value(I, D) dmap; // Distance map is aux data.
195  initialize(dmap, input);
196 
197  std::queue<unsigned> q;
198 
199  // Initialization.
200  {
201  functor.init_(input); // <-- init
202  data::fill(dmap, max);
203  // For the extension to be ignored:
204  extension::fill(input, true);
205  extension::fill(dmap, D(0));
206 
207  mln_pixter(const I) p(input);
208  mln_nixter(const I, N) n(p, nbh);
209  for_all(p)
210  if (functor.inqueue_p_wrt_input_p_(p.val())) // <-- inqueue_p_wrt_input_p
211  {
212  functor.init_p_(p); // <-- init_p
213  dmap.element(p.offset()) = 0;
214  for_all(n)
215  if (functor.inqueue_p_wrt_input_n_(n.val())) // <-- inqueue_p_wrt_input_n
216  {
217  q.push(p.offset());
218  break;
219  }
220  }
221  }
222 
223  // Propagation.
224  {
225  unsigned p;
226 
227  util::array<int> dp = offsets_wrt(input, nbh);
228  const unsigned n_nbhs = dp.nelements();
229 
230  while (! q.empty())
231  {
232  p = q.front();
233  q.pop();
234  if (dmap.element(p) == max)
235  // Saturation so stop.
236  break;
237  for (unsigned i = 0; i < n_nbhs; ++i)
238  {
239  unsigned n = p + dp[i];
240  if (dmap.element(n) == max)
241  {
242  dmap.element(n) = dmap.element(p) + 1;
243  functor.process_(p, n); // <- process
244  q.push(n);
245  }
246  }
247  }
248  }
249 
250  trace::exiting("canvas::impl::distance_geodesic_fastest");
251  return dmap;
252  }
253 
254 
255  } // of namespace mln::canvas::impl
256 
257 
258 
259  // Dispatch.
260 
261  namespace internal
262  {
263 
264  template <typename I, typename N, typename D,
265  typename F>
266  inline
267  mln_ch_value(I, D)
268  distance_geodesic_dispatch(metal::false_,
269  const Image<I>& input,
270  const Neighborhood<N>& nbh, D max,
271  F& functor)
272  {
273  return impl::generic::distance_geodesic(input, nbh, max,
274  functor);
275  }
276 
277  template <typename I, typename N, typename D,
278  typename F>
279  inline
280  mln_ch_value(I, D)
281  distance_geodesic_dispatch(metal::true_,
282  const Image<I>& input,
283  const Neighborhood<N>& nbh, D max,
284  F& functor)
285  {
286  return impl::distance_geodesic_fastest(input, nbh, max, functor);
287 // return impl::generic::distance_geodesic(input, nbh, max,
288 // functor);
289  }
290 
291  template <typename I, typename N, typename D,
292  typename F>
293  inline
294  mln_ch_value(I, D)
295  distance_geodesic_dispatch(const Image<I>& input,
296  const Neighborhood<N>& nbh, D max,
297  F& functor)
298  {
299  enum {
300  test = mlc_equal(mln_trait_image_speed(I),
301  trait::image::speed::fastest)::value
302  &&
303  mln_is_simple_neighborhood(N)::value
304  };
305  return distance_geodesic_dispatch(metal::bool_<test>(),
306  input, nbh, max,
307  functor);
308  }
309 
310 
311  } // of namespace mln::canvas::internal
312 
313 
314 
315  // Facade.
316 
317  template <typename I, typename N, typename D,
318  typename F>
319  inline
320  mln_ch_value(I, D)
321  distance_geodesic(const Image<I>& input, const Neighborhood<N>& nbh,
322  D max, F& functor)
323  {
324  trace::entering("canvas::distance_geodesic");
325 
326  internal::distance_geodesic_tests(input, nbh, max, functor);
327 
328  mln_ch_value(I,D) output;
329  output = internal::distance_geodesic_dispatch(input, nbh, max, functor);
330 
331  trace::exiting("canvas::distance_geodesic");
332  return output;
333  }
334 
335 
336 # endif // ! MLN_INCLUDE_ONLY
337 
338  } // end of namespace mln::canvas
339 
340 } // end of namespace mln
341 
342 
343 #endif // ! MLN_CANVAS_DISTANCE_GEODESIC_HH