1
votes

I'm trying to code a FFT/IFFT function with FFTW 3.3 and OpenCV 2.1 using the C++ interface. I've seen a lot of examples using the old OpenCV formats and I did a direct conversion, but something doesn't work.

The objective of my function is to return a Mat object with the real part and the imaginary part of the FFT, like dft default OpenCV function does. Here is the code of the function. Program gets blocked with memory problem in the lines that copy im_data to data_in.

Does somebody know what am I doing wrong? Thank you

Mat fft_sr(Mat& I)
{

double          *im_data;
double          *realP_data;
double          *imP_data;

fftw_complex    *data_in;
fftw_complex    *fft;      

fftw_plan       plan_f;

int width     = I.cols;
int height    = I.rows;
int step      = I.step;

int             i, j, k;

Mat realP=Mat::zeros(height,width,CV_64F); // Real Part FFT
Mat imP=Mat::zeros(height,width,CV_64F); // Imaginary Part FFT


im_data = ( double* ) I.data;
realP_data = ( double* ) realP.data;
imP_data = ( double* ) imP.data;


data_in = ( fftw_complex* )fftw_malloc( sizeof( fftw_complex ) * width * height );
fft     = ( fftw_complex* )fftw_malloc( sizeof( fftw_complex ) * width * height );

// Problem Here
for( i = 0, k = 0 ; i < height ; i++ ) {
    for( j = 0 ; j < width ; j++ ) {
        data_in[k][0] = ( double )im_data[i * step + j];
        data_in[k][1] = ( double )0.0;
        k++;
    }
}


plan_f = fftw_plan_dft_2d( height, width, data_in, fft,  FFTW_FORWARD,  FFTW_ESTIMATE );


fftw_execute( plan_f );

// Copy real and imaginary data
for( i = 0, k = 0 ; i < height ; i++ ) {
    for( j = 0 ; j < width ; j++ ) {
        realP_data[i * step + j] = ( double )fft[k][0];
        imP_data[i * step + j] = ( double )fft[k][1];
        k++;

    }
}



Mat fft_I(I.size(),CV_64FC2);
Mat fftplanes[] = {Mat_<double>(realP), Mat_<double>(imP)};
merge(fftplanes, 2, fft_I);

fftw_destroy_plan(plan_f);
fftw_free(data_in);
fftw_free(fft);
return fft_I;   
}
3
What is step set to? What exactly means "Problem Here"? What happens when you add the line std:cout << i << "/" << j << std::endl; to the body of the inner loop of the nested loop struct producing the problem?Good Night Nerd Pride
step is fixed to 4096 (8 bytes (CV_64F, 64 bit float) * 512 (row size)), they are 512x512 images. Adding this line, it throws a 'access violation reading location 0x04331000 at i=64, j=506gui

3 Answers

3
votes

You are using step wrong. It is meant to index into Mat::data. Since you already casted Mat::data to double* when assigning it to im_data, you can index into im_data "normally":

data_in[k][0] = im_data[i * width + j];

When using step the correct way to index is:

data_in[k][0] = ( double )I.data[i * step + j];

Update:

Try to access your images row-wise. That way you avoid running into problems with stride/step, while still exploiting fast access:

for (int i = 0; i < I.rows; i++)
{
    double* row = I.ptr<double>(i);

    for (int j = 0; j < I.cols; j++)
    {
        // Do something with the current pixel.
        double someValue = row[j];
    }
}
0
votes

I know this is old but when you are using fftw you need to initialize fftw_complex *data_in only after creating the plan for the fft, if i recall correctly when you create the plan it sets all the *data_in values to 0. so allocate before the plan and initialize after!

0
votes

Statement

im_data = ( double* ) I.data;

defines im_data as double pointer to image data. I think that should be mandatory that I was a double values image.