该类负责特征点与特征点之间,地图点与特征点之间通过投影关系、词袋模型或者Sim3位姿匹配。用来辅助完成单目初始化,三角化恢复新的地图点,tracking,relocalization以及loop closing,因此比较重要。

该类提供的API是:

1. 几个重载的SearchByProjection函数(第一个形参代表需要在其中寻找匹配点的当前图像帧/query;第二个形参则包含待匹配特征/train),用于

  a. 跟踪局部地图(在局部地图中寻找与当前帧特征点匹配的)。因为在TrackReferenceKeyFrame和TrackWithMotionModel中,仅仅是两帧之间跟踪,会跟丢地图点,这里通过跟踪局部地图,在当前帧中恢复出一些当前帧的地图点。  其中的阈值th一般根据单目还是双目,或者最近有没有进行过重定位来确定,代表在投影点的这个平面阈值范围内寻找匹配特征点。匹配点不仅需要满足对极几何,初始位姿的约束;还需要满足描述子之间距离较小。

int ORBmatcher::SearchByProjection(Frame &F, const vector<MapPoint*> &vpMapPoints, const float th);

  b. 匹配上一帧的地图点,即前后两帧匹配,用于TrackWithMotionModel。

int ORBmatcher::SearchByProjection(Frame &CurrentFrame, const Frame &LastFrame, const float th, const bool bMono);

  c. 在当前帧中匹配所有关键帧中的地图点,用于Relocalization。

int ORBmatcher::SearchByProjection(Frame &CurrentFrame, KeyFrame *pKF, const set<MapPoint*> &sAlreadyFound, const float th , const int ORBdist);

  d. 在当前关键帧中匹配所有关键帧中的地图点,需要计算sim3,用于Loop Closing。

int ORBmatcher::SearchByProjection(KeyFrame* pKF, cv::Mat Scw, const vector<MapPoint*> &vpPoints, vector<MapPoint*> &vpMatched, int th);

2. 两个重载的SearchByBow函数(注意这里形参表示的匹配的主被动关系和SearchByProjection是反的),用于

  a. 在当前帧中匹配关键帧中的地图点,用于TrackReferenceKeyFrame和Relocalization。

int ORBmatcher::SearchByBoW(KeyFrame* pKF,Frame &F, vector<MapPoint*> &vpMapPointMatches);

  b. 在当前关键帧中匹配所有关键帧中的地图点,用于Loop Closing。

int ORBmatcher::SearchByBoW(KeyFrame *pKF1, KeyFrame *pKF2, vector<MapPoint *> &vpMatches12);

3. 用于单目初始化的SearchForInitialization,以及利用三角化,在两个关键帧之间恢复出一些地图点SearchForTriangulation。

int ORBmatcher::SearchForInitialization(Frame &F1, Frame &F2, vector<cv::Point2f> &vbPrevMatched, vector<int> &vnMatches12, int windowSize);
int ORBmatcher::SearchForTriangulation(KeyFrame *pKF1, KeyFrame *pKF2, cv::Mat F12,vector<pair<size_t, size_t> > &vMatchedPairs, const bool bOnlyStereo);

4. 两个重载的Fuse函数,用于地图点的融合:

  地图点能匹配上当前关键帧的地图点,也就是地图点重合了,选择观测数多的地图点替换;地图点能匹配上当前帧的特征点,但是该特征点还没有生成地图点,则生成新的地图点)。

  重载的函数是为了减小尺度漂移的影响,需要知道当前关键帧的sim3位姿。

int ORBmatcher::Fuse(KeyFrame *pKF, const vector<MapPoint *> &vpMapPoints, const float th);
int ORBmatcher::Fuse(KeyFrame *pKF, cv::Mat Scw, const vector<MapPoint *> &vpPoints, float th, vector<MapPoint *> &vpReplacePoint);

5. 计算描述子之间的hanmming距离

int ORBmatcher::DescriptorDistance(const cv::Mat &a, const cv::Mat &b);

