Skip to content

DLT算法求解单应性矩阵

699字约2分钟

3DVision

2024-03-13

DLT算法求解单应性矩阵

原理:

单应性矩阵描述了两个图像之间的投影变换关系,即从一张图到另一张图的变换。

下面是DLT算法的基本原理:

  1. 构建投影方程: 对于两个图像中的对应点 (x,y,1)(x, y, 1)(u,v,1)(u, v, 1) ,投影关系可以用齐次坐标表示为 c[uv1]=H[xy1]c \begin{bmatrix} u \\ v \\ 1 \end{bmatrix} = H \begin{bmatrix} x \\ y \\ 1 \end{bmatrix}cc 只是一个常数,由于是齐次坐标,所以不影响 )。这里的 HH3×33 \times 3 矩阵)是我们要求解的单应性矩阵

H=[h1h2h3h4h5h6h7h8h9] H =\begin{bmatrix} h1 & h2 & h3 \\ h4 & h5 & h6 \\ h7 & h8 & h9 \end{bmatrix}

  1. 构建矩阵 AA 将上面的投影方程展开成 Ah=0Ah = 0 的形式,其中 AA 是一个 2n×92n \times 9 的矩阵, hh 是包含矩阵 HH 所有元素的列向量

A=[x1y11000u1x1u1y1u1000x1y11v1x1v1y1v1xnyn1000unxnunynun000xnyn1vnxnvnynvn] A = \begin{bmatrix} -x_1 & -y_1 & -1 & 0 & 0 & 0 & u_1x_1 & u_1y_1 & u_1 \\ 0 & 0 & 0 & -x_1 & -y_1 & -1 & v_1x_1 & v_1y_1 & v_1 \\ \vdots & \vdots & \vdots & \vdots & \vdots & \vdots & \vdots & \vdots & \vdots \\ -x_n & -y_n & -1 & 0 & 0 & 0 & u_nx_n & u_ny_n & u_n \\ 0 & 0 & 0 & -x_n & -y_n & -1 & v_nx_n & v_ny_n & v_n \\ \end{bmatrix}

h=[h1h2h3h4h5h6h7h8h9] h=\begin{bmatrix}h1&h2&h3&h4&h5&h6&h7&h8&h9\end{bmatrix}

  1. 奇异值分解(SVD): 对矩阵 AA 进行奇异值分解,得到 A=UΣVTA = U \Sigma V^T。取 VTV^T 的最后一列作为 hh 的估计

    方程的最小二乘解有一个既定的结论,即对 AA 进行SVD分解,得到的 VTV^T 的最后一行 即是 hh 的解,对 hh 做 reshape 得到 HH

实现:

根据你提供的信息,DLT(Direct Linear Transform)算法用于通过最小二乘法来估计单应性矩阵 HH,以拟合两组特征点之间的关系。下面是DLT算法的具体步骤:

  1. 构建矩阵 AA 对于每一对特征点 (x,y,1)(x, y, 1)(u,v,1)(u, v, 1),构建一个对应的矩阵 AiA_i。将所有这些矩阵堆叠成一个大矩阵 AA

    def get_Ai(xi_vector, xi_prime_vector):
        assert (xi_vector.shape == (3,) and xi_prime_vector.shape == (3,))
    
        Ai = np.zeros((2, 9))
        Ai[0] = np.array(
            [-xi_vector[0], -xi_vector[1], -1, 0, 0, 0, xi_vector[0] * xi_prime_vector[0],
             xi_vector[1] * xi_prime_vector[0], xi_prime_vector[0]])
        Ai[1] = np.array(
            [0, 0, 0, -xi_vector[0], -xi_vector[1], -1, xi_vector[0] * xi_prime_vector[1],
             xi_vector[1] * xi_prime_vector[1], xi_prime_vector[1]])
    
        assert (Ai.shape == (2, 9))
        return Ai

    -x & -y & -1 & 0 & 0 & 0 & ux & vy & uv \ 0 & 0 & 0 & -x & -y & -1 & ux & vy & uv \ \end

    def get_A(points_source, points_target): N = points_source.shape[0] A = np.zeros((2 * N, 9)) for i in range(len(points_target)): Ai = get_Ai(points_source[i], points_target[i]) A[2 * i:2 * i + 2] = Ai

     assert (A.shape == (2 * N, 9))
     return A
    
  2. SVD分解: 对矩阵 AA 进行奇异值分解(SVD),得到 A=UΣVTA = U \Sigma V^T 。取 VTV^T 矩阵的最后一行作为矩阵 hh

  3. Reshape: 将向量 hh reshape 为 3×33 \times 3 的单应性矩阵 HH

    def get_homography(points_source, points_target):
        A = get_A(points_source, points_target)
        _, _, Vt = np.linalg.svd(A)
        Homo = Vt[-1].reshape((3, 3))
        assert (Homo.shape == (3, 3))
        return Homo