SMIL  1.0.4
DMorphoMaxTree.hpp
1 /*
2  * Copyright (c) 2011-2015, Matthieu FAESSEL and ARMINES
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  * * Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  * * Redistributions in binary form must reproduce the above copyright
11  * notice, this list of conditions and the following disclaimer in the
12  * documentation and/or other materials provided with the distribution.
13  * * Neither the name of Matthieu FAESSEL, or ARMINES nor the
14  * names of its contributors may be used to endorse or promote products
15  * derived from this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS''
18  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS AND CONTRIBUTORS BE
21  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27  * POSSIBILITY OF SUCH DAMAGE.
28  */
29 
30 #ifndef _D_MAX_TREE
31 #define _D_MAX_TREE
32 
33 #include "DMorphImageOperations.hpp" //BMI
34 #include "DMorphoHierarQ.hpp" //BMI
35 #include "Core/include/DImage.h"
36 #include "Base/include/private/DImageHistogram.hpp"
37 #include "Morpho/include/private/DMorphoMaxTreeCriteria.hpp"
38 
39 #include <complex>
40 #include <math.h>
41 
42 namespace smil
43 {
54 #ifndef SWIG
55 
56  typedef size_t Offset_T;
57  typedef UINT32 Label_T;
58 
59  template <class T, class CriterionT, class Offset_T = size_t,
60  class Label_T = UINT32>
61  class MaxTree2
62  {
63  private:
64  size_t GRAY_LEVEL_NBR;
65  Image<T> const *img;
66 
68 
69  vector<T> levels;
70  vector<Label_T> children;
71  vector<Label_T> brothers;
72  vector<CriterionT> criteria;
73  vector<Label_T> labels;
74 
75  Label_T curLabel;
76 
77  bool initialized;
78 
79  size_t imWidth;
80  size_t imHeight;
81 
82  public:
83  MaxTree2() : hq(true) // TOTO BMI
84  {
85  GRAY_LEVEL_NBR = ImDtTypes<T>::max() - ImDtTypes<T>::min() + 1;
86  // hq.reverse();// change priority order (max first)
87  // hq = HierarchicalQueue<T,Offset_T> (true);
88 
89  labels.resize(GRAY_LEVEL_NBR);
90 
91  initialized = false;
92  }
93 
94  ~MaxTree2()
95  {
96  reset();
97  }
98 
99  void reset()
100  {
101  if (!initialized)
102  return;
103 
104  levels.clear();
105  children.clear();
106  brothers.clear();
107  criteria.clear();
108  labels.clear();
109  }
110 
111  void allocatePage()
112  {
113  levels.resize(levels.size() + 1024 * 1024);
114  children.resize(children.size() + 1024 * 1024);
115  brothers.resize(brothers.size() + 1024 * 1024);
116  criteria.resize(criteria.size() + 1024 * 1024);
117  }
118 
119  T initialize(const Image<T> &imIn, Label_T *img_eti, const StrElt &se)
120  {
121  imIn.getSize(imSize);
122 
123  // BMI BEGIN
124  sePtsNbr = sePts.size();
125  dOffsets.clear();
126  sePts.clear();
127  oddSE = se.odd;
128 
129  // set an offset distance for each se point (!=0,0,0)
130  for (vector<IntPoint>::const_iterator it = se.points.begin();
131  it != se.points.end(); it++) {
132  if (it->x != 0 || it->y != 0 || it->z != 0) {
133  sePts.push_back(*it);
134  dOffsets.push_back(it->x + it->y * imSize[0] +
135  it->z * imSize[0] * imSize[1]);
136  }
137  }
138 
139  sePtsNbr = sePts.size();
140  // BMI END
141 
142  if (initialized)
143  reset();
144 
145  this->img = &imIn;
146  typename ImDtTypes<T>::lineType pix = img->getPixels();
147 
148  T minValue = ImDtTypes<T>::max();
149  T tMinV = ImDtTypes<T>::min();
150  Offset_T minOff = 0;
151  for (size_t i = 0; i < img->getPixelCount(); i++) {
152  if (pix[i] < minValue) {
153  minValue = pix[i];
154  minOff = i;
155  if (minValue == tMinV)
156  break;
157  }
158  }
159 
160  allocatePage();
161 
162  curLabel = 1;
163  levels[curLabel] = minValue;
164 
165  // BMI labels? quel rapport avec img_eti?
166  // memset(old_labels, 0, GRAY_LEVEL_NBR * sizeof(Label_T));
167 
168  img_eti[minOff] = curLabel;
169  labels[minValue] = curLabel;
170  labels[minValue] = curLabel;
171 
172  hq.initialize(*img);
173  hq.push(minValue, minOff);
174 
175  size_t x, y, z;
176  img->getCoordsFromOffset(minOff, x, y, z);
177  // std::cout<<"PUSH:offset="<<minOff<<"(x,y)="<<x<<", "<<y<<",
178  // val="<<minValue<<"\n";
179 
180  // getCriterion(curLabel).xmin = getCriterion(curLabel).xmax = x;
181  // // A voir comment on peut melanger des criteres... BMI
182  // getCriterion(curLabel).ymin = getCriterion(curLabel).ymax = y;
183  // getCriterion(curLabel).zmin = getCriterion(curLabel).zmax = z;
184 
185  getCriterion(curLabel).initialize();
186  curLabel++;
187 
188  initialized = true;
189 
190  imWidth = img->getWidth();
191  imHeight = img->getHeight();
192 
193  return minValue;
194  }
195 
196  int nextLowerLabel(T valeur)
197  {
198  if (curLabel + 256 > levels.size())
199  allocatePage();
200 
201  getLevel(curLabel) = valeur;
202  int i;
203  for (i = valeur - 1; labels[i] == 0; i--)
204  ;
205 
206  getChild(curLabel) = getChild(labels[i]);
207  getChild(labels[i]) = curLabel;
208  getBrother(curLabel) = getBrother(getChild(curLabel));
209  getBrother(getChild(curLabel)) = 0;
210  getCriterion(curLabel).reset();
211  return curLabel++;
212  }
213 
214  int nextHigherLabel(T parent_valeur, T valeur)
215  {
216  if (curLabel + 256 > levels.size())
217  allocatePage();
218 
219  getLevel(curLabel) = valeur;
220  getBrother(curLabel) = getChild(labels[parent_valeur]);
221  getChild(labels[parent_valeur]) = curLabel;
222  getCriterion(curLabel).reset();
223  return curLabel++;
224  }
225 
226  bool subFlood(typename ImDtTypes<T>::lineType imgPix, Label_T *img_eti,
227  Offset_T p, Offset_T p_suiv)
228  {
229  Label_T indice;
230 
231  if (imgPix[p_suiv] > imgPix[p]) {
232  Label_T j;
233  for (j = imgPix[p] + 1; j < imgPix[p_suiv]; j++)
234  labels[j] = 0;
235  indice = img_eti[p_suiv] = labels[j] =
236  nextHigherLabel(imgPix[p], imgPix[p_suiv]);
237 
238  } else if (labels[imgPix[p_suiv]] == 0) {
239  indice = img_eti[p_suiv] = labels[imgPix[p_suiv]] =
240  nextLowerLabel(imgPix[p_suiv]);
241  } else {
242  indice = img_eti[p_suiv] = labels[imgPix[p_suiv]];
243  }
244 
245  size_t x, y, z;
246  img->getCoordsFromOffset(p_suiv, x, y, z);
247 
248  getCriterion(indice).update(x, y, z);
249  hq.push(imgPix[p_suiv], p_suiv);
250 
251  if (imgPix[p_suiv] > imgPix[p]) {
252  hq.push(imgPix[p], p);
253  return true;
254  }
255  return false;
256  }
257 
258  void flood(const Image<T> &img, UINT *img_eti, unsigned int level)
259  {
260  Offset_T p;
261 
262  typename ImDtTypes<T>::lineType imgPix = img.getPixels();
263  size_t x0, y0, z0;
264 
265  while ((hq.getHigherLevel() >= level) && !hq.isEmpty()) {
266  p = hq.pop();
267 
268  img.getCoordsFromOffset(p, x0, y0, z0);
269 
270  bool oddLine = oddSE && ((y0) % 2);
271 
272  // not size_t in order to (possibly be negative!)
273  off_t x, y, z;
274  Offset_T p_suiv;
275 
276  for (UINT i = 0; i < sePtsNbr; i++) {
277  IntPoint &pt = sePts[i];
278  x = x0 + pt.x;
279  y = y0 + pt.y;
280  z = z0 + pt.z;
281 
282  if (oddLine)
283  x += (((y + 1) % 2) != 0);
284 
285  if (x >= 0 && x < (int) imSize[0] && y >= 0 && y < (int) imSize[1] &&
286  z >= 0 && z < (int) imSize[2]) {
287  p_suiv = p + dOffsets[i];
288  if (oddLine)
289  p_suiv += (((y + 1) % 2) != 0);
290 
291  if (img_eti[p_suiv] == 0) {
292  if (subFlood(imgPix, img_eti, p, p_suiv))
293  break;
294  }
295  }
296  } // for each ngb
297 
298  } // while hq.notEmpty
299  } // void flood
300 
301 
302 
303  protected:
304  size_t imSize[3];
305 
306  vector<IntPoint> sePts;
307  UINT sePtsNbr;
308  bool oddSE;
309  vector<int> dOffsets;
310 
311  public:
312  inline CriterionT &getCriterion(const Label_T node)
313  {
314  return criteria[node];
315  }
316 
317  inline T &getLevel(const Label_T node)
318  {
319  return levels[node];
320  }
321 
322  inline Label_T &getChild(const Label_T node)
323  {
324  return children[node];
325  }
326 
327  inline Label_T &getBrother(const Label_T node)
328  {
329  return brothers[node];
330  }
331 
332  inline Label_T getLabelMax()
333  {
334  return curLabel;
335  }
336 
337  inline int getImWidth()
338  {
339  return imWidth;
340  }
341 
342  inline int getImHeight()
343  {
344  return imHeight;
345  }
346 
347  int build(const Image<T> &img, Label_T *img_eti, const StrElt &se)
348  {
349  T minValue = initialize(img, img_eti, se);
350 
351  // BMI: dOffset already contains se information
352  flood(img, img_eti, minValue);
353  updateCriteria(labels[minValue]);
354 
355  return labels[minValue];
356  }
357 
358  // BMI (from Andres)
359  // Update criteria of a given max-tree node
360  // void updateCriteria(const int node);
361 
362  // Update criteria on a given max-tree node.// From Andres
363  //template <class T, class CriterionT, class Offset_T, class Label_T>
364  void updateCriteria(const int node)
365  {
366  Label_T child = getChild(node);
367  while (child != 0) {
368  updateCriteria(child);
369  getCriterion(node).merge(&getCriterion(child));
370  child = getBrother(child);
371  }
372  }
373  };
374 
375  // END BMI
376 
377  // NEW BMI # ##################################################
378  //(tree, transformee_node, indicatrice_node, child, stopSize, (T)0, 0,
379  // hauteur, tree.getLevel(root), tree.getLevel(root));
380  template <class T, class CriterionT, class Offset_T, class Label_T,
381  class Attr_T>
382  void ComputeDeltaUO(MaxTree2<T, CriterionT, Offset_T, Label_T> &tree,
383  T *transformee_node, Attr_T *indicatrice_node, int node,
384  int nParent, T prev_residue, Attr_T stop, UINT delta,
385  int isPrevMaxT)
386  {
387  // self,node = 1, nParent =0, stop=0, delta = 0, isPrevMaxT = 0):
388  int child; // index node
389  T current_residue;
390  UINT cNode, cParent; // attributes
391  T lNode, lParent; // node levels, the same type than input image
392 
393  // ymax-tree.getCriterion(node).ymin+1;
394  // #current criterion
395  cNode = tree.getCriterion(node).getAttributeValue();
396  // #current level
397  lNode = tree.getLevel(node);
398 
399  // ymax-tree.getCriterion(nParent).ymin+1;//
400  // #current criterion
401  cParent = tree.getCriterion(nParent).getAttributeValue();
402  // #current level
403  lParent = tree.getLevel(nParent);
404 
405  bool flag = false;
406 
407  if ((cParent - cNode) <= delta) {
408  flag = true;
409  }
410 
411  if (flag) {
412  current_residue = prev_residue + lNode - lParent;
413  } else {
414  current_residue = lNode - lParent;
415  }
416 
417  transformee_node[node] = transformee_node[nParent];
418  indicatrice_node[node] = indicatrice_node[nParent];
419 
420  int isMaxT = 0;
421 
422  if (cNode < stop) {
423  if (current_residue > transformee_node[node]) {
424  // std::cout<<"UPDATE RES\n";
425  isMaxT = 1;
426  transformee_node[node] = current_residue;
427  if (!(isPrevMaxT && flag)) {
428  indicatrice_node[node] = cNode + 1;
429  }
430  }
431  } else {
432  indicatrice_node[node] = 0;
433  }
434  child = tree.getChild(node);
435  while (child != 0) {
436  ComputeDeltaUO(tree, transformee_node, indicatrice_node, child, node,
437  current_residue, stop, delta, isMaxT);
438  child = tree.getBrother(child);
439  }
440  }
441 
442  template <class T1, class T2>
443  void compute_max(MaxTree2<T1, HeightCriterion, size_t, UINT32> &tree,
444  T1 *transformee_node, T2 *indicatrice_node, UINT32 node,
445  T2 stop, T1 max_tr, T2 max_in, T2 hauteur_parent,
446  T1 valeur_parent, T1 previous_value)
447  {
448  T1 m;
449  T1 max_node;
450  T2 max_criterion;
451  UINT32 child;
452  T2 hauteur = tree.getCriterion(node).getAttributeValue();
453  // ymax-tree.getCriterion(node).ymin+1;
454  // std::cout<<"IN COMPUTE_MAX:"<<"; node="<<node<<"\n";
455  m = (hauteur == hauteur_parent) ? tree.getLevel(node) - previous_value
456  : tree.getLevel(node) - valeur_parent;
457  if (hauteur >= stop) {
458  max_node = max_tr;
459  max_criterion = 0; // max_in;
460  transformee_node[node] = max_node;
461 
462  indicatrice_node[node] = 0;
463  child = tree.getChild(node);
464  } else {
465  if (m > max_tr) {
466  max_node = m;
467  max_criterion = hauteur;
468  } else {
469  max_node = max_tr;
470  max_criterion = max_in;
471  }
472  transformee_node[node] = max_node;
473  indicatrice_node[node] = max_criterion + 1;
474  child = tree.getChild(node);
475  }
476  if (hauteur == hauteur_parent) {
477  while (child != 0) {
478  // if(child > tree.getLabelMax()){
479  // std::cout<<"ERROR call child:"<<child<<"\n";
480  // }
481  if (hauteur_parent > stop)
482  compute_max(tree, transformee_node, indicatrice_node, child, stop,
483  max_node, max_criterion, hauteur, tree.getLevel(node),
484  previous_value);
485  else
486  compute_max(tree, transformee_node, indicatrice_node, child, stop,
487  max_node, max_criterion, hauteur,
488  tree.getLevel(node) /*valeur_parent*/, previous_value);
489  child = tree.getBrother(child);
490  }
491  } else {
492  while (child != 0) {
493  // if(child > tree.getLabelMax()){
494  // std::cout<<"ERROR call child:"<<child<<"\n";
495  //}
496 
497  compute_max(tree, transformee_node, indicatrice_node, child, stop,
498  max_node, max_criterion, hauteur, tree.getLevel(node),
499  valeur_parent);
500  child = tree.getBrother(child);
501  }
502  }
503  }
504 
505  template <class T1, class T2>
506  void compute_contrast(MaxTree2<T1, HeightCriterion, size_t, UINT32> &tree,
507  T1 *transformee_node, T2 *indicatrice_node, UINT32 root,
508  T2 stopSize, UINT delta = 0)
509  {
510  UINT32 child;
511  T2 hauteur;
512  // std::cout<<"IN compute_contrast\n";
513 
514  transformee_node[root] = 0;
515  indicatrice_node[root] = 0;
516 
517  hauteur = tree.getCriterion(root).getAttributeValue();
518  child = tree.getChild(root);
519  // ymax - tree.getCriterion(root).ymin+1;
520  if (delta == 0) {
521  while (child != 0) {
522 
523  compute_max(tree, transformee_node, indicatrice_node, child, stopSize,
524  (T1) 0, (T2) 0, hauteur, tree.getLevel(root),
525  tree.getLevel(root));
526  child = tree.getBrother(child);
527  }
528  } // END delta == 0
529  else {
530  while (child != 0) {
531  ComputeDeltaUO(tree, transformee_node, indicatrice_node, child,
532  root /*parent*/, (T1) 0 /* prev_residue*/,
533  stopSize /*stop*/, delta, 0 /*isPrevMaxT*/);
534 
535  child = tree.getBrother(child);
536  }
537  } // END dela != 0
538  }
539 
540 #endif // SWIG
541 
555  template <class T1, class T2>
556  RES_T ultimateOpen(const Image<T1> &imIn, Image<T1> &imTrans,
557  Image<T2> &imIndic, const StrElt &se = DEFAULT_SE,
558  T2 stopSize = 0, UINT delta = 0)
559  {
560  ASSERT_ALLOCATED(&imIn, &imTrans, &imIndic);
561  ASSERT_SAME_SIZE(&imIn, &imTrans, &imIndic);
562 
563  if (stopSize == 0)
564  stopSize = imIn.getHeight() - 1;
565 
566  int imSize = imIn.getPixelCount();
567  UINT *img_eti = new UINT[imSize]();
568 
570  UINT32 root = tree.build(imIn, img_eti, se);
571 
572  // std::cout<<"ULTIMATE OPEN, after tree.build"<<"NB
573  // VERTEX="<<tree.getLabelMax()<<"\n";
574  T1 *transformee_node = new T1[tree.getLabelMax()]();
575  T2 *indicatrice_node = new T2[tree.getLabelMax()]();
576  // std::cout<<"ULTIMATE OPEN, after memory allocation\n";
577  compute_contrast(tree, transformee_node, indicatrice_node, root, stopSize,
578  delta);
579 
580  typename ImDtTypes<T1>::lineType transformeePix = imTrans.getPixels();
581  typename ImDtTypes<T2>::lineType indicatricePix = imIndic.getPixels();
582 
583  for (int i = 0; i < imSize; i++) {
584  transformeePix[i] = transformee_node[img_eti[i]];
585  indicatricePix[i] = indicatrice_node[img_eti[i]];
586  }
587 
588  delete[] img_eti;
589  delete[] transformee_node;
590  delete[] indicatrice_node;
591 
592  imTrans.modified();
593  imIndic.modified();
594 
595  return RES_OK;
596  }
597 
598 #ifndef SWIG
599  // NEW BMI # ##################################################
600  //(tree, transformee_node, indicatrice_node, child, stopSize, (T)0, 0,
601  // hauteur, tree.getLevel(root), tree.getLevel(root));
602  template <class T, class CriterionT, class Offset_T, class Label_T,
603  class Attr_T>
604  void ComputeDeltaUOMSER(MaxTree2<T, CriterionT, Offset_T, Label_T> &tree,
605  T *transformee_node, Attr_T *indicatrice_node,
606  int node, int nParent, int first_ancestor,
607  Attr_T stop, UINT delta, UINT method, int isPrevMaxT,
608  UINT minArea = 0, T threshold = 0, T mymax = 0)
609  {
610  // method: 1 (MSER), 2 (RGR)
611 
612  // "node": the current node; "nParent": its direct parent (allows
613  // attribute comparison for Delta versions); "first_ancestor": the
614  // first ancestor with a different attribute (used for residue
615  // computation level(first_ancestor) - level(node) and for area stability
616  // computation
617 
618  // self,node = 1, nParent =0, stop=0, delta = 0, isPrevMaxT = 0):
619  int child; // index node
620  T current_residue, stab_residue = 0;
621  UINT hNode, hParent; // attributes
622  size_t aNode, aParent, aAncestor;
623  T lNode, lParent, lAncestor;
624  // node levels, the same type than input image
625  float stability;
626 
627  hNode = tree.getCriterion(node).getAttributeValue().H; // #current criterion
628  aNode = tree.getCriterion(node).getAttributeValue().A;
629  lNode = tree.getLevel(node); // #current level
630 
631  // #current criterion
632  hParent = tree.getCriterion(nParent).getAttributeValue().H;
633  aParent = tree.getCriterion(nParent).getAttributeValue().A;
634  aAncestor = tree.getCriterion(first_ancestor).getAttributeValue().A;
635 
636  lParent = tree.getLevel(nParent); // #current level
637  lAncestor = tree.getLevel(first_ancestor); // #current level
638 
639  bool flag = false;
640  if ((hParent - hNode) <= delta) {
641  flag = true;
642  }
643 
644  float relativeGrowthRate; // BMI RGR
645  double lgARoot = std::log((double) tree.getImWidth() * tree.getImHeight());
646  double factor;
647 
648  if (method == 2) {
649  // RGR
650  // BMI RGR La valeur max sera max/10 pour un
651  // changement d'aire de 1 a taille_im en pixels
652  factor = ImDtTypes<T>::max() / ((double) 100 * lgARoot);
653  } else if (method == 3) { // MSER_sub
654  factor = ImDtTypes<T>::max() / ((double) 100.0); // BMI
655  factor = mymax / ((double) 25.0); // BMI
656  }
657  if (flag) {
658  current_residue = lNode - lAncestor;
659  if (method == 1) {
660  // mser stability
661  stability = 1 - ((aAncestor - aNode) * 1.0 / (aAncestor));
662  stab_residue = round(current_residue * stability);
663  } else if (method == 2) { // relative growth rate
664  relativeGrowthRate =
665  factor * (std::log((double) aAncestor) - std::log((double) aNode));
666  if (current_residue > relativeGrowthRate) {
667  stab_residue = round(current_residue - relativeGrowthRate);
668  } else {
669  stab_residue = 0;
670  }
671  } // end RGR
672  else if (method == 3) { // MSER sustraire
673  stability = factor * (((aAncestor - aNode) * 1.0 / (aAncestor)));
674  if (current_residue > stability) {
675  stab_residue = round(current_residue - stability);
676  } else {
677  stab_residue = 0;
678  }
679  } // end MSER_sub
680 
681  } // if flag
682  else {
683  current_residue = (lNode - lParent);
684  if (method == 1) { // mser stability
685  // relative growth rate
686  stability = 1 - ((aParent - aNode) * 1.0 / (aParent));
687  stab_residue = round(current_residue * stability);
688  } else if (method == 2) { // relative growth rate
689  relativeGrowthRate =
690  factor * (std::log((double) aParent) - std::log((double) aNode));
691  if (current_residue > relativeGrowthRate) {
692  stab_residue = round(current_residue - relativeGrowthRate);
693  } else {
694  stab_residue = 0;
695  }
696  } // end RGR
697  else if (method == 3) {
698  stability = factor * (((aParent - aNode) * 1.0 / (aParent))); // msersub
699  if (current_residue > stability) {
700  stab_residue = round(current_residue - stability);
701  } else {
702  stab_residue = 0;
703  }
704 
705  } else {
706  std::cout << "ERROR UNKOWN METHOD\n";
707  }
708  } // if not flag
709 
710  transformee_node[node] = transformee_node[nParent];
711  indicatrice_node[node] = indicatrice_node[nParent];
712  int isMaxT = 0;
713  if (hNode < stop) {
714  if (stab_residue > transformee_node[node] && stab_residue > threshold &&
715  aNode > minArea) {
716  isMaxT = 1;
717  transformee_node[node] = stab_residue;
718 
719  if (!(isPrevMaxT && flag)) {
720  indicatrice_node[node] = hNode + 1;
721  }
722  }
723  } else {
724  indicatrice_node[node] = 0;
725  }
726  child = tree.getChild(node);
727  while (child != 0) {
728  if (flag && (hNode < stop)) {
729  ComputeDeltaUOMSER(tree, transformee_node, indicatrice_node, child,
730  node, first_ancestor, stop, delta, method, isMaxT,
731  minArea, threshold, mymax);
732  } else {
733  ComputeDeltaUOMSER(tree, transformee_node, indicatrice_node, child,
734  node, nParent, stop, delta, method, isMaxT, minArea,
735  threshold, mymax);
736  }
737  child = tree.getBrother(child);
738  }
739  }
740 
741  inline void computeFillAspectRatioFactor(UINT wNode, UINT cNode, UINT area,
742  UINT width, UINT height,
743  float &fillRatio, float &AspectRatio)
744  {
745  // compute fillRatio and AspectRatio
746  UINT minHW, maxHW;
747  minHW = MIN(wNode, cNode);
748  maxHW = MAX(wNode, cNode);
749  fillRatio = area * 1.0 / (wNode * cNode * 1.0);
750  AspectRatio = minHW * 1.0 / maxHW;
751 
752  if (AspectRatio <= 0.4) // && fillRatio < 0.4)
753  AspectRatio = 0.0;
754  else
755  AspectRatio = std::pow(AspectRatio, 1.0 / 3);
756 
757  if (fillRatio <= 0.2 || fillRatio >= 0.9)
758  fillRatio = 0.0;
759  else {
760  fillRatio = abs(fillRatio - 0.55);
761  fillRatio = std::pow((1.0 - (fillRatio * 1.0 / 0.35)), 1.0 / 3);
762  }
763 
764  if (AspectRatio <= 0.4 && fillRatio >= 0.4) { // a verifier
765  AspectRatio = 1; // 0.9
766  fillRatio = 1;
767  } // 0.9
768 
769  if (area < 20 || area > (0.9 * width * height) || cNode < 5) {
770  //|| cNode > (tree.getImHeight()/3)){
771  AspectRatio = 0.0;
772  fillRatio = 0.0;
773  }
774  }
775 
776  // NEW BMI # ##################################################
777  //(tree, transformee_node, indicatrice_node, child, stopSize, (T)0, 0,
778  // hauteur, tree.getLevel(root), tree.getLevel(root));
779  template <class T, class CriterionT, class Offset_T, class Label_T,
780  class Attr_T>
782  T *transformee_node, Attr_T *indicatrice_node,
783  int node, int nParent, int first_ancestor,
784  Attr_T stop, UINT delta, int isPrevMaxT)
785  {
786  // "node": the current node; "nParent": its direct parent (allows
787  // attribute comparison for Delta versions); "first_ancestor": the
788  // first ancestor with a different attribute (used for residue
789  // computation level(first_ancestor) - level(node) and for area stability
790  // computation
791 
792  // self,node = 1, nParent =0, stop=0, delta = 0, isPrevMaxT = 0):
793  int child; // index node
794  T current_residue, stab_residue;
795  UINT hNode, hParent, wNode; // attributes
796  size_t aNode, aParent, aAncestor;
797  T lNode, lParent, lAncestor;
799  // node levels, the same type than input image
800  float stability, fillRatio, AspectRatio, fac;
801 
802  hNode = tree.getCriterion(node).getAttributeValue().H; // #current criterion
803  wNode = tree.getCriterion(node).getAttributeValue().W; // #width
804  aNode = tree.getCriterion(node).getAttributeValue().A;
805  lNode = tree.getLevel(node); // #current level
806 
807  hParent = tree.getCriterion(nParent).getAttributeValue().H;
808  // #current criterion
809  // wParent =
810  // tree.getCriterion(nParent).xmax-tree.getCriterion(nParent).xmin+1;//
811  // #width
812  aParent = tree.getCriterion(nParent).getAttributeValue().A;
813  aAncestor = tree.getCriterion(first_ancestor).getAttributeValue().A;
814  lParent = tree.getLevel(nParent); // #current level
815  lAncestor = tree.getLevel(first_ancestor); // #current level
816 
817  bool flag = false;
818  if ((hParent - hNode) <= delta) {
819  flag = true;
820  }
821 
822  computeFillAspectRatioFactor(wNode, hNode, aNode, tree.getImWidth(),
823  tree.getImHeight(), fillRatio, AspectRatio);
824 
825  if (flag) { // no significant attribute change
826  stability =
827  std::pow((1.0 - ((aAncestor - aNode) * 1.0 / aAncestor)), 1.0 / 3);
828  fac = (stability * AspectRatio * fillRatio);
829  current_residue = lNode - lAncestor;
830  stab_residue = round(current_residue * fac);
831  } else {
832  stability =
833  std::pow((1.0 - ((aParent - aNode) * 1.0 / aParent)), 1.0 / 3);
834  fac = (stability * AspectRatio * fillRatio);
835  current_residue = (lNode - lParent);
836  stab_residue = round(current_residue * fac);
837  }
838 
839  transformee_node[node] = transformee_node[nParent];
840  indicatrice_node[node] = indicatrice_node[nParent];
841 
842  int isMaxT = 0;
843  if (hNode < stop) {
844  if (stab_residue > transformee_node[node]) {
845  isMaxT = 1;
846  transformee_node[node] = stab_residue;
847 
848  if (!(isPrevMaxT && flag)) {
849  indicatrice_node[node] = hNode + 1;
850  }
851  }
852  } else
853  indicatrice_node[node] = 0;
854 
855  child = tree.getChild(node);
856  while (child != 0) {
857  if (flag && (hNode < stop)) {
858  ComputeDeltaUOMSERSC(tree, transformee_node, indicatrice_node, child,
859  node, first_ancestor, stop, delta, isMaxT);
860  } else {
861  ComputeDeltaUOMSERSC(tree, transformee_node, indicatrice_node, child,
862  node, nParent, stop, delta, isMaxT);
863  }
864  child = tree.getBrother(child);
865  }
866  }
867 
868  template <class T1, class T2>
869  void compute_contrast_MSER(MaxTree2<T1, HWACriterion, size_t, UINT32> &tree,
870  T1 *transformee_node, T2 *indicatrice_node,
871  UINT32 root, T2 stopSize, UINT delta = 0,
872  UINT method = 2, UINT minArea = 0,
873  T1 threshold = 0, bool use_textShape = 0)
874  {
875  int child;
876  // UINT hauteur;
877 
878  transformee_node[root] = 0;
879  indicatrice_node[root] = 0;
880 
881  // tree.updateCriteria(root);
882  // already in tree building function
883  // hauteur = tree.getCriterion(root).ymax - tree.getCriterion(root).ymin+1;
884  child = tree.getChild(root);
885 
886  // BEGIN COMPUTE DYNAMIC, BMI
887 
888  UINT32 mynode;
889  T1 mylevel, mymax;
890  mymax = 0;
891  for (mynode = 0; mynode < tree.getLabelMax(); mynode++) {
892  mylevel = tree.getLevel(mynode);
893  if (mylevel > mymax) {
894  mymax = mylevel;
895  }
896  }
897  std::cout << "mymax=" << mymax << "\n";
898  // END COMPUTE DYNAMIC, BMI
899  while (child != 0) {
900  if (!use_textShape)
901  ComputeDeltaUOMSER(tree, transformee_node, indicatrice_node, child,
902  root /*parent*/, root /*first_ancestor*/,
903  stopSize /*stop*/, delta, method, 0 /*isPrevMaxT*/,
904  minArea, threshold, mymax);
905 
906  else {
907  ComputeDeltaUOMSERSC(tree, transformee_node, indicatrice_node, child,
908  root /*parent*/, root /*first_ancestor*/,
909  stopSize /*stop*/, delta, 0 /*isPrevMaxT*/);
910  }
911  child = tree.getBrother(child);
912  }
913  }
914 
915 #endif // SWIG
916 
917  template <class T1, class T2>
918  RES_T ultimateOpenMSER(const Image<T1> &imIn, Image<T1> &imTrans,
919  Image<T2> &imIndic, const StrElt &se = DEFAULT_SE,
920  T2 stopSize = 0, UINT delta = 0, UINT method = 2,
921  UINT minArea = 0, T1 threshold = 0,
922  bool use_textShape = 0)
923  {
924  ASSERT_ALLOCATED(&imIn, &imTrans, &imIndic);
925  ASSERT_SAME_SIZE(&imIn, &imTrans, &imIndic);
926 
927  int imSize = imIn.getPixelCount();
928  UINT *img_eti = new UINT[imSize]();
929 
930  MaxTree2<T1, HWACriterion> tree;
931  int root = tree.build(imIn, img_eti, se);
932 
933  if (stopSize == 0) {
934  stopSize = imIn.getHeight() - 1;
935  }
936 
937  T1 *transformee_node = new T1[tree.getLabelMax()]();
938  T2 *indicatrice_node = new T2[tree.getLabelMax()]();
939 
940  compute_contrast_MSER(tree, transformee_node, indicatrice_node, root,
941  stopSize, delta, method, minArea, threshold,
942  use_textShape);
943 
944  typename ImDtTypes<T1>::lineType transformeePix = imTrans.getPixels();
945  typename ImDtTypes<T2>::lineType indicatricePix = imIndic.getPixels();
946 
947  for (int i = 0; i < imSize; i++) {
948  transformeePix[i] = transformee_node[img_eti[i]];
949  indicatricePix[i] = indicatrice_node[img_eti[i]];
950  }
951 
952  delete[] img_eti;
953  delete[] transformee_node;
954  delete[] indicatrice_node;
955 
956  imTrans.modified();
957  imIndic.modified();
958 
959  return RES_OK;
960  }
961 
962 #ifndef SWIG
963 
964  template <class T, class CriterionT, class Offset_T, class Label_T,
965  class Attr_T>
966  void processMaxTree(MaxTree2<T, CriterionT, Offset_T, Label_T> &tree,
967  Label_T node, T *lut_out, T previousLevel, Attr_T stop)
968  {
969  // MORPHEE_ENTER_FUNCTION("s_OpeningTree::computeMaxTree");
970  Label_T child;
971  T nodeLevel = tree.getLevel(node);
972 
973  T currentLevel = (tree.getCriterion(node).getAttributeValue() < stop)
974  ? previousLevel
975  : nodeLevel;
976 
977  lut_out[node] = currentLevel;
978 
979  child = tree.getChild(node);
980  while (child != 0) {
981  processMaxTree(tree, child, lut_out, currentLevel, stop);
982  child = tree.getBrother(child);
983  }
984  }
985 
986  template <class T, class CriterionT, class Offset_T, class Label_T,
987  class Attr_T>
988  void
989  compute_AttributeOpening(MaxTree2<T, CriterionT, Offset_T, Label_T> &tree,
990  T *lut_node, Label_T root, Attr_T stopSize)
991  {
992  Label_T child;
993 
994  lut_node[root] = tree.getLevel(root);
995 
996  // tree.updateCriteria(root);
997 
998  // DEBUG
999  // Label_T lab;
1000 
1001  // for(lab = 1; lab < tree.getLabelMax(); lab ++){
1002  // std::cout<<"lab="<<lab<<",
1003  // att="<<tree.getCriterion(lab).getAttributeValue()<<"\n";
1004  // }
1005 
1006  // END DEBUG
1007  child = tree.getChild(root);
1008 
1009  while (child != 0) {
1010  processMaxTree(tree, child, lut_node, tree.getLevel(root), stopSize);
1011  child = tree.getBrother(child);
1012  }
1013 
1014  } // compute_AttributeOpening
1015 
1016  template <class T, class CriterionT, class Offset_T = size_t,
1017  class Label_T = UINT32>
1018  RES_T attributeOpen(const Image<T> &imIn, Image<T> &imOut, size_t stopSize,
1019  const StrElt &se)
1020  {
1021  ASSERT_ALLOCATED(&imIn, &imOut);
1022  ASSERT_SAME_SIZE(&imIn, &imOut);
1023 
1024  size_t imSize = imIn.getPixelCount();
1025  Label_T *img_eti = new Label_T[imSize]();
1026 
1027  MaxTree2<T, CriterionT> tree;
1028  Label_T root = tree.build(imIn, img_eti, se);
1029 
1030  // BEGIN BMI, DEBUG
1031  // for(size_t i=0;i<imSize;i++) {
1032  // if(i%5 == 0){
1033  // std::cout<<"\n";
1034  // }
1035  // std::cout<<img_eti[i]<<",";
1036  // }
1037  // END BEGIN BMI, DEBUG
1038  T *out_node = new T[tree.getLabelMax()]();
1039 
1040  compute_AttributeOpening(tree, out_node, root, stopSize);
1041 
1042  typename ImDtTypes<T>::lineType outPix = imOut.getPixels();
1043 
1044  for (size_t i = 0; i < imSize; i++)
1045  outPix[i] = out_node[img_eti[i]];
1046 
1047  delete[] img_eti;
1048  delete[] out_node;
1049 
1050  imOut.modified();
1051 
1052  return RES_OK;
1053  }
1054 
1055 #endif // SWIG
1056 
1067  template <class T>
1068  RES_T heightOpen(const Image<T> &imIn, size_t stopSize, Image<T> &imOut,
1069  const StrElt &se = DEFAULT_SE)
1070  {
1071  return attributeOpen<T, HeightCriterion>(imIn, imOut, stopSize, se);
1072  } // END heightOpen
1073 
1084  template <class T>
1085  RES_T heightClose(const Image<T> &imIn, size_t stopSize, Image<T> &imOut,
1086  const StrElt &se = DEFAULT_SE)
1087  {
1088  ASSERT_ALLOCATED(&imIn, &imOut);
1089  ASSERT_SAME_SIZE(&imIn, &imOut);
1090 
1091  ImageFreezer freeze(imOut);
1092 
1093  Image<T> tmpIm(imIn);
1094  inv(imIn, tmpIm);
1095  RES_T res = attributeOpen<T, HeightCriterion>(tmpIm, imOut, stopSize, se);
1096  inv(imOut, imOut);
1097 
1098  return res;
1099  } // END heightClose
1100 
1111  template <class T>
1112  RES_T widthOpen(const Image<T> &imIn, size_t stopSize, Image<T> &imOut,
1113  const StrElt &se = DEFAULT_SE)
1114  {
1115  return attributeOpen<T, WidthCriterion>(imIn, imOut, stopSize, se);
1116  } // END widthOpen
1117 
1128  template <class T>
1129  RES_T widthClose(const Image<T> &imIn, size_t stopSize, Image<T> &imOut,
1130  const StrElt &se = DEFAULT_SE)
1131  {
1132  ASSERT_ALLOCATED(&imIn, &imOut);
1133  ASSERT_SAME_SIZE(&imIn, &imOut);
1134 
1135  ImageFreezer freeze(imOut);
1136 
1137  Image<T> tmpIm(imIn);
1138  inv(imIn, tmpIm);
1139  RES_T res = attributeOpen<T, WidthCriterion>(tmpIm, imOut, stopSize, se);
1140  inv(imOut, imOut);
1141 
1142  return res;
1143  } // END widthClose
1144 
1155  template <class T>
1156  RES_T areaOpen(const Image<T> &imIn, size_t stopSize, Image<T> &imOut,
1157  const StrElt &se = DEFAULT_SE)
1158  {
1159  return attributeOpen<T, AreaCriterion>(imIn, imOut, stopSize, se);
1160  }
1161 
1172  template <class T>
1173  RES_T areaClose(const Image<T> &imIn, size_t stopSize, Image<T> &imOut,
1174  const StrElt &se = DEFAULT_SE)
1175  {
1176  ASSERT_ALLOCATED(&imIn, &imOut);
1177  ASSERT_SAME_SIZE(&imIn, &imOut);
1178 
1179  ImageFreezer freeze(imOut);
1180 
1181  Image<T> tmpIm(imIn);
1182  inv(imIn, tmpIm);
1183  RES_T res = attributeOpen<T, AreaCriterion>(tmpIm, imOut, stopSize, se);
1184  inv(imOut, imOut);
1185 
1186  return res;
1187  }
1188 
1191 } // namespace smil
1192 
1193 #endif // _D_MAX_TREE_HPP
void getCoordsFromOffset(size_t off, size_t &x, size_t &y, size_t &z) const
Get x,y(,z) coordinates for a given offset.
Definition: DBaseImage.h:291
void getSize(size_t *w, size_t *h, size_t *d) const
Get image size.
Definition: DBaseImage.h:118
size_t getWidth() const
Get image width.
Definition: DBaseImage.h:80
size_t getPixelCount() const
Get the number of pixels.
Definition: DBaseImage.h:160
size_t getHeight() const
Get image height.
Definition: DBaseImage.h:85
Definition: DMorphoHierarQ.hpp:143
Definition: DBaseImage.h:386
Main Image class.
Definition: DImage.hpp:57
virtual void modified()
Trigger modified event (allows to force display update)
lineType getPixels() const
Get the pixels as a 1D array.
Definition: DImage.hpp:105
Definition: DMorphoMaxTree.hpp:62
Base structuring element.
Definition: DStructuringElement.h:68
RES_T log(const Image< T1 > &imIn, Image< T2 > &imOut, int base=0)
log() - Logarithm of an image
Definition: DImageArith.hpp:854
RES_T inv(const Image< T > &imIn, Image< T > &imOut)
inv() - Invert an image.
Definition: DImageArith.hpp:70
RES_T pow(const Image< T1 > &imIn, Image< T2 > &imOut, double exponent=2)
pow() - power of an image
Definition: DImageArith.hpp:905
RES_T threshold(const Image< T > &imIn, T minVal, T maxVal, T_out trueVal, T_out falseVal, Image< T_out > &imOut)
threshold() - Image threshold
Definition: DImageHistogram.hpp:269
RES_T widthOpen(const Image< T > &imIn, size_t stopSize, Image< T > &imOut, const StrElt &se=DEFAULT_SE)
Image opening based on width attribute.
Definition: DMorphoMaxTree.hpp:1112
RES_T ultimateOpen(const Image< T1 > &imIn, Image< T1 > &imTrans, Image< T2 > &imIndic, const StrElt &se=DEFAULT_SE, T2 stopSize=0, UINT delta=0)
Ultimate Opening using the max-trees.
Definition: DMorphoMaxTree.hpp:556
RES_T areaOpen(const Image< T > &imIn, size_t stopSize, Image< T > &imOut, const StrElt &se=DEFAULT_SE)
Image opening based on area attribute.
Definition: DMorphoMaxTree.hpp:1156
RES_T areaClose(const Image< T > &imIn, size_t stopSize, Image< T > &imOut, const StrElt &se=DEFAULT_SE)
Image closing based on area attribute.
Definition: DMorphoMaxTree.hpp:1173
RES_T widthClose(const Image< T > &imIn, size_t stopSize, Image< T > &imOut, const StrElt &se=DEFAULT_SE)
Image opening based on width attribute.
Definition: DMorphoMaxTree.hpp:1129
void ComputeDeltaUOMSERSC(MaxTree2< T, CriterionT, Offset_T, Label_T > &tree, T *transformee_node, Attr_T *indicatrice_node, int node, int nParent, int first_ancestor, Attr_T stop, UINT delta, int isPrevMaxT)
Definition: DMorphoMaxTree.hpp:781
RES_T heightOpen(const Image< T > &imIn, size_t stopSize, Image< T > &imOut, const StrElt &se=DEFAULT_SE)
Image opening based on height attribute.
Definition: DMorphoMaxTree.hpp:1068
RES_T heightClose(const Image< T > &imIn, size_t stopSize, Image< T > &imOut, const StrElt &se=DEFAULT_SE)
Image closing based on height attribute.
Definition: DMorphoMaxTree.hpp:1085
size_t area(const Image< T > &imIn)
area() - Area of an image
Definition: DMeasures.hpp:91
Definition: DTypes.hpp:88