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
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038 #ifndef IMAGE_FOURIERENGINE_C_DEFINED
00039 #define IMAGE_FOURIERENGINE_C_DEFINED
00040
00041 #include "Image/FourierEngine.H"
00042
00043 #include "rutz/trace.h"
00044
00045 #ifdef HAVE_FFTW3_H
00046
00047 namespace
00048 {
00049
00050 const bool USE_FFTW_GURU = true;
00051
00052
00053
00054 void init_threads()
00055 {
00056
00057
00058 #ifdef USE_FFTW_THREADS
00059 static bool inited = false;
00060
00061 if (!inited)
00062 {
00063 inited = true;
00064 if (fftw_init_threads() == 0)
00065 LFATAL("fftw_init_threads() failed");
00066
00067 fftw_plan_with_nthreads(4);
00068 }
00069 #endif
00070 }
00071
00072 template <class T>
00073 struct fftw;
00074
00075 template <>
00076 struct fftw<float>
00077 {
00078 static float* alloc_real(size_t n)
00079 {
00080 return static_cast<float*>(fftwf_malloc(sizeof(float)*n));
00081 }
00082
00083 static complexf* alloc_complex(size_t n)
00084 {
00085 return static_cast<complexf*>(fftwf_malloc(sizeof(complexf)*n));
00086 }
00087
00088 static void dealloc(void* mem)
00089 {
00090 fftwf_free(mem);
00091 }
00092
00093 static void* plan_dft_r2c_2d(const Dims& d,
00094 float* src,
00095 complexf* dst)
00096 {
00097 GVX_TRACE(__PRETTY_FUNCTION__);
00098
00099 return fftwf_plan_dft_r2c_2d
00100 (d.h(), d.w(),
00101 src,
00102
00103
00104
00105
00106 reinterpret_cast<fftwf_complex*>(dst),
00107 FFTW_MEASURE);
00108 }
00109
00110 static void* plan_dft_c2r_2d(const Dims& d,
00111 complexf* src,
00112 float* dst)
00113 {
00114 GVX_TRACE(__PRETTY_FUNCTION__);
00115
00116 return fftwf_plan_dft_c2r_2d
00117 (d.h(), d.w(),
00118 reinterpret_cast<fftwf_complex*>(src),
00119 dst,
00120 FFTW_MEASURE);
00121 }
00122
00123 static void destroy_plan(void* p)
00124 {
00125 fftwf_destroy_plan(static_cast<fftwf_plan>(p));
00126 }
00127
00128 static void execute_dft_r2c(void* p,
00129 const float* src,
00130 complexf* dst)
00131 {
00132 fftwf_execute_dft_r2c
00133 (static_cast<fftwf_plan>(p),
00134 const_cast<float*>(src),
00135 reinterpret_cast<fftwf_complex*>(dst));
00136 }
00137
00138 static void execute_dft_c2r(void* p,
00139 const complexf* src,
00140 float* dst)
00141 {
00142 fftwf_execute_dft_c2r
00143 (static_cast<fftwf_plan>(p),
00144 reinterpret_cast<fftwf_complex*>(const_cast<complexf*>(src)),
00145 dst);
00146 }
00147
00148 static void execute(void* p)
00149 {
00150 fftwf_execute(static_cast<fftwf_plan>(p));
00151 }
00152 };
00153
00154 template <>
00155 struct fftw<double>
00156 {
00157 static double* alloc_real(size_t n)
00158 {
00159 return static_cast<double*>(fftw_malloc(sizeof(double)*n));
00160 }
00161
00162 static complexd* alloc_complex(size_t n)
00163 {
00164 return static_cast<complexd*>(fftw_malloc(sizeof(complexd)*n));
00165 }
00166
00167 static void dealloc(void* mem)
00168 {
00169 fftw_free(mem);
00170 }
00171
00172 static void* plan_dft_r2c_2d(const Dims& d,
00173 double* src,
00174 complexd* dst)
00175 {
00176 GVX_TRACE(__PRETTY_FUNCTION__);
00177
00178 return fftw_plan_dft_r2c_2d
00179 (d.h(), d.w(),
00180 src,
00181
00182
00183
00184
00185 reinterpret_cast<fftw_complex*>(dst),
00186 FFTW_MEASURE);
00187 }
00188
00189 static void* plan_dft_c2r_2d(const Dims& d,
00190 complexd* src,
00191 double* dst)
00192 {
00193 GVX_TRACE(__PRETTY_FUNCTION__);
00194
00195 return fftw_plan_dft_c2r_2d
00196 (d.h(), d.w(),
00197 reinterpret_cast<fftw_complex*>(src),
00198 dst,
00199 FFTW_MEASURE);
00200 }
00201
00202 static void destroy_plan(void* p)
00203 {
00204 fftw_destroy_plan(static_cast<fftw_plan>(p));
00205 }
00206
00207 static void execute_dft_r2c(void* p,
00208 const double* src,
00209 complexd* dst)
00210 {
00211 fftw_execute_dft_r2c
00212 (static_cast<fftw_plan>(p),
00213 const_cast<double*>(src),
00214 reinterpret_cast<fftw_complex*>(dst));
00215 }
00216
00217 static void execute_dft_c2r(void* p,
00218 const complexd* src,
00219 double* dst)
00220 {
00221 fftw_execute_dft_c2r
00222 (static_cast<fftw_plan>(p),
00223 reinterpret_cast<fftw_complex*>(const_cast<complexd*>(src)),
00224 dst);
00225 }
00226
00227 static void execute(void* p)
00228 {
00229 fftw_execute(static_cast<fftw_plan>(p));
00230 }
00231 };
00232 }
00233
00234 #endif // HAVE_FFTW3_H
00235
00236
00237 template <class T>
00238 FourierEngine<T>::FourierEngine(const Dims& d)
00239 :
00240 itsInputDims(d),
00241 itsSrc(0),
00242 itsDst(0),
00243 itsPlan(0)
00244 {
00245 GVX_TRACE(__PRETTY_FUNCTION__);
00246
00247 #ifndef HAVE_FFTW3_H
00248 LFATAL("you must have fftw3 installed to use this function");
00249 #else
00250 init_threads();
00251
00252
00253
00254
00255
00256 itsSrc = fftw<T>::alloc_real(itsInputDims.h() * itsInputDims.w());
00257
00258 if (itsSrc == 0)
00259 LFATAL("memory allocation failure");
00260
00261 itsDst = fftw<T>::alloc_complex(itsInputDims.h() * (itsInputDims.w()/2+1));
00262
00263 if (itsDst == 0)
00264 {
00265 fftw<T>::dealloc(itsSrc);
00266 LFATAL("memory allocation failure");
00267 }
00268
00269
00270 #endif // HAVE_FFTW3_H
00271 }
00272
00273
00274 template <class T>
00275 FourierEngine<T>::~FourierEngine()
00276 {
00277 GVX_TRACE(__PRETTY_FUNCTION__);
00278 #ifndef HAVE_FFTW3_H
00279
00280 LERROR("you must have fftw3 installed to use this function");
00281 #else
00282 if (itsPlan != 0)
00283 fftw<T>::destroy_plan(itsPlan);
00284 fftw<T>::dealloc(itsDst);
00285 fftw<T>::dealloc(itsSrc);
00286 #endif
00287 }
00288
00289
00290 template <class T>
00291 Image<std::complex<T> > FourierEngine<T>::fft(const Image<T>& x)
00292 {
00293 GVX_TRACE(__PRETTY_FUNCTION__);
00294 #ifndef HAVE_FFTW3_H
00295 LFATAL("you must have fftw3 installed to use this function");
00296 return Image<std::complex<T> >();
00297 #else
00298 ASSERT(x.getDims() == itsInputDims);
00299
00300 if (itsPlan == 0)
00301 {
00302 itsPlan = fftw<T>::plan_dft_r2c_2d(itsInputDims, itsSrc, itsDst);
00303
00304 if (itsPlan == 0)
00305 {
00306 fftw<T>::dealloc(itsSrc); fftw<T>::dealloc(itsDst);
00307 LFATAL("couldn't construct fftw_plan");
00308 }
00309 }
00310
00311 if (USE_FFTW_GURU)
00312 {
00313
00314
00315
00316
00317
00318
00319
00320 Image<std::complex<T> > result(itsInputDims.w()/2 + 1,
00321 itsInputDims.h(), NO_INIT);
00322
00323 fftw<T>::execute_dft_r2c
00324 (itsPlan, x.getArrayPtr(), result.getArrayPtr());
00325
00326 return result;
00327 }
00328 else
00329 {
00330 std::copy(x.begin(), x.end(), itsSrc);
00331
00332 {
00333 GVX_TRACE("fftw_execute-forward");
00334 fftw<T>::execute(itsPlan);
00335 }
00336
00337 return Image<std::complex<T> >(itsDst,
00338 itsInputDims.w()/2 + 1, itsInputDims.h());
00339 }
00340 #endif // HAVE_FFTW3_H
00341 }
00342
00343
00344 template <class T>
00345 FourierInvEngine<T>::FourierInvEngine(const Dims& d)
00346 :
00347 itsOutputDims(d),
00348 itsSrc(0),
00349 itsDst(0),
00350 itsPlan(0)
00351 {
00352 GVX_TRACE(__PRETTY_FUNCTION__);
00353 #ifndef HAVE_FFTW3_H
00354 LFATAL("you must have fftw3 installed to use this function");
00355 #else
00356 init_threads();
00357
00358
00359
00360 itsSrc = fftw<T>::alloc_complex(itsOutputDims.h() * (itsOutputDims.w()/2+1));
00361
00362 if (itsSrc == 0)
00363 LFATAL("memory allocation failure");
00364
00365 itsDst = fftw<T>::alloc_real(itsOutputDims.h() * itsOutputDims.w());
00366
00367 if (itsDst == 0)
00368 {
00369 fftw<T>::dealloc(itsSrc);
00370 LFATAL("memory allocation failure");
00371 }
00372
00373
00374 #endif // HAVE_FFTW3_H
00375 }
00376
00377
00378 template <class T>
00379 FourierInvEngine<T>::~FourierInvEngine()
00380 {
00381 GVX_TRACE(__PRETTY_FUNCTION__);
00382 #ifndef HAVE_FFTW3_H
00383
00384 LERROR("you must have fftw3 installed to use this function");
00385 #else
00386 if (itsPlan != 0)
00387 fftw<T>::destroy_plan(itsPlan);
00388 fftw<T>::dealloc(itsDst);
00389 fftw<T>::dealloc(itsSrc);
00390 #endif
00391 }
00392
00393
00394 template <class T>
00395 Image<T> FourierInvEngine<T>::ifft(const Image<std::complex<T> >& x)
00396 {
00397 GVX_TRACE(__PRETTY_FUNCTION__);
00398 #ifndef HAVE_FFTW3_H
00399 LFATAL("you must have fftw3 installed to use this function");
00400 return Image<T>();
00401 #else
00402 ASSERT(x.getWidth() == itsOutputDims.w()/2+1);
00403 ASSERT(x.getHeight() == itsOutputDims.h());
00404
00405 if (itsPlan == 0)
00406 {
00407 itsPlan = fftw<T>::plan_dft_c2r_2d(itsOutputDims, itsSrc, itsDst);
00408
00409 if (itsPlan == 0)
00410 {
00411 fftw<T>::dealloc(itsSrc); fftw<T>::dealloc(itsDst);
00412 LFATAL("couldn't construct fftw_plan");
00413 }
00414 }
00415
00416 if (USE_FFTW_GURU)
00417 {
00418 Image<T> result(itsOutputDims, NO_INIT);
00419
00420
00421
00422 Image<std::complex<T> > xcopy(x);
00423
00424 fftw<T>::execute_dft_c2r
00425 (itsPlan,
00426 xcopy.getArrayPtr(),
00427 result.getArrayPtr());
00428
00429 return result;
00430 }
00431 else
00432 {
00433 std::copy(x.begin(), x.end(), itsSrc);
00434
00435 {
00436 GVX_TRACE("fftw_execute-reverse");
00437 fftw<T>::execute(itsPlan);
00438 }
00439
00440 return Image<T>(itsDst, itsOutputDims.w(), itsOutputDims.h());
00441 }
00442 #endif
00443 }
00444
00445
00446 template <class T>
00447 Image<T> magnitude(const Image<std::complex<T> >& img)
00448 {
00449 GVX_TRACE(__PRETTY_FUNCTION__);
00450 const std::complex<T>* c = img.getArrayPtr();
00451
00452 Image<T> result(img.getDims(), NO_INIT);
00453 for (typename Image<T>::iterator
00454 itr = result.beginw(), stop = result.endw();
00455 itr != stop;
00456 ++itr)
00457 {
00458 *itr = std::abs(*c);
00459 ++c;
00460 }
00461 return result;
00462 }
00463
00464
00465 template <class T>
00466 Image<T> logmagnitude(const Image<std::complex<T> >& img)
00467 {
00468 GVX_TRACE(__PRETTY_FUNCTION__);
00469 const std::complex<T>* c = img.getArrayPtr();
00470
00471 Image<T> result(img.getDims(), NO_INIT);
00472 for (typename Image<T>::iterator
00473 itr = result.beginw(), stop = result.endw();
00474 itr != stop;
00475 ++itr)
00476 {
00477 const double a = std::abs(*c);
00478 *itr = log(a > 0.0
00479 ? a
00480 : std::numeric_limits<double>::min());
00481 ++c;
00482 }
00483 return result;
00484 }
00485
00486
00487 template <class T>
00488 Image<T> phase(const Image<std::complex<T> >& img)
00489 {
00490 GVX_TRACE(__PRETTY_FUNCTION__);
00491 const std::complex<T>* c = img.getArrayPtr();
00492
00493 Image<T> result(img.getDims(), NO_INIT);
00494 for (typename Image<T>::iterator
00495 itr = result.beginw(), stop = result.endw();
00496 itr != stop;
00497 ++itr)
00498 {
00499 *itr = std::arg(*c);
00500 ++c;
00501 }
00502 return result;
00503 }
00504
00505
00506 template <class T>
00507 Image<T> cartesian(const Image<T>& in,
00508 const Dims& dims)
00509 {
00510 GVX_TRACE(__PRETTY_FUNCTION__);
00511 Image<T> result(dims, ZEROS);
00512 Image<int> counts(dims, ZEROS);
00513
00514 const int nfreq = dims.w();
00515 const int nori = dims.h();
00516
00517 const double theta_max = M_PI;
00518 const double rad_max =
00519 sqrt(in.getWidth()*in.getWidth() +
00520 in.getHeight()*in.getHeight()/4);
00521
00522 const int h = in.getHeight(), h2 = in.getHeight()/2;
00523
00524 const Point2D<int> left(-1, 0);
00525 const Point2D<int> right(1, 0);
00526 const Point2D<int> up(0, -1);
00527 const Point2D<int> down(0, 1);
00528
00529 for (int y = 0; y < h; ++y)
00530 if (y < h2)
00531 for (int x = 0; x < in.getWidth(); ++x)
00532 {
00533 const double th = atan2(y, x);
00534 const double r = sqrt(x*x+y*y);
00535
00536 Point2D<int> pos(int(nfreq*r/rad_max),
00537 int(nori*th/theta_max));
00538
00539 result[pos] += in[Point2D<int>(x,y)];
00540 ++counts[pos];
00541
00542 if (result.coordsOk(pos+left))
00543 { result[pos+left] += in[Point2D<int>(x,y)]; ++counts[pos+left]; }
00544 if (result.coordsOk(pos+right))
00545 { result[pos+right] += in[Point2D<int>(x,y)]; ++counts[pos+right]; }
00546 if (result.coordsOk(pos+up))
00547 { result[pos+up] += in[Point2D<int>(x,y)]; ++counts[pos+up]; }
00548 if (result.coordsOk(pos+down))
00549 { result[pos+down] += in[Point2D<int>(x,y)]; ++counts[pos+down]; }
00550 }
00551 else
00552 for (int x = 0; x < in.getWidth(); ++x)
00553 {
00554 int y2 = h - y;
00555
00556 const double th = atan2(y2, -x);
00557 const double r = sqrt(x*x+y2*y2);
00558
00559 Point2D<int> pos(int(nfreq*r/rad_max),
00560 int(nori*th/theta_max));
00561
00562 result[pos] += in[Point2D<int>(x,y)];
00563 ++counts[pos];
00564
00565 if (result.coordsOk(pos+left))
00566 { result[pos+left] += in[Point2D<int>(x,y)]; ++counts[pos+left]; }
00567 if (result.coordsOk(pos+right))
00568 { result[pos+right] += in[Point2D<int>(x,y)]; ++counts[pos+right]; }
00569 if (result.coordsOk(pos+up))
00570 { result[pos+up] += in[Point2D<int>(x,y)]; ++counts[pos+up]; }
00571 if (result.coordsOk(pos+down))
00572 { result[pos+down] += in[Point2D<int>(x,y)]; ++counts[pos+down]; }
00573 }
00574
00575 for (int i = 0; i < result.getSize(); ++i)
00576 if (counts[i] > 0)
00577 result[i] /= counts[i];
00578
00579 return result;
00580 }
00581
00582 #if 0
00583 template class FourierEngine<float>;
00584 template class FourierInvEngine<float>;
00585 #endif
00586
00587 template class FourierEngine<double>;
00588 template class FourierInvEngine<double>;
00589
00590 template Image<float> magnitude(const Image<std::complex<float> >&);
00591 template Image<float> logmagnitude(const Image<std::complex<float> >&);
00592 template Image<float> phase(const Image<std::complex<float> >&);
00593 template Image<float> cartesian(const Image<float>&, const Dims&);
00594
00595 template Image<double> magnitude(const Image<std::complex<double> >&);
00596 template Image<double> logmagnitude(const Image<std::complex<double> >&);
00597 template Image<double> phase(const Image<std::complex<double> >&);
00598 template Image<double> cartesian(const Image<double>&, const Dims&);
00599
00600
00601
00602
00603
00604
00605
00606 #endif // IMAGE_FOURIERENGINE_C_DEFINED