Bundler源码研读笔记

 以下都是按照默认options设置执行的流程:

 在根据几个样本点来计算时都先对数据点进行了归一化操作,引入的根号2缘由是?

1.进入BundlerApp::BundleAdjustFast(),最高层函数调用,快速之意应该是使用了sba;

2./* Compute epipolar geometry between all matching images */
void BundlerApp::ComputeEpipolarGeometry(bool removeBadMatches,    int new_image_start)

ComputeEpipolarGeometry(i, j, removeBadMatches);/* Compute epipolar geometry between a given pair of images */

/* Estimate an F-matrix from a given set of point matches */
std::vector<int> EstimateFMatrix(...)

/* Use RANSAC to estimate an F-matrix */
int estimate_fmatrix_ransac_matches(...)

起始随机选择8个种子点作为计算,计算出F之后统计inlier的比率小于0.95就重新选择种子点计算

/* Use linear least-squares to estimate the fundamantal matrix */
int estimate_fmatrix_linear(...)

  /* Solve for the least-squares solution to the F-matrix */

dgesv_driver(num_pts, A, b, X);

fmatrix_compute_residual(double *F, v3_t r, v3_t l)//前面在所选8个样本点计算出的F满足阈值约束,我们就可以以此剔去一些极少数的outlier,这时置信度是相当高的,随机选择样本试探的过程中并不剔除outlier而只是统计inlier比率以判别种子点选取的合理性;

/* Re-estimate using inliers */  此时应用所有筛选过的点进行计算

/* Refine an F-matrix estimate using LM */ 此时使用的点远大于8个属于超定方程组,使用非线性最小二乘法LM求解

 refine_fmatrix_nonlinear_matches(num_inliers, k2_pts_in, k1_pts_in,  F0, F);

在计算出得基础矩阵的基础上在计算一次inlier,这次检测出得outlier才彻底从匹配结果集合中剔除


/* Compute rigid transforms between all matching images */

void BundlerApp::ComputeTransforms()    //应该是计算两张图像的单应矩阵

/* Compute a transform between a given pair of images */
bool BundlerApp::ComputeTransform(int idx1, int idx2, bool removeBadMatches)

/* Estimate a transform between two sets of keypoints */
std::vector<int> EstimateTransform(...)

/* Computes the homography that, when applied to the points in l_pts, minimizes the least-squares error between the result and the corresponding points in r_pts.
void align_homography(int num_pts, v3_t *r_pts, v3_t *l_pts, double *Tout, int refine) 

/* Use non-linear least squares to refine a homography */
void align_homography_non_linear(int num_pts, v3_t *r_pts, v3_t *l_pts, double *Tin, double *Tout) 

这里选样本点ransac计算与前面不同,前面只要inlier达到阈值0.95即可,这里是计算nransac次(256),也许是因为这里使用前者比较难收敛,进而采取相对保守一点的策略;


void align_homography(int num_pts, v3_t *r_pts, v3_t *l_pts, double *Tout, int refine) //使用前面计算出的最大inlier作为初始值,所有inlier点用最小二乘法计算出优化单应矩阵(都是样本试探挑选出置信度高的点集然后用一次最小二乘优化解)

注:计算单应矩阵最后的inlier比例不高,不剔除不在最终inlier中的匹配,而在基础矩阵里是当做outlier去掉的;

pairwise_scores.txt中存储的是两张图片中计算符合单应矩阵的匹配点比例



以上为总体的匹配调用流程,后续进行track生成(两张图片间的double match一开始就剔除了)

注:生成track基于的特征匹配集合不是初始数据集,而是计算几何信息之后得到的可以计算的匹配对

生成track的大致步骤如下:

 sort(list.begin(), list.end(), CompareFirst);//对每一个图片对的特征匹配按照第一元素的编号排序,排序的目的自然是为了进行的后续的二分查找,生成track使用的是宽度优先搜索(总体上是一个四层循环以及使用队列,四层依次为:图片编号-》特征编号-》搜索的相邻图片编号-》搜索的特征编号),生成的过程中需要检测出错误的链(同一张图片中的两个特征在同一track中),但实际的生成过程是分开进行的(杂糅在一起处理起来也不合理),第一步只是对每一张图片的每一个特征作为种子点进行深度优先搜索,并且搜索的时候使用标记不重复访问同一张图片;使用不同图片的特征作为遍历起始点就可以获得双向匹配检验的信息,因此可以对最后的结果进行处理检测一致的track;

p = equal_range(list.begin(), list.end(), dummy, CompareFirst);          //STL的二分查找函数

因为查找的时候涉及的图片数可能会很多,对每一次查询都全部复位运算量太大,使用touched数据结构标记每一张被访问过的图片,使得可以保证生成track的过程中不会重复考虑同一张图片,并且可以根据此信息有选择的将标记数据结构复位;

最后将生成的track信息分派到关联的图片  ,只要有一个track就标记相关图片为neibours  /* Create the new consistent match lists */


匹配过程基本到此为止了,似乎没发现track一致性检验步骤,采用了保守的逃避矛盾信息(一张图片只访问了一次,有点鸵鸟算法的意思)

困惑:写入constrains.txt文件中的F矩阵都是全0,而单应矩阵全部有数据(部分不是标准形式,没有经过计算得出)


下面进入Bundle Adjustment的步骤,采取的迭代式计算方案,先计算两张图片的SFM,后面再迭代式加入新的图片和三维点,两张初始图片的SFM计算过程如下:

首先挑选出strong initial pair

/* Pick a good initial pair of cameras to bootstrap the bundle adjustment */
void BundlerApp::BundlePickInitialPair(...)


计算Relative Pose也是使用5点算法,

/* Estimate relative pose from a given set of point matches */
int EstimatePose5Point(...)





3.

你可能感兴趣的:(数据结构,算法,优化,image,Matrix,pair)