00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028 #ifndef OLENA_TRANSFORMS_FFT_HH
00029 # define OLENA_TRANSFORMS_FFT_HH
00030
00031
00032
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
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
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 }
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 }
00598
00599 }
00600
00601 # endif // HAVE_FFTW
00602
00603 #endif // ! OLENA_TRANSFORM_FFT_HH