OpenCV C++双目三维重建:双目摄像头实现双目测距 您所在的位置:网站首页 双目相机三维重建流程 OpenCV C++双目三维重建:双目摄像头实现双目测距

OpenCV C++双目三维重建:双目摄像头实现双目测距

2024-06-27 23:05| 来源: 网络整理| 查看: 265

OpenCV C++双目三维重建:双目摄像头实现双目测距

目录

OpenCV C++双目三维重建:双目摄像头实现双目测距

1.目录结构

2.依赖库

 (1) Ubuntu 18.04配置开发环境

 (2) Windows配置开发环境

3.双目相机标定

 (1)双目相机标定-Python版

 (2)双目相机标定-Matlab版

4.相机参数配置

5. 双目测距

6. 运行Demo

7.双目测距的误差说明

8. 双目三维重建项目代码(C/C++版本)

(1)效果图

(2)源码下载

9. 双目三维重建项目代码(Python版本)

10. 双目三维重建项目代码(Android版本)

11.参考资料

本篇博文是《双目三维重建系统(双目标定+立体校正+双目测距+点云显示)Python​​​​​​》的续作,我们将搭建一个OpenCV C++版本的双目三维重建系统。由于我们只考虑三维重建实现双目测距效果,因而去除了PCL和Open3d库三维显示效果,但依然保留了视差图,深度图等可视化效果,用户可以通过鼠标点击图像,即可获得对应的世界坐标以及深度距离信息。

从效果来看,C++版本的双目测距和Python版本的效果几乎一致,性能更优,速度更快,基本可以达到工业级别测距精度,可在Linux开发板运行,非常适合应用于无人机,智能小车测距避障等场景。​

来~先看一下Demo的效果图(鼠标点击,终端会打印对应距离信息): 

c4e2af59d2c64999bbf53e1c68832d9b.gif

OpenCV C++双目摄像头实现双目测距主要支持:

支持双USB连接线的双目摄像头支持使用WLS滤波器对视差图进行滤波支持双目测距(鼠标点击图像即可获得其深度距离)提供配套的opencv-4.3.0和opencv_contrib-4.3.0源码 (Linux系统需要自行编译;Windows10系统已提供opencv_contrib编译文件,可直接复用,无需重新编译)相比Python版本,C++版本性能更优,速度更快,可在Linux开发板运行,非常适合应用于无人机,智能小车测距避障等场景。支持Linux系统:项目源码已在Ubuntu 18.04系统验证通过(需要自行编译opencv-4.3.0和opencv_contrib-4.3.0)支持Windows10系统:项目源码已在Windows10系统验证通过,配套了Visual Studio 2017项目,可直接使用其他系统平台开发,请在配置好opencv和opencv_contrib开发环境

诚然,网上有很多C++版本双测距的代码,但项目都不是十分完整,而且恢复视差图效果也一般,难以达到商业实际应用,究其原因,主要有下面几个:

双目摄像头质量问题,双目标定存在问题,导致校准误差较大没有使用WLS滤波器对视差图进行滤波,该方法可以极大提高视差图的效果

双目测距Demo视频

