如前所述,本系列首先通过视差图的实现,从直观的角度对双目立体视觉首先进行个大概的了解。
1,SAD
参考代码:双目立体视觉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(k) = a;
}
Point minLoc;
minMaxLoc(MM, NULL, NULL, &minLoc, NULL);
int loc = minLoc.x;
Disparity.at(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(k) = a;
}
排序后便可输出视差图。
SGBM算法是一种全局匹配算法,立体匹配的效果明显好于局部匹配算法,在OpenCV中是把SGBM作为一个类对该算法进行实现的。