初学OpenCV学习记录(九)

以下内容摘自OpenCV2计算机视觉编程手册

引言

本章的内容主要是估算图像间的投影关系,包括对相机的内参矩阵和外参矩阵进行标定,计算不同视角的两张图片的基础矩阵,利用基础矩阵进行图像匹配和视角只进行旋转时候的单应矩阵计算。

相机标定

图像是由3D的场景投影到2D的平面,因此,场景中实际物体的三维坐标与它在图像中的二维像素有关系,这个关系就是我们对相机标定得到的内参和外参矩阵,这种关系是投影几何学的基础投影关系,在计算机视觉中也会使用。
基本原理:
定义3D参考坐标系原点为相机的投影中心(焦点),Z轴垂直于成像平面,Z轴穿透图像平面的像素位置称为主点,通常情况下主点为与图像平面中心,但实际会偏移几个像素,X轴与Y轴与图像平面的x轴y轴分别平行。
定义2D像素点坐标系就是图像平面的坐标系,原点位于图像左上角。坐标系定义如图所示。
在这里插入图片描述

根据针孔相机模型的投影等式,如果在场景中有一点他的坐标为 ( X , Y , Z ) (X,Y,Z) (X,Y,Z),那么他在图像中的像素坐标为:
在这里插入图片描述

其中, s s s为缩放因子,如果我们要将三维点坐标变为2D坐标时候就需要去除它的影响(怎么去除书中没有说明)。
第一个矩阵就是内参矩阵,第二个矩阵就是外参矩阵,外参矩阵是由一个3 * 3的旋转矩阵和3*1的平移向量组成的,为什么这么说呢?因为,当参考坐标系不位于相机的投影中心时,比如说我把坐标系定义在了一个物体上,那么外参矩阵的作用就是把3D坐标先转化到我们上面定义的参考坐标系上(这个参考坐标系和物体上的参考坐标系不一样),把坐标系定义在了一个物体上不同的视角的外参矩阵是不一样,当然,内参矩阵是一样的。
标定的步骤如下(书中有具体的代码,这里简单叙述一下):

  • 我们要先准备一个棋盘,从不同视角不同距离拍摄10~20幅图像。
  • 创建两个向量分别保存棋盘中角点(内部的顶点)的三维坐标和二维坐标,三维坐标是自己设置的,Z坐标为0,X轴与Y轴与网格对齐,比如第一个角点的坐标是(0,0,0),第二个就是(0,1,0),二维坐标可以由函数获得,循环打开拍摄每一幅图像,使用cv::findChessboardCorners()函数得到角点,为了获取更精确的像素坐标,借助cv::cornerSubPix()函数和cv::TermCriteria()函数获取亚像素精度的坐标并且保存在向量中。
  • 获取到足够多棋盘图像的3D/2D点对后,使用cv::calibrateCamera()函数可以得到内参矩阵和外参矩阵,还能获得畸变矩阵,因为透镜会导致畸变(直线在图像中曲线),数码相机畸变较小。
  • 标定后,使用cv::initUndistortRectifyMap()得到消除畸变需要的x坐标和y坐标的映射函数,这个工作只需要在标定以后做一次就可以,后续可以使用cv::remap函数为每一张拍摄的相片消除畸变。

计算一对图像的基础矩阵

基础矩阵研究的是不同视角下相同场景图像之间的投影关系,两张图片可以是同一个相机在不同视角下拍的,也可以是不同相机在不同视角下拍的。
基本概念:
如图所示:
在这里插入图片描述

如果我们已知一个图像中某点的像素坐标,想在另一张图片中找到对应点,应该怎么做呢?假设有一个3D点,我们首先连接3D点X与左边相机的中心得到一条上图中的直线,那3D点在左边相机中形成的像素点就在这条直线上,假如这条直线是真实存在的,那么他也会映射在右边相机中,我们要在右边相机的图片中找到相对应的像素点,就要在映射的这条直线上进行搜索,我们把这条虚构的直线叫做点x的极线。
极线描述了双视角系统的几何结构,所有的极线都会穿过同样一个点,我们称为极点,代表另一个相机中心在该相机上的投影点。
图像上的像素点与另一个图像上的极线之间的关系如下所示:
在这里插入图片描述