如果你需要Python版本的双目测距, 请查看鄙人另一篇博客《双目三维重建:双目摄像头实现双目测距(Python》

本篇将着重介绍OpenCV C++项目实现双目测距的过程,关于双目相机标定+双目校正+双目匹配等内容,请查看鄙人另一篇博客 《双目三维重建系统(双目标定+立体校正+双目测距+点云显示)Python​​​​​​》

【项目源码下载地址】OpenCV C++双目摄像头实现双目测距

【尊重原则,转载请注明出处】https://blog.csdn.net/guyuealian/article/details/127446435

1.目录结构 . ├── configs # 相机参数文件 ├── data # 相机采集的数据 ├── docs # 一些文档图片 ├── src # C++源码 ├── build.sh # 构建build脚本 ├── main.cpp # 主程序 ├── CMakeLists.txt # CMake文件 └── README.md # 说明文档 2.依赖库  (1) Ubuntu 18.04配置开发环境 系统平台:Ubuntu 18.04opencv-4.3.0 (opencv-3.4.0以上亦可)opencv_contrib-4.3.0 (opencv_contrib-3.4.0以上亦可),WLS滤波器需要用到opencv_contrib库

Ubuntu 18.04 opencv安装教程,请参考文章:Ubuntu18.04安装opencv和opencv_contrib

PS: 需确保opencv和opencv_contrib的版本号一致,避免版本差异导致编译错误。

 (2) Windows配置开发环境 系统平台:Windows10opencv-4.3.0 (opencv-3.4.0以上亦可)opencv_contrib-4.3.0 (opencv_contrib-3.4.0以上亦可),WLS滤波器需要用到opencv_contrib库

Windows opencv安装教程,请参考文章:Visual Studio 2017环境cmake编译opencv 4.3.0+opencv_contrib 4.3.0

特别说明:

鄙人是在Ubuntu 18.04平台使用CLion工具进行开发(默认编码格式utf-8),其他平台可能会出现编码格式异常的问题;特别注意,如果你在Windows系统使用Visual Studio 进行开发(默认编码格式GBK),会出现如【本地函数定义是非法的】语法异常错误等问题;解决方法也很简单,只需要在属性页的命令行中,添加/utf-8即可项目配套VS工程,可直接在Visual Studio 2017使用,其他VS版本如VS2019,VS2021需要自己配置好OpenCV路径,才能正常运行项目提供opencv 4.3.0+opencv_contrib 4.3.0,其他版本请自行编译

项目源码已经在Ubuntu 18.04和Windows10系统进行了验证;第三方依赖库只有opencv和opencv_contrib,如果你在其他系统平台开发,请自行配置好opencv和opencv_contrib开发环境;

3.双目相机标定  (1)双目相机标定-Python版

请参考鄙人另一篇博客,无需Matlab,即可进行相机标定:双目三维重建系统(双目标定+立体校正+双目测距+点云显示)Python

该方法双目标定完成后,会得到一个双目相机内外参数信息(stereo_cam.yml)文件:

%YAML:1.0 --- size: !!opencv-matrix rows: 2 cols: 1 dt: d data: [ 640., 480. ] K1: !!opencv-matrix rows: 3 cols: 3 dt: d data: [ 7.6159209686584518e+02, 0., 3.2031427422505453e+02, 0., 7.6167321445963728e+02, 2.2467546927337131e+02, 0., 0., 1. ] D1: !!opencv-matrix rows: 1 cols: 5 dt: d data: [ 3.4834574885170888e-02, -5.5261651661983137e-02, 5.7491952731614823e-04, -4.2764224824172658e-05, 1.8477350140315381e-02 ] K2: !!opencv-matrix rows: 3 cols: 3 dt: d data: [ 7.6327773941976670e+02, 0., 2.8768149948082271e+02, 0., 7.6350419442870850e+02, 2.1897333598636970e+02, 0., 0., 1. ] D2: !!opencv-matrix rows: 1 cols: 5 dt: d data: [ 3.5020972475517692e-02, -4.0770660841280497e-02, -4.4231087565750534e-04, -1.0552562170995372e-03, -9.7749906830348537e-02 ] R: !!opencv-matrix rows: 3 cols: 3 dt: d data: [ 9.9999370552351063e-01, 7.8563885326366346e-04, 3.4600122760633780e-03, -7.9503151737356746e-04, 9.9999600079883766e-01, 2.7140949167922721e-03, -3.4578661403601796e-03, -2.7168286517956050e-03, 9.9999033095517087e-01 ] T: !!opencv-matrix rows: 3 cols: 1 dt: d data: [ -6.0005833133148414e+01, 1.7047017063672587e-01, 6.0300223404957642e-01 ] E: !!opencv-matrix rows: 3 cols: 3 dt: d data: [ -1.1005724987007073e-04, -6.0346296076620343e-01, 1.6883191705475561e-01, 3.9550629985097430e-01, -1.6255182474732952e-01, 6.0007339329190145e+01, -1.2276256904913259e-01, -6.0005727085740176e+01, -1.6345135556766910e-01 ] F: !!opencv-matrix rows: 3 cols: 3 dt: d data: [ -6.7250769136371160e-10, -3.6870834234286016e-06, 1.6143104894409041e-03, 2.4160347372858321e-06, -9.9287680075344234e-07, 2.7862421257891157e-01, -1.1014218394645766e-03, -2.7856049650040260e-01, 1. ] R1: !!opencv-matrix rows: 3 cols: 3 dt: d data: [ 9.9997618806974742e-01, -2.0278309638726887e-03, -6.5963016213173775e-03, 2.0367881225372914e-03, 9.9999701250432615e-01, 1.3514719999064883e-03, 6.5935413581266105e-03, -1.3648750875444691e-03, 9.9997733090723306e-01 ] R2: !!opencv-matrix rows: 3 cols: 3 dt: d data: [ 9.9994547731576255e-01, -2.8407384289991728e-03, -1.0048512373976153e-02, 2.8270879178959596e-03, 9.9999506202764499e-01, -1.3724045434755307e-03, 1.0052361397026631e-02, 1.3439216883706559e-03, 9.9994857062992937e-01 ] P1: !!opencv-matrix rows: 3 cols: 4 dt: d data: [ 7.3741438842621210e+02, 0., 3.1126281356811523e+02, 0., 0., 7.3741438842621210e+02, 2.2189782714843750e+02, 0., 0., 0., 1., 0. ] P2: !!opencv-matrix rows: 3 cols: 4 dt: d data: [ 7.3741438842621210e+02, 0., 3.1126281356811523e+02, -4.4251577456670653e+04, 0., 7.3741438842621210e+02, 2.2189782714843750e+02, 0., 0., 0., 1., 0. ] Q: !!opencv-matrix rows: 4 cols: 4 dt: d data: [ 1., 0., 0., -3.1126281356811523e+02, 0., 1., 0., -2.2189782714843750e+02, 0., 0., 0., 7.3741438842621210e+02, 0., 0., 1.6664137886344466e-02, 0. ]

参数说明: 

参数size,对应图像宽高(width,height)参数K1,对应左目相机内参矩阵(3×3)参数D1,对应左目相机畸变系数矩阵(5×1)参数K2,对应右目相机内参矩阵(3×3)参数D2,对应右目相机畸变系数矩阵(5×1)参数T,对应双目相机平移向量T(3×1)参数R,对应双目相机旋转矩阵R(3×3)至于配置文件中的参数,如R1, R2, P1, P2, Q这些重投影矩阵,可默写即可,不用修改,这些在运行时,会重新计算。  (2)双目相机标定-Matlab版

网上已经存在很多Matlab双目相机标定的教程,请自行百度哈 ;使用Matlab工具箱进行双目相机标定后,请对应参数进行修改

需要注意的是:旋转矩阵R是(3×3)二维矩阵,而Matlab给出的是旋转向量om(1×3),请使用cv2.Rodrigues()将旋转向量转为旋转矩阵,参考下面的代码进行转换

import cv2 import numpy as np # 定义旋转矩阵R,旋转向量om R = [[9.9999370551606337e-01, 7.8563882630048958e-04, 3.4600144345510440e-03], [-7.9503149273969136e-04, 9.9999600080163187e-01, 2.7140938945082542e-03], [-3.4578682997252063e-03, -2.7168276311286426e-03, 9.9999033095047696e-01]] R = np.asarray(R) print(f"旋转矩阵R:\n {R}") # 把旋转矩阵R转化为旋转向量om om, _ = cv2.Rodrigues(R) print(f"旋转向量om:\n {om}") # 把旋转向量om转换为旋转矩阵R R1, _ = cv2.Rodrigues(om) print(f"旋转矩阵R1:\n {R1}") 4.相机参数配置 双目相机标定完成后,得到了相机内外参数信息根据自己相机参数定义C++的CameraParam即可下面C++代码中,定义了双目相机CameraParam变量camera1,用户需要根据自己的双目相机,修改对应的相机内外参数。 /** * 双目摄像头的相机参数 */ struct CameraParam { int width; //图像的宽度width int height; //图像的高度height Mat cameraMatrixL; //左相机内参K1(3×3) Mat distCoeffL; //左相机畸变系数D1(5×1) Mat cameraMatrixR; //右相机内参K2(3×3) Mat distCoeffR; //右相机畸变系数D2(5×1) Mat T; //平移向量T(3×1) Mat R; //旋转矩阵R(3×3),如果是(3×1)旋转向量,请使用cv::Rodrigues()进行变换转为(3×3)旋转矩阵R }; /*** * 设置摄像头参数,需要根据双目摄像头标定结果进行填写 */ static CameraParam camera1 = { 640,//width 480,//height (Mat_(3, 3) frameR; if (frameL.empty() or frameR.empty()) break; detector->task(frameL, frameR, 20); } capL.release(); //释放对相机的控制 capR.release(); //释放对相机的控制 delete detector; return 0; } /*** * 测试一对左右图像 * @return */ int test_pair_image_file() { CameraParam camera = camera1;//双目相机参数 bool use_wls = true; //是否使用WLS滤波器对视差图进行滤波 StereoReconstruct *detector = new StereoReconstruct(camera, use_wls); Mat frameL = imread("../data/left.png", IMREAD_COLOR); Mat frameR = imread("../data/right.png", IMREAD_COLOR); detector->task(frameL, frameR, 0); delete detector; return 0; } int main() { //测试一对左右图像 test_pair_image_file(); //测试demo视频文件 test_video_file(); //测试双目摄像头(双USB连接线的双目摄像头) test_camera(); return 0; } 终端运行脚本:bash build.sh #!/usr/bin/env bash if [ ! -d "build/" ];then mkdir "build" else echo "exist build" fi cd build cmake .. make -j4 sleep 1 ./Demo 7.双目测距的误差说明

 双目测距的误差和精度说明:

有网友反馈,测量精度较差,在评估测量精度前,请严格按照博文进行相机标定,标定误差不能超过0.1,否则测距误差较大理论上双目的测量精度可以达到毫米(mm)级别,但并非无条件的,根据上式可以看出,某点像素的深度精度取决于该点处估计的视差d的精度。假设视差d的误差恒定,当测量距离越远,得到的深度精度则越差,因此使用双目相机不适宜测量太远的目标。如果想要对与较远的目标能够得到较为可靠的深度,一方面需要提高相机的基线距离,但是基线距离越大,左右视图的重叠区域就会变小,内容差异变大,从而提高立体匹配的难度,另一方面可以选择更大焦距的相机,然而焦距越大,相机的视域则越小,导致离相机较近的物体的距离难以估计。理论上,深度方向的测量误差与测量距离的平方成正比,而X/Y方向的误差与距离成正比;而距离很近时,由于存在死角,会导致难以匹配的问题;想象一下,如果你眼前放置一块物体,那你左眼只能看到物体左侧表面,右眼同理只能看到物体右侧表面,这时由于配准失败,导致视差计算失败;这个问题在基线越长,问题就越严重下图给出双目测距误差和测量距离的关系,一般有效的测量距离是0.6米到6米之间 8. 双目三维重建项目代码(C/C++版本) (1)效果图

C++版本的双目测距与Python版本的效果几乎一致。从重建效果来看,未使用WLS滤波,其视差图出现了很多空洞,存在很多误匹配点;但使用WLS滤波后,视差图变得比较平滑,整体效果都有明显改善。

左视图右视图5a3336fbf4af441a841d588af792f80a.pngebd6856f807944fcb860151375cd4e87.png​视差图(未滤波)深度图(未滤波)f8d06f5f839142eca3b921b19661c18b.pngd2b1c330bc164790abbc72ead1ee7bd5.png​视差图(滤波后)深度图(滤波后)5e265a93d39442ba9a861a3090bd2b58.pngb883a3e05140451499e1aeb99ae12434.png​  运行主程序后,鼠标点击depth-color窗口的图像任意区域,终端会打印对应距离信息

132861d6b5fd489f9e35ea7926eb5857.gif

(2)源码下载

OpenCV C++版本双目测距项目代码包含:OpenCV C++双目摄像头实现双目测距

 【项目源码下载地址】OpenCV C++双目摄像头实现双目测距

支持双USB连接线的双目摄像头支持使用WLS滤波器对视差图进行滤波支持双目测距(鼠标点击图像即可获得其深度距离)提供配套的opencv-4.3.0和opencv_contrib-4.3.0源码 (Linux系统需要自行编译;Windows10系统已提供opencv_contrib编译文件,可直接复用,无需重新编译)相比Python版本,C++版本性能更优,速度更快,可在Linux开发板运行,非常适合应用于无人机,智能小车测距避障等场景。支持Linux系统:项目源码已在Ubuntu 18.04系统验证通过(需要自行编译opencv-4.3.0和opencv_contrib-4.3.0)支持Windows10系统:项目源码已在Windows10系统验证通过,配套了Visual Studio 2017项目,可直接使用;其他VS版本,如VS2019,VS2021需要自己配置好OpenCV路径,才能正常运行其他系统平台开发,请在配置好opencv和opencv_contrib开发环境 9. 双目三维重建项目代码(Python版本)

如果你需要Python版本的双目测距, 请查看鄙人另一篇博客《双目三维重建系统(双目标定+立体校正+双目测距+点云显示)Python》

双目测距Demo视频

10. 双目三维重建项目代码(Android版本)

如果你需要Android版本的双目测距, 请查看鄙人另一篇博客《Android OpenCV实现双目三维重建:双目摄像头实现双目测距》

       

11.参考资料 OpenCV C++双目三维重建:双目摄像头实现双目测距双目三维重建:双目摄像头实现双目测距(Python)双目三维重建系统(双目标定+立体校正+双目测距+点云显示)PythonUbuntu18.04安装opencv和opencv_contrib


【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有