...
#include <complex>//Includes C++ complex numbers (uses templates)
#include <fftw3.h> // Library to perform FFT transform (GPL license)
const int BLOCKSIZE= 10;
...
// Applies an MTF to an image. This filters the image. It is done in the frequency domain
// image_in[BLOCKSIZE][BLOCKSIZE] : Input image
// double MTF[BLOCKSIZE][BLOCKSIZE] : Modulation Transfer function (MTF)
// double image_out[BLOCKSIZE][BLOCKSIZE]: Output image after applying the MTF
//void applyMTF(const double image_in[][BLOCKSIZE], const double MTF[][BLOCKSIZE], double image_out[][BLOCKSIZE]){
void applyMTF(){
fftw_complex *image_v_spat; //Image vector in spatial domain
fftw_complex *image_v_freq; //Image vector in frequency domain
fftw_complex *MTF_v; //Modulation Transfer Function (in frequency domain by definition)
fftw_plan p; //Plan used by the fftw library
int i= 0, j= 0, counter= 0; //Loop counters
//Input parameters temporarily defined inside the function
double image_in[BLOCKSIZE][BLOCKSIZE];
double image_out[BLOCKSIZE][BLOCKSIZE];
double MTF[BLOCKSIZE][BLOCKSIZE];
//Fill image and MTF with dummy values:
for(i= 0; i< BLOCKSIZE; i++){
for(j= 0; j< BLOCKSIZE; j++){
image_in[i][j]= (double)(i*i - i + j);
MTF[i][j]= (double)(j);
}
}
//Allocate memory
image_v_spat = (fftw_complex*) fftw_malloc(sizeof(fftw_complex) * BLOCKSIZE * BLOCKSIZE);
image_v_freq = (fftw_complex*) fftw_malloc(sizeof(fftw_complex) * BLOCKSIZE * BLOCKSIZE);
MTF_v = (fftw_complex*) fftw_malloc(sizeof(fftw_complex) * BLOCKSIZE * BLOCKSIZE);
//Expand the image and MTF arrays (2-dimensional real) into vectors (1-dimensional complex array). Fill the imaginary part with zeros.
counter= 0;
for(i= 0; i< BLOCKSIZE; i++){
for(j= 0; j< BLOCKSIZE; j++){
counter++;
//Image
image_v_spat[counter][0]= image_in[i][j]; //Real part
image_v_spat[counter][1]= 0; //Imaginary part
//Same for MTF
MTF_v[counter][0]= MTF[i][j]; //Real part
MTF_v[counter][1]= 0; //Imaginary part
}
}
//Create the plan for the DFT
p= fftw_plan_dft_2d(BLOCKSIZE, BLOCKSIZE, image_v_spat, image_v_freq, FFTW_FORWARD, FFTW_ESTIMATE);
//Execute the plan (perform the Fourier transform of the image)
fftw_execute(p);
//Multiply the image in frequency domain times the MTF taking into account that they are complex numbers: (a0 + a1 i) * (b0 + b1 i) = (a0*b0 - a1*b1) + (a0*b1 + a1*b0)i
//The real part is stored in index 0 and the complex part in index 1
for(counter=0; counter < BLOCKSIZE*BLOCKSIZE; counter++){
image_v_freq[counter][0]= image_v_freq[counter][0] * MTF[counter][0] - image_v_freq[counter][1] * MTF[counter][1]; //Real part
image_v_freq[counter][1]= image_v_freq[counter][0] * MTF[counter][1] + image_v_freq[counter][1] * MTF[counter][0]; //Imaginary part
}
//Do the inverse Fourier transform
//First create the plan for the DFT
p= fftw_plan_dft_2d(BLOCKSIZE, BLOCKSIZE, image_v_freq, image_v_spat, FFTW_BACKWARD, FFTW_ESTIMATE);
//Then execute the plan (perform the inverse Fourier transform of the image)
fftw_execute(p);
//Do the absolute value and store the resulting image in a real 2D matrix instead of a complex 1D vector. This image is then returned by the function by ref.
counter= 0;
for(i= 0; i< BLOCKSIZE; i++){
for(j= 0; j< BLOCKSIZE; j++){
counter++;
image_out[i][j]= sqrt(image_v_spat[counter][0]*image_v_spat[counter][0] + image_v_spat[counter][1]*image_v_spat[counter][1]);
}
}
//Deallocate memory
fftw_destroy_plan(p);
fftw_free(image_v_spat);
fftw_free(image_v_freq);
fftw_free(MTF_v);
return;
}