3D激光SLAM:ALOAM:异常点剔除机制代码解析

简介: 在LOAM的论文中,作者提到了要剔除两种异常点.- 平行点- 遮挡点但是在ALOAM的代码中并未写相关的功能.如果想把论文中两种异常点的剔除机制加进去,可以参考下面的代码.

前言

在LOAM的论文中,作者提到了要剔除两种异常点.

  • 平行点
  • 遮挡点

但是在ALOAM的代码中并未写相关的功能.

如果想把论文中两种异常点的剔除机制加进去,可以参考下面的代码.

之前把一些其它的异常点剔除的方法总结了

  • 去除掉非常近的点
  • 去除掉非常远的点
  • 去除NaN的点
  • 反射率处理
  • 去除入射角较小的点 (实际就是平行点)

LOAM中的异常点

再回顾下LOAM中定义的两类异常点
平行点:
在这里插入图片描述
平行点指的就是 图中的B点
就是激光的射线几乎和物体的平面平行了

剔除这种点的原因有两个:
1 激光的数据会不准,射线被拉长
2 这种点被视为特征点后会非常不稳定,下一帧可能就没了,无法做配对了
例如图片中的lidar向左移一点,那么B点就消失了,形成对比的就是A点,极短时间内不会消失

遮挡点:
在这里插入图片描述
遮挡点就是 图中的A点
lidar一条sacn上,相邻的两个或几个点的距离偏差很大,被视为遮挡点

剔除这种点的原因是:
这种点被视为特征点后会非常不稳定,下一帧可能就没了,无法做配对了
例如图片中的lidar向右移一点,那么A点就消失了,形成对比的就是B点,极短时间内不会消失

此时最后把A点的左边几个点,都剔除掉

Code

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

        //获取点云中点的个数
        int cloudSize = extractedCloud->points.size();

获取点云中点的个数

        // 循环处理每个点,判断是否是遮挡点还是平行点
        for (int i = 5; i < cloudSize - 6; ++i)
        {
   

循环处理每个点,判断是否是遮挡点还是平行点
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

            /* occluded points  遮挡点的判断 */
            float depth1 = cloudInfo.pointRange[i];//当前点距离
            float depth2 = cloudInfo.pointRange[i+1];//下一个点的距离

首先是判断 遮挡点
depth就是点的距离 = sqrt(xx+yy+z*z)

             // 列索引间的距离
            int columnDiff = std::abs(int(cloudInfo.pointColInd[i+1] - cloudInfo.pointColInd[i]));

计算点的 一条scan上的 索引偏差
因为前面可能要去掉一些点,比如NAN点,如果索引偏差很大,那么就可以不进行遮挡点的判断了
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

            // 相邻两点如果列索引太小,则这个点周围的点不进行特征提取
            if (columnDiff < 10){
   
                     // 如果相邻两点距离大于0.3,选出6个点
                if (depth1 - depth2 > 0.3){
   
                    //如果i点在后面,那么i点也不能要,并且i-1至i-5不要
                    cloudNeighborPicked[i - 5] = 1;
                    cloudNeighborPicked[i - 4] = 1;
                    cloudNeighborPicked[i - 3] = 1;
                    cloudNeighborPicked[i - 2] = 1;
                    cloudNeighborPicked[i - 1] = 1;
                    cloudNeighborPicked[i] = 1;
                }else if (depth2 - depth1 > 0.3){
   
                    //如果i在前面,那么i+1是被遮挡的点,那么i+1至i+6不要
                    cloudNeighborPicked[i + 1] = 1;
                    cloudNeighborPicked[i + 2] = 1;
                    cloudNeighborPicked[i + 3] = 1;
                    cloudNeighborPicked[i + 4] = 1;
                    cloudNeighborPicked[i + 5] = 1;
                    cloudNeighborPicked[i + 6] = 1;
                }
            }

如果点的索引偏差不大的话,那么进行判断是否是遮挡点
偏差大不进行判断的原因就是比如下图
在这里插入图片描述
如图上的情况,因为去了NAN点,那么i和i+1点距离偏差过大,也不是遮挡点,要排除此种情况

如果相邻两点距离大于0.3,选出6个点
这时候要分两种情况
一个是i点的距离大,即i为被遮挡点,那么i点也不能要,并且i-1至i-5不要,因为i-1至i-5也不稳定
在这里插入图片描述
另外一种情况是i在前面,那么i+1是被遮挡的点,那么i+1至i+6不要

在这里插入图片描述
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

            /* parallel beam  平行点的判断  */
             // 平行线的情况,根据左右两点与该点的深度差,确定该点是否会被选择为特征点
            float diff1 = std::abs(float(cloudInfo.pointRange[i-1] - cloudInfo.pointRange[i]));
            float diff2 = std::abs(float(cloudInfo.pointRange[i+1] - cloudInfo.pointRange[i]));

            if (diff1 > 0.02 * cloudInfo.pointRange[i] && diff2 > 0.02 * cloudInfo.pointRange[i])
                cloudNeighborPicked[i] = 1;
        }

