DSO 系列文章(2)——DSO点帧管理策略
文章目录
- 1.点所构成的残差Residual的管理
- 1.1.前端残差的状态
- 1.2.后端点的残差的状态
- 1.3.点的某个残差的删除
- 2.点Point的管理
- 2.1.如何删除点——点Point的删除
- 2.2.边缘化时删除哪些点?
- 3.帧FrameHessian的管理
DSO代码注释:https://github.com/Cc19245/DSO-CC_Comments
1.点所构成的残差Residual的管理
1.1.前端残差的状态
PointFrameResidual
的状态有三种:
-
IN
——内点。表示这个残差状态正常,可以参与优化; -
OOB
——Out Of Boundary
,出界点。表示把host
帧上的点通过线性化点或最新状态的相机位姿投影到target
帧之后,这个点不在图像范围内,表示这个点出界了,那么这个残差不能参与优化。注意:一个残差只要被判断为出界,后面就再也不用他了,作者代码中也有一句注释叫做
can never go back from OOB
。这个确实也是有道理的,因为前端已经跟踪得到了一个初始位姿了,有投影匹配的点是不太可能出界的。 -
OUTLIER
——外点,表示这个残差能量超过了阈值,注意和OOB
区分。外点类似于特征点法中的无匹配,也就是找到了匹配关系,但是误差太大,如果使用它优化会造成不好的影响,干脆就不用这个残差。注意:随着优化的进行,外点的残差能量有可能会慢慢降低到小于阈值,此时它就可以恢复成内点,然后继续参与优化。因此外点是可以恢复的。
为了让OOB
起到一票否决的作用,在代码中使用了state_state
变量表示这个残差上次的状态,一旦它上次的状态是OOB
,那么函数都会直接跳过或返回,从而这个残差永远不可能再次参与到优化中。
1.2.后端点的残差的状态
EFResidual
的状态就比较简单了,只有一个变量bool isActiveAndIsGoodNEW
来表示这个点能量残差是否在后端优化中使用。这个变量是由前端残差的状态来设置的,只有前端残差的状态是IN
,这个变量才是true
,否则全都是false
。
那么什么时候设定后端残差的状态呢?就是调用applyRes
把前端雅克比传递给后端的时候,此时会一并把前端残差的状态传递给后端,让后端残差的状态得到更新。下面对几个函数进行说明:
-
PointFrameResidual::linearize
(1)前端残差进行线性化求雅克比。注意这个过程中有两部分雅克比, 一个是像素点关于相机位姿、内参、逆深度部分雅克比,它们使用线性化点的状态,保持不变;另一个是像素梯度和残差,它们使用最新的状态,因此是变化的。
(2)在此过程中会判断前端残差的状态,存储到前端残差的类成员变量中。
-
``PointFrameResidual::applyRes`
把前端残差更新到后端,同时把前端残差的状态也更新到后端(这个很正常,因为残差都给后端了,自然也要告诉后端这个残差是否有效)
-
FullSystem::linearizeAll_Reductor(true/false)
(1)一定会调用
PointFrameResidual::linearize
计算最新的雅克比,并且判断前端残差状态。(2)如果传入
true
,会把前端雅克比和残差状态更新到后端,并且把前端非IN
状态的残差放到toRemove
数组中。 -
FullSystem::linearizeAll(true/false)
(1)一定会调用
FullSystem::linearizeAll_Reductor(true/false)
。(2)如果传入
true
,那么会把linearizeAll_Reductor
函数里统计出来的非IN
状态的残差,从PointHessian
和后端优化的大bossEnergyFunctional
中丢弃,也就是这个残差不再存在了。注意:什么时候这个函数会传入
true
呢?答案是只有在完成迭代优化的循环之后才会传入true
,因为此时已经得到了本次滑窗优化的最终结果,可以把使用这个最终结果判断的非IN
状态的残差从前端和后端删掉了。但是其他任何时候,比如迭代优化之前或迭代优化过程中,我们只能对残差求雅克比、判断它们状态,如果不是IN
那么后端优化就不使用,但是我们不能把这些残差删掉,因为优化还没开始或者还没完成,可能这次是OUTLIER
的残差,优化几次就变成了IN
,所以我们不能删掉这些残差。
1.3.点的某个残差的删除
如上所述,在FullSystem::optimize
中后端迭代优化完成后,会调用FullSystem::linearizeAll(true)
根据最新的状态把所有残差重新线性化一次,由于传入了true
所以会筛选出非IN
状态的残差,并把他们删除掉,该函数中实现的删除残差的步骤如下:
EnergyFunctional::dropResidual
删除后端残差:先把这个残差从后端能量点的残差数组中弹出,然后把前端对应的残差持有的这个后端残差指针置零,最后delete
释放内存。FullSystem::deleteOut
删除前端残差:先把前端点的残差数组中要删除位置的残差的指针delete
释放到,然后把数组最后一个残差赋值到这个位置。其实本质上和删除后端残差的操作一致,只不过释放指针和弹出数组的先后顺序不同。
2.点Point的管理
2.1.如何删除点——点Point的删除
如上所述,在FullSystem::optimize
中后端迭代优化完成后,会根据最新的状态把所有残差重新线性化一次,同时筛选出非IN
状态的残差,并把他们删除掉。出了FullSystem::optimize
函数之后,执行FullSystem::removeOutliers
函数,把Point
的外点删除。
此函数中就是判断所有帧上的所有点,如果这个点的残差个数为0,那么他就要被删除掉了。所以从这里删除的判断条件来看,叫removeOutliers
可能不是太恰当,可能叫removePointsNonRes
,即删除没有残差的点更好一点。
下面细看这个函数中的实现步骤:
- 先把这个
PointHessian
加入到帧的前端点删除数组pointHessiansOut
中,等待后面统一删除。设置这个前端PointHessian
对应的后端EFPoint
状态为PS_DROP
,给后面后端删除EFPoint
使用。然后把这个点从帧的点数组中删掉,注意这里还没有delete
释放这个PointHessian
的内存,只是把它加入到了外点数组中。 - 调用
EnergyFunctional::dropPointsF
把后端的点删掉。此函数中调用removePoint
,该函数中会先把这个EFPoint
对应的所有EFResidual
删掉,然后把这个点从能量帧的点能量数组中删掉,最后把这个delete
这个能量点释放内存。
注意:从上面两步可以看出来,这里的代码设计还是有点瑕疵的,因为删除前端的点之后没有释放内存,而是等待后面统一释放。而删除后端的点则释放了内存,前后端的操作不统一了。
7.28最新想法:可能作者是故意这样设计的,因为看代码中显示部分好像有删除点的数组相关的内容,所以就是把这些点存到数组中来显示历史上的所有点?
7.29最新想法:这个其实是没有问题的,确实是作者有意为之,而且原因也就是删除的点还要被使用。因为上面也说了,要删除的PointHessian
指针被放到了前端点的删除数组pointHessiansOut
中,后面要给显示线程使用。即然被放到了这个数组中,自然这个指针就不能释放了,否则这个数组中存的就都是野指针了。而把这些点从正常使用的前端点数组pointHessians
中弹出,就意味着以后肯定无法再使用这个点了,因此从系统功能上已经实现了删除这个点的目的。而对于后端来说,既然这个点被删除了,那么我后端优化肯定就不会使用它构造H/b
了,因此完全可以把这个点能量EFPoint
完全从内存中抹去。
2.2.边缘化时删除哪些点?
如上述所说,在FullSystem::optimize
中后端迭代优化完成后,会根据最新的状态把所有残差重新线性化一次,同时筛选出非IN
状态的残差,并把他们删除掉。出了FullSystem::optimize
函数之后,执行FullSystem::removeOutliers
函数,把哪些没有残差的Point
删除掉。
接下来系统就进入了边缘化的阶段,首先是判断哪些点要边缘化掉,这样就会利用这些点构成的残差计算一个H/b
,然后把这些点的逆深度Schur消元掉,只保留68x68
的相机状态。然后下面对关键帧进行边缘化,再把这个H/b
消掉一个相机帧得到维度缩减的HM/bM
,从而给下一帧使用。
那么如何判断哪些点要被边缘化掉或者直接丢掉呢?在函数FullSystem::flagPointsForRemoval
中实现这些功能。这个函数中选择要边缘化或者删除的点,只有两个根据:
(1)即将被边缘化的帧上的点:显然帧都没了,帧上的点肯定也不能再存在了。所以如果这个点性质比较好(比如多次构成的残差足够多、优化的逆深度协方差足够小),那么就把它边缘化掉,从而给后面的帧形成约束;如果这个点的性质不好,那么就直接把它丢掉,而不能边缘化,因为这样可能会引入错误的约束;
(2)其他帧上的点根据性质判断:即代码中的PointHessian::isOOB
函数,内部会判断非边缘化帧上的点是否要被选择边缘化或者丢弃,这部分判断准则还不是很明白。
筛选出来这些点之后,在代码中就是对这些点进行处理,要么边缘化,要么直接丢掉。而如果一个点既不是外点,也不是要边缘化/丢掉的点,那么它就是正常的点,会继续存在于滑窗中,因此对它不进行任何处理,这就是为什么 代码 中elseif
后面没有else
了,也就相当于一个空的else
,即如果是else
则什么也不干。
最后注意:跟优化之后接着删除点一样,也上面的函数里面也是只把要丢掉的前端点PointHessian
放到了删除数组中,并且从使用数组中弹出,这样就是完成了前端点的删除。而后端的对应的能量点在这个函数中没有释放,所以还要再释放后端的能量点,但是这个释放放在了FullSystem::flagPointsForRemoval
函数外面去调用,这是我觉得不太好的地方,放在该函数里面调用更好。而且这个函数命名也不准确,我觉得命名为MarginOrDropPoints
更好,也就是边缘化或者丢掉点。同理应该把后面的ef->marginalizePointsF();
函数也一并放进里面调用,实际就完成了整个点的边缘化。这样拆开反而逻辑没有那么清晰了。
3.帧FrameHessian的管理
-
在上一步边缘化掉点之后,得到了这些点的残差构成的
HM/bM
矩阵,但是这个矩阵中仍然是含有要被边缘化掉的帧的状态的,因此还要对这个HM/bM
进行Schur消元得到消元之后维度缩减的HM/bM
,给下次滑窗优化使用。 -
在后端对边缘化的帧进行Schur消元之后,还有一个步骤需要做,那就是把其他帧上以被边缘化掉的帧为
target
帧的那些点的残差删掉,这个也是很正常的,因为这帧没有了,自然其他帧上的点和这帧关联的残差也就没有了。注意这个不是说其他帧上的点也不用了,这些点还是和别的帧可以构成残差的,所以这个和边缘化/丢掉点是不同的,这个是对仍然存在于滑窗中的点的残差进行处理。 -
而删除点的某个残差,则跟上面1.3节讲述的一样了,那就是先
dropResidual
删掉后端残差,再deleteOut
删除前端残差。 -
把残差处理完了,就要删除这个帧了,调用
deleteOutOrder
函数把这个帧从FullSystem
的帧数组中弹出,这就保证了它不会在FullSystem
中再被调用参与滑窗优化了,但是不会释放它的内存。这个跟PointHessian
的删除逻辑是一样的,本质上是因为这个FrameHessian
的指针在优化之前已经被加入到allFrameHistory
里面了,如果在这里把指针释放了,那么allFrameHistory
里面存的就是野指针了。 -
由于删除了滑窗中的一个关键帧,所以需要调用
setPrecalcValues
函数重新计算各个帧的线性化点状态、最新状态、状态增量等变量,然后还要调用ef->setAdjointsF
重新计算各个帧之间的伴随矩阵。至此,帧边缘化的操作全部完成。
相关文章:
DSO 系列文章(2)——DSO点帧管理策略
文章目录 1.点所构成的残差Residual的管理1.1.前端残差的状态1.2.后端点的残差的状态1.3.点的某个残差的删除 2.点Point的管理2.1.如何删除点——点Point的删除2.2.边缘化时删除哪些点? 3.帧FrameHessian的管理 DSO代码注释:https://github.com/Cc19245/…...
无需公网IP——搭建web站点
文章目录 概述使用 Raspberry Pi Imager 安装 Raspberry Pi OS设置 Apache Web 服务器测试 web 站点安装静态样例站点将web站点发布到公网安装 Cpolar内网穿透cpolar进行token认证生成cpolar随机域名网址生成cpolar二级子域名将参数保存到cpolar配置文件中测试修改后配置文件配…...
swift 项目集成友盟推送
1, 需要用桥接文件 , 不然引用不到依赖库 2, 可以用测试模式测试, 可以debug 3, 测试模式获取deviceToken, 添加测试设备 deviceToken获取方法 func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) { le…...
Unity之用Transform 数组加多个空物体-->简单地控制物体按照指定路线自动行驶
文章目录 **原理解释**:**带注释的代码**:实际运用 当你需要实现物体按照指定路线行驶时,你可以通过以下步骤来实现: 原理解释: 路径点:你需要定义一系列路径点,这些点将构成物体行驶的路线。每…...
交换机生成树STP
生成树协议(spanning-tree-protocol,stp):在具有物理环路的交换机网络上生成没有回路的逻辑网络的方法,生成树协议使用生成树算法,在一个具有冗余路径的容错网络中计算出一个无环路的路径,使一部分端口处于…...
3.微服务概述
1.大型网络架构变迁 SOA与微服务最大的差别就是服务拆分的细度,目前大多数微服务实际上是SOA架构,真正的微服务应该是一个接口对应一个服务器,开发速度快、成本高; 微服务SOA能拆分的就拆分是整体的,服务能放一起的都…...
cloud_mall-notes02
1、多条件分页查询page ApiOperation("多条件分页查询xxxx")GetMapping("page")PreAuthorize("hasAuthority(模块权限:权限:page)")public ResponseEntity<Page<实体类>> loadxxxxPage(Page<实体类> page,实体类 domain) {pag…...
前端轻松实现文件预览(pdf、excel、word、图片)
需求:实现一个在线预览pdf、excel、word、图片等文件的功能。 介绍:支持pdf、xlsx、docx、jpg、png、jpeg。 以下使用Vue3代码实现所有功能,建议以下的预览文件标签可以在外层包裹一层弹窗。 图片预览 iframe标签能够将另一个HTML页面嵌入到…...
docker服务器、以及容器设置自动启动
一、docker服务设置自动启动 查看已启动的服务 systemctl list-units --typeservice 查看是否设置开机启动 systemctl list-unit-files | grep enable设置开机启动 systemctl enable docker.service关闭开机启动 systemctl disable docker.service 二、docker容器设置自…...
k8s集群证书过期后,如何更新k8s证书
对于版本 1.21.5,这是我的解决方案: 步骤1: ssh 到主节点,然后在步骤 2 中检查证书。 步骤2: 运行这个命令:kubeadm certs check-expiration rootkube-master-1:~# kubeadm certs check-expiration [c…...
5.6.webrtc三大线程
那今天呢?我们来介绍一下web rtc的三大线程,那为什么要介绍这三大线程呢?最关键的原因在于web rtc的所有其他线程都是由这三大线程所创建的。那当我们将这三个线程理解清楚之后呢?我们就知道其他线程与它们之间是怎样关系…...
@Slf4j报错:Not generating field log: A field with same name already exists
错误出处: 错误原因: 同时使用了Slf4j注解以及LittlecLogger private static final LittlecLogger log LittlecLoggerFactory.getLogger(TimeTrackController.class); 修复方法: 将log改为LOG,便于区分,代码即用到了…...
乖宝宠物上市,能否打破外资承包中国宠物口粮的现实
近日,乖宝宠物上市了,这是中国宠物行业成功挂牌的第三家公司。同时,昨日,宠物行业最大的盛事“亚洲宠物展”时隔3年,于昨日在上海成功回归。 这两件事情的叠加可谓是双喜临门,行业能够走到今天实属不易&…...
Ubuntu安装Apache+Php
环境:ubuntu 22.04 虚拟机 首先更新一下 sudo apt-get update sudo apt-get upgrade安装Apache2: sudo apt-get install apache2 输入y,继续。等着他恐龙抗浪抗浪的下载安装就好了 打开浏览器访问http://localhost/ 安装php: …...
open cv学习 (四)图像的几何变换
图像的几何变换 demo1 # dsize实现缩放 import cv2 img cv2.imread("./cat.jpg") dst1 cv2.resize(img, (100, 100)) dst2 cv2.resize(img, (400, 400)) # cv2.imshow("img", img) # cv2.imshow("dst1", dst1) # cv2.imshow("dst2&quo…...
matlab 检测点云中指定尺寸的矩形平面
目录 一、概述1、算法概述2、主要函数二、代码示例三、结果展示四、参数解析输入参数名称-值对应参数输出参数五、参考链接一、概述 1、算法概述 detectRectangularPlanePoints:检测点云中指定尺寸的矩形平面 <...
HCIP——STP配置案例
STP配置案例 一、简介二、实现说明1、华为实现说明2、其他厂商实现 三、STP原理1、协商原则2、角色和状态3、报文格式4、BPDU报文处理流程4.1 BPDU报文的分类4.2 BPDU报文的处理流程4.3 BPDU报文格式 四、使用注意事项五、配置举例1、组网需求2、配置思路3、操作步骤4、配置文件…...
JCTools Mpsc源码详解(二) MpscArrayQueue
MpscArrayQueue是一个固定大小的环形数组队列,继承自ConcurrentCircularArrayQueue MpscArrayQueue的特点: 环形队列底层数据结构为数组有界 看一下MpscArrayQueue的属性(填充类除外)--- //生产者索引 private volatile long producerIndex; //生产者边界 private volatile…...
前端面试的性能优化部分(13)每天10个小知识点
目录 系列文章目录前端面试的性能优化部分(1)每天10个小知识点前端面试的性能优化部分(2)每天10个小知识点前端面试的性能优化部分(3)每天10个小知识点前端面试的性能优化部分(4)每天…...
C++ STL无序关联式容器(详解)
STL无序关联式容器 继 map、multimap、set、multiset 关联式容器之后,从本节开始,再讲解一类“特殊”的关联式容器,它们常被称为“无序容器”、“哈希容器”或者“无序关联容器”。 注意,无序容器是 C 11 标准才正式引入到 STL 标…...
Python爬虫解析工具之xpath使用详解
文章目录 一、数据解析方式二、xpath介绍三、环境安装1. 插件安装2. 依赖库安装 四、xpath语法五、xpath语法在Python代码中的使用 一、数据解析方式 爬虫抓取到整个页面数据之后,我们需要从中提取出有价值的数据,无用的过滤掉。这个过程称为数据解析&a…...
Linux防火墙报错:Failed to start firewalld.service Unit is masked
Linux防火墙报错:Failed to start firewalld.service: Unit is masked. 1、故障现象: 启动防火墙失败,报错情况如下: systemctl start firewalld # 报错: Failed to start firewalld.service: Unit is masked.原因是…...
前端面试:【Vuex】Vue.js的状态管理利器
嗨,亲爱的Vuex探险家!在Vue.js开发的旅程中,有一个强大的状态管理库,那就是Vuex。Vuex是Vue.js的官方状态管理工具,通过State、Mutation、Action和Module等核心概念,协助你轻松管理应用的状态。 1. 什么是V…...
Kotlin协程runBlocking并发launch,Semaphore同步1个launch任务运行
Kotlin协程runBlocking并发launch,Semaphore同步1个launch任务运行 <dependency><groupId>org.jetbrains.kotlinx</groupId><artifactId>kotlinx-coroutines-core</artifactId><version>1.7.3</version><type>pom&…...
c++ Union之妙用
union的作用基本是它里面的变量都用了同一块内存,跟起了别名一样,类型不一样的别名。 基本用法: struct Union{union {float a;int b;};};Union u;u.a 2.0f;std::cout << u.a << "," << u.b << std::endl…...
JSON的处理
1、JSON JSON(JavaScript Object Notation):是一种轻量级的数据交换格式。 它是基于 ECMAScript 规范的一个子集,采用完全独立于编程语言的文本格式来存储和表示数据。 简洁和清晰的层次结构使得 JSON 成为理想的数据交换语言。易于人阅读和编写&#…...
matlab使用教程(20)—插值基础
1.网格和散点样本数据 插值是在位于一组样本数据点域中的查询位置进行函数值估算的方法。函数值是根据最接近查询点的样本数据点计算的。MATLAB 根据样本数据的结构,可以执行两种插值。样本数据可以形成网格,也可以是分散的。 网格化的样本数据使得插值…...
Python功能制作之简单的3D特效
需要导入的库: pygame: 这是一个游戏开发库,用于创建多媒体应用程序,提供了处理图形、声音和输入的功能。 from pygame.locals import *: 导入pygame库中的常量和函数,用于处理事件和输入。 OpenGL.GL: 这是OpenGL的Python绑定…...
leetcode-5-最长回文串
题目描述 给你一个字符串 s,找到 s 中最长的回文子串。 如果字符串的反序与原始字符串相同,则该字符串称为回文字符串。 示例 1: 输入:s “babad” 输出:“bab” 解释:“aba” 同样是符合题意的答案。 示…...
二、Oracle 数据库安装集
一、CentOS 安装 OCI下载地址 1. 启动 # 1. 登录服务器,切换到oracle用户,或者以oracle用户登录 su - oracle# 2. 打开监听服务 lsnrctl start# 3. 查看Oracle监听器运行状况 lsnrctl status# 4. 以sys用户身份登录 sqlplus /nolog# 5. 切换用户conn 用…...
做网址导航网站/java培训班
Oracle中SEQUENCES的使用 Oracle提供了sequence对象,由系统提供自增长的序列号,通常用于生成数据库数据记录的自增长主键或序号的地方. 下面介绍一下关于sequence 的生成,修改,删除等常用的操作: 1. 创建 Sequence 使用如下命令新建sequence(用户需要有CREATE SEQUENCE 或者…...
做网站标题居中代码/新业务在线软件下载
在 Java 单机应用中,如果要处理并发名额扣减或增加的操作,那么需要考虑事务问题。 事务是指一组相关的操作,这些操作要么全部执行,要么全部不执行。例如,在处理并发名额扣减或增加的操作时,可能需要对数据库中的某些表进行更新,这些更新操作就可以构成一个事务。 为了保…...
宁津网站建设/灰色行业推广
主板都有什么类型呢?不同主板之间有什么区别吗?不同类型的主板都有什么用呢?装机的时候,主板的大小不仅和机箱有关,也和其他硬件以及自己的性能、功能需求有很大的关系,因此选择一个正确类型的主板至关重要…...
15年做啥网站致富/新闻摘抄2022最新5篇
SanicCRUD-vue Sanic + 前端MVVM 一种新一代Python高性能全栈开发实践背景 本项目将使用Sanic Vue2 + Webpack2 配合最简单CRUD的逻辑来展示一个基于Python的全新一代高性能全栈开发实践的Demo 为什么是Sanic 对于为何不是Flask、Django等著名框架&…...
网站空间一般有多大/seo在线优化网站
好久没有写文章了,和之前年初的时候说要在这里记录所以一些知识文档有一点了违被了,都过这么久了也该把我09年03月到09月所发生,所了解的知识做一记录.3月17日 拆装2612硒鼓型号先发个图上来吧.结构:分为两边. 一边: 鼓芯,橡胶棒,废粉仓.另一边: 粉盒,充电辊. 拆装加粉…...
陇西网站建设公司/软文广告文案
一个atmel,mxt540e的CTP触摸屏。 中断配置为下降沿,输入上拉。总是只能触发一次中断,中断脚就一直低电平,无法拉高。这只是表面现象不停找底层I2C驱动,改代码,没用。要靠波形来说话用逻辑分析仪,…...