opencv C++ SGBM/BM立体匹配,视差空洞消除,双目测距

这篇博客介绍了如何利用OpenCV进行立体视觉处理,包括从YAML文件读取相机内外参数,应用SGBM算法计算视差图,并通过极线矫正展示结果。同时,文章提供了编译OpenCV Contrib模块以包含ximgproc模块的步骤,解决了编译过程中可能遇到的问题。
摘要由CSDN通过智能技术生成

git代码下载地址:GitHub - liuanqi-libra7/stereoVision: stereoVision

原始数据

输出优化后的视差结果

核心代码

#include <stdio.h>
#include <iostream>
#include <string>
#include <vector>
#include "opencv2/opencv.hpp"
#include "opencv2/ximgproc.hpp"

using namespace cv;
using namespace std;
using namespace ximgproc;

bool get_calib(std::string intrinsic_filename, std::string extrinsic_filename, Size img_size, vector<Mat>& matrixs) {
	FileStorage fs(intrinsic_filename, FileStorage::READ);
	if (!fs.isOpened())
	{
		printf("Failed to open file %s\n", intrinsic_filename.c_str());
		return false;
	}

	Mat M1, D1, M2, D2;
	fs["M1"] >> M1;
	fs["D1"] >> D1;
	fs["M2"] >> M2;
	fs["D2"] >> D2;

	fs.open(extrinsic_filename, FileStorage::READ);
	if (!fs.isOpened())
	{
		printf("Failed to open file %s\n", extrinsic_filename.c_str());
		return false;
	}

	Mat R, T, R1, P1, R2, P2;
	fs["R"] >> R;
	fs["T"] >> T;

	Rect roi1, roi2;
	Mat Q;

	stereoRectify(M1, D1, M2, D2, img_size, R, T, R1, R2, P1, P2, Q, CALIB_ZERO_DISPARITY, -1, img_size, &roi1, &roi2);

	Mat map11, map12, map21, map22;
	initUndistortRectifyMap(M1, D1, R1, P1, img_size, CV_16SC2, map11, map12);
	initUndistortRectifyMap(M2, D2, R2, P2, img_size, CV_16SC2, map21, map22);
	matrixs.push_back(map11);
	matrixs.push_back(map12);
	matrixs.push_back(map21);
	matrixs.push_back(map22);
	matrixs.push_back(Q);

	return true;
}

