视觉SLAM ch12 建图(RGB-D)

这篇具有很好参考价值的文章主要介绍了视觉SLAM ch12 建图(RGB-D)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一、RGB-D稠密建图

RGB-D相机通结构光和飞行时间获取深度。

稠密重建方法:根据估计的相机位姿,将RGB-D数据转化为点云,然后进行拼接,最终得到由离散的点组成的点云地图

在此基础上,如果希望估计物体的表面,可以用三角网格(Mesh)和面片(Surfel)进行建图;如果希望知道地图的障碍物信息,可以通过体素(Voxel)建立占据网格地图(Occupancy Map)。

二、点云地图

对点云地图还需要进行滤波处理:外点去除滤波器和体素网格的降采样滤波器(Voxel grid filter)

1.PCL点云库头文件,参考【1】

#include <boost/make_shared.hpp>                            //boost指针相关头文件
#include <pcl/point_types.h>                                //点类型定义头文件
#include <pcl/point_cloud.h>                                //点云类定义头文件
#include <pcl/features/normal_3d.h>                         //法线特征头文件
#include <pcl/features/normal_3d_omp.h>                     //法线特征加速头文件    
#include <pcl/features/fpfh.h>                              //fpfh类特征头文件
#include <pcl/features/fpfh_omp.h>                          //fpfh加速类头文件
#include <pcl/features/boundary.h>                          //边界提取头文件 
#include <pcl/search/kdtree.h>                              //kdtree搜索对象类头文件
#include <pcl/point_representation.h>                       //点表示相关的头文件
#include <pcl/io/pcd_io.h>                                  //PCD文件打开存储类头文件
#include <pcl/filters/passthrough.h>                        //直通滤波器头文件
#include <pcl/filters/voxel_grid.h>                         //用于体素网格化的滤波类头文件
#include <pcl/filters/filter.h>                             //滤波相关头文件 
#include <pcl/filters/project_inliers.h>                    //点云投影头文件
#include <pcl/filters/extract_indices.h>                    //索引提取头文件
#include <pcl/filters/statistical_outlier_removal.h>        //统计离群点类头文件 
#include <pcl/segmentation/sac_segmentation.h>              //RanSaC分割
#include <pcl/segmentation/region_growing.h>                //区域生长
#include <pcl/segmentation/region_growing_rgb.h>            //基于颜色的区域生长
#include <pcl/segmentation/supervoxel_clustering.h>         //超体聚类
#include <pcl/segmentation/lccp_segmentation.h>             //基于凹凸性分割
#include <pcl/surface/mls.h>                                //点云平滑类头文件
#include <pcl/registration/icp.h>                           //ICP类相关头文件
#include <pcl/registration/icp_nl.h>                        //非线性ICP 相关头文件
#include <pcl/registration/transforms.h>                    //变换矩阵类头文件
#include <pcl/registration/ia_ransac.h>                     //sac-ia类头文件 
#include <pcl/registration/correspondence_estimation.h>     //直方图配准
#include <pcl/registration/correspondence_rejection_features.h>//特征的错误对应关系去除
#include <pcl/registration/correspondence_rejection_sample_consensus.h>//随机采样一致性去除 
#include <pcl/visualization/pcl_visualizer.h>               //可视化类头文件
 
typedef pcl::PointXYZ  Pxyz;
typedef pcl::PointXYZRGB Prgb;
typedef pcl::PointCloud<Pxyz> PXYZ;
typedef pcl::PointCloud<Prgb> PRGB;
 
typedef pcl::Normal Pnl;
typedef pcl::PointNormal Pnt;
typedef pcl::PointCloud<Pnt> PNT;

2.点云的创建、访问与转换以及读写

//创建点云指针对象
//PointXYZRGB是单个点包含xyz以及rgb信息
pcl::PointCloud< pcl::PointXYZRGB>::Ptr 
                        pointCloud (new  pcl::PointCloud< pcl::PointXYZRGB>);


//访问点云
pcl::PointXYZRGB  p;
p.x = xx;
p.y = xx;
p.z = xx;
p.b = xx;
p.g = xx;
p.r = xx;

pointCloud->points.push_back(p);
//points是个vector变量
//转换
pcl::PointCloud<pcl::PointXYZRGB> Cloud    //点云对象

