2D网格的纹理映射

4

我有一组点,定义在一个正常的二维N x M网格上,其坐标为[x,y]=meshgrid(1:N,1:M)。我还有另一组点[u,v],这些点是原始网格的某种变形,即[u,v]=f(x,y)'(但我没有导致变形的实际函数f)。如何将纹理映射到由u,v定义的“变形”网格?也就是说,给定一个具有纵横比N/M的图像,如何将它映射到变形后的网格上?


1
你能澄清一下“贴图”是什么意思吗? - Fabian Tamp
uv 的尺寸是多少?您是否有关于将 uvxy 相关的“变形”的明确表达式?您要映射的纹理是什么?它是一个函数吗?矩阵?它的尺寸是多少?如果您的问题本身过于模糊,那么奖励也无法帮助您得到一个好的答案... - Shai
我添加了更多的解释,希望足够清晰... - olamundo
非常有趣的问题。我理解的是,您想在一组变形点和图像上绘制图形?就好像您要绘制一个球体并尝试在其上绘制世界地图一样?您需要在变形之前设置每个元素图像部分,并更改每个部分以在变形表面上绘制它们。这是您想要的吗?如果是这样,请修改您的问题并添加一些图像,...让人们感兴趣(人们喜欢颜色和图像!),因为我认为这是一个非常有趣的问题。不过实时绘制似乎很困难... - Ander Biguri
4个回答

6

我认为您想在[u,v]处获取原始纹理的样本。您可以使用interp2

假设纹理样本在z中,您想要新的样本z2。要在[u,v]处插值原始纹理,请使用:

z2 = interp2(x,y,z,u,v);

另一方面,如果你想将“变形”的纹理映射回到一个规则间隔的网格[x2,y2],请使用griddata

[x2,y2] = meshgrid(1:N2,1:M2);
z2 = griddata(u,v,z,x2,y2);

更新:

这里有一些示例代码,展示如何使用真实数据来完成此操作。使用标准化坐标可以使操作更加简便。

% get texture data
load penny
z = P;

% define original grid based on image size
[m,n] = size(z);
[a,b] = meshgrid(linspace(0,1,n), linspace(0,1,m));

% define new, differently sized grid
m2 = 256;
n2 = 256;
[x,y] = meshgrid(linspace(0,1,n2), linspace(0,1,m2));

% define deformed grid
u = sqrt(x);
v = y.^2;

% sample the texture on the deformed grid
z2 = interp2(a,b,z,u,v);

% plot original and deformed texture
figure
subplot(2,1,1)
surface(a,b,z,'EdgeColor','none')
axis ij image off
colormap gray
title('original')
subplot(2,1,2)
surface(x,y,z2,'EdgeColor','none')
axis ij image off
colormap gray
title('deformed')

这是结果:

原始纹理和变形纹理的绘图


很抱歉,但这仍然不是我要求的。在这种情况下,[x,y]的尺寸与图像的尺寸相同,只有[u,v]的尺寸不同。我想要的是[u,v]的尺寸与[x,y]的尺寸相同,并且它们与图像的尺寸不同。对不起... - olamundo
@noam 请查看我的更新。[x,y]和[u,v]的大小相同,但与图像大小不同。 - shoelzer
谢谢!这正是我想要的。赏金归你 :) - olamundo
@noam 不用谢。我只是进行了一些小的编辑,使用interp2,因为我们正在对均匀网格数据(原始纹理)进行采样(映射)。这应该比griddata更快。 - shoelzer

4

编辑:

这里是使用 surface 函数进行纹理映射的示例:

%# image and 2D grid of points of the same size as the image
img = load('clown');    %# indexed color image
[m,n] = size(img.X);
[a,b] = meshgrid(1:n,1:m);

%# initial grid (here 1/5-th the size, but could be anything)
[X,Y] = meshgrid(linspace(1,n,n/5),linspace(1,m,m/5));

%# resize image to fit this grid
[C,map] = imresize(img.X, img.map, size(X), 'bicubic');

%# deformed 2D points (we dont need to know f, just load U/V here)
fx = @(x,y) sqrt(x);
fy = @(x,y) y.^2;
U = fx(X,Y);
V = fy(X,Y);

%# Z-coordinates: I'm using Z=0 for all points, but could be anything
Z = zeros(size(U));
%Z = peaks(max(size(U))); Z = Z(1:size(U,1),1:size(U,2)); view(3)