int main(int argc, char** argv){

	std::string intrinsic_filename = "1280_720_intrinsics.yml";
	std::string extrinsic_filename = "1280_720_extrinsics.yml";
	Size img_size(1280, 720);

	//读取内外参数
	vector<Mat> matrixs;
	if (!get_calib(intrinsic_filename, extrinsic_filename, img_size, matrixs)) {
		printf("get_calib fail\n");
		return -1;
	};

	//SGBM/BM参数初始化,依据自己场景做调整
	int window_size = 5;
	int blockSize = 5;
	int minDisparity = 128;
	int numDisparities = 128 * 2;
	int P1 = 8 * 3 * window_size*window_size;
	int P2 = 32 * 3 * window_size*window_size;
	int disp12MaxDiff = 1;
	int preFilterCap = 63;
	int uniquenessRatio = 15;
	int speckleWindowSize = 0;
	int speckleRange = 2;

#if 1 //SGBM
	Ptr<StereoSGBM> left_matcher = StereoSGBM::create();
	//Ptr<StereoBM>left_matcher = StereoBM::create(16, 9);
	left_matcher->setMinDisparity(-minDisparity);
	left_matcher->setNumDisparities(numDisparities);
	left_matcher->setBlockSize(blockSize);
	left_matcher->setP1(P1);
	left_matcher->setP2(P2);
	left_matcher->setDisp12MaxDiff(disp12MaxDiff);
	left_matcher->setPreFilterCap(preFilterCap);
	left_matcher->setUniquenessRatio(uniquenessRatio);
	left_matcher->setSpeckleWindowSize(speckleWindowSize);
	left_matcher->setSpeckleRange(speckleRange);
	left_matcher->setMode(StereoSGBM::MODE_SGBM_3WAY);
#else //BM
	Ptr<StereoBM>left_matcher = StereoBM::create(16, 9);
	left_matcher->setMinDisparity(-minDisparity);
	left_matcher->setNumDisparities(numDisparities);
	left_matcher->setBlockSize(blockSize);
	left_matcher->setDisp12MaxDiff(disp12MaxDiff);
	left_matcher->setPreFilterCap(preFilterCap);
	left_matcher->setUniquenessRatio(uniquenessRatio);
	left_matcher->setSpeckleWindowSize(speckleWindowSize);
	left_matcher->setSpeckleRange(speckleRange);
#endif

	//RightMatcher 初始化
	int lmbda = 8000;
	int sigma = 1.5;
	Ptr<StereoMatcher> right_matcher = cv::ximgproc::createRightMatcher(left_matcher);
	auto wls_filter = cv::ximgproc::createDisparityWLSFilter(left_matcher);
	wls_filter->setLambda(lmbda);
	wls_filter->setSigmaColor(sigma);

	Mat img_full, left_img, right_img, left_img_remap, right_img_remap;
	Mat disp_left, disp_right, disp_end, disp_show;
	Mat threeD3;

	img_full = imread("20220804154537.jpg");
	if (img_full.empty()) {
		cout << "No img Data" << endl;
		return -1;
	}
	left_img  = img_full(Rect(0, 0, 1280, 720));
	right_img = img_full(Rect(1280, 0, 1280, 720));

	cvtColor(left_img,  left_img,  CV_BGR2GRAY);
	cvtColor(right_img, right_img, CV_BGR2GRAY);
	remap(left_img,   left_img_remap, matrixs[0], matrixs[1], INTER_LINEAR);
	remap(right_img, right_img_remap, matrixs[2], matrixs[3], INTER_LINEAR);

#if 1 //显示极线矫正后的结果
	Mat remap_full(Size(2560, 720), CV_8UC1);
	left_img_remap.copyTo(remap_full(Rect(0, 0, 1280, 720)));// = left_img_remap.clone();
	right_img_remap.copyTo(remap_full(Rect(1280, 0, 1280, 720)));// = right_img_remap.clone();

	for (int kk = 0; kk < 720; kk+=50){
		line(remap_full, Point(0, kk), Point(2560, kk), Scalar(255), 2);
	}

#endif
	left_matcher->compute(left_img_remap, right_img_remap, disp_left);
	right_matcher->compute(right_img_remap, left_img_remap, disp_right);
	wls_filter->filter(disp_left, left_img, disp_end, disp_right);

	disp_end.setTo(0, disp_end < 0);
	cv::normalize(disp_end, disp_show, 0, 255, CV_MINMAX, CV_8U);
	reprojectImageTo3D(disp_end, threeD3, matrixs[4], true); 
	threeD3 *= 16; 
	threeD3 /= 1000.; //以米为单位
	vector<Mat> split_vec;
	split(threeD3, split_vec);
	auto x = split_vec[0].clone();
	auto y = split_vec[1].clone(); 
	auto z = split_vec[2].clone();
	cv::imshow("left_img", left_img);
	cv::imshow("disp_show", disp_show);
	cv::waitKey();
}

极线矫正结果图

左视差效果图

右视差效果图

视差空洞填充后效果图

(ximgproc::createRightMatcher依据左右视差,类似双边滤波操作)

该工程用到了opencv contrib中的ximgproc模块,所以需要对opencv进行重编译,把Contrib库编译进去,编译步骤如下:

Opencv Contrib 库安装

系统要求:ubuntu18.04
软件要求:vscode, opencv 3.4.9, opencv_contrib 3.4.9, mingw-w64, cmake-gui工具

opencv下载地址:https://github.com/opencv/opencv/archive/3.4.9.zip
contrib 下载地址: https://github.com/opencv/opencv_contrib/releases/tag/3.4.9
 