pcl::PointCloud< pcl::PointXYZRGB>::Ptr 
                   pointCloud (new  pcl::PointCloud< pcl::PointXYZRGB>);   //点云指针对象


cloud = * pointCloud ;
pointCloud = cloud.makeShared();
//读
pcl::PointCloud< pcl::PointXYZRGB>::Ptr 
                   pointCloud(new  pcl::PointCloud< pcl::PointXYZRGB>);
if (pcl::io::loadPCDFile<pcl::PointXYZRGB>("map.pcd", *pointCloud) == -1)
    {
        cout<<("读取pcd失败");
        return 1;
    }
    cout << "读取到 "<< pointCloud_read->width * pointCloud_read->height << " 个点"<<endl;


//写
pcl::io::savePCDFileBinary("map.pcd", *pointCloud);   //二进制形式写入文件
pcl::io::savePCDFileASCII("map.pcd", *pointCloud);    //以ascii格式写入文件

3.统计滤波器

StatisticalOutlierRemoval 滤波器主要用于剔除点云中的离群点。滤波思想为:对每一个点的利用 KD-tree 进行一个统计分析,利用KD-tree得到的结果,计算该点到所有临近点的平均距离。假设每个点与临近点之间的距离是一个高斯分布,那么平均距离就是均值,并且可以根据均值和每一个距离求得标准差,那么平均距离在标准范围之外的点,可以被定义为离群点并从数据中去除。【2】

// 新建临时点云
pcl::PointCloud< pcl::PointXYZRGB>::Ptr 
                   tmp(new  pcl::PointCloud< pcl::PointXYZRGB>);   //点云指针对象
// 创建滤波器对象
pcl::StatisticalOutlierRemoval<pcl::PointXYZ> statistical_filter;

statistical_filter.setMeanK(50);//设置在进行统计时考虑查询点邻居点数
statistical_filter.setStddevMulThresh(1.0);//设置判断是否为离群点的阈值
statistical_filter.setInputCloud(current);//设置待滤波的点云(导入当前点云)

//将滤波结果保存在临时点云中,并将临时点云存入总点云
statistical_filter.filter(*tmp);
(*pointCloud) += *tmp;

4.体素滤波器

利用体素网格滤波器进行降采样。由于多个视角存在视野重叠,在重叠区域会存在大量的位置十分相近的点。会占据内存空间。体素滤波器保证了在某个一定大小的立方体(体素)内仅有一个点,相当于对三维空间进行了降采样,从而节省了存储空间。
在体素滤波器中,把分辨率设成0.03,表示每个0.03x0.03x0.03的立方体中只有一个点,这个分辨率较高,所以实际中感觉不到地图的差异,单程序输出中点数明显减少。

// 体素滤波器
pcl::VoxelGrid<PointT> voxel_filter;

//体素网格分辨率为0.03 * 0.03 * 0.03,一个立方体晶格存放一个点
double resolution = 0.03;
voxel_filter.setLeafSize(resolution, resolution, resolution);       // resolution

//临时点云
pcl::PointCloud< pcl::PointXYZRGB>::Ptr 
                   tmp(new  pcl::PointCloud< pcl::PointXYZRGB>);

// 输入总点云,降采样结果保存到tmp
voxel_filter.setInputCloud(pointCloud);
voxel_filter.filter(*tmp);
// 交换总点云与临时点云
tmp->swap(*pointCloud);

5.点云可视化

#include <pcl/visualization/cloud_viewer.h>

pcl::visualization::CloudViewer viewer ("点云");
viewer.showCloud (pointCloud);
while (!viewer.wasStopped ())
{
    
}

Cloudviewer只是一个简单的可视化工具,其功能只有有限的showCloud,以及注册键盘、鼠标的回调函数。更加复杂的工具是PCLVisualizer,参考【3】

#include <pcl/visualization/cloud_viewer.h>
#include <thread>
#include <chrono>

//初始化
pcl::visualization::PCLVisualizer::Ptr viewer (new pcl::visualization::PCLVisualizer ("3D Viewer"));

