OpenMVG学习笔记

一直基于OpenMVG在做算法移植,在此梳理一下OpenMVG的主要源码,边学边补充。

openMVG主要的模块有openMVG_Libraries、openMVG_Samples和software。

1. openMVG:

  1.1. cameras:cameras — openMVG library

    一些相机模型:针孔、带畸变、鱼眼

  1.2. image:image — openMVG library

    主要有图像读写,格式转换,卷积,重采样,滤波,绘制等操作。

  1.3. numeric:numeric — openMVG library

    Eigen库对矩阵和向量的支持以及线性代数算法。

  1.4. features:features — openMVG library

    特征点akaze/fast/tbmr/sift和描述子dipole/liop

  1.5. multiview:multiview — openMVG library

    2D-2D 对极几何、N-view 三角化 旋转估计 平移估计、E/F/H模型、PNP问题

  1.6. linear programming:linear programming — openMVG library

    线性优化问题

  1.7. robust estimation:robust_estimation — openMVG library

    鲁棒模型估计 Max-Consensus/Ransac/LMeds/AC-Ransac

  1.8. matching:matching — openMVG library

    特征匹配方法Nearest neighbor search、K-Nearest Neighbor;

    匹配规则:欧氏距离、汉明距离

    匹配对过滤:Symmetric distance(A->B & B->A)、“Nearest Neighbor Distance Ratio” distance check(0.6~0.8)、K-VLD Filter (K-Virtual Line Descriptor)

  1.9. tracks:tracks — openMVG library

    特征追踪,和光流追踪类似吗?

  1.10. geometry:geometry — openMVG library

    相机的Pose3,Box,ConvexHull,7DoF刚体变换

  1.11. geodesy:geodesy — openMVG library

    经纬度高程(latitude,longitude,altitude)转地心地固坐标系(X,Y,Z)、

    经纬度高程(latitude,longitude,altitude)转UTM投影(x,y)

  1.12. sfm:sfm — openMVG library

    最主要的、最重要的一个库,包含了SfM_Data 和 SfM pipelines

  1.13. system:

    logger、progress、timer

  1.14. graph:

    一些图相关的内容,连通关系、三段式连接?

  1.15. exif:

    提取图片的EXIF信息(相机型号、GPS信息、拍摄信息等)

  1.16. matching_image_collection

    对图像集合中的假定对应关系进行局部匹配和几何过滤的功能。

2. openMVG_Samples:

  2.1. cameras_undisto_Brown:

  openMVG_sample_cameras_undistoBrown.exe,图像去畸变。在openMVG/cameras/Camera_undistort_image.hpp中,有两种去畸变的函数,一个是 UndistortImage(去畸变后的图像与原图尺寸一样,用空值来填充没有像素的地方),另一个是UndistortImageResized(去畸变后的图像尺寸与原图不一致,是一个box范围)。

  2.2. describle_and_match_GUI:

  openMVG_sample_describe_and_match_GUI.exe,打开图像匹配的GUI界面,可以显示图像匹配的结果。主要使用了QT来做界面。

   2.3. exif_Parsing:

  openMVG_main_exif_Parsing.exe,查看图片的EXIF信息,只输出 width、height、focal、brand、model 这几个信息而已。

   2.4. features_affine_demo:

  openMVG_sample_features_affine.exe,局部不变特征检测 MSER TBMR,是两种区域特征检测子,和Harris这种角点一样,也是用来做图像特征检测的,不过这种区域特征是另一个层面的图像特征。

  2.5. feature_image_matching:

  openMVG_sample_image_matching.exe,图像特征匹配,主要是输出匹配结果到SVG,可以用来参考一下。

  2.6. feature_image_matching_gmsfilter:

  openMVG_sample_image_matching_gmsfilter.exe,使用gms对匹配点对进行过滤,并输出到SVG。参考论文:GMS: Grid-based Motion Statistics for Fast, Ultra-robust Feature Correspondence.

  2.7. features_kvld_filter:

  openMVG_sample_features_kvld.exe,使用KVLD对匹配点对进行过滤,并输出到SVG。参考论文:Virtual Line Descriptor and Semi-Local Graph Matching Method for Reliable Feature Correspondence.

  2.8. features_repeatability:

  openMVG_sample_main_features_repeatability_dataset.exe,利用openMVG官方的数据集,测试特征的的可重复性。数据集中有一系列多角度拍摄的同一场景的图像,多张图像提取的特征点数基本一样,证明了特征的可重复性。

  2.9. features_siftPutativeMatches:

  openMVG_sample_features_siftPutative.exe,SIFT特征提取匹配+按距离过滤。

  2.10. geodesy_show_exif_gps_position:

  openMVG_sample_geodesy_show_exif_gps_position,读取一个文件夹内所有图像的GPS信息,并输出为.ply文件,文件内保存的是ECEF坐标系坐标。

  2.11. image_spherical_to_cubic、 image_spherical_to_pinholes:

  openMVG_sample_pano_spherical_to_cubic.exe、openMVG_sample_pano_converter.exe, 将全景图转为其他格式。

  2.12. image_undistort_gui:

  openMVG_sample_image_undistort.exe,图像去畸变的GUI,调用的是UndistortImageResized函数,去畸变后的图像与原图尺寸不一样。

  2.13. multiview_robust_essential、essential_ba、essential_spherical、estimation_tutorial、fundamental、fundamental_guided、homography、homography_guided

  这几个都是多视几何的变换矩阵估计,E/F/H

3.software:

  3.1. ColorHarmonize:Color Harmonization — openMVG library

  openMVG_main_ColHarmonize.exe,一个场景采集多张图像,由于拍摄角度和曝光的差异,图像之间存在整体的色差,为了保证整体色彩的一致性,需要进行颜色统一。主要思路是先通过匹配关系找到图像之间的公共色彩信息,然后选择一个参考颜色,对所有的图进行色彩变换。会建立一个符合所有影像的色彩直方图,对影像进行色彩线性拉伸,使得整体色彩最小化。

  3.2. Geodesy:Geodesy: Usage of GPS prior — openMVG library

  openMVG_main_geodesy_registration_to_gps_position.exe,Geodesy主要用来进行坐标转换的,GPS得到的经纬度高程需要转为ECEF系的XYZ或UTM的投影坐标。而且,GPS信息可以有两个用途,一是用来加速匹配,只对临近的图像进行匹配;另外是可以对SFM的结果进行一个七参数刚体变换(ApplySimilarity(sim, sfm_data);),把SFM进行坐标系的对齐。

  3.3. Localization:

  openMVG_main_SfM_Localization.exe,用来定位某影像在sfm场景的位置。需要预先跑出一个sfm场景,然后确定某影像在该场景内的位置。

  3.4. SfM:

  • openMVG main ChangeLocalOrigin.exe。对sfmdata的场景进行坐标平移变换,通过Sim变换得到新的原点场景。

  • openMVG main ComputeSfM DataColor.exe。对sfmdata的structure进行色彩赋值,主要函数 src\openMVG\sfm\sfm_data_colorization.cpp\ColorizeTracks

  • openMVG main ComputeClusters.exe。对sfmdata的数据进行聚类分区,空三分区GetSubView可以借鉴一下。

  • openMVG main ComputeFeatures.exe。特征提取。

  • openMVG main ComputeMatches.exe。特征匹配。

  • openMVG main ComputeStructureFromKnownPoses.exe。从已知pose的sfmdata和图像匹配关系来恢复场景内的3D结构。

  • openMVG main ComputeVLAD.exe。VLAD是一种图像检索算法,具体可以参考链接: VLAD算法简介_o3279的博客-CSDN博客_vlad 可以输出图像匹配的邻接矩阵。

  • openMVG main ConvertList.exe。将openMVG v0.x(x=>7) 的lists.txt文件转换为SfM_Data文件格式(v0.8),导出的SfM_Data文件包含view和intrinsic。

  • openMVG main ConvertMatches.exe。Convert matches from bin to txt or txt to bin

  • openMVG main ConvertSfM DataFormat.exe。将sfmdata转为其他形式(.json, .bin, .xml, .ply, .baf)保存。

  • openMVG main evalQuality.exe。与真实轨迹对比,评测openmvg的解算轨迹与ground truth的差异,用在VO里比较多。

  • openMVG main FrustumFiltering.exe。根据相机的成像视角对sfmdata中的匹配相机对进行过滤。

  • openMVG main GeometricFilter.exe。利用几何一致性对匹配点对进行过滤,比如E/F/H矩阵。

  • openMVG main ListMatchingPairs.exe。列出匹配相机对,有三种模式:一是逐一对应匹配,二是根据最邻近n个id来匹配,三是根据GPS位置来匹配邻进n个,并将匹配对邻接矩阵输出为SVG图。

  • openMVG main MatchesToTracks.exe。根据图像特征点匹配关系构建特征点的跟踪属性,某一个特征点在哪些图像上有对应的匹配,即存在跟踪属性。

  • openMVG main MatchingRetrievalQuality.exe。评价匹配点对的质量。

  • openMVG main PairGenerator.exe。生成匹配相机对,与 ListMatchingPairs联合使用。
  • openMVG main PointsFiltering.exe。对三维点进行过滤,滤掉深度太大的离群点。

  • openMVG main sfM.exe。主流程,以下详细介绍。

根据OPENMVG_LOG_INFO来分析sfm的一些配置和方法。

 1 OPENMVG_LOG_INFO << "Usage: " << argv[0] << '\n'
 2       << "[Required]\n" // 必要参数:
 3       << "[-i|--input_file] path to a SfM_Data scene\n" // sfmdata 的存放地址
 4       << "[-m|--match_dir] path to the matches that corresponds to the provided SfM_Data scene\n" // 场景的特征匹配结果存放的路径
 5       << "[-o|--output_dir] path where the output data will be stored\n" // 输出路径
 6       << "[-s|--sfm_engine] Type of SfM Engine to use for the reconstruction\n" // sfmdata的引擎类型,有以下3种:
 7       << "\t INCREMENTAL   : add image sequentially to a 2 view seed\n" // 增量式版本1,以 2 view seed 为基准
 8       << "\t INCREMENTALV2 : add image sequentially to a 2 or N view seed (experimental)\n" // 增量式版本2,以 2 or N view seed 为基准
 9       << "\t GLOBAL    : initialize globally rotation and translations\n" // 全局式
10       << "\n\n"
11       << "[Optional parameters]\n" // 可选参数:
12       << "\n\n"
13       << "[Common]\n"
14       << "[-M|--match_file] path to the match file to use (i.e matches.f.txt or matches.f.bin)\n" // 可用匹配文件
15       << "[-f|--refine_intrinsic_config] Intrinsic parameters refinement option\n" // 相机内参平差的配置
16       << "\t ADJUST_ALL -> refine all existing parameters (default) \n" // 所有内参均被优化
17       << "\t NONE -> intrinsic parameters are held as constant\n" // 内参保持不变,不被优化
18       << "\t ADJUST_FOCAL_LENGTH -> refine only the focal length\n" // 仅优化焦距
19       << "\t ADJUST_PRINCIPAL_POINT -> refine only the principal point position\n" // 仅优化像主点
20       << "\t ADJUST_DISTORTION -> refine only the distortion coefficient(s) (if any)\n" // 仅优化畸变参数
21       << "\t -> NOTE: options can be combined thanks to '|'\n" // 以上参数可以用 | 连接
22       << "\t ADJUST_FOCAL_LENGTH|ADJUST_PRINCIPAL_POINT\n"
23       <<    "\t\t-> refine the focal length & the principal point position\n"
24       << "\t ADJUST_FOCAL_LENGTH|ADJUST_DISTORTION\n"
25       <<    "\t\t-> refine the focal length & the distortion coefficient(s) (if any)\n"
26       << "\t ADJUST_PRINCIPAL_POINT|ADJUST_DISTORTION\n"
27       <<    "\t\t-> refine the principal point position & the distortion coefficient(s) (if any)\n"
28       << "[-e|--refine_extrinsic_config] Extrinsic parameters refinement option\n" // 相机外参平差的配置
29       << "\t ADJUST_ALL -> refine all existing parameters (default) \n" // 所有外参均被优化
30       << "\t NONE -> extrinsic parameters are held as constant\n" // 外参保持不变,不被优化
31       << "[-P|--prior_usage] Enable usage of motion priors (i.e GPS positions) (default: false)\n" // 是否使用GPS先验位置信息
32       << "\n\n"
33       << "[Engine specifics]\n"
34       << "\n\n"
35       << "[INCREMENTAL]\n"
36       << "\t[-a|--initial_pair_a] filename of the first image (without path)\n" // 增量式版本1 选择的影像对的第一张影像名,不要带影像存放路径
37       << "\t[-b|--initial_pair_b] filename of the second image (without path)\n" // 增量式版本2 选择的影响对的第二张影像名,不要带影像存放路径
38       << "\t[-c|--camera_model] Camera model type for view with unknown intrinsic:\n" // 相机模型
39       << "\t\t 1: Pinhole \n" // 
40       << "\t\t 2: Pinhole radial 1\n" 
41       << "\t\t 3: Pinhole radial 3 (default)\n"
42       << "\t\t 4: Pinhole radial 3 + tangential 2\n"
43       << "\t\t 5: Pinhole fisheye\n"
44       << "\t[--triangulation_method] triangulation method (default=" << triangulation_method << "):\n" // 三角化算法
45       << "\t\t" << static_cast<int>(ETriangulationMethod::DIRECT_LINEAR_TRANSFORM) << ": DIRECT_LINEAR_TRANSFORM\n" // 直接线性变换
46       << "\t\t" << static_cast<int>(ETriangulationMethod::L1_ANGULAR) << ": L1_ANGULAR\n" // 
47       << "\t\t" << static_cast<int>(ETriangulationMethod::LINFINITY_ANGULAR) << ": LINFINITY_ANGULAR\n"
48       << "\t\t" << static_cast<int>(ETriangulationMethod::INVERSE_DEPTH_WEIGHTED_MIDPOINT) << ": INVERSE_DEPTH_WEIGHTED_MIDPOINT\n" // 逆深度算法(默认版本)
49       << "\t[--resection_method] resection/pose estimation method (default=" << resection_method << "):\n" // 位姿解算算法
50       << "\t\t" << static_cast<int>(resection::SolverType::DLT_6POINTS) << ": DIRECT_LINEAR_TRANSFORM 6Points | does not use intrinsic data\n" // 6点法直接线性变换
51       << "\t\t" << static_cast<int>(resection::SolverType::P3P_KE_CVPR17) << ": P3P_KE_CVPR17\n" // P3P
52       << "\t\t" << static_cast<int>(resection::SolverType::P3P_KNEIP_CVPR11) << ": P3P_KNEIP_CVPR11\n"
53       << "\t\t" << static_cast<int>(resection::SolverType::P3P_NORDBERG_ECCV18) << ": P3P_NORDBERG_ECCV18\n" // 默认版本
54       << "\t\t" << static_cast<int>(resection::SolverType::UP2P_KUKELOVA_ACCV10)  << ": UP2P_KUKELOVA_ACCV10 | 2Points | upright camera\n" // UP2P
55       << "\n\n"
56       << "[INCREMENTALV2]\n"
57       << "\t[-S|--sfm_initializer] Choose the SfM initializer method:\n"
58       << "\t\t 'EXISTING_POSE'-> Initialize the reconstruction from the existing sfm_data camera poses\n" // 根据已知相机位姿初始化
59       << "\t\t 'MAX_PAIR'-> Initialize the reconstruction from the pair that has the most of matches\n" // 根据存在最多匹配的匹配对来初始化
60       << "\t\t 'AUTO_PAIR'-> Initialize the reconstruction with a pair selected automatically\n" // 随机选一对
61       << "\t\t 'STELLAR'-> Initialize the reconstruction with a 'stellar' reconstruction\n" // 选中间那个
62       << "\t[-c|--camera_model] Camera model type for view with unknown intrinsic:\n" // 相机模型
63       << "\t\t 1: Pinhole \n"
64       << "\t\t 2: Pinhole radial 1\n"
65       << "\t\t 3: Pinhole radial 3 (default)\n"
66       << "\t\t 4: Pinhole radial 3 + tangential 2\n"
67       << "\t\t 5: Pinhole fisheye\n"
68       << "\t[--triangulation_method] triangulation method (default=" << triangulation_method << "):\n"
69       << "\t\t" << static_cast<int>(ETriangulationMethod::DIRECT_LINEAR_TRANSFORM) << ": DIRECT_LINEAR_TRANSFORM\n"
70       << "\t\t" << static_cast<int>(ETriangulationMethod::L1_ANGULAR) << ": L1_ANGULAR\n"
71       << "\t\t" << static_cast<int>(ETriangulationMethod::LINFINITY_ANGULAR) << ": LINFINITY_ANGULAR\n"
72       << "\t\t" << static_cast<int>(ETriangulationMethod::INVERSE_DEPTH_WEIGHTED_MIDPOINT) << ": INVERSE_DEPTH_WEIGHTED_MIDPOINT\n"
73       << "\t[--resection_method] resection/pose estimation method (default=" << resection_method << "):\n"
74       << "\t\t" << static_cast<int>(resection::SolverType::DLT_6POINTS) << ": DIRECT_LINEAR_TRANSFORM 6Points | does not use intrinsic data\n"
75       << "\t\t" << static_cast<int>(resection::SolverType::P3P_KE_CVPR17) << ": P3P_KE_CVPR17\n"
76       << "\t\t" << static_cast<int>(resection::SolverType::P3P_KNEIP_CVPR11) << ": P3P_KNEIP_CVPR11\n"
77       << "\t\t" << static_cast<int>(resection::SolverType::P3P_NORDBERG_ECCV18) << ": P3P_NORDBERG_ECCV18\n"
78       << "\t\t" << static_cast<int>(resection::SolverType::UP2P_KUKELOVA_ACCV10)  << ": UP2P_KUKELOVA_ACCV10 | 2Points | upright camera\n"
79       << "\n\n"
80       << "[GLOBAL]\n"
81       << "\t[-R|--rotationAveraging]\n" // 全局旋转估计算法
82       << "\t\t 1 -> L1 minimization\n"
83       << "\t\t 2 -> L2 minimization (default)\n"
84       << "\t[-T|--translationAveraging]:\n" // 全局平移估计算法
85       << "\t\t 1 -> L1 minimization\n"
86       << "\t\t 2 -> L2 minimization of sum of squared Chordal distances\n"
87       << "\t\t 3 -> SoftL1 minimization (default)\n"
88       << "\t\t 4 -> LiGT: Linear Global Translation constraints from rotation and matches\n";
enum class ESfMSceneInitializer // 场景初始化,对应增量式版本2
 2 {
 3   INITIALIZE_EXISTING_POSES, // 根据已有外参来初始化
 4   INITIALIZE_MAX_PAIR, // 根据拥有最多匹配对的一对图像来初始化
 5   INITIALIZE_AUTO_PAIR, //随机选择一个匹配对来初始化
 6   INITIALIZE_STELLAR //选择中心的点构建初始化,※ 式
 7 };
 8 
 9 enum class ESfMEngine //sfm引擎类型
