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 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 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.