//设置背景颜色
viewer->setBackgroundColor (0, 0, 0);
//添加坐标系(即红绿蓝三色轴,放置在原点)
viewer->addCoordinateSystem (3.0);//3.0指轴的长度
//viewer->addCoordinateSystem (3.0,1,2,3);一个重载函数,3.0指轴的长度,放置在(1,2,3)位置
//初始化默认相机参数
viewer->initCameraParameters ();

//创建一个点云的句柄
pcl::visualization::PointCloudColorHandlerRGBField<pcl::PointXYZRGB> rgb(pointCloud);
//将点云加入到viewer,并定义一个唯一的字符串作为ID号,利用此字符串在其他成员方法中也能表示引用该点云
viewer->addPointCloud<pcl::PointXYZRGB> (pointCloud, rgb, "label_pc");

//用于改变显示点云的尺寸,可以利用该方法控制点云在视窗中的显示方式
viewer->setPointCloudRenderingProperties (pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 1, "label_pc");
while (!viewer->wasStopped ())
{
   viewer->spinOnce (100);   //更新显示
   boost::this_thread::sleep (boost::posix_time::microseconds (100));
}

点云地图提高了基本的可视化地图,但不能满足对于稠密地图的需求。

1)定位:取决与前端视觉里程计的处理方式。如果是基于特征点的视觉里程计,由于点云中没有存储特征点的信息,则无法用于基于特征点的定位方式。如果前端是点云的ICP,那么可以将局部点云对全局点云进行ICP以估计位姿。
2)导航与避障:点云无法直接用于避障,纯粹的点云无法表示“是否有障碍物",不过,可以在点云的基础上加工,得到更适合导航避障的地图形式。
3)可视化和交互:点云只有离散的点,没有物体表面的信息,所以不符合可视化要求。


点云是基础的,初级的,接近传感器读取的原始数据。更高级的功能,如导航避障,可以从点云出发,构建占据网格地图,以供导航算法查询某点是否能通过。SfM(三维重建)中常使用的柏松重建,就能通过基本的点云重建物体网格地图,得到物体的表面信息。还有Surfel也是一种表达物体表面的方式,以面元作为地图的基本单位,能建立可视化地图。
 

三、点云重建网格

思路:先计算点云的法线,在从法线计算网格。

//
// Created by gaoxiang on 19-4-25.
//

#include <pcl/point_cloud.h>                           //点云类定义头文件
#include <pcl/point_types.h>                          //点类型定义头文件
#include <pcl/io/pcd_io.h>                                 //PCD文件打开存储类头文件
#include <pcl/visualization/pcl_visualizer.h>   //可视化类头文件
#include <pcl/kdtree/kdtree_flann.h>             //用于对点云进行Kd树搜索
#include <pcl/surface/surfel_smoothing.h>  //对点云进行平滑处理
#include <pcl/surface/mls.h>                              //点云平滑类头文件
#include <pcl/surface/gp3.h>                         //对点云进行三角化处理
#include <pcl/surface/impl/mls.hpp>

// typedefs
typedef pcl::PointXYZRGB PointT;
typedef pcl::PointCloud<PointT> PointCloud;
typedef pcl::PointCloud<PointT>::Ptr PointCloudPtr;

typedef pcl::PointXYZRGBNormal SurfelT;
typedef pcl::PointCloud<SurfelT> SurfelCloud;
typedef pcl::PointCloud<SurfelT>::Ptr SurfelCloudPtr;


//把基本点云转化成光滑的带有法线信息的点云
SurfelCloudPtr reconstructSurface(
        const PointCloudPtr &input, float radius, int polynomial_order) {

     // 定义对象 (第二种定义类型是为了存储法线       
    pcl::MovingLeastSquares<PointT, SurfelT> mls;
    //由于MLS算法是基于KDTree实现的,所以需要创建KDTree对象
    pcl::search::KdTree<PointT>::Ptr tree(new pcl::search::KdTree<PointT>);
    mls.setSearchMethod(tree);
    //搜索半径
    mls.setSearchRadius(radius);
    //计算法线
    mls.setComputeNormals(true);
     // 设置近邻高斯权重系数,一般为搜索半径平方
    mls.setSqrGaussParam(radius * radius);
   
    //设置是否使用多项式拟合提高精度
    mls.setPolynomialFit(polynomial_order > 1);
     // 设置阶数
    mls.setPolynomialOrder(polynomial_order);
    // 输入点云
    mls.setInputCloud(input);

    SurfelCloudPtr output(new SurfelCloud);
     // 处理结果保存到输出点云并放返回
    mls.process(*output);
    return (output);
}

