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