一直基于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。里程计。