用RGBD投影激光雷达数据:depthimage_to_laserscan

本文详细介绍如何将ASUS Xtion Pro获取的深度图像转换为激光雷达扫描数据,包括外点和无效点剔除、图像有效区域筛选、空间点云计算及投影到xz平面的方法。通过对depthimage_to_laserscan软件包的源代码进行修改,实现了y轴阈值筛选,提高了数据处理的精度。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

转载自知乎上:https://zhuanlan.zhihu.com/p/56559798
参考:
http://wiki.ros.org/depthimage_to_laserscan
https://github.com/ros-perception/depthimage_to_laserscan
http://blog.youkuaiyun.com/Jasmine_shine/article/details/46530143

原创博主的github    下载的话记得给颗五角星(kinetic版本)       https://github.com/hiramzhang/gridmap_laser_rgbd_fusion

1.功能描述  

将asus_xtion_pro获取到的深度图像depthimage进行外点、无效点剔除和图像有效区域筛选后得到待处理的深度图像{u,v};
通过深度图像{u,v}和相机模型参数cam_modle,可以求出深度图像每个像素点对应的空间点云{x,y,z};
将空间点云{x,y,z}投影到xz平面,同时用ythresh_min<y<ythresh_max进行条件约束。

2.代码修改

在https://github.com/ros-perception/depthimage_to_laserscan代码基础上,做如下修改:
(1)修改:在Depth.cfg中添加:
gen.add("ythresh_min",            double_t, 0,                                "Minimum y thresh (in meters).",                              -0.30,   -1.0, 1.0)
gen.add("ythresh_max",            double_t, 0,                                "Maximum y thresh (in meters).",                              0.30,   -1.0, 1.0)

位置:art_ws/src/depthimage_to_laserscan/cfg/Depth.cfg
目的:保存参数,为(3)(4)做准备

(2)修改:在DepthImageToLaserScanROS类的reconfigureCb()函数中添加调用:
dtl_.set_y_thresh(config.ythresh_min, config.ythresh_max);
位置:art_ws/src/depthimage_to_laserscan/src/DepthImageToLaserScanROS.cpp

(3)修改:在DepthImageToLaserScan类中添加成员函数和成员变量:   
void set_y_thresh(const float ythresh_min, const float ythresh_max);
float ythresh_min_;
float ythresh_max_;
同时对set_y_thresh()进行具体实现。

实现添加内容:
void DepthImageToLaserScan::set_y_thresh(const float ythresh_min, const float ythresh_max){
  ythresh_min_ = ythresh_min;
  ythresh_max_ = ythresh_max;
}

位置:art_ws/src/depthimage_to_laserscan/src/DepthImageToLaserScan.cpp
目的:为(4)调用做准备
(4)修改:在DepthImageToLaserScan类的convert()方法实现中添加 :
void set_y_thresh(const float ythresh_min, const float ythresh_max);

double y = (v - center_y) * depth * constant_y;
if(y<ythresh_min_||y>ythresh_max_)
{
      r = std::numeric_limits<float>::quiet_NaN();
      continue;
}


    float ythresh_min_;
    float ythresh_max_;

目的:设置y的筛选条件
位置:
/home/w/art_ws/src/depthimage_to_laserscan/include/depthimage_to_laserscan/DepthImageToLaserScan.h


由于摄像头有区别,去掉dtl.launch 中的<include file="$(find astra_launch)/launch/astra.launch"/>
catkin_make 编译一遍

3.启动文件

roslaunch astra_launch astra.launch
//rosrun depthimage_to_laserscan depthimage_to_laserscan image:=/camera/depth/image_raw  这条命令不行
roslaunch  depthimage_to_laserscan  dtl.launch
rosrun tf static_transform_publisher 0 0 0 0 0 0 1 map camera_depth_frame 10
rosrun tf static_transform_publisher 0 0 0 0 0 0 1 map xtion_scan_frame 10
rosrun rviz rviz

