1.ORB-SLAM2为了特征点均匀化做了哪些处理?
1)构建图像金字塔,构建八层的图像金字塔,在每层图像上提取特征点,具体每层提取多少数量的特征点都事先通过缩放因子计算好;
2)提取的时候,会将图像划分成一个个网格,分别在网格上进行特征点的提取。这时候特征点的数量往往是超过我们需要的点的数量,且只是初步进行了一个均匀化;
3)紧接着会使用四叉树均匀化的方法,这里就涉及到提取器节点的这么一个类。就是最开始整幅图像是一个节点,然后会对该节点进行划分,分成四个,然后将特征点都分别分配到这四个节点。后面就是不断重复类似的操作,划分节点,直到节点数等于所需的特征点数,然后只保留响应值最大的那个特征点。其实这里的操作也有点是把图像进行分块,直到分出来的块数等于所需的节点数,然后只留下质量最好的特征点。做完均匀化之后还会利用灰度质心法计算。
4)通过上面的步骤就提取完特征点,然后这时候特征点的坐标还是不同图层下的坐标,因此需要将所有特征点坐标转到第0层图像下的坐标;
5)然后会进行高斯模糊,计算描述子。
2. H矩阵是什么?说出几个典型的使用场景
H矩阵指单应矩阵,一般如果所有特征点都落在同一平面上,可以利用这种矩阵进行运动估计,典型使用场景有无人机携带的俯视相机等。
当相机发生纯旋转时,此时平移为零,基础矩阵自由度下降,基础矩阵误差较大,选用单应矩阵来恢复位姿。
在相机标定里用的就是H矩阵,还有针对比较远的场景,也可以用H矩阵。
3.LOAM和LeGO-LOAM的区别
1,提取地面点对z,pitch俯仰角,roll翻滚角做约束,优化后的结果作初始值再用其他点对x,y,yaw偏航角做约束
2,基于BFS广度优先搜索做了一个聚类剔除外点的处理,聚类主要就是以角度为阈值划分是不是同一个物体
3.loam也有后端优化吧,只不过loam的后端优化是基于体素地图做的,这样子不好的点就是不好做回环,legoloam则是筛选关键帧,利用关键帧做局部点云地图来构建局部地图,做当前帧到局部地图的匹配。
4.IMU预积分为什么可以避免重复传播?---未看
IMU预积分与通常积分相比,解决了初始状态更新时以及加速度计、陀螺仪偏差变化时所导致的积分重新计算问题。其主要思路是计算两个关键帧之间的状态增量,当初始状态变化,就在原来增量基础上乘以初始状态的变化量;当偏差变化时,则通过求取预积分量关于偏差的雅各比,实现预积分的一阶线性近似更新。
5.so(3)和se(3)的区别是什么,如何在算法中使用?
so3旋转矩阵的李代数表示,se3位姿变换矩阵的李代数表示,二者可以通过指数-对数关系实现转换,sophus中将旋转矩阵利用Log函数转换成对应的旋转向量,在算法中扰动模型更新时,常将一个扰动向量通过指数映射关系转换成相应的扰动矩阵,左乘或右乘旋转矩阵实现更新
6.VINs-Mono的初始化和ORB-SLAM3的初始化有啥区别?---未看
7.为什么单目视觉SLAM 会有尺度不确定性,而双目视觉SLAM却不会有?简述单目视觉SLAM尺度不确定的原因?
从理论上来讲,单目视觉SLAM的初始化运动是一个2D-2D的求解问题,是通过对极几何解决的。我们通过本质或者基础矩阵的分解来得到相机运动,对极约束是等式为0的约束,因此具有尺度等价性,由分解出的平移量乘以任意非零常数任然满足对极约束,因此平移量是具有一个不确定的尺度的,即我们放大任意倍数,都是成立的,导致了单目尺度的不确定性。从直觉感官角度来讲,从一张图像中,我们无法判断图像中物体的实际大小,因为不知道物体的远近。双目相机拍摄一次能够获得具有视差的左右目两张图像,在已知基线的情况下,计算视差,可以通过三角测量原理直接得出深度信息,因此不存在尺度不确定性。
8.BA当中雅可比矩阵的维度如何计算?
梳理清楚误差量和状态量就非常好理解了。 如纯视觉情况下,误差量要么是重投影误差,要么是光度误差,维度都为2。 此时状态量有两个:位姿和空间点,那么空间点维度为3,李代数表示位姿的话维度为6。 所以最后雅可比就是2维误差量分别对6维位姿(2x6)、3维空间点(2x3)求导,结果就是2x9。 所以最终结论就是:雅可比维度=误差维度x状态量维度
9.用自己的语言讲一下逆深度的含义和作用
1、和3D位置相比,逆深度维度更小;
2、在实际应用过程中,可能会看到类似天空这样比较远的点,导致z很大。那么即使产生了微小的变化量,也会给优化带来巨大的干扰。但是使用逆深度就可以这种情况。
3、逆深度的分布更符合高斯分布。
10.如何理解视觉重投影误差?
在SLAM初始化完成后,我们可以通过世界坐标系中的3D点位置和图像中的2D点匹配关系,由PNP算法初步求解两帧图像间的位姿变换。这个位姿变换并不准确,因此采用视觉重投影误差的方式进行进一步优化。重投影,意为利用我们估计的并不完全准确的位姿对三维空间点再次投影。我们已知特征点在图像中的实际位置,即观测值,利用初步求解的位姿,通过投影关系,再次将世界坐标系中的三维点投影到二维成像平面上,得到特征点像素坐标的估计值,与实际的观测值作差,对于n个特征点,构建最小二乘问题,认为差值越小,越符合实际的投影,估计越准确,最后得到优化后的位姿。
11.请对比几种激光配准算法(ICP,NDT,PL-ICP,CSM-cartographer)的优缺点
一、原理
1.ICP:基于最小二乘法的最优配准方法,根据target点云构建kdtree,遍历source点中每一点求取距target点云中最近距离,以距离为残差,以旋转和平移为优化变量,求解最小二乘问题。
2.PL-ICP:ICP改进版,利用kdtree搜寻target中最近的两个点,以source点到直线(这两个点构成)的距离为残差,求解方法同上。
3.NDT:把target点云分割成多个cell,计算每个cell中点云高斯分布概率密度函数,再计算source点云落在cell中相应的概率分布函数,以-log(此函数)为残差,求解最小二乘问题。
4.CSM-cartographer:采用分支定界方法,代替暴力搜索(旋转,平移一步一步搜索),通过栅格地图分块分支,通过改变栅格分辨率的方法定界(即高分辨率得分一定小于低分辨率得分),得分指点云落入栅格分的总和,不详细说明了。
二、优缺点
1.ICP:需要构建kdtree,相对NDT耗时更长(NDT的cell尺寸不是特小情况下),精度相对NDT高一些,对初值敏感,否则容易陷入局部最优解。以点到点距离为残差略不合理,因为激光雷达扫描的点不能一一对应,引入误差。
2.PL-ICP:相对ICP,在一定程度上减轻了第二个问题的影响。
3.NDT:一般情况下,相比ICP计算快,对初值不像ICP那么敏感,但太差了也不太行,精配准不及ICP。
4.CSM-cartographer:分支定界方法,肯定是比暴力搜索强,个人认为是牺牲内存换取速度的方法,2D还不错,3D使用好像较少。
12.ORB-SLAM3与VINS-Mono的前端有何区别?并分析这些区别的优缺点
ORB-SLAM3跟踪线程的输入为图像帧(单目/双目/RGB-D)及IMU数据。对于图像数据,首先对图像进行金字塔分层,对每层金字塔提取ORB(Fast角点+二进制描述子)信息,并基于四叉树进行特征点均匀化,同时进行高斯模糊以及去畸变。之后进行地图初始化,ORB-SLAM3和ORB-SLAM2一样都是使用纯视觉的方法进行初始化,再之后开始进行两个阶段的跟踪。第一阶段包括恒速模型跟踪、参考关键帧跟踪以及重定位跟踪,目的是为了跟得上,但估计出的位姿可能没有那么准确。第二阶段是局部地图跟踪,是利用PNP进行最小化重投影误差求解,得到更准确的位姿。最后决定是否新建关键帧。对于IMU信息,ORB-SLAM3还需要进行IMU预积分,但IMU三个阶段的初始化是在局部建图线程完成。此外,在恒速模型跟踪中,如果有IMU数据,恒速模型的速度将根据IMU信息得到。有IMU的话,还会有一个RECENT_LOST来记录刚刚丢失的状态。
VINS-Mono前端的输入为单目RGB图像和IMU数据。对于RGB信息,首先对图像应用金字塔LK光流检测算法,这里金字塔的使用不同于ORB-SLAM3那样进行不同分辨率的特征提取,而是避免跟踪陷入局部最优。之后进行特征点均匀化,VINS的特征点均匀化策略是以特征点为中心画圈,这个圆内不允许提取其他特征点,并使用逐次逼近去畸变。再之后使用OpenCV提供的光流跟踪状态位、图像边界、对极约束进行outlier的剔除。最终前端输出结果包含特征点像素坐标、去畸变归一化坐标、特征点ID以及特征点速度。对于IMU信息,VINS-Mono还需要计算IMU预积分。ORB-SLAM3和VINS的预积分都没有依赖GTSAM,都是自己实现的。
具体的优缺点上,ORB-SLAM3是对每一帧图像都提取Fast角点和BRIEF描述子,并进行描述子匹配。而BRIEF描述子的计算和匹配非常耗时。虽然ORB-SLAM3使用了SearchByBoW等策略加速匹配,但仍然需要较多的计算时间。相较之下,LK光流只需要提取每帧图像中跟丢的特征点,计算时间大大降低。不过ORB特征的全局一致性更好,在中期、长期数据关联上要优于光流法。我觉得VINS课程讲师的描述很贴切:“VINS更适合一条路跑到头进行定位建图,ORB-SLAM3更适合具有回环的轨迹”。
13.Ceres solver 怎么加残差的权重,这样做的原理是?---未看
残差加权重的话,需要在代价函数表达式里加入信息矩阵。但Ceres Solver中只接受最小二乘优化,也就是说代价函数定义(自动求导和数值求导是重载括号运算符bool operator(),解析求导是重载虚函数virtual bool Evaluate())里没办法直接写信息矩阵表达式。因此需要对信息矩阵进行Cholesky分解,把分解后的矩阵跟原来的残差乘到一起变为新的残差。
14.特征点法SLAM中,如何增强特征描述子之间的区分度?
这个问题是说如何更有效得将两个特征点区分开吗? ORB-SLAM2/3使用的是SearchByBoW进行匹配,虽然主要目的是为了加速匹配,但我感觉也可以更有效得区分描述子,毕竟就不用比较不同节点下的特征点了。 SearchByBoW的原理是匹配当前帧和关键帧在同一节点下的特征点。SearchByBoW利用了BoW中的FeatureVector,其内部也是一个哈希表。具体来说是首先取出属于同一Node的ORB特征点,遍历关键帧中属于该Node的特征点,特征点最小距离明显小于次小距离的作为成功匹配点。然后记录特征匹配成功后每个特征点对应的MapPoint,用于后续的PNP优化。最后通过角度投票进行剔除误匹配。
个人认为这题应该落脚于描述子的计算,特征点法就谈orbslam,所以脑海中可以把问题转换为“orb描述子如何保证区分度”:orb在常规brief描述子的基础上计算了特征点的方向,然后以方向作为描述子计算轴向,使得描述子具备了旋转不变性,以此增强了描述子间的区分度。 当然开放式问题也可以谈一些其他的改进/增强常规描述子的方法,应该都ok的。
15.在没有groundtruth情况下如何判断自己的置信度?
如果是室外环境的话,可以用谷歌地图,像VINS论文里在港科大校园里跑的那样。有雷达的话可以把雷达轨迹当作视觉的参考。然后就是找同类型的主流算法做对比了,跟主流算法轨迹差不多应该也能说明精度。
走一个回环到原地 看看误差
16.光流跟踪在快速运动过程中,跟踪容易失败,有什么解决办法?
硬件加持: 1,采用全局快门相机; 2,引入imu(解决相机过速退化的外部硬件首选)
算法加持: 1,加上光度标定(参考dso); 2,引入线性约束(参考直接法点线slam的工作,如edplvo) 3,参考svo直接法➕间接法模式。
1.加入imu,通过imu得到一个相对准确的位姿,这样光流法跟踪最小化光度误差的时候可以得到一个较好的像素点位置初值。
2.利用多层金字塔光流跟踪,先在分辨率小的金字塔层上进行光流跟踪得到在该层金字塔上的最优像素点坐标,然后恢复到下一层金字塔表示的像素点坐标,下一层金字塔以该像素点坐标为初值,在进行光流跟踪,以此类推,直到最底层金字塔
17.虚函数有什么作用,析构函数为什么定义为虚函数?
虚函数用来实现C++的多态,在父类对象成员函数前面加上virtual,然后在子类中重写这个函数,具体思想是在程序运行时用父类指针来执行子类对象中不同的函数。如果不使用虚函数,那么函数地址在编译阶段就已经确定,执行时还是调用的父类函数。使用虚函数后,函数地址是在运行阶段才确定的,这样执行时就可以调用子类函数。 析构函数不一定都要定义为虚函数,只有子类对象在堆区开辟了数据才需要。这是因为父类指针在释放时无法调用到子类的析构函数,造成内存泄漏。虚析构函数就是通过父类指针释放子类对象。
虚函数的作用是为了让父类指针(或引用)指向子类对象,从而实现C++三大特性之一的多态。 分析下原理:对于函数调用而言,就是通过函数地址找到函数代码块并执行,这就涉及到地址绑定的问题,通常地址绑定发生在编译阶段,称为早绑定(也叫编译时多态,可用于运算符重载、函数重载)。另一种情况就是使用虚函数时的晚绑定:编译器发现virtual关键字时,不绑定地址,而是为类创建一张虚函数表,并将函数地址放入表中,同时增加虚指针指向该表,子类继承父类后也会继承虚表和虚指针,并在表中放入自己的重写函数地址,此后,发生父类指针或引用指向子类对象,并进行函数调用时则会通过虚指针找到虚表中子类的函数入口地址,从而实现子类函数的调用(多态)。 总结多态发生的三大条件:继承、重写、父类指针或引用指向子类对象。
18.简述一下PnP原理,适用的场景是什么?
PnP是Perspective-n-Point的简称,利用已知的3D点坐标和对应图像中的2D像素坐标求解相机位姿。OpenCV已经实现了solvePnP()和solvePnPRansac(),后者利用了RANSAC的思想,更鲁棒更精确,但是更慢。单目VO中具体使用方法是,先用两张图像的匹配点利用对极几何计算E或者F矩阵,并恢复R和t,之后利用恢复出的位姿进行三角化得到3D点,最后使用PnP进行计算。双目和RGBD因为可以直接获得3D点,可以直接计算PnP。 求解PnP可以用直接线性变换DLT,P3P(实际上是将PnP问题转换成了ICP问题),EPnP等,但感觉用的更多的还是使用非线性优化的方法,构建最小化重投影误差,进行BA计算。
PnP(Perspective-n-Point)是求解 3D 到 2D 点对运动的方法。它描述了当我们知道n 个 3D 空间点以及它们的投影位置时,如何估计相机所在的位姿。两张图像中,其中一张特征点的 3D 位置已知,那么最少只需三个点对(需要至少一个额外点验证结果)就可以估计相机运动。特征点的 3D 位置可以由三角化,或者由 RGB-D 相机的深度图确定。因此,在双目或 RGB-D 的视觉里程计中,我们可以直接使用 PnP 估计相机运动。而在单目视觉里程计中,必须先进行初始化,然后才能使用 PnP。3D-2D 方法不需要使用对极约束,又可以在很少的匹配点中获得较好的运动估计,是最重要的一种姿态估计方法
19.Eigen中矩阵求逆,用了哪些数学上的技巧?
Eigen提供了直接求逆的方法inverse(),但是只针对小矩阵。求解大矩阵的话需要用一些数学分解算法,然后调用solve()函数。solve()函数其实是用来求解线性方程组ax=b,ab是系数矩阵,x是变量,b为单位阵时x为a的逆矩阵。具体的分解算法包括部分主元LU分解(对应Eigen中的PartialPivLU)、全主元LU分解(FullPivLU)、Householder QR分解(HouseholderQR)、列主元Householder QR分解(ColPivHouseholderQR)、全主元Householder QR分解(FullPivHouseholderQR)、完全正交分解COD(CompleteOrthogonalDecomposition)、标准Cholesky分解(LLT)、鲁棒Cholesky分解(LDLT)、双对角分治SVD分解(BDCSVD)、雅各比svd分解(JacobiSVD)。
20.卡尔曼滤波状态预测的协方差矩阵怎么计算?---未看
卡尔曼滤波状态预测的协方差矩阵,表示了状态量的间的相关性,对角线表示状态量的协方差 卡尔曼滤波预测过程中:该协方差矩阵和状态量的转移矩阵\Phi_{k,k+1},系统噪声的协方差矩阵有关。该过程状态量的协方差矩阵是个放大的过程; 卡尔曼滤波更新过程中:可以简写为(I-KH)P_{k+1,k},是一个协方差矩阵减小的过程。因为观测进来以后修正了状态量,从而协方差矩阵减小。控制住了原系统状态量误差的传播过程。 根据该协方差矩阵,一般可以判断滤波器是否收敛,过度收敛等情况,一般在滤波器中可以对该矩阵设置下限。 该协方差矩阵初始值设定中,对于可观性强的状态量,可以设置的较大;对于可观性不强的状态量,设置不宜过大,状态量初始值应该尽量准确; 可以强跟踪的卡尔曼滤波器,可以通过增加一个系数给该协方差矩阵,使得其变大,滤波器将基于观测更多的权重,从而实现短时强跟踪。
21.如何存储稀疏矩阵?
最简单的肯定就是直接存每个非零元素的坐标和值,一种思路是维护一个大的容器,每个位置存一个三元组放x坐标、y坐标、值,另一种思路是维护三个数组,分别存放x坐标、y坐标、值。或者干脆做个字典,键是tuple放坐标,值放矩阵值。在实际操作时要以行或者列排序,这样能更快得查找。 一种更有效的方式是使用压缩稀疏行格式Compressed Sparse Row(CSR),维护三个数组。首先传入数据,然后指定一个indices数组放每一行的非0元素的列位置,最后另外指定一个indptr数组放每一行的数据在indices中开始的位置。当然也可以使用压缩稀疏列格式Compressed Sparse Column(CSC),思路类似。
1. 三元组顺序表:将矩阵中各个非 0 元素的行标、列标和元素值以三元组的形式存储到一维数组中 2. 行逻辑链接的顺序表:存储矩阵的过程和三元组完全相同,多使用一个数组专门记录矩阵中每行第一个非 0 元素在一维数组中的位置,提高提取查找指定行非零元素的效率 3. 十字链表:采用的是 "链表+数组" 结构,矩阵中各行各列的元素都用一条链表存储,与此同时,将所有行链表的表头存储到一个数组(rhead),将所有列链表的表头存储到另一个数组(chead)中,便于插入和删除数据
22.简述如何在slam框架基础上添加语义分割网络?
最简单的思路就是做动态特征点剔除,在图像帧上使用YOLO等目标检测网络,或者使用SegNet等语义分割网络检测动态物体,对于候选区域就不再提取特征点了,然后进行运动一致性检查进一步提高检测精度。 这种方法高效、鲁棒。缺点主要有两个,一个是只能检测训练过的类别,对于未训练的运动目标无法检测。另一个是很难检测目前静止的潜在运动对象。
23.ORB-SLAM中的B是什么?ORB和FAST的区别?
B是指BRIEF描述子,ORB特征相当于FAST关键点+BRIEF描述子,并且orb-slam利用灰度质心法计算了旋转不变性,利用金字塔在不同分辨率图像上进行特征提取和匹配。
24.回环检测如何理解?请简述你熟悉的开源框架实现流程
SLAM运行过程中会产生轨迹漂移,回环检测就是当机器人回到以前运行过的场景时,利用约束将轨迹漂移拉回来。 ORBSLAM3的闭环线程流程时,首先检测缓冲队列中是否有新的关键帧进来,然后检测共同区域,如果检测到公共区域并且公共区域发生在当前地图和非活跃地图就执行地图合并,如果公共区域在当前地图内,就执行闭环。具体的公共区域检测流程也和ORBSLAM2不一样,ORB2是连续3个闭环候选关键帧组都检测到了回环关系才认为是回环,要检查时间连续性和几何连续性,延时较高,容易漏掉回环。而ORB3的重点是检查几何一致性,主要是说当前关键帧的5个共视关键帧只要有3个和候选关键帧组匹配成功,就认为检测到了共同区域,如果不够3个,再检查后续新进来关键帧的时间一致性,以略高的计算成本为代价,提高了召回率和精度。之后利用共视关系来调整位姿和地图点。
整个SLAM过程存在累积误差,回环检测是检测出机器人经过同一个地方,为后端提供更多有效数据,得到全局一致的估计。 VINS-Fusion的闭环检测首先对所有新老角点进行BRIEF描述,计算当前帧与词袋的相似度分数,进行闭环一致性检测,获得闭环的候选帧。当检测到闭环后,开启快速重定位,将之前帧的位姿和相关特征点作为视觉约束项,加到后端非线性优化的整体目标函数中,根据优化得到的相对位姿关系,对滑窗内所有帧进行调整。当从滑窗内滑出的帧与数据库中的帧为闭环帧时,则对数据库中的所有帧进行闭环优化。
25.说说多目相机的标定原理和主要流程
对于双目相机来说,首先要对左右目的两个相机进行单目标定,得到各自的内参矩阵和畸变系数。然后标定左右目相机之间的外参,当两个相机位于同一平面时,旋转矩阵可近似为单位阵,标定平移外参可得到基线长度b。 主要流程为:(1)准备一张棋盘格,粘贴于墙面,用直尺测量黑白方格的真实物理长度。(2)使用双目相机分别从不同角度拍摄得到一系列棋盘格图像。(3)进行左目相机标定,得到左目内参矩阵K1、左目畸变系数D1。(4)进行右目相机标定,得到右目内参矩阵K2、右目畸变系数D2。(5)将标定得到的参数K1、K2、D1、D2作为输入,再同时利用左右目对齐后的棋盘格图片,调用OpenCV的stereoCalibrate函数,输出左右目的旋转矩阵R、平移向量T。(6)基于标定得到的K1、K2、D1、D2、R、T进行双目视觉的图像校正。
非常详细,补充下,实际标定基本都是特制的棋盘格,自己贴墙面不平整,误差较大
双目相机标定需要先进行两个单目相机的标定,计算出单个相机的内参矩阵和畸变参数,然后进行双目标定,计算相机之间的R,t,为提高标定效果,一般讲两个相机摆放在同一平面。最后为了提高匹配速度,根据第一步获取的相机参数来对双目成像进行校正
26.C++中智能指针相比普通指针的优势和劣势?
普通指针如果delete不当会造成内存泄露或者生成野指针,而智能指针实际上是对指针加了一层封装机制,使得它可以方便的管理对象的生命周期。在智能指针中,一个对象什么时候被析构是受智能指针本身决定的,用户不需要进行管理。 C++有四种智能指针,auto_ptr,unique_ptr,shared_ptr,weak_ptr。其中unique_ptr在C++11中新增了move语义,实现内存所有权的传递,Cartographer用了很多这方面的技巧。
优:自动内存管理,当指针不再使用时,它指向的内存被释放。shared_ptr采用计数方式进行管理,每次构造和拷贝的时候计数器+1,析构的时候减1,最会为0时才会真正析构。 缺:主要是计数器的性能损耗和循环引用,即两个对象分别使用shared_ptr成员去指向对方,会计数失败,无法释放,此时可以使用weak_ptr去解决。
27.无序map和有序map的查找复杂度
无序用的hash表,O(1)~O(n) 有序用的二叉排序树,O(logn)
28.用自己的语言描述下预积分原理和过程---未看
IMU可以获得每一时刻的加速度和角速度,通过积分就可以得到两帧之间的由IMU测出的位移和旋转。但IMU的频率远高于相机,在基于优化的VIO算法中,当被估计的状态量不断调整时,每次调整都需要在它们之间重新积分,传递IMU测量值,这个过程会导致计算量的爆炸式增长。因此提出了IMU预积分,希望对IMU的相对测量进行处理,使它与绝对位姿解耦,或者只要线性运算就可以进行矫正,从而避免绝对位姿被优化时进行重复积分。 ORB-SLAM3没有依赖GTSAM库,整个预积分的过程都是自己实现的。具体思路为:(1)由积分引出预积分,得到旋转、速度、位置的预积分表达式,重点是消除第i时刻对积分的影响并保留重力。(2)噪声分离,推导出标定好的imu噪声对预积分的影响。(3)噪声递推,之前的推导结果要么是求和,要么是多积导致每次新来一个数据都需要从头计算,这给计算平台来带来资源的浪费,因此要推出误差的递推形式。还需要计算协方差矩阵(4)由于偏置在VIO算法中会作为状态量来优化,因此要推出当偏置变化时直接求得新的预积分结果。(5)定义残差对于旋转、速度、位置的残差。
29.光流法和直接法的区别
光流法和直接法都是基于灰度不变假设。光流法提取关键点后,根据灰度不变假设得到关于像素点速度的欠定方程,之后通过对极约束、PNP、ICP计算R、t。但光流法只是一个粗略匹配,很容易陷入局部极值(VINS使用金字塔来改善),直接法相当于在光流基础上对前面估计的相机位姿进一步优化,即将下一帧位置假设为1/z*K(RP+t),之后利用光度误差来优化R、t。 光流法和直接法根据提取关键点数量可分为稀疏、半稠密、稠密。相较于特征点法来说,提取速度很快,但要求相机运动较慢,或者采样频率较高,对光照变化也不够鲁棒。
光流法:通过寻找特征点,不进行描述子匹配,根据灰度不变性得出像素运动,然后跟踪特征点,然后根据匹配关系求解RT。 直接法:寻找关键点或者随机点,同样不进行描述子匹配,根据相机运动初值,建立最小光度误差求解RT。
30.多传感器如何做时间同步(Lidar,IMU,GPS,Odom)
主要是进行硬同步和软同步。软同步是利用时间戳进行不同传感器的匹配,将各传感器数据统一到某个基准上,可以借助ROS::message_filter实现。硬同步可以借助PTP协议。
31. 线性方程组 Ax=b 的求解方法以及优缺点(LU,QR,SVD等)
LU方法:矩阵A分解成上下三角阵L和U。需要矩阵A可逆,结果的准确性依赖于A的数值形式。 QR方法:矩阵A分解成正交阵Q和上三角阵R的乘积。QR方法数值稳定,计算时间复杂度高。 SVD方法:m*n矩阵A分成U,Σ,V三个较小的矩阵组合的形式。U为m*m正交矩阵,Σ为对角阵,对角元素为奇异值,V为n*n正交矩阵。则可计算出A的伪逆B 。SVD是最小二乘求解线性方程组最可靠的分解法,但计算代价很大。
32.Rp怎么对R求导(R是SO3,p是三维点)
利用扰动模型,对李群乘以微小扰动,然后对扰动求导
33.算法题:怎么求二叉树的宽度
BFS:记录节点的 position 信息,对于每一个深度,第一个遇到的节点是最左边的节点,最后一个到达的节点是最右边的节点。记录最大值即可。 DFS:记录节点的 position 信息,对于每一个深度,将第一个到达的位置记录在 left[depth] 中,然后对于每一个节点,它对应这一层的可能宽度是 pos - left[depth] + 1 。将每一层这些可能的宽度取最大值即可。
34.谈一谈你对边缘化的理解和它的意义
SLAM属于渐进式算法,需要使用一定数目的关键帧进行BA运算以求得位姿和地图点。但随着关键帧数目的增多,滑窗(或者说ORB-SLAM3的共视图)的计算量会越来越大。因此需要想办法去掉老的关键帧,来给新关键帧腾地方。直接做法是把最老帧以及相关地图点直接丢弃,但最老帧可能包含了很强的共视关系,直接删除可能会导致BA效果变差。 而边缘化就是指,既从滑窗/共视图里剔除了老的关键帧,又能保留这个关键帧的约束效果,其核心算法是舒尔补。总体来说,就是本身要被扔掉的最老帧,他可能和后面的帧有约束关系(一起看到某个地图点,和下一帧之间 有IMU约束等),扔掉这个第0帧的数据的话,这些约束信息需要被保留下来。相当于建立起地图点和地图点之间的约束关系。
在常规视觉/激光里程计计算过程中,仅需要两帧矩阵就可以用优化模型计算出里程计信息,而优化所得结果只是一个近似逼近的优值,从而每次两帧计算后都会累积一定程度的误差,为了避免误差累积,最好的方法是做一次全局优化,但每一帧都来一次全局优化实时性就无法保证,因此,引入了滑动窗口,将优化范围限制在距当前帧的固定间隔内。所以窗口中必然存在插入新帧和删除旧帧的操作,以控制这个固定优化范围,其中删除旧帧的操作就叫边缘化。 Tips更新:边缘化时舒尔补操作后得到先验约束,直接用先验约束参与后续优化时,会导致留下的状态变量由不可观变为可观,需要用FEJ方法进行避免。
35.剔除离群点有哪些方法?
1、只对多个图像帧都观测到的点进行BA运算,观测太少的点就不参与优化了
2、ORB-SLAM2/3中对于深度超过40倍基线的点,由于估计的平移分量非常不准,因此认为是外点,剔除
3、在重投影计算时,如果投影误差超过一定阈值,则不让这个点参与优化,ORB-SLAM2/3是通过卡方检验实现
4、VINS-Fusion将追踪到的光流再反向追踪回来,然后比较追踪回来的特征点与原先的特征点之间的距离,过大就认为是外点去掉
5、VINS-Mono中通过opencv的findFundamentalMat函数自带的ransac来消除外点
6、鲁棒核函数
泡椒同学答得很棒!稍微补充:orbslam中还用了旋转直方图剔除错误特征匹配点对. 抛开slam场景只看数据的话有多种离群点判断方法,介绍适用低维数据的3个简单:
1.MAD(median absolute deviation)算法: 即绝对中位值偏差,其大致思想是通过判断每一个元素与中位值的偏差是否处于合理的范围内来判断该元素是否为离群值.
2.标准差法-3σ法: 因标准差本身可以体现数据的离散程度,和MAD算法类似,只是标准差法用到的不是中位值,而是均值,并且离群阈值为3σ,即|x_out - x_mean| > 3σ.
3.百分位法: 百分位算法类似于比赛中"去掉几个最高分,去掉几个最低分"的做法,基本步骤如下: 1)将数据值进行排序,一般用升序排序,这里排序函数可自定义;2)去掉排位百分位高于90%或排位百分位低于10%的数据值.
36.SLAM后端不收敛怎么办?
个人认为分两种情况:
(1)第一次进入后端优化就不收敛,这时候就应该分析优化变量和约束条件的理论和code是否正确;
(2)前面优化收敛,突然当前优化不收敛,这时候需要判断下是否加入了错误的回环约束:删除回环约束,重新本次优化,如果OK,则应该是回环错误。
补充下第一次进入后端优化不收敛的思路:1.迭代次数不够,增加迭代次数。 2. 优化方法的问题:使用高斯牛顿法时,可能出现JJT(H的近似)为奇异矩阵或者病态的情况,此时增量稳定性较差,导致算法不收敛。(残差函数在局部不像一个二次函数,泰勒展开不是很准确),导致算法不收敛。而且当步长较大时,也无法保证收敛性改进更换增量方程的求解方法,如果使用的是高斯牛顿法,可尝试使用LM法算法。
37.在机器人仅定位阶段,如果实际地图与加载地图发生较大差异,应该如何处理?
其实也就是说,机器人预先建好的地图,在实际定位过程中变化了怎么办。这个情况还是挺常见的,尤其是扫地机器人(毕竟麦岩就是做这个的),比如家里的桌子移动了位置,物品摆放和建图时不一样了。 我当时的回答是,先说了一下ORB-SLAM3的三种跟踪模式和跟踪失败的条件,当跟踪失败时就再开辟一个地图,利用ORB3的多地图系统来重新定位,当检测到回环时再进行地图融合,这样更新预先建好的地图。 面试官的意思是,可以在预先建立地图时就给每个物体施加不同的权重,比如柱子大概率不会移动,就加个很大的权重,椅子是很可能移动的,就加个小的权重,在地图更新时要有所侧重。 其实这个问题也就是LifeLong问题吧,现在也是一个很火的研究方向,甚至有的SLAM还可以感知季节的变化。。。
38.谈谈你对协方差矩阵的认识?
SLAM中协方差矩阵表达了对状态估计的不确定程度,也就是说在多传感器融合过程中我们认为哪个传感器估计的状态更准,就给哪个估计施加更大的权重。比如VINS-Mono中,引用沈邵劼老师的话就是“IMU和视觉信息融合也可以粗暴的叫做加权平均,那么加权就是每个测量值对应的协方差矩阵”。 另一方面来说,在进行图优化时,误差是要分摊给每一条边的。那么每条边应该分摊多少呢?显然均摊是不合适的,因为有的观测可能很准。这时候协方差矩阵就确定了应该给每条边分摊多少。
我们一般用"矩"来描述数据的分布特性,其中一阶矩表示均值,二阶矩代表协方差,三阶矩代表偏度,四阶矩代表峰度. 对于二阶矩协方差,描述了样本数据偏离均值的统计情况,越大则代表数据偏离程度越高,即数据越不稳定.因此考虑slam的状态变量时,状态的协方差也就代表了当前状态估计正确程度.
39.LEGO-LOAM中划分出地面点与非地面点的目的是什么?
首先一点共识就是lego-loam适用于平坦路面,因此其划分路面点和非路面点是算法对平坦路面的特殊处理: (1)在平坦路面,划分所得路面点具有更好的面特征信息,可以更好地提供点-面残差约束; (2)在计算Lidar Odometry时分为了两步,第一步先用点-面残差计算初始[t_z,t_roll,t_pitch],然后第二步基于第一步基础上计算[t_x, t_y, t_yaw],这样可以提升计算效率。而可以这样计算的原因是因为地面信息在相邻帧间变化不大,因此可以优先用于计算竖直维度相关量,然后再在其基础上计算水平维度变化量。
地面点与非地面点特征较为不同,特质提取时可以分为不同的特征点集,然后做特征匹配时,可以先匹配地面特征,得到状态估计,再以此为基础进行非地面点的边缘特征匹配,可以加快特征匹配过程
40.LeGO-LOAM怎么判断找到的最近5个点是不是线特征?
在构建点-线残差之前,Lego-LOAM已经进行了特征提取操作,将属于边缘点的点云加至Fme,将属于平面点的点云加至Fmp,因此找最近点构建点线残差时,只需判断找到的点是否是Fme中的点即可。
虽然是从直线特征集中选择的5个点,为了准确性,代码中加了一步判定。具体方法味: 1、计算这5个点的协方差矩阵 2、进行SVD分解求其特征值和特征向量 3、根据特征值是否存在一个明显大于另外两个的来判断是否为直线