左边向量代表了极线的方程在这里插入图片描述
。矩阵 F F F即为基础矩阵。
使用方法:

  • cv::findFundementalMat()函数可以计算基础矩阵,输入参数为两幅图像匹配的特征点(比如之前的Surf特征点)
  • cv::computeCorrespondEpilines()函数可以计算像素点在另一个图片中的极线。

可以看到,基础矩阵是根据特征点计算出来的,因此,匹配的特征点的质量决定了计算结果的精度,选取的特征点应该在图像间均匀分布,并且包含场景中不同深度的点。
实际上,已知像素点 p p p,可以用基础矩阵找到在另一个视角图像中的极线,但并不能直接找到 p p p点在另一个视角图像中的对应点 p ′ p' p,但是根据基础矩阵,我们能够推出这两个点之间的关系为 p ′ F p = 0 p'Fp=0 pFp=0,这个关系成为极性约束,利用这个约束我们就可以优化两个图像之间匹配的特征点,就是我们接下来要介绍的内容。

使用随机采样一致性算法(RANSAC)进行图像匹配

使用双视角的极性约束优化匹配的特征点,可以是SURF特征,也可以是别的特征方法。
基本原理:匹配两幅图像之间的特征点以后,计算基础矩阵,根据基础矩阵将不满足极性约束的特征点剔除。这里存在一个问题,基础矩阵要用高质量特征点计算,而有了基础矩阵以后才能优化特征点,这是一个先有鸡还是先有鸡蛋的问题,这个问题可以使用RANSAC算法解决。
匹配过程如下(代码较为复杂,具体见书,这里只做总结):

  • 检测特征点,提取特征描述子,匹配特征描述子,使用匹配器对象的knnMatch方法对每个特征点找两个匹配点(与上一章不同),同时要进行双向匹配,在图1中找图2的对应点,在图2中找图1的对应点。
  • 提高匹配质量。一方面,对于每个特征点,都有两个候选匹配点,并且有对应的距离,如果一个的距离值和另一个距离值相差很大,那么我们就取距离值小的这个作为最优匹配点,如果相差不大,选择其一可能出错,两个匹配值都拒绝,另一方面,我们同时提取出图1到图2的特征点对和图2到图1特征点对的交集,这种方法成为对称性匹配策略
  • 基于RANSAC算法计算基础矩阵,计算基础矩阵的方法仍然为cv::findFundementalMat(),只不过某一个参数要选为CV_FM_RANSAC,表示使用了RANSAC算法,RANSAC算法的基本原理是随机选取一些匹配对,然后用他们来估算基础矩阵,因为错误的匹配数量一定比较少,所以很大概率得到正确的基础矩阵,基于基础矩阵我们可以判断那些匹配点满足极性约束,并把满足的匹配点组成这个基础矩阵的支持集合,然后反复执行这一过程,最后选取支持集合最大的那个基础矩阵,那么这个矩阵很大概率是准确的。
  • findFundementalMat()同时匹配点中哪些点是不符合极性约束的,我们将这些点去除,再次使用findFundementalMat()函数,这次就不需要使用RANSAC算法,得到的基础矩阵就是我们的结果矩阵。

计算两幅图之间的单应矩阵

在前面介绍相机标定的时候,我们知道2D点的坐标与3D点之间的矩阵关系是3 * 3的内参矩阵与3 * 4的外参矩阵的乘积,如果两个视图之间只有旋转关系而没有平移,那么外参矩阵就是一个3 * 3的旋转矩阵,于是2D点的坐标与3D点坐标之间的关系可以用一个3 * 3的矩阵表示,我们称为单应矩阵,关系如下所示:
在这里插入图片描述

单应矩阵 H H H同样也是使用特征点进行估计的,方法也是RANSAC算法,使用的函数为cv::findHomography(),得到单应矩阵以后,我们可以用cv::warpPerspective函数将其中一个视角的图片转化到另一个视角下,当然输出图像的尺寸一定要变大。

猜你喜欢

转载自blog.csdn.net/weixin_42411702/article/details/123933446