透视变换原理推导及矩阵求解

4 篇文章 0 订阅

原理,推导过程

在这里插入图片描述

代码实现

#include <iostream>

#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>

#include <Eigen/dense>

/* 从原图中选取4个点,在目标图像中找出对应的想要映射到的4个点,
   根据这4对点列出8个方程求解出透视变换的8个参数(3点不共线) */

int main()
{
    /* 求解源图像到目标图像的透视变换矩阵,据源图上四个点src_pt到目标图像上的四个点dst_pt进行求解
       src_pt[0] --> dst_pt[0]
       src_pt[1] --> dst_pt[1]
       src_pt[2] --> dst_pt[2]
       src_pt[3] --> dst_pt[3] */
    cv::Point2f src_pt[] =
     { cv::Point2f(390,0),cv::Point2f(1250,0),cv::Point2f(1250,840),cv::Point2f(390, 840) };
    cv::Point2f dst_pt[] =
     { cv::Point2f(280,220),cv::Point2f(400,220),cv::Point2f(450,430),cv::Point2f(310, 410) };

    /* 方法一:根据透视变换的原理实现的透视矩阵的求解 */
    Eigen::MatrixXd m(8, 8);   // 线性方程组的系数
    for (int i = 0; i < m.rows(); ++i)
    {
        for (int j = 0; j < m.cols(); ++j)
        {
            if (i % 2 == 0)  // 偶数行
            {
                if (j <= 2)
                {
                    if (0 == j)
                    {
                        m(i, j) = src_pt[i / 2].x;
                    }
                    else if (1 == j)
                    {
                        m(i, j) = src_pt[i / 2].y;
                    }
                    else
                    {
                        m(i, j) = 1;
                    }
                }
                else if (j >=3 && j <= 5)
                {
                    m(i, j) = 0;
                }
                else
                {
                    if (6 == j)
                    {
                        m(i, j) = -src_pt[i / 2].x * dst_pt[i / 2].x;
                    }
                    else  // 7 == j
                    {
                        m(i, j) = -src_pt[i / 2].y * dst_pt[i / 2].x;
                    }
                }
            }
            else             // 奇数行
            {
                if (j <= 2)
                {
                    m(i, j) = 0;
                }
                else if (j >= 3 && j <= 5)
                {
                    if (3 == j)
                    {
                        m(i, j) = src_pt[i / 2].x;
                    }
                    else if (4 == j)
                    {
                        m(i, j) = src_pt[i / 2].y;
                    }
                    else
                    {
                        m(i, j) = 1;
                    }
                }
                else
                {
                    if (6 == j)
                    {
                        m(i, j) = -src_pt[i / 2].x * dst_pt[i / 2].y;
                    }
                    else   // 7 == j
                    {
                        m(i, j) = -src_pt[i / 2].y * dst_pt[i / 2].y;
                    }
                }
            }
        }
    }
    std::cout << m << std::endl;

    Eigen::MatrixXd dst_matrix(8, 1);
    for (int i = 0; i < dst_matrix.rows(); ++i)
    {
        if (i % 2 == 0)
        {
            dst_matrix(i, 0) = dst_pt[i / 2].x;
        }
        else
        {
            dst_matrix(i, 0) = dst_pt[i / 2].y;
        }
    }
    std::cout << "-----------------------------------" << std::endl;

    Eigen::MatrixXd perspective_matrix = m.inverse() * dst_matrix;  // 透视变换矩阵的8个参数
    std::cout << perspective_matrix << "\n-->" << std::endl;
    Eigen::MatrixXd ptmatrix_eigen(9, 1);
    int i = 0;
    for (; i < perspective_matrix.rows(); ++i)
    {
        ptmatrix_eigen(i, 0) = perspective_matrix(i, 0);
    }
    ptmatrix_eigen(i) = 1;
    std::cout << ptmatrix_eigen << std::endl;
    std::cout << "-----------------------------------" << std::endl;

    /* 方法二:直接调用OpenCV的API实现的透视矩阵的求解 */
    cv::Mat ptmatrix_cv = cv::getPerspectiveTransform(src_pt, dst_pt);
    std::cout << ptmatrix_cv << std::endl;

    /* 比较ptmatrix_eigen和ptmatrix_cv,可知求解结果一致 */
    // ... 省略比较过程,直接看打印结果

    /* 直接调用OpenCV的透视变换API进行图像变换,并可视化透视变换效果 */
    cv::Mat carton = cv::imread("../data/carton2.jpg");
    cv::Mat beauty = cv::imread("../data/beauty1.jpg");
    cv::Mat tmp;
    cv::warpPerspective(beauty, tmp, ptmatrix_cv, cv::Size(carton.cols, carton.rows));
    cv::Rect rect(280, 220, 170, 230);
    tmp(rect).copyTo(carton(rect));
    cv::imshow("perspective_carton", carton);
    cv::waitKey(0);

    return 0;
}
  • 2
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值