我有 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
这可以解决 M
在 MATLAB 中 M = B/A
或 M = (A'\B')'
.
但这并不容易。我知道变换后点的坐标,但我不知道确切的 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 中解决这个问题,我就会完全陷入困境。
最佳答案
OpenCV 有一个简洁的函数可以执行此操作,称为 getPerspectiveTransform .此函数的源代码可用 on github有这样的描述:
/* Calculates coefficients of perspective transformation
* which maps (xi,yi) to (ui,vi), (i=1,2,3,4):
*
* c00*xi + c01*yi + c02
* ui = ---------------------
* c20*xi + c21*yi + c22
*
* c10*xi + c11*yi + c12
* vi = ---------------------
* c20*xi + c21*yi + c22
*
* Coefficients are calculated by solving linear system:
* / x0 y0 1 0 0 0 -x0*u0 -y0*u0 \ /c00\ /u0\
* | x1 y1 1 0 0 0 -x1*u1 -y1*u1 | |c01| |u1|
* | x2 y2 1 0 0 0 -x2*u2 -y2*u2 | |c02| |u2|
* | x3 y3 1 0 0 0 -x3*u3 -y3*u3 |.|c10|=|u3|,
* | 0 0 0 x0 y0 1 -x0*v0 -y0*v0 | |c11| |v0|
* | 0 0 0 x1 y1 1 -x1*v1 -y1*v1 | |c12| |v1|
* | 0 0 0 x2 y2 1 -x2*v2 -y2*v2 | |c20| |v2|
* \ 0 0 0 x3 y3 1 -x3*v3 -y3*v3 / \c21/ \v3/
*
* where:
* cij - matrix coefficients, c22 = 1
*/
这个方程组较小,因为它避免求解 W
和 M33
(OpenCV 称为 c22
)。那么它是怎样工作的?可以通过以下步骤重新创建线性系统:
从一个点的等式开始:
| c00 c01 c02 | | xi | | w*ui |
| c10 c11 c12 | * | yi | = | w*vi |
| c20 c21 c22 | | 1 | | w*1 |
将其转化为方程组,求解ui
和vi
,并消去w
。你得到投影变换的公式:
c00*xi + c01*yi + c02
ui = ---------------------
c20*xi + c21*yi + c22
c10*xi + c11*yi + c12
vi = ---------------------
c20*xi + c21*yi + c22
两边都乘以分母:
(c20*xi + c21*yi + c22) * ui = c00*xi + c01*yi + c02
(c20*xi + c21*yi + c22) * vi = c10*xi + c11*yi + c12
分发 ui
和 vi
:
c20*xi*ui + c21*yi*ui + c22*ui = c00*xi + c01*yi + c02
c20*xi*vi + c21*yi*vi + c22*vi = c10*xi + c11*yi + c12
假设c22 = 1
:
c20*xi*ui + c21*yi*ui + ui = c00*xi + c01*yi + c02
c20*xi*vi + c21*yi*vi + vi = c10*xi + c11*yi + c12
收集左侧的所有cij
:
c00*xi + c01*yi + c02 - c20*xi*ui - c21*yi*ui = ui
c10*xi + c11*yi + c12 - c20*xi*vi - c21*yi*vi = vi
最后将四对点转化为矩阵形式:
/ x0 y0 1 0 0 0 -x0*u0 -y0*u0 \ /c00\ /u0\
| x1 y1 1 0 0 0 -x1*u1 -y1*u1 | |c01| |u1|
| x2 y2 1 0 0 0 -x2*u2 -y2*u2 | |c02| |u2|
| x3 y3 1 0 0 0 -x3*u3 -y3*u3 |.|c10|=|u3|
| 0 0 0 x0 y0 1 -x0*v0 -y0*v0 | |c11| |v0|
| 0 0 0 x1 y1 1 -x1*v1 -y1*v1 | |c12| |v1|
| 0 0 0 x2 y2 1 -x2*v2 -y2*v2 | |c20| |v2|
\ 0 0 0 x3 y3 1 -x3*v3 -y3*v3 / \c21/ \v3/
现在是 Ax=b
的形式,可以用 x = A\b
获得解。请记住 c22 = 1
。
关于matlab - 在 MATLAB 中从 4 个点计算二维齐次透视变换矩阵,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35819142/