提起来双目定位,相信许多人像现在的我一样,紧紧会用现成的公式,理解一些定义,明白那些参数的含义,但是深入的来说,估计连张正友教授的标定算法都没有推明白。因为其中涉及一些矩阵运算的技巧,没有数学基础,或者基础不牢,都无法深度理解。搞双目两年了,以前就是生成一张深度图,或者进行一下双目测距,网上的代码复制粘贴修改一下就能用了,但是现在要搞高精度的双目视觉定位,就必须深挖下去,搞清楚成像光路的方方面面。这里,我提供一些网上总结比较好的博客给新来的朋友铺垫一下:https://www.cnblogs.com/zyly/p/9366080.html ;这篇博客不仅系统的讲解了成像坐标过程,而且在博文最后列举了一系列参考博客,感谢他把!“大奥特曼打小怪兽”;
今天,先说说镜头畸变吧,因为没有一个镜头没有不畸变的,不过是畸变的大小不同,例如你用4.3mm的摄像头(小型USB相机),基本上是平光镜头,其他的规格的,你就不能不考虑镜头畸变了。如果你搞搞深度图,测测距离,基本也没事那些都是低精度的,误差大点无所谓,了不起用个张正友标定法,或者Matlib双目标定一下,精度就不错了。但是如果你要搞精密测量,纠结mm及的精度,那些方法就总是不能满足你了。比如现在就不能满足我了!怎么办,深挖技术细节,找到根!
张氏标定法的伟大,在于将标定过程简化到打印一张A4纸的棋盘格就能获得比较高的精度,在摄影测量相机标定场总不能还贴A4纸吧!但是,但是,我们还可以用张正友标定法!不过是更加认真的考虑各个因素的用这个方法处理标定问题。这就是方法创新的意义!
说了这么多多余的话,就是为了抛出两个相机标定的函数:OPENCV函数:
【A】CV_EXPORTS_AS(calibrateCameraExtended) double calibrateCamera( InputArrayOfArrays objectPoints,
InputArrayOfArrays imagePoints, Size imageSize,
InputOutputArray cameraMatrix, InputOutputArray distCoeffs,
OutputArrayOfArrays rvecs, OutputArrayOfArrays tvecs,
OutputArray stdDeviationsIntrinsics,
OutputArray stdDeviationsExtrinsics,
OutputArray perViewErrors,
int flags = 0, TermCriteria criteria = TermCriteria(
TermCriteria::COUNT + TermCriteria::EPS, 30, DBL_EPSILON) );
这个【A】函数,是一个支持分析标定的函数,输出的参数中给出了评估结果。
【B】CV_EXPORTS_W double calibrateCamera( InputArrayOfArrays objectPoints,
InputArrayOfArrays imagePoints, Size imageSize,
InputOutputArray cameraMatrix, InputOutputArray distCoeffs,
OutputArrayOfArrays rvecs, OutputArrayOfArrays tvecs,
int flags = 0, TermCriteria criteria = TermCriteria(
TermCriteria::COUNT + TermCriteria::EPS, 30, DBL_EPSILON) );
这个【B】函数,与【A】仅有功能区别。
以下是一些关于这两个函数怎么用的介绍,直接从OPENCV函数翻译过来的,翻译有误差,这里说一下自己的理解:
1.InputArrayOfArrays objectPoints
这个objectPoints 就是所用的棋盘格角点的世界坐标,当然这里由你用的标定板给出。当然你如果自建标定规则要,注意他的数据类型是std :: vector <std :: vector <cv :: Vec3f >>,这意味着你照相多少次就生成多少次,其中的z坐标都为0;2.InputArrayOfArrays imagePoints
这个imagePoints顾名思义就是在图像中提取棋盘格的角点的像点坐标,注意这是个数据类型是std :: vector <std :: vector <cv :: Vec2f >>,这个给你照相那些坐标都对照,一一对应
3. InputOutputArray cameraMatrix
这个好说就是相机内参数矩阵,可以初始化也可以不,与你后面选择的计算模式有关系。
4.InputOutputArray distCoeffs
这个就是今天的重点,畸变参数。可以是4,5,8,12或14个元素。一般大家都用5参数,一般精度这个就够了。至于高精度时候是不是参数越多越好,有人说多了容易不稳定,这一点我可以肯定的告诉你,对于描述一个模型参数越多肯定会越好,你想想现在的深度学习,那个网络模型参数不是成千上万!但是,但是,你参数多你需要拍的图像就越多,而且你的标定场要建的的好!如果还拿个A4纸当标定板,那就每必要设那么多参数了。想想为啥?你的数据质量都不构,怎么平差解方程!所以,这个地方就是一个分水领,不过对于一般计算机视觉需求,5个参数也就差不多了。
5. OutputArrayOfArrays rvecs,6.OutputArrayOfArrays tvecs
这两个参数是标定过程中以标定板为参考,相机的旋转、平移参数,想想Matlib标定过程中最后给你一个镜头的大致方向显示。
7.OutputArray stdDeviationsIntrinsics 8.OutputArray stdDeviationsExtrinsics 9.OutputArray perViewErrors
这些个参数是对这次标定结果的评价,值越小代表你标定的越好。
10. int flags = 0,
flags这个参数一般都设成0了,技巧也就在这里。按说一般要精密标定,一般都要标定好几次。控制一些置信度较高的参数不变,然后解算其他的。如果畸变参数选用过的不是5参数模型,则这个设置参考函数解释。
11.TermCriteria criteria = TermCriteria(TermCriteria::COUNT + TermCriteria::EPS, 30, DBL_EPSILON)
这个设置是一个计算迭代的设置,一般不改变。如果高精度标定,也要好好研究一下,第一个参数是类型就是计算迭代的终止条件,第二个是迭代次数,第三个是设置的阈值。默认的意思是迭代终止条件看后面的两个参数,最大迭代次数30,最小阈值是DBL_EPSILON。
标定函数技术细节如此,如有见解欢迎讨论,个人目前研究方向精密视觉测量!
参考如下:
/ ** @brief从校准图案的多个视图中查找相机的内部和外部参数。
@param objectPoints在新界面中,它是校准模式点矢量的矢量
校准模式坐标空间(例如std :: vector <std :: vector <cv :: Vec3f >>)。外面的
vector包含与模式视图的数量一样多的元素。如果校准模式相同
在每个视图中显示并且它是完全可见的,所有向量将是相同的。虽然如此
可以使用部分遮挡的图案,甚至不同视图中的不同图案。然后,
向量将是不同的。这些点是3D,但由于它们处于图案坐标系中,
那么,如果钻机是平面的,那么将模型放到XY坐标平面上是有意义的
每个输入对象点的Z坐标为0。
在旧界面中,来自不同视图的对象点的所有向量被连接
一起。
@param imagePoints在新界面中,它是校准投影向量的向量
模式点(例如std :: vector <std :: vector <cv :: Vec2f >>)。 imagePoints.size()和
objectPoints.size()和imagePoints [i] .size()必须等于每个i的objectPoints [i] .size()。
在旧界面中,来自不同视图的对象点的所有向量被连接
一起。
@param imageSize仅用于初始化内在相机矩阵的图像大小。
@param cameraMatrix输出3x3浮点相机矩阵
\ f $ A = \ vecthreethree {f_x} {0} {c_x} {0} {f_y} {c_y} {0} {0} {1} \ f $。如果CV \ _CALIB \ _USE \ _INTRINSIC \ _GUESS
和/或CV_CALIB_FIX_ASPECT_RATIO被指定,fx,fy,cx,cy中的部分或全部必须是
在调用函数之前初始化。
@param distCoeffs失真系数的输出向量
\ f $(k_1,k_2,p_1,p_2 [,k_3 [,k_4,k_5,k_6 [,s_1,s_2,s_3,s_4 [,\ tau_x,\ tau_y]]]])\ f $ of
4,5,8,12或14个元素。
@param rvecs为每个模式视图估计的旋转矢量的输出矢量(参见Rodrigues)
(例如std :: vector <cv :: Mat >>)。也就是说,每个第k个旋转矢量与相应的一起
第k个平移向量(参见下一个输出参数描述)带来校准模式
从模型坐标空间(指定了对象点)到世界坐标
空间,即第k个模式视图中校准图案的实际位置(k = 0 .. * M * -1)。
@param tvecs为每个模式视图估计的平移向量的输出向量。
@param stdDeviationsIntrinsics为内在参数估算的标准差的输出向量。
偏差值的顺序:
\ f $(f_x,f_y,c_x,c_y,k_1,k_2,p_1,p_2,k_3,k_4,k_5,k_6,s_1,s_2,s_3,
s_4,\ tau_x,\ tau_y)\ f $如果没有估计其中一个参数,它的偏差等于零。
@param stdDeviationsExtrinsics对外部参数估计的标准差的输出向量。
偏差值的顺序:\ f $(R_1,T_1,\ dotsc,R_M,T_M)\ f $其中M是模式视图的数量,
\ f $ R_i,T_i \ f $连接1x3向量。
@param perViewErrors为每个模式视图估计的RMS重新投影误差的输出向量。
@param flags可能为零的不同标志或以下值的组合:
- ** CV_CALIB_USE_INTRINSIC_GUESS ** cameraMatrix包含有效的初始值
fx,fy,cx,cy进一步优化。否则,(cx,cy)最初设置为图像
中心(使用imageSize),并以最小二乘方式计算焦距。
注意,如果已知内部参数,则不需要仅使用此函数
估计外在参数。请改用solvePnP。
- ** CV_CALIB_FIX_PRINCIPAL_POINT **全局期间主要点未更改
优化。它停留在中心或指定的不同位置
CV_CALIB_USE_INTRINSIC_GUESS也已设置。
- ** CV_CALIB_FIX_ASPECT_RATIO **函数仅将fy视为自由参数。该
比率fx / fy保持与输入cameraMatrix相同。什么时候
未设置CV_CALIB_USE_INTRINSIC_GUESS,fx和fy的实际输入值为
忽略,只计算它们的比率并进一步使用。
- ** CV_CALIB_ZERO_TANGENT_DIST **设置切向失真系数\ f $(p_1,p_2)\ f $
为零并保持为零。
- ** CV_CALIB_FIX_K1,...,CV_CALIB_FIX_K6 **相应的径向失真
优化期间系数不变。如果CV_CALIB_USE_INTRINSIC_GUESS是
设置,使用提供的distCoeffs矩阵的系数。否则,它被设置为0。
- ** CV_CALIB_RATIONAL_MODEL **启用系数k4,k5和k6。提供
向后兼容性,应该明确指定这个额外的标志来制作
校准函数使用有理模型并返回8个系数。如果标志不是
设置,该函数仅计算并返回5个失真系数。
- ** CALIB_THIN_PRISM_MODEL **启用系数s1,s2,s3和s4。
为了提供向后兼容性,应该明确指定这个额外的标志来制作
校准功能使用薄棱镜模型并返回12个系数。如果标志不是
设置,该函数仅计算并返回5个失真系数。
- ** CALIB_FIX_S1_S2_S3_S4 **薄棱镜失真系数在此期间不会改变
优化。如果设置了CV_CALIB_USE_INTRINSIC_GUESS,则系数来自
提供了distCoeffs矩阵。否则,它被设置为0。
- ** CALIB_TILTED_MODEL **系数tauX和tauY已启用。提供
向后兼容性,应该明确指定这个额外的标志来制作
校准功能使用倾斜传感器模型并返回14个系数。如果标志不是
设置,该函数仅计算并返回5个失真系数。
- ** CALIB_FIX_TAUX_TAUY **倾斜传感器模型的系数在此期间不会改变
优化。如果设置了CV_CALIB_USE_INTRINSIC_GUESS,则系数来自
提供了distCoeffs矩阵。否则,它被设置为0。
@param criteria迭代优化算法的终止标准。
该函数估计两个制作立体声对的相机之间的转换。如果你有一个立体声
摄像机,两个摄像机的相对位置和方向是固定的,如果你计算
相对于第一相机和第二相机(R1,T1)和(R2,T2)的物体姿势,
分别(这可以用solvePnP完成),那些姿势肯定是彼此相关的。
这意味着,给定(\ f $ R_1 \ f $,\ f $ T_1 \ f $),应该可以计算(\ f $ R_2 \ f $,\ f $ T_2 \ f $)。只有你
需要知道第二台摄像机相对于第一台摄像机的位置和方向。这是
所述功能的作用。它计算(\ f $ R \ f $,\ f $ T \ f $),以便:
\ F [R_2 = R * R_1
T_2 = R * T_1 + T,\ f]
可选地,它计算基本矩阵E:
\ f [E = \ vecthreethree {0} { - T_2} {T_1} {T_2} {0} { - T_0} { - T_1} {T_0} {0} * R \ f]
其中\ f $ T_i \ f $是翻译向量的组成部分\ f $ T \ f $:\ f $ T = [T_0,T_1,T_2] ^ T \ f $。而且功能
也可以计算基本矩阵F:
\ f [F = cameraMatrix2 ^ { - T} E cameraMatrix1 ^ { - 1} \ f]
除了立体声相关信息,该功能还可以执行每个的完整校准
两个相机。但是,由于参数空间的高维度和输入中的噪声
数据,该功能可以偏离正确的解决方案。如果内在参数可以
每个摄像机单独估算高精度(例如,使用
calibrateCamera),建议您这样做,然后将CV_CALIB_FIX_INTRINSIC标志传递给
函数以及计算的内部参数。否则,如果所有参数都是
一次估计,限制一些参数是有意义的,例如,通过
CV_CALIB_SAME_FOCAL_LENGTH和CV_CALIB_ZERO_TANGENT_DIST标志,通常是
合理的假设。
与calibrateCamera类似,该功能最大限度地减少了所有的重新投影误差
指向两个摄像头的所有可用视图。该函数返回的最终值
重新投影错误。
* /