Matlab将单应性应用于一组点(非图像)

Matlab将单应性应用于一组点(非图像),matlab,transformation,homography,Matlab,Transformation,Homography,我试图做的是将给定的单应性应用于一组点(x,y)(而不是将其应用于图像的常见用例) 我有一个存储为3x3维矩阵的单应矩阵: H = 1.06 -0.56 77.55 -0.02 0.74 28.34 0.02 -0.01 1.00 我有一套观点。例如: pts = [x1,y1 ; x2,y2 ; x3,y3 ;x4,y4 ; ...]; 如何将H应用于pts 我知道将其应用于图像非常简单,如: img = imread('pathtofile\file

我试图做的是将给定的单应性应用于一组点(x,y)(而不是将其应用于图像的常见用例)

我有一个存储为3x3维矩阵的单应矩阵:

H =
    1.06  -0.56  77.55
   -0.02   0.74  28.34
    0.02  -0.01   1.00
我有一套观点。例如:

pts = [x1,y1 ; x2,y2 ; x3,y3 ;x4,y4 ; ...];
如何将
H
应用于
pts

我知道将其应用于图像非常简单,如:

img = imread('pathtofile\file.png');
tform = projective2d(H); 
img2 = imwarp(img, tform);  
但是对于点列表,是否有一个与imwrap等价的函数?

使用属于
projective2d
类的函数。但是,请注意,您指定的单应性假设您将单应性与输入点预相乘。这是显而易见的,因为最后一列看起来像平移向量。也就是说,给定矩阵
H
和点矩阵
P
,其中每个列都是增广形式的一个点,其中第三行的值为1,可以通过以下方式实现点的扭曲:

out = H * P;
最终将获得扭曲点-每列一个点。请注意,坐标是齐次的,因此必须取第三个坐标,并将每列中对应的第一个和第二个值除以它们的第三个坐标

out(1,:) = out(1,:) ./ out(3,:);
out(2,:) = out(2,:) ./ out(3,:);
out = out(1:2,:);
但是,使用
transformpoints forward
假设您是与矩阵相乘后的,因此必须转置单应矩阵。这是由于MATLAB的列主要偏好,因此单应矩阵的系数按列主要顺序读取。但是,可以保持点矩阵不变

因此,在指定单应性
H
时,必须在创建
projective2d
实例之前先对其进行转置。完成此操作后,可以使用
transformpoints向前

tform = projective2d(H.');
out = transformPointsForward(tform, pts);
函数的第一个输入是您创建的投影变换,第二个输入是点矩阵-每行一个。输出将是一个与
pts
大小相同的矩阵,但每行都是给定
tform
的每个输入点的转换版本

但是,如果您想知道如何在引擎盖下实现这一点,您可以自己实现同样的目标,而无需
transformpoints forward
。这是通过首先转置
pts
,用
one
的行向量对其进行扩充,乘以
H
,然后将结果转置为相同大小来实现的。但是,您应该注意,这些扭曲坐标是齐次形式的,因此您必须按照前面指定的方式进行分割:

pts_aug = [pts.'; ones(1, size(pts, 1))];
out = (H * pts_aug).';
out = bsxfun(@rdivide, out(:,1:2), out(:,3));
第一行执行增强,第二行执行翘曲,最后第三行执行我们所讨论的分割。我决定使用
bsxfun
在一行中进行除法。但是,在MATLAB R2016b及以后的版本中,我们可以利用广播:

out = out(:,1:2) ./ out(:,3);    

作为一个快速示例,让我们在MATLAB中定义
H
,然后定义一组随机点:

H =[1.06  -0.56  77.55; -0.02   0.74  28.34; 0.02  -0.01   1.00];
rng(123);
pts = randi(20, 4, 2);
我们将
H
定义为单应性,并对随机生成器进行种子设定,以便生成四个2D随机点,其中最大期望值为20。一行是你在问题中指定的一点。现在,让我们确保这两种方法之间的行为是一致的:

% Method #1
tform = projective2d(H.');
out = transformPointsForward(tform, pts);

% Method #2
pts_aug = [pts.'; ones(1, size(pts, 1))];
out2 = (H * pts_aug).';
out2 = bsxfun(@rdivide, out2(:,1:2), out2(:,3));
out
out2
是输出扭曲点,我们可以显示它们:

>> format long g
>> out

out =

          74.3274336283186          34.6548672566372
          76.5728155339806          33.8640776699029
          79.6111111111111          47.8222222222222
          74.9363636363636          34.9636363636364

>> out2

out2 =

          74.3274336283186          34.6548672566372
          76.5728155339806          33.8640776699029
          79.6111111111111          47.8222222222222
          74.9363636363636          34.9636363636364

如果您也在点列表上添加循环(以便变换每个点),那就太好了。这对我来说有点挑战。但是第一种方法非常有效。但由于某种原因,第二个就不够了(但一个就足够了)。详细解释请参见Thx。这两个代码在每个点上循环。你能详细说明一下吗?为什么第二个不起作用?