选取其中一个用于Relocalization的投影匹配着重理解。疑问是,何时用投影匹配,何时用DBow2进行匹配?在Relocalization和LoopClosing中进行匹配的是在很多帧关键帧集合中匹配,属于Place Recognition,因此需要用DBow,而投影匹配适用于两帧之间,或者投影范围内(局部地图,前一个关键帧对应地图点)的MapPoints与当前帧之间。

int ORBmatcher::SearchByProjection(Frame &CurrentFrame, KeyFrame *pKF, const set<MapPoint*> &sAlreadyFound, const float th , const int ORBdist);

用关键帧pKF的地图点投影匹配当前帧的特征点:

// For Relocalization
//
// 1. 获取pKF对应的地图点vpMPs,遍历
//     (1). 若该点为NULL、isBad或者在SearchByBow中已经匹配上(Relocalization中首先会通过SearchByBow匹配一次),抛弃;
// 2. 通过当前帧的位姿,将世界坐标系下的地图点坐标转换为当前帧坐标系(相机坐标系)下的坐标
//     (2). 投影点(u,v)不在畸变矫正过的图像范围内,地图点的距离dist3D不在地图点的可观测距离内(根据地图点对应的金字塔层数,
//           也就是提取特征的neighbourhood尺寸),抛弃
// 3. 通过地图点的距离dist3D,预测特征对应金字塔层nPredictedLevel,并获取搜索window大小(th*scale),在以上约束的范围内,
//    搜索得到候选匹配点集合向量vIndices2
//     const vector<size_t> vIndices2 = CurrentFrame.GetFeaturesInArea(u, v, radius, nPredictedLevel-1, nPredictedLevel+1);
// 4. 计算地图点的描述子和候选匹配点描述子距离,获得最近距离的最佳匹配,但是也要满足距离<ORBdist。
// 5. 最后,还需要通过直方图验证描述子的方向是否匹配
int ORBmatcher::SearchByProjection(Frame &CurrentFrame, KeyFrame *pKF, const set<MapPoint*> &sAlreadyFound, const float th , const int ORBdist)
{int nmatches = 0;const cv::Mat Rcw = CurrentFrame.mTcw.rowRange(0,3).colRange(0,3);const cv::Mat tcw = CurrentFrame.mTcw.rowRange(0,3).col(3);const cv::Mat Ow = -Rcw.t()*tcw;// Rotation Histogram (to check rotation consistency)vector<int> rotHist[HISTO_LENGTH];for(int i=0;i<HISTO_LENGTH;i++)rotHist[i].reserve(500);const float factor = 1.0f/HISTO_LENGTH;const vector<MapPoint*> vpMPs = pKF->GetMapPointMatches();for(size_t i=0, iend=vpMPs.size(); i<iend; i++){MapPoint* pMP = vpMPs[i];if(pMP){// before this, Relocalization has already execute SearchByBoW, those matched was inserted into sAlreadyFoundif(!pMP->isBad() && !sAlreadyFound.count(pMP)){//Projectcv::Mat x3Dw = pMP->GetWorldPos();cv::Mat x3Dc = Rcw*x3Dw+tcw;const float xc = x3Dc.at<float>(0);const float yc = x3Dc.at<float>(1);const float invzc = 1.0/x3Dc.at<float>(2);const float u = CurrentFrame.fx*xc*invzc+CurrentFrame.cx;const float v = CurrentFrame.fy*yc*invzc+CurrentFrame.cy;// u,v是关键帧中地图点在当前帧上的投影点if(u<CurrentFrame.mnMinX || u>CurrentFrame.mnMaxX)continue;if(v<CurrentFrame.mnMinY || v>CurrentFrame.mnMaxY)continue;// Compute predicted scale levelcv::Mat PO = x3Dw-Ow;float dist3D = cv::norm(PO);const float maxDistance = pMP->GetMaxDistanceInvariance();const float minDistance = pMP->GetMinDistanceInvariance();// Depth must be inside the scale pyramid of the imageif(dist3D<minDistance || dist3D>maxDistance)continue;int nPredictedLevel = pMP->PredictScale(dist3D,&CurrentFrame);// Search in a windowconst float radius = th*CurrentFrame.mvScaleFactors[nPredictedLevel];const vector<size_t> vIndices2 = CurrentFrame.GetFeaturesInArea(u, v, radius, nPredictedLevel-1, nPredictedLevel+1);if(vIndices2.empty())continue;const cv::Mat dMP = pMP->GetDescriptor();int bestDist = 256;int bestIdx2 = -1;for(vector<size_t>::const_iterator vit=vIndices2.begin(); vit!=vIndices2.end(); vit++){const size_t i2 = *vit;if(CurrentFrame.mvpMapPoints[i2])continue;const cv::Mat &d = CurrentFrame.mDescriptors.row(i2);const int dist = DescriptorDistance(dMP,d);if(dist<bestDist){bestDist=dist;bestIdx2=i2;}}if(bestDist<=ORBdist){CurrentFrame.mvpMapPoints[bestIdx2]=pMP;nmatches++;if(mbCheckOrientation){float rot = pKF->mvKeysUn[i].angle-CurrentFrame.mvKeysUn[bestIdx2].angle;if(rot<0.0)rot+=360.0f;int bin = round(rot*factor);if(bin==HISTO_LENGTH)bin=0;assert(bin>=0 && bin<HISTO_LENGTH);rotHist[bin].push_back(bestIdx2);}}}}}if(mbCheckOrientation){int ind1=-1;int ind2=-1;int ind3=-1;ComputeThreeMaxima(rotHist,HISTO_LENGTH,ind1,ind2,ind3);for(int i=0; i<HISTO_LENGTH; i++){if(i!=ind1 && i!=ind2 && i!=ind3){for(size_t j=0, jend=rotHist[i].size(); j<jend; j++){CurrentFrame.mvpMapPoints[rotHist[i][j]]=NULL;nmatches--;}}}}return nmatches;
}

