ORB_SLAM2源码:ORBmatcher.cc
ORBmatcher.cc中的函数,主要实现(1)路标点和特征点的匹配(2D-3D点对)。(2)特征点和特征点的匹配(2D-2D点对)。SearchByProjection的函数重载看得我一脸懵逼。在这做一下笔记,以后可以参考参考。
每个路标点会有一个自己的最优描述子。个人理解,这个最优描述子的含义应该是:一个路标点会对应多个特征点,先获得所有特征点的描述子,然后计算描述子之间的两两距离,最好的描述子与其他描述子应该具有最小的距离中值。
匹配策略
在匹配2D-2D点对,2D-3D点对时,常用的策略包括:
(1)比较描述子的汉明距离,选出最优的特征点(2D-2D、3D-3D)。
(2)使用词袋加速匹配(2D-2D)。
词袋中包含单词。每个单词即使用聚类算法获得的同一类的特征点的描述子。每幅图像的每一个特征点都对应一个单词。在两幅图像的单词分布已知的情况下,如:
图像1:单词1(包含50个特征点)、单词2(包含100个特征点);
图像2:单词1(包含60个特征点)、单词2(包含90个特征点)。
可以在每个单词中去比较特征点,这样只需比较50×60+100×90=12000次,远小于150×150=22500。从而实现特征点的加速匹配。但这种方法会造成很多未匹配的特征点(比如选择的两个特征点间的汉明距离大于设置的阈值)。
约束条件
(1)相机坐标系下,z值应该大于0
(2)找到的特征点对间的汉明距离要小于阈值。
(3)找到的最优、次优特征点间的汉明距离应满足一定的比例关系。
(4)相机坐标转到像素坐标后,应该在图像的范围之内。
(5)路标点—光心间的长度应在一定范围内。
(6)在旋转直方图中,只选出前3个直方图中的特征点对。
旋转直方图:
直方图中存放的是找出的候选特征点的编号。
参考自知乎:https://zhuanlan.zhihu.com/p/267971447?utm_source=wechat_timeline
1)构建直方图
30个直方图,每个直方图的高(高,即存储500个KeyPoint的索引)
2)计算KeyFrame1的KeyPoints和其对应KeyFrame2的KeyPoints的角度差。
角度差为1~30之间的数,对应着30个直方图,并将KeyFrame1中的KeyPoint索引值放入直方图中。
示例:角度差为100,那么100/30=3.3,四舍五入为3,应该将KeyFrame1中的KeyPoint索引值存入第3个直方图中
3)筛选落在直方图中索引值最多的3个直方图:ComputeThreeMaxima
最后取选择上图中最高的3个直方图:(1)(2)(3)
SearchByProjection函数的重载
SearchByProjection函数一共有4种重载。分别为局部地图跟踪,后一帧跟踪前一帧,重定位中的跟踪,回环检测中的跟踪。均是为了建立路标点与特征点间的联系。
局部地图跟踪
int ORBmatcher::SearchByProjection(Frame &F, const vector<MapPoint*> &vpMapPoints, const float th)
流程为:
(1)遍历有效的地图点。
(2)设定搜索搜索窗口的大小。取决于视角, 若当前视角和路标点的平均视角夹角较小时, r取一个较小的值。
(3)通过投影点以及搜索窗口和预测的尺度进行搜索, 找出搜索半径内的候选匹配点索引。
(4)寻找候选匹配点中的最佳和次佳匹配点。
(5)筛选最佳匹配点。
建立局部地图的路标点与当前帧的特征点间的联系。流程如下:
当前帧追踪上一帧
将上一帧跟踪的地图点投影到当前帧,并且搜索匹配点。
int ORBmatcher::SearchByProjection(Frame &CurrentFrame, const Frame &LastFrame, const float th, const bool bMono)
流程为:
(1)建立旋转直方图,用于检测旋转一致性。
(2)计算当前帧和前一帧的平移向量。
(3)对于前一帧的每一个地图点,通过相机投影模型,得到投影到当前帧的像素坐标。
(4)根据相机的前后前进方向来判断搜索金字塔层的范围。
(5)遍历候选匹配点,寻找距离最小的最佳匹配点 。
(6)计算匹配点旋转角度差所在的直方图。
(7)进行旋转一致检测,剔除不一致的匹配。
重定位中的投影
在重定位过程中,会首先使用词袋算法加速特征点匹配,找到与当前帧F最相似的关键帧KF。建立起KF中的路标点和F中的特征点间的联系。但这会使得很多匹配没有被检测到,因此还需将KF中的路标点投影到F中,进一步查找,以增加KF中的路标点和F中的特征点的匹配数量。
int ORBmatcher::SearchByProjection(Frame &CurrentFrame, KeyFrame *pKF, const set<MapPoint*> &sAlreadyFound, const float th , const int ORBdist)
(1)建立旋转直方图,用于检测旋转一致性。
(2)遍历关键帧中的每个地图点,通过相机投影模型,得到投影到当前帧的像素坐标。
(3)确定搜索半径,获得候选特征点。
(4)遍历候选匹配点,寻找距离最小的最佳匹配点。
(5)计算匹配点旋转角度差所在的直方图。
(6)进行旋转一致检测,剔除不一致的匹配。
回环检测时的投影
首先使用词袋加速算法,找到当前关键帧的闭环关键帧。但会有遗漏。
此时已经找到了当前关键帧KFC的闭环关键帧KF(与KFC相似程度最高的关键帧)。将KF及其共视关键帧全部投影至KFC中,建立3D-2D联系。
int ORBmatcher::SearchByProjection(KeyFrame* pKF, cv::Mat Scw, const vector<MapPoint*> &vpPoints, vector<MapPoint*> &vpMatched, int th)
流程为:
(1)分解Sim变换矩阵,获得KF,KFC间的位姿变换关系。
(2)遍历闭环KF及其共视KF的所有地图点(不考虑当前KF已经匹配的地图点)投影到当前KF。
(3)根据预测的路标点所在的金字塔层级获得搜索半径。搜索候选匹配特征点。
(4)遍历候选匹配点,找到最佳匹配点。
(5)建立路标点与特征点的联系。
词袋模型加速匹配函数
词袋算法的原理上面已经介绍了。建立的是当前帧的特征点和参考帧的路标点间的联系。
在后一帧追踪前一帧、追踪局部地图时,不需要去寻找与当前帧最相似的一帧,因此无需使用。
在回环检测中,需要寻找当前关键帧的闭环关键帧。在重定位时,需要寻找与当前帧最相似的关键帧。此时使用词袋加速算法,虽然会有很多遗漏的匹配,但可以快速的找到目标帧。
重定位中的词袋加速
int ORBmatcher::SearchByBoW(KeyFrame* pKF,Frame &F, vector<MapPoint*> &vpMapPointMatches)
流程为:
(1)分别取出两图中属于同一node的ORB特征点(只有属于同一node,才有可能是匹配点)。
(2)遍历KF中属于该node的特征点。
(3)遍历F中属于该node的特征点,寻找最佳匹配点。
(4)根据汉明距离阈值和旋转直方图剔除误匹配(关键帧和当前帧进行特征点匹配之后,已知两个特征点的角度,从而可以获得角度变化)。
回环检测中的词袋加速
int ORBmatcher::SearchByBoW(KeyFrame *pKF1, KeyFrame *pKF2, vector<MapPoint *> &vpMatches12)
流程与重定位中的流程相同。
检测极线距离是否符合要求
bool ORBmatcher::CheckDistEpipolarLine(const cv::KeyPoint &kp1,const cv::KeyPoint &kp2,const cv::Mat &F12,const KeyFrame* pKF2)
在已知基础矩阵F的情况下,可获得图像1中的特征点,在图像2中的极线方程。在已知基础矩阵的情况下,用于检测所匹配的特征点是否正确。
// Epipolar line in second image l2 = x1'F12 = [a b c]// Step 1 求出kp1在pKF2上对应的极线const float a = kp1.pt.x*F12.at<float>(0,0)+kp1.pt.y*F12.at<float>(1,0)+F12.at<float>(2,0);const float b = kp1.pt.x*F12.at<float>(0,1)+kp1.pt.y*F12.at<float>(1,1)+F12.at<float>(2,1);const float c = kp1.pt.x*F12.at<float>(0,2)+kp1.pt.y*F12.at<float>(1,2)+F12.at<float>(2,2);// Step 2 计算kp2特征点到极线l2的距离// 极线l2:ax + by + c = 0// (u,v)到l2的距离为: |au+bv+c| / sqrt(a^2+b^2)const float num = a*kp2.pt.x+b*kp2.pt.y+c;const float den = a*a+b*b;
单目初始化中的特征点匹配
选第1帧作为参考,第2帧去匹配第一帧。如果匹配失败的话,第3帧作为参考,第4帧去匹配。
int ORBmatcher::SearchForInitialization(Frame &F1, Frame &F2, vector<cv::Point2f> &vbPrevMatched, vector<int> &vnMatches12, int windowSize)
流程为:
(1)构建旋转直方图。
(2)在半径窗口内搜索当前帧F2中所有的候选匹配特征点 。
(3)遍历搜索搜索窗口中的所有潜在的匹配候选点,找到最优的和次优的。
(4)对最优次优结果进行检查,满足阈值、最优/次优比例,删除重复匹配。
(5)计算匹配点旋转角度差所在的直方图,筛除旋转直方图中“非主流”部分。
(6)将最后通过筛选的匹配好的特征点保存。
局部建图中的特征点匹配
因为在local mapping线程中,关键帧的位姿已经相当准确了,即F12也是比较准确的。所以可以使用三角化生成新的MapPoint,匹配使用的是BoW,筛选部分使用了对极点邻域剔除、极线约束、角度投票(旋转一致性)进行剔除误匹配。
int ORBmatcher::SearchForTriangulation(KeyFrame *pKF1, KeyFrame *pKF2, cv::Mat F12,vector<pair<size_t, size_t> > &vMatchedPairs, const bool bOnlyStereo)
(1)使用词袋加速匹配,获得匹配点对。
(2)使用特征点到极线的距离、旋转直方图剔除误匹配。
回环检测中寻找更多的匹配点
在回环检测时使用,考虑了尺度漂移,因此使用Sim3(Sim3有7自由度)。使用词袋加速算法获得的匹配点存在遗漏,因此对当前帧和回环帧中的ORB特征相互投影,从而找到更多的匹配点。
(1)遍历KF1中的地图点,如果该地图点已经匹配(使用词袋加速算法时已经匹配了),就跳过。
(2)转换为KF2中的相机坐标、像素坐标。
(3)在搜索区域找到候选特征点。
(4)根据汉明距离,找到最优特征点。得到vnMatch1[i1]=bestIdx。其中i1为KF1中特征点的索引,bestIdx为在KF2中找到的特征点的索引。
(5)遍历KF2中的地图点,重复以上步骤,获得vnMatch1[i2]=bestIdx。
(6)比较KF1中的特征点和KF2中的特征点是否相互索引。
int ORBmatcher::SearchBySim3(KeyFrame *pKF1, KeyFrame *pKF2, vector<MapPoint*> &vpMatches12,const float &s12, const cv::Mat &R12, const cv::Mat &t12, const float th)
路标点融合函数
就是将未匹配的特征点投影至图像中,进行路标点的融合
将路标点1投影至当前帧中,寻找与之匹配的特征点。
(1)若该特征点存在与之相连的路标点2,则在路标点1,路标点2中选择被观测次数最多的点。
(2)若该特征点没有与之相连的路标点,则建立特征点与路标点1间的联系。
int ORBmatcher::Fuse(KeyFrame *pKF, const vector<MapPoint *> &vpMapPoints, const float th)
相关文章:

iOS国际化技巧
参考链接:http://www.cocoachina.com/ios/20151120/14258.html http://www.jianshu.com/p/88c1b65e3ddb http://www.cnblogs.com/levilinxi/p/4296712.html http://www.cocoachina.com/appstore/20160310/15632.html http://www.cocoachina.com/ios/20170214/18681.html转载于:…

CV08-数据预处理与数据增强
复现车道线分割项目(Lane Segmentation赛事说明在这里),学习数据预处理和数据增强。学习分为Model、Data、Training、Inference、Deployment五个阶段,也就是建模、数据、训练、推断、部署这五个阶段。现在进入的是Data阶段。项目的…

ORB_SLAM2程序入口(System.cc)
程序入口 ORB_SLAM2的程序入口为src/System.cc。在CMakeList.txt中可知,ORB_SLAM2的可执行程序为: Examples/Stereo/stereo_kitti.cc等。 add_executable(stereo_kitti Examples/Stereo/stereo_kitti.cc) target_link_libraries(stereo_kitti ${PROJECT…

HDU 6229 Wandering Robots 找规律+离散化
题目链接:Wandering Robots 题解:先讲一下规律,对于每一个格子它可以从多少个地方来有一个值(可以从自己到自己),然后答案就是统计合法格子上的数与所有格子的数的比值 比如说样例的3 0格子上的值就是 3 4 …

app、H5、safari、appstore应用主页评分页之间拉起调用、打开手机某些系统功能、app打开文档
定义打开URL的方法 - (void)openURL:(NSString *)urlStr {NSURL *url [NSURL URLWithString:urlStr];UIApplication *app [UIApplication sharedApplication];if ([app canOpenURL:url]) { #ifdef __IPHONE_10_0[app openURL:url options:[NSDictionary dictionary] complet…
XML学习总结
1、XML结构 2、XmlNodeType值为一个枚举类型: 假设我们对一个XML文件进行遍历,不推断节点是否为Element类型。就会将文本节点遍历出来,出现#test。 3、XmlElement和XmlNode的差别:(摘自CSDN论坛) ÿ…

Linux01-基本操作与Shell
目录 一、环境 二、Linux目录结构及基本操作 2.1 Linux目录结构 2.2 基本操作 三、shell 3.1 shell的意义 3.2 su - 一、环境 2019年搞下RHCE的证书,但是一直没有整理Linux学习的笔记,为了不让到手的知识被遗忘,从今天起整理Linux学习…

ORB_SLAM2中Tracking线程的三种追踪方式
1、参考关键帧追踪模式 bool Tracking::TrackReferenceKeyFrame()对参考关键帧中的路标点进行跟踪。在Tracking线程中,每传入一帧,都会进行位姿优化。 以上一帧的位姿为当前位姿进行优化。 (1)计算当前帧的词袋 mCurrentFra…

nodejs 中间件 反向代理 接口转发
背景 随着后端业务系统的增加,纵向需求不断扩展,一个业务系统已经无法满足需求了,衍生出多个业务系统,对外暴露的ip、端口就可能有多个,此时不方便外部接口调用,有些特殊行业客户出于安全性考虑不发提供多…

oneinstack
https://oneinstack.com/转载于:https://www.cnblogs.com/diyunpeng/p/9740895.html

最近在做托盘时,发现 CnTrayIcon1的OnClick 事件,不能被其它按钮来执行,蛋疼。...
比如: procedure TForm1.Button1Click(Sender: TObject);begin CnTrayIcon1.OnClick ; // 这句就是不能通过!!end; 有过路的高手,指点学生一下。谢谢转载于:https://www.cnblogs.com/hahy8008/p/6783614.html

Linux02-帮助手册
目录 一、man手册 1.1 man的基本使用 1.2 mandb更新文档 二、/usr/share/doc 三、access.redhat.com 门户 一、man手册 1.1 man的基本使用 man就是mannual的缩写,手册的意思。Linux的命令很多,参数选项更多,人脑一般是记不住的&…

ORB_SLAM2中Tracking线程
Tracking线程是ORB_SLAM2的主线程。在System.cc中,使用构造函数进行了初始化,开启了三个线程。 可执行程序—>System构造函数(初始化三个线程)—>处理输入的帧(TrackMonocular)—>调用Tracking线程…

selenium的基础知识点
from selenium import webdriver from scrapy.selector import Selector#模拟登陆 browser webdriver.Chrome(executable_pathChromedriver.exe) #路径是Chromedriver.exe的存放位置,windows下只要配置好这个环境就不需要了browser.get(http://w) #需要登陆的那个网…

iOS 直播专题2-音视频采集
从设备(手机)的摄像头、MIC中采集音频、视频的原始数据ios的音视频采集可以从AVFoundation框架里采集 视频采集 这里我们选取GPUImage来采集视频,因为这个框架集成了很多视频滤镜,例如美颜 采集流程: 摄像头采集视频代码 GPUImageVideoCamera.m // 从前摄像头或后摄像头…

bzoj 4871: [Shoi2017]摧毁“树状图”
4871: [Shoi2017]摧毁“树状图” Time Limit: 25 Sec Memory Limit: 512 MBSubmit: 53 Solved: 9[Submit][Status][Discuss]Description 自从上次神刀手帮助蚯蚓国增添了上千万人口(蚯口?),蚯蚓国发展得越来越繁荣了!…

Linux03-本地账户和组
目录 一、本地账户/etc/passwd 二、本地组/etc/group 三、切换账户su - 四、增删改本地账户useradd、userdel、usermod 五、账户默认配置文件/etc/login.defs 六、设置密码passwd(5)命令 七、增删改组groupadd、groupdel和groupmod 八、通过sudo以root身份运行命令 九…

ORB_SLAM2单目初始化策略
基本流程 单目初始化程序存储在Initializer.cc中 需要注意,对于双目/RGB-D相机,初始化时,由于可以直接获得相机的深度信息,因此无需求H/F,直接作为关键帧插入就行。 使用RANSACDLT求解H,RANSAC八点…

Powerdesigner逆向工程64位Oracle数据库
Powerdesigner老版本不支持64位Client,新版本弄不到破解码 解决方法,用Powerdesigner32位Oracle Clent访问64位Oracle Server 遇到的坑分享下 安装完64位的Oracle Server ,32位的 Oracle Clent默认的listener.ora文件有PROGRAM和ENVS这两个节点 Plsql(3…

运行jsp时,报错404
The origin server did not find a current reprsentation for the target resource or is not willing to disclose that one exists. 解决: 1. web.xml文件位置是否放错,应该放在WebContent/WEB-INF文件夹中 2. web.xml文件中是否有拼写错误࿰…

iOS 直播专题3-前置处理
前置处理 对视频添加美颜、水印、滤镜等对音频进行混音、消除环境音、声音特效等上一篇iOS 直播专题2-音视频采集提到视频采集采用的是GPUImage框架,这个框架集成了很多滤镜效果 这里主要介绍美颜、水印处理 处理流程: 美颜 这里的美颜效果用的是GPUImageBeautyFilter 功…

ORA-10873解决办法
今天,发现SAP系统的oracle数据库宕掉了。报错ORA-10873,经过查证解决该问题。记录一下,备忘。 一、问题 Oracle版本为12.1.0.2.0,在启动服务器后启动数据库startup,报错ORA-10873。 二、查证 到SAP Support Portal上…

ORB_SLAM2局部建图线程
局部建图线程入口:可执行程序在初始化三个线程的时候,在System.cc的构造函数中进入局部建图线程 mpLocalMapper new LocalMapping(mpMap, //指定使iomanipmSensorMONOCULAR); // TODO 为什么这个要设置成为MONOCULAR??&#…

十一连测day1
这次测试,是福建第三中学的某同学出的,感觉难度还行吧,今天我就浅谈一下这场比赛的时间分配与心得 打开题目,看到了T1,这题是一道计数题吧,感觉心态一下子就崩了,100%的数据点应该是组合数学容斥…

iOS 直播专题5-推流
常用的推流协议有: 协议内容RTP实时流传输协议,但不保证服务质量RTCPRTP数据流协议的一个姐妹协议,为RTP提供服务质量反馈SRTP & SRTCPRTP和RTCP的安全版本,提供数据加密、消息认证功能RTSP控制声音或影像的多媒体数据串流协议RTMPADOBE公司播放器与服务器之间多媒体数…

centos6.5-vsftp搭建
我的机子是默认是没有的vsftp。 yum install -y vsftp 创建账户专为ftp而生。useradd ftp01 更改账户不可登录系统。usermod -s /sbin/nologin ftp01 vsftp默认是可以匿名登录的,也是默认的端口,这些不安全选项都要修改! anonymous_enableYES…

Linux04-文件系统权限与ACL权限
目录 一、文件系统权限 1.1、认识文件系统权限 1.2、管理文件系统权限 1.3、特殊权限 1.4、默认权限 二、ACL权限 2.1、ACL本质是文件系统的一个挂载选项 2.2、更改文件的ACL权限 2.3、设置文件和目录的默认ACL权限 Linux中的权限管理分为两种类型 用户自主访问控制&…

ORB_SLAM2帧Frame
在追踪线程的一开始就会创建一个帧 cv::Mat Tracking::GrabImageMonocular(const cv::Mat &im,const double ×tamp)构造函数 在构造函数中,会对特征点进行提取。 ExtractORB(0,imGray);特征点分配至网格 将图像划分为48*64的网格,然后将…

Servlet的基本架构
Servlet的基本架构: package test;import java.io.IOException;import javax.servlet.ServletException;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class Serv…

ORACLE 用户权限管理
Oracle创建用户的语法: CREATE USER username IDENTIFIED BY password OR IDENTIFIED EXETERNALLY OR IDENTIFIED GLOBALLY AS CNuser [DEFAULT TABLESPACE tablespace] [TEMPORARY TABLESPACE temptablespace] [QUOTA [integer K[M] ] [UNLIMITED] ] ON tables…