介绍
标定相机可以说是计算机视觉开发者必会的技能了,实现起来也很容易。首先是采集几组不同姿态的棋盘格或者圆点标定板图像,然后用OpenCV写几行代码或者直接用Matlab的标定工具箱,从图像中检测出标定板特征点后,再用张正友标定法求解相机参数。
这种标定方案虽然简单实用,但也存在一些问题。一是要保证标定板在各个姿态下都能被很好的照明,以提高标定板检测成功率。二是要保证拍摄时标定板的完整性,这使得想要把相机边缘畸变标定好,还是需要花费很多功夫的。
本文分享一个笔者在先前项目中实现的一个标定方案,解决上述标定方案中存在的问题。读者如果有定制标定方案的需求,可以私信跟笔者进一步沟通。
特征点选择
做标定方案,首先面临的问题,是选择什么样的图案作为标定板的特征点。常用的有棋盘格角点和圆点,更高级的还有三角网格、同心圆等。相比棋盘格角点,圆点特征点检测更为精准,能更好的应对失焦、相机噪声等问题,但是在透视变形、相机畸变影响下,容易产生中心点定位偏差。虽然使用反透视变换、迭代标定、同心圆等方案可以解决定位偏差的问题,但代码实现上比较复杂。棋盘格检测角点实现起来就比较容易,有OpenCV的代码可以参考。角点对透视变形、相机畸变更加鲁棒,虽然不能很好的应对失焦、相机噪声等问题,但新的检测算法在面对这些问题时的效果已经有了不少的改进提升。所以综合考虑,选择了用棋盘格角点作为特征点。

不完整标定板检测
为了使相机边缘畸变能够被很好地标定,需要在拍摄到部分标定板的情况下,实现标定板的检测。可以在标定板上加上一些特殊编码点,实现这一目的。极致的方案是对标定图案的每个位置都做编码,这样可以保证在拍摄到标定板任意局部区域的时候都可以正确解码,找到正确的特征点坐标。但做项目不是搞科研,没有必要给自己增加太多难度。最终用了一个简单的方案,在标定板中心添加四个圆点作为编码点。只要保证中心圆点能够被完整拍摄,就能对标定板进行正确检测。下图是所设计的标定板图案。

照明
为了使标定板照明均匀,使用了透视式的标定板。包含背光灯、匀光板、玻璃基板、以及打印有标定图案的菲林膜。这种带背光的设计使得相机在任意姿态下都可以捕获高质量的标定板图案。笔者定制的背光包含可见光和940nm波段两个波段,可以对可见光相机或红外相机进行标定。由于可见光背光灯同时也包含了一点850nm波段的成分,所以850nm的红外相机也是可以用可见光背景进行标定的。下图是使用手机拍摄的标定板点亮背光的图片。

棋盘格和标定板尺寸
棋盘格的尺寸主要根据相机的分辨率、焦距、工作距离确定。笔者在确定棋盘格尺寸时,在Blender中根据实际的相机参数进行了仿真,以免尺寸过小,相机在远距离无法分辨,或者尺寸过大,相机拍摄到的特征点太少。下图是Blender仿真和生成的仿真图片示意。


标定板尺寸需要权衡考量。需要足够大,最好在设计的标定板使用距离段内,能覆盖相机大部分FOV,这样能够更好的标定边角畸变,同时减少标定姿态提高效率。又不能太大,否则成本高,平整性不好保证,移动起来也不方便。
检测算法实现
虽然调用OpenCV或者Matlab实现标定板检测很容易,但它们所提供的函数只能识别完整的标定板图案,一但有缺失就无法检测。而笔者的标定板在设计时就是为了在非完整拍摄下使用,因此只能自己来写检测算法。笔者的检测算法主要包含三个核心步骤。
- 棋盘格角点检测。
- 圆点检测。
- 标定板生长。
棋盘格角点检测
棋盘格角点检测部分的代码主要参考OpenCV findChessboardCornersSB函数实现。findChessboardCornersSB是OpenCV4新引入的棋盘格角点检测函数,可以直接获得亚像素角点坐标,对噪声的鲁棒性和对大尺寸图像的检测速度相比之前的findChessboardCorners有很大提升。对这个函数检测原理感兴趣的话可以参考笔者博客【OpenCV findChessboardCornersSB 算法原理与函数使用】。
感谢OpenCV开源,笔者把findChessboardCornersSB函数中用于检测角点的代码单独提取了出来,舍去了标定板生长部分的代码。这样既保证了角点的检测质量,又降低了笔者从零实现的工作量。
圆点检测
圆点检测部分比较简单,直接调用OpenCV的SimpleBlobDetector函数。这是一个快速的圆点检测算法,对图像进行二值化,根据设定的形态学参数(如尺寸范围、圆度等),输出检测出斑点的形心。这个算法并没有补偿圆点透视变形导致形心与中心偏离,不过由于我们的圆点主要用于辅助棋盘格角点世界坐标的判定,这个缺点并不会对标定质量产生影响。
标定板检测
标定板检测主要是为了将棋盘格角点像素坐标跟世界坐标对应。
首先,检测圆点标识。
- 根据图像坐标,对检测到的圆点进行简单过滤,留下图像中心区域的点。
- 计算圆点到其它圆点的距离。根据设计,中心圆点应另外三个圆点距离一致,且直径与此三个点的距离呈一定比例,据此设定阈值可以过滤得到中心圆点和用于标识方向三个圆点。
- 根据三圆点共线和另外一个圆点所处直线的上下位置,判定得到另外三个圆点的世界坐标。
然后,检测中心圆点四周的四个角点。由四个标识圆点的像素坐标,估算中心四个角点的像素坐标,找到最接近估算坐标的角点,并用阈值进行卡控确保正确。
最后,标定板生长。
- 建立一个二维布尔标识矩阵,用于记录角点世界坐标是否被找到。建立两个队列,一个队列记录所有已找到的世界坐标的角点,一个队列保存为找到世界坐标的角点。
- 将初始的四个角点坐标加入已找到队列,并在标识矩阵中设置为true。
- 对于已找到队列中的点,如果左侧点已被找到,且右侧点未被找到,则估算右侧点像素坐标,在余下角点中找到最近且满足阈值卡控的点。如果此点存在,则将此点在标识矩阵中标记为true,移出未找到队列,加入已找到队列。对其余三个方向进行类似的操作。
- 对于已找到队列中新加入的点,重复步骤3中的过程,直到没有新的点加入已找到队列。
下图是实际拍摄的标定板图像检测效果,检测质量很稳定,没有世界坐标的误匹配。

标定算法实现
由于相机不同姿态检测出的角点数量不一致,笔者使用了自己写的标定算法实现相机标定,具体可以参考笔者博客【张正友标定法解析与C++代码实现】。仿真图像和实际图像的标定结果如下。实拍图像的重投影误差0.13像素,相比仿真的0.06偏大,主要是因为实拍图像的清晰度和信噪比不如仿真图像。


2347

被折叠的 条评论
为什么被折叠?



