2

I'm trying to compute the FFT (Fast Fourier Transform) of an image to use the frequencies to determine whether or not the image is blurry.

I need to use a custom FFT algorithm that we already have in our codebase. The FFT algorithm requires a standard 1D vector of doubles or ints. I need a way to read in an image and then convert it to a vector of doubles so that I can compute the FFT of the image.

I have tried the following:

cv::Mat inputImage = cv::imread("testImage.png");
cv::Mat fImage; 

inputImage.convertTo(fImage, CV_32F); 
std::vector<double> actualImage = fImage.clone();

However, I am getting the error:

OpenCV Error: Assertion failed (channels() == CV_MAT_CN(dtype)) in copyTo,

Any ideas to how I can achieve this?

Jeru Luke
  • 20,118
  • 13
  • 80
  • 87
Phorce
  • 4,424
  • 13
  • 57
  • 107
  • Your requirements sound suspect. The FFT of an N-dimensional input is also N-dimensional. Hence, the FFT of a 3-channel 2D image is also 3 channel and 2D. – MSalters Feb 02 '17 at 13:57
  • @MSalters I am trying to calculate whether or not an image is blurry. My idea is that I'll take the FFT (1D of complex numbers) calculate the magnitudes and then do a high pass filtering on them – Phorce Feb 02 '17 at 16:46
  • Well, that's simply not meaningful. You can take a 1D horizontal, vertical or even diagonal slice of the image, convert it to greyscale and take a 1D FFT of that. That will tell you if there's a blur in that direction. Yes, I know you said something about disliking greyscale before. But here's the point: You simply cannot take a 1D FFT given a 3-channel 2D input, just like you can't add two complex numbers and demand that the outcome is an integer. That's just now how math works. – MSalters Feb 02 '17 at 16:58
  • @MSalters - so let's say I take the grayscale of the image, convert to doubles and (as given in mikis answer) then compute the FFT and pass this through a high pass filter.. This would work? I totally understand what you mean, I must convert the image to grayscale – Phorce Feb 02 '17 at 18:24
  • Think about what that does. Say you have a 100x100 image and you turn that into a 10000 element 1D vector. Consider a vertical line - no periodic component. In the 1D vector, each pixel of this line will now be 100 pixels apart - a very clear periodic component. You introduce fake frequencies, while at the same time eliminating other real frequencies. – MSalters Feb 02 '17 at 21:08

1 Answers1

6

CV_32F means float, not double. You should use CV_64F instead.

You also need to specify the number of channels. This example is for 1 channel image (grayscale), and probably what you need:

// Load the image
cv::Mat inputImage = cv::imread("testImage.png");
// Convert to single channel (grayscale)
cv::cvtColor(inputImage, inputImage, cv::COLOR_BGR2GRAY);

// Or directly load as grayscale    
// cv::Mat inputImage = cv::imread("testImage.png", cv::IMREAD_GRAYSCALE);

// Convert to double
cv::Mat fImage; 
inputImage.convertTo(fImage, CV_64F); 

// Initialize the vector with the image content
std::vector<double> actualImage(fImage.begin<double>(), fImage.end<double>());

For 3 channels you can do:

cv::Mat inputImage = cv::imread("testImage.png");
cv::Mat fImage; 

inputImage.convertTo(fImage, CV_64F); 
fImage = fImage.reshape(1); // You need to reshape to single channel
std::vector<double> actualImage(fImage.begin<double>(), fImage.end<double>());
Miki
  • 40,887
  • 13
  • 123
  • 202
  • Hi, I cannot convert to Grayscale though - I need the actual image – Phorce Feb 02 '17 at 09:59
  • Then see second snippet... note that in `actualImage` you'll find pixels values in the order: BGR BGR BGR... If you need another order, please let me know – Miki Feb 02 '17 at 10:00