Matlab inverse FFT from phase/magnitude only - matlab

So I have this image 'I'. I take F = fft2(I) to get the 2D fourier transform. To reconstruct it, I could go ifft2(F).
The problem is, I need to reconstruct this image from only the a) magnitude, and b) phase components of F. How can I separate these two components of the fourier transform, and then reconstruct the image from each?
I tried the abs() and angle() functions to get magnitude and phase, but the phase one won't reconstruct properly.
Help?

You need one matrix with the same magnitude as F and 0 phase, and another with the same phase as F and uniform magnitude. As you noted abs gives you the magnitude. To get the uniform magnitude same phase matrix, you need to use angle to get the phase, and then separate the phase back into real and imaginary parts.
> F_Mag = abs(F); %# has same magnitude as F, 0 phase
> F_Phase = cos(angle(F)) + j*(sin(angle(F)); %# has magnitude 1, same phase as F
> I_Mag = ifft2(F_Mag);
> I_Phase = ifft2(F_Phase);

it's too late to put another answer to this post, but...anyway
# zhilevan, you can use the codes I have written using mtrw's answer:
image = rgb2gray(imread('pillsetc.png'));
subplot(131),imshow(image),title('original image');
set(gcf, 'Position', get(0, 'ScreenSize')); % maximize the figure window
%:::::::::::::::::::::
F = fft2(double(image));
F_Mag = abs(F); % has the same magnitude as image, 0 phase
F_Phase = exp(1i*angle(F)); % has magnitude 1, same phase as image
% OR: F_Phase = cos(angle(F)) + 1i*(sin(angle(F)));
%:::::::::::::::::::::
% reconstruction
I_Mag = log(abs(ifft2(F_Mag*exp(i*0)))+1);
I_Phase = ifft2(F_Phase);
%:::::::::::::::::::::
% Calculate limits for plotting
% To display the images properly using imshow, the color range
% of the plot must the minimum and maximum values in the data.
I_Mag_min = min(min(abs(I_Mag)));
I_Mag_max = max(max(abs(I_Mag)));
I_Phase_min = min(min(abs(I_Phase)));
I_Phase_max = max(max(abs(I_Phase)));
%:::::::::::::::::::::
% Display reconstructed images
% because the magnitude and phase were switched, the image will be complex.
% This means that the magnitude of the image must be taken in order to
% produce a viewable 2-D image.
subplot(132),imshow(abs(I_Mag),[I_Mag_min I_Mag_max]), colormap gray
title('reconstructed image only by Magnitude');
subplot(133),imshow(abs(I_Phase),[I_Phase_min I_Phase_max]), colormap gray
title('reconstructed image only by Phase');

Related

How can I restore my image back from the Fourier Spectrum

I've taken the following image:
PandaNoise.bmp and tried to remove the periodic noise by focusing on its Fourier spectrum. Commented lines are the ones I'm not sure about. I can't get it back to the image plane. What am I doing wrong here?
panda = imread('PandaNoise.bmp');
fpanda = fft2(panda); % 2d fast fourier transform
fpanda = fftshift(fpanda); % center FFT
fpanda = abs(fpanda); % get magnitude
fpanda = log(1 + fpanda); % use log to expand range of dark pixels into bright region
fpanda = mat2gray(fpanda); % scale image from 0 to 1
figure; imshow(fpanda,[]); % show the picture
zpanda = fpanda;
zpanda(fpanda<0.5)=0;
zpanda(fpanda>0.5)=1;
%img = ifft2(zpanda);
%img = ifftshift(img);
%img = exp(1-img);
%img = abs(img);
Here is an example of how to work with the complex Fourier transform. We can take the log modulus for display, but don't change the original Fourier transform matrix, since the phase information that we throw away with abs is very important.
% Load data
panda = imread('https://i.stack.imgur.com/9SlW5.png');
panda = im2double(panda);
% Forward transform
fpanda = fft2(panda);
% Prepare FT for display -- don't change fpanda!
fd = fftshift(fpanda);
fd = log(1 + abs(fd));
figure; imshow(fd,[]); % show the picture
% From here we learn that we should keep the central 1/5th along both axes
% Low-pass filter
sz = size(fpanda);
center = floor(sz/2)+1;
half_width = ceil(sz/10)-1;
filter = zeros(sz);
filter(center(1)+(-half_width(1):half_width(1)),...
center(2)+(-half_width(2):half_width(2))) = 1;
filter = ifftshift(filter); % The origin should be on the top-left, like that of fpanda.
fpanda = fpanda .* filter;
% Inverse transform
newpanda = ifft2(fpanda);
figure; imshow(newpanda);
After computing the ifft2, newpanda is supposed to be purely real-valued if we designed the filter correctly (i.e. perfectly symmetric around the origin). Any imaginary component still present should be purely numerical innacuracy. MATLAB will detect that the input to ifft2 is conjugate symmetric, and return a purely real result. Octave will not, and you would have to do newpanda=real(newpanda) to avoid warnings from imshow.

MATLAB quickie: How to plot markers on a freqs plot?

I haven't used MATLAB in a while and I am stuck on a small detail. I would really appreciate it if someone could help me out!
So I am trying to plot a transfer function using a specific function called freqs but I can't figure out how I can label specific points on the graph.
b = [0 0 10.0455]; % Numerator coefficients
a = [(1/139344) (1/183.75) 1]; % Denominator coefficients
w = logspace(-3,5); % Frequency vector
freqs(b,a,w)
grid on
I want to mark values at points x=600 Hz and 7500 Hz with a marker or to be more specific, points (600,20) and (7500,-71), both of which should lie on the curve. For some reason, freqs doesn't let me do that.
freqs is very limited when you want to rely on it plotting the frequency response for you. Basically, you have no control on how to modify the graph on top of what MATLAB generates for you.
Instead, generate the output response in a vector yourself, then plot the magnitude and phase of the output yourself so that you have full control. If you specify an output when calling freqs, you will get the response of the system.
With this, you can find the magnitude of the output by abs and the phase by angle. BTW, (600,20) and (7500,-71) make absolutely no sense unless you're talking about magnitude in dB.... which I will assume is the case for the moment.
As such, we can reproduce the plot that freqs gives by the following. The key is to use semilogx to get a semi-logarithmic graph on the x-axis. On top of this, declare those points that you want to mark on the magnitude, so (600,20) and (7500,-71):
%// Your code:
b = [0 0 10.0455]; % Numerator coefficients
a = [(1/139344) (1/183.75) 1]; % Denominator coefficients
w = logspace(-3,5); % Frequency vector
%// New code
h = freqs(b,a,w); %// Output of freqs
mag = 20*log10(abs(h)); %// Magnitude in dB
pha = (180/pi)*angle(h); %// Phase in degrees
%// Declare points
wpt = [600, 7500];
mpt = [20, -71];
%// Plot the magnitude as well as markers
figure;
subplot(2,1,1);
semilogx(w, mag, wpt, mpt, 'r.');
xlabel('Frequency');
ylabel('Magnitude (dB)');
grid;
%// Plot phase
subplot(2,1,2);
semilogx(w, pha);
xlabel('Frequency');
ylabel('Phase (Degrees)');
grid;
We get this:
If you check what freqs generates for you, you'll see that we get the same thing, but the magnitude is in gain (V/V) instead of dB. If you want it in V/V, then just plot the magnitude without the 20*log10() call. Using your data, the markers I plotted are not on the graph (wpt and mpt), so adjust the points to whatever you see fit.
There are a couple issues before we attempt to answer your question. First, there is no data-point at 600Hz or 7500Hz. These frequencies fall between data-points when graphed using the freqs command. See the image below, with datatips added interactively. I copy-pasted your code to generate this data.
Second, it does not appear that either (600,20) or (7500,-71) lie on the curves, at least with the data as you entered above.
One solution is to use plot a marker on the desired position, and use a "text" object to add a string describing the point. I put together a script using your data, to generate this figure:
The code is as follows:
b = [0 0 10.0455];
a = [(1/139344) (1/183.75) 1];
w = logspace(-3,5);
freqs(b,a,w)
grid on
figureHandle = gcf;
figureChildren = get ( figureHandle , 'children' ); % The children this returns may vary.
axes1Handle = figureChildren(1);
axes2Handle = figureChildren(2);
axes1Children = get(axes1Handle,'children'); % This should be a "line" object.
axes2Children = get(axes2Handle,'children'); % This should be a "line" object.
axes1XData = get(axes1Children,'xdata');
axes1YData = get(axes1Children,'ydata');
axes2XData = get(axes2Children,'xdata');
axes2YData = get(axes2Children,'ydata');
hold(axes1Handle,'on');
plot(axes1Handle,axes1XData(40),axes1YData(40),'m*');
pointString1 = ['(',num2str(axes1XData(40)),',',num2str(axes1YData(40)),')'];
handleText1 = text(axes1XData(40),axes1YData(40),pointString1,'parent',axes1Handle);
hold(axes2Handle,'on');
plot(axes2Handle,axes2XData(40),axes2YData(40),'m*');
pointString2 = ['(',num2str(axes2XData(40)),',',num2str(axes2YData(40)),')'];
handleText2 = text(axes2XData(40),axes2YData(40),pointString2,'parent',axes2Handle);

Inverse Fourier Transform function gives wrong result

I am implementing a code for image enhancement and to apply Fourier and inverse Fourier transform I am using the code below but in result it gives black image.
F = fft2(image); F = fftshift(F); % Center FFT
F = abs(F); % Get the magnitude
F = log(F+1); % Use log, for perceptual scaling, and +1 since log(0) is undefined
F = mat2gray(F); % Use mat2gray to scale the image between 0 and 1
Y = ifft2(F);
subplot(1,1,1);
imshow(Y,[]); % Display the result
You try to image the inverse FFT of a matrix which is pure real (and positive), abs(F). The inverse FT of that is a complex one, and since you lose the phase of the original FT, you will get strange result (almost black image, with eventually the first pixel white...).
Second error, you shift the fft to make some computations, but you don't inverse the shift before
For what you want, you have to keep the phase of the FFT:
F = fft2(image); F = fftshift(F); % Center FFT
Fp = angle(F); % Get the phase
F = abs(F); % Get the magnitude
F = log(F+1); % Use log, for perceptual scaling, and +1 since log(0) is undefined
F = mat2gray(F); % Use mat2gray to scale the image between 0 and 1
Y = real(ifft2(ifftshift(F.*exp(1i*Fp))));
subplot(1,1,1);
imshow(Y,[]); % Display the result
Note: you need to take the real part of the inverse FFT since Matlab creates automatically a complex array as output of a FT (direct or inverse), even if it is a real output. You can check this if you see the value of max(abs(imag(Y(:)))), 6e-11 on my computer.

How to plot a 2D FFT in Matlab?

I am using fft2 to compute the Fourier Transform of a grayscale image in MATLAB.
What is the common way to plot the magnitude of the result?
Assuming that I is your input image and F is its Fourier Transform (i.e. F = fft2(I))
You can use this code:
F = fftshift(F); % Center FFT
F = abs(F); % Get the magnitude
F = log(F+1); % Use log, for perceptual scaling, and +1 since log(0) is undefined
F = mat2gray(F); % Use mat2gray to scale the image between 0 and 1
imshow(F,[]); % Display the result
Here is an example from my HOW TO Matlab page:
close all; clear all;
img = imread('lena.tif','tif');
imagesc(img)
img = fftshift(img(:,:,2));
F = fft2(img);
figure;
imagesc(100*log(1+abs(fftshift(F)))); colormap(gray);
title('magnitude spectrum');
figure;
imagesc(angle(F)); colormap(gray);
title('phase spectrum');
This gives the magnitude spectrum and phase spectrum of the image. I used a color image, but you can easily adjust it to use gray image as well.
ps. I just noticed that on Matlab 2012a the above image is no longer included. So, just replace the first line above with say
img = imread('ngc6543a.jpg');
and it will work. I used an older version of Matlab to make the above example and just copied it here.
On the scaling factor
When we plot the 2D Fourier transform magnitude, we need to scale the pixel values using log transform to expand the range of the dark pixels into the bright region so we can better see the transform. We use a c value in the equation
s = c log(1+r)
There is no known way to pre detrmine this scale that I know. Just need to
try different values to get on you like. I used 100 in the above example.

Applying MATLAB's idwt2 several times

I am using MATLAB to apply the Discrete Wavelet Transform on an image. I am applying it several times (3) in order to get a 3 level transform. I am using the dwt2 function provided by MATLAB in order to compress and idwt2 to make the decompression. The problem is that I do not know how to decompress several times, as in apply idwt2 several times to the previous received output, as it returns a matrix. Take for example:
x = idwt2(scaled3, vertical3, horizontal3, diagonal3, Lo_R, Ho_R);
How should idwt2 be applied to x?
Looking at the documentation for dwt2 and idwt2, it appears that you have 2 general options for reconstructing your multiply-decomposed images:
Store all of the horizontal, vertical, and diagonal detail coefficient matrices from each decomposition step and use them in the reconstruction.
Enter an empty matrix ([]) for any detail coefficient matrices that you didn't save from previous decomposition steps.
Since it was a slow day, here's some code showing how to do this and what the results look like for each case...
First, load a sample image and initialize some variables:
load woman; % Load image data
nLevel = 3; % Number of decompositions
nColors = size(map, 1); % Number of colors in colormap
cA = cell(1, nLevel); % Approximation coefficients
cH = cell(1, nLevel); % Horizontal detail coefficients
cV = cell(1, nLevel); % Vertical detail coefficients
cD = cell(1, nLevel); % Diagonal detail coefficients
Now, apply the decompositions (in this case 3) and store the detail coefficient matrices from each step in a cell array:
startImage = X;
for iLevel = 1:nLevel,
[cA{iLevel}, cH{iLevel}, cV{iLevel}, cD{iLevel}] = dwt2(startImage, 'db1');
startImage = cA{iLevel};
end
To see what the final decomposed image looks like, along with all the detail coefficient matrices along the way, run the following code (which makes use of wcodemat):
tiledImage = wcodemat(cA{nLevel}, nColors);
for iLevel = nLevel:-1:1,
tiledImage = [tiledImage wcodemat(cH{iLevel}, nColors); ...
wcodemat(cV{iLevel}, nColors) wcodemat(cD{iLevel}, nColors)];
end
figure;
imshow(tiledImage, map);
You should see something like this:
Now it's time to reconstruct! The following code performs a "full" reconstruction (using all of the stored detail coefficient matrices) and a "partial" reconstruction (using none of them), then it plots the images:
fullRecon = cA{nLevel};
for iLevel = nLevel:-1:1,
fullRecon = idwt2(fullRecon, cH{iLevel}, cV{iLevel}, cD{iLevel}, 'db1');
end
partialRecon = cA{nLevel};
for iLevel = nLevel:-1:1,
partialRecon = idwt2(partialRecon, [], [], [], 'db1');
end
figure;
imshow([X fullRecon; partialRecon zeros(size(X))], map, ...
'InitialMagnification', 50);
Notice that the original (top left) and the "full" reconstruction (top right) look indistinguishable, but the "partial" reconstruction (lower left) is very pixelated. The difference wouldn't be as severe if you applied fewer decomposition steps, like just 1 or 2.
% Multi-level reconstruction from DWT coefficients
% The variable "coefs" is what you get when you perform forward dwt2()
% on the image you're decomposing. It is a long row
% vector that has cA- approximation details, cH -horizontal details, cV-
% vertical details, cD-diagonal details
L=3; % For db 3-level reconstruction for example
k=size(image,1)/2^L; % I am assuming a square sized image where both
% dimensions are equal
for level=0:(L-1)
s=k*2^level;
if level==0
cA=reshape(coefs(1,1:s^2),s,s);
figure;imshow(cA,[])
end
cH=reshape(coefs(1,(s^2+1):2*s^2),s,s);
figure;imshow(cH,[])
cV=reshape(coefs(1,(2*s^2+1):3*s^2),s,s);
figure;imshow(cV,[])
cD=reshape(coefs(1,(3*s^2+1):4*s^2),s,s);
figure;imshow(cD,[])
I_rec=idwt2(cA,cH,cV,cD,"db1");
figure;imshow(I_rec,[])
cA=I_rec; % The recosntructed image is the approximation detail-cA
% for next levels of reconstruction
end