其中角度直方图是用来剔除不满足两帧之间角度旋转的外点的,也就是所谓的旋转一致性检测

1. 将关键帧与当前帧匹配点的angle相减,得到rot(0<=rot<360),放入一个直方图中,对于每一对匹配点的角度差,均可以放入一个bin的范围内(360/HISTO_LENGTH)。

2. 统计直方图最高的三个bin保留,其他范围内的匹配点剔除。另外,若最高的比第二高的高10倍以上,则只保留最高的bin中的匹配点。

最后该函数会

1. 为当前帧生成和关键帧匹配上的地图点

2. 统计通过投影匹配上的点

CurrentFrame.mvpMapPoints[bestIdx2]=pMP;
nmatches++;

转载于:https://www.cnblogs.com/shang-slam/p/6431017.html

ORB-SLAM(八)ORBmatcher 特征匹配相关推荐

  1. 【理解】ORB特征提取与ORBSLAM特征匹配简要剖析

    目录 ORB特征提取 优势: 经典FAST特征提取: 经典的BRIEF描述子: ORB特征提取的改进: 如何在FAST检测的基础上维持特征点的尺度不变性? 如何在FAST检测的基础上维持特征点的旋转不 ...

  2. ORB算法——特征提取特征匹配

    特征提取 Abstract ORB(Oriented Fast and Rotated Brief),可以用来对图像中的关键点快速创建特征向量,这些特征向量可以用来识别图像中的对象. 其中,Fast ...

  3. 【特征匹配】SIFT原理之KD树+BBF算法解析

    转载请注明出处:http://blog.csdn.net/luoshixian099/article/details/47606159 继上一篇中已经介绍了SIFT原理与C源码剖析,最后得到了一系列特 ...

  4. OpenCV中的特征匹配(Feature Matching)

    OpenCV中的特征匹配(Feature Matching) 1. 效果图 2. 原理 3. 源码 3.1 SIFT关键点检测+Knn近邻匹配 3.2 ORB关键点检测+蛮力特征匹配 3.3 SIFT ...

  5. SLAM从0到1——ORB特征提取及特征匹配

    点击上方"3D视觉工坊",选择"星标" 干货第一时间送达 学习3D视觉核心技术,扫描查看介绍,3天内无条件退款 圈里有高质量教程资料.可答疑解惑.助你高效解决问 ...

  6. ubuntu20.04下安装Kdevelop并实现图像ORB特征匹配

    ubuntu20.04下安装Kdevelop并实现图像ORB特征匹配 安装Kdevelop 图像ORB匹配 **CMakelists.txt文件** **使用kdevelop实现orb特征匹配** 安 ...

  7. SLAM之特征匹配(一)————RANSAC-------OpenCV中findFundamentalMat函数使用的模型

    目录 1.RANSAC原理 2. RANSAC算法步骤: 3. RANSAC源码解析 step one niters最初的值为2000,这就是初始时的RANSAC算法的循环次数,getSubset() ...

  8. (三)ORB特征匹配

    ORBSLAM2匹配方法流程 在基于特征点的视觉SLAM系统中,特征匹配是数据关联最重要的方法.特征匹配为后端优化提供初值信息,也为前端提供较好的里程计信息,可见,若特征匹配出现问题,则整个视觉SLA ...

  9. ORB/BRISK/AKAZE特征点提取、特征匹配的性能比较

    写在前面 局部特征相关算法在过去二十年期间风靡一时,其中代表的有SIFT.SURF算法等(广泛应用于目标检测.识别.匹配定位中),这两种算法是用金字塔策略构建高斯尺度空间(SURF算法采用框滤波来近似 ...

最新文章

  1. 获取可视区域高度赋值给div(解决document.body.clientHeight的返回值为0的问题)
  2. Ubuntu下安装Nginx,PHP5(及PHP-FPM),MySQL
  3. 怎么卸载Apache_pn服务-PHPnow使用问题
  4. 湖南大学第十四届ACM程序设计新生杯(重现赛)L-The Digits String (矩阵快速幂)
  5. 建立数组并写入数据_VBA数组与字典解决方案第37讲:在VBA中字典的应用
  6. datasnap 的HTTP 调用返回JSON
  7. 在适当的场合使用FlagsAttribute修饰枚举
  8. linux网络发包性能优化
  9. ionicView视图的生命周期
  10. CYQ.Data 轻量数据访问层(七) 自定义数据表实现绑定常用的数据控件(上)
  11. 利用VBA将表格保存为PDF文件
  12. 除了努力挣钱,青春也不能错过的十件事
  13. PCI/PCIE相关知识
  14. 【历史上的今天】4 月 27 日:Tumblr 上线;施乐推出了 Star 工作站;第一台安德伍德打字机诞生
  15. 激活 出现无法访问制定设备,路径或文件。您可能没有合适的权
  16. TC118S/TC118H单通道直流马达驱动IC
  17. 简谈高通Trustzone的实现【转】
  18. 网易控股的立马理财逾期,网易前员工爆料:把内部员工当韭菜
  19. 未来10年,C++5个非常有前景的就业方向
  20. 写博客的时间被看小说、刷微信的时候,要想想

热门文章

  1. 苹果公司开发Overton机器学习平台,它到底是什么?
  2. 贝叶斯方法与连续值离散化
  3. 「杂谈」白身,初识,不惑,有识,你处于深度学习哪一重境界了
  4. 人工智能AI正从这五个方面改变公司
  5. 自动驾驶中常用的四类机器学习算法
  6. 一文说清AI智能平台
  7. 北大副校长詹启敏回应“25篇论文造假”,​PubPpeer到底靠不靠谱?
  8. Nature新研究:猪脑死亡4小时后,科学家成功恢复脑细胞功能
  9. 在读博士的第八年,她破解了量子计算领域最基本的问题之一
  10. 智能哲学:“学习机器”与“机器学习” ——解读图灵思想中的人工智能