rosparam get /depthimage_to_laserscan/ythresh_max

注:dtl.launch 中改参数,改后编译

 

4   主要内容

      主要改的内容:(4)部

for(int v = offset; v < offset+scan_height_; v++, depth_row += row_step){
        for (int u = 0; u < (int)depth_msg->width; u++) // Loop over each pixel in row

//像素点遍历
        {    
          T depth = depth_row[u];
          double r = depth; // Assign to pass through NaNs and Infs
          double th = -atan2((double)(u - center_x) * constant_x, unit_scaling);
          int index = (th - scan_msg->angle_min) / scan_msg->angle_increment;
          if (depthimage_to_laserscan::DepthTraits<T>::valid(depth)){ /
            double x = (u - center_x) * depth * constant_x;
            double z = depthimage_to_laserscan::DepthTraits<T>::toMeters(depth);
            double y = (v - center_y) * depth * constant_y;//定义y数值
                  if(y<-0.3||y>0.3)//如果y不符合条件就把他忽略
                 {
                     r = std::numeric_limits<float>::quiet_NaN();
//精髓在这一步,没看懂
                     continue;
                 }

            // Calculate actual distance
            r = sqrt(pow(x, 2.0) + pow(z, 2.0));
          }
      
      // Determine if this point should be used.
      if(use_point(r, scan_msg->ranges[index], scan_msg->range_min, scan_msg->range_max)){
        scan_msg->ranges[index] = r;
      }
    }
      }
    }

5  各个文件之间的调用关系

1