下载cmake-gui工具和mingw-w64,运行以下命令即可

$ sudo apt install cmake-qt-gui
$ sudo apt install mingw-w64

安装opencv依赖

$ sudo apt install cmake  
$ sudo apt install build-essential libgtk2.0-dev libavcodec-dev libavformat-dev libjpeg.dev libtiff4.dev libswscale-dev libjasper-dev

编译安装opencv

打开cmake-gui,设置opencv源文件路径,以及Build的路径

CmakeSetup窗口默认选择,随后点击Configure按钮

1. 在搜索栏搜索EXTRA,将OPENCV_EXTRA_MODULE_PATH的值改成/path/to/opencv_contrib-3.4.9/modules
2. 修改install的路径,以防和其他opencv版本冲突

然后再点击Configure --> Generate

Cmake过程中遇到问题解决

Q:fatal error: boostdesc_bgm.i无法下载

A:执行以下脚本,下载好放到指定目录opencv_contrib-3.4.9/modules/xfeatures2d/cmake/cache

#!/bin/bash
cd ./cache/xfeatures2d/
cd boostdesc

curl https://raw.githubusercontent.com/opencv/opencv_3rdparty/34e4206aef44d50e6bbcd0ab06354b52e7466d26/boostdesc_lbgm.i > 0ae0675534aa318d9668f2a179c2a052-boostdesc_lbgm.i
curl https://raw.githubusercontent.com/opencv/opencv_3rdparty/34e4206aef44d50e6bbcd0ab06354b52e7466d26/boostdesc_binboost_256.i > e6dcfa9f647779eb1ce446a8d759b6ea-boostdesc_binboost_256.i
curl https://raw.githubusercontent.com/opencv/opencv_3rdparty/34e4206aef44d50e6bbcd0ab06354b52e7466d26/boostdesc_binboost_128.i > 98ea99d399965c03d555cef3ea502a0b-boostdesc_binboost_128.i
curl https://raw.githubusercontent.com/opencv/opencv_3rdparty/34e4206aef44d50e6bbcd0ab06354b52e7466d26/boostdesc_binboost_064.i > 202e1b3e9fec871b04da31f7f016679f-boostdesc_binboost_064.i
curl https://raw.githubusercontent.com/opencv/opencv_3rdparty/34e4206aef44d50e6bbcd0ab06354b52e7466d26/boostdesc_bgm_hd.i > 324426a24fa56ad9c5b8e3e0b3e5303e-boostdesc_bgm_hd.i
curl https://raw.githubusercontent.com/opencv/opencv_3rdparty/34e4206aef44d50e6bbcd0ab06354b52e7466d26/boostdesc_bgm_bi.i > 232c966b13651bd0e46a1497b0852191-boostdesc_bgm_bi.i
curl https://raw.githubusercontent.com/opencv/opencv_3rdparty/34e4206aef44d50e6bbcd0ab06354b52e7466d26/boostdesc_bgm.i > 0ea90e7a8f3f7876d450e4149c97c74f-boostdesc_bgm.i
cd ../vgg
curl https://raw.githubusercontent.com/opencv/opencv_3rdparty/fccf7cd6a4b12079f73bbfb21745f9babcd4eb1d/vgg_generated_120.i > 151805e03568c9f490a5e3a872777b75-vgg_generated_120.i
curl https://raw.githubusercontent.com/opencv/opencv_3rdparty/fccf7cd6a4b12079f73bbfb21745f9babcd4eb1d/vgg_generated_64.i > 7126a5d9a8884ebca5aea5d63d677225-vgg_generated_64.i
curl https://raw.githubusercontent.com/opencv/opencv_3rdparty/fccf7cd6a4b12079f73bbfb21745f9babcd4eb1d/vgg_generated_48.i > e8d0dcd54d1bcfdc29203d011a797179-vgg_generated_48.i
curl https://raw.githubusercontent.com/opencv/opencv_3rdparty/fccf7cd6a4b12079f73bbfb21745f9babcd4eb1d/vgg_generated_80.i > 7cd47228edec52b6d82f46511af325c5-vgg_generated_80.i

