点击上方“计算机视觉工坊”,选择“星标”

干货第一时间送达

作者:本文为3D视觉开发者社区特约作者-熊猫飞天授权发布。

引言:本教程主要内容为介绍如何使用双目相机计算出稠密的3D点云。主要涉及到elas包的使用,通过KITTI数据集和ZED相机进行测试。在机器人导航中深度图是产生稠密3D环境地图的重要数据,在室内机器人一般使用基于主动红外测距原理的RGB-D相机(比如kinect)获取深度图像,RGB-D相机由于其测量范围和原理导致它主要适用于室内环境中。在室外环境中由于双目相机没有尺度问题,通常使用双目相机计算深度图。

一、双目立体匹配原理

首先我们先介绍一些在双目立体匹配中的名称和双目图像立体匹配的流程。

图片来源于[1]

这里涉及几个定义:
基线:左右光心的连线
极点:像平面与基线的交点称为极点
极线:像点与极点之间的连线称为极线
极平面:左右极线与基线构成的平面为空间点对应的极平面

利用双目相机计算稠密的深度需要经过3个步骤:(图像矫正,视差计算)

1.1 图像矫正

步骤1:图像矫正,这个部分可以细分为图像去畸变矫正和图像立体匹配

图像去畸变是利用图像的畸变参数 [d1 d2 d3 p1 p2] 对图像畸变进行校正,检测方法就是,原本在图像边缘的直线由于相机的畸变导致在成像的时候变成了曲线,通过畸变校正以后,在图像中变成的直线,如下图所示:

这个也称作相机的内参数校准(焦距 fx fy 相机中心 cx cy),通常我们调用ROS里面的包就可以实现了。

步骤2:立体畸变校正

立体匹配是指把左右图像旋转到同一个平面(这里说同一个平面不太准确,应该是两个平行的平面),使得左右两幅图片的光轴平行,检测方法是判断左右目图像中的同一个像素点是否在同一水平线上面。

立体矫正是校准相机的外参数实现的,这个也可以通过ROS下的相机校准包实现,只需要输入棋盘格的size即可。校准的参数包括(基线 fx 相机的R矩阵 投影矩阵P矩阵)

在获得相机的内参数和外参数以后我们可以调用opencv的函数对双目的图像进行矫正,如下所示:

cv::initUndistortRectifyMap(K_l,D_l,R_l,P_l.rowRange(0,3).colRange(0,3),cv::Size(cols_l,rows_l),CV_32F,M1l,M2l);cv::initUndistortRectifyMap(K_r,D_r,R_r,P_r.rowRange(0,3).colRange(0,3),cv::Size(cols_r,rows_r),CV_32F,M1r,M2r);
cv::remap(img_left,imLeft,M1l,M2l,cv::INTER_LINEAR);cv::remap(img_right,imRight,M1r,M2r,cv::INTER_LINEAR);
还有一种方式是通过ROS自带的包实现,以下是通过launch文件来启动两个节点分别处理左目和右目图像
<launch><!-- If you already have rectified camera images remove the image_proc nodes --><group ns="stereo/left"><node name="left_rect" pkg="image_proc" type="image_proc"/></group>
<group ns="stereo/right"><node name="right_rect" pkg="image_proc" type="image_proc"/></group>
</launch>
1.2 视差计算

视差定义为 特征点p在左目图像中的像素坐标减去右目图像的像素坐标:disparity=xl-xr ,这里只计算横坐标的差值,因为输入的图像认为是已经立体矫正过的图像了,其左右目同一个像素在一条直线上。深度与视差转换关系:depth = (fx * baseline) / disparity,其中 baseline表示基线的长度。

双目立体匹配实质是指,如果利用双目相机在同一个时刻采集到的左、右目图像,生成一个3D的点云图。

双目计算深度点云的ROS包有两个: stereo_image_proc 和 LIBELAS(: Library for Efficient Large-scale Stereo Matching)两个库,其中LIBELAS提供了一个ROS环境下的包 elas_ros 可以在ROS下面直接使用。

