【代码阅读】SSC:Semantic Scan Context for Large-Scale Place Recognition

一、主函数

官方开源的代码提供了四个主函数,其中eval_pair.cpp和eval_top1.cpp是一组,分别用于计算两帧的相似度分数以及一帧点云在所有的51帧点云中相似度最高的25帧的相似度分数。eval_seq.cpp是在eval_top1.cpp的基础上,给了一堆序列,遍历序列中的每一帧点云并输出与之相似度足够高的25帧点云的相似度分数。eval_angle.cpp这个文件比较迷,readme里面也没有提,代码里面提到的那几个config文件开源代码也没有给出,从代码内容来看,更像是在eval_pair.cpp的基础上,计算了好多帧对的位姿变换。

主函数的具体操作基本都是类似的,先初始化config对象读取配置文件,同时利用这个配置文件初始化ssc对象,之后根据不同的需求,调用重载了许多次的ssc对象里面的getScore函数,进行相似度分数的计算。因此整个ssc算法其实都在ssc对象中实现。

二、ssc.cpp

算法的实现基本都在这个文件中,文件的结构本身不复杂,除了构造函数和析构函数,还有三个形式的读取点云函数、投影函数、计算ssc描述子的函数、两个形式的全局ICP函数、计算相似度的函数以及六个形式的计算相似度分数的函数。
在这里插入图片描述

getScore()

根据主函数的执行顺序,这里我们也从getScore函数开始。从重载函数的形式看,六个getScore函数传入的参数本质上都是一样的:两帧点云、两帧点云的语义以及变换矩阵,不同之处在于传入的形式,一二个函数传入的是XYZL形式的点云,这是pcl库中一个点云形式,L表示的是label,相当于直接把语义信息存储了进去,三四个函数这是传入了点云文件的路径和语义推理结果的路径,在函数内部分别读取两个文件,最后两个函数则是直接读取标记过语义的点云文件。从执行的路径来看,最后面四个函数都是在调整文件格式之后,转而调用了前面两个函数,所以这里我们主要看第一个形式的getScore函数。

project()

进入函数后首先对位姿变化的量进行初始化,同时利用project函数对标记过语义的点云进行投影。与其叫做投影,其实更多地是在做格式的转换。

函数首先对场景划分了扇区,扇区只对轴向做了大小的限制,而没有对径向进行约束。从代码来看,一帧点云共计划分了360个扇区,也就是每个扇区在轴向上是一度,之后初始化一个360*1的向量,每个元素为一个32位的浮点数,初始值为0。
在这里插入图片描述
之后对于函数传入下采样后的点云filtered_pointcloud,遍历点云中的每个点,对类别标记为13、14、16、18、19的这五类点进行点云格式的转换。查看配置文件可以发现,选择的这五类对应的是building、fence、trunk、pole以及traffic-sign,而没有选择出现次数更多的ground等类别。对于水平距离足够远的点,算法会根据夹角信息计算其所在的扇区,之后将这个点到中心的距离、点在水平方向上的坐标以及该点的语义坐标进行存储。
在这里插入图片描述
这里就存在一个问题,代码183行到186行对点信息的存储,是直接覆盖的,而不是添加的,这就会导致当一个扇区内同时存在13、14、16、18、19这五类点的时候扇区的描述子实际上是多次覆盖过的。查看作者的原论文,里面写的是每个扇区内部只保留距离中心最近的点,个人推测这里的这种写法是作者默认了filtered_pointcloud是从远到近的排列,因为在之前看的salsanext代码中有对点云重排列的部分,这里作者并没有调用下采样相关的内容,可能是在输入的bin文件点云中已经调整过顺序。

globalICP()

回到getScore函数,在计算出ssc_dis之后,函数进入到globalICP进行一个位姿的计算。这里对应的是原论文中的全局语义ICP的部分。由于描述子的设计具有旋转不变性,所以代码首先利用描述子径向上的距离,计算了两帧点云描述子轴向上应该旋转的量。

