很多时候我们不知道摄像机的内参数矩阵,并且我们也不太关注内参数到底是多少,因为我们仅仅关心如何得到两幅图像的稠密匹配,或者两幅图像的差别——例如我们只想计算两幅图像的视差图,或者说得到两幅立体图像对的深度图就足够了。既然不知道摄像机的内参数,那么就只能借助对极约束来达到目的了。通过计算两幅图像的基础矩阵F,然后利用对极约束矫正极线为平行线的方法,可以很好的实现这个目标,该方法也被称为Hartly方法,在OpenCV中由cv::stereoRectifyUncalibrated函数实现。

立体图像的极线矫正需要三个步骤:

(1)提取特征点并匹配,参考http://blog.sina.com.cn/s/blog_4298002e01013w4z.html

(2)计算基本矩阵F,参考http://blog.sina.com.cn/s/blog_4298002e01013w9a.html

(3)极线矫正。

Hartly方法的函数原型如下:

//! computes the rectification transformation for an uncalibrated stereo camera (zero distortion is assumed)
CV_EXPORTS_W bool stereoRectifyUncalibrated( const Mat& points1, const Mat& points2,
                                             const Mat& F, Size imgSize,
                                             CV_OUT Mat& H1, CV_OUT Mat& H2,
                                             double threshold=5 );

该函数输入参数为两幅图像的匹配特征点,基本矩阵F以及图像的尺寸,返回的参数是两幅图像各自对应的单应变换矩阵H1和H2。只需要对两幅图像按照H1和H2做单应变换,即可得到矫正后图像。假设I为图像,变换如下:

I_recty = H*I

需要说明一点,该函数的前两个参数Mat& points1, Mat& points2与cv::findFundamentalMat的前两个参数并不是相同的数据结构。它们虽然可以是同一个匹配点集,但是他们的数据结构是完全不同的!cv::findFundamentalMat中传入的匹配点集要求是2xN或者Nx2的矩阵,但是cv::stereoRectifyUncalibrated中要求传入的匹配点集必须是1x2N或者2Nx1的矩阵!在很多文档中都说他们的参数是一样的,这其实是一个天大的错误,如果用计算F的匹配点集直接传给图像矫正函数,程序将直接崩溃。正确的做法是利用cv::Mat的构造函数,直接从vector<Point2f>构造一个cv::Mat传入。

cv::stereoRectifyUncalibrated函数默认原始图像是没有径向畸变的,因此在矫正图像之前,最好先对原始图像做径向矫正。

另外需要注意的一点,函数返回的单应变换矩阵H1和H2都是double类型,也即CV_64F类型,若不是该类型的矩阵,与之相乘会报错。下面是示例代码:

// 假设前面我们已经得到两幅图像的匹配特征点,并计算出了基本矩阵F,同时得到了匹配特征点的inlier

// Mat m_matLeftImage;
// Mat m_matRightImage;

// vector<Point2f> m_LeftInlier;
// vector<Point2f> m_RightInlier;

// Mat m_Fundamental;

// 计算图像矫正的单应变换矩阵

Mat m_LeftH;
Mat m_RightH;

stereoRectifyUncalibrated(Mat(m_LeftInlier), Mat(m_RightInlier), m_Fundamental,
                          Size(m_matLeftImage.cols, m_matLeftImage.rows),
                          m_LeftH, m_RightH);

// 任意指定一个内参数矩阵K,不会影响计算结果,此处设为单位阵。

Mat K = Mat::eye(3, 3, CV_64F); // 注意一定是double类型
Mat invK = K.inv(DECOMP_SVD);
Mat LeftR = invK*m_LeftH*K;     // 根据单应变换矩阵计算左图摄像机在空间中的变换矩阵R1
Mat RightR = invK*m_RightH*K;   // 计算右图摄像机在空间中的变换矩阵R2
Mat LeftMap1, LeftMap2;
Mat RightMap1, RightMap2;

Mat Distort;                    // 径向畸变为0,设为空矩阵
Size UndistSize(m_matLeftImage.cols, m_matLeftImage.rows);

// 计算左右两幅图像的映射矩阵

initUndistortRectifyMap(K, Distort, LeftR, K, UndistSize, CV_32FC1, LeftMap1, LeftMap2);
initUndistortRectifyMap(K, Distort, RightR, K, UndistSize, CV_32FC1, RightMap1, RightMap2);

// 把原始图像投影到新图像上,得到矫正图像

Mat m_LeftRectyImage;
Mat m_RightRectyImage;

remap(m_matLeftImage, m_LeftRectyImage, LeftMap1, LeftMap2, INTER_LINEAR);
remap(m_matRightImage, m_RightRectyImage, RightMap1, RightMap2, INTER_LINEAR);

// 显示结果

cvNamedWindow( "left image", 1);
cvShowImage("left image", &(IplImage(m_LeftRectyImage)));
cvNamedWindow( "right image", 1);
cvShowImage("right image", &(IplImage(m_RightRectyImage)));
cvWaitKey( 0 );
cvDestroyWindow( "left image" );
cvDestroyWindow( "right image" );

