立体匹配算法

  • Post author:
  • Post category:其他



立体匹配算法

转载请注明出处:

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 <opencv2/opencv.hpp>
#include <vector>
#include <algorithm>
#include <iostream>  
#include <windows.h>  
#include <string>  

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<float> &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<int>(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<float> 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<int>(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<float> 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<int>(i);
        const int *ptrright = rightdisp.ptr<int>(i);
        int *ptrdisp = lastdisp.ptr<int>(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:"<<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");
}














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 <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;
}

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"<<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("D:\\project\\双目测距\\stereomatch\\测试图像\\GC_right_disparity.png",gcvdisp);


    cvNamedWindow("GC_disparity",0);
    cvShowImage("GC_disparity",gcvdisp);
    cvWaitKey(0);
    cvReleaseMat(&gcdispleft);
    cvReleaseMat(&gcdispright);
    cvReleaseMat(&gcvdisp);
}

























left.png       right.png                disparity.jpg



如何设置BM、SGBM和GC算法的状态参数?



参看:

http://blog.csdn.net/chenyusiyuan/article/details/5967291




版权声明:本文为adong76原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。