imuncle / imuncle.github.io

大叔的个人小站
https://imuncle.github.io/
78 stars 17 forks source link

基于DSCM模型的鱼眼相机标定程序 #116

Open imuncle opened 2 years ago

imuncle commented 2 years ago

鱼眼镜头因其较大的畸变而难以标定,对鱼眼镜头的畸变建模也是多种多样,相机模型的一些重要时间节点如下:

  1. 透视模型:于2000年,Zhang贡献(编码为RTCM=Radial Tangential Camera Model)。
  2. 开创理论:于2000年,Geyer和Daniilidis提出UCM(Unified Camera Model)成像模型,可用于建模平面、抛物、椭圆及双曲反射相机。
  3. 完善理论:于2001年,Barreto和Araujo优化UCM成像模型,从而简化了标定算法的开发。
  4. 理论向工程过渡:于2006年,Scaramuzza和Martinelli及Siegwart基于泰勒展开式提出用多项式来近似所有成像模型。
  5. 等距模型:于2006年,Kannala和Brandt贡献(编码为KBCM)。
  6. 开创工程:于2007年,Mei和Rives融合径向切向畸变到UCM成像模型(编码为MUCM),解决UCM建模鱼眼镜头差的问题。
  7. 优化工程:于2013年,Heng和Li及Pollefeys。
  8. 完善工程:于2016年,Khomutenko和Garcia及Martinet提出EUCM(Extended Unified Camera Model)成像模型,解决了UCM径向畸变和建模鱼眼镜头差的问题及MUCM非闭环解问题。
  9. 完善工程:于2018年,Usenko和Demmel及Cremers提出DSCM(Double Sphere Camera Model)成像模型,相对于EUCM、MUCM、KBCM等算法,在精度和速度上取得了折中。

目前也有很多工具库都支持鱼眼模型,比如MATLAB中使用的是Scaramuzza模型,OpenCV中使用的是KB模型,最近OpenCV中还加入了新的omni的标定,使用的是MUCM模型,kalibr使用的是DSCM模型。这些模型的精度对比如下图所示:

image

从上图可以看出,DSCM模型可以使用较少的参数量达到与其他8参数模型非常相近的精度,具有非常大的优势。但目前支持DSCM模型的标定工具只有kalibr,这个工具是基于ROS的,需要采集一段视频并使用rosbag录制,非常不方便,而它的代码又是C++套python,写的比较复杂,很难直接把DSCM标定相关的代码抽离出来,于是我就决定自己写一个DSCM的标定工具。

1、棋盘检测

出于方便考虑,我采用的还是棋盘格标定板。由于鱼眼成像畸变很大,像OpenCV里的棋盘格检测算法肯定是用不了了,因为OpenCV里的棋盘格检测算法是基于四边形的,而鱼眼图像里棋盘格已经很难看做是四边形了。这里我采用的是我2020年暑假的工作,当时我把MATLAB中的棋盘检测算法用OpenCV移植到了C++,MATLAB中的棋盘格检测算法是这篇论文算法的简化版,速度比原论文更快,这篇论文里的棋盘生长是基于局部梯度方向的,所以即使是畸变很大的棋盘格也能检测出来,具体的可以参考论文。

2、单目相机参数初始化

众所周知,相机标定最后都会落到非线性优化上,但非线性优化往往需要一个比较好的初始值,这样才能得到一个比较好的优化结果。与张正友标定法类似,初始值基本都是使用解析解,这就需要对相机模型有一个比较清晰的认识。DS模型的原论文中并没有详细的描述相机模型,只是给出了一张示意图和最后的投影方程,这里我按照我的理解描述一下。

image

如上图所示,球面1对应的是真正的鱼眼镜头,所以O点对应的是相机坐标系的原点,假设入射光线是从P点发出的,设P点的坐标为(x,y,z),|OP|的长度为 image 该光线的成像过程如下:

image

另外回顾整个成像过程,会发现DS模型的兼容性也比较强,当ξ=0时,DS模型转化为UCM,进一步的,当α=ξ=0时,转化为针孔模型。

内参初始化步骤参考的是这篇论文这篇论文,为简单起见,先假设ξ=0,α=0.5,f_x=f_y=γ,c_x c_y是图像中心,设归一化像平面上一点为(x,y,1),则反投影得到的入射光线方向向量为: image 归一化像平面与像素平面之间的关系为 image 于是有 image image

根据上面的流程,我们就可以完成相机内外参的初始化,剩下的便是非线性优化了。我选择使用ceres-solver来进行非线性优化,优化目标就是最小化重投影误差。Ceres使用起来非常方便,只需要对每张图片中的每个角点构建对应的重投影误差函数即可。

3、多目相机的外参标定

多相机标定流程分为两步:第一步是每个相机单独标定,第二步是多个相机联合标定。第一步使用单目相机的标定算法,可以得到相机的内参和相对于每个棋盘格的外参,第二步则是先利用第一步的外参结果对所有的棋盘格和相机外参进行初始化,然后再基于最小化重投影误差进行非线性优化。 这里要多说一句,相机的外参指的是世界坐标系在相机坐标系下的位姿,因此对于单目相机标定得到的外参来说,其实改变的是世界坐标系,不变的是相机坐标系,因此各个相机的外参对应的坐标系是不一样的,需要统一坐标系,一般将世界坐标系与第一个相机的坐标系重合,也就是说,第一个相机的外参矩阵为[I 0]。 image image

4、总结

相机标定最难的地方就在于参数的初始值计算,这一步骤需要根据相机的投影模型做一些推导,同时还要对模型参数做一些简化,不然推导起来较为困难。一般标定方法对应的论文里都会有最后的推导结果,只需要照着公式写代码就行了。非线性优化部分则直接使用开源的工具包,得益于ceres的自动求导功能,无需去计算繁琐的导数,只需要构造重投影误差项即可自动完成优化。

最后我的相机标定代码开源在这里了,里面我还写了一个简单的可视化界面,可以初步判断多目相机外参是否正确。

goofegg commented 2 years ago

大神,跑到你窝里来涂画了,gitblog主页的帖子有浏览数的显示功能么? 还有你可知道国内的博客可有能md批量下载和上传这样备份和克隆博客的?CSDN、cnblogs之类的可以么?

imuncle commented 2 years ago

@goofegg

gitblog主页的帖子有浏览数的显示功能么?

没有

国内的博客可有能md批量下载和上传这样备份和克隆博客的?CSDN、cnblogs之类的可以么?

不太清楚,应该没有

goofegg commented 2 years ago

issue页面里怎么嵌入视频啊?比如mp4扩展名的