雙目立體視覺匹配演算法-----SAD匹配演算法、BM演算法、SGBM演算法、GC演算法
一、 SAD演算法
1.演算法原理 SAD(Sum of absolute differences)是一種影象匹配演算法。基本思想:差的絕對值之和。此演算法常用於影象塊匹配,將每個畫素對應數值之差的絕對值求和,據此評估兩個影象塊的相似度。該演算法快速、但並不精確,通常用於多級處理的初步篩選。2.基本流程
輸入:兩幅影象,一幅Left-Image,一幅Right-Image
對左圖,依次掃描,選定一個錨點:
(1)構造一個小視窗,類似於卷積核; (2)用視窗覆蓋左邊的影象,選擇出視窗覆蓋區域內的所有畫素點; (3)同樣用視窗覆蓋右邊的影象並選擇出覆蓋區域的畫素點; (4)左邊覆蓋區域減去右邊覆蓋區域,並求出所有畫素點灰度差的絕對值之和; (5)移動右邊影象的視窗,重複(3)-(4)的處理(這裡有個搜尋範圍,超過這個範圍跳出); (6)找到這個範圍內SAD值最小的視窗,即找到了左圖錨點的最佳匹配的畫素塊。
參考程式碼:SAD.h
#include"iostream" #include"opencv2/opencv.hpp" #include"iomanip" using namespace std; using namespace cv; class SAD { public: SAD():winSize(7),DSR(30){} SAD(int _winSize,int _DSR):winSize(_winSize),DSR(_DSR){} Mat computerSAD(Mat &L,Mat &R); //計算SAD private: int winSize; //卷積核的尺寸 int DSR; //視差搜尋範圍 }; 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)); 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++) //左圖從DSR開始遍歷 { for(int j=0;j<Height-winSize;j++) { Kernel_L=L(Rect(i,j,winSize,winSize)); 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; //int loc=DSR-loc; Disparity.at<char>(j,i)=loc*16; } double rate=double(i)/(Width); cout<<"已完成"<<setprecision(2)<<rate*100<<"%"<<endl; //處理進度 } return Disparity; }
// MySAD.cpp : 定義控制檯應用程式的入口點。 // #include "stdafx.h" #include"SAD.h" int _tmain(int argc, _TCHAR* argv[]) { Mat Img_L=imread("imL.png",0); Mat Img_R=imread("imR.png",0); Mat Disparity; //視差圖 //SAD mySAD; SAD mySAD(7,30); Disparity=mySAD.computerSAD(Img_L,Img_R); imshow("Img_L",Img_L); imshow("Img_R",Img_R); imshow("Disparity",Disparity); waitKey(); return 0; }
二、BM演算法:速度很快,效果一般
SGBM演算法 Stereo Processing by Semiglobal Matching and Mutual Information
GC演算法 演算法文獻:Realistic CG Stereo Image Dataset with Ground Truth Disparity Maps
- <code class="language-cpp">void BM()
- {
- IplImage * img1 = cvLoadImage("left.png",0);
- IplImage * img2 = cvLoadImage("right.png",0);
- CvStereoBMState* BMState=cvCreateStereoBMState();
- assert(BMState);
- BMState->preFilterSize=9;
- BMState->preFilterCap=31;
- BMState->SADWindowSize=15;
- BMState->minDisparity=0;
- BMState->numberOfDisparities=64;
- BMState->textureThreshold=10;
- BMState->uniquenessRatio=15;
- BMState->speckleWindowSize=100;
- BMState->speckleRange=32;
- BMState->disp12MaxDiff=1;
- CvMat* disp=cvCreateMat(img1->height,img1->width,CV_16S);
- CvMat* vdisp=cvCreateMat(img1->height,img1->width,CV_8U);
- int64 t=getTickCount();
- cvFindStereoCorrespondenceBM(img1,img2,disp,BMState);
- t=getTickCount()-t;
- cout<<"Time elapsed:"<<t*1000/getTickFrequency()<<endl;
- cvSave("disp.xml",disp);
- cvNormalize(disp,vdisp,0,255,CV_MINMAX);
- cvNamedWindow("BM_disparity",0);
- cvShowImage("BM_disparity",vdisp);
- cvWaitKey(0);
- //cvSaveImage("cones\\BM_disparity.png",vdisp);
- cvReleaseMat(&disp);
- cvReleaseMat(&vdisp);
- cvDestroyWindow("BM_disparity");
- }</code>
三、SGBM演算法
作為一種全域性匹配演算法,立體匹配的效果明顯好於區域性匹配演算法,但是同時複雜度上也要遠遠大於區域性匹配演算法。演算法主要是參考Stereo Processing by Semiglobal Matching and Mutual Information。
opencv中實現的SGBM演算法計算匹配代價沒有按照原始論文的互資訊作為代價,而是按照塊匹配的代價。
#include <highgui.h>
#include <cv.h>
#include <cxcore.h>
#include <iostream>
using namespace std;
using namespace cv;
int main()
{
IplImage * img1 = cvLoadImage("left.png",0);
IplImage * img2 = cvLoadImage("right.png",0);
cv::StereoSGBM sgbm;
int SADWindowSize = 9;
sgbm.preFilterCap = 63;
sgbm.SADWindowSize = SADWindowSize > 0 ? SADWindowSize : 3;
int cn = img1->nChannels;
int numberOfDisparities=64;
sgbm.P1 = 8*cn*sgbm.SADWindowSize*sgbm.SADWindowSize;
sgbm.P2 = 32*cn*sgbm.SADWindowSize*sgbm.SADWindowSize;
sgbm.minDisparity = 0;
sgbm.numberOfDisparities = numberOfDisparities;
sgbm.uniquenessRatio = 10;
sgbm.speckleWindowSize = 100;
sgbm.speckleRange = 32;
sgbm.disp12MaxDiff = 1;
Mat disp, disp8;
int64 t = getTickCount();
sgbm((Mat)img1, (Mat)img2, disp);
t = getTickCount() - t;
cout<<"Time elapsed:"<<t*1000/getTickFrequency()<<endl;
disp.convertTo(disp8, CV_8U, 255/(numberOfDisparities*16.));
namedWindow("left", 1);
cvShowImage("left", img1);
namedWindow("right", 1);
cvShowImage("right", img2);
namedWindow("disparity", 1);
imshow("disparity", disp8);
waitKey();
imwrite("sgbm_disparity.png", disp8);
cvDestroyAllWindows();
return 0;
}
四、GC演算法 效果最好,速度最慢
void GC()
{
IplImage * img1 = cvLoadImage("left.png",0);
IplImage * img2 = cvLoadImage("right.png",0);
CvStereoGCState* GCState=cvCreateStereoGCState(64,3);
assert(GCState);
cout<<"start matching using GC"<<endl;
CvMat* gcdispleft=cvCreateMat(img1->height,img1->width,CV_16S);
CvMat* gcdispright=cvCreateMat(img2->height,img2->width,CV_16S);
CvMat* gcvdisp=cvCreateMat(img1->height,img1->width,CV_8U);
int64 t=getTickCount();
cvFindStereoCorrespondenceGC(img1,img2,gcdispleft,gcdispright,GCState);
t=getTickCount()-t;
cout<<"Time elapsed:"<<t*1000/getTickFrequency()<<endl;
//cvNormalize(gcdispleft,gcvdisp,0,255,CV_MINMAX);
//cvSaveImage("GC_left_disparity.png",gcvdisp);
cvNormalize(gcdispright,gcvdisp,0,255,CV_MINMAX);
cvSaveImage("GC_right_disparity.png",gcvdisp);
cvNamedWindow("GC_disparity",0);
cvShowImage("GC_disparity",gcvdisp);
cvWaitKey(0);
cvReleaseMat(&gcdispleft);
cvReleaseMat(&gcdispright);
cvReleaseMat(&gcvdisp);
}