轉載地址:
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,講解得非常形象詳盡。
還沒看,待續。。。。