Kinect深度图与摄像头RGB的标定与配准(转载文章)
作者原文地址:http://blog.csdn.net/aichipmunk/article/details/9264703
?
自從有了Kinect,根據(jù)深度圖提取前景就非常方便了。因此出現(xiàn)了很多虛擬現(xiàn)實、視頻融合等應(yīng)用。但是,Kinect自身的RGB攝像頭分辨率有限,清晰度也不及一些專業(yè)攝像頭,因此有了用第三方攝像頭代替Kinect攝像頭的想法。現(xiàn)在的問題是,如何將Kinect的深度圖與第三方攝像頭的RGB圖像對準(zhǔn)?
我們知道,當(dāng)使用Kinect的RGB時,有方便的MapColorCoordinatesToDepth()和MapDepthCoordinatesToColor()方法可以使用,這些函數(shù)將深度圖和RGB對準(zhǔn)到一起,從而可根據(jù)深度圖準(zhǔn)確的提取出RGB中的前景。
但打算使用第三方攝像頭時,這些函數(shù)都沒有用了,它們不可能知道我們所用攝像頭的參數(shù)以及空間位置,因此只能靠自己標(biāo)定的方法解決這一問題。
在標(biāo)定之前,先要固定好Kinect和攝像頭的位置,讓深度攝像頭和RGB攝像頭的像平面盡量平行,距離也不要隔得太遠(yuǎn),就像下面這樣(做得很丑,請見諒-_-!!):
?
一、RGB攝像頭的標(biāo)定
RGB攝像頭的標(biāo)定想必大家都很熟悉,最常用的就是棋盤法。用待標(biāo)定的攝像頭拍攝多幅不同視角下的棋盤圖片,將這些圖片扔給OpenCV或Matlab,從而計算出該攝像頭的內(nèi)參以及對應(yīng)于每一幅圖像的外參。這里就寫寫我在標(biāo)定過程中的一些感受和經(jīng)驗吧。
1、標(biāo)定所用的棋盤要盡量大,至少要有A3紙的大小;
2、棋盤平面與攝像頭像平面之間的夾角不要太大,控制在45度以下;
3、棋盤的姿勢與位置盡可能多樣化,但相互平行的棋盤對結(jié)果沒有貢獻(xiàn);
4、用于標(biāo)定的圖片要多于10張;
5、注意設(shè)置好攝像頭的分辨率,長寬比最好和深度圖的相同,比如1280x960(4:3)。
以下是一些用于標(biāo)定的樣圖:
?
二、深度攝像頭的標(biāo)定
深度攝像頭看起來和RGB攝像頭差別很大,實際上有很多相似之處。就Kinect而言,其通過一個紅外散斑發(fā)射器發(fā)射紅外光束,光束碰到障礙物后反射回深度攝像頭,然后通過返回散斑之間的幾何關(guān)系計算距離。其實,Kinect的深度攝像頭就是一個裝了濾波片的普通攝像頭,只對紅外光成像的攝像頭(可以這么認(rèn)為)。因此要對其標(biāo)定,只需用紅外光源照射物體即可,LED紅外光源在淘寶上就20元一個。還有一點必須注意,在拍攝紅外照片時,要用黑膠帶(或其他東西)將Kinect的紅外發(fā)射器完全擋住,否則其發(fā)出的散斑會在紅外照片中產(chǎn)生很多亮點,不利于棋盤角點的檢測。以下是對應(yīng)于上面RGB圖像的紅外圖:
?
三、計算內(nèi)參
得到以上圖片之后,就可以分別對RGB攝像頭和深度攝像頭計算內(nèi)參了。可以使用OpenCV,自己寫一小段程序,然后把圖片扔進(jìn)去。也可以使用著名的Matlab Camera Calibration Toolbox。自己寫代碼累,Matlab我沒裝,因此我使用?GML Calibration Toolbox,可以在這里下載?http://graphics.cs.msu.ru/en/node/909?。這是一個C++寫的標(biāo)定程序,有友好的用戶界面,精度也不錯,使用非常方便。
分別將RGB和紅外的照片扔進(jìn)去,得到RGB攝像頭的內(nèi)參(包括畸變參數(shù)):
=== Intrinsic ===
554.952628 ? ? ?0.000000 ? ? ? ? ? 327.545377
0.000000 ? ? ? ? ? 555.959694 ? ? ?248.218614
0.000000 ? ? ? ? ? 0.000000 ? ? ? ? ? 1.000000
=== Distortion ===
0.025163 ? ? ? ? ?-0.118850 ? ? ? ? ?-0.006536 ? ? ? ? ?-0.001345?
和Kinect深度攝像頭的內(nèi)參(這個對所有Kinect應(yīng)該都是差不多的):
=== Intrinsic ===
597.599759 ? ? ?0.000000 ? ? ? ? ? 322.978715
0.000000 ? ? ? ? ? 597.651554 ? ? ?239.635289
0.000000 ? ? ? ? ? 0.000000 ? ? ? ? ? 1.000000
=== Distortion ===
-0.094718 ? ? ? ? ?0.284224 ? ? ? ? ? -0.005630 ? ? ? ? ?-0.001429?
?
四、配準(zhǔn)
現(xiàn)在說說怎么配準(zhǔn),由于Kinect可以得到真實點的三維坐標(biāo),因此深度圖的配準(zhǔn)可以用一些簡單特殊的方法。
設(shè)P_ir為在深度攝像頭坐標(biāo)下某點的空間坐標(biāo),p_ir為該點在像平面上的投影坐標(biāo)(x、y單位為像素,z等于深度值,單位為毫米),H_ir為深度攝像頭的內(nèi)參矩陣,由小孔成像模型可知,他們滿足以下關(guān)系:
又設(shè)P_rgb為在RGB攝像頭坐標(biāo)下同一點的空間坐標(biāo),p_rgb為該點在RGB像平面上的投影坐標(biāo),H_rgb為RGB攝像頭的內(nèi)參矩陣。由于深度攝像頭的坐標(biāo)和RGB攝像頭的坐標(biāo)不同,他們之間可以用一個旋轉(zhuǎn)平移變換聯(lián)系起來,即:
其中R為旋轉(zhuǎn)矩陣,T為平移向量。最后再用H_rgb對P_rgb投影,即可得到該點對應(yīng)的RGB坐標(biāo):
需要注意的是,p_ir和p_rgb使用的都是齊次坐標(biāo),因此在構(gòu)造p_ir時,應(yīng)將原始的像素坐標(biāo)(x,y)乘以深度值,而最終的RGB像素坐標(biāo)必須將p_rgb除以z分量,即(x/z,y/z),且z分量的值即為該點到RGB攝像頭的距離(單位為毫米)。
現(xiàn)在的問題是,如何求聯(lián)系兩個坐標(biāo)系的旋轉(zhuǎn)矩陣和平移向量。這就要用到攝像頭的外參了。
外參矩陣實際上也是由一個旋轉(zhuǎn)矩陣R_ir(R_rgb)和平移向量T_ir(T_rgb)構(gòu)成的,它表示將一個全局坐標(biāo)系下的點P變換到攝像頭坐標(biāo)系下,分別對深度攝像頭和RGB攝像頭進(jìn)行變換,有以下關(guān)系:
在第一式中,將P用P_ir、R_ir和T_ir表示,并帶入第二式,可得:
從上式可以看出,這是在將P_ir變換為P_rgb,對比之前的式子:
可得:
因此,我們只需在同一場景下,得到棋盤相對于深度攝像頭和RGB攝像頭的外參矩陣,即可算出聯(lián)系兩攝像頭坐標(biāo)系的變換矩陣(注意,所有旋轉(zhuǎn)矩陣都是正交陣,因此可用轉(zhuǎn)置運算代替求逆運算)。雖然不同場景下得到的外參矩陣都不同,計算得到的R和T也有一些變化,但根據(jù)實際實驗結(jié)果來看,使用一個正面棋盤的標(biāo)定圖像就可達(dá)到較好的效果,如下圖:
注意,這兩幅圖像必須來自于同一場景,否則沒有意義。當(dāng)然你也可以使用多個場景下的外參,然后使用OpenCV的StereoCalibration函數(shù)求得兩個攝像頭的最佳相對變換矩陣,由于時間關(guān)系,我沒有做這個測試。
使用GML Calibration Toolbox得到以上兩圖的外參(在菜單欄的Calibration->Export Calibration Data菜單中選擇導(dǎo)出),然后根據(jù)上式,扔進(jìn)Mathematica里面去做矩陣運算,得到最終的R和T:
R={?{0.999853, -0.00340388, 0.0167495},?
{0.00300206, 0.999708,??0.0239986},
{-0.0168257, -0.0239459, 0.999571} ?}
T={ ?{15.2562}, {70.2212}, {-10.9926} ?}
?
五、測試
最后寫一個小程序測試一下,看看配準(zhǔn)前(左)和配準(zhǔn)后(右)的區(qū)別:
從圖像上看,配準(zhǔn)已經(jīng)很精確了。若還要更好,可以手動微調(diào)一下兩個攝像頭的平移向量T,主要改x分量和y分量,這樣可以控制RGB和深度圖的左右對齊和上下對齊。另外,還可以加入對畸變系數(shù)的處理,不過由于Kinect的攝像頭以及我使用的RGB攝像頭本身質(zhì)量較高,畸變影響不大,這里就全部忽略了。
?
說一下這個測試程序的思路。
1、獲取Kinect的深度圖像;
2、獲取RGB攝像頭的圖像;
3、為深度圖像中的每一個像素附上對應(yīng)的RGB顏色,比如你要給坐標(biāo)為(x, y)的深度圖像素附上顏色,具體步驟如下;
1)構(gòu)造一個三維向量p_ir = (x, y, z),其中x,y是該點的像素坐標(biāo),z是該像素的深度值;
2)用Kinect內(nèi)參矩陣H_ir的逆,乘以p_ir得到對應(yīng)的空間點坐標(biāo)P_ir,具體公式見上文第四部分(配準(zhǔn));
3)由于P_ir是該點在Kinect坐標(biāo)系下的坐標(biāo),我們需要將其轉(zhuǎn)換到RGB攝像頭的坐標(biāo)系下,具體的,就是乘以一個旋轉(zhuǎn)矩陣R,再加上一個平移向量T,得到P_rgb;
4)用RGB攝像頭的內(nèi)參矩陣H_rgb乘以P_rgb,得到p_rgb,p_rgb也是一個三維向量,其x和y坐標(biāo)即為該點在RGB圖像中的像素坐標(biāo),取出該像素的顏色,作為深度圖像中對應(yīng)像素的顏色;
5)對深度圖像中的每一個像素都做上述操作,得到配準(zhǔn)后的深度圖。
?
作者原文地址:http://blog.csdn.net/aichipmunk/article/details/9264703
知乎上網(wǎng)友代碼:https://www.zhihu.com/question/29631310
?
國外的標(biāo)定:
http://rgbdemo.org/index.php/Documentation/Calibration
http://burrus.name/index.php/Research/KinectCalibration#tocLink5
?
Kinect彩色圖深度圖配準(zhǔn)(分辨率不一樣時的處理方式):http://blog.csdn.net/shihz_fy/article/details/43602393
ROS下的驅(qū)動與圖像序列保存及opencv顯示深度坐標(biāo):http://blog.csdn.net/sunbibei/article/details/51594824
?
================================分割線=====================================
============================================
2017.09.08
SDK獲取出廠內(nèi)參數(shù)代碼,MATLAB 標(biāo)定Kinect v2等
http://blog.csdn.net/jiaojialulu/article/details/77430563
?================================分割線====================================SaveSave
彩色圖和深度圖配準(zhǔn)的事,我目前是不推薦自己做配準(zhǔn),很繁瑣。如果要自己來做配準(zhǔn),目前我認(rèn)為的三個配的比較好的(暫且不說Kinect?2的SDK了,需要安裝SDK 2.0 +Visual studio + opencv + PCL,很繁瑣,Kinect C++資料較C#少很多),個人精力有限,源碼沒有深究。
1.?PCL1.8里有個程序,pcl_openni2_viewer,在Linux下面直接接上相機華碩的Xtion?Pro?live,輸入上面代碼可以看到效果;其他的相機我沒試過,這個pcl的github有源碼,調(diào)用的openni的東西
2.?Kinect?V2相機在Linux下的驅(qū)動freenect2,源碼編譯之后,bin文件夾有個Protonect的程序,效果也很好,github官網(wǎng)也可以看到源碼https://github.com/OpenKinect/libfreenect2
3.?Processing?3程序有個Kinect?插件kinect4WinSDK(Kinect?1代和2代都有對應(yīng)插件),下圖是Kinect1代的
總結(jié)
以上是生活随笔為你收集整理的Kinect深度图与摄像头RGB的标定与配准(转载文章)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: edius裁剪快捷键_edius常用快捷
- 下一篇: 小说取名软件(附带截图)分享与介绍