OpenCV双目标定的流程

转载地址:

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,讲解得非常形象详尽。

还没看,待续。。。。

展开阅读全文

没有更多推荐了,返回首页