How to do inverse DFT in OpenCV [duplicate] - c++

This question already has an answer here:
Inverse fourier transformation in OpenCV
(1 answer)
Closed 6 years ago.
I'm trying to implement inverse DFT using OpenCV in C++
I downloaded complete dft example in docs.opencv.org and just adjust couple of lines to inverse.
my DFT code is like this
Mat DFT(const char* filename)
{
Mat I = imread(filename, CV_LOAD_IMAGE_GRAYSCALE);
if (I.empty())
{
Mat emty(7, 7, CV_32FC2, Scalar(1, 3));
return emty;
}
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);
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(filename, magI);
// waitKey();
return magI;
}
and did IDFT. By just fix dft to idft. But the output was just look like noise. What did I do wrong? I thought the dft and idft is just same....
Mat IDFT(Mat src)
{
Mat I = src;
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, DFT_INVERSE); // this way the result may fit in the source matrix
// compute the magnitude and switch to logarithmic scale
// => log(1 + sqrt(Re(IDFT(I))^2 + Im(IDFT(I))^2))
split(complexI, planes); // planes[0] = Re(IDFT(I), planes[1] = Im(IDFT(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);
normalize(magI, magI, 0, 1, CV_MINMAX);
imshow("forged map", magI);
return magI;
}

you have to rewrite your code like this to get the inverse DFT which is the original image read :
#include "stdafx.h"
#include <opencv2/core/core.hpp>
#include <opencv2\highgui\highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <iostream>
using namespace std;
using namespace cv;
int main()
{
Mat I = imread("test.tif", 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
normalize(phaseVals, phaseVals, 0, 1, CV_MINMAX);
// viewable image form (float between values 0 and 1).
imshow("Input Image" , I ); // Show the result
imshow("Spectrum Magnitude", magI);
waitKey();
//calculating the idft
cv::Mat inverseTransform;
cv::dft(complexI, inverseTransform, cv::DFT_INVERSE|cv::DFT_REAL_OUTPUT);
normalize(inverseTransform, inverseTransform, 0, 1, CV_MINMAX);
imshow("Reconstructed", inverseTransform);
waitKey();
return 0;
}
I just added this part to your code :
//calculating the idft
cv::Mat inverseTransform;
cv::dft(complexI, inverseTransform, cv::DFT_INVERSE|cv::DFT_REAL_OUTPUT);
normalize(inverseTransform, inverseTransform, 0, 1, CV_MINMAX);
imshow("Reconstructed", inverseTransform);
waitKey();

for some reason using the normalize function in the given idft block doesn't give exactly the desired original image (contrast wise). Instead use convertTo. To be precise, replace the normalize function with the following line.
inverseTransform.convertTo(inverseTransform, CV_8U);

Related

C++ Cross Correlation of 2 shifted images with OpenCV

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

wiener filter OpenCV

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;
}

Save spectrum of DFT using OpenCV

I am using Visual Studio 2013 and OpenCV library. I display discrete Fourier transform and it works well. I'd like to save the displayed image which is the spectrum, but the saved one is black even when I use JPEG quality=100.
#include "opencv2/core/core.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/opencv.hpp"
#include <iostream>
#include <cmath>
using namespace cv;
using namespace std;
static void help(char* progName)
{
cout << endl
<< "This program demonstrated the use of the discrete Fourier transform (DFT). " << endl
<< "The dft of an image is taken and it's power spectrum is displayed." << endl
<< "Usage:" << endl
<< progName << " [image_name -- default lena.jpg] " << endl << endl;
}
int main(int argc, char ** argv)
{
help(argv[0]);
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);
cv::Mat gs_bgr(magI.size(), CV_8UC1);
cv::cvtColor(magI, gs_bgr, CV_RGB2GRAY);
imwrite("orig.png", gs_bgr);
waitKey();
return 0;
}
the outcome of the dft (magI) is a float Mat, but you can only save uchar images with imwrite.
since you normalized the image to [0..1] , the resulting uchar - grayscale img only has 0 and 1 values, which will look pretty black indeed.
also, applying cv::cvtColor(magI, gs_bgr, CV_RGB2GRAY); to a 1chan float img seems broken.
instead of that, try:
Mat gray;
magI.convertTo(gray, CV_8U, 255); // upscale to [0..255]

OpenCV: Data type assertion fail with split() function

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,

