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