Create 2D grid from vector data in Matlab - matlab

I am trying to create a 2-D grid from a vector.
So, for example I have:
x = 1:1:10;
z = 2:2:20;
Now, I want to create a grid which has x on both side of the grid cell and z as grid cell value.
I tried doing it as :
[X,Y] = meshgrid(x, x);
newZ = griddata(x, x ,z, X, Y);
But this gives me error:
The underlying triangulation is empty - the points may be
collinear.
Need help solving this.

In a high level, griddata() takes a 2d surface with variable z-value at each point as the first part of the input, and the query points as the second part of the input. To be more specific, when we look into the definition of the function:
vq = griddata(x,y,v,xq,yq)
x and y specifies the range of x and y values, v is like z-value in a plane, and xq and yq together are query points. Here, v (in your case, z) is expected to be a 2d matrix, to be more specific, the size of v is [length(x), length(y)], whereas in your case, you put z as a vector. Matlab generates the warning since the size doesn't match.
For your reference: http://www.mathworks.com/help/matlab/ref/griddata.html?refresh=true

Related

Calculating 3D affine transform and re-sampling a volume using that

I am trying to register two volumes(vol1 and vol2). The size of the vol1 is 40x40x24. The size of the vol2 is 64 x64x11.
So far, I have extracted their features and then matched them. Now, I have a set of corresponding points in two volumes that is stored in pairs which is a matrix of size 100x6 (every row of pairs is [x y z X Y Z] where (x,y,z) are the coordinates of a voxel in vol1 and [X Y Z] is the corresponding voxel in vol2). Then, using RANSAC algorithm, I have calculated the 3D affine transform, T. For example, T is something like below:
T=
2.7791 0.8204 0.7561 -61.6055
-0.4418 2.2663 -1.9882 29.0375
-0.2120 0.6568 -0.7041 6.2702
0 0 0 1.0000
I have a couple of questions. First, does this affine transformation matrix look correct? It looks correct to me. If it is correct then why the function affine3d in MATLAB which calculates the 3D affine transform has the column of zeroes instead of the row of zeroes (like in T above)? It looks like the transpose of my transform T.
If my transform is correct then another problem occurs. I tried to resample vol1 using transform T, but the calculated voxel coordinates are negative!!! I am so confused. I do not know what causes this problem.
Here, is my code. Please let me know if you see any problem with it.
function [ vol1R ] = resampling(vol1, vol2, T)
[size1, size2, size3] = size(vol2);
vol1R = zeros(size1,size2,size3); % Initializing registered vol1
for i= 1:size1
for j= 1:size2
for k = 1:size3
V = [i;j;k;1]; % V is the coordinates of a voxel on the registered vol1
% correspoding to voxel v on the vol1
% V = T * v : Relationship between v and V
v = T\V; % Problem occurs here!!!!!!! v has some negative values
% v (coordinates in vol1)
% continue
end
end
end
The format of your affine matrix looks fine if you are using it to operate on column vectors, as in [X; Y; Z; 1] = T*[x; y; z; 1]. The reason MATLAB's example is transposed is because it operates on 1x4 row vectors, as in [X, Y, Z, 1] = [x, y, z, 1]*(T').
As for the the actual numbers in the matrix, I can't comment since I don't know the original images. I do notice that there is an x-translation of -61.6055, which seems pretty big for the sizes of the images you have. Do you know for sure this is the right answer?
I'd suggest maybe starting with a simple pair of images where you know the answer beforehand (maybe white squares on a black background drawn in Paint) to confirm your registration algorithm gives the right answer.

How to integrate over a discrete 2D surface in MATLAB?