这个是平行点的判断

平行线的情况,根据左右两点与该点的深度差,确定该点是否会被选择为特征点

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
整体代码

// 标记遮挡点与平行点,不进行特征提取
    void markOccludedPoints()
    {
   
        //获取点云中点的个数
        int cloudSize = extractedCloud->points.size();

        // 循环处理每个点,判断是否是遮挡点还是平行点
        for (int i = 5; i < cloudSize - 6; ++i)
        {
   
            /* occluded points  遮挡点的判断 */
            float depth1 = cloudInfo.pointRange[i];//当前点距离
            float depth2 = cloudInfo.pointRange[i+1];//下一个点的距离
             // 列索引间的距离
            int columnDiff = std::abs(int(cloudInfo.pointColInd[i+1] - cloudInfo.pointColInd[i]));

            // 相邻两点如果列索引太小,则这个点周围的点不进行特征提取
            if (columnDiff < 10){
   
                     // 如果相邻两点距离大于0.3,选出6个点
                if (depth1 - depth2 > 0.3){
   
                    //如果i点在后面,那么i点也不能要,并且i-1至i-5不要
                    cloudNeighborPicked[i - 5] = 1;
                    cloudNeighborPicked[i - 4] = 1;
                    cloudNeighborPicked[i - 3] = 1;
                    cloudNeighborPicked[i - 2] = 1;
                    cloudNeighborPicked[i - 1] = 1;
                    cloudNeighborPicked[i] = 1;
                }else if (depth2 - depth1 > 0.3){
   
                    //如果i在前面,那么i+1是被遮挡的点,那么i+1至i+6不要
                    cloudNeighborPicked[i + 1] = 1;
                    cloudNeighborPicked[i + 2] = 1;
                    cloudNeighborPicked[i + 3] = 1;
                    cloudNeighborPicked[i + 4] = 1;
                    cloudNeighborPicked[i + 5] = 1;
                    cloudNeighborPicked[i + 6] = 1;
                }
            }

            /* parallel beam  平行点的判断  */
             // 平行线的情况,根据左右两点与该点的深度差,确定该点是否会被选择为特征点
            float diff1 = std::abs(float(cloudInfo.pointRange[i-1] - cloudInfo.pointRange[i]));
            float diff2 = std::abs(float(cloudInfo.pointRange[i+1] - cloudInfo.pointRange[i]));

            if (diff1 > 0.02 * cloudInfo.pointRange[i] && diff2 > 0.02 * cloudInfo.pointRange[i])
                cloudNeighborPicked[i] = 1;
        }
    }

以上是ALOAM中 异常点剔除 功能的 代码 分析

