独家|OpenCV110 使用OpenCV实现摄像头标定
作者:Kaustubh Sadekar Satya Mallick
翻译:陈之炎
校对:王可汗
本文约3200字,建议阅读5分钟
本文为大家系统地介绍了使用OpenCV实现摄像头标定。
摄像头是一种视觉传感器,它已经成为了机器人技术、监控、空间探索、社交媒体、工业自动化,甚至娱乐业等多个领域不可分割的组成部分。
在摄像头的多种应用中,了解摄像头的参数对于视觉传感器的有效使用至关重要。
在本文中,将阐述摄像头标定所涉及的步骤及其含义。
此外,文中还共享了棋盘格模式示例图像的C++和Python代码。
什么是摄像头标定?
对摄像头参数进行估计的过程称为摄像头标定。
通过摄像头标定,可以掌握摄像头的所有信息(参数或系数),从而可以确定现实世界中的三维点与摄像头捕获图像的二维投影(像素)之间的精确关系。
通常,摄像头标定意味着恢复以下两类参数:
1. 摄像头 /镜头系统的固有参数。如:镜头的焦距、光心和径向失真系数等参数。
2. 外部参数:这是指摄像头相对于某个世界坐标系的方向(旋转矩阵R和平移向量t)。
在下图中,采用了几何标定来估计透镜的参数,从而消除图像的失真。
对失真图像采用几何标定之后的效果
使用OpenCV实现摄像头标定
为了更好地理解整个标定过程,首先需要了解成像的几何特征。点击下面的链接来查看详细的解释。
成像的几何特征
正如前文所述,为了找出一个三维点在图像平面上的投影,首先需要使用外部参数(旋转矩阵R和平移向量t)将该点从世界坐标系转换到摄像头坐标系。
接下来,利用摄像头的固有参数,将该点投影到图像平面上。
将世界坐标中的三维点(Xw, YW,Zw)投影到图像坐标 (u、v)的关联方程如下所示:
其中,P是一个由两部分组成的3×4投影矩阵——包含固有参数的固有矩阵(K)、由3×3旋转矩阵R和3×1平移向量t组合而成的外部矩阵([R|t])。
如前文所述,固有矩阵是上三角矩阵
其中
fx,fy是x和y的焦距(通常二者是相同的)。
cx,cy是图像平面上光心的x、 y坐标,这一坐标通常用图像的中心来近似。
γ是各轴之间的斜度,通常为0。
摄像头标定的目的
摄像头标定的目的是:利用一组已知的3D点坐标(Xw, YW,Zw)及其相应的图像坐标(u、v)来找出3×3矩阵K、3×3旋转矩阵R和3×1平移向量t。当得出固有参数和外部参数的值之后,便实现了摄像头标定。
总之,摄像头标定算法应具备以下输入和输出:
1. 输入:已知二维图像坐标和三维世界坐标点的图像集合。
2. 输出:3×3摄像头固有矩阵,每幅图像的旋转矩阵和平移向量。
注:在OpenCV中,摄像头固有矩阵没有倾斜参数,所以该矩阵的形式为
多种类型的摄像头标定方法
有以下几种摄像头标定方法:
1. 模式标定:当能完全控制成像过程时,执行标定的最佳方法是从不同的角度捕捉一个物体或已知维度模式的多幅图像。本文中涉及到的基于棋盘格的方法属于这种标定。也可以使用已知尺寸的圆形模式来替代棋盘格模式。
2. 几何线索:有时场景中有如直线和消失点等其他的几何线索,可以利用于这些几何线索来进行标定。
3. 基于深度学习的标定:当对成像设置的控制很少时(例如:当只有一个场景的单一图像),可使用基于深度学习的方法获得摄像头的标定信息。
摄像头标定的步骤
标定过程的步骤可用下图中的流程图来解释。
下面,来看看这些步骤是如何实现的:
第1步:用棋盘格模式定义真实世界的坐标
世界坐标系:世界坐标系由附在房间里一面墙上的棋盘格图案来固定,三维点是棋盘格中正方形的拐角。上述棋盘格中的任何一个角都可以定为世界坐标系的原点。XW轴和YW轴沿墙移动,ZW轴垂直于墙移动。因此,棋盘格上的所有点都在XY平面上(即ZW=0)。
在标定过程中,通过一组已知的三维点(Xw, YW,Zw)及其在图像中相应的像素位置(u,v)来计算出摄像头的参数。
对于3D点,可以在许多不同的方向上拍摄一个已知尺寸的棋盘格图案。将世界坐标映射到棋盘格上,由于所有的角点都在一个平面上,可以任意选取ZW为0。由于各点在棋盘格中是等间隔的,可以将其中一个点设为参考点(0,0),这样,便很容易定义出每个三维点的坐标(XW,YW)。
为什么棋盘格图案在摄像头标定中应用如此之广?
棋盘格图案的独特之处是:在图像检测过程中,它很容易检测到。不仅如此,棋盘格上的正方形是定位的理想选择,因为它们在两个方向的梯度比较尖锐。此外,这些方格与它们在棋盘线的交叉点有关。所有这些特点,都有利于方便地定位出正方形的拐角。
绘制出检测到的棋盘板拐角坐标后的结果图
第2步:从多个不同的角度捕捉多个棋盘格图像
上述图像用于标定摄像头。
接下来,确保棋盘格为静态,并通过移动摄像头拍摄出多幅棋盘图像。
或者,也可以保持摄像头不动,拍摄不同方向的棋盘格图案,从数学的角度来看,这两种情况很类似。
第3步:找出棋盘格板的二维坐标
有了多幅棋盘格图像之后,世界坐标系上棋盘格上点的三维位置也已知,最后,需要找出的是图像在棋盘格上二维像素的位置。
3.1找出棋盘格的角
OpenCV提供了一个名为findChessboardCorners的内置函数,利用这个函数可以找出棋盘格中各个角的坐标。下面,来看看这一代码的用法:
C++
Python
其中:
根据是否检测到一个棋盘格模式,输出为真或假。
3.2调整棋盘格的角
良好的标定应完全满足精度的要求。为了获得良好的结果,应对各个角的位置进行调整,以获得亚像素级的精度。
OpenCV有一个 cornerSubPix函数,利用这个函数获取原始图像和棋盘格角的位置,并在原始位置的小范围内找出最佳的位置角度。该算法的本质是一个迭代过程,为此需要指定终止条件(如,迭代次数和/或精度)
C++
Python
其中
第4步:标定摄像头
摄像头标定的最后一步是:将世界坐标中的三维点及其在所有图像的二维位置传递给OpenCV的calibrateCamera 方法。这是基于张正友的一篇论文。数学上有点复杂,需要线性代数的背景知识。
来看看calibrateCamera方法的语法
C++
Python
其中
摄像头标定源代码
摄像头标定的Python和C++代码如下。利用下面的链接,下载所有的图像和代码则更为简单。
摄像头标定的Python代码
请仔细阅读代码的注释,它们对每一步都在做什么作了详细解释。
C++ 源代码
请通读每一条注释,以了解每一步都实现了什么。