ELAS这个库计算的深度相比于 stereo_image_proc 更加的稠密,推荐使用ELAS这个库。

二、elas_ros 包运行

ELAS [2] 是一种基于概率模型的有效立体匹配算法,该算法具有两个假设:(I)某些立体对应关系可以得到可靠匹配,(II)像素i的视差独立于所有其他像素。因此,ELAS首先使用梯度图像上的SAD匹配来计算稀疏的支持点集,然后使用Delaunay三角剖分来构造用于密集匹配的2D网格。最后,使用最大后验(MAP)模型来估计视差。如果对文章感兴趣的话,可以阅读以下大佬在FPGA上对ELAS算法实现了加速 [3],并开源了代码 [4].
1、首先在 elas_ros 的github地址上下载代码包,然后进行编译

cd ~/catkin_ws/srcgit clone https://github.com/jeffdelmerico/cyphy-elas-ros.gitcd ..catkin_make
2、参考 elas_ros 中launch文件夹下面 elas.launch 文件,新建一个名为 dataset.launch 的文件夹,并把launch文件第四行的 参数 "stereo" 修为 "narrow_stereo_textured" 修改后的 dataset.launch 文件内容如下:
<launch><!-- Launches ELAS node, and rectification nodes for input --><!-- Arguments: input stereo namespace and output elas namespace --><arg name="stereo" default="narrow_stereo_textured"/><arg name="elas_ns" default="elas"/>
<!-- If you already have rectified camera images remove the image_proc nodes --><group ns="$(arg stereo)/left"><node name="left_rect" pkg="image_proc" type="image_proc"/></group>
<group ns="$(arg stereo)/right"><node name="right_rect" pkg="image_proc" type="image_proc"/></group>
<!-- This node actually does the stereo reconstruction --><node name="$(arg elas_ns)" pkg="elas_ros" type="elas_ros" output="screen"><remap from="stereo" to="$(arg stereo)"/><remap from="image" to="image_rect"/>
<param name="approximate_sync" value="true" /><param name="disp_min" type="int" value="0"/><param name="disp_max" type="int" value="255"/><param name="support_threshold" type="double" value="0.95"/><param name="support_texture" type="int" value="10"/><param name="candidate_stepsize" type="int" value="5"/><param name="incon_window_size" type="int" value="5"/><param name="incon_threshold" type="int" value="5"/><param name="incon_min_support" type="int" value="5"/><param name="add_corners" type="bool" value="0"/><param name="grid_size" type="int" value="20"/><param name="beta" type="double" value="0.02"/><param name="gamma" type="double" value="3"/><param name="sigma" type="double" value="1"/><param name="sradius" type="double" value="2"/><param name="match_texture" type="int" value="1"/><param name="lr_threshold" type="int" value="2"/><param name="speckle_sim_threshold" type="double" value="1"/><param name="speckle_size" type="int" value="200"/><param name="ipol_gap_width" type="int" value="300"/><param name="filter_median" type="bool" value="0"/><param name="filter_adaptive_mean" type="bool" value="1"/><param name="postprocess_only_left" type="bool" value="1"/><param name="subsampling" type="bool" value="0"/>
<!-- If your cameras are not synchronised then uncomment the following line --><!-- <param name="approximate_sync" value="true" type="bool"/> --></node></launch>
3、下载我们所用的测试数据集 “rotating_detergent_1_6.bag”,(下载链接:https://pan.baidu.com/s/1uXsNj77OydZoDxaK4PIjIw 提取码:e9ga)
数据集源地址:http://download.ros.org/data/stereo_image_proc/rotating_detergent_1_6.bag

4、新建三个终端,然后启动节点

  • 启动 elas_ros

    roslaunch elas_ros dataset.launch
    
  • 播放 rosbag

    rosbag play  rotating_detergent_1_6.bag
    
  • 启动 rviz

    rosrun rviz rviz
    

在RVIZ中添加对应的话题,即可看到视差图和点云图:

elas双目点云建图

3、KITTI数据集运行

3.1 kitti数据集转换为rosbag

在运行双目深度话的过程中我们首先需要把KITTI数据集转换为rosbag,以便使用。kitti数据集转换为rosbag 可以参考博客: KITTI数据集测试 - 1 从KITTI数据到rosbag

python img2bag_kitti_odo.py /your directory/KITTI/dataset/sequences/00/image_0 kitti_00.bag /your directory/KITTI/dataset/sequences/00/times.txt
除此之外还有两个包也可以实现这个功能,第一个是 ethz-asl 的 kitti_to_rosbag包,但是 kitti_to_rosbag 需要依赖很多的包,这我没有使用这个包,感兴趣的小伙伴可以研究一下。还有一个是 kitti2bag 。

这里需要注意添加上双目之间的基线信息(通常是在P矩阵中加入bf=基线*fx)。其次我所使用的kITTI的数据及是对齐以后的数据集,也就是KITTI官网上Odometry那个网页上的,其中的图像是经过立体矫正以后的图像,因此我们在使用kitti数据集时,不需要包含图像立体矫正的包

3.2 运行KITTI数据集

创建一个名为 kitti.launch 的 launch 文件写入以下内容

<launch>
<!-- Launches ELAS node, and rectification nodes for input -->
<!-- Arguments: input stereo namespace and output elas namespace -->
<arg name="stereo" default="camera"/>
<arg name="elas_ns" default="elas"/><!-- If you already have rectified camera images remove the image_proc nodes -->
<group ns="$(arg stereo)/left">
<node name="left_rect" pkg="image_proc" type="image_proc"/>
</group><group ns="$(arg stereo)/right">
<node name="right_rect" pkg="image_proc" type="image_proc"/>
</group><!-- This node actually does the stereo reconstruction -->
<node name="$(arg elas_ns)" pkg="elas_ros" type="elas_ros" output="screen">
<remap from="stereo" to="$(arg stereo)"/>
<remap from="image" to="image_rect"/><param name="disp_min" type="int" value="0"/>
<param name="disp_max" type="int" value="255"/>
<param name="support_threshold" type="double" value="0.95"/>
<param name="support_texture" type="int" value="10"/>
<param name="candidate_stepsize" type="int" value="5"/>
<param name="incon_window_size" type="int" value="5"/>
<param name="incon_threshold" type="int" value="5"/>
<param name="incon_min_support" type="int" value="5"/>
<param name="add_corners" type="bool" value="0"/>
<param name="grid_size" type="int" value="20"/>
<param name="beta" type="double" value="0.02"/>
<param name="gamma" type="double" value="3"/>
<param name="sigma" type="double" value="1"/>
<param name="sradius" type="double" value="2"/>
<param name="match_texture" type="int" value="1"/>
<param name="lr_threshold" type="int" value="2"/>
<param name="speckle_sim_threshold" type="double" value="1"/>
<param name="speckle_size" type="int" value="200"/>
<param name="ipol_gap_width" type="int" value="300"/>
<param name="filter_median" type="bool" value="0"/>
<param name="filter_adaptive_mean" type="bool" value="1"/>
<param name="postprocess_only_left" type="bool" value="1"/>
<param name="subsampling" type="bool" value="0"/><param name="approximate_sync" value="true" />
<param name="queue_size" type="int" value="5"/>
<!-- If your cameras are not synchronised then uncomment the following line -->
<!-- <param name="approximate_sync" value="true" type="bool"/> -->
</node><!--node pkg="rviz" type="rviz" name="$(anon rviz)" respawn="false" output="screen" args="-d $(find elas_ros)/rviz/KITTI.rviz" / -->
</launch>
注:在上述launch文件中的第7行-14行,这里我偷懒为不去修改topic 我依旧保留了这个图像立体矫正的,实际中输入已经矫正过的图像情况下不需要再使用这段代码了。

接下来播放kitti对应的rosbag包并启动elas_ros既可以:

roslaunch elas_ros kitti.launchrosbag play kitti_01.bag
这样就可以看到使用elas_ros包实时构建的双目点云了,这个包大约可以以10HZ左右的频率运行,因此在用于建图时候最好还是使用关键帧。


(ELAS在KITTI数据集上的运行效果)

elas

参考资料

官方教程:https://github.com/MichaelGrupp/evo
[1] https://blog.csdn.net/luoru/article/details/49048287
[2] Geiger A, Roser M, Urtasun R. Efficient large-scale stereo matching[C]//Asian conference on computer vision. Springer, Berlin, Heidelberg, 2010: 25-38.
[3] Rahnama O, Frost D, Miksik O, et al. Real-time dense stereo matching with ELAS on FPGA-accelerated embedded devices[J]. IEEE Robotics and Automation Letters, 2018, 3(3): 2008-2015.
[4] https://github.com/torrvision/ELAS_SoC
[5] Jellal R A, Lange M, Wassermann B, et al. LS-ELAS: Line segment based efficient large scale stereo matching[C]//2017 IEEE International Conference on Robotics and Automation (ICRA). IEEE, 2017: 146-152.

本文仅做学术分享,如有侵权,请联系删文。

下载1

在「计算机视觉工坊」公众号后台回复:深度学习,即可下载深度学习算法、3D深度学习、深度学习框架、目标检测、GAN等相关内容近30本pdf书籍。

下载2

在「计算机视觉工坊」公众号后台回复:计算机视觉,即可下载计算机视觉相关17本pdf书籍,包含计算机视觉算法、Python视觉实战、Opencv3.0学习等。

下载3

在「计算机视觉工坊」公众号后台回复:SLAM,即可下载独家SLAM相关视频课程,包含视觉SLAM、激光SLAM精品课程。

重磅!计算机视觉工坊-学习交流群已成立

扫码添加小助手微信,可申请加入3D视觉工坊-学术论文写作与投稿 微信交流群,旨在交流顶会、顶刊、SCI、EI等写作与投稿事宜。

同时也可申请加入我们的细分方向交流群,目前主要有ORB-SLAM系列源码学习、3D视觉CV&深度学习SLAM三维重建点云后处理自动驾驶、CV入门、三维测量、VR/AR、3D人脸识别、医疗影像、缺陷检测、行人重识别、目标跟踪、视觉产品落地、视觉竞赛、车牌识别、硬件选型、深度估计、学术交流、求职交流等微信群,请扫描下面微信号加群,备注:”研究方向+学校/公司+昵称“,例如:”3D视觉 + 上海交大 + 静静“。请按照格式备注,否则不予通过。添加成功后会根据研究方向邀请进去相关微信群。原创投稿也请联系。

▲长按加微信群或投稿

▲长按关注公众号

3D视觉从入门到精通知识星球:针对3D视觉领域的视频课程(三维重建系列、三维点云系列、结构光系列、手眼标定、相机标定、orb-slam3等视频课程)、知识点汇总、入门进阶学习路线、最新paper分享、疑问解答五个方面进行深耕,更有各类大厂的算法工程人员进行技术指导。与此同时,星球将联合知名企业发布3D视觉相关算法开发岗位以及项目对接信息,打造成集技术与就业为一体的铁杆粉丝聚集区,近2000星球成员为创造更好的AI世界共同进步,知识星球入口:

学习3D视觉核心技术,扫描查看介绍,3天内无条件退款

圈里有高质量教程资料、可答疑解惑、助你高效解决问题

觉得有用,麻烦给个赞和在看~  

双目相机计算稠密深度点云详解教程相关推荐

  1. 双目相机计算稠密深度点云(一)

    双目相机计算稠密深度点云 1.双目立体匹配原理 1.1 图像矫正 1.2 视差计算 2.elas_ros 包运行 3.KITTI数据集运行 3.1 kitti数据集转换为rosbag 3.2 运行KI ...

  2. 双目相机计算稠密深度点云(二)

    双目相机计算稠密深度点云 1.ZED相机驱动包 2.校准ZED相机 3.运行ELAS 参考资料 接着上一篇的文章实现利用真实的相机计算3D点云,实验中我们使用的是ZED的相机. 1.ZED相机驱动包 ...

  3. 深度学习优化函数详解(5)-- Nesterov accelerated gradient (NAG) 优化算法

    深度学习优化函数详解系列目录 深度学习优化函数详解(0)– 线性回归问题 深度学习优化函数详解(1)– Gradient Descent 梯度下降法 深度学习优化函数详解(2)– SGD 随机梯度下降 ...

  4. 视频教程-深度学习原理详解及Python代码实现-深度学习

    深度学习原理详解及Python代码实现 大学教授,美国归国博士.博士生导师:人工智能公司专家顾问:长期从事人工智能.物联网.大数据研究:已发表学术论文100多篇,授权发明专利10多项 白勇 ¥88.0 ...

  5. 【深度学习】详解Resampling和softmax模型集成

    [深度学习]详解Resampling和softmax模型集成 文章目录 1 图像重采样1.1 次级采样(sub-sampling)1.2 高斯金字塔(Gaussian pyramids)1.3 上采样 ...

  6. 深度学习优化函数详解(5)-- Nesterov accelerated gradient (NAG)

    深度学习优化函数详解系列目录 本系列课程代码,欢迎star: https://github.com/tsycnh/mlbasic 深度学习优化函数详解(0)-- 线性回归问题 深度学习优化函数详解(1 ...

  7. 协方差矩阵数学原理,numpy计算协方差矩阵(np.cov)函数详解与源码剖析

    协方差矩阵详解以及numpy计算协方差矩阵(np.cov) 协方差矩阵详解 均值,标准差与方差 由简单的统计学基础知识,我们有如下公式: X ˉ = ∑ i = 1 n X i n \bar X{\r ...

  8. 涨姿势|小众建模软件Make human,MakeClothes插件使用详解教程(2)

    衣服可以从头开始建模,或者通过改变人体网格或由MakeClothes工具提供的"服装助手"(见下文)来建模.在设计和建模一件衣物时,应该记住两个限制.首先,将服装网格映射到人体网格 ...

  9. PE文件详解(教程1-7)

    PE文件详解(教程1-7) ========================================= PE教程1: PE文件格式一览 PE 的意思就是 Portable Executable ...

  10. 5W字高质量java并发系列详解教程(上)-附PDF下载

    文章目录 第一章 java.util.concurrent简介 主要的组件 Executor ExecutorService ScheduledExecutorService Future Count ...

最新文章

  1. easyUI datagrid 多行多列数据渲染异常缓慢原因以及解决方法
  2. 学习excel的使用技巧一空格替换为0
  3. 删除表的sql命令是什么_【技术干货】30个最适合初学者的SQL查询
  4. php调用应用程序api,使用PHP调用openAPI
  5. javascript事件循环机制EventLoop
  6. android 获取文件夹下的所有文件
  7. Python文件练习
  8. 【英语学习】【Level 07】U08 Old Stories L5 Fulfilling a life goal
  9. (33)VHDL实现异步复位D触发器
  10. 计算指数函数的和的对数
  11. python和c 的区别-C++/C/JAVA/Python之间的区别?
  12. 【机器学习】主成分分析 (PCA)、无监督特征提取
  13. 你认为3D建模是像程序员一样敲代码吗?你太out了
  14. 《Flutter实战》开源电子书
  15. 大学c语言程序设计听不懂,C语言听不懂?那你还不点进来看看?
  16. 最in [IN词] 分享
  17. Formality简单实用之1--RTLvsRTL
  18. 流量计专用无线物联模块介绍
  19. Java设计登录界面——GUI
  20. mmdetection-inference-画出bbox和mask

热门文章

  1. 社会工程学利用的人性_社会工程学利用的人性弱点包括
  2. 如意淘商品推荐技术介绍之二:高级技术
  3. keytool条目_keytool常用命令
  4. EasyUI实现用户登录界面
  5. vue自执行函数,vue3动态组件
  6. C51单片机串口初始化为何是这样:SCON=0X52;TMOD=0X20;TH1=0XF3;TR1=1;
  7. <永洪BI>慢查询记录
  8. viewHolder的作用
  9. caffe lmdb
  10. WIFI远程控制实例分享,喜欢你就来!