%# show image as texture-mapped surface
surface(U, V, Z, C, 'CDataMapping','direct', ...
    'FaceColor','texturemap', 'EdgeColor','none')
colormap(map)
axis ij tight off
view(2)

pic

使用显式插值的方法是使用 imresize 的一种替代方法(这个想法来自 @shoelzer):

CC = ind2rgb(img.X, img.map);    %# convert to full truecolor
C = zeros(size(X));
for i=1:size(CC,3)
    C(:,:,i) = griddata(a,b, CC(:,:,i), X,Y, 'linear');
end

当然,有了这个改变,就不再需要使用颜色映射/数据映射了...
(注:我认为 interp2 在这里会更快)
注意,在上面的示例中,我使用了一个带有关联颜色映射表的索引颜色图像。该代码可以轻松适应灰度或真彩色全RGB图像。请参阅this page,以了解不同图像类型的说明。

@AnderBiguri 如果你真的必须要这样做,你可以授予他150声望奖励。 - Shai
1
@Amro 我有一个问题:'小丑'图片是什么类型的数据?我无法将使用'imread'加载的图像转换为那种结构。 - Ander Biguri
1
@amro - 我不确定我理解你的说法。您特别生成了x y以与小丑图像相同的大小。如果您可以更改代码,使[x y]的大小为小丑图像的1/5,并且它仍然有效,则我将考虑它是一个完整的答案。 - olamundo
@noam 如果要使网格的大小与图像不同,您需要某种插值方法。我更新了我的答案,并提供了示例代码以展示如何实现。 - shoelzer
@noam:抱歉,我现在明白你的观点了。请看我上面的编辑...这可以很容易地通过imresize或使用插值方法来修复,就像其他人提到的那样。 - Amro
显示剩余6条评论

1
似乎你可以使用tformfwdtforminv,稍加改动即可得到ftformfwd将点从输入空间转换为输出空间。例如,要对点(u,v)=(5,3)应用仿射变换,可以这样做:
uv = [5 3];
xy = tformfwd(tform, uv)

这将输出给定tform的(x,y)坐标。

同样地,tforminv将点从输出空间转换为输入空间。如果我们对上面计算出的点xy应用逆变换,我们应该能够得到原始点。

uvp = tforminv(tform, xy)
uvp =
     5     3

因此,您可以使用这台机器通过正向和反向几何变换来映射点。

如果您正在使用R2013a及更高版本,则可以使用几何变换类(例如affine2d、projective2d)的transformPointsForwardtransformPointsInverse方法,并考虑imwarp


谢谢,这肯定是朝着正确方向迈出的一步,但它并没有完全回答我的问题。我仍然需要根据网格将图像分解为补丁,然后分别映射每个补丁。问题在于,我有网格上的点及其映射。我正在寻找一个完整的解决方案,只需提供x,y,u,v给Matlab,它就可以完成所有工作。实现起来似乎很容易,但我想避免使用for循环,因为我的代码需要实时运行。 - olamundo
谢谢您提供更多信息。所以您没有f,但是您有x,y,u,v?转换(x,y)->(u,v)是一对一的吗?还是什么都不知道? - bla
我会这样做。获取每个元素的变换基本矩阵,然后将该变换应用于该元素的小图像。但我仍然认为这无法在没有for循环(在matlab中不再缓慢)或实时处理的情况下完成。 - Ander Biguri
@natan - 如果我没记错的话,您更新后的回答似乎假定我将变形定义为某个解析函数,即tform参数。但事实并非如此。我只有[x,y]点和[u,v]点。 - olamundo
tform 是一个值矩阵,需要是非奇异实数。它始终是数值型的。更多信息请参见:http://www.mathworks.com/help/images/ref/maketform.html - bla
@noam,请查看Jona在此处的答案:https://dev59.com/rmcs5IYBdhLWcg3woFXt,其中涉及使用`tform`(他在答案中将其表示为`tf`)对数字随机应用`imtransform`。 - bla

1
假设xyuv大小相同(MxN 二维矩阵),您希望映射的图像/纹理I大小为MxNx3(三个颜色通道),那么您可能会发现scatter很有用:
figure;
scatter( u(:), v(:), 30, reshape( I, [], 3 ), 's', 'filled' );

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