Q:face_landmark_model.dat无法下载

A:按照下方链接下载好放到指定目录,并修改对应face模块makefile,修改方式如下图 

下载地址https://raw.githubusercontent.com/opencv/opencv_3rdparty/8afa57abc8229d611c4937165d20e2a2d9fc5a12/face_landmark_model.dat

$ cd /cmake时候你指定的opencv build path/
$ sudo make -j32
$ sudo make install 

  • 7
    点赞
  • 50
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: 双目重建,是利用双目立体视觉原理,通过计算图像中对应点之间的位移和深度信息来实现三维物体的重建。而OpenCV C是一个用于计算机视觉和机器学习的开源计算机视觉库,包含了许多用于处理和分析图像的算法和函数。 OpenCV C的双目重建实现常用的方法是基于两张图像的匹配点来计算深度信息,匹配点可以通过SIFT、ORB等算法来得到。通过匹配点,我们可以估算出两张图像之间的位置关系和角度关系,进而得到深度信息。 在OpenCV C中,使用双目重建需要先对两张图像进行校正,以消除由于摄像机位置和配置不同而引起的图像失真,然后通过计算两张图像之间的位移和深度信息生成三维视图。 需要注意的是,双目重建的过程非常复杂,实现起来需要掌握相对较高的图像处理和计算机视觉算法知识。同时,还需要选择合适的硬件设备来对处理后的数据进行实时渲染和操作,以达到较好的视觉效果。 总的来说,OpenCV C的双目重建是一个非常有用的工具,为许多计算机视觉和机器学习应用提供了基础支持。但要注意,此技术需要使用者精通相关领域的基础知识,才能够进一步将其应用于实际项目中。 ### 回答2: 双目重建是基于双目摄像机的三维重建技术,也是计算机视觉领域的重要研究方向之一。在使用双目摄像机进行三维重建时,需要通过摄像机拍摄场景中物体在不同位置的多张图片,分别通过双目校正和匹配算法获取图像间的对应点,然后通过三角测量等数学方法计算出该物体在空间中的三维坐标。 OpenCV是一个开源的计算机视觉库,其包含了很多用于图像处理和计算机视觉的函数和工具。在OpenCV中,可以使用双目摄像机进行图像采集和双目校正,也可通过SGBM(Semi-Global Block Matching)算法等方法进行视差图的计算和深度图的重建。 具体使用步骤为首先进行双目相机标定,包括标定板的拍摄、角点检测和相机内外参数计算,以便进行双目校正。接着进行图像采集和双目校正,使用SGBM算法计算视差图。最后,通过三角测量或其他方法将视差图转化为深度图,实现三维重建。 双目重建技术广泛应用于机器人视觉、自动驾驶、医学影像等领域。在OpenCV中,通过使用C/C++等编程语言,灵活自由地进行双目重建,满足各种需求。 ### 回答3: 双目重建是利用双目摄像机采集的左右两张图像,通过视差计算方法获得物体在三维空间中的位置,并进行三维重建的过程。OpenCV是一种广泛使用的计算机视觉库,提供了对双目摄像机进行三维重建的支持。 在OpenCV中,双目重建的流程主要可以分为四个步骤:相机标定、视差计算、三维重建和显示或保存。首先进行相机标定,校正左右两个摄像机的畸变,确定两个摄像机之间的基线距离和内参矩阵等参数。 接下来进行视差计算,可以使用OpenCV中的BM算法、SGBM算法或自定义算法等方法,得到每个像素点的视差值。然后根据一定的三角剖分方法,将图片中的点云构建成三维模型。 最后,利用OpenGL等图形处理库对三维模型进行显示或保存,生成最终的三维重建结果。总的来说,OpenCV提供了非常方便的双目重建工具,能够实现高效、精度较高的三维重建效果。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值