2
votes

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?

1
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
@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 themPhorce
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
@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 grayscalePhorce
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

1 Answers

6
votes

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>());