双目立体匹配方法:BM、SGBM、GC算法的实现及性能对比(附代码)

在双目立体匹配中,有基于SAD算法的BM、SGBM、GC立体匹配技术,但是在OpenCv3.0以后,GC算法就从legacy中去除掉了。为了查看三种算法的匹配效果及运算性能,我在Windows10中安装了OpenCv2.4.9,并以VsCode为IDE进行程序编写。

一、VsCode中集成OpenCv2.4.9

VsCode中集成OpenCv2.4.9,我主要是参照了这个文章的方法,根据这位博主的方法,我完成了环境的配置,由于需要相应的legacy库,所以我的tasks.json如下所示

{
    // See https://go.microsoft.com/fwlink/?LinkId=733558
    // for the documentation about the tasks.json format
    "version": "2.0.0",
    "command": "g++",
    "args": [
        "-g", 
        "-std=c++11", 
        "${file}", 
        "-o", 
        "${fileBasenameNoExtension}.exe",  
        "-I", "F:\\opencv\\build\\include",
        "-I", "F:\\opencv\\build\\include\\opencv2",
        "-I", "F:\\opencv\\build\\include\\opencv",
        "-L", "F:\\opencv\\build\\x64\\MinGW\\lib",
        "-l", "opencv_core249",
        "-l", "opencv_imgproc249",
        "-l", "opencv_video249",
        "-l", "opencv_ml249",
        "-l", "opencv_highgui249",
        "-l", "opencv_objdetect249",
        "-l", "opencv_flann249",
        "-l", "opencv_photo249",
        "-l", "opencv_legacy249",
        "-l", "opencv_calib3d249"
    ],// 编译命令参数
    "problemMatcher":{
        "owner": "cpp",
        "fileLocation":[
            "relative",
            "${workspaceFolder}"
        ],
        "pattern":[
            {
                "regexp": "^([^\\\\s].*)\\\\((\\\\d+,\\\\d+)\\\\):\\\\s*(.*)$",
                "file": 1,
                "location": 2,
                "message": 3
            }
        ]
    },
    "group": {
        "kind": "build",
        "isDefault": true
    }
  }
  

二、程序的实现

程序实现的文章参考了OpenCV三种立体匹配求视差图算法总结这篇博客,同时也有对官网例程的参考。程序的完整代码如下:

#include <ctime> 
#include <math.h>  
#include <iostream>

#include "opencv2/calib3d/calib3d.hpp"    
#include "opencv2/imgproc/imgproc.hpp"    
#include "opencv2/highgui/highgui.hpp"    
#include "opencv2/contrib/contrib.hpp"   
#include "opencv2/legacy/legacy.hpp" 
#include <opencv2/nonfree/features2d.hpp>
#include <opencv2/features2d/features2d.hpp>

using namespace std;
using namespace cv;

enum { STEREO_BM=0, STEREO_SGBM=1, STEREO_HH=2, STEREO_VAR=3 };
int alg = STEREO_SGBM;

int main()
{
    time_t begin,end;
    double ret;
    int SADWindowSize = 0, numberOfDisparities = 0;

    IplImage * img1 = cvLoadImage("D:/projects/images/Cones_l.png",0);
    IplImage * img2 = cvLoadImage("D:/projects/images/Cones_r.png",0);

    Mat left = imread("D:/projects/images/Cones_l.png",0);
    Mat right = imread("D:/projects/images/Cones_r.png",0);
    Size img_size = left.size();

    CvMat* displeft=cvCreateMat(img1->height,img1->width,CV_16S);
    CvMat* dispright=cvCreateMat(img2->height,img2->width,CV_16S);
    CvMat* disp=cvCreateMat(img1->height,img1->width,CV_8U);

    //BM算法
    CvStereoBMState *BMState = cvCreateStereoBMState();
    numberOfDisparities = numberOfDisparities > 0 ? numberOfDisparities : ((img_size.width/8) + 15) & -16;
    BMState->SADWindowSize = SADWindowSize > 0 ? SADWindowSize : 9;
    BMState->minDisparity = 0;
    BMState->numberOfDisparities = numberOfDisparities;
    BMState->textureThreshold = 10;
    BMState->uniquenessRatio = 15;
    BMState->speckleWindowSize = 100;
    BMState->speckleRange = 32;
    BMState->disp12MaxDiff = 1;
    begin=clock();
    cvFindStereoCorrespondenceBM( img1, img2, displeft,BMState);
    end=clock();
    ret=double(end-begin)/CLOCKS_PER_SEC;
    cout<<"BM algorithm runtime:   "<<ret<<" s"<<endl;
    cvNormalize( displeft, disp, 0, 255, CV_MINMAX );
    cvSaveImage("BM_right_disparity.png",disp);

    cvNamedWindow("BM_disparity",0);
    cvShowImage("BM_disparity",disp);


    //SGBM算法
    StereoSGBM sgbm;
	sgbm.preFilterCap = 63;
    sgbm.SADWindowSize = SADWindowSize > 0 ? SADWindowSize : 5;
    numberOfDisparities = numberOfDisparities > 0 ? numberOfDisparities : ((img_size.width/8) + 15) & -16;
	int cn = left.channels();
	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;
    sgbm.fullDP = alg == STEREO_HH;
    Mat disp_, disp8;
	//sgbm(left , right , left_disp);
	begin=clock();
	sgbm(left, right, disp_);
    disp_.convertTo(disp8, CV_8U,255/(numberOfDisparities*16.));
    end=clock();
    ret=double(end-begin)/CLOCKS_PER_SEC;
    cout<<"SGBM algorithm runtime:   "<<ret<<" s"<<endl;
    imwrite("SGBM_disparity.png",disp8);
    namedWindow("SGBM_disparity",WINDOW_AUTOSIZE);
    imshow("SGBM_disparity",disp8);

    //GC算法
    numberOfDisparities = numberOfDisparities > 0 ? numberOfDisparities : ((img1->width/8) + 15) & -16;
    CvStereoGCState* GCState=cvCreateStereoGCState(numberOfDisparities,2);   //原始为64 3
    assert(GCState);
    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);    
    begin=clock();  
    cvFindStereoCorrespondenceGC(img1,img2,gcdispleft,gcdispright,GCState);
    end=clock();
    ret=double(end-begin)/CLOCKS_PER_SEC;
    cout<<"GC algorithm runtime:   "<<ret<<" s"<<endl;
    cvNormalize(gcdispright,gcvdisp,0,255,CV_MINMAX);
    cvSaveImage("GC_disparity.png",gcvdisp);
    cvNamedWindow("GC_disparity",0);
    cvShowImage("GC_disparity",gcvdisp);
    cvWaitKey(0);
    cvReleaseMat(&displeft);
    cvReleaseMat(&dispright);
    cvReleaseMat(&disp);
    cvReleaseMat(&gcdispleft);
    cvReleaseMat(&gcdispright);
    cvReleaseMat(&gcvdisp);    
    return 0;

