我已经得到了在2D中形成矩形的4个点的坐标,以及应用透视变换后的坐标。
透视变换在齐次坐标中计算,并由3x3矩阵M
定义。如果矩阵是未知的,我如何从给定的点计算它?
一个点的计算方法是:
| M11 M12 M13 | | P1.x | | w*P1'.x |
| M21 M22 M23 | * | P1.y | = | w*P1'.y |
| M31 M32 M33 | | 1 | | w*1 |
为了同时计算所有的点,我把它们一起写在一个矩阵A
中,类似地,把变换后的点写在一个矩阵B
中:
| P1.x P2.x P3.x P4.x |
A = | P1.y P2.y P3.y P4.y |
| 1 1 1 1 |
所以方程是M*A=B
,在MATLAB中可以通过M = B/A
或M = (A'\B')'
求解M
。
但没那么容易。我知道变换后点的坐标,但我不知道确切的B
,因为有因子w
,在齐次变换后不需要1。因为在齐次坐标系中,向量的每一个倍数都是同一个点,我不知道我会得到哪个倍数。
为了考虑这些未知因素,我将方程写为M*A=B*W
,其中W
是一个对角矩阵,B
中对角线上的每个点的因子为w1.w4。所以A
和B
现在是完全已知的,我必须解出M
和W
的方程。
如果我可以把方程重新排列成x*A=B
或A*x=B
的形式,其中x
将是类似于M*W
的东西,我就可以解出它,知道M*W
的解可能已经足够了。然而,尽管尝试了所有可能的重新安排,我还是没能做到。直到我意识到封装(M*W)
是不可能的,因为一个是3x3矩阵,另一个是4x4矩阵。我被困在这里了。M*A=B*W
也没有M
的单一解,因为M
的每一个倍数都是相同的变换。将其写成线性方程组,可以简单地固定M
中的一个条目以获得单个解。此外,可能有一些输入根本没有M
的解决方案,但我们现在不要担心这个问题。
我实际上试图实现的是某种矢量图形编辑程序,用户可以拖动形状边界框的角来转换它,同时在内部计算转换矩阵。
实际上,我需要用JavaScript来实现,但如果我不能用MATLAB来解决这个问题,我就完全被卡住了。
3条答案
按热度按时间aurhwmvo1#
OpenCV有一个很好的函数来完成这个任务,叫做getPerspectiveTransform。这个函数的源代码可以在github上找到,描述如下:
这个方程组更小,因为它避免了求解
W
和M33
(OpenCV称为c22
)。那么它是如何工作的呢?线性系统可以通过以下步骤重新创建:从一个点的方程开始:
将其转换为方程组,求解
ui
和vi
,并消除w
。你会得到投影变换的公式:两边乘以分母:
分发
ui
和vi
:假设
c22 = 1
:收集左手侧的所有
cij
:最后转换成四对点的矩阵形式:
这是现在的形式
Ax=b
和解决方案可以得到x = A\b
。记住c22 = 1
。ocebsuys2#
这个问题应该很简单那么,如何将
M*A=B*W
转化为可解形式呢?这只是矩阵乘法,所以我们可以把它写成线性方程组。你知道,就像:M11*A11 + M12*A21 + M13*A31 = B11*W11 + B12*W21 + B13*W31 + B14*W41
。每个线性方程组都可以写成Ax=b
的形式,或者为了避免与我的问题中已经使用的变量混淆:N*x=y
就这样根据我的问题举个例子:我用已知的
M
和W
生成一些输入数据:然后我忘记了
M
和W
。意味着我现在有13个变量要解。我把M*A=B*W
重写成一个线性方程组,并从那里变成N*x=y
的形式。在N
中,每一列都有一个变量的因子:y
是:注意
N
中最后一行描述的方程,根据y
,其解为1。这就是我在我的问题中提到的,你必须修复M
的一个条目才能得到一个解决方案。(我们可以这样做,因为M
的每一个倍数都是相同的变换。)根据这个等式,我说M33应该是1。我们对
x
求解:并获得:
[ M11, M12, M13, M21, M22, M23, M31, M32, M33, w1, w2, w3, w4 ]
的解决方案M
计算完成后就不需要W
了。对于一般点(x, y)
,在求解x'
和y'
时计算对应的w
。当在JavaScript中解决这个问题时,我可以使用Numeric JavaScript库,该库具有所需的函数solve来解决Ax=b。
b1zrtrql3#
要使用此函数,可以传入两组对应的点作为输入参数(srcPts和destPts)。每组点应该是一个四行两列的矩阵,其中每行代表一个点的x和y坐标。
例如,你可以像这样调用函数:
该函数将返回将源点Map到目的地点的3x3透视变换矩阵T。