SMIL  1.1
FastLineMorard.hpp
1 #ifndef __FAST_LINE_MORARD_T_HPP__
2 #define __FAST_LINE_MORARD_T_HPP__
3 
4 // Vincent Morard
5 // 9 september 2010
6 // MAJ 8 ctober 2010 (in constant time wrt the radius)
7 // The algorithm used below is described in:
8 // Morard, Dokladal, Decenciere, "One-dimensional openings, granulometries and
9 // component trees in O (1) per pixel", IEEE Journal of Selected Topics in
10 // Signal Processing 6 (7), 840-848, 2011
11 
12 #include "Core/include/DCore.h"
13 
14 namespace smil
15 {
16  template <typename T> class MorardLineMorpho
17  {
18  public:
19  MorardLineMorpho(){};
20  ~MorardLineMorpho(){};
21 
22  private:
23  struct Node {
24  // c'etait unsigned int
25  int StartPos;
26  unsigned char Passed;
27  T Value;
28  };
29 
30  int wp, size, *LineIdx; // Writing position
31 
32  inline void BuildOpeningFromPoint(T F, int Ind, Node *MyStack,
33  int *stackSize, T *bufferOut)
34  {
35  LineIdx[wp] = Ind;
36 
37  // -1- Si la pile est vide ou si on a un front montant, on empile
38  // if(*stackSize == 0 || F > MyStack[*stackSize-1].Value){
39  // WE ASSUME THAT WE HAVE PUSH THE FIRST PIXEL OF THE LINE!!
40  if (F > MyStack[*stackSize - 1].Value) {
41  (MyStack[*stackSize]).StartPos = wp;
42  (MyStack[*stackSize]).Passed = 0;
43  (MyStack[*stackSize]).Value = F;
44  *stackSize += 1;
45  } else {
46  while (F < (MyStack[*stackSize - 1]).Value) {
47  // On depile... then MyStack[*stackSize]-->NodeOut
48  *stackSize -= 1;
49 
50  // We have passed the criteria
51  if (MyStack[*stackSize].Passed ||
52  (wp - (MyStack[*stackSize]).StartPos >= size)) {
53  for (int j = 0; j < *stackSize; j++) {
54  for (int i = (MyStack[j]).StartPos; i < (MyStack[j + 1]).StartPos;
55  i++)
56  bufferOut[LineIdx[i]] = (MyStack[j]).Value;
57  }
58  for (int i = (MyStack[*stackSize]).StartPos; i < wp; i++)
59  bufferOut[LineIdx[i]] = (MyStack[*stackSize]).Value;
60 
61  (MyStack[0]).StartPos = wp;
62  (MyStack[0]).Passed = 1;
63  (MyStack[0]).Value = F;
64  *stackSize = 1;
65  break;
66  }
67 
68  if (*stackSize == 0 || F > (MyStack[*stackSize - 1]).Value) {
69  (MyStack[*stackSize]).Value = F;
70  *stackSize += 1;
71  break;
72  }
73  }
74  }
75  wp++;
76  }
77 
78  void EndProcess(Node *MyStack, int *stackSize, T *bufferOut)
79  {
80  while (*stackSize != 0) {
81  if (wp - (MyStack[*stackSize - 1]).StartPos >= size) {
82  for (int j = 0; j < *stackSize - 1; j++) {
83  for (int i = (MyStack[j]).StartPos; i < (MyStack[j + 1]).StartPos;
84  i++)
85  bufferOut[LineIdx[i]] = (MyStack[j]).Value;
86  }
87 
88  for (int i = (MyStack[*stackSize - 1]).StartPos; i < wp; i++)
89  bufferOut[LineIdx[i]] = (MyStack[*stackSize - 1]).Value;
90  *stackSize = 0;
91  return;
92  }
93  *stackSize -= 1;
94  }
95 
96  // La ligne ne respecte pas le critère:
97  for (int i = (MyStack[0]).StartPos; i < wp; i++)
98  bufferOut[LineIdx[i]] = (MyStack[0]).Value;
99  }
100 
101  int ComputeLinePosDiag(T *bufferIn, int W, int H, int x, int y,
102  Node *MyStack, int *stackSize, T *bufferOut)
103  {
104  int idx;
105  int x0;
106 
107  if (x < 0) {
108  y -= x;
109  x = 0;
110  }
111  if (y < 0) {
112  x -= y;
113  y = 0;
114  }
115  x0 = x;
116  idx = y * W + x;
117 
118  if ((x < W) && (y < H)) {
119  wp = 1;
120  MyStack[0].Passed = 0;
121  MyStack[0].Value = bufferIn[idx];
122  MyStack[0].StartPos = 0;
123  *stackSize = 1;
124  LineIdx[0] = idx;
125 
126  // Next pixel
127  idx += W + 1;
128  y++;
129  }
130 
131  for (; (x < W) && (y < H); x++) {
132  BuildOpeningFromPoint(bufferIn[idx], idx, MyStack, stackSize,
133  bufferOut);
134  idx += W + 1;
135  y++;
136  }
137  return (x - x0);
138  }
139 
140  int ComputeLineNegDiag(T *bufferIn, int W, int H, int x, int y,
141  Node *MyStack, int *stackSize, T *bufferOut)
142  {
143  int idx;
144  int x0;
145 
146  if (y >= H) {
147  x += y - H + 1;
148  y = H - 1;
149  }
150  if (x >= W)
151  return (0);
152  x0 = x;
153  idx = y * W + x;
154 
155  wp = 1;
156  MyStack[0].Passed = 0;
157  MyStack[0].Value = bufferIn[idx];
158  MyStack[0].StartPos = 0;
159  *stackSize = 1;
160  LineIdx[0] = idx;
161 
162  // The first one is already push
163  // BuildOpeningFromPoint(bufferIn[idx],idx,MyStack,stackSize,bufferOut);
164 
165  while ((x < W - 1) && (y > 0)) {
166  // p++;
167  x++;
168  y--;
169  idx -= W - 1;
170 
171  BuildOpeningFromPoint(bufferIn[idx], idx, MyStack, stackSize,
172  bufferOut);
173  }
174  return (x - x0 + 1);
175  }
176 
177  int ComputeBresenhamLinePX(T *bufferIn, int W, int H, int x, int y,
178  int dx, int dy, Node *MyStack, int *stackSize,
179  T *bufferOut)
180  {
181  int idx;
182  int x0;
183  int dp = 2 * dy - 2, twody = 2 * dy, twodydx = 2 * dy - 2 * dx;
184 
185  while ((x < 0) || (y < 0)) {
186  if (dp >= 0) {
187  y++;
188  dp += twodydx;
189  } else
190  dp += twody;
191  x++;
192  }
193  x0 = x;
194  idx = y * W + x;
195 
196  if (x >= 0 && x < W && y >= 0 && y < H) {
197  wp = 1;
198  MyStack[0].Passed = 0;
199  MyStack[0].Value = bufferIn[idx];
200  MyStack[0].StartPos = 0;
201  *stackSize = 1;
202  LineIdx[0] = idx;
203 
204  // Next pixel, The first one is already push
205  if (dp >= 0) {
206  y++;
207  idx += W;
208  dp += twodydx;
209  } else
210  dp += twody;
211  x++;
212  idx++;
213  }
214 
215  while ((x < W) && (y < H)) {
216  BuildOpeningFromPoint(bufferIn[idx], idx, MyStack, stackSize,
217  bufferOut);
218 
219  if (dp >= 0) {
220  y++;
221  idx += W;
222  dp += twodydx;
223  } else
224  dp += twody;
225  x++;
226  idx++;
227  }
228  return (x - x0);
229  }
230 
231  int ComputeBresenhamLineNX(T *bufferIn, int W, int H, int x, int y,
232  int dx, int dy, Node *MyStack, int *stackSize,
233  T *bufferOut)
234  {
235  int x0 = x, idx = y * W + x;
236  int dp = 2 * dy - 2, twody = 2 * dy, twodydx = 2 * dy - 2 * dx;
237 
238  while (y >= H) {
239  if (dp >= 0) {
240  y--;
241  dp += twodydx;
242  } else
243  dp += twody;
244  x++;
245  }
246  if (x >= W)
247  return (0);
248  x0 = x;
249  idx = y * W + x;
250 
251  wp = 1;
252  MyStack[0].Passed = 0;
253  MyStack[0].Value = bufferIn[idx];
254  MyStack[0].StartPos = 0;
255  *stackSize = 1;
256  LineIdx[0] = idx;
257  // The first one is already push
258  // BuildOpeningFromPoint(bufferIn[idx],idx,MyStack,stackSize,bufferOut);
259 
260  while ((x < W - 1) && (y > 0)) {
261  if (dp >= 0) {
262  y--;
263  idx -= W;
264  dp += twodydx;
265  } else
266  dp += twody;
267  x++;
268  idx++;
269 
270  BuildOpeningFromPoint(bufferIn[idx], idx, MyStack, stackSize,
271  bufferOut);
272  }
273  return (x - x0 + 1);
274  }
275 
276  int ComputeBresenhamLinePY(T *bufferIn, int W, int H, int x, int y,
277  int dx, int dy, Node *MyStack, int *stackSize,
278  T *bufferOut)
279  {
280  int y0, idx;
281  int dp = 2 * dx - 2, twodx = 2 * dx, twodxdy = 2 * dx - 2 * dy;
282 
283  while ((x < 0) || (y < 0)) {
284  if (dp >= 0) {
285  x++;
286  dp += twodxdy;
287  } else
288  dp += twodx;
289  y++;
290  }
291  y0 = y;
292  idx = y * W + x;
293 
294  // We push the first pixel
295  if (x >= 0 && x < W && y >= 0 && y < H) {
296  wp = 1;
297  MyStack[0].Passed = 0;
298  MyStack[0].Value = bufferIn[idx];
299  MyStack[0].StartPos = 0;
300  *stackSize = 1;
301  LineIdx[0] = idx;
302 
303  // Next pixel, the first one is already pushed
304  if (dp >= 0) {
305  x++;
306  idx++;
307  dp += twodxdy;
308  } else
309  dp += twodx;
310  y++;
311  idx += W;
312  }
313 
314  while ((y < H) && (x < W)) {
315  BuildOpeningFromPoint(bufferIn[idx], idx, MyStack, stackSize,
316  bufferOut);
317  if (dp >= 0) {
318  x++;
319  idx++;
320  dp += twodxdy;
321  } else
322  dp += twodx;
323  y++;
324  idx += W;
325  }
326  return (y - y0);
327  }
328 
329  int ComputeBresenhamLineNY(T *bufferIn, int W, int H, int x, int y,
330  int dx, int dy, Node *MyStack, int *stackSize,
331  T *bufferOut)
332  {
333  int y0, idx;
334  int dp = 2 * dx - 2, twodx = 2 * dx, twodxdy = 2 * dx - 2 * dy;
335 
336  while (x >= W) {
337  if (dp >= 0) {
338  x--;
339  dp += twodxdy;
340  } else
341  dp += twodx;
342  y++;
343  }
344  if (y >= H)
345  return (0);
346  y0 = y;
347  idx = y * W + x;
348 
349  wp = 1;
350  MyStack[0].Passed = 0;
351  MyStack[0].Value = bufferIn[idx];
352  MyStack[0].StartPos = 0;
353  *stackSize = 1;
354  LineIdx[0] = idx;
355  // Next pixel, the first one is already pushed
356  // BuildOpeningFromPoint(bufferIn[idx],idx,MyStack,stackSize,bufferOut);
357 
358  while ((y < H - 1) && (x > 0) && (x < W)) {
359  if (dp >= 0) {
360  x--;
361  idx--;
362  dp += twodxdy;
363  } else
364  dp += twodx;
365  y++;
366  idx += W;
367 
368  BuildOpeningFromPoint(bufferIn[idx], idx, MyStack, stackSize,
369  bufferOut);
370  }
371  return (y - y0 + 1);
372  }
373 
374  void LineOpeningHorz(T *bufferIn, int W, int H, int radius, T *bufferOut)
375  {
376  size = radius * 2 + 1;
377  // Pas génant de faire <T2> puisque T1 est du même type que T2 mais T1 est
378  // const...
379 
380  Node MyStack[256];
381  int stackPos = 0;
382 
383  int i, j;
384 
385  for (j = 0; j < H; j++) // Pour toutes les lignes
386  {
387  wp = 1;
388  MyStack[0].Passed = 0;
389  MyStack[0].Value = bufferIn[j * W];
390  MyStack[0].StartPos = 0;
391  stackPos = 1;
392  LineIdx[0] = j * W;
393  for (i = 1; i < W; i++) // Pour toutes les colonnes
394  BuildOpeningFromPoint(bufferIn[i + j * W], i + j * W, MyStack,
395  &stackPos, bufferOut);
396  EndProcess(MyStack, &stackPos, bufferOut);
397  }
398  }
399 
400  void LineOpeningVert(T *bufferIn, int W, int H, int radius, T *bufferOut)
401  {
402  size = radius * 2 + 1;
403 
404  Node MyStack[256];
405  int stackPos = 0;
406 
407  int i, j;
408 
409  for (i = 0; i < W; i++) // Pour toutes les colonnes
410  {
411  wp = 1;
412  MyStack[0].Passed = 0;
413  MyStack[0].Value = bufferIn[i];
414  MyStack[0].StartPos = 0;
415  stackPos = 1;
416  LineIdx[0] = i;
417  for (j = 1; j < H; j++) // Pour toutes les lignes
418  BuildOpeningFromPoint(bufferIn[i + j * W], i + j * W, MyStack,
419  &stackPos, bufferOut);
420  EndProcess(MyStack, &stackPos, bufferOut);
421  }
422  }
423 
424  void LineOpeningDiag(T *bufferIn, int W, int H, int dx, int dy,
425  int radius, T *bufferOut)
426  {
427  size = radius * 2 + 1;
428  int y, x, nx;
429 
430  Node MyStack[256];
431  int stackPos = 0;
432 
433  if (abs(dx) == abs(dy)) {
434  if (dx == -dy) {
435  y = 0;
436  do {
437  nx = ComputeLineNegDiag(bufferIn, W, H, 0, y++, MyStack,
438  &stackPos, bufferOut);
439  EndProcess(MyStack, &stackPos, bufferOut);
440  } while (nx > 0);
441 
442  } else {
443  y = H - 2; //-2 to avoid a bug (empty image)
444  do {
445  nx = ComputeLinePosDiag(bufferIn, W, H, 0, y--, MyStack,
446  &stackPos, bufferOut);
447  EndProcess(MyStack, &stackPos, bufferOut);
448  } while (nx > 0);
449  }
450  } else if (abs(dx) > abs(dy)) {
451  if (((dx > 0) && (dy > 0)) || ((dx < 0) && (dy < 0))) {
452  dx = abs(dx);
453  dy = abs(dy);
454 
455  y = H - 1;
456  do {
457  nx = ComputeBresenhamLinePX(bufferIn, W, H, 0, y--, dx, dy,
458  MyStack, &stackPos, bufferOut);
459  EndProcess(MyStack, &stackPos, bufferOut);
460  } while (nx > 0);
461  } else {
462  dx = abs(dx);
463  dy = abs(dy);
464 
465  y = 0;
466  do {
467  nx = ComputeBresenhamLineNX(bufferIn, W, H, 0, y++, dx, dy,
468  MyStack, &stackPos, bufferOut);
469  EndProcess(MyStack, &stackPos, bufferOut);
470  } while (nx > 0);
471  }
472  } else {
473  if (((dx > 0) && (dy > 0)) || ((dx < 0) && (dy < 0))) {
474  dx = abs(dx);
475  dy = abs(dy);
476 
477  x = W - 1;
478  do {
479  nx = ComputeBresenhamLinePY(bufferIn, W, H, x--, 0, dx, dy,
480  MyStack, &stackPos, bufferOut);
481  EndProcess(MyStack, &stackPos, bufferOut);
482  } while (nx > 0);
483  } else {
484  dx = abs(dx);
485  dy = abs(dy);
486 
487  x = 0;
488  do {
489  nx = ComputeBresenhamLineNY(bufferIn, W, H, x++, 0, dx, dy,
490  MyStack, &stackPos, bufferOut);
491  EndProcess(MyStack, &stackPos, bufferOut);
492  } while (nx > 0);
493  }
494  }
495  }
496 
497  ;
498 
499  public:
500  RES_T ImFastLineOpen(const Image<T> &imIn, const int angle,
501  const int radius, Image<T> &imOut)
502  {
503  // Check inputs
504  ASSERT_ALLOCATED(&imIn);
505  ASSERT_ALLOCATED(&imOut);
506  ASSERT_SAME_SIZE(&imIn, &imOut);
507 
508  int W, H;
509 
510  W = imIn.getWidth();
511  H = imIn.getHeight();
512 
513  typename Image<T>::lineType bufferIn = imIn.getPixels();
514  typename Image<T>::lineType bufferOut = imOut.getPixels();
515 
516  int rd = (int) (angle * PI / 180.);
517  int r = (int) (radius * std::max(fabs(cos(rd)), fabs(sin(rd))) + 0.5);
518 
519  int maxnx = std::max(W, H);
520  LineIdx = new int[maxnx + 3];
521  int dx = (int) (cos(angle * PI / 180.0) * maxnx);
522  int dy = (int) (-sin(angle * PI / 180.0) * maxnx);
523 
524  if (dx == 0)
525  LineOpeningVert(bufferIn, W, H, r, bufferOut);
526  else if (dy == 0)
527  LineOpeningHorz(bufferIn, W, H, r, bufferOut);
528  else
529  LineOpeningDiag(bufferIn, W, H, dx, dy, r, bufferOut);
530 
531  delete[] LineIdx;
532  return RES_OK;
533  }
534  };
535 
536  //
537  //
538  // Start of global code
539  //
540  template <class T>
541  RES_T imFastLineOpen(const Image<T> &imIn, const int angle,
542  const int radius, Image<T> &imOut)
543  {
544  MorardLineMorpho<T> morard;
545 
546  return morard.ImFastLineOpen(imIn, angle, radius, imOut);
547  }
548 
549 } // namespace smil
550 
551 #endif
Definition: FastLineMorard.hpp:17
Definition: FastLineMorard.hpp:23