如何绘制具有纹理映射的表面

4
我希望能够在表面上绘制贴图,但条件并不是“理想”的。
首先让我们解释一下我的情况。我有一组点(约7000个)作为图像坐标,形成一个网格。这些点不构成完美的正方形,也不是网格。为了便于解释,假设我们有9个点,下面的图片展示了我们所拥有的内容:
 X=[310,270,330,430,410,400,480,500,520]
 Y=[300,400,500,300,400,500,300,400,500]

这里输入图片描述 假设我们可以获得网格的“结构”,那么

 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;

现在假设我们有第三个维度,Z。

编辑:忘记加一条信息了。我对图像中的点进行三角剖分,并获得三维对应关系,因此当它们显示在表面上时,它们不具有图像的X和Y坐标。为了简化给定的数据,让我们假设X=X/2 Y=Y/3

然后我们有:

 points=zeros(size1,size2,3)
 Z=[300,330,340;
    300,310,330;
    290,300,300]

 surf(points(:,:,1)/2,points(:,:,2)/3,points(:,:,3))

我想要的是将带有图像纹理的表面绘制成3D。每个元素应该具有第一张图像中所拥有的纹理块。
这需要适用于大数据表。我不需要它特别快。
相关文章(但我有一个初始点网格):Texture map for a 2D grid 附注:如果需要,我可以发布原始图像+真实数据,只是发了这个帖子,因为我认为小数据更容易处理。
3个回答

10
您可以使用surftexturemap属性,它适用于矩形网格和非矩形网格。

创建非矩形数据点

% creating non-rectangular data points
[X, Y] = meshgrid(1:100, 1:100);
X = X+rand(size(X))*5; 
Y = Y+rand(size(X))*5; 

这导致以下数据点:

enter image description here

生成高度数据:

Z = sin(X/max(X(:))*2*pi).*sin(Y/max(Y(:))*2*pi);

enter image description here

正在加载图片:

[imageTest]=imread('peppers.png');

并将其映射为网格的纹理:

surf(X,Y,Z, imageTest, ...
     'edgecolor', 'none','FaceColor','texturemap')

在此输入图像描述

请注意,为了演示,这个非矩形网格的点是相当稀疏的,这导致了一种相当锯齿状的纹理。随着更多的点,结果会变得更好,而不考虑网格点的扭曲。

还要注意,网格点的数量不必与纹理图像中的像素数量匹配。

~编辑~

如果X和Y坐标仅对图像的部分可用,则可以调整纹理图像。

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

不使用网格怎么样?我知道如何使用网格,在我提问中发布的链接中可以看到。抱歉,这并没有回答问题。 - Ander Biguri
@AnderBiguri:请查看我的更新答案,对于一开始没有仔细阅读你的问题,请原谅我。 - H.Muster
谢谢H.Muster。我忘记添加一些表面网格的细节,请检查我的编辑。我认为这个更改对你的答案来说很小,但我似乎找不到答案。 - Ander Biguri
@AnderBiguri:网格坐标不必与纹理坐标匹配。只要您不对网格点执行非线性变换,纹理就应该被映射到网格点上,无论进行了哪些变换。 - H.Muster
抱歉,但你正在做的仍然是获取图像的一个正方形部分。我需要每个元素的纹理与图像中相应的纹理一致。尽管你最后编辑的答案已经更接近预期的结果了。例如,想象一下这些点是圆形的,甚至是“逐渐增长的月亮”形状。你的答案在这种情况下不起作用。 - Ander Biguri
显示剩余3条评论

4
我认为你不能使用Matlab的内置命令和功能来实现你想要的。但是,使用我之前的答案中的技术以高分辨率版本的网格可以帮助你实现它。
所谓“高分辨率”,就是指非均匀网格的插值版本,具有更密集的数据点。这用于在更密集的数据点处采样纹理,以便使用surftexturemap功能进行绘制。然而,你不能使用普通的二维插值,因为你需要保留非均匀网格的形状。这就是我想出来的方法:
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

请注意,您需要调用两次以独立地插值X和Y点。以下是原始网格和每个方向上具有10个点的插值版本的示例。
这是如何使用高分辨率网格与interp2和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

Plot of the mapped texture


太棒了,伙计。我喜欢这个想法。我会尝试做类似的事情,这可能会非常成功。不过还是想知道,这需要多长时间完成?看起来也很快! - Ander Biguri
@AnderBiguri 谢谢!在我有了这个想法之后,编写代码只花了几分钟。对于这个小数据集来说,它很好又快。你的“巨大”数据集进展如何? - shoelzer
我还没有实现绘图,因为它有点更复杂,但是想法是正确的,应该可以工作! - Ander Biguri

1
我不确定我理解你的问题,但我认为你需要做的是在网格的X,Y点上采样(映射)纹理。然后,您可以简单地绘制表面并使用这些样本作为颜色。
以下是使用您在问题中提供的数据的示例。它看起来不太起眼,但使用更多的X、Y、Z点应该可以得到您想要的结果。
% 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

Plot of the mapped texture


不,那不是我想要的,抱歉。我想在这个表面中绘制纹理本身。你只绘制了一种颜色,但在4个点之间有一个完整的纹理。我想提取第一张图像中每个元素的纹理,以便在表面的每个元素中绘制它(作为纹理,而不是颜色)。 - Ander Biguri
@AnderBiguri 现在我明白了!请看我的新答案。 - shoelzer

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接