How to plot a surface with a texture map

孤街醉人 提交于 2019-12-30 05:15:07

问题


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.


回答1:


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




回答2:


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')



回答3:


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!