Milena (Olena)  User documentation 2.0a Id
 All Classes Namespaces Functions Variables Typedefs Enumerator Groups Pages
linear/gaussian/impl.hh
1 // Copyright (C) 2001, 2002, 2003, 2004, 2008, 2009, 2010, 2011 EPITA
2 // Research and Development Laboratory (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_IMPL_HH
28 # define MLN_LINEAR_GAUSSIAN_IMPL_HH
29 
36 
37 # include <vector>
38 # include <cmath>
39 
40 # include <mln/core/concept/image.hh>
41 # include <mln/core/alias/point2d.hh>
42 # include <mln/core/alias/dpoint1d.hh>
43 # include <mln/core/alias/dpoint3d.hh>
44 # include <mln/extension/adjust_fill.hh>
45 # include <mln/geom/ncols.hh>
46 # include <mln/geom/nrows.hh>
47 # include <mln/geom/ninds.hh>
48 # include <mln/geom/nslis.hh>
49 # include <mln/data/paste.hh>
50 # include <mln/data/stretch.hh>
51 # include <mln/algebra/vec.hh>
52 
53 # include <mln/linear/gaussian/internal/coefficients.hh>
54 
55 
56 namespace mln
57 {
58 
59  namespace linear
60  {
61 
62  namespace gaussian
63  {
64 
65  namespace impl
66  {
67 
68 
69 # ifndef MLN_INCLUDE_ONLY
70 
71  template <class WorkType, class I>
72  inline
73  void
74  recursivefilter_(I& ima,
75  const internal::coefficients& c,
76  const mln_psite(I)& start,
77  const mln_psite(I)& finish,
78  int len,
79  const mln_deduce(I, psite, delta)& d)
80  {
81  std::vector<WorkType> tmp1(len);
82  std::vector<WorkType> tmp2(len);
83 
84  // The fourth degree approximation implies to have a special
85  // look on the four first points we consider that there is
86  // no signal before 0 (to be discussed)
87 
88  // --
89  // Causal part
90 
91  tmp1[0] =
92  c.n[0] * ima(start);
93 
94  tmp1[1] =
95  c.n[0] * ima(start + d)
96  + c.n[1] * ima(start)
97  - c.d[1] * tmp1[0];
98 
99  tmp1[2] =
100  c.n[0] * ima(start + d + d)
101  + c.n[1] * ima(start + d)
102  + c.n[2] * ima(start)
103  - c.d[1] * tmp1[1]
104  - c.d[2] * tmp1[0];
105 
106  tmp1[3] =
107  c.n[0] * ima(start + d + d + d)
108  + c.n[1] * ima(start + d + d)
109  + c.n[2] * ima(start + d)
110  + c.n[3] * ima(start)
111  - c.d[1] * tmp1[2] - c.d[2] * tmp1[1]
112  - c.d[3] * tmp1[0];
113 
114  mln_psite(I) current(start + d + d + d + d);
115  for (mln_deduce(I, site, coord) i = 4; i < len; ++i)
116  {
117  tmp1[i] =
118  c.n[0] * ima(current)
119  + c.n[1] * ima(current - d)
120  + c.n[2] * ima(current - d - d)
121  + c.n[3] * ima(current - d - d - d)
122  - c.d[1] * tmp1[i - 1] - c.d[2] * tmp1[i - 2]
123  - c.d[3] * tmp1[i - 3] - c.d[4] * tmp1[i - 4];
124  current = current + d;
125  }
126 
127  // Non causal part
128 
129  tmp2[len - 1] = WorkType(); // FIXME : = 0, literal::zero ...?
130 
131  tmp2[len - 2] =
132  c.nm[1] * ima(finish);
133 
134  tmp2[len - 3] =
135  c.nm[1] * ima(finish - d)
136  + c.nm[2] * ima(finish)
137  - c.dm[1] * tmp2[len - 2];
138 
139  tmp2[len - 4] =
140  c.nm[1] * ima(finish - d - d)
141  + c.nm[2] * ima(finish - d)
142  + c.nm[3] * ima(finish)
143  - c.dm[1] * tmp2[len - 3]
144  - c.dm[2] * tmp2[len - 2];
145 
146  current = finish - d - d - d ;
147 
148  for (int i = len - 5; i >= 0; --i)
149  {
150  tmp2[i] =
151  c.nm[1] * ima(current)
152  + c.nm[2] * ima(current + d)
153  + c.nm[3] * ima(current + d + d)
154  + c.nm[4] * ima(current + d + d + d)
155  - c.dm[1] * tmp2[i + 1] - c.dm[2] * tmp2[i + 2]
156  - c.dm[3] * tmp2[i + 3] - c.dm[4] * tmp2[i + 4];
157  current = current - d;
158  }
159 
160  // Combine results from causal and non-causal parts.
161  current = start;
162  for (int i = 0; i < len; ++i)
163  {
164  ima(current) = tmp1[i] + tmp2[i];
165  current = current + d;
166  }
167  }
168 
169 
170  template <class I, class F>
171  inline
172  void
173  generic_filter_(trait::image::dimension::one_d,
174  Image<I>& img_, const F& coef, int dir)
175  {
176  I& img = exact(img_);
177  typedef mln_site(I) S; // Help g++-2.95.
178 
179  mln_precondition(dir < S::dim);
180 
181  recursivefilter_<mln_value(I)>(img, coef,
182  point1d(static_cast<def::coord>(-img.border())),
183  point1d(static_cast<def::coord>(geom::ninds(img) - 1 +
184  img.border())),
185  geom::ninds(img) + 2 * img.border(),
186  dpoint1d(1));
187  }
188 
189  template <class I, class F>
190  inline
191  void
192  generic_filter_(trait::image::dimension::two_d,
193  Image<I>& img_, const F& coef, int dir)
194  {
195  I& img = exact(img_);
196  typedef mln_site(I) S; // Help g++-2.95.
197 
198  mln_precondition(dir < S::dim);
199 
200  if (dir == 0)
201  {
202  // Apply on rows.
203  for (unsigned j = 0; j < geom::ncols(img); ++j)
204  recursivefilter_<mln_value(I)>(img, coef,
205  point2d(static_cast<def::coord>(-img.border()),
206  static_cast<def::coord>(j)),
207  point2d(static_cast<def::coord>(geom::nrows(img) - 1 +
208  img.border()),
209  static_cast<def::coord>(j)),
210  geom::nrows(img) + 2 * img.border(),
211  dpoint2d(1, 0));
212  }
213 
214  if (dir == 1)
215  {
216  // Apply on columns.
217  for (unsigned i = 0; i < geom::nrows(img); ++i)
218  recursivefilter_<mln_value(I)>(img, coef,
219  point2d(static_cast<def::coord>(i),
220  static_cast<def::coord>(-img.border())),
221  point2d(static_cast<def::coord>(i),
222  static_cast<def::coord>(geom::ncols(img) - 1 +
223  img.border())),
224  geom::ncols(img) + 2 * img.border(),
225  dpoint2d(0, 1));
226  }
227  }
228 
229  template <class I, class F>
230  inline
231  void
232  generic_filter_(trait::image::dimension::three_d,
233  Image<I>& img_, const F& coef, int dir)
234  {
235  I& img = exact(img_);
236  typedef mln_site(I) S; // Help g++-2.95.
237 
238  mln_precondition(dir < S::dim);
239 
240  if (dir == 0)
241  {
242  // Apply on slices.
243  for (unsigned j = 0; j < geom::nrows(img); ++j)
244  for (unsigned k = 0; k < geom::ncols(img); ++k)
245  recursivefilter_<mln_value(I)>(img, coef,
246  point3d(static_cast<def::coord>(-img.border()),
247  static_cast<def::coord>(j),
248  static_cast<def::coord>(k)),
249  point3d(static_cast<def::coord>(geom::nslis(img) - 1 +
250  img.border()),
251  static_cast<def::coord>(j),
252  static_cast<def::coord>(k)),
253  geom::nslis(img) + 2 *
254  img.border(),
255  dpoint3d(1, 0, 0));
256  }
257 
258 
259  if (dir == 1)
260  {
261  // Apply on rows.
262  for (unsigned i = 0; i < geom::nslis(img); ++i)
263  for (unsigned k = 0; k < geom::ncols(img); ++k)
264  recursivefilter_<mln_value(I)>(img, coef,
265  point3d(static_cast<def::coord>(i),
266  static_cast<def::coord>(-img.border()),
267  static_cast<def::coord>(k)),
268  point3d(static_cast<def::coord>(i),
269  static_cast<def::coord>(geom::nrows(img) - 1 +
270  img.border()),
271  static_cast<def::coord>(k)),
272  geom::nrows(img) + 2 *
273  img.border(),
274  dpoint3d(0, 1, 0));
275  }
276 
277  if (dir == 2)
278  {
279  // Apply on columns.
280  for (unsigned i = 0; i < geom::nslis(img); ++i)
281  for (unsigned j = 0; j < geom::nrows(img); ++i)
282  recursivefilter_<mln_value(I)>(img, coef,
283  point3d(static_cast<def::coord>(i),
284  static_cast<def::coord>(j),
285  static_cast<def::coord>(-img.border())),
286  point3d(static_cast<def::coord>(i),
287  static_cast<def::coord>(j),
288  static_cast<def::coord>(geom::ncols(img) -
289  1 + img.border())),
290  geom::ncols(img) + 2 *
291  img.border(),
292  dpoint3d(0, 0, 1));
293  }
294  }
295 
296 
297 
298  template <class I, class F, class O>
299  inline
300  void
301  generic_filter_common_(trait::value::nature::floating,
302  const Image<I>& in,
303  const F& coef,
304  double sigma,
305  Image<O>& out)
306  {
307  typedef mln_site(I) S; // Help g++-2.95.
308 
309  mln_ch_value(O, double) work_img(exact(in).domain());
310  data::paste(in, work_img);
311  extension::adjust_fill(work_img, 4, 0);
312 
313  // On tiny sigma, Derich algorithm doesn't work.
314  // It is the same thing that to convolve with a Dirac.
315  if (sigma > 0.006)
316  for (int i = 0; i < S::dim; ++i)
317  generic_filter_(mln_trait_image_dimension(I)(),
318  work_img, coef, i);
319 
320  // We don't need to convert work_img
321  data::paste(work_img, out);
322  }
323 
324  template <class I, class F, class O>
325  inline
326  void
327  generic_filter_common_(trait::value::nature::floating,
328  const Image<I>& in,
329  const F& coef,
330  double sigma,
331  Image<O>& out,
332  int dir)
333  {
334  mln_ch_value(O, double) work_img(exact(in).domain());
335  data::paste(in, work_img);
336  extension::adjust_fill(work_img, 4, 0);
337 
338  // On tiny sigma, Derich algorithm doesn't work.
339  // It is the same thing that to convolve with a Dirac.
340  if (sigma > 0.006)
341  generic_filter_(mln_trait_image_dimension(I)(),
342  work_img, coef, dir);
343 
344  // We don't need to convert work_img
345  data::paste(work_img, out);
346  }
347 
348 
349  template <class I, class F, class O>
350  inline
351  void
352  generic_filter_common_(trait::value::nature::scalar,
353  const Image<I>& in,
354  const F& coef,
355  double sigma,
356  Image<O>& out)
357  {
358  typedef mln_site(I) S; // Help g++-2.95.
359 
360  mln_ch_value(O, double) work_img(exact(in).domain());
361  data::paste(in, work_img);
362  extension::adjust_fill(work_img, 4, 0);
363 
364  // On tiny sigma, Derich algorithm doesn't work.
365  // It is the same thing that to convolve with a Dirac.
366  if (sigma > 0.006)
367  for (int i = 0; i < S::dim; ++i)
368  generic_filter_(mln_trait_image_dimension(I)(),
369  work_img, coef, i);
370 
371  // Convert work_img into result type
372  data::paste(data::stretch(mln_value(I)(), work_img), out);
373  }
374 
375  template <class I, class F, class O>
376  inline
377  void
378  generic_filter_common_(trait::value::nature::scalar,
379  const Image<I>& in,
380  const F& coef,
381  double sigma,
382  Image<O>& out,
383  int dir)
384  {
385  mln_ch_value(O, double) work_img(exact(in).domain());
386  data::paste(in, work_img);
387  extension::adjust_fill(work_img, 4, 0);
388 
389  // On tiny sigma, Derich algorithm doesn't work.
390  // It is the same thing that to convolve with a Dirac.
391  if (sigma > 0.006)
392  generic_filter_(mln_trait_image_dimension(I)(),
393  work_img, coef, dir);
394 
395  // Convert work_img into result type
396  data::paste(data::stretch(mln_value(I)(), work_img), out);
397  }
398 
399 
400 
401  template <class I, class F, class O>
402  inline
403  void
404  generic_filter_common_(trait::value::nature::vectorial,
405  const Image<I>& in,
406  const F& coef,
407  double sigma,
408  Image<O>& out)
409  {
410  typedef mln_site(I) S; // Help g++-2.95.
411 
412  // typedef algebra::vec<3, double> vec3f;
413  // mln_ch_value(O, vec3f) work_img(exact(in).domain());
414  // FIXME : paste does not work (rgb8 -> vec3f).
415  data::paste(in, out);
416 
417  // On tiny sigma, Derich algorithm doesn't work.
418  // It is the same thing that to convolve with a Dirac.
419  if (sigma > 0.006)
420  for (int i = 0; i < S::dim; ++i)
421  generic_filter_(mln_trait_image_dimension(I)(),
422  out, coef, i);
423  }
424 
425  template <class I, class F, class O>
426  inline
427  void
428  generic_filter_common_(trait::value::nature::vectorial,
429  const Image<I>& in,
430  const F& coef,
431  double sigma,
432  Image<O>& out,
433  int dir)
434  {
435  // typedef algebra::vec<3, double> vec3f;
436  // mln_ch_value(O, vec3f) work_img(exact(in).domain());
437  // FIXME : paste does not work (rgb8 -> vec3f).
438  data::paste(in, out);
439 
440  // On tiny sigma, Derich algorithm doesn't work.
441  // It is the same thing that to convolve with a Dirac.
442  if (sigma > 0.006)
443  generic_filter_(mln_trait_image_dimension(I)(),
444  out, coef, dir);
445  }
446 
447 
448 # endif // ! MLN_INCLUDE_ONLY
449 
450 
451  } // end of namespace mln::linear::gaussian::impl
452 
453  } // end of namespace mln::linear::gaussian
454 
455 } // end of namespace mln::linear
456 
457 } // end of namespace mln
458 
459 
460 #endif // ! MLN_LINEAR_GAUSSIAN_IMPL_HH