// 为点云表面添加三角网格面元
pcl::PolygonMeshPtr triangulateMesh(const SurfelCloudPtr &surfels) {
    // 创建搜索树
    pcl::search::KdTree<SurfelT>::Ptr tree(new pcl::search::KdTree<SurfelT>);
    tree->setInputCloud(surfels);

    // Initialize objects
    pcl::GreedyProjectionTriangulation<SurfelT> gp3;
    pcl::PolygonMeshPtr triangles(new pcl::PolygonMesh);

    // Set the maximum distance between connected points (maximum edge length)
    gp3.setSearchRadius(0.05);

    // Set typical values for the parameters
    gp3.setMu(2.5);
    gp3.setMaximumNearestNeighbors(100);
    gp3.setMaximumSurfaceAngle(M_PI / 4); // 45 degrees
    gp3.setMinimumAngle(M_PI / 18); // 10 degrees
    gp3.setMaximumAngle(2 * M_PI / 3); // 120 degrees
    gp3.setNormalConsistency(true);

    // Get result
    gp3.setInputCloud(surfels);
    gp3.setSearchMethod(tree);
    gp3.reconstruct(*triangles);

    return triangles;
}

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

    // Load the points
    PointCloudPtr cloud(new PointCloud);
    if (argc == 0 || pcl::io::loadPCDFile(argv[1], *cloud)) {
        cout << "failed to load point cloud!";
        return 1;
    }
    cout << "point cloud loaded, points: " << cloud->points.size() << endl;

    // Compute surface elements
    cout << "computing normals ... " << endl;
    double mls_radius = 0.05, polynomial_order = 2;
    auto surfels = reconstructSurface(cloud, mls_radius, polynomial_order);

    // Compute a greedy surface triangulation
    cout << "computing mesh ... " << endl;
    pcl::PolygonMeshPtr mesh = triangulateMesh(surfels);

    cout << "display mesh ... " << endl;
    pcl::visualization::PCLVisualizer vis;
    vis.addPolylineFromPolygonMesh(*mesh, "mesh frame");
    vis.addPolygonMesh(*mesh, "mesh");
    vis.resetCamera();
    vis.spin();
}

四、八叉树地图

点云地图与八叉树地图对比:点云地图规模大,而且无法处理运动物体;八叉树地图占用空间很小,而且可以用于导航。

八叉树octomap参考【4】

视觉SLAM ch12 建图(RGB-D)

 五、如何在八叉树地图中进行导航或路径规划吗?

在起点与终点之间,选择概率值最小的路径。若概率值最小的路径仍超过某一阈值,则说明无法到达终点。若有多条概率值小的路径,可以根据高斯分布选择路最“宽”的路径。文章来源地址https://www.toymoban.com/news/detail-416969.html

