This is probably very basic matlab, so forgive me.
I use the command sphere to create a 3D sphere and have the x,y,z matrices that will produce it using surf. For example:
[x,y,z]=sphere(64);
I'd like to project (or sum) this 3D sphere into one of the Cartesian 2D planes (for example X-Y plane) to obtain a 2D matrix that will be the projection of that sphere. Using imshow or imagesc on the output should look something like this:
simple summing obviously doesn't work, how can I accomplish that in Matlab?
It is possible that I completely misunderstand your question, in which case I apologize; but I think one of the following three methods may in fact be what you need. Note that method 3 gives an image that looks a lot like the example you provided... but I got there with a very different route (not using the sphere command at all, but computing "voxels inside" and "voxels outside" by working directly with their distance from the center). I inverted the second image compared to the third on since it looked better that way - filling the sphere with zeros made it look almost like a black disk.
%% method 1: find the coordinates, and histogram them
[x y z]=sphere(200);
xv = linspace(-1,1,40);
[xh xc]=histc(x(:), xv);
[yh yc]=histc(y(:), xv);
% sum the occurrences of coordinates using sparse:
sm = sparse(xc, yc, ones(size(xc)));
sf = full(sm);
figure;
subplot(1,3,1);
imagesc(sf); axis image; axis off
caxis([0 sf(19,19)]) % add some clipping
title 'projection of point density'
%% method 2: fill a sphere and add its volume elements:
xv = linspace(-1,1,100);
[xx yy zz]=meshgrid(xv,xv,xv);
rr = sqrt(xx.^2 + yy.^2 + zz.^2);
vol = zeros(numel(xv)*[1 1 1]);
vol(rr<1)=1;
proj = sum(vol,3);
subplot(1,3,2)
imagesc(proj); axis image; axis off; colormap gray
title 'projection of volume'
%% method 3: visualize just a thin shell:
vol2 = ones(numel(xv)*[1 1 1]);
vol2(rr<1) = 0;
vol2(rr<0.95)=1;
projShell = sum(vol2,3);
subplot(1,3,3);
imagesc(projShell); axis image; axis off; colormap gray
title 'projection of a shell'
You can project on the X-Y plane in Matlab by using:
[x,y,z] = sphere(64);
surf(x,y,zeros(size(z)));
But I think you should not use Matlab for this, because the problem is so simple you can do this analytically...
I would look at map projections, which are designed for this purpose.
A search on "map projections matlab" yields documentation on a Matlab mapping toolbox. However, if you want or need to roll your own, there is a good summary at the USGS website, as well as a wikipedia article.
Related
I'm trying to print out QR codes onto the surface of water bottles using matlab. However, the QR bottles cannot be recognized because of the curved surface of the bottle, and the therefore deformed shape of the QR codes.
I was wondering what mathematical equation I might have to apply to deform the picture (for both the general geometry of the picture, and the spacing deformation inside the picture), so that when printed onto a cylindrical surface, it seems like its on a flat surface to a camera.
Thanks!
I had some success with this and though it doesn't use Matlab, it may give you, or someone else an idea on a possible way to get started.
I generated a QR code with qrencode in Terminal like this:
qrencode -o qr.png -d 300 'http://www.thesetchells.com'
I resized that to 500x500 and then generated a "displacement map" which is just a linear gradient with a contrast stretch created to match the size of the QR code. I used ImageMagick in Terminal, but obviously you can use Matlab or other tools:
I then applied the displacement map to my QR code like this:
convert qr.png map.png -fx 'p{v*w,j}' result.png
And got a distorted QR code, which I printed and wrapped round a large bottle and my iPhone was able to read it.
Anthony Thyssen has some very useful information on "displacement maps" here.
So I've tried an approach to my problem using the basic "car.jpg" image included in Matlab.
So far, I've taken a square part of the car picture, and wrapped it around the surface of part of a cylinder.
Here is my code:
close all, clf, clear all
%% Creating cylinder
r = 6; %centimeter
h = 25; %centimeter
[X,Y,Z] = cylinder(r,100);
x = X(:,1:ceil(length(X)/3));
y = Y(:,1:ceil(length(Y)/3));
z = Z(:,1:ceil(length(Z)/3));
%% Plotting cylinder surface
figure(1), clf
h = surf(x,y,z); hold on
axis([-r r -r r]*2.2)
plot3([-r -r], get(gca,'ylim'), [0 0]);
plot3([r r], get(gca,'ylim'), [0 0]);
plot3(get(gca,'xlim'), [-r -r], [0 0]);
plot3(get(gca,'xlim'), [r r], [0 0]);
xlabel('x');
ylabel('y');
zlabel('z');
rotate3d on
axis vis3d
%% Car image
img = imread('car.jpg');
img = imrotate(img,180);
figure(2), clf
%imshow(img(1:340, 1:340, :));
imagesc(img(1:340, 1:340, :));
figure(), clf
warped_plot = warp(x,y,z,img(1:340, 1:340, :))
The next step could be to now project that warped image onto a flat surface (but I'm not sure how to do that mathematically, nor have I found a in-built Matlab function to do this).
Another possibility I was hoping to get feedback on, is to find a mathematical relation between corresponding horizontal points on the flat and cylindrical image, and then to apply the inverse of that equation to the flat image, so that once it is printed out and stuck onto a cylindrical surface it appears flat.
I am currently trying to plot 3D streamtubes. I want the tubes to be colored corresponding to their respective velocity (e.g. slow = blue, fast = red).
To be more exact, I have three 3D-matrices containing the velocity in x, y and z direction. The color of the streamtubes should be sqrt(vx^2+vy^2+vz^2). When using streamtube(x,y,z,vx,vy,vz,sx,sy,sz) the tubes are colored according to their z-coordinate which is useless because it's a 3D plot anyway.
Well this wasn't easy (it ought to be a builtin option), but by modifying the CData of each tube (they are each their own graphics object), you can achieve the desired result. Here's an example
load wind
[sx,sy,sz] = meshgrid(80,20:10:50,0:5:15);
h=streamtube(x,y,z,u,v,w,sx,sy,sz);
drawnow
view(3)
axis tight
shading interp;
This gives this picture:
but then doing this:
vel=sqrt(u.^2+v.^2+w.^2); %// calculate velocities
for i=1:length(h)
%// Modify the colour data of each tube
set(h(i),'CData',interp3(x,y,z,vel,get(h(i),'XData')...
,get(h(i),'YData'),get(h(i),'ZData'),'spline'))
end
drawnow
view(3)
axis tight
shading interp;
gives this result
NOTES:
1) I don't know if this is fully correct, I don't know how to test it
2) You have to interpolate the velocity data from the points where it's known onto the vertices of the streamtubes
3) I found the spline interpolation option to work best, but the other options might work better in other cases
I need to ask help in plotting a 3D volume in MATLAB. My data set includes the X, Y, Z coordinate and corresponding intensity value, V.
I was using pcolor (X,Y,V) and shading interp while i was doing the 2D images but then I got stuck when I am about to create the 3D images. I have tried scatter3, smooth3 and slice but it seems it does not fit the function I need.
My goal is to plot the 3D grid with the corresponding intensity value per coordinate and apply shading interp between these points.
I am really new in 3D plotting and I would really appreciate any help in achieving my goal. Thank you so much!
Here are some example of images that I am trying to create
(source: ndt.net)
(source: www.bam.de)
I have a solution for your first example, in which you show three cross-sections of the volume data. With this solution you can essentially plot several pcolor with different orientations, in one same 3D figure.
First, you need the data for the different slices. This is exactly what you had when you did pcolor(X,Y,V) to plot the cross section in 2D, where X, Y and V are two dimensional matrices. You will also need to create a matrix Z with the z-position of the slice (e.g. Z = zeros(size(X)) + z0). Then you use the command surface(X,Y,Z,V) to plot the cross section image in 3D, where X,Y,Z are the positions, and V is the color (value of the function).
Repeat this procedure for all the other slices, using appropriate X,Y,Z,V matrices for each slice. For slices oriented on other axes you will have to define X,Y,Z accordingly. Remember to use "hold on" after the first surface command, so that all the slices are plotted.
Example:
surface(X1,Y1,Z1,V1); shading interp; hold on
surface(X2,Y2,Z2,V2); shading interp;
surface(X3,Y3,Z3,V3); shading interp;
colormap(jet(2048)); caxis([0,3]); % color axis colormap and scaling
axis equal; xlabel('X'); ylabel('Y'); zlabel('Z') % X,Y,Z scaling and label
Result figure here:
Hi can any one give me a simple example of how to use the isosurface function in MATLAB.
The example given if you type help isosurface is quite confusing. Searching on google did not help as no one gives simple examples anywhere. All of them use predefined functions like
flow.
For starters, suppose i have points (x,y,z) where z=0 and at each point I define a constant
function f(x,y,z)=6. So if I use the isosurface function on the isovalue 6 I would like MATLAB to give me a 3d plot with the XY plane highlighted in some colour, say green.
I don't quite understand your example, but here's how you use isosurface to draw a sphere:
%# create coordinates
[xx,yy,zz] = meshgrid(-15:15,-15:15,-15:15);
%# calculate distance from center of the cube
rr = sqrt(xx.^2 + yy.^2 + zz.^2);
%# create the isosurface by thresholding at a iso-value of 10
isosurface(xx,yy,zz,rr,10);
%# make sure it will look like a sphere
axis equal
The example you gave is very uninteresting, in fact maybe even problematic.
By collapsing all points to z=0, you no longer can/need to use ISOSURFACE, and CONTOUR should be called instead. Even then, a constant function f(X,Y)=6 won't show anything either...
Since #Jonas already showed how to use ISOSURFACE, here is an example for the CONTOUR function:
%# create a function to apply to all X/Y coordinates
[X,Y] = meshgrid(-2:0.1:2,-1:0.1:1);
f = #(X,Y) X.^3 -2*Y.^2 -3*X;
%# plot the function surface
subplot(121), surfc(X,Y,f(X,Y))
axis equal, daspect([1 1 3])
%# plot the iso-contour corresponding to where f=-1
subplot(122), contour(X,Y,f(X,Y),[-1 -1]),
axis square, title('Contour where f(X,Y)=-1')
I know I can create a 3D surface plot in MATLAB by doing:
x = linspace(1,10,100);
y = linspace(10,20,100);
[X Y] = meshgrid(x,y);
Z = X * Y;
surf(X,Y,Z);
But this requires that all the nodes for the height map generated line up. I have a set of data which has arbitrary points (x,y) and a height (z). Is there a simple way to plot a graph which will generate a surface between the points in a similar fashion to surf?
Appologies, after some hunting I managed to answer my own question:
You can use the trisurf function:
tri = delaunay(x,y);
trisurf(tri,x,y,z);
If you have dense data you will want to do shading interp (or another value, check doc shading) so you don't get a black blob due to the grid.
It looks like you've found your answer by using DELAUNAY and TRISURF to generate and plot a triangulated surface.
As an alternative, you could also fit a regularly-spaced grid to your nonuniformly-spaced points in order to generate a surface that can be plotted with the SURF command. I discuss how this can be done using the TriScatteredInterp class (or the deprecated function GRIDDATA) in my answer to this other question on SO.