/** Author: Charles Dubout (charles.dubout@idiap.ch) Fourier transform heuristic. Compute the 2D DFT of the region of interest to convert it to the frequency domain. */#include <mash/heuristic.h>#include <algorithm>#include <cmath>#include <complex>#include <vector>usingnamespaceMash;//------------------------------------------------------------------------------/// The 'Fourier' heuristic class//------------------------------------------------------------------------------classFourierHeuristic:publicHeuristic{//_____ Implementation of Heuristic __________public:virtualunsignedintdim();virtualvoidprepareForCoordinates();virtualscalar_tcomputeFeature(unsignedintfeature_index);private:// Fast fourier transformstaticvoidfft(std::complex<scalar_t>*data,unsignedintn,unsignedintstride=1,boolinverse=false);// The transformed version of the region of intereststd::vector<std::complex<scalar_t>>features_;};//------------------------------------------------------------------------------/// Creation function of the heuristic//------------------------------------------------------------------------------extern"C"Heuristic*new_heuristic(){returnnewFourierHeuristic();}/************************* IMPLEMENTATION OF Heuristic ************************/unsignedintFourierHeuristic::dim(){// Twice the number of pixels (rounded to the next highest power of 2)unsignedintroi_size=roi_extent*2+1;unsignedintroi_size_2=std::pow(2.0f,std::ceil(std::log(float(roi_size))/std::log(2.0f)));returnroi_size_2*roi_size_2*2;}voidFourierHeuristic::prepareForCoordinates(){// Compute the coordinates of the top-left pixel of the region of interestunsignedintx0=coordinates.x-roi_extent;unsignedinty0=coordinates.y-roi_extent;// Compute the size of the region of interestunsignedintroi_size=roi_extent*2+1;unsignedintroi_size_2=std::pow(2.0f,std::ceil(std::log(float(roi_size))/std::log(2.0f)));// Get the pixels values of the region of interestbyte_t**pLines=image->grayLines();// Resize the features to the correct dimensionfeatures_.clear();features_.resize(roi_size_2*roi_size_2);// Fill the feature imagefor(unsignedinty=0;y<roi_size;++y){for(unsignedintx=0;x<roi_size;++x){features_[y*roi_size_2+x].real()=pLines[y0+y][x0+x]/scalar_t(255);}}// Do 1D ffts along the rows before doing 1D ffts along the columnsfor(unsignedinty=0;y<roi_size;++y){fft(&features_[y*roi_size_2],roi_size_2);}for(unsignedintx=0;x<roi_size_2;++x){fft(&features_[x],roi_size_2,roi_size_2);}// Exchange the first quadrant with the fourth, and the second with the third// (unnecessary but better to visualize the image)// for(unsigned int y = 0; y < roi_size_2 / 2; ++y) {// std::swap_ranges(&features_[y * roi_size_2],// &features_[y * roi_size_2 + roi_size_2 / 2],// &features_[(y + roi_size_2 / 2) * roi_size_2 + roi_size_2 / 2]);// std::swap_ranges(&features_[y * roi_size_2 + roi_size_2 / 2],// &features_[y * roi_size_2 + roi_size_2],// &features_[(y + roi_size_2 / 2) * roi_size_2]);// }}scalar_tFourierHeuristic::computeFeature(unsignedintfeature_index){// Separate the magnitude and phase parts of the image (unnecessary but// better to visualize the image)if(feature_index<features_.size()){returnstd::abs(features_[feature_index]);}else{returnstd::arg(features_[feature_index-features_.size()]);}}// Fast fourier transform (adapted from the book Numerical Recipes, 3rd Ed.)voidFourierHeuristic::fft(std::complex<scalar_t>*data,unsignedintn,unsignedintstride,boolinverse){// Bit-reversal sectionfor(unsignedinti=0,j=0;i<n;++i){if(i<j){// Exchange the 2 complex numbersstd::swap(data[i*stride],data[j*stride]);}unsignedintm=n/2;while(m>=1&&j>=m){j-=m;m>>=1;}j+=m;}// Danielson-Lanczos sectionunsignedintmmax=1;while(mmax<n){constunsignedintistep=mmax<<1;constscalar_ttheta=inverse?-M_PI/mmax:M_PI/mmax;std::complex<scalar_t>wp(std::cos(theta)-1,std::sin(theta));std::complex<scalar_t>w(1,0);for(unsignedintm=0;m<mmax;++m){for(unsignedinti=m;i<n;i+=istep){unsignedintj=i+mmax;std::complex<scalar_t>temp=w*data[j*stride];data[j*stride]=data[i*stride]-temp;data[i*stride]+=temp;}w+=w*wp;}mmax=istep;}}