转载请注明出处:http://www.cnblogs.com/adong7639/p/4267326.html
(blog园可以看实验效果,CSDN的编辑器太烂了)
立体匹配算法最新动态:http://vision.middlebury.edu/stereo/eval/
介绍立体匹配的基本原理: http://vision.deis.unibo.it/~smatt/Seminars/StereoVision.pdf(比较清晰)
立体匹配综述性文章 : http://wenku.baidu.com/view/5b359d7d5acfa1c7aa00cc7b.html
立体匹配算法的基本目标:找出图像的每个像素点在另一个视角的图像上对应的像素点,算出视差图像,估算出景深图像。
最简单的SAD块匹配算法
这个SAD算法是比较直接的利用水平对极线约束,代码没有优化。
//Stereo Match By SAD
#include
#include
#include
#include
#include
#include
using namespace std;
using namespace cv;
DWORD t1;
DWORD t2;
void timebegin()
{
t1 = GetTickCount();
}
void timeend(string str)
{
t2 = GetTickCount();
cout << str << " is "<< (t2 - t1)/1000 << "s" << endl;
}
float sadvalue(const Mat &src1, const Mat &src2)
{
Mat matdiff = cv::abs(src1 -src2);
int saddiff = cv::sum(matdiff)[0];
return saddiff;
}
float GetMinSadIndex(std::vector &sad)
{
float minsad = sad[0];
int index = 0;
int len = sad.size();
for (int i = 1; i < len; ++i)
{
if (sad[i] < minsad)
{
minsad = sad[i];
index = i;
}
}
return index;
}
void MatDataNormal(const Mat &src, Mat &dst)
{
normalize(src, dst, 255, 0, NORM_MINMAX );
dst.convertTo(dst, CV_8UC1);
}
void GetPointDepthRight(Mat &disparity, const Mat &leftimg, const Mat &rightimg,
const int MaxDisparity, const int winsize)
{
int row = leftimg.rows;
int col = leftimg.cols;
if (leftimg.channels() == 3 && rightimg.channels() == 3)
{
cvtColor(leftimg, leftimg, CV_BGR2GRAY);
cvtColor(rightimg, rightimg, CV_BGR2GRAY);
}
//Mat disparity = Mat ::zeros(row,col, CV_32S);
int w = winsize;
int rowrange = row - w;
int colrange = col - w - MaxDisparity;
for (int i = w; i < rowrange; ++i)
{
int *ptr = disparity.ptr(i);
for (int j = w; j < colrange; ++j)
{
//Rect rightrect;
Mat rightwin = rightimg(Range(i - w,i + w + 1),Range(j - w,j + w + 1));
std::vector sad(MaxDisparity);
for (int d = j; d < j + MaxDisparity; ++d)
{
//Rect leftrect;
Mat leftwin = leftimg(Range(i - w,i + w + 1),Range(d - w,d + w + 1));
sad[d - j] = sadvalue(leftwin, rightwin);
}
*(ptr + j) = GetMinSadIndex(sad);
}
}
}
void GetPointDepthLeft(Mat &disparity, const Mat &leftimg, const Mat &rightimg,
const int MaxDisparity, const int winsize)
{
int row = leftimg.rows;
int col = leftimg.cols;
if (leftimg.channels() == 3 && rightimg.channels() == 3)
{
cvtColor(leftimg, leftimg, CV_BGR2GRAY);
cvtColor(rightimg, rightimg, CV_BGR2GRAY);
}
//Mat disparity = Mat ::zeros(row,col, CV_32S);
int w = winsize;
int rowrange = row - w;
int colrange = col - w;
for (int i = w; i < rowrange; ++i)
{
int *ptr = disparity.ptr(i);
for (int j = MaxDisparity + w; j < colrange; ++j)
{
//Rect leftrect;
Mat leftwin = leftimg(Range(i - w,i + w + 1),Range(j - w,j + w + 1));
std::vector sad(MaxDisparity);
for (int d = j; d > j - MaxDisparity; --d)
{
//Rect rightrect;
Mat rightwin = rightimg(Range(i - w,i + w + 1),Range(d - w,d + w + 1));
sad[j - d] = sadvalue(leftwin, rightwin);
}
*(ptr + j) = GetMinSadIndex(sad);
}
}
}
//(Left-Right Consistency (LRC)
void CrossCheckDiaparity(const Mat &leftdisp, const Mat &rightdisp, Mat &lastdisp,
const int MaxDisparity, const int winsize)
{
int row = leftdisp.rows;
int col = rightdisp.cols;
int w = winsize;
int rowrange = row - w;
int colrange = col - MaxDisparity - w;
int diffthreshold = 2;
for (int i = w; i < row -w; ++i)
{
const int *ptrleft = leftdisp.ptr(i);
const int *ptrright = rightdisp.ptr(i);
int *ptrdisp = lastdisp.ptr(i);
for (int j = MaxDisparity + w; j < col - MaxDisparity - w; ++j)
{
int leftvalue = *(ptrleft + j);
int rightvalue = *(ptrright + j - leftvalue );
int diff = abs(leftvalue - rightvalue);
if (diff > diffthreshold)
{
*(ptrdisp + j) = 0;
}else
{
*(ptrdisp + j) = leftvalue;
}
}
}
}
int main()
{
Mat leftimg = imread("left1.png",0);
Mat rightimg = imread("right1.png",0);
if (leftimg.channels() == 3 && rightimg.channels() == 3)
{
cvtColor(leftimg, leftimg, CV_BGR2GRAY);
cvtColor(rightimg, rightimg, CV_BGR2GRAY);
}
float scale = 1;
int row = leftimg.rows * scale;
int col = leftimg.cols * scale;
resize(leftimg, leftimg, Size( col, row));
resize(rightimg,rightimg, Size(col, row));
Mat depthleft = Mat ::zeros(row,col, CV_32S);
Mat depthright = Mat ::zeros(row,col, CV_32S);
Mat lastdisp = Mat ::zeros(row,col, CV_32S);
int MaxDisparity = 60 * scale;
int winsize = 31*scale;
timebegin();
GetPointDepthLeft(depthleft, leftimg, rightimg, MaxDisparity, winsize);
GetPointDepthRight(depthright, leftimg, rightimg, MaxDisparity, winsize);
CrossCheckDiaparity(depthleft,depthright, lastdisp, MaxDisparity, winsize);
timeend("time ");
MatDataNormal(depthleft,depthleft);
MatDataNormal(depthright, depthright);
MatDataNormal(lastdisp, lastdisp);
namedWindow("left", 0);
namedWindow("right", 0);
namedWindow("depthleft", 0);
namedWindow("depthright", 0);
namedWindow("lastdisp",0);
imshow("left", leftimg);
imshow("right", rightimg);
imshow("depthleft", depthleft);
imshow("depthright", depthright);
imshow("lastdisp",lastdisp);
string strsave = "result_";
imwrite(strsave +"depthleft.jpg", depthleft);
imwrite(strsave +"depthright.jpg", depthright);
imwrite(strsave +"lastdisp.jpg",lastdisp);
waitKey(0);
return 0;
}
OpenCv中实现了三种立体匹配算法:
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
BM算法:速度很快,效果一般
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:"<
left.png right.png disparity.jpg
SGBM算法,作为一种全局匹配算法,立体匹配的效果明显好于局部匹配算法,但是同时复杂度上也要远远大于局部匹配算法。算法主要是参考Stereo Processing by Semiglobal Matching and Mutual Information。
opencv中实现的SGBM算法计算匹配代价没有按照原始论文的互信息作为代价,而是按照块匹配的代价。
参考:http://www.opencv.org.cn/forum.php?mod=viewthread&tid=23854
#include
#include
#include
#include
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:"<
left.png right.png disparity.jpg
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"<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:"<
left.png right.png disparity.jpg
如何设置BM、SGBM和GC算法的状态参数?
参看:http://blog.csdn.net/chenyusiyuan/article/details/5967291