fft.hh

00001 // Copyright (C) 2001, 2002, 2003, 2004  EPITA Research and Development Laboratory
00002 //
00003 // This file is part of the Olena Library.  This library is free
00004 // software; you can redistribute it and/or modify it under the terms
00005 // of the GNU General Public License version 2 as published by the
00006 // Free Software Foundation.
00007 //
00008 // This library is distributed in the hope that it will be useful,
00009 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00010 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00011 // General Public License for more details.
00012 //
00013 // You should have received a copy of the GNU General Public License
00014 // along with this library; see the file COPYING.  If not, write to
00015 // the Free Software Foundation, 59 Temple Place - Suite 330, Boston,
00016 // MA 02111-1307, USA.
00017 //
00018 // As a special exception, you may use this file as part of a free
00019 // software library without restriction.  Specifically, if other files
00020 // instantiate templates or use macros or inline functions from this
00021 // file, or you compile this file and link it with other files to
00022 // produce an executable, this file does not by itself cause the
00023 // resulting executable to be covered by the GNU General Public
00024 // License.  This exception does not however invalidate any other
00025 // reasons why the executable file might be covered by the GNU General
00026 // Public License.
00027 
00028 #ifndef OLENA_TRANSFORMS_FFT_HH
00029 # define OLENA_TRANSFORMS_FFT_HH
00030 
00031 // FIXME: this file has not been adjusted to the coding style since it
00032 // will be completely rewritten in next release.
00033 
00034 # include <oln/config/system.hh>
00035 
00036 # ifdef HAVE_FFTW
00037 
00038 #  include <fftw.h>
00039 #  include <rfftw.h>
00040 
00041 #  include <ntg/basics.hh>
00042 #  include <ntg/all.hh>
00043 #  include <oln/basics2d.hh>
00044 
00045 namespace oln {
00046 
00047   namespace internal {
00048 
00050     enum fft_dispatch { fft_cplx, fft_real };
00051 
00055     template <class T>
00056     struct fft_trait
00057     {
00058       void ensure() { ntg_is_a(T, ntg::real)::ensure(); }
00059 
00060       static const fft_dispatch         which = fft_real; 
00061       typedef fftw_real                 fftw_input; 
00062     };
00063 
00069     template <ntg::cplx_representation R, class T>
00070     struct fft_trait<ntg::cplx<R, T> >
00071     {
00072       static const fft_dispatch         which = fft_cplx; 
00073       typedef fftw_complex              fftw_input; 
00074     };
00075 
00082     template <class T, ntg::cplx_representation R>
00083     class _fft
00084     {
00085     public:
00091       const image2d<ntg::cplx<R, ntg::float_d> > transformed_image() const
00092       {
00093         return trans_im;
00094       }
00095 
00101       image2d<ntg::cplx<R, ntg::float_d> >& transformed_image()
00102       {
00103         return trans_im;
00104       }
00105 
00116       template <class T1>
00117       image2d<T1> transformed_image_magn(bool ordered = true) const
00118       {
00119         ntg_is_a(T1, ntg::real)::ensure();
00120 
00121         image2d<T1> new_im(trans_im.size());
00122 
00123         if (ordered)
00124           for (int row = 0; row < new_im.nrows(); ++row)
00125             for (int col = 0; col < new_im.ncols(); ++col)
00126               new_im(row, col) =
00127                 trans_im((row + trans_im.nrows() / 2) % trans_im.nrows(),
00128                          (col + trans_im.ncols() / 2) % trans_im.ncols()).magn();
00129         else
00130           {
00131             typename image2d<ntg::cplx<R, ntg::float_d> >::iter it(trans_im);
00132 
00133             for_all(it)
00134               new_im[it] = trans_im[it].magn();
00135           }
00136 
00137         return new_im;
00138       }
00139 
00148       image2d<T> transformed_image_magn(bool ordered = true) const
00149       {
00150         return transformed_image_magn<T>(ordered);
00151       }
00152 
00164       template <class T1>
00165       image2d<T1> transformed_image_clipped_magn(const ntg::float_d clip,
00166                                                  bool ordered = true) const
00167       {
00168         ntg_is_a(T1, ntg::real)::ensure();
00169 
00170         image2d<T1> new_im(trans_im.size());
00171         ntg::range<ntg::float_d, ntg::bounded_u<0, 1>, ntg::saturate> c(clip);
00172         ntg::float_d max = 0;
00173         typename image2d<ntg::cplx<R, ntg::float_d> >::iter_type it(trans_im);
00174 
00175         for_all(it)
00176           if (max < trans_im[it].magn())
00177             max = trans_im[it].magn();
00178 
00179         if (ordered)
00180           for (int row = 0; row < new_im.nrows(); ++row)
00181             for (int col = 0; col < new_im.ncols(); ++col)
00182               {
00183                 if (trans_im((row + trans_im.nrows() / 2) % trans_im.nrows(),
00184                              (col + trans_im.ncols() / 2) %
00185                              trans_im.ncols()).magn() >= max * c)
00186                   new_im(row, col) = ntg_max_val(T);
00187                 else
00188                   new_im(row, col) =
00189                     ntg_max_val(T) *
00190                     trans_im((row + trans_im.nrows() / 2) % trans_im.nrows(),
00191                              (col + trans_im.ncols() / 2) %
00192                              trans_im.ncols()).magn() / (max * c);
00193               }
00194         else
00195           for_all(it)
00196               {
00197                 if (trans_im[it].magn() >= max * c)
00198                   new_im[it] = ntg_max_val(T);
00199                 else
00200                   new_im[it] = ntg_max_val(T) *
00201                     trans_im[it].magn() / (max * c);
00202               }
00203 
00204         return new_im;
00205       }
00206 
00216       image2d<T> transformed_image_clipped_magn(const ntg::float_d clip,
00217                                                 bool ordered = true) const
00218       {
00219         return transformed_image_clipped_magn<T>(clip, ordered);
00220       }
00221 
00232       template <class T1>
00233       image2d<T1> transformed_image_clipped_magn(bool ordered = true) const
00234       {
00235         return transformed_image_clipped_magn<T1>(1, ordered);
00236       }
00237 
00248       image2d<T> transformed_image_clipped_magn(bool ordered = true) const
00249       {
00250         return transformed_image_clipped_magn<T>(1, ordered);
00251       }
00252 
00253       // FIXME: Find a more elegant way to fix range interval on a and b.
00264       template <class T1>
00265       image2d<T1> transformed_image_log_magn(const ntg::range<ntg::float_d,
00266                                              ntg::bounded_u<0, 1000>,
00267                                              ntg::saturate> a,
00268                                              const ntg::range<ntg::float_d,
00269                                              ntg::bounded_u<0, 1000>,
00270                                              ntg::saturate> b,
00271                                              bool ordered = true) const
00272       {
00273         ntg_is_a(T1, ntg::real)::ensure();
00274 
00275         image2d<T1> new_im(trans_im.size());
00276         ntg::float_d max = 0;
00277         typename image2d<ntg::cplx<R, ntg::float_d> >::iter_type it(trans_im);
00278 
00279         for_all(it)
00280           if (max < trans_im[it].magn())
00281             max = trans_im[it].magn();
00282 
00283         if (ordered)
00284           for (int row = 0; row < new_im.nrows(); ++row)
00285             for (int col = 0; col < new_im.ncols(); ++col)
00286               new_im(row, col) =
00287                 log(a + b * trans_im((row + trans_im.nrows() / 2) %
00288                                      trans_im.nrows(),
00289                                      (col + trans_im.ncols() / 2) %
00290                                      trans_im.ncols()).magn()) /
00291                 log(a + b * max) * ntg_max_val(T);
00292         else
00293           for_all(it)
00294             new_im[it] = log(a + b * trans_im[it].magn()) /
00295             log(a + b * max) * ntg_max_val(T);
00296 
00297         return new_im;
00298       }
00299 
00300       // FIXME: Find a more elegant way to fix boundaries of a and b.
00311       image2d<T> transformed_image_log_magn(const ntg::range<ntg::float_d,
00312                                             ntg::bounded_u<0, 1000>,
00313                                             ntg::saturate> a,
00314                                             const ntg::range<ntg::float_d,
00315                                             ntg::bounded_u<0, 1000>,
00316                                             ntg::saturate> b,
00317                                             bool ordered = true) const
00318       {
00319         return transformed_image_log_magn<T>(a, b, ordered);
00320       }
00321 
00332       template <class T1>
00333       image2d<T1> transformed_image_log_magn(bool ordered = true) const
00334       {
00335         return transformed_image_log_magn<T1>(1, 100, ordered);
00336       }
00337 
00346       image2d<T> transformed_image_log_magn(bool ordered = true) const
00347       {
00348         return transformed_image_log_magn<T>(1, 100, ordered);
00349       }
00350 
00356       ~_fft()
00357       {
00358         delete [] in;
00359         delete [] out;
00360         fftwnd_destroy_plan(p);
00361         fftwnd_destroy_plan(p_inv);
00362       }
00363 
00364     protected:
00365 
00366       typename fft_trait<T>::fftw_input *in; 
00367       fftw_complex                      *out; 
00368       fftwnd_plan                       p; 
00369       fftwnd_plan                       p_inv; 
00370       image2d<ntg::cplx<R, ntg::float_d> >              trans_im; 
00371 
00372     };
00373 
00374   } // end of namespace internal
00375 
00376   namespace transforms {
00377 
00385     template <class T,
00386               ntg::cplx_representation R = ntg::polar,
00387               internal::fft_dispatch which = internal::fft_trait<T>::which >
00388     class fft;
00389 
00396     template <class T, ntg::cplx_representation R>
00397     class fft<T, R, internal::fft_real> : public internal::_fft<T, R>
00398     {
00399 
00400     public:
00401 
00409       fft(const image2d<T>& original_im)
00410       {
00411         this->in  = new fftw_real[original_im.nrows() * original_im.ncols()];
00412         this->out = new fftw_complex[original_im.nrows() *
00413                                      (original_im.ncols() / 2 + 1)];
00414 
00415         for (int row = 0; row < original_im.nrows(); ++row)
00416           for (int col = 0; col < original_im.ncols(); ++col)
00417             this->in[row * original_im.ncols() + col] = original_im(row, col);
00418 
00419         this->p = rfftw2d_create_plan(original_im.nrows(), original_im.ncols(),
00420                                 FFTW_REAL_TO_COMPLEX, FFTW_ESTIMATE);
00421         this->p_inv = rfftw2d_create_plan(original_im.nrows(), original_im.ncols(),
00422                                     FFTW_COMPLEX_TO_REAL, FFTW_ESTIMATE);
00423 
00424         this->trans_im = image2d<ntg::cplx<R, ntg::float_d> >(original_im.size());
00425       }
00426 
00430       image2d<ntg::cplx<R, ntg::float_d> > transform()
00431       {
00432         rfftwnd_one_real_to_complex(this->p, this->in, this->out);
00433 
00434         unsigned denom = this->trans_im.nrows() * this->trans_im.ncols();
00435         int i = 0;
00436         for (int row = 0; row < this->trans_im.nrows(); ++row)
00437           for (int col = 0; col <= this->trans_im.ncols() / 2; ++col)
00438             {
00439               this->out[i].re /= denom;
00440               this->out[i].im /= denom;
00441               this->trans_im(row, col) = ntg::cplx<ntg::rect, ntg::float_d>(this->out[i].re,
00442                                                              this->out[i].im);
00443               ++i;
00444             }
00445         for (int row = 0; row < this->trans_im.nrows(); ++row)
00446           for (int col = this->trans_im.ncols() - 1; col > this->trans_im.ncols() / 2; --col)
00447             this->trans_im(row, col) = this->trans_im(this->trans_im.nrows() - row - 1,
00448                                           this->trans_im.ncols() - col - 1);
00449         return this->trans_im;
00450       }
00451 
00457       template <class T1>
00458       image2d<T1> transform_inv()
00459       {
00460         ntg_is_a(T1, ntg::real)::ensure();
00461 
00462         for (int row = 0; row < this->trans_im.nrows(); ++row)
00463           for (int col = 0; col <= this->trans_im.ncols() / 2; ++col)
00464             {
00465               this->out[row * (this->trans_im.ncols() / 2 + 1) + col].re =
00466                 this->trans_im(row, col).real();
00467               this->out[row * (this->trans_im.ncols() / 2 + 1) + col].im =
00468                 this->trans_im(row, col).imag();
00469             }
00470         rfftwnd_one_complex_to_real(this->p_inv, this->out, this->in);
00471 
00472         image2d<T1> new_im(this->trans_im.size());
00473         int i = 0;
00474         for (int row = 0; row < this->trans_im.nrows(); ++row)
00475           for (int col = 0; col < this->trans_im.ncols(); ++col)
00476             {
00477               new_im(row, col) = (this->in[i] >= ntg_inf_val(T1) ?
00478                                   (this->in[i] <= ntg_sup_val(T1) ?
00479                                    this->in [i] :
00480                                    ntg_sup_val(T1)) :
00481                                   ntg_inf_val(T1));
00482               ++i;
00483             }
00484         return new_im;
00485       }
00486 
00490       image2d<T> transform_inv()
00491       {
00492         return transform_inv<T>();
00493       }
00494 
00495     };
00496 
00503     template <class T, ntg::cplx_representation R>
00504     class fft<T, R, internal::fft_cplx> : public internal::_fft<T, R>
00505     {
00506 
00507     public:
00508 
00516       template <ntg::cplx_representation R1>
00517       fft(const image2d<ntg::cplx<R1, T> >& original_im)
00518       {
00519         this->in = new fftw_complex[original_im.nrows() * original_im.ncols()];
00520         this->out = new fftw_complex[original_im.nrows() * original_im.ncols()];
00521 
00522         for (int row = 0; row < original_im.nrows(); ++row)
00523           for (int col = 0; col < original_im.ncols(); ++col)
00524             {
00525               this->in[row * original_im.ncols() + col].re =
00526                 original_im(row, col).real();
00527               this->in[row * original_im.ncols() + col].im =
00528                 original_im(row, col).imag();
00529             }
00530 
00531         this->p = fftw2d_create_plan(original_im.nrows(), original_im.ncols(),
00532                                      FFTW_FORWARD, FFTW_ESTIMATE);
00533         this->p_inv = fftw2d_create_plan(original_im.nrows(), original_im.ncols(),
00534                                          FFTW_BACKWARD, FFTW_ESTIMATE);
00535 
00536         this->trans_im = image2d<ntg::cplx<ntg::rect, ntg::float_d> >(original_im.size());
00537       }
00538 
00542       image2d<ntg::cplx<R, ntg::float_d> > transform()
00543       {
00544         fftwnd_one(this->p, this->in, this->out);
00545 
00546         unsigned denom = this->trans_im.nrows() * this->trans_im.ncols();
00547         int i = 0;
00548         for (int row = 0; row < this->trans_im.nrows(); ++row)
00549           for (int col = 0; col < this->trans_im.ncols(); ++col)
00550             {
00551               this->out[i].re /= denom;
00552               this->out[i].im /= denom;
00553               this->trans_im(row, col) = ntg::cplx<ntg::rect, ntg::float_d>(this->out[i].re,
00554                                                        this->out[i].im);
00555               ++i;
00556             }
00557         return this->trans_im;
00558       }
00559 
00565       template <class T1>
00566       image2d<ntg::cplx<R, T1> > transform_inv()
00567       {
00568         for (int row = 0; row < this->trans_im.nrows(); ++row)
00569           for (int col = 0; col < this->trans_im.ncols(); ++col)
00570             {
00571               this->out[row * this->trans_im.ncols() + col].re = this->trans_im(row, col).real();
00572               this->out[row * this->trans_im.ncols() + col].im = this->trans_im(row, col).imag();
00573             }
00574         fftwnd_one(this->p_inv, this->out, this->in);
00575 
00576         image2d<ntg::cplx<R, T1> > new_im(this->trans_im.size());
00577         int i = 0;
00578         for (int row = 0; row < this->trans_im.nrows(); ++row)
00579           for (int col = 0; col < this->trans_im.ncols(); ++col)
00580             {
00581               new_im(row, col) = this->in[i];
00582               ++i;
00583             }
00584         return new_im;
00585       }
00586 
00590       image2d<ntg::cplx<R, T> > transform_inv()
00591       {
00592         return transform_inv<T>();
00593       }
00594 
00595     };
00596 
00597   } // end of namespace transforms
00598 
00599 } // end of namespace oln
00600 
00601 # endif // HAVE_FFTW
00602 
00603 #endif // ! OLENA_TRANSFORM_FFT_HH

Generated on Thu Apr 15 20:13:09 2004 for Olena by doxygen 1.3.6-20040222