1. 雙目相機概述
-
雙目立體視覺模型
- 雙目立體相機分別校準可參考
ROS_單目相機_分別校準
- 雙目立體相機分別校準可參考
-
雙目立體匹配算法案例
https://www.cnblogs.com/riddick/p/8486223.html
https://www.cnblogs.com/zyly/p/9373991.html -
雙目相機的特性
1.雙目相機有左右兩個視野圖,所以有了參數
基線
;-
基線的特性
1.當系統的硬件結構固定不變,則通過外參校準的T中的位移量可對比參考基線長;且工作距離越大,測量精度越低。
2.當基線增大時,FOV中水平角在增大,其對精度的影響是非線性的。
-
-
雙目相機的矯正
-
相機內參標定
相機內參標定,獲取相機座標系與圖像座標系之間的投影關係,如(fx, fy, cx, cy, k1, k2, k3, 等)
-
相機外參標定
相機外參反應的是攝像機座標系和世界座標系之間的旋轉R+T關係,雙目相機外參主要獲取兩個相機之間“基線”
-
-
雙目相機的立體匹配算法
在雙目相機中特徵點的匹配與單目類似,用光流法跟蹤特徵,選取匹配點。
然後對匹配的特徵點對計算本質矩陣,再分解矩陣獲得旋轉矩陣R和平移矩陣t;
-
基於局部的塊匹配 - BM(Block Matching StereoBM)
-
半全局塊匹配 - SGBM(Semi-Global-Block-Matching)
SGBM算法要遠遠優於BM算法。
-
2. 單目相機+雙目相機+深度相機(結構光)+TOF對比
- 單目無法確認深度
單目SLAM不受環境大小的影響,因此既可以用於室內,又可以用於室外。
- 雙目相機
雙目相機標定配置較爲複雜(why?)(好像還有一個對準,有點不太記得…歡迎補充):
1. 雙目相機的各個單獨的鏡頭需要內參校準;
2. 雙目相機的各個單獨的鏡頭需要外參校準;
3. 雙目相機兩個相機之間需要校準;
4. 雙目相機的兩個相機校準之後還要與出廠的基線對齊,若誤差較大則校準失敗。
雙目相機的優勢: 它不管在靜止和運動下都可以直接估計場景的深度值。其深度量程受雙目的基線和分辨率限制。
另外,使用雙目相機去計算視差,還原深度值,比較耗時(如SGBM立體匹配)。
- 結構光測量 (主動式測量:可以直接獲取距離值)
3D結構光投射的是散斑或編碼圖案
,接收模組需要拍攝到清晰的圖案
才能計算出深度。
而隨着距離的增加
,投出的圖案或出現模糊
,或出現亮度能量上的衰減
,導致深度圖不完整
,出現破洞,甚至於失效,所以3D結構光並不適用於遠距離深度信息採集。
結構光在室外容易受到強光的影響,效果很差。因爲光斑成像很容易受到環境的干擾。
結構光的測量距離一般較近(0.1~10m)如realsense D435
- TOF(飛行時間測距法) (主動式測量:可以直接獲取距離值)
TOF是通過紅外光發射器
發射調製後的紅外光脈衝
,不停地打在物體表面,經反射後被接收器接收,通過相位的變化來計算時間差
,進而結合光速
計算出物體深度信息
。
不受環境光照的影響,室內室外都可行。TOF測量的距離一般較遠(0.4~130m) 如VLP16
3. 視差圖和深度圖的填充方法
① 以視差圖dispImg爲例
。計算圖像的積分圖integral,並保存對應積分圖中每個積分值處所有累加的像素點個數n(空洞處的像素點不計入n中,因爲空洞處像素值爲0,對積分值沒有任何作用,反而會平滑圖像)。
② 採用多層次均值濾波
。首先以一個較大的初始窗口去做均值濾波(積分圖實現均值濾波就不多做介紹了,可以參考我之前的一篇博客),將大區域的空洞賦值。然後下次濾波時,將窗口尺寸縮小爲原來的一半,利用原來的積分圖再次濾波,給較小的空洞賦值(覆蓋原來的值);依次類推,直至窗口大小變爲3x3,此時停止濾波,得到最終結果。
③ 多層次濾波考慮的是對於初始較大的空洞區域
,需要參考更多的鄰域值,如果採用較小的濾波窗口,不能夠完全填充,而如果全部採用較大的窗口,則圖像會被嚴重平滑。因此根據空洞的大小,不斷調整濾波窗口。先用大窗口給所有空洞賦值,然後利用逐漸變成小窗口濾波覆蓋原來的值,這樣既能保證空洞能被填充上,也能保證圖像不會被過度平滑
void insertDepth32f(cv::Mat& depth)
{
const int width = depth.cols;
const int height = depth.rows;
float* data = (float*)depth.data;
cv::Mat integralMap = cv::Mat::zeros(height, width, CV_64F);
cv::Mat ptsMap = cv::Mat::zeros(height, width, CV_32S);
double* integral = (double*)integralMap.data;
int* ptsIntegral = (int*)ptsMap.data;
memset(integral, 0, sizeof(double) * width * height);
memset(ptsIntegral, 0, sizeof(int) * width * height);
for (int i = 0; i < height; ++i)
{
int id1 = i * width;
for (int j = 0; j < width; ++j)
{
int id2 = id1 + j;
if (data[id2] > 1e-3)
{
integral[id2] = data[id2];
ptsIntegral[id2] = 1;
}
}
}
// 積分區間
for (int i = 0; i < height; ++i)
{
int id1 = i * width;
for (int j = 1; j < width; ++j)
{
int id2 = id1 + j;
integral[id2] += integral[id2 - 1];
ptsIntegral[id2] += ptsIntegral[id2 - 1];
}
}
for (int i = 1; i < height; ++i)
{
int id1 = i * width;
for (int j = 0; j < width; ++j)
{
int id2 = id1 + j;
integral[id2] += integral[id2 - width];
ptsIntegral[id2] += ptsIntegral[id2 - width];
}
}
int wnd;
double dWnd = 2;
while (dWnd > 1)
{
wnd = int(dWnd);
dWnd /= 2;
for (int i = 0; i < height; ++i)
{
int id1 = i * width;
for (int j = 0; j < width; ++j)
{
int id2 = id1 + j;
int left = j - wnd - 1;
int right = j + wnd;
int top = i - wnd - 1;
int bot = i + wnd;
left = max(0, left);
right = min(right, width - 1);
top = max(0, top);
bot = min(bot, height - 1);
int dx = right - left;
int dy = (bot - top) * width;
int idLeftTop = top * width + left;
int idRightTop = idLeftTop + dx;
int idLeftBot = idLeftTop + dy;
int idRightBot = idLeftBot + dx;
int ptsCnt = ptsIntegral[idRightBot] + ptsIntegral[idLeftTop] - (ptsIntegral[idLeftBot] + ptsIntegral[idRightTop]);
double sumGray = integral[idRightBot] + integral[idLeftTop] - (integral[idLeftBot] + integral[idRightTop]);
if (ptsCnt <= 0)
{
continue;
}
data[id2] = float(sumGray / ptsCnt);
}
}
int s = wnd / 2 * 2 + 1;
if (s > 201)
{
s = 201;
}
cv::GaussianBlur(depth, depth, cv::Size(s, s), s, s);
}
}
4. 相對於單目, 雙目相機的劣勢?
1.配置及標定比較複雜,兩個鏡頭都需要單獨標定內參和外參矩陣,然後將兩個相機聯合校準計算基線,並與出廠參數進行對照,
若相差較大,則需要重新校準;
2.雙目(900--1600)成本相對於單目相機(50--200)貴;
3.雙目相機是被動式數據獲取,單目相機是主動式數據獲取; 雙目通過視差可以獲取深度值,而單目需要運動才能獲取深度信息;
4.雙目在計算立體配準獲取視差時(像素級計算,若想圖像塊計算則會模糊深度值),需要消耗較大的計算量。而單目不需要大量或者GPU計算;
5.所以可能就是因爲從成本、計算量、實時性等方面考慮, 目前單目落地應用相比於雙目要多一些。