Milena (Olena)  User documentation 2.0a Id
 All Classes Namespaces Functions Variables Typedefs Enumerator Groups Pages
gaussian_directional_2d.hh
1 // Copyright (C) 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_LINEAR_GAUSSIAN_DIRECTIONAL_2D_HH
27 # define MLN_LINEAR_GAUSSIAN_DIRECTIONAL_2D_HH
28 
34 
35 #include <mln/core/image/image2d.hh>
36 #include <mln/extension/adjust_fill.hh>
37 #include <mln/extension/adjust_duplicate.hh>
38 
39 
40 
41 namespace mln
42 {
43 
44  namespace linear
45  {
46 
47 
48  template <typename I>
49  mln_concrete(I)
50  gaussian_directional_2d(const Image<I>& input,
51  unsigned dir, double sigma,
52  const mln_value(I)& bdr);
53 
54 
55 
56 # ifndef MLN_INCLUDE_ONLY
57 
58  namespace my
59  {
60 
61  struct recursivefilter_coef_
62  {
63  enum FilterType { DericheGaussian,
64  DericheGaussianFirstDerivative,
65  DericheGaussianSecondDerivative };
66 
67  std::vector<double> n, d, nm, dm;
68  double sumA, sumC;
69 
70  recursivefilter_coef_(double a0, double a1,
71  double b0, double b1,
72  double c0, double c1,
73  double w0, double w1,
74  double s, FilterType filter_type)
75  {
76  n.reserve(5);
77  d.reserve(5);
78  nm.reserve(5);
79  dm.reserve(5);
80 
81  b0 /= s;
82  b1 /= s;
83  w0 /= s;
84  w1 /= s;
85 
86  double sin0 = sin(w0);
87  double sin1 = sin(w1);
88  double cos0 = cos(w0);
89  double cos1 = cos(w1);
90 
91  switch (filter_type) {
92 
93  case DericheGaussian :
94  {
95  sumA =
96  (2.0 * a1 * exp( b0 ) * cos0 * cos0 - a0 * sin0 * exp( 2.0 * b0 )
97  + a0 * sin0 - 2.0 * a1 * exp( b0 )) /
98  (( 2.0 * cos0 * exp( b0 ) - exp( 2.0 * b0 ) - 1 ) * sin0);
99 
100  sumC =
101  (2.0 * c1 * exp( b1 ) * cos1 * cos1 - c0 * sin1 * exp( 2.0 * b1 )
102  + c0 * sin1 - 2.0 * c1 * exp( b1 ))
103  / (( 2.0 * cos1 * exp( b1 ) - exp( 2.0 * b1 ) - 1 ) * sin1);
104  break;
105  }
106 
107  case DericheGaussianFirstDerivative :
108  {
109  sumA = -2.f *
110  (a0 * cos0 - a1 * sin0 + a1 * sin0 * exp( 2.0 * b0 )
111  + a0 * cos0 * exp( 2.0 * b0 ) - 2.0 * a0 * exp( b0 ))
112  * exp( b0 )
113  / (exp( 4.0 * b0 ) - 4.0 * cos0 * exp( 3.0 * b0 )
114  + 2.0 * exp( 2.0 * b0 ) + 4.0 * cos0 * cos0 * exp( 2.0 * b0 )
115  + 1.0 - 4.0 * cos0 * exp( b0 ));
116  sumC = - 2.f *
117  (c0 * cos1 - c1 * sin1 + c1 * sin1 * exp( 2.0 * b1 )
118  + c0 * cos1 * exp( 2.0 * b1 ) - 2.0 * c0 * exp( b1 ))
119  * exp( b1 ) /
120  (exp( 4.0 * b1 ) - 4.0 * cos1 * exp( 3.0 * b1 )
121  + 2.0 * exp( 2.0 * b1 ) + 4.0 * cos1 * cos1 * exp( 2.0 * b1 )
122  + 1.0 - 4.0 * cos1 * exp( b1 ));
123  break;
124  }
125 
126  case DericheGaussianSecondDerivative :
127  {
128  double aux;
129  aux =
130  12.0 * cos0 * exp( 3.0 * b0 ) - 3.0 * exp( 2.0 * b0 )
131  + 8.0 * cos0 * cos0 * cos0 * exp( 3.0 * b0 ) - 12.0 * cos0 * cos0 *
132  exp( 4.0 * b0 )
133  - (3.0 * exp( 4.0 * b0 ))
134  + 6.0 * cos0 * exp( 5.0 * b0 ) - exp( 6.0 * b0 ) + 6.0 * cos0 * exp
135  ( b0 )
136  - ( 1.0 + 12.0 * cos0 * cos0 * exp( 2.0 * b0 ) );
137  sumA =
138  4.0 * a0 * sin0 * exp( 3.0 * b0 ) + a1 * cos0 * cos0 * exp( 4.0 * b0 )
139  - ( 4.0 * a0 * sin0 * exp( b0 ) + 6.0 * a1 * cos0 * cos0 * exp( 2.0 * b0 ) )
140  + 2.0 * a1 * cos0 * cos0 * cos0 * exp( b0 ) - 2.0 * a1 * cos0 * exp(b0)
141  + 2.0 * a1 * cos0 * cos0 * cos0 * exp( 3.0 * b0 ) - 2.0 * a1 * cos0
142  * exp( 3.0 * b0 )
143  + a1 * cos0 * cos0 - a1 * exp( 4.0 * b0 )
144  + 2.0 * a0 * sin0 * cos0 * cos0 * exp( b0 ) - 2.0 * a0 * sin0 * cos0
145  * cos0 * exp( 3.0 * b0 )
146  - ( a0 * sin0 * cos0 * exp( 4.0 * b0 ) + a1 )
147  + 6.0 * a1 * exp( 2.0 * b0 ) + a0 * cos0 * sin0
148  * 2.0 * exp( b0 ) / ( aux * sin0 );
149  aux =
150  12.0 * cos1 * exp( 3.0 * b1 ) - 3.0 * exp( 2.0 * b1 )
151  + 8.0 * cos1 * cos1 * cos1 * exp( 3.0 * b1 ) - 12.0 * cos1 * cos1 *
152  exp( 4.0 * b1 )
153  - 3.0 * exp( 4.0 * b1 )
154  + 6.0 * cos1 * exp( 5.0 * b1 ) - exp( 6.0 * b1 ) + 6.0 * cos1 * exp
155  ( b1 )
156  - ( 1.0 + 12.0 * cos1 * cos1 * exp( 2.0 * b1 ) );
157  sumC = 4.0 * c0 * sin1 * exp( 3.0 * b1 ) + c1 * cos1 * cos1 * exp( 4.0 * b1 )
158  - ( 4.0 * c0 * sin1 * exp( b1 ) + 6.0 * c1 * cos1 * cos1 * exp( 2.0 * b1 ) )
159  + 2.0 * c1 * cos1 * cos1 * cos1 * exp( b1 ) - 2.0 * c1 * cos1 * exp( b1 )
160  + 2.0 * c1 * cos1 * cos1 * cos1 * exp( 3.0 * b1 ) - 2.0 * c1 * cos1
161  * exp( 3.0 * b1 )
162  + c1 * cos1 * cos1 - c1 * exp( 4.0 * b1 )
163  + 2.0 * c0 * sin1 * cos1 * cos1 * exp( b1 ) - 2.0 * c0 * sin1 * cos1
164  * cos1 * exp( 3.0 * b1 )
165  - ( c0 * sin1 * cos1 * exp( 4.0 * b1 ) + c1 )
166  + 6.0 * c1 * exp( 2.0 * b1 ) + c0 * cos1 * sin1
167  * 2.0 * exp( b1 ) / ( aux * sin1 );
168  sumA /= 2;
169  sumC /= 2;
170  break;
171  }
172  }
173 
174  a0 /= (sumA + sumC);
175  a1 /= (sumA + sumC);
176  c0 /= (sumA + sumC);
177  c1 /= (sumA + sumC);
178 
179  n[3] =
180  exp( -b1 - 2*b0 ) * (c1 * sin1 - cos1 * c0) +
181  exp( -b0 - 2*b1 ) * (a1 * sin0 - cos0 * a0);
182  n[2] =
183  2 * exp(-b0 - b1) * ((a0 + c0) * cos1 * cos0 -
184  cos1 * a1 * sin0 -
185  cos0 * c1 * sin1) +
186  c0 * exp(-2 * b0) + a0 * exp(-2 * b1);
187  n[1] =
188  exp(-b1) * (c1 * sin1 - (c0 + 2*a0) * cos1) +
189  exp(-b0) * (a1 * sin0 - (2*c0 + a0) * cos0);
190  n[0] =
191  a0 + c0;
192 
193  d[4] = exp(-2 * b0 - 2 * b1);
194  d[3] =
195  -2 * cos0 * exp(-b0 - 2*b1) -
196  2 * cos1 * exp(-b1 - 2*b0);
197  d[2] =
198  4 * cos1 * cos0 * exp(-b0 - b1) +
199  exp(-2*b1) + exp(-2*b0);
200  d[1] =
201  -2*exp(-b1) * cos1 - 2 * exp(-b0) * cos0;
202 
203  switch (filter_type) {
204  case DericheGaussian :
205  case DericheGaussianSecondDerivative :
206  {
207  for (unsigned i = 1; i <= 3; ++i)
208  {
209  dm[i] = d[i];
210  nm[i] = n[i] - d[i] * n[0];
211  }
212  dm[4] = d[4];
213  nm[4] = -d[4] * n[0];
214  break;
215  }
216  case DericheGaussianFirstDerivative :
217  {
218  for (unsigned i = 1; i <= 3; ++i)
219  {
220  dm[i] = d[i];
221  nm[i] = - (n[i] - d[i] * n[0]);
222  }
223  dm[4] = d[4];
224  nm[4] = d[4] * n[0];
225  break;
226  }
227  }
228  }
229  };
230 
231 
232  } // end of namespace mln::linear::my
233 
234 
235 
236 
237  // FIXME: in the "generic" code below there is no test that we
238  // actually stay in the image domain...
239 
240 
241  template <typename I, typename C>
242  inline
243  void
244  recursivefilter_directional_generic(I& ima,
245  const C& c,
246  const mln_psite(I)& start,
247  const mln_psite(I)& finish,
248  int len,
249  const mln_deduce(I, psite, delta)& d)
250  {
251  std::vector<double> tmp1(len);
252  std::vector<double> tmp2(len);
253 
254  tmp1[0] =
255  c.n[0]*ima(start);
256 
257  tmp1[1] =
258  c.n[0]*ima(start + d)
259  + c.n[1]*ima(start)
260  - c.d[1]*tmp1[0];
261 
262  tmp1[2] =
263  c.n[0]*ima(start + d + d)
264  + c.n[1]*ima(start + d)
265  + c.n[2]*ima(start)
266  - c.d[1]*tmp1[1]
267  - c.d[2]*tmp1[0];
268 
269  tmp1[3] =
270  c.n[0]*ima(start + d + d + d)
271  + c.n[1]*ima(start + d + d)
272  + c.n[2]*ima(start + d)
273  + c.n[3]*ima(start)
274  - c.d[1]*tmp1[2] - c.d[2]*tmp1[1]
275  - c.d[3]*tmp1[0];
276 
277  mln_site(I) current = start + d + d + d + d;
278  for (int i = 4; i < len; ++i)
279  {
280  tmp1[i] =
281  c.n[0]*ima(current)
282  + c.n[1]*ima(current - d)
283  + c.n[2]*ima(current - d - d)
284  + c.n[3]*ima(current - d - d - d)
285  - c.d[1]*tmp1[i - 1] - c.d[2]*tmp1[i - 2]
286  - c.d[3]*tmp1[i - 3] - c.d[4]*tmp1[i - 4];
287  current += d;
288  }
289 
290  // Non causal part
291 
292  tmp2[len - 1] = 0;
293 
294  tmp2[len - 2] =
295  c.nm[1]*ima(finish);
296 
297  tmp2[len - 3] =
298  c.nm[1]*ima(finish - d)
299  + c.nm[2]*ima(finish)
300  - c.dm[1]*tmp2[len-2];
301 
302  tmp2[len - 4] =
303  c.nm[1]*ima(finish - d - d)
304  + c.nm[2]*ima(finish - d)
305  + c.nm[3]*ima(finish)
306  - c.dm[1]*tmp2[len-3]
307  - c.dm[2]*tmp2[len-2];
308 
309  current = finish - d - d - d ;
310 
311  for (int i = len - 5; i >= 0; --i)
312  {
313  tmp2[i] =
314  c.nm[1]*ima(current)
315  + c.nm[2]*ima(current + d)
316  + c.nm[3]*ima(current + d + d)
317  + c.nm[4]*ima(current + d + d + d)
318  - c.dm[1]*tmp2[i+1] - c.dm[2]*tmp2[i+2]
319  - c.dm[3]*tmp2[i+3] - c.dm[4]*tmp2[i+4];
320  current -= d;
321  }
322 
323  // Combine results from causal and non-causal parts.
324 
325  current = start;
326  for (int i = 0; i < len; ++i)
327  {
328  ima(current) = (tmp1[i] + tmp2[i]);
329  current += d;
330  }
331  }
332 
333 
334 
335 
336  template <typename I, typename C>
337  inline
338  void
339  recursivefilter_directional_fastest(I& ima,
340  const C& c,
341  const mln_psite(I)& start,
342  const mln_psite(I)& finish,
343  int len,
344  const mln_deduce(I, psite, delta)& d,
345  const mln_value(I)& bdr)
346  {
347  // extension::adjust_fill(ima, 5 * int(151 + .50001) + 1, bdr);
348  // extension::fill(ima, bdr);
349 
350  std::vector<double> tmp1(len);
351  std::vector<double> tmp2(len);
352 
353  unsigned delta_offset = ima.delta_index(d);
354  unsigned
355  o_start = ima.index_of_point(start),
356  o_start_d = o_start + delta_offset,
357  o_start_dd = o_start + 2 * delta_offset,
358  o_start_ddd = o_start + 3 * delta_offset;
359 
360  tmp1[0] =
361  c.n[0] * ima.element(o_start);
362 
363  tmp1[1] = 0
364  + c.n[0] * ima.element(o_start_d)
365  + c.n[1] * ima.element(o_start)
366  - c.d[1] * tmp1[0];
367 
368  tmp1[2] = 0
369  + c.n[0] * ima.element(o_start_dd)
370  + c.n[1] * ima.element(o_start_d)
371  + c.n[2] * ima.element(o_start)
372  - c.d[1] * tmp1[1]
373  - c.d[2] * tmp1[0];
374 
375  tmp1[3] = 0
376  + c.n[0] * ima.element(o_start_ddd)
377  + c.n[1] * ima.element(o_start_dd)
378  + c.n[2] * ima.element(o_start_d)
379  + c.n[3] * ima.element(o_start)
380  - c.d[1] * tmp1[2] - c.d[2] * tmp1[1]
381  - c.d[3] * tmp1[0];
382 
383  unsigned
384  o_current = o_start + 4 * delta_offset,
385  o_current_d = o_current - delta_offset,
386  o_current_dd = o_current - 2 * delta_offset,
387  o_current_ddd = o_current - 3 * delta_offset;
388 
389  for (int i = 4; i < len; ++i)
390  {
391  tmp1[i] = 0
392  + c.n[0] * ima.element(o_current)
393  + c.n[1] * ima.element(o_current_d)
394  + c.n[2] * ima.element(o_current_dd)
395  + c.n[3] * ima.element(o_current_ddd)
396  - c.d[1] * tmp1[i - 1] - c.d[2] * tmp1[i - 2]
397  - c.d[3] * tmp1[i - 3] - c.d[4] * tmp1[i - 4];
398  o_current += delta_offset;
399  o_current_d += delta_offset;
400  o_current_dd += delta_offset;
401  o_current_ddd += delta_offset;
402  }
403 
404  // Non causal part
405 
406  (void) bdr;
407  // extension::fill(ima, bdr);
408 
409  unsigned
410  o_finish = ima.index_of_point(finish),
411  o_finish_d = o_finish - delta_offset,
412  o_finish_dd = o_finish - 2 * delta_offset;
413 
414  tmp2[len - 1] = 0;
415 
416  tmp2[len - 2] =
417  c.nm[1] * ima.element(o_finish);
418 
419  tmp2[len - 3] = 0
420  + c.nm[1] * ima.element(o_finish_d)
421  + c.nm[2] * ima.element(o_finish)
422  - c.dm[1] * tmp2[len-2];
423 
424  tmp2[len - 4] = 0
425  + c.nm[1] * ima.element(o_finish_dd)
426  + c.nm[2] * ima.element(o_finish_d)
427  + c.nm[3] * ima.element(o_finish)
428  - c.dm[1] * tmp2[len-3]
429  - c.dm[2] * tmp2[len-2];
430 
431  o_current = o_finish - 3 * delta_offset;
432  o_current_d = o_current + delta_offset;
433  o_current_dd = o_current + 2 * delta_offset;
434  o_current_ddd = o_current + 3 * delta_offset;
435 
436  for (int i = len - 5; i >= 0; --i)
437  {
438  tmp2[i] = 0
439  + c.nm[1] * ima.element(o_current)
440  + c.nm[2] * ima.element(o_current_d)
441  + c.nm[3] * ima.element(o_current_dd)
442  + c.nm[4] * ima.element(o_current_ddd)
443  - c.dm[1] * tmp2[i+1] - c.dm[2] * tmp2[i+2]
444  - c.dm[3] * tmp2[i+3] - c.dm[4] * tmp2[i+4];
445  o_current -= delta_offset;
446  o_current_d -= delta_offset;
447  o_current_dd -= delta_offset;
448  o_current_ddd -= delta_offset;
449  }
450 
451  // Combine results from causal and non-causal parts.
452 
453  o_current = o_start;
454  for (int i = 0; i < len; ++i)
455  {
456  ima.element(o_current) = static_cast<mln_value(I)>(tmp1[i] + tmp2[i]);
457  o_current += delta_offset;
458  }
459  }
460 
461 
462  template <typename I>
463  inline
464  mln_concrete(I)
465  gaussian_directional_2d(const Image<I>& input_,
466  unsigned dir, double sigma,
467  const mln_value(I)& bdr)
468  {
469  trace::entering("linear::gaussian_directional_2d");
470 
471  typedef mln_site(I) P;
472  mlc_bool(P::dim == 2)::check();
473 
474  const I& input = exact(input_);
475 
476  mln_precondition(dir == 0 || dir == 1);
477  mln_precondition(input.is_valid());
478 
479  my::recursivefilter_coef_ coef(1.68f, 3.735f,
480  1.783f, 1.723f,
481  -0.6803f, -0.2598f,
482  0.6318f, 1.997f,
483  sigma,
484  my::recursivefilter_coef_::DericheGaussian);
485 
486  extension::adjust_fill(input, 5 * int(sigma + .50001) + 1, bdr);
487  mln_concrete(I) output = duplicate(input);
488 
489  if (sigma < 0.006)
490  return output;
491 
492  int
493  nrows = geom::nrows(input),
494  ncols = geom::ncols(input),
495  b = input.border();
496 
497  if (dir == 0)
498  {
499  for (int j = 0; j < ncols; ++j)
500  recursivefilter_directional_fastest(output, coef,
501  point2d(- b, j),
502  point2d(nrows - 1 + b, j),
503  nrows + 2 * b,
504  dpoint2d(1, 0),
505  bdr);
506  }
507 
508  if (dir == 1)
509  {
510  for (int i = 0; i < nrows; ++i)
511  recursivefilter_directional_fastest(output, coef,
512  point2d(i, - b),
513  point2d(i, ncols - 1 + b),
514  ncols + 2 * b,
515  dpoint2d(0, 1),
516  bdr);
517  }
518 
519  trace::exiting("linear::gaussian_directional_2d");
520  return output;
521  }
522 
523 # endif // ! MLN_INCLUDE_ONLY
524 
525  } // end of namespace mln::linear
526 
527 } // end of namespace mln
528 
529 
530 #endif // ! MLN_LINEAR_GAUSSIAN_DIRECTIONAL_2D_HH