点击上方“小白学视觉”,选择加"星标"或“置顶”
重磅干货,第一时间送达
相机和距离传感器的标定是机器人和计算机视觉领域中非常重要的基础问题之一。虽然MATLAB和OpenCV里都有对应的工具箱或者库函数,可以直接用来做相机标定,但如果需要同时标定多个相机(比如多目机器人、阵列相机),那这些传统的标定法将消耗掉研究者和开发者的大量时间和精力。
有没有一种省心的、全自动化的标定方法呢?
这里介绍一种可以实现全自动化对相机-相机、相机-距离传感器之间进行标定的方法,并且有论文和源码哦(见文末)!例如,该算法可以实现同时对三目相机 + 激光扫描仪(下图左)、双目相机 + Kinect (下图右)的标定。是不是觉得很赞!
角点检测方法对比
这种全自动化标定方法比较复杂,本文重点介绍一下该方法在棋盘格角点检测方面的原理。
我们知道棋盘格中角点检测方法是相机标定中重要的步骤之一。比如Opencv中的函数findChessboardCorners 就可以轻松实现棋盘格角点检测结果。如下图所示:
那为什么这里还要研究棋盘格角点检测呢?直接调函数不就OK了吗?
这是因为OpenCV函数虽然简单易用,但是在实际使用中,存在不少问题,这里列举几个:
需要提前指定棋盘格的行数列数作为输入。
需要多次拍摄获得多张不同方向角度的棋盘格图片进行标定。
鲁棒性差。棋盘格不能有干扰,否则就会使得角点检测失败,而且棋盘倾斜角度较大也会检测失败。
无法同时进行多个相机的标定。
本文的角点检测方法可以解决上述问题,主要体现在:
不需要提前指定棋盘格行数列数。
标定过程只需要拍摄一张包含多个棋盘的图片。
鲁棒性好。因为是基于生长的算法,所以如果出现干扰,就会绕过干扰,生长出最大的棋盘。
标定精度很高。
适用范围广。包括针孔相机、鱼眼相机、全景相机等。
基于生长的棋盘格角点检测原理
本文棋盘格角点检测算法主要分三个步骤:定位棋盘格角点位置;亚像素级角点和方向的精细化;优化能量函数、生长棋盘格。下面分别详细介绍。
1
定位棋盘格角点位置
要处理的图片中一般会包含很多非棋盘的自然或人工背景,所以第一步就是定位角点的位置。下图是角点检测原理示例。
首先定义两种不同的角点原型。一种用于和坐标轴平行的角点(上图a),另一种用于旋转45°的角点(上图b)。根据实践经验可以发现,这两种简单的原型对于由透视变换引起的较大范围的变形的角点检测来说,已经足够。每个原型由4个滤波核{A,B,C,D}组成,用于后面和图像进行卷积操作。然后利用这两个角点原型来计算每个像素点与角点的相似程度(Corner likelihood),这里称之为角点概率。
我们得到的角点概率图虽然能够给出大致的角点范围,但是如何进一步得到角点精确的位置呢?下一步就是在角点概率图上利用非极大值抑制(non-maxima-suppression,NMS)来获得候选点。
那么何为非极大值抑制呢?
非极大值抑制顾名思义就是抑制不是极大值的元素,搜索局部的极大值。这个局部代表的是一个邻域,邻域有两个参数可变,一是邻域的维数,二是邻域的大小。这里我们用NMS来选取那些邻域里分数最高的极大值像素点,同时抑制那些分数低的像素点。
然后用梯度统计的方法在一个局域的n x n邻域内验证这些候选点(上图e)。先对局域灰度图进行sobel滤波,然后计算加权方向直方图(32bins),用mean shift算法找到其中的两个主要的模态α1,α2,。根据边缘的方向,对于期望的梯度强度:
构造一个模板T:
(*表示互相关操作符)和角点概率图的乘积作为角点得分(Corner score),然后用阈值进行判断就得到了角点(上图f)。
2
亚像素级角点和方向的精细化
但是上面得到的角点一般不是很精确,需要进一步对角点的位置以及边缘方向进行亚像素级精细化处理。
假设c是理想的角点位置,p是c的局部邻域的一个像素点,gp是p点的图像梯度向量,那么就有:
简单解释一下上式。原因如下图:中心绿色的点表示理想角点c,假如像素点p不在边界上,如下图标号为1的位置,平坦区域梯度gp为零向量,所以上式成立;假如像素点p在边界上,如下图标号为2的位置,梯度gp向量方向垂直向下,(p-c)方向水平向左,两向量方向互相垂直,所以上式仍成立。
上图是理想情况下棋盘格,但是实际上边缘不可能这样锐利(只有一个像素大小),梯度方向也没有这么理想,最理想的角点c的位置就是我们在角点候选点c’的邻域Ni(c’)内找到满足以下式子的c’:
邻域的像素通过梯度幅值自动加权,上述式子右侧对c’求导并令其等于0,可以得到解析解:
下一步就是refine边缘方向矢量e1,e2,可以通过最小化normals的偏差和对应的梯度实现:
3
优化能量函数生长棋盘格
定义棋盘格的能量函数如下:
其中第一项E_corners是当前棋盘中角点总数的负值。第二项E_structure描述了用两个相邻角点来预测第3个角点的匹配程度,分别对棋盘的每行和每列相邻的3个角点(triples)计算其结构能量,取其中的最大值作为该棋盘的结构能量。
值得注意的是,由于结构能量约束中使用的是局域的线性约束,上述棋盘格生长方法可以扩展到鱼眼镜头拍摄的高畸变图像。
不难发现,计算量和棋盘大小呈现指数关系,当棋盘尺寸较大时,计算量会非常惊人。所以在求解时不能使用穷举法搜索,在此使用的是一种离散优化策略,在实践中证明比较有效。具体过程见上图(a)。
解释一下:
给定一个种子角点,我们沿着其边缘方向搜索产生一个初始化的种子棋盘格。该棋盘格有3x3个角点,有2x2个棋盘(见上图(a)中最左侧)。然后以此种子棋盘格为基础,分别从最外沿的4个边缘去生长棋盘格,生成4个新的棋盘格proposals。如果其中能量最小的那个棋盘格的能量值比棋盘格扩展前的能量更减少了,就说明生长成功,用这个新的棋盘格代替原来棋盘格。继续生长,直到4个 方向新棋盘格能量不再减少为止。上图(c)是最终的检测结果。
另外,为了在单张图片中生长出多个棋盘格,我们把每个角点都尝试作为种子点用上述方法去生长,这样会产生多个重叠的棋盘格。我们只保留能量函数最小的那个作为最终的结果,其他的重叠部分去掉即可。
关于优化部分不再 介绍,这部分可以参考文末的论文。
先来欣赏一下该方法的结果吧,棋盘格生长结果如下图所示。
结构恢复和棋盘匹配结果如下图所示。最上面的一行是单目广角和鱼眼相机标定图像;中间一行是双目相机和Kinect相机标定图;最下面一行是三目相机和Velodyne HDL 64线激光扫描仪标定图。
总结讨论
本文介绍的全自动化标定方法的优势:
1、可以同时计算多相机的内参、外参,以及相机-距离传感器之间的变换矩阵,时间在一分钟内
2、算法在不同的光照条件下仍然鲁棒
3、标定过程完全不需要人工干预,真正全自动化
本文算法有什么缺点吗?
该算法受限于棋盘格的约束,所以当棋盘被部分遮挡时,检测结果就不尽如人意。如下图,算法找到的棋盘格是在其约束条件下最好的结果。但是左下方的棋盘因为是次优的所以被忽略掉。这在鱼眼相机标定中非常不利。因为鱼眼镜头越靠近边缘畸变越大,越难以被检测到,但是却对计算标定参数越重要。下一篇我再介绍其他的棋盘格角点检测方法,可以解决这个问题。
论文及源码
本文算法对应的参考论文:
Geiger A, Moosmann F, Car Ö, et al. Automatic camera and range sensor calibration using a single shot[C]//Robotics and Automation (ICRA), 2012 IEEE International Conference on. IEEE, 2012: 3936-3943.
本文算法工程及源码:
http://www.cvlibs.net/software/libcbdetect/
本文算法在线标定toolbox:
http://www.cvlibs.net/software/calibration/
好消息!
小白学视觉知识星球
开始面向外开放啦👇👇👇
下载1:OpenCV-Contrib扩展模块中文版教程
在「小白学视觉」公众号后台回复:扩展模块中文教程,即可下载全网第一份OpenCV扩展模块教程中文版,涵盖扩展模块安装、SFM算法、立体视觉、目标跟踪、生物视觉、超分辨率处理等二十多章内容。
下载2:Python视觉实战项目52讲
在「小白学视觉」公众号后台回复:Python视觉实战项目,即可下载包括图像分割、口罩检测、车道线检测、车辆计数、添加眼线、车牌识别、字符识别、情绪检测、文本内容提取、面部识别等31个视觉实战项目,助力快速学校计算机视觉。
下载3:OpenCV实战项目20讲
在「小白学视觉」公众号后台回复:OpenCV实战项目20讲,即可下载含有20个基于OpenCV实现20个实战项目,实现OpenCV学习进阶。
交流群
欢迎加入公众号读者群一起和同行交流,目前有SLAM、三维视觉、传感器、自动驾驶、计算摄影、检测、分割、识别、医学影像、GAN、算法竞赛等微信群(以后会逐渐细分),请扫描下面微信号加群,备注:”昵称+学校/公司+研究方向“,例如:”张三 + 上海交大 + 视觉SLAM“。请按照格式备注,否则不予通过。添加成功后会根据研究方向邀请进入相关微信群。请勿在群内发送广告,否则会请出群,谢谢理解~