美文网首页
透视变换

透视变换

作者: 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;
}

相关文章

  • opencv python版-lesson 11

    缩放,平移,旋转.仿射变换,透视变换

  • OpencvSharp-图像修正

    OpencvSharp 使用透视变换。

  • matlab

    透视变换 There is a transformPointsForward function that you ...

  • 透视变换之变换为鸟瞰图

    仿射变换:能够将平行四边形变换为另一个平行四边形透视变换:能够将平行四边形变换为梯形。仿射变换是透视变换的子集。 ...

  • 透视变换(补充)

    一 前言   之前在公众号中写过一篇文章——图像处理的仿射变换与透视变换,这篇文章是对透视变换做了进一步深入研究。...

  • OpenCV 透视变换

    平时在拍照片时难免不小心把照片拍歪了,这时候可以使用透视变换矫正拍歪的照片! 效果 源代码

  • 定位+透视变换

    https://www.cnblogs.com/little-monkey/p/7429579.html?tdso...

  • OpenCV实现图像的几何变换

    图像的几何变换 几何变换主要包括缩放、平移、旋转、仿射变换、透视变换和图像裁剪等。执行这些几何变换的两个关键函数是...

  • OpenGL ES(四) 变换

    基本变换:平移(translation)、旋转(roration)、缩放(scale)、透视(perspectiv...

  • 透视投影变换就是三维变换

    透视投影(Perspective Projection)变换推导[https://www.cnblogs.com/...

网友评论

      本文标题:透视变换

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