Milena (Olena)  User documentation 2.0a Id
 All Classes Namespaces Functions Variables Typedefs Enumerator Groups Pages
canvas/distance_front.hh
1 // Copyright (C) 2008, 2009 EPITA Research and Development Laboratory (LRDE)
2 //
3 // This file is part of Olena.
4 //
5 // Olena is free software: you can redistribute it and/or modify it under
6 // the terms of the GNU General Public License as published by the Free
7 // Software Foundation, version 2 of the License.
8 //
9 // Olena is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 // General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with Olena. If not, see <http://www.gnu.org/licenses/>.
16 //
17 // As a special exception, you may use this file as part of a free
18 // software project without restriction. Specifically, if other files
19 // instantiate templates or use macros or inline functions from this
20 // file, or you compile this file and link it with other files to produce
21 // an executable, this file does not by itself cause the resulting
22 // executable to be covered by the GNU General Public License. This
23 // exception does not however invalidate any other reasons why the
24 // executable file might be covered by the GNU General Public License.
25 
26 #ifndef MLN_CANVAS_DISTANCE_FRONT_HH
27 # define MLN_CANVAS_DISTANCE_FRONT_HH
28 
32 
33 # include <vector>
34 # include <mln/core/concept/image.hh>
35 # include <mln/core/concept/neighborhood.hh>
36 # include <mln/core/concept/weighted_window.hh>
37 # include <mln/data/fill.hh>
38 # include <mln/accu/stat/max.hh>
39 # include <mln/extension/adjust_fill.hh>
40 
41 
42 namespace mln
43 {
44 
45  namespace canvas
46  {
47 
49  template <typename I,
50  typename N, typename W, typename D,
51  typename F>
52  mln_ch_value(I, D)
53  distance_front(const Image<I>& input,
54  const Neighborhood<N>& nbh, const Weighted_Window<W>& w_win, D max,
55  F& functor);
56 
57 
58 
59 # ifndef MLN_INCLUDE_ONLY
60 
61 
62  // Tests.
63 
64  namespace internal
65  {
66 
67  template <typename I,
68  typename N, typename W, typename D,
69  typename F>
70  void
71  distance_front_tests(const Image<I>& input_,
72  const Neighborhood<N>& nbh_,
73  const Weighted_Window<W>& w_win_,
74  D max,
75  F& functor)
76  {
77  const I& input = exact(input_);
78  const N& nbh = exact(nbh_);
79  const W& w_win = exact(w_win_);
80 
81  mln_precondition(input.is_valid());
82  mln_precondition(nbh.is_valid());
83 
84  (void) input;
85  (void) nbh;
86  (void) max;
87  (void) functor;
88  (void) w_win;
89  }
90 
91 
92  } // of namespace mln::canvas::internal
93 
94 
95 
96  // Implementations.
97 
98  namespace impl
99  {
100 
101  namespace generic
102  {
103 
104  template <typename I,
105  typename N, typename W, typename D,
106  typename F>
107  mln_ch_value(I, D)
108  distance_front(const Image<I>& input_,
109  const Neighborhood<N>& nbh_,
110  const Weighted_Window<W>& w_win_,
111  D max,
112  F& functor)
113  {
114  trace::entering("canvas::impl::generic::distance_front");
115 
116  const I& input = exact(input_);
117  const N& nbh = exact(nbh_);
118  const W& w_win = exact(w_win_);
119 
120  mln_precondition(input.is_valid());
121  mln_precondition(w_win.is_valid());
122 
123  typedef mln_site(I) P;
124  typedef std::vector<P> bucket_t;
125 
126  // Distance map.
127  mln_ch_value(I, D) dmap;
128  initialize(dmap, input);
129  data::fill(dmap, max);
130 
131  // Mod determination.
132  unsigned mod;
133  {
134  accu::stat::max<unsigned> m;
135  for (unsigned i = 0; i < w_win.size(); ++i)
136  m.take(w_win.w(i));
137  mod = unsigned(m) + 1;
138  }
139 
140  // Aux data.
141  std::vector<bucket_t> bucket(mod);
142  unsigned bucket_size = 0;
143 
144  // Initialization.
145  {
146  functor.init(input); // <-- init
147  mln_piter(I) p(input.domain());
148  mln_niter(N) n(nbh, p);
149  for_all(p)
150  if (functor.inqueue_p_wrt_input_p(input(p))) // <-- inqueue_p_wrt_input_p
151  {
152  dmap(p) = 0;
153  for_all(n)
154  if (input.domain().has(n) &&
155  functor.inqueue_p_wrt_input_n(input(n))) // <-- inqueue_p_wrt_input_n
156  {
157  bucket[0].push_back(p);
158  ++bucket_size;
159  break;
160  }
161  }
162  } // end of Initialization.
163 
164  // Propagation.
165  {
166  P p;
167  mln_qiter(W) q(w_win, p);
168  for (unsigned d = 0; bucket_size != 0; ++d)
169  {
170  bucket_t& bucket_d = bucket[d % mod];
171  for (unsigned i = 0; i < bucket_d.size(); ++i)
172  {
173  p = bucket_d[i];
174 
175  if (dmap(p) == max)
176  {
177  // Saturation so stop.
178  bucket_size = bucket_d.size(); // So at end bucket_size == 0.
179  break;
180  }
181 
182  if (dmap(p) < d)
183  // p has already been processed, having a distance less than d.
184  continue;
185 
186  for_all(q)
187  if (dmap.domain().has(q) && dmap(q) > d)
188  {
189  unsigned d_ = d + q.w();
190  if (d_ < dmap(q))
191  {
192  dmap(q) = d_;
193  functor.process(p, q); // <- process
194  bucket[d_ % mod].push_back(q);
195  ++bucket_size;
196  }
197  }
198  }
199  bucket_size -= bucket_d.size();
200  bucket_d.clear();
201  }
202  } // end of Propagation.
203 
204  trace::exiting("canvas::impl::generic::distance_front");
205  return dmap;
206  }
207 
208  } // of namespace mln::canvas::impl::generic
209 
210 
211 
212  // Fastest version.
213 
214  template <typename I,
215  typename N, typename W, typename D,
216  typename F>
217  mln_ch_value(I, D)
218  distance_front_fastest(const Image<I>& input_,
219  const Neighborhood<N>& nbh_,
220  const Weighted_Window<W>& w_win_,
221  D max, F& functor)
222  {
223  trace::entering("canvas::impl::distance_front_fastest");
224 
225  const I& input = exact(input_);
226  const N& nbh = exact(nbh_);
227  const W& w_win = exact(w_win_);
228 
229  mln_precondition(input.is_valid());
230  mln_precondition(w_win.is_valid());
231 
232  // Handling w_win.
233  extension::adjust(input, w_win);
234  const unsigned n_ws = w_win.size();
235  util::array<int> dp = offsets_wrt(input, w_win.win());
236  mln_invariant(dp.nelements() == n_ws);
237 
238  // Distance map.
239  mln_ch_value(I, D) dmap;
240  initialize(dmap, input);
241  data::fill(dmap, max);
242 
243  // Mod determination.
244  unsigned mod;
245  {
246  accu::stat::max<unsigned> m;
247  for (unsigned i = 0; i < w_win.size(); ++i)
248  m.take(w_win.w(i));
249  mod = unsigned(m) + 1;
250  }
251 
252  // Aux data.
253  typedef std::vector<unsigned> bucket_t;
254  std::vector<bucket_t> bucket(mod);
255  unsigned bucket_size = 0;
256 
257  // Initialization.
258  {
259  functor.init_(input); // <-- init
260 
261  // For the extension to be ignored:
262  extension::fill(input, true);
263  extension::fill(dmap, D(0));
264 
265  mln_pixter(const I) p(input);
266  mln_nixter(const I, N) n(p, nbh);
267  for_all(p)
268  if (functor.inqueue_p_wrt_input_p_(p.val())) // <-- inqueue_p_wrt_input_p
269  {
270  dmap.element(p.offset()) = 0;
271  for_all(n)
272  if (functor.inqueue_p_wrt_input_n_(n.val())) // <-- inqueue_p_wrt_input_n
273  {
274  bucket[0].push_back(p.offset());
275  ++bucket_size;
276  break;
277  }
278  }
279  } // end of Initialization.
280 
281  // Propagation.
282  {
283  unsigned p;
284 
285  for (unsigned d = 0; bucket_size != 0; ++d)
286  {
287  bucket_t& bucket_d = bucket[d % mod];
288  for (unsigned i = 0; i < bucket_d.size(); ++i)
289  {
290  p = bucket_d[i];
291 
292  if (dmap.element(p) == max)
293  {
294  // Saturation so stop.
295  bucket_size = bucket_d.size(); // So at end bucket_size == 0.
296  break;
297  }
298 
299  if (dmap.element(p) < d)
300  // p has already been processed, having a distance less than d.
301  continue;
302 
303  for (unsigned i = 0; i < n_ws; ++i)
304  {
305  unsigned q = p + dp[i];
306  if (dmap.element(q) > d)
307  {
308  unsigned d_ = d + w_win.w(i);
309  if (d_ < dmap.element(q))
310  {
311  dmap.element(q) = d_;
312  functor.process_(p, q); // <- process
313  bucket[d_ % mod].push_back(q);
314  ++bucket_size;
315  }
316  }
317  }
318  }
319  bucket_size -= bucket_d.size();
320  bucket_d.clear();
321  }
322  } // end of Propagation.
323 
324  trace::exiting("canvas::impl::distance_front_fastest");
325  return dmap;
326  }
327 
328 
329  } // of namespace mln::canvas::impl
330 
331 
332 
333  // Dispatch.
334 
335  namespace internal
336  {
337 
338  template <typename I,
339  typename N, typename W, typename D,
340  typename F>
341  inline
342  mln_ch_value(I, D)
343  distance_front_dispatch(metal::false_,
344  const Image<I>& input,
345  const Neighborhood<N>& nbh, const Weighted_Window<W>& w_win,
346  D max, F& functor)
347  {
348  return impl::generic::distance_front(input, nbh, w_win, max, functor);
349  }
350 
351  template <typename I,
352  typename N, typename W, typename D,
353  typename F>
354  inline
355  mln_ch_value(I, D)
356  distance_front_dispatch(metal::true_,
357  const Image<I>& input,
358  const Neighborhood<N>& nbh, const Weighted_Window<W>& w_win,
359  D max, F& functor)
360  {
361  return impl::distance_front_fastest(input, nbh, w_win, max, functor);
362  }
363 
364  template <typename I,
365  typename N, typename W, typename D,
366  typename F>
367  inline
368  mln_ch_value(I, D)
369  distance_front_dispatch(const Image<I>& input,
370  const Neighborhood<N>& nbh, const Weighted_Window<W>& w_win,
371  D max, F& functor)
372  {
373  enum {
374  test = mlc_equal(mln_trait_image_speed(I),
375  trait::image::speed::fastest)::value
376  &&
377  mln_is_simple_neighborhood(N)::value
378  &&
379  mln_is_simple_weighted_window(W)::value
380  };
381  return distance_front_dispatch(metal::bool_<test>(),
382  input, nbh, w_win, max, functor);
383  }
384 
385 
386  } // of namespace mln::canvas::internal
387 
388 
389 
390  // Facade.
391 
392  template <typename I,
393  typename N, typename W, typename D,
394  typename F>
395  inline
396  mln_ch_value(I, D)
397  distance_front(const Image<I>& input,
398  const Neighborhood<N>& nbh, const Weighted_Window<W>& w_win,
399  D max, F& functor)
400  {
401  trace::entering("canvas::distance_front");
402 
403  internal::distance_front_tests(input, nbh, w_win, max, functor);
404 
405  mln_ch_value(I,D) output;
406  output = internal::distance_front_dispatch(input, nbh, w_win, max, functor);
407 
408  trace::exiting("canvas::distance_front");
409  return output;
410  }
411 
412 
413 # endif // ! MLN_INCLUDE_ONLY
414 
415  } // end of namespace mln::canvas
416 
417 } // end of namespace mln
418 
419 
420 #endif // ! MLN_CANVAS_DISTANCE_FRONT_HH