AliceVision代码阅读【4】
发布时间: 2024-01-11 17:25:50
main_featureMatching.cpp→aliceVision_featureMatching
【90-253】设置输入参数,并对输入进行configure
【263-267】与之前一样,从之前的cameraInit.sfm读取sfmData 【280-301】读取上一步获取的pair
【304-308】将所有出现在pair里面的id存到filter里面 【313-328】载入之前提取的feature,描述子到regoinPerview
【335-352】看这些pair的位姿是否有定义 【354-361】有位姿情况下的匹配方式
match函数
对于每个pair,先获取对应的位姿,相机内参(如果不是pinhole就不行) 【118-119】计算相机投影矩阵乘以位姿 【121】计算基本矩阵https://blog.csdn.net/weixin_45485946/article/details/125493895 https://blog.csdn.net/u011089570/article/details/79040948 【122】获得每个pair共有的描述子类型
【124】allImagePairMatches是一个map,索引是描述子类型,成员是std::vectormatching::IndMatch,matching::IndMatch三个成员,其中两个表示这两个id所表示的描述子是相近的,第三个成员函数表示有多近(可以看后续代码离着这个成员)。每个view都有一个allImagePairMatches,表示这个view,每个描述子类型下,图中每个描述子和其最相似的描述子编号。 【142】左侧相机在右侧相机图像中的位置 【145】guidedMatchingFundamentalFast,参考Rajvi Shah, Vanshika Shrivastava, and P J Narayanan Geometry-aware Feature Matching for Structure from Motion Applications.
其最简单的实现就是对比pair里面每个描述子,可以参考函数guidedMatching 通过极线约束,可以加快上面方法的速度。 【390-392】创立一个buckets,用来存放极线与图像四个边框交点,buckets是个vector,从图像原点开始,顺时针方向增长(可以看函数pix_to_bucket) 【399】算出极线(基本矩阵乘以左图的点,得到应该是直线参数ab c) 【402】找到极线与图像四个边框的交点:line_to_endPoints
【32,49】??判断极线是否在右侧图像上??为什么极线不能平行坐标轴(a=0或者b=0?) 先假设这里可以判断出极线就在右侧图像上 ???剩下的看的都不是很懂,比如极线的搜索范围的设定。应该就是找到每个左侧描述子对应的最像的右侧描述子 无位姿情况下的匹配过程
(ANN_L2)
【49-54】把pair重新放到一个map里面,原文说目的是Sort pairs according the first index to minimize the MatcherT build operations 【71】创建matcher
构造函数里面有一个createRegionsMatcher,会根据matcherType和特征是scalar还是binary为成员_regionsMatcher创建不同的值 以ANN_L2为例,分配了RegionsMatcher<ArrayMatcher_kdtreeFlann> 里面有个成员ArrayMatcher_kdtreeFlann matcher_,在构造函数时候会调用一个函数Build
【96】根据上面的_regionsMatcher类型,进行match,细节在RegionsMatcher.cpp这个文件里面
这里的match输入的query是另一个region的所有描述子,对每一个描述子都要查找离他最近的NNN_=2的邻居 【140】同上,获得查找的矩阵0行0列的地址 【147】SearchNeighbours,到ArrayMatcher_kdtreeFlann.hpp这个文件
【110】看之前的flann的kdtree初始化了没 【113-119】构建距离和索引矩阵,应为一个regions里面每个描述子个数都要查,所以共有描述子个数行,NNN_列 【126】开始查询 【130-139】将查找结果保存 【158-164】查找的第一个结果和第二个结果距离要差的足够大才可以 【166-175】符合结果的pair保存 【90-115】重复上面的步骤,只不过把左右view切换,看得到结果是否一样 【120-125】保存这个pair,这个描述子类型下,结果相同描述子匹配matches (FAST_CASCADE_HASHING_L2)
不同的nearestMatchingMethod,匹配方法不同,(基类IImageCollectionMatcher),后文以ANN_L2作为例子 先看mapPutativesMatches的类型:PairwiseMatches=std::map<Pair, MatchesPerDescType> = std::map<Pair, std::map<feature::EImageDescriberType, std::vectormatching::IndMatch> 以单个pair做索引,成员是(一个索引是描述子类型,成员是该pair下的所有描述子对)的一个map 【228】调出第一个view下的,对应描述子类型的regions(基类,实际是包含该view下所有特征和描述子的FeatDescRegions类) 【233】typeid:https://www.geeksforgeeks.org/typeid-operator-in-c-with-examples/ (剩下的先跳过) 【383-388】检查匹配结果是否是空的 【390-403】如果geometricFilterType是HOMOGRAPHY_GROWING的话,需要对前面得到的匹配的分数(第一近的距离除以第二近的距离,越小越好)进行排序
【462-545】根据不同的geometricFilterType进行filter,下文FUNDAMENTAL_MATRIX为例
omp parallel for schedule https://blog.csdn.net/drzhouweiming/article/details/1844762 dynamic_cast https://blog.csdn.net/weixin_44212574/article/details/89043854 uniform_int_distribution https://blog.csdn.net/Andyooper/article/details/89314678 【471】robustModelEstimation函数,里面的参数GeometricFilterMatrix_F_AC是一个拟函数(Functor)表示使用的方法是Fundamental matrix+ACransac方法
【70】geometricEstimation函数,以GeometricFilterMatrix_F_AC.hpp为例
【100】同之前一样,获得左右图相同类型的描述子 【107】fillMatricesWithUndistortFeaturesMatches函数获得左右图特征点其原始undistort的点,注意这边把所有描述子类型的点全放在一起了 【112】判断是否是鱼眼类型的相机 dynamic_cast https://blog.csdn.net/weixin_44212574/article/details/89043854 【130】geometricEstimation_Mat_ACRANSAC 模板Fundamental7PSolver表示用7点求基本矩阵 Mat3Model表示基本矩阵
【269】RelativePoseKernel
里面FundamentalEpipolarDistanceError的error是Sampson error,参考书Multiple View Geometry in Computer Vision
参数UnnormalizerT则表示将匹配点对们进行归一化,参考书的4.4.4 初始化过程:RelativePoseKernel.hpp
【54-55】归一化过程,可以自己对照程序,拿一个1010图片和100 10图片做例子来理解这个归一化 【63】_logalpha0,参考ransac里面的误差项前面的归一项 【283】ACRANSAC 原理看https://zhuanlan.zhihu.com/p/483852907 + https://blog.csdn.net/u012348774/article/details/79802957 + 原文1.2 Automatic Homographic Registration of a Pair of Images, with A Contrario Elimination of Outliers http://www.ipol.im/pub/art/2012/mmm-oh/article.pdf
大致原理
在匹配点中抽取若干个点(比如在这里七点法求F,就取7个点) 解出模型(F的值) 算出剩下点的残差(sampson距离),从小到大排列 根据排列依次加入之前的若干点,求NFA,然后保留最小的NFA对应的点 重复多次 【168】std::itoa https://cplusplus.com/reference/numeric/iota/ 【173】生成
(
n
l
)
\binom{n}{l}
( l n ? )
l
=
0
,
1...
n
l=0,1...n
l = 0 , 1... n 和
(
l
k
)
\binom{l}{k}
( k l ? )
l
=
0
,
1...
n
l=0,1...n
l = 0 , 1... n 【188-192】随机选择7个点的索引到vec_sample里 【195】根据这7个点,解出F
RelativePoseKernel.hpp 【143-144】根据之前的索引获得对应的点 【146】开始解F Fundamental7PSolver.cpp
【202】求Sampson error 【204-213】如果设置了阈值,那就先筛选并判断阈值内点够吗 【225-233】上面讲的ACRANSAC第4步 【235-252】如果找到就复制出inlier 【258】找不到合适的model 【262】对应找了model和循环已经结束的情况
【264-268】找不到,继续找 【272-277】找到了,在找到的模型中选取点再来一次 【289】将F unnormalize,参考上文 返回,得到内点 【160】copyInlierMatches函数,由于【107】把所有描述子类型点放进去了,因此需要根据index对应的类型 【163】计算(在sift例子下)0.14*内点数是否大于7(如果是求F) guidedmatching:之前得到了F,对于一个pair,两个图片下的特征点,利用F,得到一个error(guidedMatching.hpp 【260】),如果小于阈值,计算这两个点之间的距离,和之前一样(第一近的距离除以第二近的距离,越小越好),小于阈值这加入matches 如此,就得到最终的matches了 【556-606】gridFiltering,如果设置了最大特征点数目numMatchesToKeep 则需要选取的特征点足够分散。将图片划分成一个网格,类似于亚像素,然后依次,每个网格提取一个(每个网格可能有多个特征点,这样就可以分散特征点了)
【577】将特征点按特征点的scale从大到小排序 【582】matchesGridFiltering:(默认的是3*3网格,以此为例)
【77-80】算出每一个网格的长宽 【82】左右图各保留3*3的网格空间,因此乘以2 【84-87】假设有90个特征点,则每个网格可以储存5个。因为有左右两图,有9个网格,所以一共存储52 9=90个 【91-103】根据x y 得到grid的坐标,【99-100】代码应该有错,最大值可以设置gridSize*gridSize-1 【105-112】先把match储存在前面,如果有重复则放后面 【129-139】精华部分,注意里面的循环依次扫描网格,最外层的是每个网格里面匹配点的编号,也就是前面说的:然后依次,每个网格提取一个(每个网格可能有多个特征点,这样就可以分散特征点了) 【609】保存match
主要函数saveTxt,先保存pair的编号,再保存pair有几种类型的描述子,之后是这个类型名称和这个类型下描述子个数,最后就是这些匹配点的编号
文章来源:https://blog.csdn.net/m0_46598929/article/details/126493123
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:chenni525@qq.com进行投诉反馈,一经查实,立即删除!