通俗易懂理解ORBSLAM2初始化模块
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了通俗易懂理解ORBSLAM2初始化模块相关的知识,希望对你有一定的参考价值。
参考技术A[1] ORBSLAM2 source code
初始化特征匹配
找候选匹配点函数,为什么要用网格呢,如果一个网格内没有特征点,直接跳过去,加速搜索。
连续2帧 特征点的数量 都大于100 才进行初始化。
[1] ORBSLAM2 source code
找最优和次优的逻辑:
这个BUG导致删除误差的能力下降了
筛选出在旋转角度差落在在直方图区间内数量最多的前三个bin的索引
阈值变大了,单个bin本来是12度,现在变为30度,比如说大部分都是12度以内,但是有的是20度,应该把他们删除,但是如果单个bin是30度的话,那就无法删除,这样弱化了对角度差过大的匹配的删除。
暴力匹配,那么重复怎么办?把之前的匹配不要了,当前的匹配放进去
[1] ORBSLAM2 source code
[2] 复习SVD分解
[3] 解Ax=b
为什么要对数据进行归一化?
对于不是很好的条件问题,数据归一化很重要,比如基础矩阵F直接线性变换DLT的计算方法。(如下说明)
归一化操作、归一化函数
一阶距、一阶绝对距
这个式子自己展开下,就是和上面计算的过程一模一样。
就是V^T的最后一行(也就是第9个奇异向量)变成3X3求解的H矩阵。
U是左奇异向量,是一个8X8的矩阵
V^T是右奇异向量,是一个9X9的矩阵
w是奇异值矩阵,奇异值在对角线上,是一个8X9对角矩阵
奇异值是按照从大到小的顺序排的
为什么要对图像坐标进行归一化:能够提高运算结果的精度。
:均值
偏离程度的均值
// 归一化
// 去归一化
// RANSAC 随机采样
我们知道他的奇异值的维度是9(因为是要求9个未知量),但是为什么是第9个呢,咋们怎么知道他的奇异值个数呢。正交矩阵是方阵,所以是第九个。
为什么ATA的特征向量就是VT的特征向量?这个怎么看的?有什么数学推理吗?还有想问下这个回答好像没有回答为什么V的第9个奇异向量是最优解这个问答?
[1] ORBSLAM2 source code
极线
对每一对点正向反向进行计算点到线的距离,误差在允许范围内就累加得分。误差越大,得分越低。然后选择一个最高得分的单应矩阵。
[1] ORBSLAM2 source code
[2] [ORB-SLAM2]卡方分布(Chi-squared)外点(outlier)剔除(说的太好了)
LocalMapping.cpp
不同的金字塔层级,重投影误差都用同一个相同的阈值不合理,因为每层金字塔,他的不确定是不一样的,用协方差对误差进行归一化,也就是去量纲了。接下来就是阈值的设定。
在概率论和数理统计中,k个自由度的卡方分布为k个互相独立服从标准正态的随机变量的平方和。卡方分布的自由度即为向量的维度。
因为是计算的是点到线的距离
这是基础矩阵的重要性质。因为F求不出尺度,尺度等价性。
正交阵<==>A的转置等于A的逆。
正定阵:x^Tx > 0,x是一个非0向量
对角矩阵:(diagonal matrix)是一个主对角线之外的元素皆为0的矩阵,常写为diag(a1,a2,...,an) 。
自由度为2,服从高斯分布,出现的概率超过95%时对应的卡方分布的值,如果小于这个值的话,那就是内点。
H的话是重投影,自由度是2。
F的话是计算点到极线的距离,自由度是1,维度降低了。
不同的金字塔层级,重投影误差都用同一个相同的阈值不合理,因为每层金字塔,他的不确定是不一样的,用协方差对误差进行归一化,也就是去量纲了。接下来就是阈值的设定。使用卡方分布进行设定。
[!问题已提出][w1]11.通俗易懂理解单目初始化单应矩阵归一化及DLT计算原理
[1] ORBSLAM2 source code
通过H恢复R,t需要看吗?作者说不用看。不是重点。
CheckRT很关键的一个函数(很值得学习) :
三角化的分析看 第6讲 视觉前端(切题 Done) 这个理解思路会更好。
取的是前4行的值,用第4个元素进行归一化 或者说用取的是前3行的值,用第3个元素进行归一化,有点奇怪?
VINS也是这样的,没问题。就是把第四维弄成1。
(1)三角化的特征点的x,y,z坐标是否无穷大
(2)夹角小于0.36度认为不好
(3)2帧中重投影误差是否太大。
(4)看下good点的数量。找good点最多的,并且good点要足够突出(second good < 0.75* good)等
, 为深度值, 为相机归一化坐标, 是投影矩阵 , 是点在世界坐标系下的坐标.
取第三行, , 所以
[1] ORBSLAM2 source code
F矩阵分解得到4组解,如何选择最好的呢?看每一种有效3D点的个数。看哪一种大于阈值0.7 * maxGood并且只有他一个。然后看下视差是否大于最小视差来判断最佳位姿。
H矩阵分解是几组解呢?8组解。看下good点的数量。找good点最多的,并且good点要足够突出(second good < 0.75* good)等
[1] ORBSLAM2 source code
[1] ORBSLAM2 source code
[2] 通俗易懂理解KeyFrame类问题 要点(切题 Done)
对当前帧和所有地图点进行尺度归一化。
Python-Thread(通俗易懂)
此类表示在单独的控制线程中运行的活动,有两种方法可以指定该活动,一是将可调用对象传递给构造函数,二是通过覆盖子类中的run()方法。
如果你对线程不太理解,我们可以打个比方,把线程数看作车辆数,我们来完成一个简单的客运运输工作(以下为了方便理解,也加入相应注释)。
更多threading模块函数和对象说明,可参考:https://www.cnblogs.com/leozhanggg/p/10317494.html
一、无线程:
示例:
import time
start = time.time() people = 500 # 假设有500个人 def action(num): global people while people>0: people -= 50 # 每次运输50人 print("车辆编号:%d, 当前车站人数:%d" %(num, people)) time.sleep(1) num = 1 # 车辆编号 action(num) end = time.time() print("Duration time: %0.3f" %(end-start))
运行结果:
C:\\Python37\\python.exe Y:/Project-python/threading/test.py 车辆编号:1, 当前车站人数:450 车辆编号:1, 当前车站人数:400 车辆编号:1, 当前车站人数:350 车辆编号:1, 当前车站人数:300 车辆编号:1, 当前车站人数:250 车辆编号:1, 当前车站人数:200 车辆编号:1, 当前车站人数:150 车辆编号:1, 当前车站人数:100 车辆编号:1, 当前车站人数:50 车辆编号:1, 当前车站人数:0 Duration time: 10.001 Process finished with exit code 0
二、单线程:
编码示例:
import threading import time
start = time.time() people = 500 # 假设有500个人 def action(num): global people while people>0: people -= 50 # 每次运输50人 print("车辆编号:%d, 当前车站人数:%d" %(num, people)) time.sleep(1) num = 1 # 车辆编号 vehicle = threading.Thread(target=action, args=(num,)) # 新建车辆 vehicle.start() # 启动车辆 vehicle.join() # 检查到站车辆 end = time.time() print("Duration time: %0.3f" %(end-start))
运行结果:
C:\\Python37\\python.exe Y:/Project-python/threading/test.py 车辆编号:1, 当前车站人数:450 车辆编号:1, 当前车站人数:400 车辆编号:1, 当前车站人数:350 车辆编号:1, 当前车站人数:300 车辆编号:1, 当前车站人数:250 车辆编号:1, 当前车站人数:200 车辆编号:1, 当前车站人数:150 车辆编号:1, 当前车站人数:100 车辆编号:1, 当前车站人数:50 车辆编号:1, 当前车站人数:0 Duration time: 10.001 Process finished with exit code 0
三、多线程(传递对象方式):
编码示例:
# -*- coding: utf-8 -* import threading import time people = 500 # 假设有500个人 def action(num): global people while people>0: people -= 50 # 每次运输50人 print("车辆编号:%d, 当前车站人数:%d" %(num, people)) time.sleep(1) start = time.time() vehicles = [] # 新建车辆组 for num in range(5): vehicle = threading.Thread(target=action, args=(num,)) # 新建车辆 vehicles.append(vehicle) # 添加车辆到车辆组中 for vehicle in vehicles: vehicle.start() # 分别启动车辆 for vehicle in vehicles: vehicle.join() # 分别检查到站车辆 end = time.time() print("Duration time: %0.3f" % (end-start))
运行结果:
C:\\Python37\\python.exe Y:/Project-python/threading/test.py 车辆编号:0, 当前车站人数:450 车辆编号:1, 当前车站人数:400 车辆编号:2, 当前车站人数:350 车辆编号:3, 当前车站人数:300 车辆编号:4, 当前车站人数:250 车辆编号:2, 当前车站人数:200 车辆编号:1, 当前车站人数:150 车辆编号:0, 当前车站人数:100 车辆编号:3, 当前车站人数:50 车辆编号:4, 当前车站人数:0 Duration time: 2.001 Process finished with exit code 0
四、多线程(覆盖子类方式)
编码示例:
# -*- coding: utf-8 -* import threading import time people = 500 class MyThread(threading.Thread): def __init__(self, num): super(MyThread, self).__init__() self.num = num def run(self): global people while people > 0: people -= 50 print("车辆编号:%d, 当前车站人数:%d " % (self.num, people)) time.sleep(1) start = time.time() vehicles = [] # 新建车辆组 for num in range(5): # 设置车辆数 vehicle = MyThread(num) # 新建车辆 vehicles.append(vehicle) # 添加车辆到车辆组中 vehicle.start() #启动车辆 for vehicle in vehicles: vehicle.join() # 分别检查到站车辆 end = time.time() print("Duration time: %0.3f" % (end-start))
运行结果:
C:\\Python37\\python.exe Y:/Project-python/threading/test.py 车辆编号:0, 当前车站人数:450 车辆编号:1, 当前车站人数:400 车辆编号:2, 当前车站人数:350 车辆编号:3, 当前车站人数:300 车辆编号:4, 当前车站人数:250 车辆编号:0, 当前车站人数:200 车辆编号:2, 当前车站人数:150 车辆编号:3, 当前车站人数:100车辆编号:1, 当前车站人数:50 车辆编号:4, 当前车站人数:0 Duration time: 2.003 Process finished with exit code 0
五、结果分析
1. 通过结果不难发现,不使用线程类和使用单线程运行时间是一样的,因为我们正常执行一个脚本,本质上就是单线程。
2. 创建多线程的两种方法运行时间也是一样的,因为最终都是交给Thread类来处理,自行选择即可。
3. 多线程运行时间明显比单线程快的多,从理论上来说是和线程数成正比的,但是实际并非是线程越多越好,因为线程越多所消耗的资源也就越多。
六、有关该类的其他说明:
a. 创建线程对象后,必须通过调用线程的start()方法启动其活动,这将在单独的控制线程中调用run()方法。
b. 一旦线程的活动开始,线程就被认为是“活着的”,当run()方法终止时,它会停止活动,或者引发异常。
c. 线程可以调用is_alive()方法测试是否处于活动状态,其他线程可以调用线程的join()方法,这将阻塞调用线程,直到调用其join()方法的线程终止。
d. 线程有一个名称,这个名称可以传递给构造函数,并通过name属性读取或更改。
e. 线程可以标记为“守护程序线程”,这个标志的意义在于,当只剩下守护进程线程时,整个Python程序都会退出,可以通过守护程序属性设置该标志。
----- 转载请注明原作,谢谢:https://www.cnblogs.com/leozhanggg/p/10335098.html
以上是关于通俗易懂理解ORBSLAM2初始化模块的主要内容,如果未能解决你的问题,请参考以下文章