Matlab将单应性应用于一组点(非图像)
我试图做的是将给定的单应性应用于一组点(x,y)(而不是将其应用于图像的常见用例) 我有一个存储为3x3维矩阵的单应矩阵: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
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。这两个代码在每个点上循环。你能详细说明一下吗?为什么第二个不起作用?