SMIL  1.0.4
AreaOpeningPixelQueue.hpp
1 #ifndef __FAST_AREA_OPENIN_PIXEL_QUEUE_T_HPP__
2 #define __FAST_AREA_OPENIN_PIXEL_QUEUE_T_HPP__
3 
4 #include "Core/include/DCore.h"
5 
6 // Interface to SMIL Vincent Morard
7 // Date : 7 march 2011
8 
9 // This program computes the grey scale area closing using
10 // Vincent's priority-queue algorithm.
11 // The input is a grey scale image (im), and its output is
12 // a grey-scale image (out).
13 // The time complexity of this algorithm is quadratic in the
14 // number of pixels, and AlogA in the area A of the closing.
15 //
16 // (c) Arnold Meijster and Michael Wilkinson
17 //
18 
19 namespace smil
20 {
21 #define MAXGREYVAL 256
22 #ifndef FALSE
23 #define FALSE 0
24 #endif
25 #ifndef TRUE
26 #define TRUE 1
27 #endif
28 
29  typedef int greyval;
30  typedef greyval **GImage;
31 
32  int *Queue;
33  int head, tail;
34 
35  /********** Heap Management **************************************/
36  typedef struct {
37  long *heap;
38  long N, HeapMax;
39  } PixelHeap;
40 
41  void InitPixelHeap(PixelHeap *p_heap, int lambda)
42  {
43  p_heap->heap = (long *) malloc((lambda + 1) * sizeof(long));
44  p_heap->N = 0;
45  p_heap->HeapMax = lambda;
46  }
47 
48  void ExitPixelHeap(PixelHeap *p_heap)
49  {
50  free(p_heap->heap);
51  p_heap->N = 0;
52  }
53 
54  void InsertInPixelHeap(PixelHeap *p_heap, greyval *im, long pixel)
55  {
56  long child, parent, gval = im[pixel];
57  p_heap->N++;
58  child = p_heap->N;
59  p_heap->heap[child] = pixel;
60  while ((parent = (child >> 1)) && (im[p_heap->heap[parent]] > gval)) {
61  p_heap->heap[child] = p_heap->heap[parent];
62  child = parent;
63  }
64  p_heap->heap[child] = pixel;
65  }
66 
67  int RemoveFromPixelHeap(PixelHeap *p_heap, greyval *im)
68  {
69  long pixel = p_heap->heap[p_heap->N--], temp = p_heap->heap[1],
70  gval = im[pixel], child, parent, maxparent = p_heap->N >> 1;
71 
72  p_heap->heap[parent = 1] = pixel;
73  while (parent <= maxparent) {
74  child = parent << 1;
75  if (child < p_heap->N)
76  if (im[p_heap->heap[child]] > im[p_heap->heap[child + 1]])
77  child++;
78  if (gval <= im[p_heap->heap[child]])
79  break;
80  p_heap->heap[parent] = p_heap->heap[child];
81  parent = child;
82  }
83  p_heap->heap[parent] = pixel;
84  return temp;
85  }
86 
87  int HeapEmpty(PixelHeap *p_heap)
88  {
89  return (p_heap->N == 0);
90  }
91 
92  /********** Area opening according Luc Vincent *******************/
93 
94  long FillExtremum(int *Qpos, SMIL_UNUSED int lambda, greyval *im,
95  greyval *label, int width, int height, PixelHeap *p_heap,
96  int *Queue, int Qmax, long *fill_list)
97  {
98  long area = 0;
99  int i = *Qpos, pixel = Queue[i], curneigh, px, MARK = label[pixel],
100  uplimit = (height - 1) * width;
101  p_heap->N = 0;
102  do {
103  label[pixel] = -MARK;
104 
105  fill_list[area++] = pixel;
106  px = pixel % width;
107  if (pixel >= width) {
108  curneigh = pixel - width;
109  if ((label[curneigh] != MARK) && (label[curneigh] != -MARK)) {
110  InsertInPixelHeap(p_heap, im, curneigh);
111  label[curneigh] = -MARK;
112  }
113  }
114  if (pixel < uplimit) {
115  curneigh = pixel + width;
116  if ((label[curneigh] != MARK) && (label[curneigh] != -MARK)) {
117  InsertInPixelHeap(p_heap, im, curneigh);
118  label[curneigh] = -MARK;
119  }
120  }
121  if (px > 0) {
122  curneigh = pixel - 1;
123  if ((label[curneigh] != MARK) && (label[curneigh] != -MARK)) {
124  InsertInPixelHeap(p_heap, im, curneigh);
125  label[curneigh] = -MARK;
126  }
127  }
128  if (px < width - 1) {
129  curneigh = pixel + 1;
130  if ((label[curneigh] != MARK) && (label[curneigh] != -MARK)) {
131  InsertInPixelHeap(p_heap, im, curneigh);
132  label[curneigh] = -MARK;
133  }
134  }
135  i++;
136  if (i == Qmax)
137  break;
138  pixel = Queue[i];
139  } while (label[pixel] == MARK);
140  *Qpos = i;
141  return area;
142  }
143 
144  void SmallRegionalMinima(greyval *im, greyval *label, int *Queue, int *Qmax,
145  int width, int height, int lambda)
146  {
147 #define REGMAX -2
148 #define NARM 0
149  register int i, j, curneigh, pixel, px, gval, curlab = 1;
150 
151  /* Determine regional maxima */
152  for (i = 0; i < width * height; i++)
153  label[i] = REGMAX;
154  *Qmax = 0;
155  for (i = 0; i < width * height; i++) {
156  if (label[i] == REGMAX) /* not processed yet */
157  {
158  gval = im[i];
159  label[i] = curlab;
160  head = *Qmax;
161  Queue[head] = i;
162  tail = head + 1;
163  while (head != tail) {
164  pixel = Queue[head++];
165  px = pixel % width;
166  if (pixel >= width) {
167  curneigh = pixel - width;
168  if (im[curneigh] < gval) {
169  label[pixel] = NARM;
170  break;
171  } else if ((im[curneigh] == gval) && (label[curneigh] == REGMAX)) {
172  label[curneigh] = curlab;
173  Queue[tail++] = curneigh;
174  }
175  }
176  if (pixel < (height - 1) * width - 1) {
177  curneigh = pixel + width;
178  if (im[curneigh] < gval) {
179  label[pixel] = NARM;
180  break;
181  } else if ((im[curneigh] == gval) && (label[curneigh] == REGMAX)) {
182  label[curneigh] = curlab;
183  Queue[tail++] = curneigh;
184  }
185  }
186  if (px > 0) {
187  curneigh = pixel - 1;
188  if (im[curneigh] < gval) {
189  label[pixel] = NARM;
190  break;
191  } else if ((im[curneigh] == gval) && (label[curneigh] == REGMAX)) {
192  label[curneigh] = curlab;
193  Queue[tail++] = curneigh;
194  }
195  }
196  if (px < width - 1) {
197  curneigh = pixel + 1;
198  if (im[curneigh] < gval) {
199  label[pixel] = NARM;
200  break;
201  } else if ((im[curneigh] == gval) && (label[curneigh] == REGMAX)) {
202  label[curneigh] = curlab;
203  Queue[tail++] = curneigh;
204  }
205  }
206  }
207  if (label[pixel] != NARM) {
208  if ((head - *Qmax) < lambda) {
209  curlab++;
210  *Qmax = head;
211  } else
212  for (j = *Qmax; j < head; j++)
213  label[Queue[j]] = NARM;
214  } else {
215  head--;
216  for (j = *Qmax; j < head; j++)
217  label[Queue[j]] = NARM;
218  while (head != tail) {
219  pixel = Queue[head++];
220  px = pixel % width;
221  label[pixel] = NARM;
222  curneigh = pixel - width;
223  if ((pixel >= width) && (im[curneigh] == gval) &&
224  (label[curneigh] != NARM)) {
225  label[curneigh] = NARM;
226  Queue[tail++] = curneigh;
227  }
228  curneigh = pixel + width;
229  if ((pixel < (height - 1) * width - 1) && (im[curneigh] == gval) &&
230  (label[curneigh] != NARM)) {
231  label[curneigh] = NARM;
232  Queue[tail++] = curneigh;
233  }
234  curneigh = pixel - 1;
235  if ((px > 0) && (im[curneigh] == gval) &&
236  (label[curneigh] != NARM)) {
237  label[curneigh] = NARM;
238  Queue[tail++] = curneigh;
239  }
240  curneigh = pixel + 1;
241  if ((px < width - 1) && (im[curneigh] == gval) &&
242  (label[curneigh] != NARM)) {
243  label[curneigh] = NARM;
244  Queue[tail++] = curneigh;
245  }
246  }
247  }
248  }
249  }
250  return;
251  }
252 
253  void VincentAreaClosing(int lambda, greyval *im, greyval *label, int width,
254  int height, PixelHeap *p_heap, long *fill_list)
255  {
256  int Qpos, j, pixel, px,
257  // JOE imagesize=width*height,
258  uplimit = (height - 1) * width, maxarea, MARK, curneigh, Qmax;
259  greyval gval;
260  SmallRegionalMinima(im, label, Queue, &Qmax, width, height, lambda);
261  Qpos = 0;
262  MARK = label[Queue[Qpos]];
263  while (Qpos < Qmax) {
264  maxarea = FillExtremum(&Qpos, lambda, im, label, width, height, p_heap,
265  Queue, Qmax, fill_list);
266  MARK = -MARK;
267  while (maxarea < lambda) {
268  gval = im[pixel = RemoveFromPixelHeap(p_heap, im)];
269  px = pixel % width;
270  fill_list[maxarea++] = pixel;
271  curneigh = pixel - width;
272  if ((pixel >= width) && (label[curneigh] != MARK)) {
273  if (gval <= im[curneigh]) {
274  label[curneigh] = MARK;
275  InsertInPixelHeap(p_heap, im, curneigh);
276  } else
277  break;
278  }
279  curneigh = pixel + width;
280  if ((pixel < uplimit) && (label[curneigh] != MARK)) {
281  if (gval <= im[curneigh]) {
282  label[curneigh] = MARK;
283  InsertInPixelHeap(p_heap, im, curneigh);
284  } else
285  break;
286  }
287  curneigh = pixel - 1;
288  if ((px > 0) && (label[curneigh] != MARK)) {
289  if (gval <= im[curneigh]) {
290  label[curneigh] = MARK;
291  InsertInPixelHeap(p_heap, im, curneigh);
292  } else
293  break;
294  }
295  curneigh = pixel + 1;
296  if ((px < width - 1) && (label[curneigh] != MARK)) {
297  if (gval <= im[curneigh]) {
298  label[curneigh] = MARK;
299  InsertInPixelHeap(p_heap, im, curneigh);
300  } else
301  break;
302  }
303  }
304  for (j = 0; j < maxarea; j++)
305  im[fill_list[j]] = gval;
306  if (Qpos < Qmax)
307  MARK = label[Queue[Qpos]];
308  }
309  }
310 
311  GImage CreateImage(int width, int height)
312  {
313  GImage img;
314  greyval *buf;
315  int i;
316  img = (GImage) malloc(height * sizeof(greyval *));
317  buf = (greyval *) malloc(width * height * sizeof(greyval));
318  img[0] = buf;
319  for (i = 1; i < height; i++)
320  img[i] = img[i - 1] + width;
321  return img;
322  }
323 
324  void ReleaseImage(GImage img)
325  {
326  free(img[0]);
327  free(img);
328  img = 0;
329  }
330 
331  // This algorithm needs an INT32 input and an INT32 output. It can be an
332  // inplace transform However, we are working with UINT8 and UINT8 input and
333  // output buffer. Hence, we have already converted the input image in INT32.
334  // (not const) First, the result of the area op will be store in imIn. Then we
335  // convert it into imOut
336 
337  // Here T1 = INT32
338  template <class T1, class T2>
339  RES_T ImAreaClosing_PixelQueue(const Image<T1> &imIn, int size,
340  Image<T2> &imOut)
341  {
342  // Check inputs
343  ASSERT_ALLOCATED(&imIn)
344  ASSERT_SAME_SIZE(&imIn, &imOut)
345 
346  ImageFreezer freeze(imOut);
347  fill(imOut, T2(0));
348 
349  Image<INT32> im_32(imIn);
350  RES_T res = copy(imIn, im_32);
351  if (res != RES_OK)
352  return res;
353 
354  int W, H;
355  W = im_32.getWidth();
356  H = im_32.getHeight();
357 
358  typename Image<INT32>::lineType bufferIn = im_32.getPixels();
359 
360  // Change the way to read the image for the output image
361  GImage outputImage;
362  outputImage = (GImage) malloc(H * sizeof(greyval *));
363  outputImage[0] = bufferIn;
364  for (int i = 1; i < H; i++)
365  outputImage[i] = outputImage[i - 1] + W;
366 
367  // Create space for the label image
368  GImage labelImage = CreateImage(W, H);
369 
370  // Allocate the queue
371  Queue = (int *) malloc(W * H * sizeof(int));
372 
373  PixelHeap p_heap;
374  InitPixelHeap(&p_heap, 2 * (size + 1));
375  long *fill_list = (long *) malloc(size * sizeof(long));
376 
377  VincentAreaClosing(size, outputImage[0], labelImage[0], W, H, &p_heap,
378  fill_list);
379 
380  res = copy(im_32, imOut);
381  if (res != RES_OK)
382  return res;
383 
384  // Free the extra memory
385  ExitPixelHeap(&p_heap);
386  free(outputImage);
387  ReleaseImage(labelImage);
388  free(Queue);
389  free(fill_list);
390 
391  return RES_OK;
392  }
393 } // namespace smil
394 
395 #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 ImAreaClosing_PixelQueue(const Image< T1 > &imIn, int size, Image< T2 > &imOut)
Area closing with pixel queue algorithm (V4)
Definition: AreaOpeningPixelQueue.hpp:339
RES_T fill(Image< T > &imOut, const T &value)
fill() - Fill an image with a given value.
Definition: DImageArith.hpp:1456
size_t label(const Image< T1 > &imIn, Image< T2 > &imOut, const StrElt &se=DEFAULT_SE)
label() - Image labelization
Definition: DMorphoLabel.hpp:564
size_t area(const Image< T > &imIn)
area() - Area of an image
Definition: DMeasures.hpp:91
RES_T copy(const Image< T1 > &imIn, size_t startX, size_t startY, size_t startZ, size_t sizeX, size_t sizeY, size_t sizeZ, Image< T2 > &imOut, size_t outStartX=0, size_t outStartY=0, size_t outStartZ=0)
copy() - Copy image (or a zone) into an output image
Definition: DImageTransform.hpp:84
Definition: AreaOpeningPixelQueue.hpp:36