$extrastylesheet
Olena  User documentation 2.1
An Image Processing Platform
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
fft.hh
1 // Copyright (C) 2007, 2008, 2009, 2012 EPITA Research and Development
2 // Laboratory
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_TRANSFORM_FFT_HH
28 # define MLN_TRANSFORM_FFT_HH
29 
30 # include <complex>
31 
32 # include <fftw3.h>
33 
34 # include <mln/core/image/image2d.hh>
35 # include <mln/estim/min_max.hh>
36 # include <mln/opt/at.hh>
37 
38 
39 namespace mln
40 {
41 
42  namespace internal
43  {
44 
47 
48 
50  template <typename T>
51  struct fft_trait;
52 
54  template <>
55  struct fft_trait<double>
56  {
58  static const fft_dispatch which = fft_real;
60  typedef double fftw_input;
61  };
62 
64  template <typename T>
65  struct fft_trait< std::complex<T> >
66  {
68  static const fft_dispatch which = fft_cplx;
70  typedef std::complex<T> fftw_input;
71  };
72 
73 
79  template <class T>
80  class fft
81  {
82  public:
85 
88 
97  template <class R>
98  image2d<R> transformed_image_magn(bool ordered = true) const;
99 
106  image2d<T> transformed_image_magn(bool ordered = true) const;
107 
118  template <class R>
120  bool ordered = true) const;
121 
131  bool ordered = true) const;
132 
142  template <class R>
143  image2d<R> transformed_image_clipped_magn(bool ordered = true) const;
144 
152  image2d<T> transformed_image_clipped_magn(bool ordered = true) const;
153 
166  template <class R>
167  image2d<R> transformed_image_log_magn(double a, double b,
168  bool ordered = true) const;
169 
180  image2d<T> transformed_image_log_magn(double a, double b,
181  bool ordered = true) const;
182 
193  template <class R>
194  image2d<R> transformed_image_log_magn(bool ordered = true) const;
195 
204  image2d<T> transformed_image_log_magn(bool ordered = true) const;
205 
206  ~fft();
207 
208  protected:
210  typename fft_trait<T>::fftw_input* in;
212  std::complex<T>* out;
214  fftw_plan p;
216  fftw_plan p_inv;
220  };
221 
222  } // end of namespace mln::internal
223 
224 
225  namespace transform
226  {
227 
234  template <class T,
235  internal::fft_dispatch which = internal::fft_trait<T>::which >
236  class fft;
237 
238 
242  template <class T>
243  class fft<T, internal::fft_real> : public internal::fft<T>
244  {
245  public:
251  template <typename D>
252  fft(const image2d<D>& original_im);
253 
256 
261  template <class R>
262  image2d<R> transform_inv();
263 
265  image2d<T> transform_inv();
266  };
267 
268 
272  template <class T>
273  class fft<T, internal::fft_cplx> : public internal::fft<T>
274  {
275  public:
281  fft(const image2d< std::complex<T> >& original_im);
282 
285 
291  template <class R>
292  image2d< std::complex<R> > transform_inv();
293 
295  image2d< std::complex<T> > transform_inv();
296  };
297 
298  } // end of namespace mln::transform
299 
300 
301 
302 # ifndef MLN_INCLUDE_ONLY
303 
304  namespace internal
305  {
306 
307  template <class T>
308  inline
309  const image2d< std::complex<T> >&
311  {
312  return trans_im;
313  }
314 
315  template <class T>
316  inline
317  image2d< std::complex<T> >&
319  {
320  return trans_im;
321  }
322 
323  template <class T>
324  template <class R>
325  inline
326  image2d<R>
327  fft<T>::transformed_image_magn(bool ordered) const
328  {
329  // FIXME: Ensure R is real.
330 
331  const unsigned nrows = trans_im.nrows();
332  const unsigned ncols = trans_im.ncols();
333  image2d<R> new_im(trans_im.domain());
334  if (ordered)
335  for (unsigned row = 0; row < new_im.nrows(); ++row)
336  for (unsigned col = 0; col < new_im.ncols(); ++col)
337  opt::at(new_im, row, col) =
338  std::norm(opt::at(trans_im,
339  (row + nrows / 2) % nrows,
340  (col + ncols / 2) % ncols));
341  else
342  {
343  mln_piter(image2d< std::complex<T> >) it(trans_im.domain());
344  for_all(it)
345  new_im(it) = std::norm(trans_im(it));
346  }
347  return new_im;
348  }
349 
350  template <class T>
351  inline
352  image2d<T>
353  fft<T>::transformed_image_magn(bool ordered) const
354  {
355  return transformed_image_magn<T>(ordered);
356  }
357 
358  template <class T>
359  template <class R>
360  inline
361  image2d<R>
362  fft<T>::transformed_image_clipped_magn(double clip, bool ordered) const
363  {
364  // FIXME: Ensure R is real.
365  // FIXME: Ensure `clip' is between 0 and 1?
366 
367  double max = mln_min(double);
368  mln_piter(image2d<T>) it(trans_im.domain());
369  for_all(it)
370  if (std::norm(trans_im(it)) > max)
371  max = std::norm(trans_im(it));
372 
373  const unsigned nrows = trans_im.nrows();
374  const unsigned ncols = trans_im.ncols();
375  image2d<R> new_im(trans_im.domain());
376  if (ordered)
377  for (unsigned row = 0; row < new_im.nrows(); ++row)
378  for (unsigned col = 0; col < new_im.ncols(); ++col)
379  if (std::norm(opt::at(trans_im,
380  (row + nrows / 2) % nrows,
381  (col + ncols / 2) % ncols))
382  >= max * clip)
383  opt::at(new_im, row, col) = mln_max(R);
384  else
385  opt::at(new_im, row, col) =
386  (double) mln_max(R) *
387  std::norm(opt::at(trans_im,
388  (row + nrows / 2) % nrows,
389  (col + ncols / 2) % ncols)) / (max * clip);
390  else
391  for_all(it)
392  if (std::norm(trans_im(it)) >= max * clip)
393  new_im(it) = mln_max(R);
394  else
395  new_im(it) =
396  (double) mln_max(R) * std::norm(trans_im(it)) / (max * clip);
397  return new_im;
398  }
399 
400  template <class T>
401  inline
402  image2d<T>
403  fft<T>::transformed_image_clipped_magn(double clip, bool ordered) const
404  {
405  return transformed_image_clipped_magn<T>(clip, ordered);
406  }
407 
408  template <class T>
409  template <class R>
410  inline
411  image2d<R>
412  fft<T>::transformed_image_clipped_magn(bool ordered) const
413  {
414  return transformed_image_clipped_magn<R>(1, ordered);
415  }
416 
417  template <class T>
418  inline
419  image2d<T>
420  fft<T>::transformed_image_clipped_magn(bool ordered) const
421  {
422  return transformed_image_clipped_magn<T>(1, ordered);
423  }
424 
425  template <class T>
426  template <class R>
427  inline
428  image2d<R>
429  fft<T>::transformed_image_log_magn(double a, double b, bool ordered) const
430  {
431  /* FIXME: Find a more elegant way to fix range interval on a
432  and b (Note from Roland: what does it mean?). */
433 
434  // FIXME: Ensure R is real.
435  // FIXME: Ensure 0 <= a <= 1000.
436  // FIXME: Ensure 0 <= b <= 1000.
437 
438  image2d<R> new_im(trans_im.domain());
439 
440  double max = mln_min(double);
441  mln_piter(image2d<R>) it(trans_im.domain());
442  for_all(it)
443  if (std::norm(trans_im(it)) > max)
444  max = std::norm(trans_im(it));
445 
446  const unsigned nrows = trans_im.nrows();
447  const unsigned ncols = trans_im.ncols();
448  if (ordered)
449  for (unsigned row = 0; row < new_im.nrows(); ++row)
450  for (unsigned col = 0; col < new_im.ncols(); ++col)
451  opt::at(new_im, row, col) =
452  log(a + b * std::norm(opt::at(trans_im,
453  (row + nrows / 2) % nrows,
454  (col + ncols / 2) % ncols)))
455  / log (a + b * max) * mln_max(R);
456  else
457  {
458  mln_piter(image2d< std::complex<T> >) it(trans_im.domain());
459  for_all(it)
460  new_im(it) =
461  log(a + b * std::norm(trans_im(it)))
462  / log (a + b * max) * mln_max(R);
463  }
464  return new_im;
465  }
466 
467  template <class T>
468  inline
469  image2d<T>
470  fft<T>::transformed_image_log_magn(double a, double b, bool ordered) const
471  {
472  return transformed_image_log_magn<T>(a, b, ordered);
473  }
474 
475  template <class T>
476  template <class R>
477  inline
478  image2d<R>
479  fft<T>::transformed_image_log_magn(bool ordered) const
480  {
481  return transformed_image_log_magn<R>(1, 100, ordered);
482  }
483 
484  template <class T>
485  inline
486  image2d<T>
487  fft<T>::transformed_image_log_magn(bool ordered) const
488  {
489  return transformed_image_log_magn<T>(1, 100, ordered);
490  }
491 
492  template <class T>
493  inline
494  fft<T>::~fft()
495  {
496  fftw_free(in);
497  fftw_free(out);
498  fftw_destroy_plan(p);
499  fftw_destroy_plan(p_inv);
500  }
501 
502  } // end of namespace mln::internal
503 
504 
505  namespace transform
506  {
507 
508  /*--------------------------------------------------------.
509  | FFT engine (specialization for images of real values). |
510  `--------------------------------------------------------*/
511 
512  template <class T>
513  template <typename D>
514  inline
515  fft<T, internal::fft_real>::fft(const image2d<D>& original_im)
516  {
517  const unsigned nrows = original_im.nrows();
518  const unsigned ncols = original_im.ncols();
519 
520  this->in = (T*) fftw_malloc(nrows * ncols * sizeof(T));
521  this->out = (std::complex<T>*) fftw_malloc(nrows
522  * (ncols / 2 + 1)
523  * sizeof(std::complex<T>));
524 
525  for (unsigned row = 0; row < nrows; ++row)
526  for (unsigned col = 0; col < ncols; ++col)
527  this->in[row * ncols + col] =
528  opt::at(original_im, row, col);
529 
530  this->p =
531  fftw_plan_dft_r2c_2d (nrows, ncols,
532  this->in,
533  reinterpret_cast<fftw_complex*>(this->out),
534  FFTW_ESTIMATE);
535  this->p_inv =
536  fftw_plan_dft_c2r_2d (nrows, ncols,
537  reinterpret_cast<fftw_complex*>(this->out),
538  this->in,
539  FFTW_ESTIMATE);
540  this->trans_im = image2d< std::complex<T> >(original_im.domain());
541  }
542 
543  template <class T>
544  inline
545  image2d< std::complex<T> >
547  {
548  fftw_execute(this->p);
549 
550  const unsigned nrows = this->trans_im.nrows();
551  const unsigned ncols = this->trans_im.ncols();
552  unsigned denom = nrows * ncols;
553  int i = 0;
554  for (unsigned row = 0; row < nrows; ++row)
555  for (unsigned col = 0; col <= ncols / 2; ++col)
556  {
557  this->out[i] = std::complex<T> (this->out[i].real() / denom,
558  this->out[i].imag() / denom);
559  opt::at(this->trans_im, row, col) = this->out[i];
560  ++i;
561  }
562  for (unsigned row = 0; row < nrows; ++row)
563  for (unsigned col = ncols - 1; col > ncols / 2; --col)
564  opt::at(this->trans_im, row, col) =
565  opt::at(this->trans_im, nrows - row - 1, ncols - col - 1);
566  return this->trans_im;
567  }
568 
569  template <class T>
570  template <class R>
571  inline
572  image2d<R>
573  fft<T, internal::fft_real>::transform_inv()
574  {
575  // FIXME: Ensure R is real.
576 
577  const unsigned nrows = this->trans_im.nrows();
578  const unsigned ncols = this->trans_im.ncols();
579  for (unsigned row = 0; row < nrows; ++row)
580  for (unsigned col = 0; col <= ncols / 2; ++col)
581  this->out[row * (ncols / 2 + 1) + col] =
582  opt::at(this->trans_im, row, col);
583 
584  fftw_execute(this->p_inv);
585 
586  image2d<R> new_im(this->trans_im.domain());
587  int i = 0;
588  for (unsigned row = 0; row < nrows; ++row)
589  for (unsigned col = 0; col < ncols; ++col)
590  {
591  opt::at(new_im, row, col) = (this->in[i] >= mln_min(R)
592  ? (this->in[i] <= mln_max(R)
593  ? (R) this->in [i]
594  : mln_min(R))
595  : mln_max(R));
596  ++i;
597  }
598  return new_im;
599  }
600 
601  template <class T>
602  inline
603  image2d<T>
604  fft<T, internal::fft_real>::transform_inv()
605  {
606  return transform_inv<T>();
607  }
608 
609 
610  /*-----------------------------------------------------------.
611  | FFT engine (specialization for images of complex values). |
612  `-----------------------------------------------------------*/
613 
614  template <class T>
615  inline
616  fft<T, internal::fft_cplx>::fft(const image2d< std::complex<T> >& original_im)
617  {
618  const unsigned nrows = original_im.nrows();
619  const unsigned ncols = original_im.ncols();
620 
621  this->in = fftw_malloc(sizeof(std::complex<T>) * nrows * ncols);
622  this->out = fftw_malloc(sizeof(std::complex<T>) * nrows * ncols);
623 
624  for (unsigned row = 0; row < nrows; ++row)
625  for (unsigned col = 0; col < ncols; ++col)
626  {
627  this->in[row * ncols + col].re = original_im(row, col).real();
628  this->in[row * ncols + col].im = original_im(row, col).imag();
629  }
630 
631  this->p = fftw_plan_dft_2d(nrows, ncols, this->in, this->out,
632  FFTW_FORWARD, FFTW_ESTIMATE);
633  this->p_inv = fftw_plan_dft_2d(nrows, ncols, this->out, this->in,
634  FFTW_BACKWARD, FFTW_ESTIMATE);
635  this->trans_im = image2d< std::complex<T> >(original_im.domain());
636  }
637 
638  template <class T>
639  inline
640  image2d< std::complex<T> >
642  {
643  fftw_execute(this->p);
644 
645  const unsigned nrows = this->trans_im.nrows();
646  const unsigned ncols = this->trans_im.ncols();
647  unsigned denom = nrows * ncols;
648  int i = 0;
649  for (unsigned row = 0; row < nrows; ++row)
650  for (unsigned col = 0; col < ncols; ++col)
651  {
652  this->out[i].re /= denom;
653  this->out[i].im /= denom;
654  this->trans_im(row, col) =
655  std::complex<double>(this->out[i].re, this->out[i].im);
656  ++i;
657  }
658  return this->trans_im;
659  }
660 
661  template <class T>
662  template <class R>
663  inline
664  image2d< std::complex<R> >
665  fft<T, internal::fft_cplx>::transform_inv()
666  {
667  const unsigned nrows = this->trans_im.nrows();
668  const unsigned ncols = this->trans_im.ncols();
669  for (unsigned row = 0; row < nrows; ++row)
670  for (unsigned col = 0; col < ncols; ++col)
671  {
672  this->out[row * ncols + col].re =
673  this->trans_im(row, col).real();
674  this->out[row * ncols + col].im =
675  this->trans_im(row, col).imag();
676  }
677 
678  fftw_execute(this->p_inv);
679 
680  image2d< std::complex<R> > new_im(this->trans_im.size());
681  int i = 0;
682  for (unsigned row = 0; row < nrows; ++row)
683  for (unsigned col = 0; col < ncols; ++col)
684  {
685  new_im(row, col) = this->in[i];
686  ++i;
687  }
688  return new_im;
689  }
690 
691  template <class T>
692  inline
693  image2d< std::complex<T> >
694  fft<T, internal::fft_cplx>::transform_inv()
695  {
696  return transform_inv<T>();
697  }
698 
699  } // end of namespace mln::transform
700 
701 # endif // ! MLN_INCLUDE_ONLY
702 
703 } // end of namespace mln
704 
705 #endif // ! MLN_TRANSFORM_FFT_HH