1. 程式人生 > >雙目立體視覺匹配演算法-----SAD匹配演算法、BM演算法、SGBM演算法、GC演算法

雙目立體視覺匹配演算法-----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

  1. <code class="language-cpp">void BM()  
  2. {  
  3.   IplImage * img1 = cvLoadImage("left.png",0);  
  4.     IplImage * img2 = cvLoadImage("right.png",0);  
  5.     CvStereoBMState* BMState=cvCreateStereoBMState();  
  6.     assert(BMState);  
  7.     BMState->preFilterSize=9;  
  8.     BMState->preFilterCap=31;  
  9.     BMState->SADWindowSize=15;  
  10.     BMState->minDisparity=0;  
  11.     BMState->numberOfDisparities=64;  
  12.     BMState->textureThreshold=10;  
  13.     BMState->uniquenessRatio=15;  
  14.     BMState->speckleWindowSize=100;  
  15.     BMState->speckleRange=32;  
  16.     BMState->disp12MaxDiff=1;  
  17.     CvMat* disp=cvCreateMat(img1->height,img1->width,CV_16S);  
  18.     CvMat* vdisp=cvCreateMat(img1->height,img1->width,CV_8U);  
  19.     int64 t=getTickCount();  
  20.     cvFindStereoCorrespondenceBM(img1,img2,disp,BMState);  
  21.     t=getTickCount()-t;  
  22.     cout<<"Time elapsed:"<<t*1000/getTickFrequency()<<endl;  
  23.     cvSave("disp.xml",disp);  
  24.     cvNormalize(disp,vdisp,0,255,CV_MINMAX);  
  25.     cvNamedWindow("BM_disparity",0);  
  26.     cvShowImage("BM_disparity",vdisp);  
  27.     cvWaitKey(0);  
  28.     //cvSaveImage("cones\\BM_disparity.png",vdisp);  
  29.     cvReleaseMat(&disp);  
  30.     cvReleaseMat(&vdisp);  
  31.     cvDestroyWindow("BM_disparity");  
  32. }</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);
}