读书笔记:视觉里程计1
之前的内容,介绍了运动方程和观测方程的具体形式,并讲解了以非线性优化为主的求解方法。从本讲开始,我们结束了基础知识的铺垫,开始步入正题:按照第二讲的内容,分别介绍视觉里程计、优化后端、回环检测和地图构建四个模块。本讲和下一讲主要介绍作为视觉里程计的主要理论,然后在第九章中进行一次实践。本讲关注基于特征点方式的视觉里程计算法。我们将介绍什么是特征点,如何提取和匹配特征点,以及如何根据配对的特征点估计相机运动。
特征点法
- 经典SLAM模型中以位姿——路标(Landmark)来描述SLAM过程
- 路标是三维空间中固定不变的点,能够在特定位姿下观测到
- 数量充足,以实现良好的定位
- 较好的区分性,以实现数据关联
- 在视觉SLAM中,可利用图像特征点作为SLAM中的路标
2D-2D: 对极几何
特征匹配之后,得到了特征点之间的对应关系:
- 如果只有两个单目图像,得到2D-2D间的关系 ——对极几何
- 如果匹配的是帧和地图,得到3D-2D间的关系 ——PnP
- 如果匹配的是RGB-D图,得到3D-3D间的关系 ——ICP
八点法的讨论: - 尺度不确定性:归一化 t 或特征点的平均深度
- 纯旋转问题:t=0 时无法求解
- 多于八对点时:最小二乘
- 有外点时:RANSAC
小结:
- 2D-2D情况下,只知道图像坐标之间的对应关系
- 当特征点在平面上时(例如俯视或仰视),使用H恢复R,t
- 否则,使用E或F恢复R,t
- t 没有尺度
- 求得R,t后:
- 利用三角化计算特征点的3D位置(即深度)
- 实际中用于单目SLAM的初始化部分
3D-2D PnP
3D-2D ICP
三角化与深度估计
小结:
本节介绍了基于特征点的视觉里程计中的几个重要的问题。包括:
- 特征点是如何提取并匹配的;
- 如何通过2D-2D 的特征点估计相机运动;
- 如何从2D-2D 的匹配估计一个点的空间位置;
- 3D-2D 的PnP 问题,它的线性解法和Bundle Adjustment 解法;
- 3D-3D 的ICP 问题,其线性解法和Bundle Adjustment 解法。
实践部分
orb_cv:
和之前几章一样,导入相应的图片参数后运行代码即可:
/home/wh/shenlan/slambook2/ch7/cmake-build-debug/orb_cv /home/wh/shenlan/slambook2/ch7/1.png /home/wh/shenlan/slambook2/ch7/2.png
extract ORB cost = 0.222814 seconds.
match ORB cost = 0.000989399 seconds.
-- Max dist : 95.000000
-- Min dist : 7.000000
orb_self:
需要注意一下配置文件(通过之前的各种错误调试,对这个已经驾轻就熟了(逃 ):
运行后结果为:
/home/wh/shenlan/slambook2/ch7/cmake-build-debug/orb_self /home/wh/shenlan/slambook2/ch7/1.png /home/wh/shenlan/slambook2/ch7/2.png
bad/total: 43/638
bad/total: 8/595
extract ORB cost = 0.00240357 seconds.
match ORB cost = 0.000984295 seconds.
matches: 51
可见,这个程序中,ORB的提取只要2.4毫秒,匹配只需要0.98毫秒。提升效果还是很明显的。
pose_estimation_2d2d:
导入正确的图片位置参数即可,运行结果如下:
/home/wh/shenlan/slambook2/ch7/cmake-build-debug/pose_estimation_2d2d /home/wh/shenlan/slambook2/ch7/1.png /home/wh/shenlan/slambook2/ch7/2.png
-- Max dist : 95.000000
-- Min dist : 7.000000
一共找到了81组匹配点
fundamental_matrix is
[5.435453065896191e-06, 0.0001366043242983499, -0.02140890086929781;
-0.0001321142229818118, 2.339475702766975e-05, -0.006332906454914053;
0.02107630352186664, -0.003666833952417687, 1]
essential_matrix is
[0.007841371796261635, 0.2075176016541406, 0.1181719698273573;
-0.190270235105878, 0.03346203071185214, -0.6710910536624433;
-0.07512093110340777, 0.6702181417805779, 0.0197271235906156]
homography_matrix is
[0.9131751791765326, -0.1092435315745437, 29.95860009812312;
0.02223560352253669, 0.9826008005030865, 6.50891083922104;
-0.000100156038109612, 0.0001037779436268401, 1]
R is
[0.9980704024700457, -0.05457644989749674, 0.02961220744670522;
0.05354481493884546, 0.9979665375218761, 0.03457951387400768;
-0.03143921924039243, -0.03292720916178488, 0.9989631496658776]
t is
[-0.9411804751897357;
-0.1569351957186449;
0.2992501586739325]
t^R=
[-0.01108937434188349, -0.293474206690423, -0.1671204024221927;
0.2690827470026501, -0.04732245765724633, 0.9490660696766777;
0.1062370395845343, -0.947831585854587, -0.02789836572845881]
epipolar constraint = [-0.001315242027480734]
epipolar constraint = [-0.001578304298745531]
epipolar constraint = [-0.001188503296648852]
epipolar constraint = [0.000231454910588208]
epipolar constraint = [5.920836904108051e-06]
epipolar constraint = [-0.001906135302240319]
epipolar constraint = [0.001046084386893034]
epipolar constraint = [0.0009795765878930773]
epipolar constraint = [-0.0003239362890374575]
epipolar constraint = [-0.0004425996166594337]
epipolar constraint = [-0.0002057979682931685]
epipolar constraint = [0.00309757027701868]
epipolar constraint = [0.0001543220573124587]
epipolar constraint = [0.0001057558186303362]
epipolar constraint = [0.000982938500707721]
epipolar constraint = [-0.002056665209698355]
epipolar constraint = [0.0004537706540336806]
epipolar constraint = [0.001610332400382775]
epipolar constraint = [0.001161827219661932]
epipolar constraint = [-0.0004870771555920278]
epipolar constraint = [-0.0003993608476327987]
epipolar constraint = [-0.0003329559615270622]
epipolar constraint = [-0.00088382778902861]
epipolar constraint = [-1.498645374714558e-06]
epipolar constraint = [-0.001155951594946386]
epipolar constraint = [8.048799454629663e-05]
epipolar constraint = [0.003038437011066118]
epipolar constraint = [0.000451686407563056]
epipolar constraint = [-0.003277609434146483]
epipolar constraint = [-0.002934131424439268]
epipolar constraint = [-0.002222657513295145]
epipolar constraint = [-0.0003868024848980439]
epipolar constraint = [0.001072081248433387]
epipolar constraint = [-0.00169765798540511]
epipolar constraint = [-0.0008204712266620118]
epipolar constraint = [-0.001972687615056333]
epipolar constraint = [-2.826712818398969e-06]
epipolar constraint = [-0.002258727831157652]
epipolar constraint = [-0.0008702667711562029]
epipolar constraint = [-0.001218580809426037]
epipolar constraint = [-0.002336988149393177]
epipolar constraint = [-0.0006575502558372748]
epipolar constraint = [-0.0009060475158950698]
epipolar constraint = [-0.00189436480620922]
epipolar constraint = [0.001421118364198753]
epipolar constraint = [-0.0005509673654771341]
epipolar constraint = [0.000158827601014766]
epipolar constraint = [0.001285228314665821]
epipolar constraint = [-0.001026421195603887]
epipolar constraint = [0.0004643210164508079]
epipolar constraint = [-0.00222923849676292]
epipolar constraint = [0.001290700262098514]
epipolar constraint = [-0.0031103750939852]
epipolar constraint = [-0.0003932780062060742]
epipolar constraint = [-0.001152506568867138]
epipolar constraint = [-0.003034220911886543]
epipolar constraint = [-4.828133382105138e-05]
epipolar constraint = [-0.0001527852492553428]
epipolar constraint = [0.002588301606486126]
epipolar constraint = [0.001890010099941455]
epipolar constraint = [-0.001642417783651661]
epipolar constraint = [0.001930624231954135]
epipolar constraint = [0.002246487616943293]
epipolar constraint = [-0.001477228764549884]
epipolar constraint = [-0.004235795643742005]
epipolar constraint = [2.228958490314847e-06]
epipolar constraint = [-0.0009659228457190305]
epipolar constraint = [-0.003072669318699595]
epipolar constraint = [-0.003622364122535623]
epipolar constraint = [1.938973302750835e-06]
epipolar constraint = [-0.0006807313116127256]
epipolar constraint = [-0.003286467983308061]
epipolar constraint = [-0.0004361159025121769]
epipolar constraint = [-0.001366953017694232]
epipolar constraint = [0.005797813009221719]
epipolar constraint = [-0.001973336987100609]
epipolar constraint = [0.005029711184354425]
epipolar constraint = [0.0008215996290642322]
epipolar constraint = [-0.0007730408705936692]
epipolar constraint = [-0.001487168895993207]
epipolar constraint = [-0.005774275635465974]
Process finished with exit code 0
triangulation :
结果如下:
/home/wh/shenlan/slambook2/ch7/cmake-build-debug/triangulation /home/wh/shenlan/slambook2/ch7/1.png /home/wh/shenlan/slambook2/ch7/2.png
-- Max dist : 95.000000
-- Min dist : 7.000000
一共找到了81组匹配点
depth: 25.6005
depth: 14.2517
depth: 13.2127
depth: 12.4369
depth: 12.9603
depth: 19.9448
depth: 13.4837
depth: 13.0071
depth: 11.3976
depth: 11.7005
depth: 14.4569
depth: 14.2757
depth: 12.5237
depth: 12.1336
depth: 14.7006
depth: 19.111
depth: 27.3023
depth: 27.9239
depth: 13.1105
depth: 11.9614
depth: 12.8352
depth: 14.1183
depth: 11.9569
depth: 20.0006
depth: 13.2497
depth: 12.6386
depth: 14.7556
depth: 10.8357
depth: 11.6692
depth: 19.0431
depth: 19.0221
depth: 12.8111
depth: 13.9456
depth: 12.4831
depth: 13.2798
depth: 11.562
depth: 11.6092
depth: 11.486
depth: 25.5423
depth: 12.5049
depth: 19.2999
depth: 19.4775
depth: 26.0318
depth: 13.1139
depth: 13.6773
depth: 14.3747
depth: 12.6378
depth: 13.9104
depth: 13.8709
depth: 15.9466
depth: 14.8439
depth: 14.9515
depth: 13.1652
depth: 13.0997
depth: 14.0257
depth: 19.7209
depth: 12.8506
depth: 15.3617
depth: 13.299
depth: 13.947
depth: 15.0744
depth: 15.0309
depth: 10.2287
depth: 14.5318
depth: 11.9676
depth: 13.8962
depth: 17.5034
depth: 9.59917
depth: 13.6066
depth: 9.43376
depth: 9.27307
depth: 13.9897
depth: 12.7457
depth: 15.2451
depth: 15.005
depth: 14.6806
depth: 15.4565
depth: 13.9786
depth: 12.5546
depth: 10.4952
depth: 14.1119
pose_estimation_3d2d :
需要注意的是图片的配置顺序为:1.png 2.png 1_depth.png 2_depth.png ,运行结果如下:
/home/wh/shenlan/slambook2/ch7/cmake-build-debug/pose_estimation_3d2d /home/wh/shenlan/slambook2/ch7/1.png /home/wh/shenlan/slambook2/ch7/2.png /home/wh/shenlan/slambook2/ch7/1_depth.png /home/wh/shenlan/slambook2/ch7/2_depth.png
-- Max dist : 95.000000
-- Min dist : 7.000000
一共找到了81组匹配点
3d-2d pairs: 77
solve pnp in opencv cost time: 0.000360876 seconds.
R=
[0.9979193252225095, -0.05138618904650331, 0.03894200717385427;
0.05033852907733771, 0.9983556574295407, 0.02742286944795591;
-0.0402871299273294, -0.0254055280147182, 0.998865109165653]
t=
[-0.1255867099750184;
-0.007363525258815302;
0.06099926588678119]
calling bundle adjustment by gauss newton
iteration 0 cost=644765.3537799
iteration 1 cost=12727.290187745
iteration 2 cost=12319.869976045
iteration 3 cost=12319.609322181
iteration 4 cost=12319.608618764
pose by g-n:
0.997919445787 -0.0514022442838 0.0389177209255 -0.125572632451
0.050357937298 0.998356535388 0.0273551896056 -0.00725277456688
-0.040259879167 -0.0253384595005 0.998867911488 0.0612840241886
0 0 0 1
solve pnp by gauss newton cost time: 8.7966e-05 seconds.
calling bundle adjustment by g2o
iteration= 0 chi2= 431.695367 time= 1.9896e-05 cumTime= 1.9896e-05 edges= 77 schur= 0
iteration= 1 chi2= 319.560037 time= 1.0547e-05 cumTime= 3.0443e-05 edges= 77 schur= 0
iteration= 2 chi2= 319.558868 time= 9.708e-06 cumTime= 4.0151e-05 edges= 77 schur= 0
iteration= 3 chi2= 319.558868 time= 9.691e-06 cumTime= 4.9842e-05 edges= 77 schur= 0
iteration= 4 chi2= 319.558868 time= 9.48e-06 cumTime= 5.9322e-05 edges= 77 schur= 0
iteration= 5 chi2= 319.558868 time= 9.459e-06 cumTime= 6.8781e-05 edges= 77 schur= 0
iteration= 6 chi2= 319.558868 time= 9.428e-06 cumTime= 7.8209e-05 edges= 77 schur= 0
iteration= 7 chi2= 319.558868 time= 9.576e-06 cumTime= 8.7785e-05 edges= 77 schur= 0
iteration= 8 chi2= 319.558868 time= 9.407e-06 cumTime= 9.7192e-05 edges= 77 schur= 0
iteration= 9 chi2= 319.558868 time= 9.396e-06 cumTime= 0.000106588 edges= 77 schur= 0
optimization costs time: 0.000335117 seconds.
pose estimated by g2o =
0.997919325223 -0.0513861890471 0.0389420071732 -0.125586709974
0.0503385290779 0.998355657429 0.0274228694493 -0.007363525261
-0.0402871299268 -0.0254055280161 0.998865109166 0.0609992658862
0 0 0 1
solve pnp by g2o cost time: 0.000436081 seconds.
Process finished with exit code 0
pose_estimation_3d3d:
依然按照上一部分的顺序配置好图片,运行结果为:
/home/wh/shenlan/slambook2/ch7/cmake-build-debug/pose_estimation_3d3d /home/wh/shenlan/slambook2/ch7/1.png /home/wh/shenlan/slambook2/ch7/2.png /home/wh/shenlan/slambook2/ch7/1_depth.png /home/wh/shenlan/slambook2/ch7/2_depth.png
-- Max dist : 95.000000
-- Min dist : 7.000000
一共找到了81组匹配点
3d-3d pairs: 75
W= 11.8688 -0.717698 1.89486
-1.88065 3.83391 -5.78219
3.25846 -5.82734 9.65267
U= 0.592295 -0.805658 -0.0101195
-0.418171 -0.318113 0.850845
0.688709 0.499719 0.525319
V= 0.64736 -0.761401 -0.0345329
-0.388765 -0.368829 0.844291
0.655581 0.533135 0.534772
ICP via SVD results:
R = [0.9972065648712517, 0.0583427326421373, -0.04663895931006082;
-0.0578774537434991, 0.9982601222918898, 0.0112662589154357;
0.04721511755620851, -0.008535443141899036, 0.9988482762084164]
t = [0.1379879639364656;
-0.06551699902642298;
-0.02981649372255757]
R_inv = [0.9972065648712517, -0.0578774537434991, 0.04721511755620851;
0.0583427326421373, 0.9982601222918898, -0.008535443141899036;
-0.04663895931006082, 0.0112662589154357, 0.9988482762084164]
t_inv = [-0.1399866713350012;
0.05709791558567686;
0.03695589986706069]
calling bundle adjustment
iteration= 0 chi2= 1.815772 time= 2.6893e-05 cumTime= 2.6893e-05 edges= 75 schur= 0 lambda= 0.000787 levenbergIter= 1
iteration= 1 chi2= 1.815193 time= 1.3267e-05 cumTime= 4.016e-05 edges= 75 schur= 0 lambda= 0.000524 levenbergIter= 1
iteration= 2 chi2= 1.815193 time= 1.202e-05 cumTime= 5.218e-05 edges= 75 schur= 0 lambda= 0.000350 levenbergIter= 1
iteration= 3 chi2= 1.815193 time= 1.1902e-05 cumTime= 6.4082e-05 edges= 75 schur= 0 lambda= 0.000233 levenbergIter= 1
iteration= 4 chi2= 1.815193 time= 1.1803e-05 cumTime= 7.5885e-05 edges= 75 schur= 0 lambda= 0.000155 levenbergIter= 1
iteration= 5 chi2= 1.815193 time= 1.1795e-05 cumTime= 8.768e-05 edges= 75 schur= 0 lambda= 0.000104 levenbergIter= 1
iteration= 6 chi2= 1.815193 time= 2.2467e-05 cumTime= 0.000110147 edges= 75 schur= 0 lambda= 0.070714 levenbergIter= 5
iteration= 7 chi2= 1.815193 time= 1.1726e-05 cumTime= 0.000121873 edges= 75 schur= 0 lambda= 0.047143 levenbergIter= 1
iteration= 8 chi2= 1.815193 time= 4.85e-05 cumTime= 0.000170373 edges= 75 schur= 0 lambda= 12654823.401608 levenbergIter= 7
optimization costs time: 0.000437763 seconds.
after optimization:
T=
0.997207 0.0583427 -0.046639 0.137988
-0.0578775 0.99826 0.0112663 -0.065517
0.0472151 -0.00853546 0.998848 -0.0298169
0 0 0 1
课后习题
1. 除了本书介绍的ORB 特征点外,你还能找到哪些其他的特征点?请说说SIFT 或SURF 的原理,对比它们与ORB 之间的优劣。
除了ORB之外,一般还有还有SIFT、SURF、BRISK、AKAZE,这些都是在OpenCV中已经实现了的。
SIFT算法,又称为尺度不变特征转换(Scale-invariant feature transform),大致方法是首先搜索所有尺度下图像的位置,通过高斯微分函数来识别潜在的对于尺度和旋转不变的兴趣点,然后在候选位置通过拟合精细的模型来确定位置和尺度,再基于图像梯度,分配给关键点一个或多个方向,最后在每个关键点的周围邻域,在选定的尺度下测量图像局部梯度来描述关键点。使用斑点检测方法和浮点型特征描述子,在建立高斯差分空间金字塔的基础上提取初具有尺度不变性的特征点,然后对特征点邻域内的点的梯度方向进行直方图统计。特征点的主方向就是直方图中比重最大的方向,必要时可选一个辅方向。SIFT特征集旋转不变性,尺度不变性,对图像变形和光照鲁棒鲁等优点于一身,不足之处是计算量大,计算速度慢,需要GPU加速才可满足实时性需求。
SURF算法,又称为加速稳健特征(Speeded Up Robust Features),其方法和构建图像金字塔的方法相反,其主要方法是通过修改滤波器的尺寸和模糊度从而得到不同层级的影像,但是寻找特征点的方法和SIFT类似。使用基于DoH的斑点特征检测方法,在特征点的描述上,SURF算法通过积分图,利用两个方向上的Harr小波模型进行梯度计算,然后对邻域内点的梯度方向以扇形的方式进行统计,得到特征点的主方向。其算法速度快且稳定性好。
SIFT和SURF能够比较稳定地提供较高的准确率,其中SIFT比SURF跟准确一点,但是二者都特别慢。相较而言ORB速度更快,但是更容易出现问题,而且错误率远比其他二者大。
计算速度: ORB>>SURF>>SIFT(各差一个量级)
旋转鲁棒性: SURF>ORB~SIFT(表示差不多)
模糊鲁棒性: SURF>ORB~SIFT
尺度变换鲁棒性: SURF>SIFT>ORB(ORB并不具备尺度变换性)
综上所述,如果对计算实时性要求非常高,可选用ORB算法,但基本要保证正对拍摄;如果对实行性要求稍高,可以选择SURF;基本不用SIFT
2. 设计程序,调用OpenCV 中的其他种类特征点。统计在提取1000 个特征点时,在你的机器上所用的时间。
参考
自己做的待填坑
3. * 我们发现OpenCV 提供的ORB 特征点,在图像当中分布不够均匀。你是否能够找到或提出让特征点分布更加均匀的方法?
用熵来度量局部信息量大小,将图像分为若干网格,计算每个网格图像的熵,在熵较大的区域内提取特征点。若局部依旧集中可再次划分网格,在没有特征的网格中,强行提取一个兴趣值最大的特征点。
2016年出的ORB_SLAM2中已经用四叉树实现的特征点均匀分布算法。四叉树均匀划分的方法跟经典ORB算法变化不大,一般还是:1.构建图像金字塔;2.将每层图像划分网格,FAST算法提取特征点;3.对网格内的特征点进行评估,选取质量最好的留下作为代表关键点;4.用强度质心法计算每个关键点的方向;5对金字塔图层进行高斯滤波;6.使用BRIEF计算各个关键点的描述子(包含论文中的启发式搜索算法得到的256对匹配对坐标进行优化);7.保留关键点和描述子。
4. 研究FLANN 为何能够快速处理匹配问题。除了FLANN 之外,还能哪些可以加速匹配的手段?
FLANN的全称为Fast Library for Approximate Nearest Neighbors。它是一个对大数据集和高维特征进行最近邻近的算法的集合。在面对大数据集时它的性能要好于BFMatcher。匹配问题实际上就是一个特征向量求相似度问题。对于最简单的办法,就是逐个匹配对计算距离。明显这种遍历的方式是效率极低的,对于大数据情况下不适用。因此经典kd-tree的搜索回溯的搜索办法在这里派上了用场,减少了不必要的计算过程,提高了效率,但是对于多维数据而言,其效果往往不升反降。在经典kd-tree算法上提出了随机kd-tree算法,随即选出方差较大的维度,建立kd-tree,再进行搜索回溯。还有一种分级k-means tree,与之前不同的是先通过k-means算法(之后回环检测时会用到)来进行先数据聚类,然后再进行kd-tree的建立。这些方法相交于传统的直接匹配法优势都比较大。有关k-d tree
加速匹配的方法:预排序图像检索;GPU加速,可以使得匹配速度提高十多倍;再后来就是用FPGA加速,其匹配速度能提升10倍;再后来的VF-SIFT(very fast SIFT)算法,其核心思想是从SIFT特征中提取4个特征角,根据特征角区间的不同,避免了大量不必要的搜索,这样据说是普通搜索的1250倍。
5. 把演示程序使用的EPnP 改成其他PnP 方法,并研究它们的工作原理。
目前除了EPnP外,OpenCV还提供了另外两种方法:迭代法和P3P法,其中,在OpenCV3中还另外提供了DLS法和UPnP法。
EPnP(Efficient PnP)的思路是将空间中的任意3D点可以用4个不共面的3D点加权表示,然后通过n个3D点在相机平面的投影关系以及四个控制点的权重关系构建一个的矩阵,求这个矩阵的特征向量,就可以得到这个相机平面的坐标,再用POSIT正交投影变换算法得到相机位姿。迭代法实质是迭代求出重投影误差的最小解先用DLT直接线性变换求解,然后用LM算法进行优化,这个解显然不是正解,而且这个方法只能使用4个共面特征点才能求得。
P3P法,它需要3对3D-2D的匹配点,然后通过三角形投影关系得到的方程组,然后将方程组进行变换得到两个二元二次方程进行求解。
DLS(Direct Least-Squares)算法整体思路是首先对PnP非线性最小贰乘建模,重新定义LS模型以便于参数降维然后构造Maculy矩阵进行求解,将PnP问题重构为无约束LSM问题然后优化求解。UPnP(Uncalibrated PnP)算法跟EPnP差不了太多,仅仅是多估计了焦距。因此,比较适合未标定场合。
6. 在PnP 优化中,将第一个相机的观测也考虑进来,程序应如何书写?最后结果会有何变化?
7. 在ICP 程序中,将空间点也作为优化变量考虑进来,程序应如何书写?最后结果会有何变化?
8. *在特征点匹配过程中,不可避免地会遇到误匹配的情况。如果我们把错误匹配输入到PnP 或ICP 中,会发生怎样的情况?你能想到哪些避免误匹配的方法?
目前书中用的是根据汉明距离的暴力匹配方法,然后根据经验参数(30或者是最小距离的两倍)对匹配子根据其距离进行筛选。如果误匹配情况输入到PnP或是ICP中,再加上迭代算法选择不正确,初值估计不准确,就很容易导致计算结果产生误差,更有甚者会让迭代过程不稳定,甚至报错。目前比较流行的避免误匹配方法有:交叉匹配(在暴力匹配的基础上再匹配一次,如果两次结果一致,则认为是个特征点,如果不一致则滤掉,BFMatcher XX (NORM_HAMMING, true) )、KNN匹配(K邻近匹配,匹配时候选择K个与特征点相似的点,一般K是2,如果区别足够大,则选择最相似的点作为匹配点,bfMatcher->knnMatch(descriptors1, descriptors2, knnMatches, 2) )、RANSAC(随机采样一致性,利用两个图像之间的单应矩阵,根据重投影误差判定某个匹配是不是正确匹配,findHomography)等等,一般可以跟觉已有的成熟框架如ORB_SLAM2等等观察其对于不同场景所采取的避免误匹配的方法。同样,对于后端,在优化时可以用Huber损失函数等等增强优化算法的鲁棒性。
9. *使用Sophus 的SE3 类,自己设计g2o 的节点与边,实现PnP 和ICP 的优化。
也就是将g2o优化转换成Ceres优化。由于《视觉SLAM十四讲》一书中主要运用的是重投影误差优化法,主要针对的是BA优化问题,而g2o工具对这一类问题求解比较准确方便,以至于对Ceres这工具不太了解。相交于g2o仅适用于BA问题的求解,Ceres更加通用对于最小贰乘问题的计算。通过本题我们可以增加对Ceres优化方法的认识,当然更多的大家还是去看Ceres官方教材。