How to do inverse DFT using magnitude and phase of a image in opencv?

I want to show that phase of an image carries more information than that of its magnitude, so I want to exchange the magnitude of two image and then do the inverse DFT.
here is the code:
void main()
{
Mat I1 = imread("lena.jpg", CV_LOAD_IMAGE_GRAYSCALE);
Mat I2 = imread("peppers.png", CV_LOAD_IMAGE_GRAYSCALE);
Mat padded1,padded2;
//expand input image to optimal size
int m1= getOptimalDFTSize( I1.rows );
int n1 = getOptimalDFTSize( I1.cols );
int m2= getOptimalDFTSize( I2.rows );
int n2 = getOptimalDFTSize( I2.cols );
// on the border add zero values
copyMakeBorder(I1, padded1, 0, m1 - I1.rows, 0, n1 - I1.cols, BORDER_CONSTANT, Scalar::all(0));
copyMakeBorder(I2, padded2, 0, m2 - I2.rows, 0, n2 - I2.cols, BORDER_CONSTANT, Scalar::all(0));
Mat planes1[] = {Mat_<float>(padded1), Mat::zeros(padded1.size(), CV_32F)};
Mat planes2[] = {Mat_<float>(padded2), Mat::zeros(padded2.size(), CV_32F)};
Mat complexI, complexII;
// Add to the expanded another plane with zeros
merge(planes1, 2, complexI);
merge(planes2, 2, complexII);
dft(complexI, complexI);
dft(complexII, complexII);
// compute the magnitude and phase then switch to logarithmic scale
// => magnitude:log(1 + sqrt(Re(DFT(I))^2 + Im(DFT(I))^2)), phase:arctan(Im(DFT(I)),Re(DFT(I)))
split(complexI, planes1);// planes[0] = Re(DFT(I)), planes[1] = Im(DFT(I))
Mat ph1, magI1;
phase(planes1[0], planes1[1], ph1);//ph1 = phase
magnitude(planes1[0], planes1[1], magI1);// magI1 = magnitude
magI1 = magI1(Rect(0, 0, magI1.cols & -2, magI1.rows & -2));
ph1 = ph1(Rect(0, 0, ph1.cols & -2, ph1.rows & -2));
split(complexII, planes2);// planes[0] = Re(DFT(I)), planes[1] = Im(DFT(I))
Mat ph2, magI2;
phase(planes2[0], planes2[1], ph2);//ph2 = phase
magnitude(planes2[0], planes2[1], magI2);// mag2 = magnitude
magI2 = magI2(Rect(0, 0, magI2.cols & -2, magI2.rows & -2));
ph2 = ph2(Rect(0, 0, ph2.cols & -2, ph2.rows & -2));
planes1[1] = ph1; planes1[0] = magI2;
planes2[1] = ph2; planes2[0] = magI1;
dft(complexI,complexI,DFT_INVERSE);
dft(complexII,complexII,DFT_INVERSE);
imshow("image", complexI);
waitKey();
}
I just simply merge magnitude and phase together then do the IDFT, seems totally wrong.
I guess from your question that something with your dft is not working.
Try the below Code (after adding your split Planes) and see if it works.
The images have to be the Exact same Size.
If something else is wrong: please show your images and results. Maybe your code is correct and you are just expecting the wrong thing.
Here is the working Example:
// Load an image
Mat I1 = imread("lena.jpg", CV_LOAD_IMAGE_GRAYSCALE);
Mat I2 = imread("peppers.png", CV_LOAD_IMAGE_GRAYSCALE);
Mat fI1;
Mat fI2;
I1.convertTo(fI1, CV_32F);
I2.convertTo(fI2, CV_32F);
//Perform DFT
Mat fourierTransform1;
Mat fourierTransform2;
dft(fI1, fourierTransform1, DFT_SCALE|DFT_COMPLEX_OUTPUT);
dft(fI2, fourierTransform2, DFT_SCALE|DFT_COMPLEX_OUTPUT);
//your split plane and everything else
//Perform IDFT
Mat inverseTransform1;
Mat inverseTransform2;
dft(fourierTransform1, inverseTransform1, DFT_INVERSE|DFT_REAL_OUTPUT);
dft(fourierTransform2, inverseTransform2, DFT_INVERSE|DFT_REAL_OUTPUT);
Mat result1;
Mat result2;
inverseTransform1.convertTo(result1, CV_8U);
inverseTransform2.convertTo(result2, CV_8U);
You can't merge the magnitude and phase by using cv::merge() function, instead you should use cv::polarToCart(). Here's my code to do what you want:
using namespace cv;
// Rearrange the quadrants of a Fourier image so that the origin is at
// the image center
void shiftDFT(Mat &fImage )
{
Mat tmp, q0, q1, q2, q3;
// first crop the image, if it has an odd number of rows or columns
fImage = fImage(Rect(0, 0, fImage.cols & -2, fImage.rows & -2));
int cx = fImage.cols / 2;
int cy = fImage.rows / 2;
// rearrange the quadrants of Fourier image
// so that the origin is at the image center
q0 = fImage(Rect(0, 0, cx, cy));
q1 = fImage(Rect(cx, 0, cx, cy));
q2 = fImage(Rect(0, cy, cx, cy));
q3 = fImage(Rect(cx, cy, cx, cy));
q0.copyTo(tmp);
q3.copyTo(q0);
tmp.copyTo(q3);
q1.copyTo(tmp);
q2.copyTo(q1);
tmp.copyTo(q2);
}
int main()
{
// Load an image
Mat I1 = imread("lena.jpg", CV_LOAD_IMAGE_GRAYSCALE);
Mat I2 = imread("pepper.jpg", CV_LOAD_IMAGE_GRAYSCALE);
Mat fI1;
Mat fI2;
I1.convertTo(fI1, CV_32F);
I2.convertTo(fI2, CV_32F);
//expand input image to optimal size
int m = getOptimalDFTSize( I1.rows );
int n = getOptimalDFTSize( I1.cols );
Mat padded1, padded2;
// on the border add zero values
copyMakeBorder(fI1, padded1, 0, m - I1.rows, 0, n - I1.cols, BORDER_CONSTANT, Scalar::all(0));
copyMakeBorder(fI2, padded2, 0, m - I2.rows, 0, n - I2.cols, BORDER_CONSTANT, Scalar::all(0));
//Perform DFT
Mat fourierTransform1;
Mat fourierTransform2;
Mat planes1[2], planes2[2];
dft(fI1, fourierTransform1, DFT_SCALE|DFT_COMPLEX_OUTPUT);
dft(fI2, fourierTransform2, DFT_SCALE|DFT_COMPLEX_OUTPUT);
shiftDFT(fourierTransform1);
shiftDFT(fourierTransform2);
split(fourierTransform1, planes1);// planes[0] = Re(DFT(I)), planes[1] = Im(DFT(I))
split(fourierTransform2, planes2);// planes[0] = Re(DFT(I)), planes[1] = Im(DFT(I))
Mat ph1, mag1;
mag1.zeros(planes1[0].rows, planes1[0].cols, CV_32F);
ph1.zeros(planes1[0].rows, planes1[0].cols, CV_32F);
cartToPolar(planes1[0], planes1[1], mag1, ph1);
Mat ph2, mag2;
mag2.zeros(planes2[0].rows, planes2[0].cols, CV_32F);
ph2.zeros(planes2[0].rows, planes2[0].cols, CV_32F);
cartToPolar(planes2[0], planes2[1], mag2, ph2);
polarToCart(mag1, ph2, planes1[0], planes1[1]);
polarToCart(mag2, ph1, planes2[0], planes2[1]);
merge(planes1, 2, fourierTransform1);
merge(planes2, 2, fourierTransform2);
shiftDFT(fourierTransform1);
shiftDFT(fourierTransform2);
//Perform IDFT
Mat inverseTransform1, inverseTransform2;
dft(fourierTransform1, inverseTransform1, DFT_INVERSE|DFT_REAL_OUTPUT);
dft(fourierTransform2, inverseTransform2, DFT_INVERSE|DFT_REAL_OUTPUT);
namedWindow("original image 1");
imshow("original image 1", I1);
namedWindow("original image 2");
imshow("original image 2", I2);
waitKey(0);
cv::Mat out1, out2;
inverseTransform1.convertTo(out1, CV_8U);
inverseTransform2.convertTo(out2, CV_8U);
namedWindow("result image 1");
imshow("result image 1", out1);
namedWindow("result image 2");
imshow("result image 2", out2);
waitKey(0);
}