SMIL  1.0.4
AreaOpeningMaxTree.hpp
1 #ifndef __FAST_AREA_OPENIN_MAX_TREE_T_HPP__
2 #define __FAST_AREA_OPENIN_MAX_TREE_T_HPP__
3 
4 #include "Core/include/DCore.h"
5 
6 // Interface to SMIL Vincent Morard
7 // Date : 7 march 2011
8 
9 /* maxtree3a.c
10  * May 26, 2005 Erik R. Urbach
11  * Email: erik@cs.rug.nl
12  * Max-tree with a single attribute parameter and an optional template
13  * Attribute: I/(A^2) (default) and others (start program without arguments for
14  * a complete list of attributes available)
15  * Decision: Min, Direct, Max, Subtractive (default)
16  * Input images: raw (P5) and plain (P2) PGM 8-bit gray-scale images
17  * Output image: raw (P5) PGM 8-bit gray-scale image
18  * Compilation: gcc -ansi -pedantic -Wall -O3 -o maxtree3a maxtree3a.c
19  *
20  * Related papers:
21  * [1] E. J. Breen and R. Jones.
22  * Attribute openings, thinnings and granulometries.
23  * Computer Vision and Image Understanding.
24  * Vol.64, No.3, Pages 377-389, 1996.
25  * [2] P. Salembier and A. Oliveras and L. Garrido.
26  * Anti-extensive connected operators for image and sequence processing.
27  * IEEE Transactions on Image Processing,
28  * Vol.7, Pages 555-570, 1998.
29  * [3] E. R. Urbach and M. H. F. Wilkinson.
30  * Shape-Only Granulometries and Grey-Scale Shape Filters.
31  * Proceedings of the ISMM2002,
32  * Pages 305-314, 2002.
33  * [4] E. R. Urbach and J. B. T. M. Roerdink and M. H. F. Wilkinson.
34  * Connected Rotation-Invariant Size-Shape Granulometries.
35  * Proceedings of the 17th Int. Conf. Pat. Rec.,
36  * Vol.1, Pages 688-691, 2004.
37  */
38 
39 namespace smil
40 {
41 #define NUMLEVELS 256
42 #define CONNECTIVITY 4
43 #ifdef PI
44 #undef PI
45 #endif
46 #define PI 3.14159265358979323846
47 #define bzero(b, len) (memset((b), '\0', (len)), (void) 0)
48 
49  typedef unsigned char ubyte;
50  typedef unsigned int uint;
51  typedef unsigned long ulong;
52 
53 #ifdef MIN
54 #undef MIN
55 #endif
56 #define MIN(a, b) ((a <= b) ? (a) : (b))
57 #ifdef MAX
58 #undef MAX
59 #endif
60 #define MAX(a, b) ((a >= b) ? (a) : (b))
61 
62  typedef struct ImageGray ImageGray;
63 
64  struct ImageGray {
65  ulong Width;
66  ulong Height;
67  ubyte *Pixmap;
68  };
69 
70  typedef struct HQueue {
71  ulong *Pixels;
72  ulong Head;
73  ulong Tail; /* First free place in queue, or -1 when the queue is full */
74  } HQueue;
75 
76  typedef struct MaxNode MaxNode;
77 
78  struct MaxNode {
79  ulong Parent;
80  ulong Area;
81  void *Attribute;
82  ubyte Level;
83  ubyte NewLevel; /* gray level after filtering */
84  };
85 
86 /* Status stores the information of the pixel status: the pixel can be
87  * NotAnalyzed, InTheQueue or assigned to node k at level h. In this
88  * last case Status(p)=k. */
89 #define ST_NotAnalyzed -1
90 #define ST_InTheQueue -2
91 
92  typedef struct MaxTree MaxTree;
93 
94  struct MaxTree {
95  long *Status;
96  ulong *NumPixelsBelowLevel;
97  ulong *NumNodesAtLevel; /* Number of nodes C^k_h at level h */
98  MaxNode *Nodes;
99  void *(*NewAuxData)(ulong, ulong);
100  void (*AddToAuxData)(void *, ulong, ulong);
101  void (*MergeAuxData)(void *, void *);
102  void (*DeleteAuxData)(void *);
103  };
104 
105  void MaxTreeDelete(MaxTree *mt);
106 
107  /****** Typedefs and functions for area attributes
108  * ******************************/
109 
110  typedef struct AreaData {
111  ulong Area;
112  } AreaData;
113 
114  void *NewAreaData(SMIL_UNUSED ulong x, SMIL_UNUSED ulong y)
115  {
116  AreaData *areadata;
117 
118  areadata = (AreaData *) malloc(sizeof(AreaData));
119  areadata->Area = 1;
120  return (areadata);
121  } /* NewAreaData */
122 
123  void DeleteAreaData(void *areaattr)
124  {
125  free(areaattr);
126  } /* DeleteAreaData */
127 
128  void AddToAreaData(void *areaattr, SMIL_UNUSED ulong x, SMIL_UNUSED ulong y)
129  {
130  AreaData *areadata = (AreaData *) areaattr;
131 
132  areadata->Area++;
133  } /* AddToAreaData */
134 
135  void MergeAreaData(void *areaattr, void *childattr)
136  {
137  AreaData *areadata = (AreaData *) areaattr;
138  AreaData *childdata = (AreaData *) childattr;
139 
140  areadata->Area += childdata->Area;
141  } /* MergeAreaData */
142 
143  double AreaAttribute(void *areaattr)
144  {
145  AreaData *areadata = (AreaData *) areaattr;
146  double area;
147 
148  area = areadata->Area;
149  return (area);
150  } /* AreaAttribute */
151 
152  /****** Typedefs and functions for minimum enclosing rectangle attributes
153  * *******/
154 
155  typedef struct EnclRectData {
156  ulong MinX;
157  ulong MinY;
158  ulong MaxX;
159  ulong MaxY;
160  } EnclRectData;
161 
162  void *NewEnclRectData(ulong x, ulong y)
163  {
164  EnclRectData *rectdata;
165 
166  rectdata = (EnclRectData *) malloc(sizeof(EnclRectData));
167  rectdata->MinX = rectdata->MaxX = x;
168  rectdata->MinY = rectdata->MaxY = y;
169  return (rectdata);
170  } /* NewEnclRectData */
171 
172  void DeleteEnclRectData(void *rectattr)
173  {
174  free(rectattr);
175  } /* DeleteEnclRectData */
176 
177  void AddToEnclRectData(void *rectattr, ulong x, ulong y)
178  {
179  EnclRectData *rectdata = (EnclRectData *) rectattr;
180 
181  rectdata->MinX = MIN(rectdata->MinX, x);
182  rectdata->MinY = MIN(rectdata->MinY, y);
183  rectdata->MaxX = MAX(rectdata->MaxX, x);
184  rectdata->MaxY = MAX(rectdata->MaxY, y);
185  } /* AddToEnclRectData */
186 
187  void MergeEnclRectData(void *rectattr, void *childattr)
188  {
189  EnclRectData *rectdata = (EnclRectData *) rectattr;
190  EnclRectData *childdata = (EnclRectData *) childattr;
191 
192  rectdata->MinX = MIN(rectdata->MinX, childdata->MinX);
193  rectdata->MinY = MIN(rectdata->MinY, childdata->MinY);
194  rectdata->MaxX = MAX(rectdata->MaxX, childdata->MaxX);
195  rectdata->MaxY = MAX(rectdata->MaxY, childdata->MaxY);
196  } /* MergeEnclRectData */
197 
198  double EnclRectAreaAttribute(void *rectattr)
199  {
200  EnclRectData *rectdata = (EnclRectData *) rectattr;
201  double area;
202 
203  area = (rectdata->MaxX - rectdata->MinX + 1) *
204  (rectdata->MaxY - rectdata->MinY + 1);
205  return (area);
206  } /* EnclRectAreaAttribute */
207 
208  double EnclRectDiagAttribute(void *rectattr)
209  /* Computes the square of the length of the diagonal */
210  {
211  EnclRectData *rectdata = (EnclRectData *) rectattr;
212  double minx, miny, maxx, maxy, l;
213 
214  minx = rectdata->MinX;
215  miny = rectdata->MinY;
216  maxx = rectdata->MaxX;
217  maxy = rectdata->MaxY;
218  l = (maxx - minx + 1) * (maxx - minx + 1) +
219  (maxy - miny + 1) * (maxy - miny + 1);
220  return (l);
221  } /* EnclRectDiagAttribute */
222 
223  /****** Typedefs and functions for moment of inertia attributes
224  * **************************/
225 
226  typedef struct InertiaData {
227  ulong Area;
228  double SumX, SumY, SumX2, SumY2;
229  } InertiaData;
230 
231  void *NewInertiaData(ulong x, ulong y)
232  {
233  InertiaData *inertiadata;
234 
235  inertiadata = (InertiaData *) malloc(sizeof(InertiaData));
236  inertiadata->Area = 1;
237  inertiadata->SumX = x;
238  inertiadata->SumY = y;
239  inertiadata->SumX2 = x * x;
240  inertiadata->SumY2 = y * y;
241  return (inertiadata);
242  } /* NewInertiaData */
243 
244  void DeleteInertiaData(void *inertiaattr)
245  {
246  free(inertiaattr);
247  } /* DeleteInertiaData */
248 
249  void AddToInertiaData(void *inertiaattr, ulong x, ulong y)
250  {
251  InertiaData *inertiadata = (InertiaData *) inertiaattr;
252 
253  inertiadata->Area++;
254  inertiadata->SumX += x;
255  inertiadata->SumY += y;
256  inertiadata->SumX2 += x * x;
257  inertiadata->SumY2 += y * y;
258  } /* AddToInertiaData */
259 
260  void MergeInertiaData(void *inertiaattr, void *childattr)
261  {
262  InertiaData *inertiadata = (InertiaData *) inertiaattr;
263  InertiaData *childdata = (InertiaData *) childattr;
264 
265  inertiadata->Area += childdata->Area;
266  inertiadata->SumX += childdata->SumX;
267  inertiadata->SumY += childdata->SumY;
268  inertiadata->SumX2 += childdata->SumX2;
269  inertiadata->SumY2 += childdata->SumY2;
270  } /* MergeInertiaData */
271 
272  double InertiaAttribute(void *inertiaattr)
273  {
274  InertiaData *inertiadata = (InertiaData *) inertiaattr;
275  double area, inertia;
276 
277  area = inertiadata->Area;
278  inertia = inertiadata->SumX2 + inertiadata->SumY2 -
279  (inertiadata->SumX * inertiadata->SumX +
280  inertiadata->SumY * inertiadata->SumY) /
281  area +
282  area / 6.0;
283  return (inertia);
284  } /* InertiaAttribute */
285 
286  double InertiaDivA2Attribute(void *inertiaattr)
287  {
288  InertiaData *inertiadata = (InertiaData *) inertiaattr;
289  double inertia, area;
290 
291  area = (double) (inertiadata->Area);
292  inertia = inertiadata->SumX2 + inertiadata->SumY2 -
293  (inertiadata->SumX * inertiadata->SumX +
294  inertiadata->SumY * inertiadata->SumY) /
295  area +
296  area / 6.0;
297  return (inertia * 2.0 * PI / (area * area));
298  } /* InertiaDivA2Attribute */
299 
300  double MeanXAttribute(void *inertiaattr)
301  {
302  InertiaData *inertiadata = (InertiaData *) inertiaattr;
303  double area, sumx;
304 
305  area = inertiadata->Area;
306  sumx = inertiadata->SumX;
307  return (sumx / area);
308  } /* MeanXAttribute */
309 
310  double MeanYAttribute(void *inertiaattr)
311  {
312  InertiaData *inertiadata = (InertiaData *) inertiaattr;
313  double area, sumy;
314 
315  area = inertiadata->Area;
316  sumy = inertiadata->SumY;
317  return (sumy / area);
318  } /* MeanYAttribute */
319 
320  /****** Image create/read/write functions ******************************/
321 
322  ImageGray *ImageGrayCreate(ulong width, ulong height)
323  {
324  ImageGray *img;
325 
326  img = (ImageGray *) malloc(sizeof(ImageGray));
327  if (img == NULL)
328  return (NULL);
329  img->Width = width;
330  img->Height = height;
331  img->Pixmap = (ubyte *) malloc(width * height);
332  if (img->Pixmap == NULL) {
333  free(img);
334  return (NULL);
335  }
336  return (img);
337  } /* ImageGrayCreate */
338 
339  void ImageGrayDelete(ImageGray *img)
340  {
341  free(img->Pixmap);
342  free(img);
343  } /* ImageGrayDelete */
344 
345  void ImageGrayInit(ImageGray *img, ubyte h)
346  {
347  memset(img->Pixmap, h, (img->Width) * (img->Height));
348  } /* ImageGrayInit */
349 
350  /****** Max-tree routines ******************************/
351 
352  HQueue *HQueueCreate(ulong imgsize, ulong *numpixelsperlevel)
353  {
354  HQueue *hq;
355  int i;
356 
357  hq = (HQueue *) calloc(NUMLEVELS, sizeof(HQueue));
358  if (hq == NULL)
359  return (NULL);
360  hq->Pixels = (ulong *) calloc(imgsize, sizeof(ulong));
361  if (hq->Pixels == NULL) {
362  free(hq);
363  return (NULL);
364  }
365  hq->Head = hq->Tail = 0;
366  for (i = 1; i < NUMLEVELS; i++) {
367  hq[i].Pixels = hq[i - 1].Pixels + numpixelsperlevel[i - 1];
368  hq[i].Head = hq[i].Tail = 0;
369  }
370  return (hq);
371  } /* HQueueCreate */
372 
373  void HQueueDelete(HQueue *hq)
374  {
375  free(hq->Pixels);
376  free(hq);
377  } /* HQueueDelete */
378 
379 #define HQueueFirst(hq, h) (hq[h].Pixels[hq[h].Head++])
380 #define HQueueAdd(hq, h, p) hq[h].Pixels[hq[h].Tail++] = p
381 #define HQueueNotEmpty(hq, h) (hq[h].Head != hq[h].Tail)
382 
383  int GetNeighbors(ubyte *shape, ulong imgwidth, ulong imgsize, ulong p,
384  ulong *neighbors)
385  {
386  ulong x;
387  int n = 0;
388 
389  x = p % imgwidth;
390  if ((x < (imgwidth - 1)) && (shape[p + 1]))
391  neighbors[n++] = p + 1;
392  if ((p >= imgwidth) && (shape[p - imgwidth]))
393  neighbors[n++] = p - imgwidth;
394  if ((x > 0) && (shape[p - 1]))
395  neighbors[n++] = p - 1;
396  p += imgwidth;
397  if ((p < imgsize) && (shape[p]))
398  neighbors[n++] = p;
399  return (n);
400  } /* GetNeighbors */
401 
402  int MaxTreeFlood(MaxTree *mt, HQueue *hq, ulong *numpixelsperlevel,
403  bool *nodeatlevel, ImageGray *img, ubyte *shape, int h,
404  ulong *thisarea, void **thisattr)
405  /* Returns value >=NUMLEVELS if error */
406  {
407  ulong neighbors[CONNECTIVITY];
408  ubyte *pixmap;
409  void *attr = NULL, *childattr;
410  ulong imgwidth, imgsize, p, q, idx, x, y;
411  ulong area = *thisarea, childarea;
412  MaxNode *node;
413  int numneighbors, i;
414  int m;
415 
416  imgwidth = img->Width;
417  imgsize = imgwidth * (img->Height);
418  pixmap = img->Pixmap;
419  while (HQueueNotEmpty(hq, h)) {
420  area++;
421  p = HQueueFirst(hq, h);
422  x = p % imgwidth;
423  y = p / imgwidth;
424  if (attr)
425  mt->AddToAuxData(attr, x, y);
426  else {
427  attr = mt->NewAuxData(x, y);
428  if (attr == NULL)
429  return (NUMLEVELS);
430  if (*thisattr)
431  mt->MergeAuxData(attr, *thisattr);
432  }
433  mt->Status[p] = mt->NumNodesAtLevel[h];
434  numneighbors = GetNeighbors(shape, imgwidth, imgsize, p, neighbors);
435  for (i = 0; i < numneighbors; i++) {
436  q = neighbors[i];
437  if (mt->Status[q] == ST_NotAnalyzed) {
438  HQueueAdd(hq, pixmap[q], q);
439  mt->Status[q] = ST_InTheQueue;
440  nodeatlevel[pixmap[q]] = true;
441  if (pixmap[q] > pixmap[p]) {
442  m = pixmap[q];
443  childarea = 0;
444  childattr = NULL;
445  do {
446  m = MaxTreeFlood(mt, hq, numpixelsperlevel, nodeatlevel, img,
447  shape, m, &childarea, &childattr);
448  if (m >= NUMLEVELS) {
449  mt->DeleteAuxData(attr);
450  return (m);
451  }
452  } while (m != h);
453  area += childarea;
454  mt->MergeAuxData(attr, childattr);
455  }
456  }
457  }
458  }
459  mt->NumNodesAtLevel[h] = mt->NumNodesAtLevel[h] + 1;
460  m = h - 1;
461  while ((m >= 0) && (nodeatlevel[m] == false))
462  m--;
463  if (m >= 0) {
464  node =
465  mt->Nodes + (mt->NumPixelsBelowLevel[h] + mt->NumNodesAtLevel[h] - 1);
466  node->Parent = mt->NumPixelsBelowLevel[m] + mt->NumNodesAtLevel[m];
467  } else {
468  idx = mt->NumPixelsBelowLevel[h];
469  node = mt->Nodes + idx;
470  node->Parent = idx;
471  }
472  node->Area = area;
473  node->Attribute = attr;
474  node->Level = h;
475  nodeatlevel[h] = false;
476  *thisarea = area;
477  *thisattr = attr;
478  return (m);
479  } /* MaxTreeFlood */
480 
481  MaxTree *MaxTreeCreate(ImageGray *img, ImageGray *templateImg,
482  void *(*newauxdata)(ulong, ulong),
483  void (*addtoauxdata)(void *, ulong, ulong),
484  void (*mergeauxdata)(void *, void *),
485  void (*deleteauxdata)(void *))
486  {
487  ulong numpixelsperlevel[NUMLEVELS];
488  bool nodeatlevel[NUMLEVELS];
489  HQueue *hq;
490  MaxTree *mt;
491  ubyte *pixmap = img->Pixmap;
492  void *attr = NULL;
493  ulong imgsize, p, m = 0, area = 0;
494  int l;
495 
496  /* Allocate structures */
497  mt = (MaxTree *) malloc(sizeof(MaxTree));
498  if (mt == NULL)
499  return (NULL);
500  imgsize = (img->Width) * (img->Height);
501  mt->Status = (long *) calloc((size_t) imgsize, sizeof(long));
502  if (mt->Status == NULL) {
503  free(mt);
504  return (NULL);
505  }
506  mt->NumPixelsBelowLevel = (ulong *) calloc(NUMLEVELS, sizeof(ulong));
507  if (mt->NumPixelsBelowLevel == NULL) {
508  free(mt->Status);
509  free(mt);
510  return (NULL);
511  }
512  mt->NumNodesAtLevel = (ulong *) calloc(NUMLEVELS, sizeof(ulong));
513  if (mt->NumNodesAtLevel == NULL) {
514  free(mt->NumPixelsBelowLevel);
515  free(mt->Status);
516  free(mt);
517  return (NULL);
518  }
519  mt->Nodes = (MaxNode *) calloc((size_t) imgsize, sizeof(MaxNode));
520  if (mt->Nodes == NULL) {
521  free(mt->NumNodesAtLevel);
522  free(mt->NumPixelsBelowLevel);
523  free(mt->Status);
524  free(mt);
525  return (NULL);
526  }
527 
528  /* Initialize structures */
529  for (p = 0; p < imgsize; p++)
530  mt->Status[p] = ST_NotAnalyzed;
531  bzero(nodeatlevel, NUMLEVELS * sizeof(bool));
532  bzero(numpixelsperlevel, NUMLEVELS * sizeof(ulong));
533  /* Following bzero is redundant, array is initialized by calloc */
534  /* bzero(mt->NumNodesAtLevel, NUMLEVELS*sizeof(ulong)); */
535  for (p = 0; p < imgsize; p++)
536  numpixelsperlevel[pixmap[p]]++;
537  mt->NumPixelsBelowLevel[0] = 0;
538  for (l = 1; l < NUMLEVELS; l++) {
539  mt->NumPixelsBelowLevel[l] =
540  mt->NumPixelsBelowLevel[l - 1] + numpixelsperlevel[l - 1];
541  }
542  hq = HQueueCreate(imgsize, numpixelsperlevel);
543  if (hq == NULL) {
544  free(mt->Nodes);
545  free(mt->NumNodesAtLevel);
546  free(mt->NumPixelsBelowLevel);
547  free(mt->Status);
548  free(mt);
549  return (NULL);
550  }
551 
552  /* Find pixel m which has the lowest intensity l in the image */
553  for (p = 0; p < imgsize; p++) {
554  if (pixmap[p] < pixmap[m])
555  m = p;
556  }
557  l = pixmap[m];
558 
559  /* Add pixel m to the queue */
560  nodeatlevel[l] = true;
561  HQueueAdd(hq, l, m);
562  mt->Status[m] = ST_InTheQueue;
563 
564  /* Build the Max-tree using a flood-fill algorithm */
565  mt->NewAuxData = newauxdata;
566  mt->AddToAuxData = addtoauxdata;
567  mt->MergeAuxData = mergeauxdata;
568  mt->DeleteAuxData = deleteauxdata;
569  l = MaxTreeFlood(mt, hq, numpixelsperlevel, nodeatlevel, img,
570  templateImg->Pixmap, l, &area, &attr);
571 
572  if (l >= NUMLEVELS)
573  MaxTreeDelete(mt);
574  HQueueDelete(hq);
575  return (mt);
576  } /* MaxTreeCreate */
577 
578  void MaxTreeDelete(MaxTree *mt)
579  {
580  void *attr;
581  ulong i;
582  int h;
583 
584  for (h = 0; h < NUMLEVELS; h++) {
585  for (i = 0; i < mt->NumNodesAtLevel[h]; i++) {
586  attr = mt->Nodes[mt->NumPixelsBelowLevel[h] + i].Attribute;
587  if (attr)
588  mt->DeleteAuxData(attr);
589  }
590  }
591  free(mt->Nodes);
592  free(mt->NumNodesAtLevel);
593  free(mt->NumPixelsBelowLevel);
594  free(mt->Status);
595  free(mt);
596  } /* MaxTreeDelete */
597 
598  void MaxTreeFilterMin(MaxTree *mt, ImageGray *img, ImageGray *templateImg,
599  ImageGray *out, double (*attribute)(void *),
600  double lambda)
601  {
602  MaxNode *node, *parnode;
603  ubyte *shape = templateImg->Pixmap;
604  ulong i, idx, parent;
605  int l;
606 
607  for (l = 0; l < NUMLEVELS; l++) {
608  for (i = 0; i < mt->NumNodesAtLevel[l]; i++) {
609  idx = mt->NumPixelsBelowLevel[l] + i;
610  node = &(mt->Nodes[idx]);
611  parent = node->Parent;
612  parnode = &(mt->Nodes[parent]);
613  if ((idx != parent) && (((*attribute)(node->Attribute) < lambda) ||
614  (parnode->Level != parnode->NewLevel))) {
615  node->NewLevel = parnode->NewLevel;
616  } else
617  node->NewLevel = node->Level;
618  }
619  }
620  for (i = 0; i < (img->Width) * (img->Height); i++) {
621  if (shape[i]) {
622  idx = mt->NumPixelsBelowLevel[img->Pixmap[i]] + mt->Status[i];
623  out->Pixmap[i] = mt->Nodes[idx].NewLevel;
624  }
625  }
626  } /* MaxTreeFilterMin */
627 
628  void MaxTreeFilterDirect(MaxTree *mt, ImageGray *img, ImageGray *templateImg,
629  ImageGray *out, double (*attribute)(void *),
630  double lambda)
631  {
632  MaxNode *node;
633  ubyte *shape = templateImg->Pixmap;
634  ulong i, idx, parent;
635  int l;
636 
637  for (l = 0; l < NUMLEVELS; l++) {
638  for (i = 0; i < mt->NumNodesAtLevel[l]; i++) {
639  idx = mt->NumPixelsBelowLevel[l] + i;
640  node = &(mt->Nodes[idx]);
641  parent = node->Parent;
642  if ((idx != parent) && ((*attribute)(node->Attribute) < lambda)) {
643  node->NewLevel = mt->Nodes[parent].NewLevel;
644  } else
645  node->NewLevel = node->Level;
646  }
647  }
648  for (i = 0; i < (img->Width) * (img->Height); i++) {
649  if (shape[i]) {
650  idx = mt->NumPixelsBelowLevel[img->Pixmap[i]] + mt->Status[i];
651  out->Pixmap[i] = mt->Nodes[idx].NewLevel;
652  }
653  }
654  } /* MaxTreeFilterDirect */
655 
656  void MaxTreeFilterMax(MaxTree *mt, ImageGray *img, ImageGray *templateImg,
657  ImageGray *out, double (*attribute)(void *),
658  double lambda)
659  {
660  MaxNode *node;
661  ubyte *shape = templateImg->Pixmap;
662  ulong i, idx, parent;
663  int l;
664 
665  for (l = 0; l < NUMLEVELS; l++) {
666  for (i = 0; i < mt->NumNodesAtLevel[l]; i++) {
667  idx = mt->NumPixelsBelowLevel[l] + i;
668  node = &(mt->Nodes[idx]);
669  parent = node->Parent;
670  if ((idx != parent) && ((*attribute)(node->Attribute) < lambda)) {
671  node->NewLevel = mt->Nodes[parent].NewLevel;
672  } else
673  node->NewLevel = node->Level;
674  }
675  }
676  for (l = NUMLEVELS - 1; l > 0; l--) {
677  for (i = 0; i < mt->NumNodesAtLevel[l]; i++) {
678  idx = mt->NumPixelsBelowLevel[l] + i;
679  node = &(mt->Nodes[idx]);
680  parent = node->Parent;
681  if ((idx != parent) && (node->NewLevel == node->Level)) {
682  mt->Nodes[parent].NewLevel = mt->Nodes[parent].Level;
683  }
684  }
685  }
686  for (i = 0; i < (img->Width) * (img->Height); i++) {
687  if (shape[i]) {
688  idx = mt->NumPixelsBelowLevel[img->Pixmap[i]] + mt->Status[i];
689  out->Pixmap[i] = mt->Nodes[idx].NewLevel;
690  }
691  }
692  } /* MaxTreeFilterMax */
693 
694  void MaxTreeFilterSubtractive(MaxTree *mt, ImageGray *img,
695  ImageGray *templateImg, ImageGray *out,
696  double (*attribute)(void *), double lambda)
697  {
698  MaxNode *node, *parnode;
699  ubyte *shape = templateImg->Pixmap;
700  ulong i, idx, parent;
701  int l;
702 
703  for (l = 0; l < NUMLEVELS; l++) {
704  for (i = 0; i < mt->NumNodesAtLevel[l]; i++) {
705  idx = mt->NumPixelsBelowLevel[l] + i;
706  node = &(mt->Nodes[idx]);
707  parent = node->Parent;
708  parnode = &(mt->Nodes[parent]);
709  if ((idx != parent) && ((*attribute)(node->Attribute) < lambda)) {
710  node->NewLevel = parnode->NewLevel;
711  } else
712  node->NewLevel = ((int) (node->Level)) + ((int) (parnode->NewLevel)) -
713  ((int) (parnode->Level));
714  }
715  }
716  for (i = 0; i < (img->Width) * (img->Height); i++) {
717  if (shape[i]) {
718  idx = mt->NumPixelsBelowLevel[img->Pixmap[i]] + mt->Status[i];
719  out->Pixmap[i] = mt->Nodes[idx].NewLevel;
720  }
721  }
722  } /* MaxTreeFilterSubtractive */
723 
724  typedef struct AttribStruct AttribStruct;
725 
726  struct AttribStruct {
727  char const *Name;
728  void *(*NewData)(ulong, ulong);
729  void (*DeleteData)(void *);
730  void (*AddToData)(void *, ulong, ulong);
731  void (*MergeData)(void *, void *);
732  double (*Attribute)(void *);
733  };
734 
735 #define NUMATTR 7
736 
737  AttribStruct Attribs[NUMATTR] = {
738  {"Area", NewAreaData, DeleteAreaData, AddToAreaData, MergeAreaData,
739  AreaAttribute},
740  {"Area of min. enclosing rectangle", NewEnclRectData, DeleteEnclRectData,
741  AddToEnclRectData, MergeEnclRectData, EnclRectAreaAttribute},
742  {"Square of diagonal of min. enclosing rectangle", NewEnclRectData,
743  DeleteEnclRectData, AddToEnclRectData, MergeEnclRectData,
744  EnclRectDiagAttribute},
745  {"Moment of Inertia", NewInertiaData, DeleteInertiaData, AddToInertiaData,
746  MergeInertiaData, InertiaAttribute},
747  {"(Moment of Inertia) / (area)^2", NewInertiaData, DeleteInertiaData,
748  AddToInertiaData, MergeInertiaData, InertiaDivA2Attribute},
749  {"Mean X position", NewInertiaData, DeleteInertiaData, AddToInertiaData,
750  MergeInertiaData, MeanXAttribute},
751  {"Mean Y position", NewInertiaData, DeleteInertiaData, AddToInertiaData,
752  MergeInertiaData, MeanYAttribute}};
753 
754  typedef struct DecisionStruct DecisionStruct;
755 
756  struct DecisionStruct {
757  char const *Name;
758  void (*Filter)(MaxTree *, ImageGray *, ImageGray *, ImageGray *,
759  double (*attribute)(void *), double);
760  };
761 
762 #define NUMDECISIONS 4
763 
764  DecisionStruct Decisions[NUMDECISIONS] = {
765  {"Min", MaxTreeFilterMin},
766  {"Direct", MaxTreeFilterDirect},
767  {"Max", MaxTreeFilterMax},
768  {"Subtractive", MaxTreeFilterSubtractive},
769  };
770 
771  template <class T1, class T2>
772  RES_T ImAreaOpening_MaxTree(const Image<T1> &imIn, int size, Image<T2> &imOut)
773  {
774  // Check inputs
775  ASSERT_ALLOCATED(&imIn)
776  ASSERT_SAME_SIZE(&imIn, &imOut)
777 
778  ImageFreezer freeze(imOut);
779  fill(imOut, T2(0));
780 
781  MaxTree *mt;
782  int attrib = 0, decision = 2;
783  int W = imIn.getWidth();
784  int H = imIn.getHeight();
785  typename Image<T1>::lineType bufferIn = imIn.getPixels();
786  typename Image<T2>::lineType bufferOut = imOut.getPixels();
787 
788  ImageGray img, *templateImg, out;
789  img.Height = H;
790  img.Width = W;
791  img.Pixmap = bufferIn;
792 
793  out.Height = H;
794  out.Width = W;
795  out.Pixmap = bufferOut;
796 
797  templateImg = ImageGrayCreate(img.Width, img.Height);
798  if (templateImg)
799  ImageGrayInit(templateImg, NUMLEVELS - 1);
800 
801  mt = MaxTreeCreate(&img, templateImg, Attribs[attrib].NewData,
802  Attribs[attrib].AddToData, Attribs[attrib].MergeData,
803  Attribs[attrib].DeleteData);
804  Decisions[decision].Filter(mt, &img, templateImg, &out,
805  Attribs[attrib].Attribute, size);
806  MaxTreeDelete(mt);
807  ImageGrayDelete(templateImg);
808 
809  return RES_OK;
810  }
811 
812  template <class T1, class T2>
813  RES_T ImInertiaThinning_MaxTree(const Image<T1> &imIn, double size,
814  Image<T2> &imOut)
815  {
816  // Check inputs
817  ASSERT_ALLOCATED(&imIn)
818  ASSERT_SAME_SIZE(&imIn, &imOut)
819 
820  ImageFreezer freeze(imOut);
821  fill(imOut, T2(0));
822 
823  MaxTree *mt;
824  int attrib = 4, decision = 2;
825  int W = imIn.getWidth();
826  int H = imIn.getHeight();
827  typename Image<T1>::lineType bufferIn = imIn.getPixels();
828  typename Image<T2>::lineType bufferOut = imOut.getPixels();
829 
830  ImageGray img, *templateImg, out;
831  img.Height = H;
832  img.Width = W;
833  img.Pixmap = bufferIn;
834 
835  out.Height = H;
836  out.Width = W;
837  out.Pixmap = bufferOut;
838 
839  templateImg = ImageGrayCreate(img.Width, img.Height);
840  if (templateImg)
841  ImageGrayInit(templateImg, NUMLEVELS - 1);
842 
843  mt = MaxTreeCreate(&img, templateImg, Attribs[attrib].NewData,
844  Attribs[attrib].AddToData, Attribs[attrib].MergeData,
845  Attribs[attrib].DeleteData);
846  Decisions[decision].Filter(mt, &img, templateImg, &out,
847  Attribs[attrib].Attribute, size);
848  MaxTreeDelete(mt);
849  ImageGrayDelete(templateImg);
850 
851  return RES_OK;
852  }
853 
854 } // namespace smil
855 
856 #endif
size_t getWidth() const
Get image width.
Definition: DBaseImage.h:80
size_t getHeight() const
Get image height.
Definition: DBaseImage.h:85
Definition: DBaseImage.h:386
lineType getPixels() const
Get the pixels as a 1D array.
Definition: DImage.hpp:105
RES_T ImInertiaThinning_MaxTree(const Image< T1 > &imIn, double size, Image< T2 > &imOut)
Inertia thinning with a max tree algorithm (V4)
Definition: AreaOpeningMaxTree.hpp:813
RES_T ImAreaOpening_MaxTree(const Image< T1 > &imIn, int size, Image< T2 > &imOut)
Area opening with a max tree algorithm (V4)
Definition: AreaOpeningMaxTree.hpp:772
RES_T fill(Image< T > &imOut, const T &value)
fill() - Fill an image with a given value.
Definition: DImageArith.hpp:1456
RES_T neighbors(const Image< T1 > &imIn, Image< T2 > &imOut, const StrElt &se=DEFAULT_SE)
neighbors() - Neighbors count
Definition: DMorphoLabel.hpp:1160
size_t area(const Image< T > &imIn)
area() - Area of an image
Definition: DMeasures.hpp:91
Definition: AreaOpeningMaxTree.hpp:110
Definition: AreaOpeningMaxTree.hpp:726
Definition: AreaOpeningMaxTree.hpp:756
Definition: AreaOpeningMaxTree.hpp:155
Definition: AreaOpeningMaxTree.hpp:70
Definition: AreaOpeningMaxTree.hpp:64
Definition: AreaOpeningMaxTree.hpp:226
Definition: AreaOpeningMaxTree.hpp:78
Definition: AreaOpeningMaxTree.hpp:94