I want to plot a surface with a texture map on it, but the conditions are not the "ideal" ones.
first lets explain what I have.
I have a set of points (~7000) that are image coordinates, in a grid. This points do NOT define perfect squares. IT IS NOT A MESHGRID. For the sake of the question, lets assume that we have 9 points. Lets ilustrate what we have with an image:
X=[310,270,330,430,410,400,480,500,520]
Y=[300,400,500,300,400,500,300,400,500]
Lets say we can get the "structure" of the grid, so
size1=3;
size2=3;
points=zeros(size1,size2,2)
X=[310,270,330;
430,410,400;
480,500,520]
Y=[300,400,500;
300,400,500;
300,400,500]
points(:,:,1)=X;
points(:,:,2)=Y;
And now lets say we have a 3rd dimension, Z.
EDIT: Forgot to add a piece if info. I triangulate the points in the image and get a 3D correspondence, so when displayed in a surface they don't have the X and Y coords of the image, for a simplification of the given data lets say X=X/2 Y=Y/3
And we have:
points=zeros(size1,size2,3)
Z=[300,330,340;
300,310,330;
290,300,300]
surf(points(:,:,1)/2,points(:,:,2)/3,points(:,:,3))
What I want is to plot the surface in 3D with the image texture. Each element should have the texture piece that have in the first image.
This needs to work for huge datasheets. I don't specially need it to be fast.
related post (but I has a meshgrid as initial set of points) : Texture map for a 2D grid
PD: I can post original images + real data if needed, just posted this because i think it is easier with small data.
I don't think you can do what you want with Matlab's built in commands and features. But using the technique from my other answer with a high-res version of the grid can do it for you.
By "high-res", I mean an interpolated version of the non-uniform grid with denser data points. That is used to sample the texture at denser data points so it can be drawn using the texturemap
feature of surf
. You can't use a normal 2D interpolation, however, because you need to preserve the non-uniform grid shape. This is what I came up with:
function g = nonUniformGridInterp2(g, sx, sy)
[a,b] = size(g);
g = interp1(linspace(0,1,a), g, linspace(0,1,sy)); % interp columns
g = interp1(linspace(0,1,b), g', linspace(0,1,sx))'; % interp rows
Note that you have to call this twice to interpolate the X and Y points independently. Here's an example of the original grid and an interpolated version with 10 points in each direction.
Here's how to use that high-res grid with interp2
and texturemap
.
function nonUniformTextureMap
% define the non-uniform surface grid
X = [310,270,330; 430,410,400; 480,500,520];
Y = [300,400,500; 300,400,500; 300,400,500];
Z = [300,330,340; 300,310,330; 290,300,300];
% get texture data
load penny % loads data in variable P
% define texture grid based on image size
% note: using 250-550 so that a,b covers the range used by X,Y
[m,n] = size(P);
[a,b] = meshgrid(linspace(250,550,n), linspace(250,550,m));
% get a high-res version of the non-uniform grid
s = 200; % number of samples in each direction
X2 = nonUniformGridInterp2(X, s, s);
Y2 = nonUniformGridInterp2(Y, s, s);
% sample (map) the texture on the non-uniform grid
C = interp2(a, b, P, X2, Y2);
% plot the original and high-res grid
figure
plot(X(:),Y(:),'o',X2(:),Y2(:),'.')
legend('original','high-res')
% plot the surface using sampled points for color
figure
surf(X, Y, Z, C, 'edgecolor', 'none', 'FaceColor','texturemap')
colormap gray
You can use the texturemap
property of surf
which works with rectangular meshes as well as with non-rectangular ones.
Creating non-rectangular data points
% creating non-rectangular data points
[X, Y] = meshgrid(1:100, 1:100);
X = X+rand(size(X))*5;
Y = Y+rand(size(X))*5;
which results in the following data points:
Generating height data:
Z = sin(X/max(X(:))*2*pi).*sin(Y/max(Y(:))*2*pi);
Loading picture:
[imageTest]=imread('peppers.png');
and mapping it as texture to the mesh:
surf(X,Y,Z, imageTest, ...
'edgecolor', 'none','FaceColor','texturemap')
Note that, for the sake of demonstration, this non-rectangular grid is quite sparsely populated which results in a rather jagged texture. With more points, the result gets much better, irrespective of the distortion of the grid points.
Note also that the number of grid points does not have to match the number of pixels in the texture image.
~edit~
If X and Y coordinates are only available for parts of the image, you can adjust the texture accordingly by
minX = round(min(X(:)));
maxX = round(max(X(:)));
minY = round(min(Y(:)));
maxY = round(max(Y(:)));
surf(X,Y,Z, imageTest(minX:maxX, minY:maxY, :), ...
'edgecolor', 'none','FaceColor','texturemap')
I'm not sure I understand your question, but I think that what you need to do is sample (map) the texture at your grid's X,Y points. Then you can simply plot the surface and use those samples as colors.
Here's an example using the data you gave in your question. It doesn't look like much, but using more X,Y,Z points should give the result you're after.
% define the non-uniform surface grid
X = [310,270,330; 430,410,400; 480,500,520];
Y = [300,400,500; 300,400,500; 300,400,500];
Z = [300,330,340; 300,310,330; 290,300,300];
% get texture data
load penny % loads data in variable P
% define texture grid based on image size
% note: using 600 so that a,b covers the range used by X,Y
[m,n] = size(P);
[a,b] = meshgrid(linspace(0,600,n), linspace(0,600,m));
% sample (map) the texture on the non-uniform grid
C = interp2(a, b, P, X, Y);
% plot the surface using sampled points for color
figure
surf(X, Y, Z, C)
colormap gray
来源:https://stackoverflow.com/questions/16342164/how-to-plot-a-surface-with-a-texture-map