天天看點

Kinect深度圖與攝像頭RGB的标定與配準

轉自:http://blog.csdn.net/aichipmunk/article/details/9264703

自從有了Kinect,根據深度圖提取前景就非常友善了。是以出現了很多虛拟現實、視訊融合等應用。但是,Kinect自身的RGB攝像頭分辨率有限,清晰度也不及一些專業攝像頭,是以有了用第三方攝像頭代替Kinect攝像頭的想法。現在的問題是,如何将Kinect的深度圖與第三方攝像頭的RGB圖像對準?

我們知道,當使用Kinect的RGB時,有友善的MapColorCoordinatesToDepth()和MapDepthCoordinatesToColor()方法可以使用,這些函數将深度圖和RGB對準到一起,進而可根據深度圖準确的提取出RGB中的前景。但打算使用第三方攝像頭時,這些函數都沒有用了,它們不可能知道我們所用攝像頭的參數以及空間位置,是以隻能靠自己标定的方法解決這一問題。

在标定之前,先要固定好Kinect和攝像頭的位置,讓深度攝像頭和RGB攝像頭的像平面盡量平行,距離也不要隔得太遠,就像下面這樣(做得很醜,請見諒-_-!!):

Kinect深度圖與攝像頭RGB的标定與配準

一、RGB攝像頭的标定

RGB攝像頭的标定想必大家都很熟悉,最常用的就是棋盤法。用待标定的攝像頭拍攝多幅不同視角下的棋盤圖檔,将這些圖檔扔給OpenCV或Matlab,進而計算出該攝像頭的内參以及對應于每一幅圖像的外參。這裡就寫寫我在标定過程中的一些感受和經驗吧。

1、标定所用的棋盤要盡量大,至少要有A3紙的大小;

2、棋盤平面與攝像頭像平面之間的夾角不要太大,控制在45度以下;

3、棋盤的姿勢與位置盡可能多樣化,但互相平行的棋盤對結果沒有貢獻;

4、用于标定的圖檔要多于10張;

5、注意設定好攝像頭的分辨率,長寬比最好和深度圖的相同,比如1280x960(4:3)。

以下是一些用于标定的樣圖:

Kinect深度圖與攝像頭RGB的标定與配準

二、深度攝像頭的标定

深度攝像頭看起來和RGB攝像頭差别很大,實際上有很多相似之處。就Kinect而言,其通過一個紅外散斑發射器發射紅外光束,光束碰到障礙物後反射回深度攝像頭,然後通過傳回散斑之間的幾何關系計算距離。其實,Kinect的深度攝像頭就是一個裝了濾波片的普通攝像頭,隻對紅外光成像的攝像頭(可以這麼認為)。是以要對其标定,隻需用紅外光源照射物體即可,LED紅外光源在淘寶上就20元一個。還有一點必須注意,在拍攝紅外照片時,要用黑膠帶(或其他東西)将Kinect的紅外發射器完全擋住,否則其發出的散斑會在紅外照片中産生很多亮點,不利于棋盤角點的檢測。以下是對應于上面RGB圖像的紅外圖:

Kinect深度圖與攝像頭RGB的标定與配準

三、計算内參

得到以上圖檔之後,就可以分别對RGB攝像頭和深度攝像頭計算内參了。可以使用OpenCV,自己寫一小段程式,然後把圖檔扔進去。也可以使用著名的Matlab Camera Calibration Toolbox。自己寫代碼累,Matlab我沒裝,是以我使用 GML Calibration Toolbox,可以在這裡下載下傳 http://graphics.cs.msu.ru/en/node/909 。這是一個C++寫的标定程式,有友好的使用者界面,精度也不錯,使用非常友善。

分别将RGB和紅外的照片扔進去,得到RGB攝像頭的内參(包括畸變參數):

=== 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深度攝像頭的内參(這個對所有Kinect應該都是差不多的):

=== 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 

四、配準

現在說說怎麼配準,由于Kinect可以得到真實點的三維坐标,是以深度圖的配準可以用一些簡單特殊的方法。

設P_ir為在深度攝像頭坐标下某點的空間坐标,p_ir為該點在像平面上的投影坐标(x、y機關為像素,z等于深度值,機關為毫米),H_ir為深度攝像頭的内參矩陣,由小孔成像模型可知,他們滿足以下關系:

Kinect深度圖與攝像頭RGB的标定與配準

又設P_rgb為在RGB攝像頭坐标下同一點的空間坐标,p_rgb為該點在RGB像平面上的投影坐标,H_rgb為RGB攝像頭的内參矩陣。由于深度攝像頭的坐标和RGB攝像頭的坐标不同,他們之間可以用一個旋轉平移變換聯系起來,即:

Kinect深度圖與攝像頭RGB的标定與配準

其中R為旋轉矩陣,T為平移向量。最後再用H_rgb對P_rgb投影,即可得到該點對應的RGB坐标:

Kinect深度圖與攝像頭RGB的标定與配準

需要注意的是,p_ir和p_rgb使用的都是齊次坐标,是以在構造p_ir時,應将原始的像素坐标(x,y)乘以深度值,而最終的RGB像素坐标必須将p_rgb除以z分量,即(x/z,y/z),且z分量的值即為該點到RGB攝像頭的距離(機關為毫米)。

現在的問題是,如何求聯系兩個坐标系的旋轉矩陣和平移向量。這就要用到攝像頭的外參了。

外參矩陣實際上也是由一個旋轉矩陣R_ir(R_rgb)和平移向量T_ir(T_rgb)構成的,它表示将一個全局坐标系下的點P變換到攝像頭坐标系下,分别對深度攝像頭和RGB攝像頭進行變換,有以下關系:

Kinect深度圖與攝像頭RGB的标定與配準

在第一式中,将P用P_ir、R_ir和T_ir表示,并帶入第二式,可得:

Kinect深度圖與攝像頭RGB的标定與配準

從上式可以看出,這是在将P_ir變換為P_rgb,對比之前的式子:

Kinect深度圖與攝像頭RGB的标定與配準

可得:

Kinect深度圖與攝像頭RGB的标定與配準

是以,我們隻需在同一場景下,得到棋盤相對于深度攝像頭和RGB攝像頭的外參矩陣,即可算出聯系兩攝像頭坐标系的變換矩陣(注意,所有旋轉矩陣都是正交陣,是以可用轉置運算代替求逆運算)。雖然不同場景下得到的外參矩陣都不同,計算得到的R和T也有一些變化,但根據實際實驗結果來看,使用一個正面棋盤的标定圖像就可達到較好的效果,如下圖:

Kinect深度圖與攝像頭RGB的标定與配準

注意,這兩幅圖像必須來自于同一場景,否則沒有意義。當然你也可以使用多個場景下的外參,然後使用OpenCV的StereoCalibration函數求得兩個攝像頭的最佳相對變換矩陣,由于時間關系,我沒有做這個測試。

使用GML Calibration Toolbox得到以上兩圖的外參(在菜單欄的Calibration->Export Calibration Data菜單中選擇導出),然後根據上式,扔進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}  }

五、測試

最後寫一個小程式測試一下,看看配準前(左)和配準後(右)的差別:

Kinect深度圖與攝像頭RGB的标定與配準

從圖像上看,配準已經很精确了。若還要更好,可以手動微調一下兩個攝像頭的平移向量T,主要改x分量和y分量,這樣可以控制RGB和深度圖的左右對齊和上下對齊。另外,還可以加入對畸變系數的處理,不過由于Kinect的攝像頭以及我使用的RGB攝像頭本身品質較高,畸變影響不大,這裡就全部忽略了。

繼續閱讀