I have a set of points [x,y]=meshgrid(1:N,1:M)
defined on a regular 2D, N x M
grid. I have another set of points [u,v]
that are some defor
It seems that you can use tformfwd
and tforminv
with a small twist to get f
.
tformfwd
transforms points from input space to output space. For example, to apply an affine transform to the point (u,v) = (5,3), you can do this:
uv = [5 3];
xy = tformfwd(tform, uv)
This will out put the (x,y) coordinates given tform
Similarly, tforminv
transforms points from output space to input space. If we apply the inverse transformation to the point xy computed above, we should get back the original point.
uvp = tforminv(tform, xy)
uvp =
5 3
So, you can use this machinery to map points by the forward and inverse geometric transformation.
If you are using R2013a and later, you can use the transformPointsForward
and transformPointsInverse
methods of the geometric transformation classes (e.g. affine2d, projective2d), and also consider imwarp.
Assuming x
, y
, u
and v
are of the same size (MxN
2D matrices) and the image/texture you wish to map is I
of size MxNx3
(three color channels), then you might find scatter
useful:
figure;
scatter( u(:), v(:), 30, reshape( I, [], 3 ), 's', 'filled' );
Here is an example of texture mapping using the surface function:
%# 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)
An alternative to using imresize
is explicit interpolation (idea borrowed from @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
of course with this change, there is no need for the colormap/CDataMapping anymore...
(Note: I think interp2 would be much faster here)
Note that in the example above, I'm using an indexed color image with an associated colormap. The code can easily be adapted to work on grayscale or truecolor full RGB images. See this page for an explanation on the different image types.
I think you are asking to get samples of the original texture at [u,v]
. You can use interp2.
Let's say that the texture samples are in z
and you want new samples z2
. To interpolate the original texture at [u,v]
, use:
z2 = interp2(x,y,z,u,v);
On the other hand, if you want to map the "deformed" texture back to a regularly spaced grid [x2,y2]
, use griddata:
[x2,y2] = meshgrid(1:N2,1:M2);
z2 = griddata(u,v,z,x2,y2);
Update:
Here's some example code showing how to do this with real data. Using normalized coordinates makes it easier.
% 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')
And this is the result: