openMVG--IncrementalSFM
0、pre
- SFM综述—对应4种方法
- incrementalSFM bacic pipeline:Photo Tourism: Exploring Photo Collections in 3D(阅读笔记)
- openMVG对应两个IncrementalSFM的实现
1、V1
1.1、算法简介
- 论文参考:Adaptive Structure from Motion with a contrario model estimation(阅读笔记)
1.2、具体步骤及实现
1.2.1、选择initial
1.2.1.1. 由用户自己选择
输入initial pair(官方解释)
1.2.1.2. default:选择baseline较大的pair
baseline衡量指标:同名光线夹角(采用不同同名点间形成的射线夹角 中值 )
- 计算同名光线夹角:
- 计算原理
将image point坐标从像素坐标(相平面坐标)转为像空间坐标(利用内参矩阵K),再转为世界坐标(利用相机R\T) 将camera position坐标由像空间坐标转为世界坐标(利用相机R\T) 生成ray,并计算三维空间向量夹角(示意图如下)
重点:涉及坐标转换、空间坐标系的统一
- 计算步骤:{pose I, poseJ} — E -----relative Pose—计算同名光线夹角
- 代码实现:
// x = (u, v, 1.0) // image coordinates
// X = R.t() * K.inv() * x + C // Camera world point
// getting the ray:
// ray = X - C = R.t() * K.inv() * x
由函数AngleBetweenRay()实现
1.2.2、Initial pair选择后的操作
- E—relative pose
- Ac-ransac
- BA
- intrinsic constant
- 初值:
landmarks:(P = K\R\T)Triangulate --3d landmarks(outlier + inlier)
- save inlier 3d landmarks to sfm_data
inlier判断条件:同名光线夹角、手性(landmark 位于相机前方)、重投影误差
1.2.3、Add remain images
1.2.3.1、priciple
M+ 0.75M(s)
Select the image I that share the most of correspondences. Then keep all the images that have at least: 0.75correspondences(I) common correspondences to the reconstruction.
实质:得到resectionGroupIndex,按组(含多张image)添加view
1.2.3.2、代码实现
- 接口函数:
bool SequentialSfMReconstructionEngine::FindImagesWithPossibleResection(
std::vector<uint32_t> & vec_possible_indexes)
1.2.4、Add remain images后的计算
1.2.4.1、resection
- 具体内容:
-
compute pose
采用三角化计算pose(localization)时,需check三角化的结果是否满足精度要求
-
refine added poses : intrinsics constant
-
tracks 处理:
已计算的tracks:该view作为此track新的observation;
未计算的tracks:在满足三角化计算条件
的前提下,计算初值
Ps: 三角化计算条件:
该track的observation views包含已添加到scene中的view id
- 代码实现
- 接口函数:
bool SequentialSfMReconstructionEngine::Resection(const uint32_t viewIndex)
- 核心代码:
Ps:
resection method (dafult):resection::SolverType::DLT_6POINTS
1.2.4.2、 BA–每组resectionGroupIndexBA一次
BA前提:有效pose数据达到一定阈值(default: 100)
1.2.4.3、Reject bad tracks-remove pose、landmarks、observation
- 针对sfm_data中的所有tracks
- remove pose\observation
Remove observation和 pose的指示条件:
- observation:与其对应view的pose未解算(未加入到sfm_data)
伴随的另一个remove操作--landmarks:
min_points_per_landmark(landmark至少需要的观察点数目,不满足则remove the landmark)
- pose: pose对应view所产生的observation数目// If usage count is smaller than the threshold, remove the Pose
- 接口函数:
1.2.5、循环1.2.3-1.2.4
得到新的vec_possible_indexes并计算
1.2.6、Reject bad tracks
循环1.2.3-1.2.4操作,add resectionGroupIndex后: 再次执行Reject bad tracks
2、V2
2.1、算法简介
2.2、具体步骤及实现
2.2.1、Init the reconstruction with a seed
2.2.1.1、Seed选择的方法
default:
std::string sSfMInitializer_method = "STELLAR";
2.2.1.2、 STELLAR(default)
的具体实现
- 接口函数:
bool SfMSceneInitializerStellar::Process()
- 核心函数(使用两次):
find_largest_stellar_configuration(
relative_pose_pairs,
matches_provider_,
selected_stellar_pod)
largest
: the StellarPod has the most matchesstellar configuration :using StellarPods = Hash_Map<IndexT, Pair_Set>;
//{index:view id, pair set:与该view相关的pair}
- 对largest _stellar_configuration(StellarPod)的进一步计算–是否solvable
- 针对每一个2 nodes edge,是否可以构建理想的tiny scene
- 融合每个edge三角化结果,得到尺度统一的tiny scene
重点:relative scale计算:
1)Relative scale计算原理 ----采用所有common track计算得到的depth ration序列的中值 Median进行计算
2)depth ratio计算原理:
根据StellarPod 内部的2 edges(与common nodes相关),对应的两视图,进行三角化,计算common track在该局部坐标系(以center pose 为原点的相机坐标系,不同pair尺度不同)下的深度(深度的表示方式-Vector: center pose –common track )
对于该vector,其在在不同尺度坐标系下,不同长度,可根据比值计算坐标系的尺度ratio,即depth ratio,并进一步得到尺度统一的三角化结果
3)depth ratio代码实现
核心函数:见下,得到track 在局部空间坐标系下的三维坐标
bool TriangulateNViewAlgebraic
(
const Mat3X & points,
const std::vector<Mat34> &poses,
Vec4 *X
)
4)//some 2-uplet cannot lead to a relative scale if they don’t share a sufficient track amount
原因:
// If there is insufficient 3-view track count,
// We reject this triplet, since the relative scale factor cannot be reliably computed.
代码:
if (tracksBuilder.NbTracks() < 15) { return false; }
4)进一步基于depth ration(scale) 调整StellarPod内部,使其统一(以center pose 为原点的统一三维空间相机坐标系)
/// Solve the relative scale to a common coordinate system
/// Since ratios of depth are used, the found solution is an approximation
/// Solving equation (4) from “Global Structure-from-Motion by Similarity Averaging"
/// Zhaopeng Cui and Ping Tan. (ICCV 2015).”
论文对应函数:Inline bool Solve_stellar_translation_scales_averaging()
核心: Tj = Rij * Ti + scale* t_ij
2.2.2、 localize some cameras in the reconstruction
2.2.2.1、Add pose -Triangulation
// Incrementally estimate the pose of the cameras based on a confidence score.
// The confidence score is based on the track_inlier_ratio.
// First the camera with the most of 2D-3D overlap are added then we add
// ones with lower confidence.
Add pose的具体细节:
根据track_inlier_ratios = {0.2, 0.0} 设定的两个批次的阈值,在每个阈值下,循环添加满足条件的pose group,一个group BA一次,并保存ply结果,并检查是否则进入下一个阈值批次
进入下一个阈值批次的条件:
- 满足条件的pose group不为空
- resection后pose的计算结果 满足精度要求
- location后的操作后,有效pose数目较先前增加:
代码实现:
// Stop if no cameras have been added
// Note: some cameras could have been removed due to instable camera positions.(见2.2.2.2)
const IndexT pose_after = sfm_data_.GetPoses().size(); if (pose_before >= pose_after) break;
2.2.2.2、Bundle Adjustment and cleaning
相关操作:
2.2.3、Final bundle Adjustment
略