I have a function z = f(x, y), where z is the value at point (x, y). How may I integrate z over the x-y plane in MATLAB?
By function above, I actually mean I have something similar to a hash table. That is, given a (x, y) pair, I can look up the table to find the corresponding z value.
The problem would be rather simple, if the points were uniformly distributed over x-y plane, in which case I can simply sum up all the z values, multiply it with the bottom area, and finally divide it by the number of points I have. However, the distribution is not uniform as shown below. So I am actually asking for the computation method that minimises the error.
The currently accepted answer will only work for gridded data. If your data is scattered you can use the following approach instead:
scatteredInterpolant + integral2:
f = scatteredInterpolant(x(:), y(:), z(:), 'linear');
int = integral2(#(x,y) f(x,y), xmin, xmax, ymin, ymax);
This defines the linear interpolant f of the data z(i) = f(x(i),y(i)) and uses it as an argument to integral2. Note that ymin and ymax, instead of doubles, can be function handles depending on x. So usually you will be integrating rectangles, but this could be used for integration regions a bit more complicated.
If your integration area is rather complicated or has holes, you should consider triangulating your data.
DIY using triangulation:
Let's say your integration area is given by the triangulation trep, which for example could be obtained by trep = delaunayTriangulation(x(:), y(:)). If you have your values z corresponding to z(i) = f(trep.Points(i,1), trep.Points(i,2)), you can use the following integration routine. It computes the exact integral of the linear interpolant. This is done by evaluating the areas of all the triangles and then using these areas as weights for the midpoint(mean)-value on each triangle.
function int = integrateTriangulation(trep, z)
P = trep.Points; T = trep.ConnectivityList;
d21 = P(T(:,2),:)-P(T(:,1),:);
d31 = P(T(:,3),:)-P(T(:,1),:);
areas = abs(1/2*(d21(:,1).*d31(:,2)-d21(:,2).*d31(:,1)));
int = areas'*mean(z(T),2);
If you have a discrete dataset for which you have all the x and y values over which z is defined, then just obtain the Zdata matrix corresponding to those (x,y) pairs. Save this matrix, and then you can make it a continuous function using interp2:
function z_interp = fun(x,y)
z_interp = interp2(Xdata,Ydata,Zdata,x,y);
end
Then you can use integral2 to find the integral:
q = integral2(#fun,xmin,xmax,ymin,ymax)
where #fun is your function handle that takes in two inputs.
I had to integrate a biavariate normal distribution recently in MatLab. The idea is very simple. Matlab defines a surface through a meshgrid, so from x, y you need to do this:
x = -10:0.05:10;
y = x;
[X,Y] = meshgrid(x',y');
...for example. Then, let's call FX the function that defines the value at each point of the surface. To calculate the integral you just need to do this:
surfint = zeros(length(X),1);
for a = 1:length(X)
surfint(a,1) = trapz(x,FX(:,a));
end
trapz(x, surfint)
For me, this is the simplest way.

plotting three column variables in a 2D plane in matlab

I have a file with data arranged in three columns. I am trying to make 2D contour plot of these values, where the values in the third column (Z) is projected on the space formed by values in the first (X) and second column (Y). But usual matlab commands like 'contour' and 'imagesc' take the Z-values in the matrix format. Is there a way out in Matlab to plot these values in a 2D-plane?
Contour usually works with two vectors (X and Y) and a matrix (Z). So for each elements of the two vectors (X(i) , Y(i)), there should be a value in the matrix (Z(i,j)). Thus the size of the matrix Z should be equal to the size of the first vector (X) multiplied by the size of the second vector (Y).
if the x,y,z have the same size then you can do something like this:
[X,Y,Z] = meshgrid(x,y,z);
contour(X,Y,Z)
on the other hand if you manage to make the sizes correct then you can do something like this example:
x = linspace(-2*pi,2*pi);
y = linspace(0,4*pi);
[X,Y] = meshgrid(x,y);
Z = sin(X)+cos(Y);
figure
contour(X,Y,Z)

Matlab surface plot not giving desired results

I am charting the following data:
a=[...
0.1, 0.7, 0.00284643369242828;...
0.1, 0.71, 0.00284643369242828;...]
such that column 1 never surpasses approximately 10
also such that column 2 goes from .7 to 1.
Column 3 seems ok
When i chart my surface using surf(a) it looks like this:
it appears not to be properly considering what should be x and y.
anything seem weird there?
I think you need to try one of two things: either break out your height column into its own rectangular matrix Z and use surf(Z) to plot each point relative to its location in the matrix (so your x- and y-axes will not be scaled the way you want), or you can put your desired x- and y-coordinates in their own vectors, and plot the matrix Z (defined at every point (xi, yj) for all i in N and j in M where x is N elements long and y is M elements long) with surf(x,y,Z).
x = 0.1:0.1:10; % or whatever increment you need
y = 0.7:0.01:1; % or whatever increment you need
Z = zeros(length(x),length(y); % initialized to the correct size, fill with data
I think you are going to have to regenerate your Z-data so that it is in a rectangular matrix that is (elements in x) by (elements in y) in dimension.
EDIT: You do not need to recreate your data. If you know that you have n unique elements in x and m unique elements in y, then you can use:
X = reshape(data(:,1),m,n);
Y = reshape(data(:,2),m,n);
Z = reshape(data(:,3),m,n);
surf(X,Y,Z);
And that should give you what you are looking for.

Finding the belonging value of given point on a grid of 3D histogram?

I use 2D dataset like below,
37.0235000000000 18.4548000000000
28.4454000000000 15.7814000000000
34.6958000000000 20.9239000000000
26.0374000000000 17.1070000000000
27.1619000000000 17.6757000000000
28.4101000000000 15.9183000000000
33.7340000000000 17.1615000000000
34.7948000000000 18.2695000000000
34.5622000000000 19.3793000000000
36.2884000000000 18.4551000000000
26.1695000000000 16.8195000000000
26.2090000000000 14.2081000000000
26.0264000000000 21.8923000000000
35.8194000000000 18.4811000000000
to create a 3D histogram.
How can I find the histogram value of a point on a grid? For example, if [34.7948000000000 18.2695000000000] point is given, I would like to find the corresponding value of a histogram for a given point on the grid.
I used this code
point = feat_vec(i,:); // take the point given by the data set
X = centers{1}(1,:); // take center of the bins at one dimension
Y = centers{2}(1,:); // take center of the bins at other dim.
distanceX = abs(X-point(1)); // find distance to all bin centers at one dimension
distanceY = abs(Y-point(2)); // find distance to center points of other dimension
[~,indexX] = min(distanceX); // find the index of minimum distant center point
[~,indexY] = min(distanceY); // find the index of minimum distant center point for other dimension
You could use interp2 to accomplish that!
If X (1-D Vector, length N) and Y (1-D vector, length M) determine discrete coordinate on the axes where your histogram has defined values Z (matrix, size M x N). Getting value for one particular point with coordinates (XI, YI) could be done with:
% generate grid
[XM, YM] = meshgrid(X, Y);
% interpolate desired value
ZI = interp2(XM, YM, Z, XI, YI, 'spline')
In general, this kind of problem is interpolation problem. If you would want to get values for multiple points, you would have to generate grid for them in similar fashion done in code above. You could also use another interpolating method, for example linear (refer to linked documentation!)
I think you mean this:
[N,C] = hist3(X,...) returns the positions of the bin centers in a
1-by-2 cell array of numeric vectors, and does not plot the histogram.
That being said, if you have a 2D point x=[x1, x2], you are only to look up the closest points in C, and take the corresponding value in N.
In Matlab code:
[N, C] = hist3(data); % with your data format...
[~,indX] = min(abs(C{1}-x(1)));
[~,indY] = min(abs(C{2}-x(2)));
result = N(indX,indY);
done. (You can make it into your own function say result = hist_val(data, x).)
EDIT:
I just saw, that my answer in essence is just a more detailed version of #Erogol's answer.