Inverse fourier transformation in OpenCV
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);
FFT and then Inverse FFT in openCV does not give the same results as the original image
Check out this answer. It probably has something to do with your output data type. The the default output type is a complex number.
How to inverse a DFT with magnitude with opencv python
If you need to modify the magnitude by raising it to a power near 1 (called coefficient rooting or alpha rooting), then it is just a simple modification of my code above using Python/OpenCV. Simply add cv2.pow(mag, 1.1) before converting the magnitude and phase back to real and imaginary components.
Input:
import numpy as np
import cv2
# read input as grayscale
img = cv2.imread('lena.png', 0)
# convert image to floats and do dft saving as complex output
dft = cv2.dft(np.float32(img), flags = cv2.DFT_COMPLEX_OUTPUT)
# apply shift of origin from upper left corner to center of image
dft_shift = np.fft.fftshift(dft)
# extract magnitude and phase images
mag, phase = cv2.cartToPolar(dft_shift[:,:,0], dft_shift[:,:,1])
# get spectrum for viewing only
spec = np.log(mag) / 30
# NEW CODE HERE: raise mag to some power near 1
# values larger than 1 increase contrast; values smaller than 1 decrease contrast
mag = cv2.pow(mag, 1.1)
# convert magnitude and phase into cartesian real and imaginary components
real, imag = cv2.polarToCart(mag, phase)
# combine cartesian components into one complex image
back = cv2.merge([real, imag])
# shift origin from center to upper left corner
back_ishift = np.fft.ifftshift(back)
# do idft saving as complex output
img_back = cv2.idft(back_ishift)
# combine complex components into original image again
img_back = cv2.magnitude(img_back[:,:,0], img_back[:,:,1])
# re-normalize to 8-bits
min, max = np.amin(img_back, (0,1)), np.amax(img_back, (0,1))
print(min,max)
img_back = cv2.normalize(img_back, None, alpha=0, beta=255, norm_type=cv2.NORM_MINMAX, dtype=cv2.CV_8U)
cv2.imshow("ORIGINAL", img)
cv2.imshow("MAG", mag)
cv2.imshow("PHASE", phase)
cv2.imshow("SPECTRUM", spec)
cv2.imshow("REAL", real)
cv2.imshow("IMAGINARY", imag)
cv2.imshow("COEF ROOT", img_back)
cv2.waitKey(0)
cv2.destroyAllWindows()
# write result to disk
cv2.imwrite("lena_grayscale_opencv.png", img)
cv2.imwrite("lena_grayscale_coefroot_opencv.png", img_back)
Original Grayscale:
Coefficient Rooting Result:
Here is an animation showing the differences (created using ImageMagick):
Related Topics
Why, Really, Deleting an Incomplete Type Is Undefined Behaviour
How to Support Both Ipv4 and Ipv6 Connections
Throw New Std::Exception VS Throw Std::Exception
Order of Evaluation of Function Parameters
Difference Between 'Strcpy' and 'Strcpy_S'
How Computer Does Floating Point Arithmetic
C++ Boost: What's the Cause of This Warning
If Temporaries Are Implicitly Non-Modifiable, How Does This Work
Generate Include File Name in a MACro
Member Fields, Order of Construction
How Are Local and Global Variables Initialized by Default
How to Use C++11 Enum Class for Flags
Using Bts Assembly Instruction with Gcc Compiler
Why Is Locking a Std::Mutex Twice 'Undefined Behaviour'
C++ Visual Studio "Non-Standard Syntax; Use '&' to Create a Pointer to Member"
Better Shading on Bw Display While Rendering Filled Surfaces