一點(diǎn)標(biāo)定_攝像機(jī)標(biāo)定和立體標(biāo)定
本文關(guān)鍵詞:標(biāo)定,由筆耕文化傳播整理發(fā)布。
嘗試用OpenCV來(lái)實(shí)現(xiàn)立體視覺(jué)也有一段時(shí)間了,主要的參考資料就是Learning OpenCV十一、十二章和OpenCV論壇上一些前輩的討論。過(guò)程中磕磕碰碰,走了不少?gòu)澛,終于在前不久解決了最頭大的問(wèn)題,把整個(gè)標(biāo)定、校準(zhǔn)、匹配的流程調(diào)試成功。(雖然還有一些問(wèn)題至今尚未搞清)
在這里寫(xiě)這篇文章,第一方面是給自己一個(gè)總結(jié),第二方面是感覺(jué)OpenCV立體視覺(jué)方面的資料還是相當(dāng)零散和不完整,新手入門(mén)需要花很長(zhǎng)時(shí)間才能摸索出來(lái),第三方面,也是自己在過(guò)程中有些問(wèn)題仍舊迷迷糊糊,希望可以拋磚引玉。
1. 攝像頭
我用的攝像頭是淘寶上買(mǎi)的三維攝像頭,兩個(gè)USB Camera加一個(gè)可調(diào)節(jié)的支架。實(shí)物照片如下
1.1 三維攝像頭實(shí)物圖
雙USB攝像頭的OpenCV驅(qū)動(dòng)可以參考以下鏈接
使用DirectShow采集圖像
將上面代碼復(fù)制到自己的工程之后還需要對(duì)工程或者編譯環(huán)境做一下設(shè)置
VC6下的詳盡設(shè)置可以見(jiàn)代碼的注釋(修改工程的屬性)
VS2008中的設(shè)置也可以參照代碼注釋中VC++2005的設(shè)置(修改編譯環(huán)境)
2. 標(biāo)定
由于OpenCV中cvStereoCalibrate總是會(huì)得到很夸張的結(jié)果(見(jiàn)下文5.1問(wèn)題描述),所以最后還是決定用Bouguet的Matlab標(biāo)定工具箱立體標(biāo)定,再將標(biāo)定的結(jié)果讀入OpenCV,來(lái)進(jìn)行后續(xù)圖像校準(zhǔn)和匹配。
Matlab標(biāo)定工具箱的參考鏈接如下:
上面有詳細(xì)的使用步驟,用起來(lái)相當(dāng)?shù)姆奖恪?/p>
以下是我個(gè)人用Matlab工具箱進(jìn)行立體標(biāo)定的步驟,供參考,如果需要更詳細(xì)步驟的話還是參照上面的鏈接
把Matlab工具箱的文件copy到對(duì)應(yīng)目錄下,把所要標(biāo)定的棋盤(pán)圖也放到.m文件所在的目錄下,然后在Matlab命令行窗口中打入calib_gui,選擇Standard之后便出現(xiàn)以下窗口
2.1. calilb_gui面板
我們先對(duì)右攝像頭的標(biāo)定,所以先把從右攝像頭上采集到的棋盤(pán)圖復(fù)制到工具箱目錄下。
點(diǎn)擊Image names, 命令行窗口會(huì)提示你輸入圖片的basename以及圖片的格式(比如你圖片文件名是right1, right2, …, right10,basename就是right),然后Matlab會(huì)自動(dòng)幫你讀入這些圖片,如下圖所示,可以看到,讀入了10幅右攝像頭的棋盤(pán)圖。
采集棋盤(pán)圖的時(shí)候要注意,盡量讓棋盤(pán)占據(jù)盡可能多的畫(huà)面,這樣可以得到更多有關(guān)攝像頭畸變方面的信息
2.2. 圖像basename讀入
2.3. 讀入的棋盤(pán)圖
然后再回到主控制界面,點(diǎn)擊Extract grid corners,提取每幅圖的角點(diǎn)
2.4. calib_gui面板
點(diǎn)擊完后,命令行會(huì)出現(xiàn)如下提示,主要是讓你輸入棋盤(pán)角點(diǎn)搜索窗口的大小。窗口定的大一點(diǎn)的話提取角點(diǎn)會(huì)比較方便點(diǎn)(即便點(diǎn)得偏離了也能找到),但也要注意不能大過(guò)一個(gè)方格的大小。剩下的兩個(gè)選項(xiàng),只要回車(chē)選用默認(rèn)設(shè)置就可以了
2.5. 選擇窗口大小
然后就開(kāi)始了角點(diǎn)的提取工作,按一定順序分別提取棋盤(pán)的最邊上的角點(diǎn),程序會(huì)自動(dòng)幫你找到所有對(duì)應(yīng)的角點(diǎn)
2.6. 提取角點(diǎn)
2.7. 提取角點(diǎn)2
在提取第一幅圖的時(shí)候命令行窗口可能會(huì)提示你輸入方格大小,這里輸入你方格的實(shí)際大小就行,比如我方格是27mm,就輸入27。這步事實(shí)上相當(dāng)關(guān)鍵,它定義了空間的尺度,如果要對(duì)物體進(jìn)行測(cè)量的話,這步是必須的。
按相同的方法提取完10幅圖后,點(diǎn)擊Calibration,開(kāi)始攝像頭標(biāo)定
2.8. calib_gui面板
經(jīng)過(guò)多次迭代后,程序會(huì)最終得到攝像頭的內(nèi)外參數(shù),如下圖所示(圖中符號(hào)由于字體關(guān)系沒(méi)有完全顯示,中間的問(wèn)號(hào)是表示誤差的加減號(hào))
2.9. Calibration迭代過(guò)程及結(jié)果
可以通過(guò)面板上的Show Extrinsic查看一下標(biāo)定結(jié)果,可以驗(yàn)證一下標(biāo)定外參數(shù)的結(jié)果
2.10. 外部參數(shù)圖示
驗(yàn)證標(biāo)定結(jié)果無(wú)誤之后,就點(diǎn)擊面板上的Save按鈕,程序會(huì)把標(biāo)定結(jié)果放在一個(gè)叫Calib_Result.mat中,為了方便后續(xù)立體標(biāo)定,把這個(gè)文件名改為Calib_Result_right.mat。
左攝像頭標(biāo)定的方法與右攝像頭相同,生成的Calib_Result.mat之后,將其改名為Calib_Result_left.mat就可以了
左右攝像頭都標(biāo)定完成之后,就可以開(kāi)始立體標(biāo)定了。
在Matlab命令行中鍵入stereo_gui啟動(dòng)立體標(biāo)定面板,如下圖所示
2.11. stereo_gui面板
點(diǎn)擊Load left and right calibration files并在命令行中選擇默認(rèn)的文件名(Calib_Result_left.mat和Calib_Result_right.mat)之后就可以開(kāi)始Run stereo calibration了,run之后的結(jié)果如下圖所示,左右攝像頭的參數(shù)都做了修正,并且也求出了兩個(gè)攝像頭之間的旋轉(zhuǎn)和平移關(guān)系向量(om和T)
2.12. 立體標(biāo)定結(jié)果
在面板上點(diǎn)擊Show Extrinsics of stereo rig,可以看到如下圖所示的雙攝像頭關(guān)系圖,可以看到,兩個(gè)攝像頭基本是前向平行的
2.13. 雙攝像頭與定標(biāo)棋盤(pán)間的位置關(guān)系
得到了立體標(biāo)定參數(shù)之后,就可以把參數(shù)放入xml文件,然后用cvLoad讀入OpenCV了。具體的方法可以參照Learning OpenCV第11章的例子,上面就是用cvSave保存標(biāo)定結(jié)果,然后再用cvLoad把之前的標(biāo)定結(jié)果讀入矩陣的
2.14. xml文件示例
這里需要注意的是Matlab標(biāo)定結(jié)果中的om向量,這個(gè)向量是旋轉(zhuǎn)矩陣通過(guò)Rodrigues變換之后得出的結(jié)果,如果要在cvStereoRectify中使用的話,需要首先將這個(gè)向量用cvRodrigues轉(zhuǎn)換成旋轉(zhuǎn)矩陣。關(guān)于Rodrigues變換,Learning OpenCV的第11章也有說(shuō)明。
2.15. 旋轉(zhuǎn)矩陣的Rodrigues形式表示
3. 立體校準(zhǔn)和匹配
有了標(biāo)定參數(shù),校準(zhǔn)的過(guò)程就很簡(jiǎn)單了。
我使用的是OpenCV中的cvStereoRectify,得出校準(zhǔn)參數(shù)之后用cvRemap來(lái)校準(zhǔn)輸入的左右圖像。這部分的代碼參考的是Learning OpenCV 十二章的例子。
校準(zhǔn)之后,就可以立體匹配了。立體匹配OpenCV里面有兩種方法,一種是Block Matching,一種是Graph Cut。Block Matching用的是SAD方法,速度比較快,但效果一般。Graph Cut可以參考Kolmogrov03的那篇博士論文,效果不錯(cuò),但是運(yùn)行速度實(shí)在是慢到不能忍。所以還是選擇BM。
以下是我用BM進(jìn)行立體匹配的參數(shù)設(shè)置
[cpp:nogutter]
其中minDisparity這個(gè)參數(shù)我設(shè)置為0是由于我的兩個(gè)攝像頭是前向平行放置,相同的物體在左圖中一定比在右圖中偏右,如下圖3.1所示。所以沒(méi)有必要設(shè)置回搜的參數(shù)。
如果為了追求更大的雙目重合區(qū)域而將兩個(gè)攝像頭向內(nèi)偏轉(zhuǎn)的話,這個(gè)參數(shù)是需要考慮的。
3.1. 校正后的左右視圖
另外需要提的參數(shù)是uniquenessRatio,實(shí)驗(yàn)下來(lái),我感覺(jué)這個(gè)參數(shù)對(duì)于最后的匹配結(jié)果是有很大的影響。uniquenessRatio主要可以防止誤匹配,其主要作用從下面三幅圖的disparity效果比對(duì)就可以看出。在立體匹配中,我們寧愿區(qū)域無(wú)法匹配,也不要誤匹配。如果有誤匹配的話,碰到障礙檢測(cè)這種應(yīng)用,就會(huì)很麻煩。
3.2. UniquenessRatio為0時(shí)的匹配圖,可以看到大片的誤匹配區(qū)域
3.3. UniquenessRatio為10時(shí)的disparity map, 可以看到誤匹配被大量減少了, 但還是有噪點(diǎn)
3.4. UniquenessRatio為20時(shí)的disparity map, 可以看到誤匹配基本被去除了, 點(diǎn)云干凈了很多
關(guān)于cvFindStereoCorrespondenceBM這個(gè)函數(shù)的源代碼,曾經(jīng)做過(guò)比較詳細(xì)的研究,,過(guò)一段時(shí)間也會(huì)把之前寫(xiě)的代碼注釋整理一下,發(fā)篇博文。
4. 實(shí)際距離的測(cè)量
在用cvFindStereoCorrespondenceBM得出disparity map之后,還需要通過(guò)cvReprojectImageTo3D這個(gè)函數(shù)將單通道Disparity Map轉(zhuǎn)換成三通道的實(shí)際坐標(biāo)矩陣。
具體的數(shù)學(xué)原理可以參考下面這個(gè)公式(from chenyusiyuan ,實(shí)際深度的一些問(wèn)題這篇博文中也有提到)
4.1 距離轉(zhuǎn)換公式
但是在實(shí)際操作過(guò)程中,用cvReprojectImageTo3D得到的數(shù)據(jù)并未如實(shí)際所想,生成深度矩陣所定義的世界坐標(biāo)系我就一直沒(méi)弄清楚。這在下面的例子中會(huì)詳細(xì)說(shuō)明,希望這方面的專(zhuān)家能幫忙解答一下:
圖4.2是測(cè)量時(shí)的實(shí)際場(chǎng)景圖,場(chǎng)景中主要測(cè)量的三個(gè)物體就是最前面的利樂(lè)包裝盒、中間的紙杯、和最遠(yuǎn)的塑料瓶。
4.2. 實(shí)際場(chǎng)景中三個(gè)待測(cè)物體的位置
圖4.3是校準(zhǔn)后的左右圖和匹配出來(lái)的disparity map,disparity窗口中是實(shí)際的點(diǎn)云,object窗口是給disparity map加了個(gè)閾值之后得到的二值圖,主要是為了分割前景和背景?梢钥吹揭獪y(cè)的三個(gè)物體基本被正確地分割出來(lái)了
4.3. 雙目攝像頭得到的disparity map
圖4.4是在disparity窗口中選取一個(gè)點(diǎn)后然后在實(shí)際坐標(biāo)矩陣中得到的對(duì)應(yīng)三維信息,在這里,我在三個(gè)物體的點(diǎn)云上各選一個(gè)點(diǎn)來(lái)代表一個(gè)物體實(shí)際的坐標(biāo)信息。(這里通過(guò)鼠標(biāo)獲取一點(diǎn)坐標(biāo)信息的方法參考的是opencv sample里的watershed.cpp)
4.4. 對(duì)應(yīng)點(diǎn)的三維坐標(biāo)
在這里可以看到,(265, 156)也就是利樂(lè)包裝盒的坐標(biāo)是(13, 12, -157),(137, 142)紙杯的坐標(biāo)是(77, 30, -312),(95, 115)塑料瓶的坐標(biāo)是(144, 63, -482)。
補(bǔ)充一下:為了方便顯示,所以視差圖出來(lái)之后進(jìn)行了一個(gè)0-255的normalize,所以value值的前一個(gè)是normalize之后點(diǎn)的灰度值,后一個(gè)是normalize之前點(diǎn)的實(shí)際視差圖。
由cvFindStereoCorrespondenceBM算法的源代碼:
dptr[y*dstep] = (short)(((ndisp - mind - 1 + mindisp)*256 + (d != 0 ? (p-n)*128/d : 0) + 15) >> 4);
其中
ndisp是ndisp = state->numberOfDisparities;
mindisp是mindisp = state->minDisparity;
mind就是sad得出的視差
實(shí)際視差大約是(64-mind-1)*256=1163, 基本是對(duì)的, 后面一項(xiàng)修正值在通常情況下可以忽略
目前我還是不是很清楚立體坐標(biāo)系原點(diǎn)和尺度,但是從這三個(gè)點(diǎn)的z坐標(biāo)可以大致看出這三個(gè)物體的距離差大概是1:2:3,基本與實(shí)際場(chǎng)景中物體的位置一致。因此,可以通過(guò)這種方法確定出物體的大致距離信息。
但是,如果就從攝像頭參數(shù)本身來(lái)測(cè)量距離的話,就不是很明白了,還求這方面的大牛解答。
5. 一些問(wèn)題
5.1 關(guān)于StereoCalibrate
OpenCV自帶的cvStereoCalibrate感覺(jué)不怎么好用,用這個(gè)函數(shù)求出的內(nèi)參外參和旋轉(zhuǎn)平移矩陣進(jìn)行校準(zhǔn),往往無(wú)法達(dá)到行對(duì)準(zhǔn),有時(shí)甚至?xí)霈F(xiàn)比較可怕的畸變。在看了piao的?f=1&t=4603帖子之后,也曾經(jīng)嘗試過(guò)現(xiàn)用cvCalibrateCamera2單獨(dú)標(biāo)定(左右各20幅圖),得出的結(jié)果基本和Matlab單獨(dú)標(biāo)定的相同,然后再在cvStereoCalibrate中將參數(shù)設(shè)成CV_CALIB_USE_INTRINSIC_GUESS,用來(lái)細(xì)化內(nèi)參數(shù)和畸變參數(shù),結(jié)果得出的標(biāo)定結(jié)果就又走樣了。
不知道有誰(shuí)在這方面有過(guò)成功經(jīng)驗(yàn)的,可以出來(lái)分享一下。畢竟用Matlab工具箱還是麻煩了些。
5.2 Translation向量以及立體匹配得出的世界坐標(biāo)系
Learning OpenCV中對(duì)于Translation和Rotation的圖示是這樣的
5.1. Learning OpenCV中的圖示
可是在實(shí)驗(yàn)過(guò)程中發(fā)現(xiàn),如果將Translation向量按尺度縮放,對(duì)于StereoRectify之后的左右視圖不會(huì)有變化,比如將T = [ -226.73817 -0.62302 8.93984 ] ,變成T = [ -22.673817 -0.062302 0.893984 ],在OpenCV中顯示的結(jié)果不會(huì)有任何變化。而且我如果修改其中的一個(gè)參量的話,左右視圖發(fā)生的變化也不是圖5.1中所示的那種變化(比如把x縮小,那么視圖發(fā)生的變化不是往x軸方向的平移)。
因此又回到了老問(wèn)題,這里這些坐標(biāo)的尺度究竟是什么?通過(guò)ReprojectTo3D那個(gè)函數(shù)得到的三維坐標(biāo)又是以哪個(gè)點(diǎn)為原點(diǎn),那三個(gè)方向?yàn)閤,y,z軸的?
補(bǔ)充: 對(duì)這個(gè)問(wèn)題的解答來(lái)自于和maxwellsdemon的討論
他的解釋如下:rotation是兩者的旋轉(zhuǎn)角度的關(guān)系,但是你要把它矯正平行,也是需要translation matrix的。你可以設(shè)想,兩個(gè)看似已經(jīng)平行了的攝像頭,但是深度上放置的有差距,那么在矯正的時(shí)候會(huì)議translation matrix所對(duì)應(yīng)的角度或者直線為基準(zhǔn),二者旋轉(zhuǎn)一個(gè)小角度,使得完全平行。
本文關(guān)鍵詞:標(biāo)定,由筆耕文化傳播整理發(fā)布。
本文編號(hào):182047
本文鏈接:http://sikaile.net/jianzhugongchenglunwen/182047.html