具体来说其实就是一个遍历的过程,对于下面的这个二层循环,第一层的i表示的是轴向上应该移动的距离,单位是扇区数量,第二层则是遍历每个扇区,之后计算旋转后两个描述子第一维也就是到中心的距离的差,差值统计在dis_count这个量里面,取最小值对应的i作为两个描述子或者两帧点云在轴向上应该旋转的值。
在这里插入图片描述
得到角度之后,就可以将描述子进行旋转,让两个描述子对齐,描述子一共四个维度,其中第一个和最后一个是不用换的,只有第二和第三个的坐标需要调整,也就是根据正弦和余弦进行投影。
在这里插入图片描述
之后进行共计100轮次的迭代计算,这一次需要计算的是xy方向上面的平移。每一次迭代首先会取出一个合法扇区,根据先前计算出的径向旋转得到投影之后的位置,在这个位置左右各10个扇区共计20个扇区范围内进行检验。指标是扇区描述子中二三维度对应的点的几何距离。
在这里插入图片描述
对于当前扇区找到的最近点扇区,如果坐标偏差足够小则进行统计计算,对偏移量进行累计。
在这里插入图片描述
遍历完所有扇区之后,对所有的偏差取平均,作为当前这一次迭代计算中的偏差值,这个偏差值表示的是xy方向上面的偏移,直接对点云描述子进行校正,同时存储所有的偏差。
在这里插入图片描述
最终,diff_x、diff_y以及angle将会被作为两帧点云之间的位姿差异传递回主函数。从这整个过程来看,globalICP这个函数就是将位姿变化拆分为旋转和平移进行计算,旋转依赖的是扇区描述子的旋转不变性,通过最小化轴向距离差值来找到最优的径向旋转偏差,而平移则是依靠得到的旋转结果进行调整,在计算平移时则不利用径向距离,而是利用扇区之间点的几何距离来调优,迭代100轮以完成平移的计算。这里说一下个人感觉不足的地方,在整个的计算过程中点云被十分过分地简化,按照代码默认的配置文件,径向上划分了360个扇区,就算不考虑语义类别,一帧点云顶天也就只保留了360个点用于构建这个描述子,从数量上来看简化的有些过分。另外,在计算的过程中,旋转和平移被完全拆分开来,先只计算旋转,计算平移时则固定旋转,这种方法未必得到的就是最优的结果,平移和旋转应该作为整体共同进行调整,而没见过这种拆分固定的计算策略。最后,扇区的划分很大程度上会影响结果的准确性,由于选择扇区的点的时候只考虑了到中心点的距离这一个指标,而在径向上完全不做考虑,这就有可能导致一个扇区对应的1度范围内,0.0001度的点和0.9999度的点进行了对齐,有可能导致径向上1度的偏差,而在固定旋转调整平移的过程中更有可能错上加错,所以这一策略或者是开源的代码本身其实是有较大的不足的。

calculateSSC()

回到getScore函数,globalICP计算出的位姿变化会被存储在diff_x、diff_y以及angle中,利用这个变化关系将点云进行投影,之后调用calculateSSC函数进行ssc描述子的计算。这个函数要简单的多,首先初始化径向和轴向的步长,得到一个二维的矩阵用于存放描述子,矩阵的每个位置存放的都是一个8位无符号数。
在这里插入图片描述
之后遍历点云内的每个点,对于需要统计的类别的点,确定其在二维矩阵中的位置。原论文提到了写在描述子中的类别是根据优先级选择的,从代码来看,这个优先级就是提前写死在order_vec里面了。在确定好的位置中,如果已经写入了,就根据优先级进行判断,选择覆盖或者保持不变。
在这里插入图片描述

calculateSim()

完成ssc描述子的计算后,就会调用calculateSim函数计算相似度,相似度的计算也很简单,就是比较相同位置上的语义是否相同,最终统计相同的占总合法位置中的比例,这个比例会作为相似度分数返回给主函数。
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/33615.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

图解布隆过滤器(Bloom Filter)

布隆过滤器详解 布隆过滤器(Bloom Filter)是一种空间效率非常高的随机数据结构,由布隆(Burton Howard Bloom)在1970年提出,用于检验一个元素是否属于一个集合。 具体来说,它可能会错误地认为一个…

Jmeter插件管理器,websocket协议,Jmeter连接数据库,测试报告的查看

目录 1、Jmeter插件管理器 1、Jmeter插件管理器用处:Jmeter发展并产生大量优秀的插件,比如取样器、性能监控的插件工具等。但要安装这些优秀的插件,需要先安装插件管理器。 2、插件的下载,从Availabale Plugins中选择&#xff…

达梦(DM8)数据库表空间的备份与还原(联机备份) 四

一、表空间的备份 1、备份表空间的命令操作 backup tablespace main backupset /home/dmdba/dmdata/DAMENG/bak/full_back_01 ; 2、检查表空间的备份文件 select sf_bakset_check(disk,/home/dmdba/dmdata/DAMENG/bak/full_back_01); 二、表空间的还原 1、修改表空间位脱机…

AI播客下载:Edge of AI (AI最新应用场景和发展趋势)

Edge of AI Podcast 是一个探讨人工智能(AI)最新应用和发展的播客。该播客由Ron Levy主持,他于2023年8月9日接任新主持人。每个节目都会邀请专家分享他们在AI领域的见解和经验,探索最新的应用场景和发展趋势。例如,在第…

PointCloudLib 法线微分算法(Don)分割点云 C++版本

0.实现效果 原始点云 不同尺度上计算法向量 计算出don特征量,并以颜色显示在点云上 可以看出平面中心的点 不涉及到周围点变化的点 特征量比较低,以红色表示 边缘过渡剧烈的点,特征量比较高,以蓝色表示 以Don算法特征量来作为阈值分割点云,可以分割出剧烈变化的点云 欧…

国标GB28181视频汇聚平台EasyCVR设备展示数量和显示条数不符的原因排查与解决

国标GB28181/GA/T1400协议/安防综合管理系统EasyCVR视频汇聚平台能在复杂的网络环境中,将前端设备统一集中接入与汇聚管理。智慧安防/视频存储/视频监控/视频汇聚EasyCVR平台可以提供实时远程视频监控、视频录像、录像回放与存储、告警、语音对讲、云台控制、平台级…

