Show an image in a MATLAB 3D surface plot with a separate colormap

The surface / surf plot in MATLAB can visualize data in 3D. When I took a course in grad school on statistical image processing, I saw a very interesting plot where data is shown as a surf plot and underneath, on the ground or x-y plane, an image is shown. The pixels of the image corresponded to the points in the 3D surface and gave some extra information about the each point, sort of like an image-based version of surfc or a 3D version of plotting over an image background. I always wanted to know how to make that plot but rather than asking the prof who made it (as one is supposed to after paying tuition), I decided to figure it out on my own (thus proving why I was never good at accounting). It took some experimentation but I finally figured out how this type of plot is accomplished. In this tutorial, I will show how to do this and how to make it so that the surface plot and the image can use different colormaps, getting around the restriction that MATLAB only has one colormap per figure. In effect, this will simulate multiple colormaps. The result will look something like this:

Image shown as a texture mapped plane in a MATLAB 3D surface plot

Note how the image is mapped to a plane and is shown with a jet colormap while the 3d surf is shown with a gray colormap.

Basic way to show an image on the same axes as a 3D surface

I will first go through the basic way to do this without multiple colormap support. Take a look at this code:

% the data that you want to plot as a 3D surface.
[x,y,z] = peaks;
 
% get the corners of the domain in which the data occurs.
min_x = min(min(x));
min_y = min(min(y));
max_x = max(max(x));
max_y = max(max(y));
 
% the image data you want to show as a plane.
planeimg = abs(z);
 
% set hold on so we can show multiple plots / surfs in the figure.
figure; hold on;
 
% do a normal surface plot.
surf(x,y,z);
 
% set a colormap (but this has no effect because the next colormap
% command overwrites it)
colormap(gray);
 
% desired z position of the image plane.
imgzposition = -10;
 
% plot the image plane using surf.
surf([min_x max_x],[min_y max_y],repmat(imgzposition, [2 2]),...
    planeimg,'facecolor','texture')
 
% set a colormap for the figure.
colormap(jet);
 
% set the view angle.
view(45,30);
 
% labels
 
xlabel('x');
ylabel('y');
zlabel('z');

The above code will produce this plot:

Image shown as a texture mapped plane in a MATLAB 3D surface plot

I first created the 3D data to be plotted by making use of the peaks function. Next, I found the domain of the data (extent in the x-y plane). This is used to define the plane that the image will be mapped to in the final plot. The image to be shown is stored in planeimg (in this case I simply used abs(z) but the image can any arbitrarily sized array of data - it will be stretched or squeezed to fit the plane defined by the extent of the domain of the data). I then plotted the 3D data by calling surf. Finally, the image is mapped to a plane parallel to the x-y plane by the following lines:

% desired z position of the image plane.
imgzposition = -10;
 
% plot the image plane using surf.
surf([min_x max_x],[min_y max_y],repmat(imgzposition, [2 2]),...
    planeimg,'facecolor','texture')
 

imgzposition sets where on the z axis the image plane is to be placed; I set -10 so it would not intersect with the existing 3D surface. The surf command here has defined a planar surface with the following vertices:

(min_x, min_y, imgzposition)

(max_x, min_y, imgzposition)

(max_x, max_y, imgzposition)

(min_x, max_y, imgzposition)

To understand how this works, refer to MATLAB's surf documentation, which states:

surf(X,Y,Z) creates a shaded surface using Z for the color data as well as surface height. X and Y are vectors or matrices defining the x and y components of a surface. If X and Y are vectors, length(X) = n and length(Y) = m, where [m,n] = size(Z). In this case, the vertices of the surface faces are (X(j), Y(i), Z(i,j)) triples.

In any case, the planeimg is used as a texture map for the single face of the planar surface.

You will have noticed that I actually have two colormap commands in the code, but both the 3D surface and the image have the same colormap. This is because there is only one colormap for the figure. The next section will discuss how to get around this and use a different colormap for the 3D surface and the image plane.

Show the image with a different colormap by faking multiple colormaps

To give the image a different colormap than the 3D surface, all I need to do is convert the image (which is just a 2D array of values) into a true color image according to the desired colormap. This is how:

% scale the between [0, 255] in order to use a custom color map for it.
minplaneimg = min(min(planeimg)); % find minimum first.
scaledimg = (floor(((planeimg - minplaneimg) ./ ...
    (max(max(planeimg)) - minplaneimg)) * 255)); % perform scaling
 
% convert the image to a true color image with the jet colormap.
colorimg = ind2rgb(scaledimg,jet(256));

Due to the way colormap and ind2rgb work, the image must first be scaled to between [0, 255] before being converted to true color. I also have to specify a 256 element colormap (since [0, 255] has 256 possible values).

Now all we have to do is instead of showing planeimg, we show colorimg instead:

% plot the image plane using surf.
surf([min_x max_x],[min_y max_y],repmat(imgzposition, [2 2]),...
    colorimg,'facecolor','texture')

This will produce a figure very similar to the one at the beginning of this tutorial. If you want to get rid of the wireframe mesh (as I did), then simply specify 'edgecolor' to be 'none' in your surf commands:

surf(x,y,z,'edgecolor','none');

Complete code snippet

Here it is altogether:

% the data that you want to plot as a 3D surface.
[x,y,z] = peaks;
 
% get the corners of the domain in which the data occurs.
min_x = min(min(x));
min_y = min(min(y));
max_x = max(max(x));
max_y = max(max(y));
 
% the image data you want to show as a plane.
planeimg = abs(z);
 
% scale image between [0, 255] in order to use a custom color map for it.
minplaneimg = min(min(planeimg)); % find the minimum
scaledimg = (floor(((planeimg - minplaneimg) ./ ...
    (max(max(planeimg)) - minplaneimg)) * 255)); % perform scaling
 
