OpenCV-透视变换及对二维点求透视变换之后的坐标

36 篇文章 31 订阅

OpenCV-透视变换及对二维点求透视变换之后的坐标

微信公众号:幼儿园的学霸
个人的学习笔记,关于OpenCV,关于机器学习, …。问题或建议,请公众号留言;

目录

前言

基本原理

OpenCV透视变换函数代码

前言

  在做车道线检测中用到了透视变换的一点内容,用于将相机拍摄的图像转换到道路平行的视角下,即鸟瞰图,然后在鸟瞰图中进行车道线检测。
  如图1、图2所示分别为相机拍摄的原始图像和逆透视变换后的图像,一般来说逆透视变换后的两条车道线应该是平行的,此处不平行应是透视变换矩阵没有选好,在实际项目中发现没有影响,毕竟图2中过滤掉了大部分杂乱线段。此处对逆透视变换内容进行记录,方便日后查找。

图1 原始图像

图1 原始图像


图2 鸟瞰图

图2 鸟瞰图

 

基本原理

  透视变换(Perspective Transformation)是将成像投影到一个新的视平面(Viewing Plane),也称作投影映射(Projective Mapping)。如图3,通过透视变换ABC变换到A'B'C'。

图3 透视变换示意

图3 透视变换示意


  透视变换通用公式为:

其中为源图像的像素坐标,为源图像变换后的点所对应的像素坐标。透视变换矩阵可以拆程如下4个部分:

,表示图像的线性变换,比如scaling,shearing和ratotion,产生透视变换,用于平移。
  根据透视变换的通用公式,可以得到透视变换的数学表达式为:


从上面的计算公式可以看到,透视变换部分是其分母,而线性变换和平移部分是作为分子存在的。
  因此,给定透视变换对应的四对点坐标,可以求得透视变换矩阵;反之,给定透视变换矩阵,也可以对图像或者坐标点完成透视变换。

 

OpenCV透视变换函数

在我所写车道线检测代码中,透视变换部分用到了以下3个函数

//用于求得透视变换的变换矩阵,
//src::源图像上的四个顶点坐标
//dst::src的坐标在目标图像上的对应坐标
//返回值:3X3的透视变换矩阵
//在车道线检测代码中作用:得到将原始图转换到鸟瞰图的转换矩阵
cv::Mat getPerspectiveTransform(const Point2f* src, const Point2f* dst)
//求得点/点数组在经过变换矩阵m后的对应坐标
//src:目标点,如鸟瞰图中的坐标
//m:src到dst的转换矩阵
//dst:src经过m转换后的对应点
在车道线检测代码中作用:将鸟瞰图中的车道线坐标转换到原始视图下的像素作弊码
void perspectiveTransform(InputArray src, OutputArray dst, InputArray m ) 
 //对图像进行透视变换
//src:输入图像
//dst:输出图像
//M:变换矩阵,如getPerspectiveTransform函数得到的矩阵
//dsize:目标图像的大小
//flags:目标图像的插值方法
//borderMode:外推方法
//borderValue:常量边界时使用
//在车道线检测代码中作用:
//   1.将原始图像转换到鸟瞰图中,进行车道线检测;
//   2.将鸟瞰图转换到原始视图下,以进行结果展示等
void warpPerspective(InputArray src, OutputArray dst, InputArray M, Size dsize, int flags=INTER_LINEAR, int borderMode=BORDER_CONSTANT, const Scalar& borderValue=Scalar())

代码

代码示例如下。该代码流程为:
1.通过4对点计算透视变换矩阵T;
2.利用T对图像进行逆透视变换得到鸟瞰图;
3.将鸟瞰图下的车道线坐标转换到正常视图下;
该流程和我项目中的流程一致,但展示的代码比较简单,仅做示例。
如图4所示为鸟瞰图下的车道线,图5位转换到原始视图视角下的车道线。

图4 鸟瞰图及其车道线

图4 鸟瞰图及其车道线


图5 原始视图及其车道线

图5 原始视图及其车道线


具体代码:

 

//====================================================================//
// Created by liheng on 19-2-12.
//Program:将逆透视变换后的坐标点转换到原图中
//Data:2019.2.12
//Author:liheng
//Version:V1.0
//====================================================================//

#include <iostream>
#include <opencv2/opencv.hpp>
#include <opencv2/imgproc/types_c.h>

int main()
{
    //首先读入图像
    cv::Mat srcImage = cv::imread("../pictures/000177.png",cv::IMREAD_GRAYSCALE);

    //定义源点和目标点,源点为正常读入的图像的点,目标点为转换后的鸟瞰图上的对应点
    cv::Point2f srcPoints[4],dstPoints[4];
    srcPoints[0] = cv::Point2f(369,375);
    srcPoints[1] = cv::Point2f(545,221);
    srcPoints[2] = cv::Point2f(650,221);
    srcPoints[3] = cv::Point2f(793,375);

    dstPoints[0] = cv::Point2f(339,375);
    dstPoints[1] = cv::Point2f(339,211);
    dstPoints[2] = cv::Point2f(823,211);
    dstPoints[3] = cv::Point2f(823,375);

    //1°求解变换矩阵
    cv::Mat m_persctiveMat = cv::getPerspectiveTransform(srcPoints,dstPoints);//读入图像转换为鸟瞰图的矩阵
    cv::Mat m_unPersctiveMat =cv::getPerspectiveTransform(dstPoints,srcPoints);//鸟瞰图到原始图像的转换矩阵

    //2°求解鸟瞰图
    cv::Mat birdViewImage;
    cv::warpPerspective(srcImage,birdViewImage,m_persctiveMat,cv::Size(srcImage.cols,srcImage.rows),cv::INTER_LINEAR);


    //鸟瞰图车道线上的两点.Note:此处为了简单,仅选择2点进行变换
    std::vector<cv::Point2f> leftLine,rightLine;
    leftLine.push_back(cv::Point2f(661,0));
    leftLine.push_back(cv::Point2f(366,376));

    rightLine.push_back(cv::Point2f(1097,0));
    rightLine.push_back(cv::Point2f(883,376));

    //3°求解其在原始图像上对应的坐标
    std::vector<cv::Point2f> unWarpedLeftLine,unWarpedRightLine;
    cv::perspectiveTransform(leftLine,unWarpedLeftLine,m_unPersctiveMat);
    cv::perspectiveTransform(rightLine,unWarpedRightLine,m_unPersctiveMat);

    //线段可视化
    cv::cvtColor(srcImage,srcImage,CV_GRAY2BGR);
    cv::line(srcImage,unWarpedLeftLine[0],unWarpedLeftLine[1],cv::Scalar(0,255,0),2);
    cv::line(srcImage,unWarpedRightLine[0],unWarpedRightLine[1],cv::Scalar(0,255,0),2);

    cv::cvtColor(birdViewImage,birdViewImage,CV_GRAY2BGR);
    cv::line(birdViewImage,leftLine[0],leftLine[1],cv::Scalar(0,255,0),2);
    cv::line(birdViewImage,rightLine[0],rightLine[1],cv::Scalar(0,255,0),2);

    cv::imshow("srcImage",srcImage);
    cv::imshow("birdViewImage",birdViewImage);
    cv::waitKey(0);


    return 0;
}


下面的是我的公众号二维码图片,欢迎关注。

图注:幼儿园的学霸

图注:幼儿园的学霸

 

 

  • 7
    点赞
  • 57
    收藏
    觉得还不错? 一键收藏
  • 7
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值