10 {
11   INCREMENTAL, // 增量式版本1,基于2-view seed 不断添加图像的SFM。输入两幅图像的filename,找到这两幅图像在场景内的index,基于这两个图像间的尺度来进行增量式sfm估计
12   INCREMENTALV2, //增量式版本2,初始化参考 ESFMSceneInitializer,其初始化大于2-view,可以有 N-views,而这N-views如何选就看 ESFMSceneInitializer 来定了
13   GLOBAL //全局式
14 };
  • openMVG main SfMlnitlmagelisting.exe。影像初始化,生成sfmdata的view和intrinsic的初始值。会根据图像的EXIF信息提取相机信息,GPS信息,焦距等。如果sfm想使用先验的POS信息,这个函数必不可少。

  • openMVG main SfMlnitlmagelistingFromKnownPoses.exe。

  • openMVG main SplitMatchFilelntoMatchFiles.exe。对sfmdata进行分区,根据匹配关系和链接关系生成多个components。

  • openMVG main ExportCameraFrustums.exe,导出相机的视场锥体。

  

  • openMVG main exportKeypoints.exe,导出特征提取结果。

   

  • openMVG main exporMatches.exe,导出特征匹配结果。

  

  • openMVG main exportTracks.exe。导出特征点追踪结果,也就是同一对匹配点在连续几张图像上的匹配结果。

   第0张图与第1,2,3,4,5张图的匹配点对数量分别是5491,1793,684,311,44.匹配点数在逐渐减少,也就是可追踪的匹配点在减少。

  • openMVG main ExportUndistortedlmages.exe。导出去畸变图像。

  • 将openmvg的结果 sfmdata 转为各种格式,以适配后续的研发
    • openMVG main openMVG2Agisoft.exe
    • openMVG main openMVG2CMPMVS.exe
    • openMVG main openMVG2Colmap.exe
    • openMVG main openMVG2MESHLAB.exe
    • openMVG main openMVG2MVE2.exe
    • openMVG main openMVG2MVSTEXTURING.exe
    • openMVG main openMVG2NVM.exe
    • openMVG main openMVG2openMVS.exe
    • openMVG main openMVG2PMVS.exe
    • openMVG main openMVG2WebGL.exe
    • openMVG main openMVGSpherical2Cubic.exe

  3.5. SfMViewer:

  

  3.6. SfMWebGLViewer:

 

  3.7. ui:

  • ui_openMVG_control_points_registration.exe。可以调出控制点刺点的UI界面,刺点,给控制点输入坐标,然后保存sfmdata,可以再进行一次平差解算。
  • ui_openMVG_MatchesViewer.exe。可视化图形匹配关系的邻接矩阵图。

  3.8. VO:

  • openMVG main VO.exe。里程计。

posted @ 2023-01-06 17:27  Du_huili  阅读(2150)  评论(0编辑  收藏  举报