在MATLAB中从4个点计算二维均匀透视变换矩阵

dai*_*ign 8 matlab transform matrix linear-algebra

我在 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     |
Run Code Online (Sandbox Code Playgroud)

为了同时计算所有点,我将它们一起写在一个矩阵中A,类似于矩阵中的转换点B

    | P1.x P2.x P3.x P4.x |
A = | P1.y P2.y P3.y P4.y |
    | 1    1    1    1    |
Run Code Online (Sandbox Code Playgroud)

所以方程是M*A=B,这可以M在 MATLAB 中通过M = B/A或求解M = (A'\B')'

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

为了考虑这些未知因素,我将方程写为M*A=B*W whereW是一个对角矩阵,其中对角线B上的每个点都有因子 w1...w4 。所以AB现在完全知道了,我必须为M和解这个方程W

如果我能重新进入方程的形式x*A=BA*x=B在那里x会是这样的M*W,我可以解决这个问题,并知道该解决方案M*W将可能是已经足够。然而,尽管尝试了所有可能的重新排列,我还是没能做到。直到我发现封装(M*W)是不可能的,因为一个是 3x3 矩阵,另一个是 4x4 矩阵。我被困在这里。

M*A=B*W没有单一的解决方案M,因为 的每个倍数M都是相同的变换。把它写成一个线性方程组,一个人可以简单地修复其中的一个条目M以获得一个单一的解决方案。此外,可能存在根本没有解决方案的输入M,但我们现在不要担心这个。

我实际上想要实现的是某种矢量图形编辑程序,用户可以在其中拖动形状边界框的角来对其进行转换,而在内部计算转换矩阵。

实际上我在 JavaScript 中需要这个,但是如果我什至不能在 MATLAB 中解决这个问题,我就完全被卡住了。

mor*_*paj 6

OpenCV 有一个简洁的函数,称为getPerspectiveTransform。这个函数的源代码可以在 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
 */
Run Code Online (Sandbox Code Playgroud)

该方程组较小,因为它避免了求解WM33c22由 OpenCV调用)。那么它是怎样工作的?可以通过以下步骤重新创建线性系统:

从投影变换的公式开始:

     c00*xi + c01*yi + c02
ui = ---------------------
     c20*xi + c21*yi + c22

     c10*xi + c11*yi + c12
vi = ---------------------
     c20*xi + c21*yi + c22
Run Code Online (Sandbox Code Playgroud)

两边乘以分母:

(c20*xi + c21*yi + c22) * ui = c00*xi + c01*yi + c02
(c20*xi + c21*yi + c22) * vi = c10*xi + c11*yi + c12
Run Code Online (Sandbox Code Playgroud)

分发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
Run Code Online (Sandbox Code Playgroud)

假设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
Run Code Online (Sandbox Code Playgroud)

收集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
Run Code Online (Sandbox Code Playgroud)

最后转换为四对点的矩阵形式:

/ 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/
Run Code Online (Sandbox Code Playgroud)

这是现在的形式Ax=b并且可以通过 获得解决方案x = A\b。请记住c22 = 1


dai*_*ign 5

应该是一个简单的问题。那么如何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 = [
    1 2 3;
    4 5 6;
    7 8 1
];
A = [
    0 0 1 1;
    0 1 0 1;
    1 1 1 1
];
W = [
    4 0 0 0;
    0 3 0 0;
    0 0 2 0;
    0 0 0 1
];
B = M*A*(W^-1);
Run Code Online (Sandbox Code Playgroud)

然后我忘记了MW。这意味着我现在有 13 个要解决的变量。我重M*A=B*W写成一个线性方程组,并从那里变成形式N*x=y. 在N每一列中都有一个变量的因子:

N = [
    A(1,1) A(2,1) A(3,1)      0      0      0      0      0      0 -B(1,1)       0       0       0;
         0      0      0 A(1,1) A(2,1) A(3,1)      0      0      0 -B(2,1)       0       0       0;
         0      0      0      0      0      0 A(1,1) A(2,1) A(3,1) -B(3,1)       0       0       0;
    A(1,2) A(2,2) A(3,2)      0      0      0      0      0      0       0 -B(1,2)       0       0;
         0      0      0 A(1,2) A(2,2) A(3,2)      0      0      0       0 -B(2,2)       0       0;
         0      0      0      0      0      0 A(1,2) A(2,2) A(3,2)       0 -B(3,2)       0       0;
    A(1,3) A(2,3) A(3,3)      0      0      0      0      0      0       0       0 -B(1,3)       0;
         0      0      0 A(1,3) A(2,3) A(3,3)      0      0      0       0       0 -B(2,3)       0;
         0      0      0      0      0      0 A(1,3) A(2,3) A(3,3)       0       0 -B(3,3)       0;
    A(1,4) A(2,4) A(3,4)      0      0      0      0      0      0       0       0       0 -B(1,4);
         0      0      0 A(1,4) A(2,4) A(3,4)      0      0      0       0       0       0 -B(2,4);
         0      0      0      0      0      0 A(1,4) A(2,4) A(3,4)       0       0       0 -B(3,4);
         0      0      0      0      0      0      0      0      1       0       0       0       0
];
Run Code Online (Sandbox Code Playgroud)

并且y是:

y = [ 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 1 ];
Run Code Online (Sandbox Code Playgroud)

注意最后一行描述的方程,根据 ,N其解为 1 y。这就是我在我的问题中提到的,您必须修复其中一个条目M才能获得单一解决方案。(我们可以这样做,因为 的每一个倍数M都是相同的变换。)对于这个等式,我说 M33 应该是 1。

我们解决这个问题x

x = N\y
Run Code Online (Sandbox Code Playgroud)

并得到:

x = [ 1.00000; 2.00000; 3.00000; 4.00000; 5.00000; 6.00000; 7.00000; 8.00000; 1.00000; 4.00000; 3.00000; 2.00000; 1.00000 ]
Run Code Online (Sandbox Code Playgroud)

哪些是解决方案 [ M11, M12, M13, M21, M22, M23, M31, M32, M33, w1, w2, w3, w4 ]

当在JavaScript我做这个可以用数字的JavaScript具有所需的函数库解决解决Ax = b的。