转载地址:
http://blog.csdn.net/chenyusiyuan/article/details/5967291
《1》首先应该阅读张正友大神的文章,对单目标定,都求解的是哪些参数,如何求的初始值,然后是如何带入到后面的L-M 优化中对参数refine的。
Zhang Z. A Flexible New Technique for Camera Calibration[J]. Tpami, 2000, 22(11):1330-1334.
Zhang Z. Flexible Camera Calibration by Viewing a Plane from Unknown Orientations[C]// The Proceedings of the Seventh IEEE International Conference on Computer Vision. IEEE, 2002:666-673 vol.1.
《2》然后阅读Learning OpenCV的中文版第十一章(单目),第十二章(双目),同时打开英文原版对照着一起阅读。因为中文版中有一些翻译读不太通顺,而且有的公式印刷错了,最好也在线打开OpenCV Documents,查看相应API 的解释,比如OpenCV-2.4.13.5 Docs
《3》阅读 OpenCV 源代码目录下 /samples/cpp 下的calibration.cpp(单目标定,矫正),stereo_calib.cpp(双目标定,矫正,校正), stereo_match.cpp(双目匹配,计算视差)
一些实践总结:
《1》单目标定:
a. 根据张论文在自己实现求单应阵 H时,在棋盘格上选择点时, 要保证能提供至少4个点,且这4个点不能有三点共线的情况,否则,实际上只有三个点有用。OpenCV中可以用RANSAC的思想计算鲁棒的H。
b. 每个标定版平面和每个成像平面存在一个H。求解相机参数,至少需要2帧图像(2帧时,除了构造AX=b 的方式和3帧以上的方式不一样,还有额外的假设),一般3帧以上。 将这n帧 H 联合起来解内参;
c. 内参求得后,带入到每个H中求得每帧的位姿R,T
d. 论文中求畸变时,是对K1,K2,构造的方程,类似的扩展到K3, p1, p2的也可以自己推导,思路一致。
《2》双目标定
a. 通过立体标定得到左右相机的外参R,T=[Tx,Ty,Tz]。设左,右相机的内参分别为 :
KL=[fx_l, 0, cx_l
0, fy_l, cy_l
0, 0, 1 ]
KR=[fx_r, 0, cx_r
0, fy_r, cy_r
0, 0, 1 ]
畸变系数各自为:distCoeffsL, distCoeffsR
Mat Rl, Rr, Pl, Pr, Q; Rect validRoi[2];
stereoRectify(cameraMatrix[0], distCoeffs[0],
cameraMatrix[1], distCoeffs[1],
imageSize, R, T, Rl, Rr, Pl, Pr, Q,
CALIB_ZERO_DISPARITY, 1, imageSize, &validRoi[0], &validRoi[1]);
最后由stereoRectify()函数输出的 Rl, Rr,Pl,Pr分别是 :
Rl:左相机和左虚拟相机的变换,只有旋转Rl,没有平移; 两个虚拟相机之间是共面,行对齐。
Rr:右相机和右虚拟相机的变换,只有旋转Rr,没有平移;
Rl, Rr是如下得来:
1. 把 R分解为两个旋转矩阵rl, rr,每个都旋转一半,rl, rr 满足: rr * rl=R //实际发现,rr,rl所在的轴角方向,与原来R所在的轴角方向不一致。
2. Eigen::Vector3d e1 = T.normalized();
Eigen::Vector3d e2 = Eigen::Vector3d(-T(1), T(0), 0);
e2.normalize();
Eigen::Vector3d e3 = e1.cross(e2);
Eigen::Matrix3d Rect, rl, rr;
Rect << e1.transpose(), e2.transpose(), e3.transpose();
RL=Rect* rl;
RR=Rect* rr;
Pl: 左虚拟相机的内参KL_virtual;
Pr: 右虚拟相机的内参KR_virtual;
KL_virtual=[f, 0 , cx1, 0
0, f, cy, 0
0, 0, 1, 0 ]
KR_virtual=[f, 0 , cx2, f*b
0, f, cy, 0
0, 0, 1, 0 ]
当 stereoRectify() 的标志位 flags=CALIB_ZERO_DISPARITY时, cx1=cx2, 深度值计算公式不变:
Z=f*b/d
当标志位不是上面的时,cx1 不等于cx2, 深度值计算公式修正为:
Z=f*b/(d-delta), delta=cx1-cx2
输出的Q:当flags=CALIB_ZERO_DISPARITY时, Q(3,3)=0
Q=[1, 0, 0, -cx1
0, 1, 0, -cy
0, 0, 0, f
0, 0, -1/b, (cx1-cx2)/b ]
实际发现:
OpenCV中返回的 Q(3,2)是 1/b,取了绝对值。
两个虚拟相机的基线b=normal(T)
b. 然后分别对原始左右相机计算映射阵
Mat rmap[2][2];
initUndistortRectifyMap( KL, distCoeffsL, Rl, Pl, imageSize, CV_16SC2, rmap[0][0], rmap[0][1]);
initUndistortRectifyMap( KR, distCoeffsR, Rr, Pr, imageSize, CV_16SC2, rmap[1][0], rmap[1][1]);
c.最后
Mat img = imread(raw_image, 0), rimg;
remap(img, rimg, rmap[0][0], rmap[0][1], CV_INTER_LINEAR);//对左图rectification
相应的用 rmap[1][0], rmap[1][1]对右图rectify 。
论文 “A Compact Algorithm for Rectification of Stereo Pairs” Andrea Fusiello · Emanuele Trucco · Alessandro Verri 也提出了一种计算rectify的方法,其中有几个地方备注:
OpenCV 和matlab中计算rectify的方法和上面论文中不一样,大致原理:Learning OpenCV 12章,具体细节详见 matlab工具箱中 rectify_stereo_pair.m。
Matlab Calibration ToolBox http://www.vision.caltech.edu/bouguetj/calib_doc/index.html
这样大致就对单应矩阵,本征矩阵,基础矩阵有了一个大致了解。从上面可以大致看来,对空间点3D位置估计的精确程度取决于该点深度值的计算,而深度值的计算主要依赖于双目匹配,或者叫立体匹配的精度,当然也依赖于前期标定过程中确定的相机内参,畸变参数,两个相机间R,T的精确程度。
http://vision.deis.unibo.it/~smatt/stereo.htm Stefano Mattoccia 的讲义 Stereo Vision: algorithms and applications,190页的ppt,讲解得非常形象详尽。
还没看,待续。。。。