三、效果对比

我的电脑为联想拯救者Y7000,在上面运行,三种算法的时间分别为BM:8ms,SGBM:33ms,GC:2030ms,效果图如下:
Cones_l.png
在这里插入图片描述
Cones_r.png
在这里插入图片描述

BM算法

在这里插入图片描述

SGBM算法
在这里插入图片描述

GC算法
在这里插入图片描述

  • 3
    点赞
  • 88
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
以下是双目立体匹配算法SGM的实时代码: ``` #include <iostream> #include <opencv2/opencv.hpp> using namespace std; using namespace cv; const int max_image_size = 960; const int max_disparity = 64; const int P1 = 5; const int P2 = 70; const int penalty_scale = 10; const int uniqueness_ratio = 15; const int speckle_window_size = 100; const int speckle_range = 32; int main(int argc, char** argv) { if(argc != 3) { cout << "Usage: ./sgm_stereo left_image right_image" << endl; return -1; } Mat imgL = imread(argv[1], IMREAD_GRAYSCALE); Mat imgR = imread(argv[2], IMREAD_GRAYSCALE); if(imgL.empty() || imgR.empty()) { cout << "Error: Could not open or find the images" << endl; return -1; } int width = imgL.cols; int height = imgL.rows; if(width > max_image_size || height > max_image_size) { cout << "Error: Image size too large" << endl; return -1; } int min_disparity = 0; int max_disparity = 64; Mat disparity_map = Mat::zeros(height, width, CV_8UC1); for(int y = 0; y < height; y++) { for(int x = 0; x < width; x++) { int min_cost = INT_MAX; int best_disparity = min_disparity; for(int d = min_disparity; d < max_disparity; d++) { int sum = 0; int count = 0; for(int dy = -1; dy <= 1; dy++) { for(int dx = -1; dx <= 1; dx++) { int xl = x + dx; int xr = x + dx - d; if(xl < 0 || xl >= width || xr < 0 || xr >= width) { continue; } int diff = abs((int)imgL.at<uchar>(y+dy, x+dx) - (int)imgR.at<uchar>(y+dy, xr)); sum += diff; count++; } } int cost = sum / count; if(d > min_disparity) { int diff = abs(d - best_disparity); cost += (diff == 1) ? P1 : (P1 + (diff - 1) * P2); } if(cost < min_cost) { min_cost = cost; best_disparity = d; } } disparity_map.at<uchar>(y, x) = best_disparity; } } Ptr<StereoSGBM> stereo = StereoSGBM::create(min_disparity, max_disparity, penalty_scale, 8 * imgL.channels() * speckle_window_size * speckle_window_size, 32 * speckle_range, uniqueness_ratio, StereoSGBM::MODE_SGBM_3WAY); stereo->compute(imgL, imgR, disparity_map); namedWindow("Disparity Map", WINDOW_NORMAL); imshow("Disparity Map", disparity_map); waitKey(0); return 0; } ``` 需要注意的是,此代码只是SGM算法实现之一,针对不同的场景和需求,实现方式可能会有所不同。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值