到了这里,关于视觉SLAM ch12 建图(RGB-D)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【文献分享】动态环境下竟然能实现实时语义RGB-D SLAM??

    论文题目: Towards Real-time Semantic RGB-D SLAM in Dynamic Environments 中文题目: 动态环境下实时语义RGB-D SLAM研究 作者:Tete Ji, Chen Wang, and Lihua Xie 作者机构:新加坡南洋理工大学电气与电子工程学院 卡内基梅隆大学机器人研究所 论文链接:https://arxiv.org/pdf/2104.01316.pdf 大多数现有的视

    2024年02月15日
    浏览(39)
  • 高翔ORB-SLAM2稠密建图编译(添加实时彩色点云地图+保存点云地图)

    本文写于2022年5月18日。 Ubuntu18.04 + ROS melodic ORBSLAM2_with_pointcloud_map 是基于 ORB_SLAM2 改动的, ORB_SLAM2 编译前一些库的安装以及编译时的报错参考此篇博客 ORBSLAM2_with_pointcloud_map源码地址 将源码下载到 ~/catkin_ws/src 目录下面 如果没有安装 Ros Melodic ,参考Ubuntu18.04安装Ros Melodic 以及

    2024年01月23日
    浏览(75)
  • 论文复现《SplaTAM: Splat, Track & Map 3D Gaussians for Dense RGB-D SLAM》

    SplaTAM算法是 首个 开源的基于 RGB-D数据 ,生成高质量密集3D重建的SLAM技术。 通过结合 3DGS技术 和 SLAM框架 ,在保持高效性的同时,提供 精确的相机定位和场景重建 。 代码仓库: spla-tam/SplaTAM: SplaTAM: Splat, Track Map 3D Gaussians for Dense RGB-D SLAM (CVPR 2024) (github.com) https://github.com/s

    2024年04月27日
    浏览(40)
  • 工程(十)——github代码ubuntu20.04在ROS环境运行单目和RGBD相机ORB-SLAM3稠密

    博主创建了一个科研互助群Q:772356582,欢迎大家加入讨论交流一起学习。 加稠密建图:git@github.com:huashu996/ORB_SLAM3_Dense_YOLO.git 纯净版:git@github.com:huashu996/ORB_SLAM3.git orb-slam3的整个环境配置还是比较麻烦的,先将一些坑写在前面,供大家参考和避开这些坑。 orb-slam3的配置要求

    2024年01月25日
    浏览(53)
  • 视觉SLAM十四讲——ch10实践(后端2)

    视觉SLAM(Simultaneous Localization and Mapping)后端是一种用于处理视觉SLAM问题的算法。视觉SLAM是指机器在未知环境中同时实现自身的定位和地图构建的技术。 视觉SLAM后端的任务是在视觉SLAM中负责维护一个优化后的地图和机器人的轨迹。常见的视觉SLAM后端算法包括基于图优化的

    2024年02月09日
    浏览(49)
  • 视觉SLAM十四讲——ch9实践(后端1)

    Ceres BA使用的是BAL数据集。在本例中,使用problem-16-22106-pre.txt文件。 BAL的数据集自身存在的特殊 BAL的相机内参模型由焦距f和畸变参数k1,k2给出。 因为BAL数据在投影时假设投影平面在相机光心之后,所以按照我们之前用的模型计算,需要在投影之后乘以系数-1。 安装meshlab,

    2024年02月09日
    浏览(49)
  • 踩坑 Sophus 模板库安装及编译(视觉SLAM 十四讲第二版 ch4 )

    在《视觉slam十四讲》第二版中,第4、7、8、9、10讲都需要Sophus库,因此我们需要安装Sophus库,并且需要的是Sophus模板库,因此很多人因为安装了非模板版本导致报错,下面提供Sophus模板版本安装方式,以及对应不报错版本。 只要是 3.3以上的版本即可 官网进入,然后下载T

    2024年01月22日
    浏览(64)
  • 手撕 视觉slam14讲 ch7 / pose_estimation_3d2d.cpp (1)

     1. 读图,两张rgb(cv::imread)  2. 找到两张rgb图中的特征点匹配对        2.1定义所需要的参数:keypoints1, keypoints2,matches        2.2 提取每张图像的检测 Oriented FAST 角点位置并匹配筛选(调用功能函数1)  3. 建立3d点(像素坐标到相机坐标)         3.1读出深度图(c

    2024年02月10日
    浏览(43)
  • 基于全景相机的视觉SLAM

    相机坐标系中空间点投影到二维图像的过程可以简化为将空间点投影到单位球面上,然后将此球面展开成全景图像。 式中:ri一空间点在相机坐标系中与原点的距离;t0一投影函数。可以看出,全景相机的投影过程是非线性的。 能看出全景图像的畸变系数为cosp,图2-4为全景机

    2024年02月10日
    浏览(46)
  • 视觉SLAM中的相机分类及用途

    目录 1. 单目相机 2. 双目相机 3. 深度相机(RGB-D相机) 4. 全景相机 5. 结构光相机 6. 激光雷达相机(Lidar) 应用场景与选择 7.热感相机 热感相机用于SLAM的挑战 视觉SLAM(Simultaneous Localization and Mapping)算法主要用于机器人和自动导航系统中,用于同时进行定位和建立环境地图。

    2024年02月04日
    浏览(44)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包