美文网首页
透视变换

透视变换

作者: leon_tly | 来源:发表于2024-05-07 16:29 被阅读0次

    透视变换原理及求解推导

    透视变换(Perspective Transformation)是将二维的图片投影到一个三维视平面上,然后再转换到二维坐标下,所以也称为投影映射(Projective Mapping)。简单来说就是二维 → 三维 → 二维的一个过程。
    矩阵形式表示
    \begin{bmatrix} a_{11}&a_{12}&a_{13}\\ a_{21}&a_{22}&a_{23}\\ a_{31}&a_{32}&a_{33}\\ \end{bmatrix} * \begin{bmatrix} x\\ y\\ 1\\ \end{bmatrix} = \begin{bmatrix} X\\ Y\\ Z\\ \end{bmatrix}
    其中\begin{bmatrix} a_{11}&a_{12}\\ a_{21}&a_{22}\\ \end{bmatrix} 表示线性变换
    其中\begin{bmatrix} a_{31}&a_{32} \end{bmatrix} 表示透视变换
    其余表示平移变换
    通过除以Z轴将三维坐标转换为二维坐标Z=a_{31}x + a_{32}y + a_{33}
    x^{'} = \frac{X}{Z} = \frac{a_{11}x + a_{12}y + a_{13}}{a_{31}x + a_{32}y + a_{33}}
    y^{'} = \frac{Y}{Z} = \frac{a_{21}x + a_{22}y + a_{23}}{a_{31}x + a_{32}y + a_{33}}
    其中a_{33} = 1
    有8个未知数,因此需要原图上的4个点和目标图上的4个点来构成8个方程来求解变换矩阵。
    x^{'} = \frac{X}{Z} = \frac{a_{11}x + a_{12}y + a_{13}}{a_{31}x + a_{32}y + 1}
    ({a_{31}x + a_{32}y + 1}) x^{'} = a_{11}x + a_{12}y + a_{13}
    a_{11}x + a_{12}y + a_{13} - {a_{31}xx^{'} - a_{32}yx^{'}} = x^{'}
    同理得到
    a_{21}x + a_{22}y + a_{23} - {a_{31}xy^{'} - a_{32}yy^{'}} = y^{'}

    当有(x_{0}, y_{0}), (x_{1}, y_{1}), (x_{2}, y_{2}), (x_{3}, y_{3})(x^{'}_{0}, y^{'}_{0}), (x^{'}_{1}, y^{'}_{1}), (x^{'}_{2}, y^{'}_{2}), (x^{'}_{3}, y^{'}_{3}) 8个点时可以得到方程

    \begin{cases} a_{11}x_{0} + a_{12}y_{0} + a_{13} - {a_{31}x_{0}x_{0}^{'} - a_{32}y_{0}x_{0}^{'}} = x_{0}^{'}\\ a_{21}x_{0} + a_{22}y_{0} + a_{23} - {a_{31}x_{0}y_{0}^{'} - a_{32}y_{0}y_{0}^{'}} = y_{0}^{'}\\ a_{11}x_{1} + a_{12}y_{1} + a_{13} - {a_{31}x_{1}x_{1}^{'} - a_{32}y_{1}x_{1}^{'}} = x_{1}^{'}\\ a_{21}x_{1} + a_{22}y_{1} + a_{23} - {a_{31}x_{1}y_{1}^{'} - a_{32}y_{1}y_{1}^{'}} = y_{1}^{'}\\ a_{11}x_{2} + a_{12}y_{2} + a_{13} - {a_{31}x_{2}x_{2}^{'} - a_{32}y_{2}x_{2}^{'}} = x_{2}^{'}\\ a_{21}x_{2} + a_{22}y_{2} + a_{23} - {a_{31}x_{2}y_{2}^{'} - a_{32}y_{2}y_{2}^{'}} = y_{2}^{'}\\ a_{11}x_{3} + a_{12}y_{3} + a_{13} - {a_{31}x_{3}x_{3}^{'} - a_{32}y_{3}x_{3}^{'}} = x_{3}^{'}\\ a_{21}x_{3} + a_{22}y_{3} + a_{23} - {a_{31}x_{3}y_{3}^{'} - a_{32}y_{3}y_{3}^{'}} = y_{3}^{'}\\ \end{cases}
    写成矩阵形式则有
    \begin{bmatrix} x_{0} & y_{0} & 1 & 0 & 0 & 0 & -x_{0}x_{0}^{'} & -y_{0}x_{0}^{'}\\ 0 & 0 & 0 & x_{0} & y_{0} & 1 & -x_{0}y_{0}^{'} & -y_{0}y_{0}^{'}\\ x_{1} & y_{1} & 1 & 0 & 0 & 0 & -x_{1}x_{1}^{'} & -y_{1}x_{1}^{'}\\ 0 & 0 & 0 & x_{1} & y_{1} & 1 & -x_{1}y_{1}^{'} & -y_{1}y_{1}^{'}\\ x_{2} & y_{2} & 1 & 0 & 0 & 0 & -x_{2}x_{2}^{'} & -y_{2}x_{2}^{'}\\ 0 & 0 & 0 & x_{2} & y_{2} & 1 & -x_{2}y_{2}^{'} & -y_{2}y_{2}^{'}\\ x_{3} & y_{3} & 1 & 0 & 0 & 0 & -x_{3}x_{3}^{'} & -y_{3}x_{3}^{'}\\ 0 & 0 & 0 & x_{3} & y_{3} & 1 & -x_{3}y_{3}^{'} & -y_{3}y_{3}^{'}\\ \end{bmatrix} * \begin{bmatrix} a_{11} \\ a_{12}\\ a_{13}\\ a_{21}\\ a_{22}\\ a_{23}\\ a_{31}\\ a_{32}\\ \end{bmatrix} = \begin{bmatrix} x_{0}^{'} \\ y_{0}^{'}\\ x_{1}^{'}\\ y_{1}^{'}\\ x_{2}^{'}\\ y_{2}^{'}\\ x_{3}^{'}\\ y_{3}^{'}\\ \end{bmatrix}

    高斯消元法求解代码

    struct Point{
        float x;
        float y;
    };
    
    
    static std::vector<std::vector<float>> getPerspectiveTransform(const std::vector<Point>& src, const std::vector<Point>& dst) 
    {
        std::vector<std::vector<float>> A(8, std::vector<float>(8, 0));
        std::vector<float> b(8, 0);
        
        // 矩阵赋初始值
        for (int i = 0; i < 4; ++i) {
            A[i * 2][0] = src[i].x;
            A[i * 2][1] = src[i].y;
            A[i * 2][2] = 1.0;
            A[i * 2][6] = -src[i].x * dst[i].x;
            A[i * 2][7] = -src[i].y * dst[i].x;
    
            A[i * 2 + 1][3] = src[i].x;
            A[i * 2 + 1][4] = src[i].y;
            A[i * 2 + 1][5] = 1.0;
            A[i * 2 + 1][6] = -src[i].x * dst[i].y;
            A[i * 2 + 1][7] = -src[i].y * dst[i].y;
    
            b[i * 2] = dst[i].x;
            b[i * 2 + 1] = dst[i].y;
        }
    
        std::vector<float> x(8);
        for (int i = 0; i < 8; ++i) {
            x[i] = b[i];
        }
    
        for (int i = 0; i < 8; ++i) {
            int pivot = i;
            for (int j = i + 1; j < 8; ++j) {
                if (std::abs(A[j][i]) > std::abs(A[pivot][i])) {
                    pivot = j;
                }
            }
            // 按照列循环,将该列中值比较大的行向上交换
            std::swap(A[i], A[pivot]);
            std::swap(x[i], x[pivot]);
            // 消除主元
            for (int j = i + 1; j < 8; ++j) {
                float factor = A[j][i] / A[i][i];
                for (int k = i; k < 8; ++k) {
                    A[j][k] -= factor * A[i][k];
                }
                x[j] -= factor * x[i];
            }
        }
        // 求解
        std::vector<float> H(9);
        for (int i = 7; i >= 0; --i) {
            float sum = 0;
            for (int j = i + 1; j < 8; ++j) {
                sum += A[i][j] * H[j];
            }
            H[i] = (x[i] - sum) / A[i][i];
        }
        H[8] = 1.0;
    
        std::vector<std::vector<float>> transform(3, std::vector<float>(3));
        for (int i = 0; i < 3; ++i) {
            for (int j = 0; j < 3; ++j) {
                transform[i][j] = H[i * 3 + j];
            }
        }
    
        return transform;
    }
    
    

    相关文章

      网友评论

          本文标题:透视变换

          本文链接:https://www.haomeiwen.com/subject/mfzrfjtx.html