matlab - 在 MATLAB 中从 4 个点计算二维齐次透视变换矩阵

标签 matlab matrix transform linear-algebra

我有 4 个二维点的坐标,它们形成一个矩形,并且在应用透视变换后它们的坐标。

enter image description here

透视变换在齐次坐标系中计算并由 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/AM = (A'\B')' .

但这并不容易。我知道变换后点的坐标,但我不知道确切的 B , 因为有因子 w并且在齐次变换后不需要 1 。因为在齐次坐标中,向量的每个倍数都是同一个点,我不知道我会得到哪个倍数。

为了考虑这些未知因素,我将等式写为 M*A=B*W 其中 WB 中每个点的因子 w1...w4 的对角矩阵在对角线上。所以AB现在完全知道了,我必须为 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
 */

这个方程组较小,因为它避免求解 WM33(OpenCV 称为 c22)。那么它是怎样工作的?可以通过以下步骤重新创建线性系统:

从一个点的等式开始:

| c00 c01 c02 |   | xi |   | w*ui |
| c10 c11 c12 | * | yi | = | w*vi |
| c20 c21 c22 |   | 1  |   | w*1  |

将其转化为方程组,求解uivi,并消去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

分发 uivi:

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/

相关文章:

c++ - 无限脉冲响应 (IIR) 函数

Matlab:明确指定饼图切片颜色

c++ - 在 C++ 中处理大型矩阵

javascript - 我们如何在不修改场景树结构或几何形状的情况下更改 Three.js 对象的旋转原点(枢轴点)?

javascript - 如何一个接一个地对 CSS 转换命令进行排序

import - 在 Spring WS 中转换 XSD 导入以用于 WSDL

matlab - 在 MATLAB 中执行 imwrite 后像素值发生变化

c++ - C++ 中的 Matlab 希尔伯特变换

algorithm - 使用矩阵在 O(1) 时间内回答查询

C:打印数组中某个点的水平、垂直和倾斜值