Milena (Olena)  User documentation 2.0a Id
 All Classes Namespaces Functions Variables Typedefs Enumerator Groups Pages
flooding.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_MORPHO_WATERSHED_FLOODING_HH
27 # define MLN_MORPHO_WATERSHED_FLOODING_HH
28 
40 
41 # include <mln/trait/ch_value.hh>
42 
43 # include <mln/morpho/includes.hh>
44 # include <mln/literal/zero.hh>
45 # include <mln/labeling/regional_minima.hh>
46 
47 # include <mln/core/site_set/p_queue_fast.hh>
48 # include <mln/core/site_set/p_priority.hh>
49 
50 # include <mln/extension/adjust_fill.hh>
51 
52 
53 namespace mln
54 {
55 
56  namespace morpho
57  {
58 
59  namespace watershed
60  {
61 
73 
74  template <typename L, typename I, typename N>
75  mln_ch_value(I, L)
76  flooding(const Image<I>& input, const Neighborhood<N>& nbh,
77  L& n_basins);
78 
95  template <typename L, typename I, typename N>
96  mln_ch_value(I, L)
97  flooding(const Image<I>& input, const Neighborhood<N>& nbh);
98 
99 
100 
101 # ifndef MLN_INCLUDE_ONLY
102 
103 
104  // Implementations.
105 
106  namespace impl
107  {
108 
109  namespace generic
110  {
111 
112  template <typename L, typename I, typename N>
113  mln_ch_value(I, L)
114  flooding(const Image<I>& input_, const Neighborhood<N>& nbh_,
115  L& n_basins)
116  {
117  trace::entering("morpho::watershed::impl::generic::flooding");
118  /* FIXME: Ensure the input image has scalar values. */
119 
120  const I input = exact(input_);
121  const N nbh = exact(nbh_);
122 
123  typedef L marker;
124  const marker unmarked = literal::zero;
125 
126  typedef mln_value(I) V;
127  const V max = mln_max(V);
128 
129  // Initialize the output with the markers (minima components).
130  mln_ch_value(I, marker) output =
131  labeling::regional_minima (input, nbh, n_basins);
132 
133  typedef mln_psite(I) psite;
134 
135  // Ordered queue.
136  typedef p_queue_fast<psite> Q;
137  p_priority<V, Q> queue;
138 
139  // In_queue structure to avoid processing sites several times.
140  mln_ch_value(I, bool) in_queue;
141  initialize(in_queue, input);
142  data::fill(in_queue, false);
143 
144  // Insert every neighbor P of every marked area in a
145  // hierarchical queue, with a priority level corresponding to
146  // the grey level input(P).
147  mln_piter(I) p(output.domain());
148  mln_niter(N) n(nbh, p);
149  for_all(p)
150  if (output(p) == unmarked)
151  for_all(n)
152  if (output.domain().has(n) && output(n) != unmarked)
153  {
154  queue.push(max - input(p), p);
155  in_queue(p) = true;
156  break;
157  }
158 
159  /* Until the queue is empty, extract a psite P from the
160  hierarchical queue, at the highest priority level, that is,
161  the lowest level. */
162  while (! queue.is_empty())
163  {
164  psite p = queue.front();
165  queue.pop();
166 
167  // Last seen marker adjacent to P.
168  marker adjacent_marker = unmarked;
169  // Has P a single adjacent marker?
170  bool single_adjacent_marker_p = true;
171  mln_niter(N) n(nbh, p);
172  for_all(n)
173  if (output.domain().has(n) && output(n) != unmarked)
174  {
175  if (adjacent_marker == unmarked)
176  {
177  adjacent_marker = output(n);
178  single_adjacent_marker_p = true;
179  }
180  else
181  if (adjacent_marker != output(n))
182  {
183  single_adjacent_marker_p = false;
184  break;
185  }
186  }
187  /* If the neighborhood of P contains only psites with the
188  same label, then P is marked with this label, and its
189  neighbors that are not yet marked are put into the
190  hierarchical queue. */
191  if (single_adjacent_marker_p)
192  {
193  output(p) = adjacent_marker;
194  for_all(n)
195  if (output.domain().has(n) && output(n) == unmarked
196  && ! in_queue(n))
197  {
198  queue.push(max - input(n), n);
199  in_queue(n) = true;
200  }
201  }
202  }
203 
204  trace::exiting("morpho::watershed::impl::generic::flooding");
205  return output;
206  }
207 
208  } // end of namespace mln::morpho::watershed::impl::generic
209 
210 
211 
212  // Fastest version.
213 
214  template <typename I, typename N, typename L>
215  mln_ch_value(I, L)
216  flooding_fastest(const Image<I>& input_, const Neighborhood<N>& nbh_,
217  L& n_basins)
218  {
219  trace::entering("morpho::watershed::impl::flooding_fastest");
220  /* FIXME: Ensure the input image has scalar values. */
221 
222  const I input = exact(input_);
223  const N nbh = exact(nbh_);
224 
225  typedef L marker;
226  const marker unmarked = literal::zero;
227 
228  typedef mln_value(I) V;
229  const V max = mln_max(V);
230 
231  extension::adjust_fill(input, nbh, max);
232 
233  // Initialize the output with the markers (minima components).
234  typedef mln_ch_value(I, L) O;
235  O output = labeling::regional_minima(input, nbh, n_basins);
236  extension::fill(output, unmarked);
237 
238  // Ordered queue.
239  typedef p_queue_fast<unsigned> Q;
240  p_priority<V, Q> queue;
241 
242  // FIXME: With typedef std::pair<V, unsigned> VU;
243  // std::priority_queue<VU> queue;
244  // we do not get the same results!!!
245 
246  // In_queue structure to avoid processing sites several times.
247  mln_ch_value(I, bool) in_queue;
248  initialize(in_queue, input);
249  data::fill(in_queue, false);
250  extension::fill(in_queue, true);
251 
252  // Insert every neighbor P of every marked area in a
253  // hierarchical queue, with a priority level corresponding to
254  // the grey level input(P).
255  mln_pixter(const O) p_out(output);
256  mln_nixter(const O, N) n_out(p_out, nbh);
257  for_all(p_out)
258  if (p_out.val() == unmarked)
259  for_all(n_out)
260  if (n_out.val() != unmarked)
261  {
262  unsigned po = p_out.offset();
263  queue.push(max - input.element(po), po);
264  in_queue.element(po) = true;
265  break;
266  }
267 
268  /* Until the queue is empty, extract a psite P from the
269  hierarchical queue, at the highest priority level, that is,
270  the lowest level. */
271  util::array<int> dp = offsets_wrt(input, nbh);
272  const unsigned n_nbhs = dp.nelements();
273  while (! queue.is_empty())
274  {
275  unsigned p = queue.front();
276  queue.pop();
277 
278  // Last seen marker adjacent to P.
279  marker adjacent_marker = unmarked;
280  // Has P a single adjacent marker?
281  bool single_adjacent_marker_p = true;
282  for (unsigned i = 0; i < n_nbhs; ++i)
283  {
284  unsigned n = p + dp[i];
285  // In the border, output is unmarked so N is ignored.
286  if (output.element(n) != unmarked)
287  {
288  if (adjacent_marker == unmarked)
289  {
290  adjacent_marker = output.element(n);
291  single_adjacent_marker_p = true;
292  }
293  else
294  if (adjacent_marker != output.element(n))
295  {
296  single_adjacent_marker_p = false;
297  break;
298  }
299  }
300  }
301  /* If the neighborhood of P contains only psites with the
302  same label, then P is marked with this label, and its
303  neighbors that are not yet marked are put into the
304  hierarchical queue. */
305  if (single_adjacent_marker_p)
306  {
307  output.element(p) = adjacent_marker;
308  for (unsigned i = 0; i < n_nbhs; ++i)
309  {
310  unsigned n = p + dp[i];
311  if (output.element(n) == unmarked
312  // In the border, in_queue is true so N is ignored.
313  && ! in_queue.element(n))
314  {
315  queue.push(max - input.element(n), n);
316  in_queue.element(n) = true;
317  }
318  }
319  }
320  }
321 
322  trace::exiting("morpho::watershed::impl::flooding_fastest");
323  return output;
324  }
325 
326 
327  } // end of namespace mln::morpho::watershed::impl
328 
329 
330 
331  // Dispatch.
332 
333  namespace internal
334  {
335 
336  template <typename I, typename N, typename L>
337  inline
338  mln_ch_value(I, L)
339  flooding_dispatch(metal::false_,
340  const Image<I>& input, const Neighborhood<N>& nbh,
341  L& n_basins)
342  {
343  return impl::generic::flooding(input, nbh, n_basins);
344  }
345 
346 
347  template <typename I, typename N, typename L>
348  inline
349  mln_ch_value(I, L)
350  flooding_dispatch(metal::true_,
351  const Image<I>& input, const Neighborhood<N>& nbh,
352  L& n_basins)
353  {
354  return impl::flooding_fastest(input, nbh, n_basins);
355  }
356 
357  template <typename I, typename N, typename L>
358  inline
359  mln_ch_value(I, L)
360  flooding_dispatch(const Image<I>& input, const Neighborhood<N>& nbh,
361  L& n_basins)
362  {
363  enum {
364  test = mlc_equal(mln_trait_image_speed(I),
365  trait::image::speed::fastest)::value
366  &&
367  mln_is_simple_neighborhood(N)::value
368  };
369  return flooding_dispatch(metal::bool_<test>(),
370  input, nbh, n_basins);
371  }
372 
373  } // end of namespace mln::morpho::watershed::internal
374 
375 
376  // Facades.
377 
378  template <typename L, typename I, typename N>
379  inline
380  mln_ch_value(I, L)
381  flooding(const Image<I>& input, const Neighborhood<N>& nbh, L& n_basins)
382  {
383  trace::entering("morpho::watershed::flooding");
384 
385  // FIXME: internal::flooding_tests(input, nbh, n_basins);
386 
387  mln_ch_value(I, L) output =
388  internal::flooding_dispatch(input, nbh, n_basins);
389 
390  trace::exiting("morpho::watershed::flooding");
391  return output;
392  }
393 
394  template <typename L, typename I, typename N>
395  mln_ch_value(I, L)
396  flooding(const Image<I>& input, const Neighborhood<N>& nbh)
397  {
398  L nbasins;
399  return flooding<L>(input, nbh, nbasins);
400  }
401 
402 # endif // ! MLN_INCLUDE_ONLY
403 
404  } // end of namespace mln::morpho::watershed
405 
406  } // end of namespace mln::morpho
407 
408 } // end of namespace mln
409 
410 
411 #endif // ! MLN_MORPHO_WATERSHED_FLOODING_HH