Can't plot results of matlab 2D fast fourier transform - matlab

I conducted a 2D fourier transform on a 4436413x3 matrix using the matlab fft2 command (this one: https://www.mathworks.com/help/matlab/ref/fft2.html). The product is a 4436413x3 matrix containing complex values. When I try to plot the data, I end up with a graph that is all one color or an error message that references the complex values in my data.
I have tried interpolating to create a 2D set of values using the griddata() function, however, when applied to my 3D dataset, this returns a 1D vector equal to the z-column in my original 3D dataset. My 3D dataset consists of x, y, and z points, and in my attempt to interpolate I used vq = griddata(x,y,z,x,y). I had also tried to create a 4436412x3 meshgrid for my query points (using [xq, yq] = meshgrid(4436412, 3), and then using xq and yq as my query points), but this was returning NaN.
When I run
Y = fft2(x);
imagesc(abs(fftshift(Y)))
I get a single purple box.
When I run
Y = fft2(x);
imagesc(Y)
I get the following error message:
Error using image
Complex values are not supported. Specify the color data as numeric or logical values.
Error in imagesc (line 52)
hh = image(varargin{:}, 'CDataMapping', 'scaled');

To apply the FFT, you need data to be sampled on a regular grid. Your data represents (x,y,z) coordinates of points. Here's how to use griddata to resample these coordinates onto a regular (x,y) grid:
% Generate example data, let's say x and y are in the range [-3,3]:
n = 62500;
x = rand(n, 1) * 6 - 3;
y = rand(n, 1) * 6 - 3;
z = sin(4*x) + cos(2*y); % an example function
data = [x,y,z]; % This is a 4436413x3 array with (x,y,z) coordinates
% Interpolate z values onto a regular (x,y) grid:
[xq, yq] = meshgrid(linspace(min(x), max(x), sqrt(n)), ...
linspace(min(y), max(y), sqrt(n)));
zq = griddata(x, y, z, xq, yq);
% griddata doesn't extrapolate, writes NaN instead. Let's fill those
% in with zeros (maybe a different value is more meaningful in your
% application).
zq(isnan(zq)) = 0;
% Now you can apply a 2D Fourier transform:
Z = fft2(zq);
imshow(log(abs(fftshift(Z))), []);

Related

Plotting a coloured 3D figure in MATLAB

I have 3 axes: X of size N, Y of size M and Z of size O, which correspond to the coordinates of my data.
I have a matrix: DATA of size MxNxO, which corresponds to the module for each points.
I would like to plot the MATLAB figure of coordinate X, Y, Z and color the point depending of the value of the matrix DATA of size MxNxO.
I tried lots of functions such as scatter3, surf, plot3, but none is working as I wanted.
This is what I tried:
n = 10;
x = linspace(0,10,n);
y = linspace(0,10,n);
z = linspace(0,10,n);
DATA = randn(n,n,n);
scatter3(x,y,z,DATA);
This code didn't work because DATA is not the same size as x, y, z. I also tried with:
[X,Y,Z] = ndgrid(x,y,z)
scatter3(X,Y,Z,DATA);
but this didn't work either.
The trick with scatter3() is to "unroll" your matrices to a column vector, and don't forget that the fourth argument is size, rather than colour:
n = 10;
x = linspace(0,10,n);
y = linspace(0,10,n);
z = linspace(0,10,n);
[X,Y,Z] = ndgrid(x,y,z);
DATA = randn(n,n,n);
% here 3 is the size. You can set it to a different constant, or vary it as well
scatter3(X(:), Y(:), Z(:), 3, DATA(:));
Results in
You can colour a surface, see its documentation, however, it doesn't seem to make much sense in your case, given you have a full cube of data points. A surface is 2D, whereas your data is 3D. For a 2D surface, simply follow the example in the docs:
n = 10;
x = linspace(0,10,n);
y = linspace(0,10,n);
Z = rand(n);
DATA = randn(n);
surf(x, y, Z, DATA);
Images rendered in R2007b, syntax cross-checked with the documentation.
If you've got a surface defined by an M -by- 4 array containing X, Y, Z and Data, you can use delaunay() to create a Delaunay triangulation of your points and then trisurf() to plot that. Note that this still requires a 2D surface, albeit it can vary in three dimensions. The cube of data in your example still doesn't make sense to plot as a surface, even with this method.

How to interpolate using in polar coordinate

I have polar coordinates, radius 0.05 <= r <= 1 and 0 ≤ θ ≤ 2π. The radius r is 50 values between 0.05 to 1, and polar angle θ is 24 values between 0 to 2π.
How do I interpolate r = 0.075 and theta = pi/8?
I dunno what you have tried, but interp2 works just as well on polar data as it does on Cartesian. Here is some evidence:
% Coordinates
r = linspace(0.05, 1, 50);
t = linspace(0, 2*pi, 24);
% Some synthetic data
z = sort(rand(50, 24));
% Values of interest
ri = 0.075;
ti = pi/8;
% Manually interpolate
rp = find(ri <= r, 1, 'first');
rm = find(ri >= r, 1, 'last');
tp = find(ti <= t, 1, 'first');
tm = find(ti >= t, 1, 'last');
drdt = (r(rp) - r(rm)) * (t(tp) - t(tm));
dr = [r(rp)-ri ri-r(rm)];
dt = [t(tp)-ti ti-t(tm)];
fZ = [z(rm, tm) z(rm, tp)
z(rp, tm) z(rp, tp)];
ZI_manual = (dr * fZ * dt.') / drdt
% Interpolate with MATLAB
ZI_MATLAB = interp2(r, t, z', ri, ti, 'linear')
Result:
ZI_manual =
2.737907208525297e-002
ZI_MATLAB =
2.737907208525298e-002
Based on comments you have the following information
%the test point
ri=0.53224;
ti = pi/8;
%formula fo generation of Z
g=9.81
z0=#(r)0.01*(g^2)*((2*pi)^-4)*(r.^-5).*exp(-1.25*(r/0.3).^-4);
D=#(t)(2/pi)*cos(t).^2;
z2=#(r,t)z0(r).*D(t) ;
%range of vlaues of r and theta
r=[0.05,0.071175,0.10132,0.14422,0.2053, 0.29225,0.41602,0.5922,0.84299,1.2];
t=[0,0.62832,1.2566,1.885, 2.5133,3.1416,3.7699,4.3982,5.0265,5.6549,6.2832];
and you want interplation of the test point.
When you sample some data to use them for interpolation you should consider how to sample data according to your requirements.
So when you are sampling a regular grid of polar coordinates ,those coordinates when converted to rectangular will form a circular shape that
most of the points are concentrated in the center of the cricle and when we move from the center to outer regions distance between the points increased.
%regular grid generated for r and t
[THETA R] = meshgrid(t ,r);
% Z for polar grid
Z=z2(R,THETA);
%convert coordinate from polar to cartesian(rectangular):
[X, Y] = pol2cart (THETA, R);
%plot points
plot(X, Y, 'k.');
axis equal
So when you use those point for interpolation the accuracy of the interpolation is greater in the center and lower in the outer regions where the distance between points increased.
In the other word with this sampling method you place more importance on the center region related to outer ones.
To increase accuracy density of grid points (r and theta) should be increased so if length of r and theta is 11 you can create r and theta with size 20 to increase accuracy.
In the other hand if you create a regular grid in rectangular coordinates an equal importance is given to each region . So accuracy of the interpolation will be the same in all regions.
For it first you create a regular grid in the polar coordinates then convert the grid to rectangular coordinates so you can calculate the extents (min max) of the sampling points in the rectangular coordinates. Based on this extents you can create a regular grid in the rectangular coordinates
Regular grid of rectangular coordinates then converted to polar coordinated to get z for grid points using z2 formula.
%get the extent of points
extentX = [min(X(:)) max(X(:))];
extentY = [min(Y(:)) max(Y(:))];
%sample 100 points(or more or less) inside a region specified be the extents
X_samples = linspace(extentX(1),extentX(2),100);
Y_samples = linspace(extentY(1),extentY(2),100);
%create regular grid in rectangular coordinates
[XX YY] = meshgrid(X_samples, Y_samples);
[TT RR] = cart2pol(XX,YY);
Z_rect = z2(RR,TT);
For interpolation of a test point say [ri ti] first it converted to rectangular then using XX ,YY value of z is interpolated
[xi yi] = pol2cart (ti, ri);
z=interp2(XX,YY,Z_rect,xi,yi);
If you have no choice to change how you sample the data and only have a grid of polar points as discussed with #RodyOldenhuis you can do the following:
Interpolate polar coordinates with interp2 (interpolation for gridded data)
this approach is straightforward but has the shortcoming that r and theta are not of the same scale and this may affect the accuracy of the interpolation.
z = interp2(THETA, R, Z, ti, ri)
convert polar coordinates to rectangular and then apply an interpolation method that is for scattered data.
this approach requires more computations but result of it is more reliable.
MATLAB has griddata function that given scattered points first generates a triangulation of points and then creates a regular grid on top of the triangles and interpolates values of grid points.
So if you want to interpolate value of point [ri ti] you should then apply a second interpolation to get value of the point from the interpolated grid.
With the help of some information from spatialanalysisonline and Wikipedia linear interpolation based on triangulation calculated this way (tested in Octave. In newer versions of MATLAB use of triangulation and pointLocation recommended instead of delaunay and tsearch ):
ri=0.53224;
ti = pi/8;
[THETA R] = meshgrid(t ,r);
[X, Y] = pol2cart (THETA, R);
[xi yi] = pol2cart (ti, ri);
%generate triangulation
tri = delaunay (X, Y);
%find the triangle that contains the test point
idx = tsearch (X, Y, tri, xi, yi);
pts= tri(idx,:);
%create a matrix that repesents equation of a plane (triangle) given its 3 points
m=[X(pts);Y(pts);Z(pts);ones(1,3)].';
%calculate z based on det(m)=0;
z= (-xi*det(m(:,2:end)) + yi*det([m(:,1) m(:,3:end)]) + det(m(:,1:end-1)))/det([m(:,1:2) m(:,end)]);
More refinement:
Since it is known that the search point is surrounded by 4 points we can use only those point for triangulation. these points form a trapezoid. Each diagonal of trapezoid forms two triangles so using vertices of the trapezoid we can form 4 triangles, also a point inside a trapezoid can lie in at least 2 triangles.
the previous method based on triangulation only uses information from one triangle but here z of the test point can be interpolated two times from data of two triangles and the calculated z values can be averaged to get a better approximation.
%find 4 points surrounding the test point
ft= find(t<=ti,1,'last');
fr= find(cos(abs(diff(t(ft+(0:1))))/2) .* r < ri,1,'last');
[T4 R4] = meshgrid(t(ft+(0:1)), r(fr+(0:1)));
[X4, Y4] = pol2cart (T4, R4);
Z4 = Z(fr+(0:1),ft+(0:1));
%form 4 triangles
tri2= nchoosek(1:4,3);
%empty vector of z values that will be interpolated from 4 triangles
zv = NaN(4,1);
for h = 1:4
pts = tri2(h,:);
% test if the point lies in the triangle
if ~isnan(tsearch(X4(:),Y4(:),pts,xi,yi))
m=[X4(pts) ;Y4(pts) ;Z4(pts); [1 1 1]].';
zv(h)= (-xi*det(m(:,2:end)) + yi*det([m(:,1) m(:,3:end)]) + det(m(:,1:end-1)))/det([m(:,1:2) m(:,end)]);
end
end
z= mean(zv(~isnan(zv)))
Result:
True z:
(0.0069246)
Linear Interpolation of (Gridded) Polar Coordinates :
(0.0085741)
Linear Interpolation with Triangulation of Rectangular Coordinates:
(0.0073774 or 0.0060992) based on triangulation
Linear Interpolation with Triangulation of Rectangular Coordinates(average):
(0.0067383)
Conclusion:
Result of interpolation related to structure of original data and the sampling method. If the sampling method matches pattern of original data result of interpolation is more accurate, so in cases that grid points of polar coordinates follow pattern of data result of interpolation of regular polar coordinate can be more reliable. But if regular polar coordinates do not match the structure of data or structure of data is such as an irregular terrain, method of interpolation based on triangulation can better represent the data.
please check this example, i used two for loops, inside for loop i used condition statement, if u comment this condition statement and run the program, u'll get correct answer, after u uncomment this condition statement and run the program, u'll get wrong answer. please check it.
% Coordinates
r = linspace(0.05, 1, 10);
t = linspace(0, 2*pi, 8);
% Some synthetic data
%z = sort(rand(50, 24));
z=zeros();
for i=1:10
for j=1:8
if r(i)<0.5||r(i)>1
z(i,j)=0;
else
z(i,j) = r(i).^3'*cos(t(j)/2);
end
end
end
% Values of interest
ri = 0.55;
ti = pi/8;
% Manually interpolate
rp = find(ri <= r, 1, 'first');
rm = find(ri >= r, 1, 'last');
tp = find(ti <= t, 1, 'first');
tm = find(ti >= t, 1, 'last');
drdt = (r(rp) - r(rm)) * (t(tp) - t(tm));
dr = [r(rp)-ri ri-r(rm)];
dt = [t(tp)-ti ti-t(tm)];
fZ = [z(rm, tm) z(rm, tp)
z(rp, tm) z(rp, tp)];
ZI_manual = (dr * fZ * dt.') / drdt
% Interpolate with MATLAB
ZI_MATLAB = interp2(r, t, z', ri, ti, 'linear')
Result:
z1 =
0.1632
ZI_manual =
0.1543
ZI_MATLAB =
0.1582

Generating cylindery symmetric 3D data by revolution of a 2d plane around one axis

Following a previous question that was asked, I wanted to create a 3d volume, i,e, f(x,y,z), starting from a 2D matrix I(x,y) and not just a curve.
For example, assume I=peaks(10), how can I revolve it around one of the axes (say the y-axis), to get a 3D matrix? Will it be easier if I instead have I(r,theta)?
I can rotate a plane in 3D, but this will not be part of a 3D matrix, just new x,y,z coordinates.
I think it's pretty straightforward to check the indices of your expected 3d array, find geometrically which I(x,y) value they correspond to (yes, essentially with a Cartesian to cylindrical transformation), then filling up each value as necessary.
Here's a minimal version of what I mean. It is assumed that the input array of size [N,N] corresponds to coordinates x, y in 0:N-1. The input array is assumed to be oriented along the xz plane, and it is rotated about the z axis in order to generate the output array V. The dimensions of V thus correspond to -(N-1):N-1 along x and y, and 0:N-1 along z. Thus the dimensions of V are [2*N-1, 2*N-1, N].
Demonstrating two approaches (using griddata and interp2, respectively), complete with plotting for reproducibility:
% size of the problem
N = 10;
% input data
I = peaks(N);
% two sets of output V for two methods
V1 = zeros(2*N-1,2*N-1,N);
V2 = zeros(2*N-1,2*N-1,N);
[i1,i2,i3] = ndgrid(1:2*N-1,1:2*N-1,1:N);
% [i1(:), i2(:), i3(:)] are the contiguous indices of V
% z dimension is the same as of I: rotate around z axis
% it will be assumed that input 1:N span elements from 0 to N-1
% output V spans -(N-1):N-1 along x and y
x = i1-N; % -(N-1):N-1
y = i2-N; % -(N-1):N-1
z = i3-1; % 0:N-1
% input array I is in xz plane, rotated along z axis, geometrically speaking
% identify the cylindrical coordinates of each voxel [i1,i2,i3]
[~,r_out,z_out] = cart2pol(x,y,z); % theta is redundant; z_out===z
% identify the coordinates of each input pixel with the above
[j1,j2] = meshgrid(1:N,1:N);
r_in = j1-1; % Cartesian input x <-> cylindrical output r
z_in = j2-1; % Cartesian input y <-> cylindrical output z
% note that j1 and j2 are swapped with respect to x and y
% but this is what interp2 will expect later
% interpolate each voxel based on r and z
method = 'nearest'; %probably the least biased
%method = 'cubic'; %probably the prettiest
V1(:) = griddata(r_in,z_in,I,...
r_out(:),z_out(:),method);
V2(:) = interp2(r_in,z_in,I,...
r_out(:),z_out(:),method,...
0); % extrapolation value, otherwise NaNs appear outside
% plot two slices: xz plane and general rotated one
figure;
% generate rotated versions of the xz plane by rotating with phi around z
for phi=[0, -25, -90]/180*pi
[xp0,zp] = meshgrid(-(N-1):0.1:N-1,0:0.1:N-1);
xp = xp0*cos(phi);
yp = xp0*sin(phi);
subplot(121);
slice(y,x,z,V1,xp,yp,zp);
title('griddata nearest');
shading flat;
axis equal vis3d;
hold on;
subplot(122);
slice(y,x,z,V2,xp,yp,zp);
title('interp2 nearest, extrap 0');
shading flat;
axis equal vis3d;
hold on;
end
As you can see, slice directly plots the data in V, so this is an accurate representation of the resulting 3d array.
For reference, here is a single specimen of the input I = peaks(10):

Matlab:Make a contour plot with 3 vectors

I have 3 vectors of data, X (position), Y (position) both of which are not regularly spaced, and Z(value of interest at each location). I tried contourf, which doesn't work because it needs a matrix for Z input.
You can also use griddata.
%Generate random data
x = rand(30,1);
y = rand(30,1);
z = rand(30,1);
%Create regular grid across data space
[X,Y] = meshgrid(linspace(min(x),max(x),n), linspace(min(y),max(y),n))
%create contour plot
contour(X,Y,griddata(x,y,z,X,Y))
%mark original data points
hold on;scatter(x,y,'o');hold off
For a contour plot you actually need either a matrix of z values, or a set (vector) of z-values evaluated on a grid. You cannot define contours using isolated Z values at (X,Y) points on the grid (i.e. what you claim you have).
You need to have the generating process (or function) provide values for a grid of (x,y) points.
If not, then you can create a surface from nonuniform data as #nate correctly pointed out, and then draw the contours on that surface.
Consider the following (random) example:
N = 64; % point set
x = -2 + 4*rand(N,1); % random x vector in[-2,2]
y = -2 + 4*rand(N,1); % random y vector in[-2,2]
% analytic function, or z-vector
z = x.*exp(-x.^2-y.^2);
% construct the interpolant function
F = TriScatteredInterp(x,y,z);
t = -2:.25:2; % sample uniformly the surface for matrices (qx, qy, qz)
[qx, qy] = meshgrid(t, t);
qz = F(qx, qy);
contour(qx, qy, qz); hold on;
plot(x,y,'bo'); hold off
The circles correspond to the original vector points with values (x,y,z) per point, the contours on the contours of the interpolant surface.

Texture mapping in MATLAB

I have points in 3D space and their corresponding 2D image points. How can I make a mesh out of the 3D points, then texture the triangle faces formed by the mesh?
Note that the function trisurf that you were originally trying to use returns a handle to a patch object. If you look at the 'FaceColor' property for patch objects, you can see that there is no 'texturemap' option. That option is only valid for the 'FaceColor' property of surface objects. You will therefore have to find a way to plot your triangular surface as a surface object instead of a patch object. Here are two ways to approach this:
If your data is in a uniform grid...
If the coordinates of your surface data represent a uniform grid such that z is a rectangular set of points that span from xmin to xmax in the x-axis and ymin to ymax in the y-axis, you can plot it using surf instead of trisurf:
Z = ... % N-by-M matrix of data
x = linspace(xmin, xmax, size(Z, 2)); % x-coordinates for columns of Z
y = linspace(ymin, ymax, size(Z, 1)); % y-coordinates for rows of Z
[X, Y] = meshgrid(x, y); % Create meshes for x and y
C = imread('image1.jpg'); % Load RGB image
h = surf(X, Y, Z, flipdim(C, 1), ... % Plot surface (flips rows of C, if needed)
'FaceColor', 'texturemap', ...
'EdgeColor', 'none');
axis equal
In order to illustrate the results of the above code, I initialized the data as Z = peaks;, used the built-in sample image 'peppers.png', and set the x and y values to span from 1 to 16. This resulted in the following texture-mapped surface:
If your data is non-uniformly spaced...
If your data are not regularly spaced, you can create a set of regularly-spaced X and Y coordinates (as I did above using meshgrid) and then use one of the functions griddata or TriScatteredInterp to interpolate a regular grid of Z values from your irregular set of z values. I discuss how to use these two functions in my answer to another SO question. Here's a refined version of the code you posted using TriScatteredInterp (Note: as of R2013a scatteredInterpolant is the recommended alternative):
x = ... % Scattered x data
y = ... % Scattered y data
z = ... % Scattered z data
xmin = min(x);
xmax = max(x);
ymin = min(y);
ymax = max(y);
F = TriScatteredInterp(x(:), y(:), z(:)); % Create interpolant
N = 50; % Number of y values in uniform grid
M = 50; % Number of x values in uniform grid
xu = linspace(xmin, xmax, M); % Uniform x-coordinates
yu = linspace(ymin, ymax, N); % Uniform y-coordinates
[X, Y] = meshgrid(xu, yu); % Create meshes for xu and yu
Z = F(X, Y); % Evaluate interpolant (N-by-M matrix)
C = imread('image1.jpg'); % Load RGB image
h = surf(X, Y, Z, flipdim(C, 1), ... % Plot surface
'FaceColor', 'texturemap', ...
'EdgeColor', 'none');
axis equal
In this case, you have to first choose the values of N and M for the size of your matrix Z. In order to illustrate the results of the above code, I initialized the data for x, y, and z as follows and used the built-in sample image 'peppers.png':
x = rand(1, 100)-0.5; % 100 random values in the range -0.5 to 0.5
y = rand(1, 100)-0.5; % 100 random values in the range -0.5 to 0.5
z = exp(-(x.^2+y.^2)./0.125); % Values from a 2-D Gaussian distribution
This resulted in the following texture-mapped surface:
Notice that there are jagged edges near the corners of the surface. These are places where there were too few points for TriScatteredInterp to adequately fit an interpolated surface. The Z values at these points are therefore nan, resulting in the surface point not being plotted.
If your texture is already in the proper geometry you can just use regular old texture mapping.
The link to the MathWorks documentation of texture mapping:
http://www.mathworks.com/access/helpdesk/help/techdoc/visualize/f0-18164.html#f0-9250
Re-EDIT: Updated the code a little:
Try this approach (I just got it to work).
a=imread('image.jpg');
b=double(a)/255;
[x,y,z]=peaks(30); %# This is a surface maker that you do have
%# The matrix [x,y,z] is the representation of the surface.
surf(x,y,z,b,'FaceColor','texturemap') %# Try this with any image and you
%# should see a pretty explanatory
%# result. (Just copy and paste) ;)
So [x,y,z] is the 'surface' or rather a matrix containing a number of points in the form (x,y,z) that are on the surface. Notice that the image is stretched to fit the surface.