How can I divide a complex Mat with a real Mat in OpenCV? I want to calculate cross-power spectrum for phase correlation but I get a runtime error when using divide.
Update
I figured out a way to calculate cross-power spectrum but i don't get the appropriate result to find the translation of an image. Below is the code.
I split the result of inverse dft because it has two channels. Then, I was able to divide but the result is not good for translation only in the horizontal axis. There should be only one max value, but there are a lot of max values.
Image
void computeFFTMag(Mat&,Mat&,Mat&);
string getImgType(int );
int main( int argc, char** argv )
{
Mat ref,sens,refMag,sensMag,refFFT,sensFFT;
ref = imread("lena1.jpg",CV_LOAD_IMAGE_GRAYSCALE);
sens = imread("lena3.jpg",CV_LOAD_IMAGE_GRAYSCALE);
namedWindow( "Sensed Image", CV_WINDOW_AUTOSIZE );
imshow( "Sensed Image", sens );
computeFFTMag(ref,refMag,refFFT);
computeFFTMag(sens,sensMag,sensFFT);
Mat R1,R2,R,r,rf[2],rff;
mulSpectrums(refFFT,sensFFT,R1,0,true);
multiply(refMag,sensMag,R2);
dft(R1,r,DFT_REAL_OUTPUT);
split(r,rf);
divide(rf[0],R2,r);
normalize(r, r, 0, 1, CV_MINMAX);
namedWindow( "Reference Image", CV_WINDOW_AUTOSIZE );
imshow("Reference Image" , r );
}
void computeFFTMag(Mat& input,Mat& fftMag,Mat& complexFFT){
Mat inputPadded;
/*int r=getOptimalDFTSize(input.rows);
int c=getOptimalDFTSize(input.cols);
copyMakeBorder(input,inputPadded,0,r-input.rows,0,c-input.cols,BORDER_CONSTANT, Scalar::all(0));*/
Mat fftPlanes[] = {Mat_<float>(input), Mat::zeros(input.size(), CV_32F)};
//Mat complexFFT;
merge(fftPlanes, 2, complexFFT);
dft(complexFFT,complexFFT);
split(complexFFT,fftPlanes);
magnitude(fftPlanes[0],fftPlanes[1],fftPlanes[0]);
fftMag=fftPlanes[0];
//fftMag = fftMag(Rect(0, 0, fftMag.cols & -2, fftMag.rows & -2));
int cx = fftMag.cols/2;
int cy = fftMag.rows/2;
Mat q0(fftMag, Rect(0, 0, cx, cy)); // Top-Left - Create a ROI per quadrant
Mat q1(fftMag, Rect(cx, 0, cx, cy)); // Top-Right
Mat q2(fftMag, Rect(0, cy, cx, cy)); // Bottom-Left
Mat q3(fftMag, Rect(cx, cy, cx, cy)); // Bottom-Right
Mat tmp; // swap quadrants (Top-Left with Bottom-Right)
q0.copyTo(tmp);
q3.copyTo(q0);
tmp.copyTo(q3);
q1.copyTo(tmp); // swap quadrant (Top-Right with Bottom-Left)
q2.copyTo(q1);
tmp.copyTo(q2);
}
A complex number can be divided by a scalar by dividing the real and complex terms by the same scalar. So, (2 + 3i) / 4 is equal to 2/4 + (3/4)i.
OpenCV doesn't let you do elementwise division of complex mats with scalar mats, but it does let you do elementwise division of complex mats with complex mats. You can get the division to work by creating a complex matrix where both the real and imaginary components are the same as the real values in your real mat that you want to divide by.
// Goal: Divide 'complex' by 'real'
Mat complex = Mat(rows, cols, CV_32FC2);
Mat real = Mat(rows, cols, CV_32FC1);
Mat channels[2] = {real, real};
Mat divisor = Mat(rows, cols, CV_32FC2);
merge(channels, 2, divisor);
Mat result = Mat(rows, cols, CV_32FC2);
divide(complex, divisor, result);
Related
I want to do a cross correlation of 2 shifted images. In general I would do it like this:
- Load the 2 images
- make an dft with this 2 images
- multiply this images with each other with mulSpectrum (opencv)
- make an inverse dft of the result of the multipliation
- show the result--in the result image there must be a shift of the frequency, which is the shift of the real images.
I have done this with openCV:
#include "opencv2/core/core.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"
#include <iostream>
using namespace std;
using namespace cv;
void fft_shift(Mat &I, Mat &magI) //shift the origin to the center of the image (taken from OpenCV example of dft)
{
Mat padded; //expand input image to optimal size
int m = getOptimalDFTSize(I.rows);
int n = getOptimalDFTSize(I.cols); // on the border add zero values
copyMakeBorder(I, padded, 0, m - I.rows, 0, n - I.cols, BORDER_CONSTANT, Scalar::all(0));
Mat planes[] = { Mat_<float>(padded), Mat::zeros(padded.size(), CV_32F) };
Mat complexI;
merge(planes, 2, complexI); // Add to the expanded another plane with zeros
dft(complexI, complexI); // this way the result may fit in the source matrix
// compute the magnitude and switch to logarithmic scale
// => log(1 + sqrt(Re(DFT(I))^2 + Im(DFT(I))^2))
split(complexI, planes); // planes[0] = Re(DFT(I), planes[1] = Im(DFT(I))
magnitude(planes[0], planes[1], planes[0]);// planes[0] = magnitude
magI = planes[0];
magI += Scalar::all(1); // switch to logarithmic scale
log(magI, magI);
// crop the spectrum, if it has an odd number of rows or columns
magI = magI(Rect(0, 0, magI.cols & -2, magI.rows & -2));
// rearrange the quadrants of Fourier image so that the origin is at the image center
int cx = magI.cols / 2;
int cy = magI.rows / 2;
Mat q0(magI, Rect(0, 0, cx, cy)); // Top-Left - Create a ROI per quadrant
Mat q1(magI, Rect(cx, 0, cx, cy)); // Top-Right
Mat q2(magI, Rect(0, cy, cx, cy)); // Bottom-Left
Mat q3(magI, Rect(cx, cy, cx, cy)); // Bottom-Right
Mat tmp; // swap quadrants (Top-Left with Bottom-Right)
q0.copyTo(tmp);
q3.copyTo(q0);
tmp.copyTo(q3);
q1.copyTo(tmp); // swap quadrant (Top-Right with Bottom-Left)
q2.copyTo(q1);
tmp.copyTo(q2);
}
int main()
{
//load images and convert them to greyscale
Mat I = imread("original_Image.png");
cv::cvtColor(I, I, CV_BGR2GRAY);
Mat II = imread("shifted_Image.png");
cv::cvtColor(II, II, CV_BGR2GRAY);
if (I.empty())
return -1;
// call the fft_shift function and multiply this to spectrum
Mat mag1, mag1_shift, mag3,mag4;
fft_shift(I,mag1);
fft_shift(II, mag1_shift);
mulSpectrums(mag1, mag1_shift,mag3, 0, 1);
//perform an inverse dft and shift it, then normalize is for displaying
cv::dft(mag3, mag3, cv::DFT_INVERSE | cv::DFT_REAL_OUTPUT);
fft_shift(mag3, mag4);
normalize(mag4, mag4, 0, 1, CV_MINMAX);
imshow("spectrum shift", mag4);
waitKey();
return 0;
}
Here is the result of this calculations: result
And here is the result I expected: expected result
this result was taken out of a python programm from: http://scikit-image.org/docs/0.11.x/auto_examples/plot_register_translation.html I try to translate this code to C++, which is the code above, but it is not working. Does anybody know, what I´m doing wrong here?
I have found a solution from the second post of this page:
http://answers.opencv.org/question/1624/phase-correlation-for-image-registrationimage-stitching/
The result of this code is:
Now I have to normalize this image, to see only the shiftet point.
So before you make an ifft, you have to normalize the result of the mulspectrum (code snipped taken out from the link above):
mulSpectrums(fft1,fft2,fft1,0,true);
fft1 = fft1/abs(fft1) //-->new
idft(fft1,fft1);
After this, you have to swap the quadrants, like in the openCV example:
// crop the spectrum, if it has an odd number of rows or columns
fft1 = fft1(Rect(0, 0, fft1.cols & -2, fft1.rows & -2));
// rearrange the quadrants of Fourier image so that the origin is at the image center
int cx = fft1.cols / 2;
int cy = fft1.rows / 2;
Mat q0(fft1, Rect(0, 0, cx, cy)); // Top-Left - Create a ROI per quadrant
Mat q1(fft1, Rect(cx, 0, cx, cy)); // Top-Right
Mat q2(fft1, Rect(0, cy, cx, cy)); // Bottom-Left
Mat q3(fft1, Rect(cx, cy, cx, cy)); // Bottom-Right
Mat tmp; // swap quadrants (Top-Left with Bottom-Right)
q0.copyTo(tmp);
q3.copyTo(q0);
tmp.copyTo(q3);
q1.copyTo(tmp); // swap quadrant (Top-Right with Bottom-Left)
q2.copyTo(q1);
tmp.copyTo(q2);
Now the result looks like the one from the python code:
or I can use just:
Point2d phaseCorrelate(InputArray src1, InputArray src2, InputArray window=noArray())
that´s doing all the stuff for me
You may make error on the inverse fft's scale, since you mulSpectrums, you need to divide (width*height)^2 for correct result, other than normalize it.
You may take my recipe:
cv::Mat XCorrelation(cv::Mat const& I, cv::Mat const& I1)
{
int width = cv::getOptimalDFTSize(std::max(I.cols,I1.cols));
int height = cv::getOptimalDFTSize(std::max(I.rows,I1.rows));
cv::Mat fft1;
cv::Mat fft2;
cv::copyMakeBorder(I, fft1, 0, height - I.rows, 0, width - I.cols, cv::BORDER_CONSTANT, cv::Scalar::all(0));
cv::copyMakeBorder(I1, fft2, 0, height - I.rows, 0, width - I.cols, cv::BORDER_CONSTANT, cv::Scalar::all(0));
fft1.convertTo(fft1, CV_32F);
fft2.convertTo(fft2, CV_32F);
cv::dft(fft1,fft1,0,I.rows);
cv::dft(fft2,fft2,0,I1.rows);
cv::mulSpectrums(fft1,fft2,fft1,0,true);
// here cv::DFT_SCALE divide `width*height` 1 times
cv::idft(fft1,fft1,cv::DFT_SCALE|cv::DFT_REAL_OUTPUT);
Rearrange(fft1, fft1);
// here divide another times
return cv::abs(fft1)/(width*height);
}
The Rearrange function is the same with your fft_shift as follows:
void Rearrange(cv::Mat& src, cv::Mat& dst)
{
int cx = src.cols / 2;
int cy = src.rows / 2;
cv::Mat tmp;
tmp.create(src.size(), src.type());
src(cv::Rect(0, 0, cx, cy)).copyTo(tmp(cv::Rect(cx, cy, cx, cy)));
src(cv::Rect(cx, cy, cx, cy)).copyTo(tmp(cv::Rect(0, 0, cx, cy)));
src(cv::Rect(cx, 0, cx, cy)).copyTo(tmp(cv::Rect(0, cy, cx, cy)));
src(cv::Rect(0, cy, cx, cy)).copyTo(tmp(cv::Rect(cx, 0, cx, cy)));
dst = tmp;
}
And for famous Lena with a shift (dx=30, dy=20), i got a result image looks similar with your python output:
Lena3020
Basically I am trying to implement a very basic version of the Wiener filter on a grey scale image, using the a stripped down Wiener equation: (1/(SNR))*DFT(Image) after which I take the IDFT of the whole thing. My problem is that my output image which is supposed to be filtered looks exactly like the input, and therefore it seems that the pixel values aren't changing at all. Can anyone please indicate to me where I am going wrong? Here's the code I am currently using:
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv/cv.hpp"
#include "opencv/cxcore.hpp"
#include <iostream>
using namespace cv;
using namespace std;
void updateMag(Mat complex);
Mat updateResult(Mat complex);
Mat computeDFT(Mat image);
Mat DFT2(Mat I);
void shift(Mat magI);
int kernel_size = 0;
int main( int argc, char** argv )
{
Mat result;
String file;
file = " << SAMPLE FILE >>";
Mat image = imread("/Users/John/Desktop/house.png", CV_LOAD_IMAGE_GRAYSCALE);
namedWindow( "Orginal window", CV_WINDOW_AUTOSIZE );// Create a window for display.
imshow( "Orginal window", image ); // Show our image inside it.
float x = 1/0.001;
Mat complex = computeDFT(image); // DFT of image
updateMag(complex); // compute magnitude of complex, switch to logarithmic scale and display...
Mat fourierImage(complex.size(), complex.type());
fourierImage = cv::Scalar::all(x);
//cout<< "Fourier = " << endl << fourierImage << endl;
//Mat complexFourier = computeDFT(fourierImage);
//cout << "1" << endl << complexFourier.type() << endl << complexFourier.type() << endl;
//complex = complex.mul(fourierImage);
//mulSpectrums(complex, fourierImage, complex, DFT_ROWS);
complex = complex.mul(x);
result = updateResult(complex); // do inverse transform and display the result image
waitKey(0);
return 0;
}
Mat updateResult(Mat complex)
{
Mat work;
//work.convertTo(work, CV_32F);
idft(complex, work);
//dft(complex, work, DFT_INVERSE + DFT_SCALE);
Mat planes[] = {Mat::zeros(complex.size(), complex.type()), Mat::zeros(complex.size(), complex.type())};
split(work, planes); // planes[0] = Re(DFT(I)), planes[1] = Im(DFT(I))
magnitude(planes[0], planes[1], work); // === sqrt(Re(DFT(I))^2 + Im(DFT(I))^2)
normalize(work, work, 1, 0, NORM_MINMAX);
imshow("result", work);
return work;
}
void updateMag(Mat complex )
{
Mat magI;
Mat planes[] = {Mat::zeros(complex.size(), CV_32F), Mat::zeros(complex.size(), CV_32F)};
split(complex, planes); // planes[0] = Re(DFT(I)), planes[1] = Im(DFT(I))
magnitude(planes[0], planes[1], magI); // sqrt(Re(DFT(I))^2 + Im(DFT(I))^2)
// switch to logarithmic scale: log(1 + magnitude)
magI += Scalar::all(1);
log(magI, magI);
shift(magI);
normalize(magI, magI, 1, 0, NORM_INF); // Transform the matrix with float values into a
// viewable image form (float between values 0 and 1).
imshow("spectrum", magI);
}
Mat computeDFT(Mat image) {
Mat padded; //expand input image to optimal size
int m = getOptimalDFTSize( image.rows );
int n = getOptimalDFTSize( image.cols ); // on the border add zero values
copyMakeBorder(image, padded, 0, m - image.rows, 0, n - image.cols, BORDER_CONSTANT, Scalar::all(0));
Mat planes[] = {Mat_<float>(padded), Mat::zeros(padded.size(), CV_32F)};
Mat complex;
merge(planes, 2, complex); // Add to the expanded another plane with zeros
dft(complex, complex, DFT_COMPLEX_OUTPUT); // furier transform
return complex;
}
void shift(Mat magI) {
// crop if it has an odd number of rows or columns
magI = magI(Rect(0, 0, magI.cols & -2, magI.rows & -2));
int cx = magI.cols/2;
int cy = magI.rows/2;
Mat q0(magI, Rect(0, 0, cx, cy)); // Top-Left - Create a ROI per quadrant
Mat q1(magI, Rect(cx, 0, cx, cy)); // Top-Right
Mat q2(magI, Rect(0, cy, cx, cy)); // Bottom-Left
Mat q3(magI, Rect(cx, cy, cx, cy)); // Bottom-Right
Mat tmp; // swap quadrants (Top-Left with Bottom-Right)
q0.copyTo(tmp);
q3.copyTo(q0);
tmp.copyTo(q3);
q1.copyTo(tmp); // swap quadrant (Top-Right with Bottom-Left)
q2.copyTo(q1);
tmp.copyTo(q2);
}
Mat DFT2(Mat I)
{
Mat padded; //expand input image to optimal size
int m = getOptimalDFTSize( I.rows );
int n = getOptimalDFTSize( I.cols ); // on the border add zero values
copyMakeBorder(I, padded, 0, m - I.rows, 0, n - I.cols, BORDER_CONSTANT, Scalar::all(0));
Mat planes[] = {Mat_<float>(padded), Mat::zeros(padded.size(), CV_32F)};
Mat complexI;
merge(planes, 2, complexI); // Add to the expanded another plane with zeros
dft(complexI, complexI); // this way the result may fit in the source matrix
// compute the magnitude and switch to logarithmic scale
// => log(1 + sqrt(Re(DFT(I))^2 + Im(DFT(I))^2))
split(complexI, planes); // planes[0] = Re(DFT(I), planes[1] = Im(DFT(I))
magnitude(planes[0], planes[1], planes[0]);// planes[0] = magnitude
Mat magI = planes[0];
magI += Scalar::all(1); // switch to logarithmic scale
log(magI, magI);
// crop the spectrum, if it has an odd number of rows or columns
magI = magI(Rect(0, 0, magI.cols & -2, magI.rows & -2));
// rearrange the quadrants of Fourier image so that the origin is at the image center
int cx = magI.cols/2;
int cy = magI.rows/2;
Mat q0(magI, Rect(0, 0, cx, cy)); // Top-Left - Create a ROI per quadrant
Mat q1(magI, Rect(cx, 0, cx, cy)); // Top-Right
Mat q2(magI, Rect(0, cy, cx, cy)); // Bottom-Left
Mat q3(magI, Rect(cx, cy, cx, cy)); // Bottom-Right
Mat tmp; // swap quadrants (Top-Left with Bottom-Right)
q0.copyTo(tmp);
q3.copyTo(q0);
tmp.copyTo(q3);
q1.copyTo(tmp); // swap quadrant (Top-Right with Bottom-Left)
q2.copyTo(q1);
tmp.copyTo(q2);
normalize(magI, magI, 0, 1, CV_MINMAX); // Transform the matrix with float values into a
// viewable image form (float between values 0 and 1).
return complexI;
}
Platform: opencv 2.4.9 on win7 with VC2015
Issue:
Input image DFT magnitude image
strange noise:
I use dft transfer image into frequency domain and transfer back by idft.
I use 2 ways to get the result. convertTo() and normalize().
the result by convertTo() has strange noise.
normalize() result ........... .......... ......................convertTo() result
wrong high pass filter result:
I pass dft image(both Re & Im) through a Gaussian High Pass Filter
and the result. convertTo() and normalize() are totally different.
convertTo() seem right but has noise and normalize() is strange but no noise...
high pass filter image for display
normalize() result of high pass filter result..... convertTo() result of high pass filter result
Code:
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <iostream>
using namespace cv;
using namespace std;
void DFT_Shift(Mat &a_tImage)
{
// rearrange the image so that the origin is at the image center
int cx = a_tImage.cols / 2;
int cy = a_tImage.rows / 2;
Mat q0(a_tImage, Rect(0, 0, cx, cy)); // Top-Left - Create a ROI per quadrant
Mat q1(a_tImage, Rect(cx, 0, cx, cy)); // Top-Right
Mat q2(a_tImage, Rect(0, cy, cx, cy)); // Bottom-Left
Mat q3(a_tImage, Rect(cx, cy, cx, cy)); // Bottom-Right
Mat tmp; // swap quadrants (Top-Left with Bottom-Right)
q0.copyTo(tmp);
q3.copyTo(q0);
tmp.copyTo(q3);
q1.copyTo(tmp); // swap quadrant (Top-Right with Bottom-Left)
q2.copyTo(q1);
tmp.copyTo(q2);
}
int main()
{
Mat I = imread("Src.bmp", CV_LOAD_IMAGE_GRAYSCALE);
if (I.empty())
return -1;
Mat padded; // expand input image to optimal size
int m = getOptimalDFTSize(I.rows);
int n = getOptimalDFTSize(I.cols); // on the border add zero values
copyMakeBorder(I, padded, 0, m - I.rows, 0, n - I.cols, BORDER_CONSTANT, Scalar::all(0));
Mat planes[] = { Mat_<float>(padded), Mat::zeros(padded.size(), CV_32F) };
#if DO_GHPF > 0
Mat tPlanesFilter[] = { Mat_<float>(padded), Mat::zeros(padded.size(), CV_32F) };
#endif
Mat complexI;
merge(planes, 2, complexI); // Add to the expanded another plane with zeros
dft(complexI, complexI); // this way the result may fit in the source matrix
// compute the magnitude and switch to logarithmic scale
// => log(1 + sqrt(Re(DFT(I))^2 + Im(DFT(I))^2))
split(complexI, planes); // planes[0] = Re(DFT(I), planes[1] = Im(DFT(I))
// Pass both Re & Im Planes through Gaussian High Pass Filter
#if DO_GHPF > 0
GaussianHighPassFilter(complexI, tPlanesFilter);
#endif
Mat magI = planes[0];
printf("Re: %f\n", planes[0].at<float>(40, 40));
printf("Im: %f\n", planes[1].at<float>(40, 40));
magnitude(magI, planes[1], planes[0]); // planes[0] = magnitude
// switch to logarithmic scale
magI += Scalar::all(1);
log(magI, magI);
// crop the spectrum, if it has an odd number of rows or columns
magI = magI(Rect(0, 0, magI.cols & -2, magI.rows & -2));
// dft data base should be shifted to image's center
DFT_Shift(magI);
// Transform the matrix with float values into a viewable image form (float between values 0 and 1).
normalize(magI, magI, 0, 1, CV_MINMAX);
imshow("Input Image", I); // Show the result
imshow("spectrum magnitude", magI);
magI = magI * 255;
imwrite("./Magnitude.jpg", magI);
#if 1 // test idft
Mat ifft;
idft(complexI, ifft, DFT_REAL_OUTPUT);
Mat ifftConvert;
ifft.convertTo(ifftConvert, CV_8U);
imwrite("./IDFT_CV_8U.jpg", ifft);
normalize(ifft, ifft, 0, 1, CV_MINMAX);
imshow("IDFT", ifft);
ifft = ifft * 255;
imwrite("./IDFT.jpg", ifft);
#endif
waitKey();
return 0;
}
The backward Fourier Transform is not normalized. Indeed, if the image is 512x512, idft(dft(x)) is 512x512 times bigger than x. The strange noise is due to the fact that numbers are not in the range 0 - 255 anymore.
In particular, the backward dft features negative values and values as large as 6.6e7. It can be checked by adding:
double min, max;
cv::minMaxLoc(ifft, &min, &max);
std::cout << min<< " " << max <<std::endl;
Scaling down the backward dft can be done by adding:
ifft=ifft/(512*512);
The strange noise is removed.
2/ the normalize() result of high pass filter seems correct. Such a filter will substract a blured image from the original image. In particular, the average of the ouput is 0. Hence, it features negative and positive values. Since the maximum and minimum are of the same magnitude in your case, normalize() will set the zero value near 127\approx 255/2. This is the reason why the image becomes grey. White values correspond to positive values and black values to negative ones.
convertTo() will get very large negative and positive values out of the range 0 -255 for the edges. These values will be converted to white. Far from the edges, the values are close to zero and the color remains black.
I'm trying to follow the discreet fourier transform (dft) example here:
http://docs.opencv.org/doc/tutorials/core/discrete_fourier_transform/discrete_fourier_transform.html
I'm running 2.4.8 on Visual Studio 2013 Express in Windows 8.
I've modified the example so that instead of loading a greyscale image I'm using a colour image captured from my webcam (loaded into a Mat variable).
When I run the example above, I get the following error:
"Assertion Failed Tp>::channels == m.channels()) in
cv::Mat::operator"
and a break at the following line:
Mat planes[] = { Mat_<float>(padded), Mat::zeros(padded.size(), CV_32F) };
Looking around, I saw that this is the old way of converting between types, so I added these lines to convert everything to CV_32F:
padded.convertTo(padded32, CV_32F);
Mat planes[] = { padded32, Mat::zeros(padded32.size(), CV_32F) };
Now the problem is that I get another assertion fail a few lines down at:
split(complexI, planes);
The Error is:
"Assertion Failed (Type == CV_32FC1 || Type == CV_32FC2 || ... || Type
== CV_64FC2) in cv::dft"
So now it seems like it doesn't like the CV_32F data type. I tried making the data type CV_32FC1, but it had the same error. I suspect it's related to the output data type of complexI from the dft() function but I'm not sure what to do. It may also be related to the number of channels in my input (3 channel colour vs 1 channel greyscale image).
Thanks for the help.
Complete code from the linked example:
#include "opencv2/core/core.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"
#include <iostream>
int main(int argc, char ** argv)
{
const char* filename = argc >=2 ? argv[1] : "lena.jpg";
Mat I = imread(filename, CV_LOAD_IMAGE_GRAYSCALE);
if( I.empty())
return -1;
Mat padded; //expand input image to optimal size
int m = getOptimalDFTSize( I.rows );
int n = getOptimalDFTSize( I.cols ); // on the border add zero values
copyMakeBorder(I, padded, 0, m - I.rows, 0, n - I.cols, BORDER_CONSTANT, Scalar::all(0));
Mat planes[] = {Mat_<float>(padded), Mat::zeros(padded.size(), CV_32F)};
Mat complexI;
merge(planes, 2, complexI); // Add to the expanded another plane with zeros
dft(complexI, complexI); // this way the result may fit in the source matrix
// compute the magnitude and switch to logarithmic scale
// => log(1 + sqrt(Re(DFT(I))^2 + Im(DFT(I))^2))
split(complexI, planes); // planes[0] = Re(DFT(I), planes[1] = Im(DFT(I))
magnitude(planes[0], planes[1], planes[0]);// planes[0] = magnitude
Mat magI = planes[0];
magI += Scalar::all(1); // switch to logarithmic scale
log(magI, magI);
// crop the spectrum, if it has an odd number of rows or columns
magI = magI(Rect(0, 0, magI.cols & -2, magI.rows & -2));
// rearrange the quadrants of Fourier image so that the origin is at the image center
int cx = magI.cols/2;
int cy = magI.rows/2;
Mat q0(magI, Rect(0, 0, cx, cy)); // Top-Left - Create a ROI per quadrant
Mat q1(magI, Rect(cx, 0, cx, cy)); // Top-Right
Mat q2(magI, Rect(0, cy, cx, cy)); // Bottom-Left
Mat q3(magI, Rect(cx, cy, cx, cy)); // Bottom-Right
Mat tmp; // swap quadrants (Top-Left with Bottom-Right)
q0.copyTo(tmp);
q3.copyTo(q0);
tmp.copyTo(q3);
q1.copyTo(tmp); // swap quadrant (Top-Right with Bottom-Left)
q2.copyTo(q1);
tmp.copyTo(q2);
normalize(magI, magI, 0, 1, CV_MINMAX); // Transform the matrix with float values into a
// viewable image form (float between values 0 and 1).
imshow("Input Image" , I ); // Show the result
imshow("spectrum magnitude", magI);
waitKey();
return 0;
}
You cannot use dft on an imagine that has more than 2 channels.
Even if the image has 2 channels the second one is interpreted as the imaginary part of a complex number so this probably not what you want anyway.
So you have 2 options: either convert the colour image that you get from your webcam to a single channel image, like a grayscale image, or apply the dft for each channel independently.
You can take a look over mix channels or split, both of them can extract the individual channels from your image and then apply dft on each of them,
I am new in OpenCV and image processing algorithms. I need to do inverse discrete fourier transformation in OpenCV in C++, but I don't know how. I searched over internet and I didn't find answer. I am doing fourier transformation in my program with this code from this page: http://opencv.itseez.com/doc/tutorials/core/discrete_fourier_transform/discrete_fourier_transform.html. I have tried to do inverse to that code, but I don't know where I am doing wrong. My code is here (I think that whole code is wrong):
void doFourierInverse(const Mat &src, Mat &dst) {
normalize(src, dst, 0, -1, CV_MINMAX);
int cx = dst.cols/2;
int cy = dst.rows/2;
Mat q0(dst, Rect(0, 0, cx, cy));
Mat q1(dst, Rect(cx, 0, cx, cy));
Mat q2(dst, Rect(0, cy, cx, cy));
Mat q3(dst, Rect(cx, cy, cx, cy));
Mat tmp;
q0.copyTo(tmp);
q3.copyTo(q0);
tmp.copyTo(q3);
q1.copyTo(tmp);
q2.copyTo(q1);
tmp.copyTo(q2);
dst = dst(Rect(0, 0, dst.cols & -2, dst.rows & -2));
exp(dst, dst);
dst -= Scalar::all(1);
Mat planes[2];
polarToCart(dst, Mat::zeros(dst.rows, dst.cols, dst.type()), planes[0], planes[1]);
merge(planes, 2, dst);
idft(dst, dst, DFT_INVERSE | DFT_SCALE);
split(dst, planes);
dst = planes[0];
}
Actually, you don't have to swap the different quadrants, it's needed only if you're a human and want a more natural looking visualization of the FFT result (i.e. with the 0 frequency in the middle, negative frequencies left/bottom and positive frequencies up/right).
To invert the FFT, you need to pass the result of the forward transform "as is" (or after the frequency filtering you wanted) to the same dft() function, only adding the flag DFT_INVERSE. If you remember your math about FFT, the forward and backward transforms have very tight kinks in the formulation...
--- EDIT ---
What exactly doesn't work ?
The following code does perform forward-then-backward FFT, and everything works just fine as expected.
// Load an image
cv::Mat inputImage = cv::imread(argv[argc-1], 0);
// Go float
cv::Mat fImage;
inputImage.convertTo(fImage, CV_32F);
// FFT
std::cout << "Direct transform...\n";
cv::Mat fourierTransform;
cv::dft(fImage, fourierTransform, cv::DFT_SCALE|cv::DFT_COMPLEX_OUTPUT);
// Some processing
doSomethingWithTheSpectrum();
// IFFT
std::cout << "Inverse transform...\n";
cv::Mat inverseTransform;
cv::dft(fourierTransform, inverseTransform, cv::DFT_INVERSE|cv::DFT_REAL_OUTPUT);
// Back to 8-bits
cv::Mat finalImage;
inverseTransform.convertTo(finalImage, CV_8U);