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