Django教程(002):模板语法的使用

目录 1 字符串2 列表3 字典4 列表中是字典5 if语句6 案例:使用爬虫爬取联通新闻并在页面渲染 模板语法本质上:在HTML中写一些占位符,由数据对这些占位符进行替换和处理。模板语法主要是方便对方法返回的数据在前端进行渲染,这些数…

【Proteus仿真】【Arduino单片机】寻迹避障蓝牙遥控小车

文章目录 一、功能简介二、软件设计三、实验现象联系作者 一、功能简介 本项目使用Proteus8仿真Arduino单片机控制器,使LCD1602液晶,L298电机,直流电机,HC05/06蓝牙模块,HCSR04超声波,红外寻迹模块等。 主…

C++初学者指南-2.输入和输出---命令行参数

C初学者指南-2.输入和输出—命令行参数 文章目录 C初学者指南-2.输入和输出---命令行参数1.这是什么&为什么这样?2.如何在C中访问3.转换为std::string、int......4.字符串到数字的转换函数5.命令行参数解析库 1.这是什么&为什么这样? 程序调用后…

说说 SSL 的错误认识和不足之处

最近明月在学习折腾 LNMP 期间无意中建了一个 Typecho 的博客小站,近一周的折腾下来,收获真的不少,致使兴趣也越来越浓了,在升级 LNMP 的时候捎带手的给这个 Typecho 博客也启用了 SSL。并且开启了 memcached 和 OPcache 优化加速…

C++在VS2022开发Windows窗口程序1:第一个win窗口程序

Windows操作系统是由微软公司开发和维护的一系列图形化操作系统的统称。Windows操作系统主要用于个人计算机、笔记本电脑、平板电脑、服务器等设备上。Windows起源于Microsoft-DOS模拟环境,相比于DOS的指令化模式,Windows采用图形化的模式,因…

OkHttp框架源码深度剖析【Android热门框架分析第一弹】

OkHttp介绍 OkHttp是当下Android使用最频繁的网络请求框架,由Square公司开源。Google在Android4.4以后开始将源码中的HttpURLConnection底层实现替换为OKHttp,同时现在流行的Retrofit框架底层同样是使用OKHttp的。 源码传送门 优点: 支持Http1、Http…

[保姆级教程]uniapp设置字体引入字体格式

文章目录 在 UniApp 中设置和引入自定义字体(如 .ttf、.woff、.woff2 等格式)通常涉及几个步骤。 准备字体文件: 首先,你需要有字体文件。这些文件通常以 .ttf、.woff 或 .woff2 格式提供。确保有权使用这些字体,并遵守…

代码随想录算法训练营第二十八天

题目:134. 加油站 暴力方法 暴力的方法很明显就是O(n^2)的,遍历每一个加油站为起点的情况,模拟一圈。 如果跑了一圈,中途没有断油,而且最后油量大于等于0,说明这个起点是ok的。 暴力的方法思路比较简单…

SCI一区TOP|电鳗觅食优化算法(EEFO)原理及实现【免费获取Matlab代码】

目录 1.背景2.算法原理2.1算法思想2.2算法过程 3.结果展示4.参考文献5.代码获取 1.背景 2024年,W Zhao受到自然界中电鳗群体觅食行为启发,提出了电鳗觅食优化算法(Electric Eel Foraging Optimization, EEFO)。 2.算法原理 2.1算…

SSRF漏洞原理与案例分析

一、什么是SSRF漏洞 SSRF (Server-Side Request Forgery:服务器端请求伪造)是一种由攻击者构造请求,由服务端发起请求的安全漏洞。一般情况下,SSRF攻击的目标是外网无法访问的内部系统(正因为请求是由服务端发起的,所以服务端能请…

Marin说PCB之如何在CST仿真软件中添加三端子的电容模型?--02

小编我在上期文章的结尾给大家留下一个小问题就是:在三端子电容创建模型中间的部分我有说了一句就是:(其中有一个creat reference pin 设置我们也默认不勾选),这个勾选不勾选有啥区别呢?这期文章就来给大家…

提高LabVIEW程序可靠性

​提高LabVIEW程序的可靠性是确保系统稳定运行、减少故障和维护成本的重要措施。以下从多个方面详细分析如何提高LabVIEW程序的可靠性 1. 选择合适的架构 1.1 状态机架构 适用情况: 多状态、多步骤操作。 具体例子:在一个自动测试系统中,…

[汇总] Docker容器详解 Macvlan 创建不同容器独立跑仿真(持续更新中)

一、概念介绍 1.1 什么是macvlan macvlan是一种网卡虚拟化技术,能够将一张网卡(Network Interface Card, NIC)虚拟出多张网卡,这意味着每个虚拟网卡都能拥有独立的MAC地址和IP地址,从而在系统层面表现为完全独立的网络…

mybatisplus字段注入MetaObjectHandler扫描不到我的指定填充字段

使用mybatisplus自带的字段填充策略注入值的时候,发现并没有扫描到我的指定字段。 1. 初始代码 Component Slf4j public class MyMetaObjectHandler implements MetaObjectHandler {private static final String createByFiled "createBy";private stati…