程序计算的结果如下图所示:

原始图像对:

极线矫正后的图像:

得到上面的矫正图像之后,就可以计算视差或者进行稠密匹配了。下面以视差计算的应用为例,分别用GC和SGBM算法计算视差,结果如下图:

SGBM算法:

GC算法:

OpenCV在未知相机内参数情况下的立体图像矫正方法相关推荐

  1. 机器视觉-相机内参数和外参数

    点击上方"小白学视觉",选择加"星标"或"置顶" 重磅干货,第一时间送达 1.相机内参数是与相机自身特性相关的参数,比如相机的焦距.像素大小 ...

  2. 计算机视觉-相机内参数和外参数

    1.相机内参数是与相机自身特性相关的参数,比如相机的焦距.像素大小等: 相机外参数是在世界坐标系中的参数,比如相机的位置.旋转方向等. 相机标定(或摄像机标定): 一句话就是世界坐标到像素坐标的映射, ...

  3. 发送端未知信道状态信息情况下MIMO系统容量仿真

    在发送端与接收端天线个数不同的情况下,MIMO系统的容量 clear all; close all; M=1000;%循环次数 n_bins=round(M/10);%round函数用于舍入到最接近的 ...

  4. python设计一个节假日字典_python实现在无须过多援引的情况下创建字典的方法

    本文实例讲述了python实现在无须过多援引的情况下创建字典的方法.分享给大家供大家参考.具体实现方法如下: 1.使用itertools模块 import itertools the_key = [' ...

  5. [css] 写出div在不固定高度的情况下水平垂直居中的方法?

    [css] 写出div在不固定高度的情况下水平垂直居中的方法? 我知道的有两种方法<!DOCTYPE html> <html><head><meta char ...

  6. [css] 写出在不固定宽高的元素在固定高度的情况下水平垂直居中的方法

    [css] 写出在不固定宽高的元素在固定高度的情况下水平垂直居中的方法 flex布局:还有就是可以用定位也可以实现等等: flex:父div:{display:flex: justify-conten ...

  7. mysql 并发避免锁表_Yii+MYSQL锁表防止并发情况下重复数据的方法

    本文实例讲述了Yii+MYSQL锁表防止并发情况下重复数据的方法.分享给大家供大家参考,具体如下: lock table 读锁定 如果一个线程获得在一个表上的read锁,那么该线程和所有其他线程只能从 ...

  8. 并发产生mysql锁表_Yii+MYSQL锁表防止并发情况下重复数据的方法

    本文实例讲述了Yii+MYSQL锁表防止并发情况下重复数据的方法.分享给大家供大家参考,具体如下: lock table 读锁定 如果一个线程获得在一个表上的read锁,那么该线程和所有其他线程只能从 ...

  9. 浅析不同情况下Docker的逃逸方法

    火线Zone社区(https://zone.huoxian.cn/) 一.Docker逃逸 1.docker daemon api未授权访问 漏洞原理:在使用docker swarm的时候,节点上会开 ...

最新文章

  1. 通信原理之IP协议,ARP协议 (三)
  2. 【数理知识】《随机过程》方兆本老师-目录
  3. 想要做服务类APP,先来看看独立商城系统开发方案
  4. 关于jquery的ajax编码的另类解决方案,巨简便
  5. bzoj2460: [BeiJing2011]元素
  6. php遍历文件夹及其子文件夹并计算所占的磁盘空间
  7. 计算机二进制怎么转化成十六进制数是,6、计算机进制之二进制、十进制、十六进制之间的转换...
  8. 桥牌笔记L4D17:小心阻塞
  9. python数据透视表对各列统计_python pandas数据分析基础入门2——(数据格式转换、排序、统计、数据透视表)...
  10. arcgis 经纬度转大地坐标_arcgis下平面坐标与大地坐标的转换
  11. 均值,期望和加权平均数理解和区分
  12. 代码分享:面波数据快速成图
  13. Java三部曲(二)JavaWeb
  14. nginx 正向代理http和https
  15. E12:后台管理系统开发-修改文章功能
  16. Go:测试库(GoConvey,testify,GoStub,GoMonkey)对比及简介
  17. iris接口返回json数据封装
  18. 社交平台上的“引流”黑色产业链:“假聊”获粉,精准割韭菜
  19. 数据仓库系列3-事实表
  20. Junction.exe 命令应用详解及下载

热门文章

  1. 数据科学家赚多少?数据全分析与可视化 ⛵
  2. 《香帅财富报告——分化时代的财富选择》Aphrodite Wealth Trends 香帅/著 读后感2021-02-13
  3. 全球数字出版格式大全A - [电子书] (转载)
  4. LVM 详细基本操作
  5. SemiBin宏基因组半监督分箱工具中GTDB数据的下载与配置
  6. 数钢筋软件,让您的工作变得更简单、更快捷
  7. 架构师如何应对复杂业务场景?领域建模的实战案例解析
  8. 2021-2022学年广州市白云广外附中九年级第一学期期中英语试题
  9. 光芯片上的全光脉冲神经网络
  10. 北大青鸟昌平校区:职业教育一定教的好他们!