% convert the image to a true color image with the jet colormap.
colorimg = ind2rgb(scaledimg,jet(256));
 
% set hold on so we can show multiple plots / surfs in the figure.
figure; hold on;
 
% do a normal surface plot.
surf(x,y,z,'edgecolor','none');
 
% set a colormap for the surface
colormap(gray);
 
% desired z position of the image plane.
imgzposition = -10;
 
% plot the image plane using surf.
surf([min_x max_x],[min_y max_y],repmat(imgzposition, [2 2]),...
    colorimg,'facecolor','texture')
 
% set the view.
view(45,30);
 
% label the axes
xlabel('x');
ylabel('y');
zlabel('z');

This will produce the figure shown at the beginning of the tutorial:

Image shown as a texture mapped plane in a MATLAB 3D surface plot

Discussion

Ben, 2010/10/12 13:31
Thanks!!! Very detailed and helpful.
Daniel, 2011/03/17 16:06
Thanks!
I used it to combine eye-tracking data with the picture which was watched.
But I have problems exporting it from MatLab. "saveas" and "print" just export the surf but not the picture.
Did anybody try this?
Peter Yu, 2011/03/18 01:43
The saveas command works for me in various formats:

% png
saveas(gcf, 'output.png');

% pdf
saveas(gcf, 'output.pdf');

An alternative to try if saveas is somehow messed up is to use getframe to capture the current figure as an image and then write it out using imwrite:

c = getframe(gcf);
imwrite(c.cdata, 'output.png');
Daniel, 2011/03/26 20:06
Thanks again!
Now it works. I used the same command before but it didn't work.
Maybe there was an error in my script...
damris, 2011/06/07 06:12
i want create our face image to 3d image.in matlab please help me
suganya.s, 2011/07/13 06:20
sir,
this is very useful for us......i need one help.I need matlab coding for 3d image
Yathindra, 2011/07/27 17:43
I need help for this.

How to mark different points in different surface plots;
Peter Yu, 2011/07/30 02:01
Everyone - Please don't ask me vague questions that contain no details about what you want to do. Ask your TA, your prof or tech support if you are that lost.
Anne , 2011/08/11 10:08
Thanks, your descriptions are very detailed and helpful.
I have just used surface plot and found all my labels (titles, legend, tick-marks...) upside down and mirrored (i.e. if you want to read them correctly you would have to stand on your head behind the screen). Has anyone ever seen anything like this? Why does it happen, and how do I fix it?
Peter Yu, 2011/08/11 22:18
Anne - I haven't encountered that before. It might be a graphics card issue? e.g.

http://www.mathworks.com/matlabcentral/newsreader/view_thread/243468
rohit chikkaraddy, 2011/10/29 16:55
Thanks!
I was wondering, how to manipulate the code, if one want to do a 3D surface plot for some image that one has?
Can you please help he out of this?
anitha, 2011/12/13 07:54
this thread was useful but i would like to know if we could create a 3d image from two 2d images.. can u pls suggest any ways??
hari, 2012/02/16 14:13
this thread helped me in my project.i would like to know more about 2d image conversion into 3d using matlab.and the coding related to that.will you please help me?
Isai, 2012/06/22 11:48
Hi, thanks for a very detailed explanation. I have just one question:

I want to give the flat surface plot a grid-like appeareance (such as the one from the 3D surface). I have tried with the commands MeshStyle (both), LineStyle (-,--), and FaceColor (flat, interp). None of these commands gave me the desired result. Actually, changing the value for FaceColor made the flat surface plot dissapear (Matlab gave the following comment: Warning: size(CData) must equal size(ZData) or size(ZData)-1 for flat shading).

Do you have any suggestions for this task?

Thanks in advance.
Peter Yu, 2012/06/22 17:49
I haven't tried this but you should be able to use a texture mapped surface:

http://www.mathworks.com/help/techdoc/ref/surface.html#f67-521436

Instead of using the peaks function as in that example, you should be able to create a flat grid surface.
Fariha, 2012/12/13 14:25
Hi, thanks for a very detailed explanation. I have one question:

if i want to make this plot for a FMRI image then what should i do?

Do you have any suggestions for this task?

Thanks in advance.
Amir Beigzadeh, 2013/02/22 11:16
Dear sirs/madam

please note that as an academic project we have decided to chenge a 2D image of face to a 3D image to machinhig by CNC through matlab software.kindly sbmit your comment or references that can help us in this project.
surbhi, 2013/07/15 10:22
Dear sir/Madam,

can you help to plot an mirror image of an object using MATLAB.
Quentin, 2013/08/21 21:51
Very usefull, thank you very much.
c.c.j, 2013/12/16 06:23
thanks,it is very useful
zahra, 2014/03/16 13:46
Hi, Thanks for the useful info here. I am a beginner of matlab. Just wonder for the first example:
% the data that you want to plot as a 3D surface.
[x,y,z] = peaks;

How can I utilize your code for my 2D color image? is it by using imread function? Hope you could help me on this matter

Thanks.
JOSE, 2014/05/21 04:56
how to put an image in plane z-x or z-y and not at plane x-y as is custom
I would love to hear your feedback. Enter your comment below [ Terms of Use ]:
HURLF
 

About Peter Yu I am a research and development professional with expertise in the areas of image processing, remote sensing and computer vision. I received BASc and MASc degrees in Systems Design Engineering at the University of Waterloo. My working experience covers industries ranging from district energy to medical imaging to cinematic visual effects. I like to dabble in 3D artwork, I enjoy cycling recreationally and I am interested in sustainable technology. More about me...

Feel free to contact me with any questions about this site at [user]@[host] where [user]=web and [host]=peteryu.ca

Copyright © 1997 - 2014 Peter Yu