c++opencvdft

Round trip through cv::dft() and cv::DFT_INVERSE leads to doubling magnitude of 1d samples


I'm playing with some toy code, to try to verify that I understand how discrete fourier transforms work in OpenCV. I've found a rather perplexing case, and I believe the reason is that the flags I'm calling cv::dft() with, are incorrect.

I start with a 1-dimensional array of real-valued (e.g. audio) samples. (Stored in a cv::Mat as a column.)

I use cv::dft() to get a complex-valued array of fourier buckets.

I use cv::dft(), with cv::DFT_INVERSE, to convert it back.

I do this several times, printing the results. The results seem to be the correct shape but the wrong magnitude.

Code:

cv::Mat samples(1, 2, CV_64F);
samples.at<double>(0, 0) = -1;
samples.at<double>(0, 1) = 1;
std::cout << "samples(" << samples.type() << "):" << samples << std::endl;
for (int i = 0; i < 3; ++i) {
  cv::Mat buckets;
  cv::dft(samples, buckets, cv::DFT_COMPLEX_OUTPUT);
  samples = cv::Mat();
  cv::dft(buckets, samples,
          cv::DFT_INVERSE | cv::DFT_COMPLEX_INPUT | cv::DFT_REAL_OUTPUT);

  std::cout << "buckets(" << buckets.type() << "):" << buckets << std::endl;
  std::cout << "samples(" << samples.type() << "):" << samples << std::endl;
}

Output:

samples(6):[-1, 1]
buckets(14):[0, 0, -2, 0]
samples(6):[-2, 2]
buckets(14):[0, 0, -4, 0]
samples(6):[-4, 4]
buckets(14):[0, 0, -8, 0]
samples(6):[-8, 8]

I would have expected the above output to repeat. E.g. [-1, 1], [0, 0, -1, 0], .... Instead, the magnitude is doubling on each round-trip.

Is my understanding wrong? Or am I using the wrong flags? Etc.


Solution

  • The inverse DFT in opencv will not scale the result by default, so you get your input times the length of the array. This is a common optimization, because the scaling is not always needed and the most efficient algorithms for the inverse DFT just use the forward DFT which does not produce the scaling. You can solve this by adding the cv::DFT_SCALE flag to your inverse DFT.

    Some libraries scale both forward and backward transformation with 1/sqrt(N), so it is often useful to check the documentation (or write quick test code) when working with Fourier Transformations.