在RTAB-Map中,视觉(RGB-D相机)和激光雷达(LiDAR)的数据输入并非直接未经处理地传递给算法,而是通过一系列预处理、同步和融合步骤,确保数据的一致性和有效性。以下是详细的流程解析: --- ### **1. 数据输入与预处理** #### **(1) 视觉数据(RGB-D相机)** - **输入形式**: - **RGB图像**:提供纹理信息(如`/camera/rgb/image_raw`)。 - **深度图像**:提供像素级3D信息(如`/camera/depth/image_raw`)。 - **相机内参**:焦距(`fx, fy`)、主点(`cx, cy`)和畸变参数(`distortion_coefficients`)。 - **预处理步骤**: - **特征提取**:使用ORB/SIFT等算法提取关键点和描述子,用于帧间匹配和回环检测。 - **点云生成**:将深度图像转换为3D点云(通过`depth_image_proc/convert_metric`节点)。 - **去噪**:移除深度图像中的无效值(如`NaN`)或应用双边滤波平滑数据。 #### **(2) 激光雷达数据(LiDAR)** - **输入形式**: - **2D激光扫描**(如`/scan`,类型为`sensor_msgs/LaserScan`)。 - **3D点云**(如`/velodyne_points`,类型为`sensor_msgs/PointCloud2`)。 - **预处理步骤**: - **降采样**:使用体素网格滤波(VoxelGrid)减少点云密度。 - **地面分割**:移除地面点(如基于RANSAC的平面拟合)。 - **去噪**:统计离群点移除(StatisticalOutlierRemoval)。 --- ### **2. 数据同步与传感器融合** #### **(1) 时间同步** - **硬件同步**:部分设备(如Kinect V2+LiDAR)支持硬件触发同步。 - **软件同步**:在ROS中通过`message_filters`实现近似时间同步: ```python sync = ApproximateTimeSynchronizer( [rgb_sub, depth_sub, scan_sub], queue_size=10, slop=0.1 # 允许的时间偏差(秒) ) sync.registerCallback(callback) ``` #### **(2) 坐标系对齐** - **外参标定**:通过`tf2`发布相机与LiDAR的静态变换(如`/camera_link`到`/lidar_link`的`geometry_msgs/TransformStamped`)。 - **点云对齐**:将LiDAR点云转换到相机坐标系(通过`pcl_ros.transformPointCloud`)。 --- ### **3. 里程计生成与关键帧选择** #### **(1) 视觉里程计(RGB-D Odometry)** - **特征匹配**:对连续RGB帧提取ORB特征,通过RANSAC计算本质矩阵(Essential Matrix)。 - **ICP优化**:对齐连续深度点云,优化位姿(`rtabmap::ICP()`)。 #### **(2) 激光里程计(LiDAR Odometry)** - **扫描匹配**:使用ICP或NDT算法匹配相邻LiDAR扫描(`pcl::GeneralizedIterativeClosestPoint`)。 - **运动估计**:输出为`nav_msgs/Odometry`消息(如`/odom_lidar`)。 #### **(3) 融合策略** - **松耦合**:通过EKF融合视觉和激光里程计(如`robot_localization`包)。 - **紧耦合**:在RTAB-Map的因子图中联合优化视觉和LiDAR约束(需设置`Reg/Strategy=1`启用RGB-D+LiDAR模式)。 --- ### **4. RTAB-Map的数据输入接口** #### **(1) ROS话题订阅** - **单传感器模式**: ```xml <param name="subscribe_depth" type="bool" value="true"/> <param name="subscribe_scan" type="bool" value="false"/> ``` - **多传感器模式**: ```xml <param name="subscribe_rgbd" type="bool" value="true"/> <param name="subscribe_scan_cloud" type="bool" value="true"/> ``` #### **(2) 关键帧策略** - **基于运动量**:当位移超过`RGBD/LinearUpdate=0.1m`或旋转超过`RGBD/AngularUpdate=0.2rad`时创建关键帧。 - **基于信息量**:使用熵值判断场景变化(`Mem/STMSize=30`限制短期记忆中的关键帧数)。 --- ### **5. 实际配置示例** #### **(1) 启动文件片段(ROS)** ```xml <node pkg="rtabmap_ros" type="rtabmap" name="rtabmap"> <param name="frame_id" value="base_link"/> <param name="subscribe_rgbd" value="true"/> <param name="subscribe_scan_cloud" value="true"/> <param name="Reg/Strategy" value="1"/> <!-- 0=Visual, 1=ICP, 2=Visual+ICP --> <param name="Icp/CorrespondenceRatio" value="0.3"/> <remap from="rgbd_image" to="/camera/rgbd_image"/> <remap from="scan_cloud" to="/velodyne_points"/> </node> ``` #### **(2) 外参配置(TF树)** ```bash rosrun tf static_transform_publisher 0.1 0 0 0 0 0 /camera_link /lidar_link 100 ``` --- ### **6. 数据是否“直接输入”?** - **否**:原始数据需经过以下处理链: ``` RGB/Depth → 特征提取 → 点云生成 → 时间同步 → 坐标系对齐 → 里程计计算 → 关键帧选择 → 图优化 LiDAR → 降采样 → 去噪 → 配准 → 时间同步 → 坐标系对齐 → 里程计计算 → 关键帧选择 → 图优化 ``` - **是**:若使用已同步且校准的传感器(如Intel RealSense L515+LiDAR模块),可直接通过`rtabmap_ros/rtabmap`订阅`/rgbd_image`和`/scan_cloud`话题。 --- ### **7. 性能优化技巧** 1. **降采样**:将深度图像和LiDAR点云分辨率降低至QVGA(320x240)或`VoxelSize=0.05m`。 2. **并行计算**:启用`RGBD/OptimizeFromGraphEnd=true`在后台优化位姿图。 3. **硬件加速**:使用OpenCV的CUDA模块加速特征提取(如`ORB::setUseCuda(true)`)。 --- ### **总结** RTAB-Map通过严格的预处理流程(时间同步、坐标变换、特征提取/配准)将视觉和LiDAR数据转化为统一的位姿约束和地图点云。多传感器数据并非“直接输入”,而是经过融合后参与图优化,最终输出高精度三维地图与轨迹。实际应用中需重点关注**传感器标定质量**和**关键帧策略**以平衡精度与实时性。 将以上进行总结,只使用汉语文字
05-31
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值