【雙目視覺探索路2】獲取視差圖(未完待續)
阿新 • • 發佈:2019-01-29
如前所述,本系列首先通過視差圖的實現,從直觀的角度對雙目立體視覺首先進行個大概的瞭解。
立體視覺的整體概述:
雙目立體視覺測物體空間資訊的流程順序應為: 如前一講所述,整個雙目立體視覺的實現流程可分為標定以及立體視覺的實現。標定:
標定的目的為獲得相機的內外參,其基本原理是基於相機成像平面與空間的對映對應關係(單應性)。內參為:主點位置(cx,cy),橫縱向的焦距(fx,fy);外參為相機成像平面與標定平面的R(rotation)、T(transtion)矩陣。立體視覺實現:
後面的立體標定、立體矯正、立體匹配以及對映到三維的深度對映四個部分歸屬於立體視覺實現這一部分內容。 由上一講可知:立體視覺的基本模型是基於雙目前向平行,而現實中基本不可能做到這一點,故需要通過演算法進行解決。立體標定、矯正以及匹配的大部分就是基於這個目的而採用的方法。 立體標定參考資料:
依據雙目標定可以計算出兩個相機座標系關係的矩陣:R&T,立體校正的目的就是轉換為前向平行的雙目配置。 Bouguet校正的原理為:將Rrect左乘到R分解後作用於左右座標系的矩陣。重投影矩陣
重投影矩陣Q實現了世界座標系與畫素座標系之間的轉換 Q[x,y,d,1]T=[X,Y,Z,W]T程式碼實現
由已知內外引數輸出視差圖
程式實現:
Raw data:
Experiment Results:
SAD視差圖Coding:
1,SAD
class SAD{
private:
int winSize;//卷積核尺寸
int DSR;//視差搜尋範圍
public:
SAD() :winSize(7), DSR(30){}
SAD(int _winSize, int _DSR) :winSize(_winSize), DSR(_DSR){}
Mat computerSAD(Mat&L, Mat&R);//計算SAD
};
Mat SAD::computerSAD(Mat&L, Mat&R){
int Height = L.rows;
int Width = L.cols;
Mat Kernel_L(Size(winSize, winSize), CV_8U, Scalar::all(0));
//CV_8U:0~255的值,大多數影象/視訊的格式,該段設定全0矩陣
Mat Kernel_R(Size(winSize, winSize), CV_8U, Scalar::all(0));
Mat Disparity(Height, Width, CV_8U, Scalar(0));
for (int i = 0; i < Width - winSize; ++i){
for (int j = 0; j < Height - winSize; ++j){
Kernel_L = L(Rect(i, j, winSize, winSize));//L為做影象,Kernel為這個範圍內的左圖
Mat MM(1, DSR, CV_32F, Scalar(0));//定義匹配範圍
for (int k = 0; k < DSR; ++k){
int x = i - k;
if (x >= 0){
Kernel_R = R(Rect(x, j, winSize, winSize));
Mat Dif;
absdiff(Kernel_L, Kernel_R, Dif);
Scalar ADD = sum(Dif);
float a = ADD[0];
MM.at<float>(k) = a;
}
Point minLoc;
minMaxLoc(MM, NULL, NULL, &minLoc, NULL);
int loc = minLoc.x;
Disparity.at<char>(j, i) = loc * 16;
}
double rate = double(i) / (Width);
cout << "已完成" << setprecision(2) << rate * 100 << "%" << endl;
}
}
return Disparity;
}
int main(){
Mat left = imread("1.png");
Mat right = imread("2.png");
//-------影象顯示-----------
namedWindow("leftimag");
imshow("leftimag", left);
namedWindow("rightimag");
imshow("rightimag", right);
//--------由SAD求取視差圖-----
Mat Disparity;
SAD mySAD(7, 30);
Disparity = mySAD.computerSAD(left, right);
//-------結果顯示------
namedWindow("Disparity");
imshow("Disparity",Disparity);
//-------收尾------
waitKey(0);
return 0;
}
程式解讀:
可以看到SAD演算法的效果確實很一般,而且在實際執行過程中,結果圖的邊界會出現黑色塊的現象。
主程式中先定義了卷積核尺寸為7,視差搜尋範圍為30,參見建構函式Mat SAD():winSize(),DSR(){}
computerSAD計算出視差圖。
其程式實現如下:
首先定義左右兩幅影象的kernel,大小為winSize尺寸,並定義視差圖Mat矩陣
----------------------------------------------------------------------------------------------------------------
第二步就是在影象內實現塊的遍歷匹配
塊的大小為winSize,範圍為(0:width-winSize,0:height-winSize);
遍歷方法如下
for (int k = 0; k < DSR; ++k){
int x = i - k;
if (x >= 0){
Kernel_R = R(Rect(x, j, winSize, winSize));
Mat Dif;
absdiff(Kernel_L, Kernel_R, Dif);
Scalar ADD = sum(Dif);
float a = ADD[0];
MM.at<float>(k) = a;
}
排序後便可輸出視差圖。
SGBM演算法是一種全域性匹配演算法,立體匹配的效果明顯好於區域性匹配演算法,在OpenCV中是把SGBM作為一個類對該演算法進行實現的。