相关文章
|
6月前
|
算法 PyTorch 算法框架/工具
昇腾 msmodelslim w8a8量化代码解析
msmodelslim w8a8量化算法原理和代码解析
450 5
|
8月前
|
搜索推荐 UED Python
实现一个带有昼夜背景切换的动态时钟:从代码到功能解析
本文介绍了一个使用Python和Tkinter库实现的动态时钟程序,具有昼夜背景切换、指针颜色随机变化及整点和半点报时功能。通过设置不同的背景颜色和随机变换指针颜色,增强视觉吸引力;利用多线程技术确保音频播放不影响主程序运行。该程序结合了Tkinter、Pygame、Pytz等库,提供了一个美观且实用的时间显示工具。欢迎点赞、关注、转发、收藏!
375 94
|
6月前
|
传感器 监控 Java
Java代码结构解析:类、方法、主函数(1分钟解剖室)
### Java代码结构简介 掌握Java代码结构如同拥有程序世界的建筑蓝图,类、方法和主函数构成“黄金三角”。类是独立的容器,承载成员变量和方法;方法实现特定功能,参数控制输入环境;主函数是程序入口。常见错误包括类名与文件名不匹配、忘记static修饰符和花括号未闭合。通过实战案例学习电商系统、游戏角色控制和物联网设备监控,理解类的作用、方法类型和主函数任务,避免典型错误,逐步提升编程能力。 **脑图速记法**:类如太空站,方法即舱段;main是发射台,static不能换;文件名对仗,括号要成双;参数是坐标,void不返航。
246 5
|
7月前
|
人工智能 文字识别 自然语言处理
保单AI识别技术及代码示例解析
车险保单包含基础信息、车辆信息、人员信息、保险条款及特别约定等关键内容。AI识别技术通过OCR、文档结构化解析和数据校验,实现对保单信息的精准提取。然而,版式多样性、信息复杂性、图像质量和法律术语解析是主要挑战。Python代码示例展示了如何使用PaddleOCR进行保单信息抽取,并提出了定制化训练、版式分析等优化方向。典型应用场景包括智能录入、快速核保、理赔自动化等。未来将向多模态融合、自适应学习和跨区域兼容性发展。
|
9月前
|
自然语言处理 搜索推荐 数据安全/隐私保护
鸿蒙登录页面好看的样式设计-HarmonyOS应用开发实战与ArkTS代码解析【HarmonyOS 5.0(Next)】
鸿蒙登录页面设计展示了 HarmonyOS 5.0(Next)的未来美学理念,结合科技与艺术,为用户带来视觉盛宴。该页面使用 ArkTS 开发,支持个性化定制和无缝智能设备连接。代码解析涵盖了声明式 UI、状态管理、事件处理及路由导航等关键概念,帮助开发者快速上手 HarmonyOS 应用开发。通过这段代码,开发者可以了解如何构建交互式界面并实现跨设备协同工作,推动智能生态的发展。
531 10
鸿蒙登录页面好看的样式设计-HarmonyOS应用开发实战与ArkTS代码解析【HarmonyOS 5.0(Next)】
|
8月前
|
SQL Java 数据库连接
如何在 Java 代码中使用 JSqlParser 解析复杂的 SQL 语句?
大家好,我是 V 哥。JSqlParser 是一个用于解析 SQL 语句的 Java 库,可将 SQL 解析为 Java 对象树,支持多种 SQL 类型(如 `SELECT`、`INSERT` 等)。它适用于 SQL 分析、修改、生成和验证等场景。通过 Maven 或 Gradle 安装后,可以方便地在 Java 代码中使用。
2640 11
|
9月前
|
PHP 开发者 容器
PHP命名空间深度解析:避免命名冲突与提升代码组织####
本文深入探讨了PHP中命名空间的概念、用途及最佳实践,揭示其在解决全局命名冲突、提高代码可维护性方面的重要性。通过生动实例和详尽分析,本文将帮助开发者有效利用命名空间来优化大型项目结构,确保代码的清晰与高效。 ####
145 20
|
10月前
|
机器学习/深度学习 存储 人工智能
强化学习与深度强化学习:深入解析与代码实现
本书《强化学习与深度强化学习:深入解析与代码实现》系统地介绍了强化学习的基本概念、经典算法及其在深度学习框架下的应用。从强化学习的基础理论出发,逐步深入到Q学习、SARSA等经典算法,再到DQN、Actor-Critic等深度强化学习方法,结合Python代码示例,帮助读者理解并实践这些先进的算法。书中还探讨了强化学习在无人驾驶、游戏AI等领域的应用及面临的挑战,为读者提供了丰富的理论知识和实战经验。
505 5
|
10月前
|
存储 安全 Java
系统安全架构的深度解析与实践:Java代码实现
【11月更文挑战第1天】系统安全架构是保护信息系统免受各种威胁和攻击的关键。作为系统架构师,设计一套完善的系统安全架构不仅需要对各种安全威胁有深入理解,还需要熟练掌握各种安全技术和工具。
454 10
|
10月前
|
前端开发 JavaScript 开发者
揭秘前端高手的秘密武器:深度解析递归组件与动态组件的奥妙,让你代码效率翻倍!
【10月更文挑战第23天】在Web开发中,组件化已成为主流。本文深入探讨了递归组件与动态组件的概念、应用及实现方式。递归组件通过在组件内部调用自身,适用于处理层级结构数据,如菜单和树形控件。动态组件则根据数据变化动态切换组件显示,适用于不同业务逻辑下的组件展示。通过示例,展示了这两种组件的实现方法及其在实际开发中的应用价值。
153 1

推荐镜像

更多
  • DNS