目录
Open_MVG是什么?
OpenMVG是一个强大的多视角立体几何库,它提供了一套丰富的接口和功能,用于解决多视角立体几何的精准匹配问题,并提供了一系列SfM需要用到的特征提取和匹配方法。主要作用是用来构建稀疏点云,可以搭配MVS构建稠密点云,最后使用meshlab网格化,纹理贴图等等...
核心功能
- OpenMVG实现了基于多视图像的稀疏重建,其SfM pipeline包括四个基本过程:图片文件的整理、图像描述子计算、图片对应点计算以及运动恢复结构的解算(光束法平差)。
- 它还支持GPS辅助的空三测量和含控制点的SFM。
- OpenMVG还包含了完整的SfM工具链,包括校正、参估、重建和表面处理等步骤。
技术特点
- OpenMVG信奉“简单,可维护”的原则,其代码具有良好的可读性,方便开发者进行二次开发。
- 它与其他库(如CMVS-PMVS)相结合,可以实现从原始图像到稀疏点云、稠密点云、重建表面和纹理映射的完整多视图三维重建管线。
SFM_Data 数据结构:
struct SfM_Data
{
Views views; /// 储存影像物理性质、索引号等基本信息
Poses poses; /// 储存影像外参数,包括旋转矩阵、平移矩阵
Intrinsics intrinsics; /// 储存影像内参数,支持多组不同内参数
Landmarks structure; /// 物方点信息,物方点坐标及其tracks
Landmarks control_points; ///控制点信息
std::string s_root_path; /// 根视图路径
}
View views:
- 这是一个容器,用于存储关于图像或视图的元数据。每个视图通常包含其文件名、索引、尺寸、拍摄时间等物理性质信息。
Pose poses:
- 这也是一个容器,用于存储每个视图的相机姿态(外参数)。每个姿态通常由一个旋转矩阵和一个平移向量组成,它们定义了相机在世界坐标系中的位置和朝向。
Intrinsics intrinsics:
- 用于存储相机的内参数。内参数定义了相机的几何和光学特性,例如焦距、主点位置、畸变系数等。
OpenMVG
支持多组不同的内参数,以适应具有不同相机参数的多个视图。
Landmarks structure:
- 用于存储重建的3D点(物方点)的信息。每个物方点通常与多个视图相关联,这些视图通过特征匹配或跟踪算法检测到该点。这个结构还包含物方点的三维坐标以及与之相关联的视图索引(或称为tracks)。
Landmarks contrlol_points:
- 这与
structure
类似,但专门用于存储控制点信息。控制点通常是已知其精确三维位置的点(例如通过GPS或手动测量获得),它们用于提高SfM过程的精度和鲁棒性。
string s_root_path:
- 这是一个字符串,表示根视图路径。这通常用于确定输入图像文件的相对或绝对路径,以便在后续处理中加载这些图像。
SFM的基本步骤
1. 构建配置文件(JSON文件)
sfm_data.json,代码如下所示:
{
"sfm_data_version": "0.3",
"root_path": "images",
"views": [
{
"key": 0,
"value": {
"polymorphic_id": 1073741824,
"ptr_wrapper": {
"id": 2147483649,
"data": {
"local_path": "",
"filename": "100_7100.JPG",
"width": 2832,
"height": 2128,
"id_view": 0,
"id_intrinsic": 0,
"id_pose": 0
}
}
}
},
{
"key": 1,
"value": {
"polymorphic_id": 1073741824,
"ptr_wrapper": {
"id": 2147483650,
"data": {
"local_path": "",
"filename": "100_7101.JPG",
"width": 2832,
"height": 2128,
"id_view": 1,
"id_intrinsic": 0,
"id_pose": 1
}
}
}
},
],
"intrinsics": [
{
"key": 0,
"value": {
"polymorphic_id": 2147483649,
"polymorphic_name": "pinhole_radial_k3",
"ptr_wrapper": {
"id": 2147483660,
"data": {
"width": 2832,
"height": 2128,
"focal_length": 2884.2617914205145,
"principal_point": [
1416.0,
1064.0
],
"disto_k3": [
0.0,
0.0,
0.0
]
}
}
}
}
],
"extrinsics": [],
"structure": [],
"control_points": []
}
从代码中可以看出,views中包含了包含了多个视图(即多张图像)的信息。每一个视图都是一个字典,由key和value构成,key的值一般是从0开始依次递增,假如有5张图片,那么最后一张图片key的值为4。
values中包括了一些标识符, 图像的本地路径(local_path),图像的文件名(filename),图像的宽度和高度(
width
和height
),与该视图关联的相机内参的标识符(id_intrinsic),与该视图关联的相机姿态的标识符(id_pose)...
openMVG_main_SfMInit_ImageListing
-d ../openMVG/src/openMVG/exif/sensor_width_database/sensor_width_camera_database.txt \
-i ../openMVG_Build/image_datasets/ImageDataset_SceauxCastle/images \
-o ../openMVG_Build/image_datasets/ImageDataset_SceauxCastle/matches
-d 传感器宽度数据集
-i 图片数据集
-o sfm_data.json主要包括两部分:views(一张图片对应一个view)和intrinsics信息(相机内参数)
2. 提取特征
主要是对每张影像进行特征提取与特征描述,输出.feat和.desc特征文件和特征描述子文件,还有一个特征描述子json文件,默认使用的是SIFT算子,特征描述子json文件如下:
{
"image_describer": {
"polymorphic_id": 2147483649,
"polymorphic_name": "SIFT_Image_describer",
"ptr_wrapper": {
"valid": 1,
"data": {
"params": {
"first_octave": 0,
"num_octaves": 6,
"num_scales": 3,
"edge_threshold": 10.0,
"peak_threshold": 0.03999999910593033,
"root_sift": true
},
"bOrientation": true
}
}
},
"regions_type": {
"polymorphic_id": 2147483650,
"polymorphic_name": "SIFT_Regions",
"ptr_wrapper": {
"valid": 1,
"data": {
"value0": [],
"value1": []
}
}
}
}
从代码中可以看出,文件主要分为两部分,image_describer和regions_type,在regions_type中的polymorphic_name,这是区域类型的名称,表示它是使用SIFT算法来提取图像区域的,在这里,它的值是
SIFT_Regions
。
openMVG_main_ComputeFeatures
-i ../openMVG_Build/image_datasets/ImageDataset_SceauxCastle/matches/sfm_data.json
-o ../openMVG_Build/image_datasets/ImageDataset_SceauxCastle/output/matches
-i:用于sfm计算的数据结构,也就是前面那一步输出的sfm_data.json文件
-o: 输出.feat和.desc的目录
3. 匹配点集
计算图像之间的两两匹配对,主要有两种方式:
1. 暴力匹配
2. 顺序匹配
代码中定义的匹配模式如下图所示:
enum EPairMode
{
PAIR_EXHAUSTIVE = 0, // 每一张图片都和其他图片一一匹配(默认)
PAIR_CONTIGUOUS = 1 // 只有相邻的图片才进行匹配
};
openMVG_main_PairGenerator
-i ../openMVG_Build/image_datasets/ImageDataset_SceauxCastle/matches/sfm_data.json
-o ../openMVG_Build/image_datasets/ImageDataset_SceauxCastle/pairlist
4. 特征匹配
- 读取图像的特征点描述子(通常由 openMVG_main_ComputeFeatures 生成)。
- 使用特征描述子进行特征点之间的匹配,通常基于最近邻搜索。
- 输出匹配的特征点对和相关的数据(如匹配得分)
openMVG_main_ComputeMatches
-i ../openMVG_Build/image_datasets/ImageDataset_SceauxCastle/matches/sfm_data.json \
-o ../openMVG_Build/image_datasets/ImageDataset_SceauxCastle/matches/output
5. 匹配过滤
关键步骤如下:
- 加载视图图像描述(区域: features & descriptors):
这一步骤涉及读取每幅图像中提取的特征点(通常是关键点,如SIFT、SURF、ORB等)及其对应的描述符。
- 计算假定的局部特征匹配(描述符匹配):
这一步骤使用描述符来找到图像之间的初步匹配。这通常是通过比较一个图像中的描述符与另一个图像中的所有描述符,并找到最近邻来实现的。这会产生一个初步的匹配集合,但其中可能包含大量的错误匹配。
- 计算几何相干特征匹配(从假定匹配中进行鲁棒模型估计):
- 一致性检验:如果有多幅图像,可以检查匹配在多个视图之间是否保持一致。
- 比率测试:对于每个特征点,不仅查找最近邻的描述符,还查找次近邻。如果最近邻与次近邻之间的距离比率小于某个阈值(例如0.8),则保留该匹配。
- 随机抽样一致性(RANSAC):用于从包含外点的数据集中估计数学模型的参数。在特征匹配中,RANSAC可以用于估计两幅图像之间的单应性(Homography)或基本矩阵(Essential Matrix),并只保留那些与估计模型一致的匹配。
- 双向匹配:检查匹配是否是双向的,即如果点A在图像1中的最佳匹配是点B,那么点B在图像2中的最佳匹配也应该是点A。
openMVG_main_GeometricFilter
-i ../openMVG_Build/image_datasets/ImageDataset_SceauxCastle/matches/sfm_data.json
-m ../openMVG_Build/image_datasets/ImageDataset_SceauxCastle/matches.putative.bin
-o ../openMVG_Build/image_datasets/ImageDataset_SceauxCastle/matches/matches.f.bin
6. SFM
在这里主要有两种SFM方法,增量式和全局式.
输入参数:
-i // 输入路径
-m // 匹配文件夹路径
-M // 匹配的文件
-o // 输出路径
-s // 可以为如下形式 INCREMENTAL 增量式 GLOBAL 全局式
-f // 优化内参配置
-e // 优化外参配置
-P // 使用先验信息 GPS
// 增量式sfm的选项:
-t // 三角化方法
-r // 重定位方法
-c // 相机模型
openMVG_main_SfM
-i ../openMVG_Build/image_datasets/ImageDataset_SceauxCastle/matches/sfm_data.json \
-m ../openMVG_Build/image_datasets/ImageDataset_SceauxCastle/matches/\
-o ../openMVG_Build/image_datasets/ImageDataset_SceauxCastle
/out_Incremental_Reconstruction/\
-s INCREMENTAL
那先简单介绍到这,后续会对每个步骤的代码逻辑进行详细介绍