转载自:https://blog.csdn.net/liulina603/article/details/53302168
一、 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
参考:http://blog.csdn.net/wqvbjhc/article/details/6260844
- 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");
- }
![](https://i-blog.csdnimg.cn/blog_migrate/006efe0a9469eeecea6180abeed37e89.png)
三、SGBM算法
作为一种全局匹配算法,立体匹配的效果明显好于局部匹配算法,但是同时复杂度上也要远远大于局部匹配算法。算法主要是参考Stereo Processing by Semiglobal Matching and Mutual Information。
opencv中实现的SGBM算法计算匹配代价没有按照原始论文的互信息作为代价,而是按照块匹配的代价。
参考:http://www.opencv.org.cn/forum.php?mod=viewthread&tid=23854
- #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;
- }
![](https://i-blog.csdnimg.cn/blog_migrate/ed05c481fdbbb5b9a8efe76afd5d0ef7.png)
四、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);
- }
![](https://i-blog.csdnimg.cn/blog_migrate/63c8c88348302f48019a86d688acfeee.png)