$extrastylesheet
Olena  User documentation 2.1
An Image Processing Platform
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
topological.hh
1 // Copyright (C) 2008, 2009, 2013 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_TOPOLOGICAL_HH
28 # define MLN_MORPHO_WATERSHED_TOPOLOGICAL_HH
29 
39 
40 # include <cstdlib>
41 
42 # include <vector>
43 # include <map>
44 # include <queue>
45 
46 # include <mln/core/site_set/p_set.hh>
47 # include <mln/core/site_set/p_priority.hh>
48 # include <mln/core/site_set/p_queue_fast.hh>
49 
50 # include <mln/util/ord.hh>
51 
52 # include <mln/data/sort_psites.hh>
53 # include <mln/data/fill.hh>
54 
55 
56 // FIXME: Clean up and document.
57 
58 namespace mln
59 {
60 
61  namespace morpho
62  {
63 
64  namespace watershed
65  {
66 
67  template <class I>
68  mln_psite(I) min(const Image<I> &ima_, p_set<mln_psite(I)>& components)
69  {
70  const I& ima = exact(ima_);
71 
72  if (components.is_empty())
73  // FIXME: Display an error message? Or throw an exception?
74  abort();
75 
76  typename p_set<mln_psite(I)>::fwd_piter it(components);
77  mln_psite(I) min = components[0];
78 
79  for_all(it)
80  if (ima(it) < ima(min))
81  min = it;
82 
83  return min;
84  }
85 
86  template <class I>
87  mln_psite(I) max(p_set<mln_psite(I)>& components)
88  {
89  if (components.is_empty())
90  // FIXME: Display an error message? Or throw an exception?
91  abort();
92 
93  typename p_set<mln_psite(I)>::fwd_piter it(components);
94  mln_psite(I) max = components[0];
95 
96  for_all(it)
97  if (ima(it) > ima(max))
98  max = it;
99 
100  return max;
101  }
102 
103 
104  // Actually, this structure is a tree, despite its confusing name.
105  template <class I, class N>
106  struct topo_wst
107  {
108  // Typedefs
109  // --------
110  typedef mln_psite(I) psite;
111  typedef I image_t;
112  typedef N neighborhood_t;
113 
114  // Component tree management
115  // -------------------------
116  private:
117  struct node {
118  mln_value(I) level;
119  int area;
120  int highest;
121  typedef mln_psite(I) psite;
122  // Can't modify the sites in a p_array
123  // p_array<mln_psite(I)> children;
124  std::vector<psite> children;
125 
126  void addChildren(const node& n)
127  {
128  // typename p_array<mln_psite(I)>::fwd_piter it(n.children);
129  // for (it.start();
130  // it.is_valid();
131  // it.next())
132  // children.append(it.to_psite());
133  for (unsigned i=0; i < n.children.size(); ++i)
134  children.push_back(n.children[i]);
135  }
136 
137  void addChild(const psite p)
138  {
139  // children.append(n);
140  children.push_back(p);
141  }
142  }; // struct node
143 
144  public:
145 
146  mln_ch_value(I, psite) Par_node;
147  mln_ch_value(I, psite) Par_tree;
148 
149  mln_ch_value(I, int) Rnk_tree;
150  mln_ch_value(I, int) Rnk_node;
151  mln_ch_value(I, psite) subtreeRoot;
152  mln_ch_value(I, node) nodes;
154 
155  private:
156 
157  void MakeSet_tree(psite x);
158  void MakeSet_node(psite x);
159  psite Find_tree(psite x);
160  psite Find_node(psite x);
161  void BuildComponentTree();
162  psite MergeNode(psite& node1, psite& node2);
163  psite Link_tree(psite x, psite y);
164  psite Link_node(psite x, psite y);
165  node MakeNode(int level);
166 
167  private:
168  mln_ch_value(I, bool) isproc;
169 
170  // Ctor
171  public:
172  topo_wst(const Image<I>& i,
173  const Neighborhood<N>& n);
174 
175  public:
176  const I &ima;
177  const N &nbh;
178 
179  public:
180  void go();
181 
182  private:
183  psite min (p_set<psite>& components);
184  psite max (p_set<psite>& components);
185  bool highest_fork (p_set<psite>& components);
186  bool highest_fork (p_set<psite>& components, psite &r);
187 
188  // Optimized LCA Algorithm
189 
190  public:
191  psite lca (psite a, psite b);
192 
193  private:
194  int *euler;
195  int *depth;
196  int ctree_size;
197  std::map<psite, int, mln::util::ord<psite> > pos;
198  psite *repr;
199 
200  int *minim;
201  int **Minim;
202 
203  void compute_ctree_size (psite p);
204  void build_euler_tour_rec(psite p, int &position, int d);
205  void build_euler_tour();
206  void build_minim ();
207  void removeOneSonNodes(psite *p, mln_ch_value(I, psite) &newPar_node);
208  void compressTree();
209  };
210 
212  template <class T>
213  typename T::image_t
214  topological(T &tree);
215 
216 
217 
218 # ifndef MLN_INCLUDE_ONLY
219 
220  // Ctor
221  template <class I, class N>
223  const Neighborhood<N>& n)
224  : ima(exact(i)), nbh(exact(n))
225  {
226  initialize(Par_node, i);
227  initialize(Par_tree, i);
228  initialize(Rnk_tree, i);
229  initialize(Rnk_node, i);
230  initialize(subtreeRoot, i);
231  initialize(nodes, i);
232  initialize(isproc, i);
233  }
234 
235  template <class I, class N>
236  void topo_wst<I, N>::MakeSet_tree(psite x)
237  {
238  Par_tree(x) = x;
239  Rnk_tree(x) = 0;
240  }
241 
242  template <class I, class N>
243  void topo_wst<I, N>::MakeSet_node(psite x)
244  {
245  Par_node(x) = x;
246  Rnk_node(x) = 0;
247  }
248 
249  template <class I, class N>
250  typename topo_wst<I, N>::psite topo_wst<I, N>::Find_tree(psite x)
251  {
252  if (Par_tree(x) != x)
253  Par_tree(x) = Find_tree(Par_tree(x));
254  return Par_tree(x);
255  }
256 
257  template <class I, class N>
258  typename topo_wst<I, N>::psite topo_wst<I, N>::Find_node(psite x)
259  {
260  if (Par_node(x) != x)
261  Par_node(x) = Find_node(Par_node(x));
262  return Par_node(x);
263  }
264 
265  template <class I, class N>
266  void topo_wst<I, N>::go()
267  {
268  BuildComponentTree();
269  compressTree();
270 
271  build_euler_tour();
272  build_minim();
273  }
274 
275  template <class I, class N>
276  void topo_wst<I, N>::BuildComponentTree()
277  {
278  // Init:
279 
280  // Sort the sites in increasing order
281  p_array<mln_psite(I)> S;
283 
284  // Clear the marker map
285  data::fill(isproc, false);
286  for (int ip = 0; ip < int(S.nsites()); ++ip)
287  {
288  psite p = S[ip];
289  MakeSet_node(p);
290  MakeSet_tree(p);
291  // if (subtreeRoot.hold(p))
292  subtreeRoot(p) = p;
293  // if (nodes.hold(p))
294  nodes(p) = MakeNode(ima(p));
295  }
296 
297 
298 
299  typename p_array<mln_psite(I)>::fwd_piter ip(S);
300  for_all(ip)
301  {
302  psite p = ip;
303 
304  psite curCanonicalElt = Find_tree(p);
305  psite curNode = Find_node(subtreeRoot(curCanonicalElt));
306 
307  // FIXME: Should be `n' instead of `q'.
308  mln_niter(N) q(nbh, ip);
309  for_all(q)
310  if (ima.has(q) and isproc(q) and ima(q) <= ima(p))
311  {
312  psite adjCanonicalElt = Find_tree(q);
313  psite adjNode = Find_node(subtreeRoot(adjCanonicalElt));
314  if (curNode != adjNode)
315  {
316  if (nodes(curNode).level == nodes(adjNode).level)
317  curNode = MergeNode(adjNode, curNode);
318  else
319  {
320  nodes(curNode).addChild(adjNode);
321  nodes(curNode).area += nodes(adjNode).area;
322  nodes(curNode).highest += nodes(adjNode).highest;
323  }
324  }
325 
326  curCanonicalElt = Link_tree(adjCanonicalElt, curCanonicalElt);
327  subtreeRoot(curCanonicalElt) = curNode;
328  }
329  isproc(p) = true;
330  }
331  // Pour garder une map de correspondance psite <-> local_root
332  // for (int ip = 0; ip < int(S.size()); ++ip)
333  // {
334  // psite p = S[ip];
335  // M(p) = Find_node(p);
336  // }
337 
338  mln_piter(I) r(Par_node.domain());
339  for_all(r)
340  Par_node(r) = Find_node(r);
341 
342  // Find the ``first'' psite of ima, according to the forward
343  // traversal order.
344  mln_fwd_piter(I) rp(Par_node.domain());;
345  rp.start();
346 
347  Root = subtreeRoot(Find_tree(Find_node(rp)));
348  }
349 
350 
351  template <class I, class N>
352  typename topo_wst<I, N>::psite topo_wst<I, N>::MergeNode(psite& node1,
353  psite& node2)
354  {
355  psite tmpNode = Link_node(node1, node2);
356  psite tmpNode2;
357  if (tmpNode == node2)
358  {
359  nodes(node2).addChildren(nodes(node1));
360  tmpNode2 = node1;
361  }
362  else
363  {
364  nodes(node1).addChildren(nodes(node2));
365  tmpNode2 = node2;
366  }
367  nodes(tmpNode).area += nodes(tmpNode2).area;
368  nodes(tmpNode).highest += nodes(tmpNode2).highest;
369  return tmpNode;
370  }
371 
372  template <class I, class N>
373  typename topo_wst<I, N>::psite topo_wst<I, N>::Link_tree(psite x, psite y)
374  {
375  if (Rnk_tree(x) > Rnk_tree(y))
376  std::swap(x, y);
377  else
378  if (Rnk_tree(x) == Rnk_tree(y))
379  Rnk_tree(y) += 1;
380  Par_tree(x) = y;
381  return y;
382  }
383 
384  template <class I, class N>
385  typename topo_wst<I, N>::psite topo_wst<I, N>::Link_node(psite x, psite y)
386  {
387  if (Rnk_node(x) > Rnk_node(y))
388  std::swap(x, y);
389  else
390  if (Rnk_node(x) == Rnk_node(y))
391  Rnk_node(y) += 1;
392  Par_node(x) = y;
393  return y;
394  }
395 
396  template <class I, class N>
397  typename topo_wst<I, N>::node topo_wst<I, N>::MakeNode(int level)
398  {
399  node n;
400  n.level = level;
401  n.area = 1;
402  n.highest = level;
403  return n;
404  }
405 
406 
407  template <class I, class N>
408  bool topo_wst<I, N>::highest_fork (p_set<psite>& components, psite &r)
409  {
410  if (components.nsites() == 0)
411  {
412  std::cerr << "highest fork : empty set" << std::endl;
413  return false;
414  }
415 
416  psite
417  m = min(components),
418  hfork = m;
419 
420  typename p_set<psite>::fwd_piter it(components);
421  for_all(it)
422  {
423  // Can't remove the psite from the set
424  if (it.to_psite() == m)
425  continue;
426 
427  psite c = lca(hfork, it.to_psite());
428  if (c != it.to_psite())
429  hfork = c;
430  }
431 
432  if (nodes(m).level == nodes(hfork).level)
433  return false;
434 
435  r = hfork;
436  return true;
437  }
438 
439  template <class I, class N>
440  bool topo_wst<I, N>::highest_fork (p_set<psite>& components) {
441  psite i;
442  return highest_fork(components, i);
443  }
444 
445  template <class I, class N>
446  void topo_wst<I, N>::compute_ctree_size (psite p)
447  {
448  ctree_size += 1;
449  node& n = nodes(p);
450 
451  // typename p_array<mln_psite(I)>::fwd_piter it(n.children);
452  // for_all(it)
453  // compute_ctree_size(it.to_psite());
454 
455  for (unsigned i=0; i < n.children.size(); ++i)
456  compute_ctree_size(n.children[i]);
457  }
458 
459 
460  template <class I, class N>
461  void topo_wst<I, N>::build_euler_tour_rec(psite p, int &position, int d)
462  {
463  if (pos.find(p) == pos.end())
464  pos[p] = position;
465 
466  repr[position] = p;
467  depth[position] = d;
468  euler[position] = pos[p];
469  ++position;
470  node& n = nodes(p);
471 
472  // typename p_array<mln_psite(I)>::fwd_piter it(n.children);
473  // for_all(it)
474  // {
475  // build_euler_tour_rec(it.to_psite(), position, d+1);
476  // depth[position] = d; // Not optimized
477  // euler[position] = pos[p];
478  // repr[position] = p; // Pas necessaire?
479  // ++position;
480  // }
481 
482  for (unsigned i=0; i < n.children.size(); ++i)
483  {
484  build_euler_tour_rec(n.children[i], position, d+1);
485  depth[position] = d; // Not optimized
486  euler[position] = pos[p];
487  repr[position] = p; // Pas necessaire?
488  ++position;
489  }
490  }
491 
492 
493  template <class I, class N>
494  void topo_wst<I, N>::build_euler_tour ()
495  {
496  ctree_size = 0;
497  compute_ctree_size(Root);
498 
499  int size = 2 * ctree_size - 1;
500 
501  // FIXME : free this
502  euler = new int[size];
503  depth = new int[size];
504  repr = new psite[size];
505 
506  int position = 0;
507  build_euler_tour_rec(Root, position, 0);
508  }
509 
510 
511  template <class I, class N>
512  void topo_wst<I, N>::build_minim ()
513  {
514  // compute_tree_size(); // Already done in build_euler_tour
515  int size = 2 * ctree_size - 1;
516  int logn = (int)(ceil(log((double)(size))/log(2.0)));
517  // minim.reserve(size);
518  minim = new int [logn * size]; // FIXME : Think about freeing this
519  Minim = new int* [logn];
520 
521  Minim[0] = minim;
522 
523  // Init
524  for (int i = 0; i < size - 1; ++i)
525  if (depth[euler[i]] < depth[euler[i+1]]) {
526  Minim[0][i] = i;
527  } else {
528  Minim[0][i] = i+1;
529  }
530 
531  // Minim[0][size - 1] = size - 1;
532 
533  int k;
534  for (int j = 1; j < logn; j++) {
535  k = 1 << (j - 1);
536  Minim[j] = &minim[j * size];
537  for (int i = 0; i < size; i++) {
538  if ((i + (k << 1)) >= size) {
539  //Minim[j][i] = size - 1;
540  }
541  else {
542  if (depth[euler[Minim[j - 1][i]]]
543  <= depth[euler[Minim[j - 1][i + k]]])
544  Minim[j][i] = Minim[j - 1][i];
545  else
546  Minim[j][i] = Minim[j - 1][i + k];
547  }
548  }
549  }
550 
551  } // void build_minim ()
552 
553 
554  template <class I, class N>
555  typename topo_wst<I, N>::psite topo_wst<I, N>::lca (psite a, psite b)
556  {
557  int
558  m = pos[a],
559  n = pos[b],
560  k;
561 
562  if (m == n)
563  return repr[m];
564 
565  if (m > n)
566  {
567  k = n;
568  n = m;
569  m = k;
570  }
571 
572  k = (int)(log((double)(n - m))/log(2.));
573 
574  if (depth[euler[Minim[k][m]]] < depth[euler[Minim[k][n - (1 << k)]]]) {
575  return repr[euler[Minim[k][m]]];
576  } else {
577  return repr[euler[Minim[k][n - (1 << k)]]];
578  }
579  }
580 
581 
582  template <class I, class N>
583  void topo_wst<I, N>::removeOneSonNodes(psite *p,
584  mln_ch_value(I, psite) &newPar_node)
585  {
586  node &n = nodes(*p);
587 
588  if (n.children.size() == 1) // this node has 1 son, delete it
589  {
590  n.area = -1;
591  newPar_node(*p) = n.children[0];
592  *p = n.children[0];
593  removeOneSonNodes(p, newPar_node);
594  }
595  else // there is more than one son, recursive call
596  {
597  for (unsigned i = 0; i < n.children.size(); ++i)
598  removeOneSonNodes(&(n.children[i]), newPar_node);
599  }
600  }
601 
602 
603  template <class I, class N>
604  void topo_wst<I, N>::compressTree()
605  {
606  mln_ch_value(I, psite) newPar_node;
607  initialize(newPar_node, Par_node);
608 
609  // Remove the nodes with one son
610  removeOneSonNodes(&Root, newPar_node);
611 
612  // Update the references on deleted nodes
613  mln_piter(I) p(Par_node.domain());
614  for_all(p)
615  while (nodes(Par_node(p)).area == -1)
616  Par_node(p) = newPar_node(Par_node(p));
617  }
618 
619  template <class T>
620  bool w_constructible(T &tree, typename T::psite p, typename T::psite &r)
621  {
622 
623  typedef typename T::image_t I;
624  typedef typename T::neighborhood_t N;
625 
626  const I &ima = exact(tree.ima);
627  const N &nbh = exact(tree.nbh);
628 
629  // FIXME: Should be `n' instead of `q'.
630  mln_niter(N) q(nbh, p);
631  p_set<mln_psite(I)> v;
632 
633  for_all(q)
634  // FIXME: Shouldn't it be: `ima.has(q)' instead of
635  // `ima.domain().has(q)'?
636  if (ima.domain().has(q) && ima(q) < ima(p))
637  v.insert(tree.Par_node(q));
638 
639  if (v.nsites() == 0)
640  return false;
641 
642  if (v.nsites() == 1)
643  {
644  r = v[0];
645  return true;
646  }
647 
648  mln_psite(I) c = min(ima, v);
649  mln_psite(I) cmin = c;
650 
651  typename p_set<mln_psite(I)>::fwd_piter it(v);
652  for_all(it)
653  {
654  // Can't remove the psite from the set
655  if (it == cmin)
656  continue;
657 
658  mln_psite(I) c1 = tree.lca(c, it);
659 
660  if (c1 != it)
661  c = c1;
662  }
663 
664  if (tree.nodes(c).level >= ima(p))
665  return false;
666 
667  r = c;
668  return true;
669  }
670 
671  template <class T>
672  bool w_constructible(T &tree, typename T::psite p) {
673  typename T::psite r;
674  return w_constructible(tree, p, r);
675  }
676 
677 
678 
679  template <class T>
680  typename T::image_t topological(T &tree)
681  {
682 
683  typedef typename T::image_t I;
684  typedef typename T::neighborhood_t N;
685 
686  I ima = exact(tree.ima);
687  const N &nbh = exact(tree.nbh);
688 
689  // Maxima components
690  mln_ch_value(I, bool) cmax;
691  initialize(cmax, ima);
692 
693  // Mark enqueued sites
694  mln_ch_value(I, bool) enqueued;
695  initialize(enqueued, ima);
696 
697  p_priority< mln_value(I), p_queue_fast<mln_psite(I)> > l;
698  // p_queue < psite > m;
699  std::queue<mln_psite(I)> m;
700 
701  // Flag C-maxima
702  data::fill(cmax, false);
703  data::fill(enqueued, false);
704 
705  mln_piter(I) it(tree.Par_node.domain());
706  for_all(it)
707  // if (nodes(Par_node(it.to_psite())).children.nsites() == 0)
708  if (tree.nodes(tree.Par_node(it)).children.size() == 0)
709  {
710  cmax(it) = true;
711  m.push(it);
712  }
713 
714  while (!m.empty())
715  {
716  // FIXME: Should be `n' instead of `q'.
717  mln_niter(N) q(nbh, m.front());
718  // FIXME: Shouldn't it be: `cmax.has(q)' instead of
719  // `cmax.domain().has(q)'?
720  for_all(q)
721  if (cmax.domain().has(q) && !cmax(q) && !enqueued(q))
722  {
723  enqueued(q) = true;
724  l.push(mln_max(mln_value(I)) - ima(q), q);
725  }
726  m.pop();
727  }
728 
729 
730  // Main loop
731  while (!l.is_empty())
732  {
733  mln_psite(I) x = l.front();
734  l.pop();
735  enqueued(x) = false;
736 
737  mln_psite(I) c;
738  bool is_w = w_constructible(tree, x, c);
739 
740  if (is_w)
741  {
742  ima(x) = tree.nodes(c).level;
743  tree.Par_node(x) = c;
744 
745  // if (nodes(c).children.nsites() == 0)
746  if (tree.nodes(c).children.size() == 0)
747  cmax(x) = true;
748  else
749  // if (nodes(c).children.nsites() > 1)
750  if (tree.nodes(c).children.size() == 1)
751  std::cerr << "ERREUR COMPOSANTE BRANCHE "
752  << tree.nodes(c).children.size() << std::endl;
753 
754 
755  // FIXME: Should be `n' instead of `q'.
756  mln_niter(N) q(nbh, x);
757  // FIXME: Shouldn't it be: `ima.has(q)' instead of
758  // `ima.domain().has(q)'?
759  for_all(q)
760  if (ima.domain().has(q) && !cmax(q) && !enqueued(q))
761  {
762  enqueued(q) = true;
763  l.push(mln_max(mln_value(I)) - ima(q), q); // FIXME:
764  // Just
765  // invert
766  // the
767  // priority.
768  }
769  }
770  } // while(!l.empty())
771 
772  for_all(it)
773  ima(it) = tree.nodes(tree.Par_node(it)).level;
774 
775  return ima;
776  }
777 
778 # endif // MLN_INCLUDE_ONLY
779 
780 
781  } // end of namespace mln::morpho::watershed
782 
783  } // end of namespace mln::morpho
784 
785 } // end of namespace mln
786 
787 #endif // ! MLN_MORPHO_WATERSHED_TOPOLOGICAL_HH