“读一份好源码,就是和许多智慧的人谈话“。
本文记录了笔者学习 openMVG 开源软件的一些初步经验和心得。如果你对计算机视觉和摄影测量有兴趣,需要用到相关技术,这篇文章正好就是你的菜。
全文约4500字,含11副图,阅读时间大约13分钟。
觉得有用可以转发给身边同学、朋友,如有不同意见欢迎在后台留言与我探讨。

整理/撰写: calman

校稿/排版: 迷途兄

测试环境 : Windows 7 64位 + Visual Studio 2015

1 简要介绍

openMVG (open Multiple View Geometry):是一个计算机视觉领域处理多视角立体几何的著名开源库 [1,2],信奉“简单,可维护”,提供了一套强大的接口,每个模块都被测试过,尽力提供一致可靠的体验。软件所针对的基于影像的三维重建任务,在摄影测量、计算机视觉、机器人等领域都有着重要的应用,是近年来热门的无人机、自动驾驶、SLAM等技术的重要组成部分[3,4]。

openMVG能够:

  1. 准确计算多视角立体几何模型;
  2. 提供SfM(Structure from Motion)重建需要的特征提取和匹配方法;
  3. 完整的SfM工具链;

openMVG尽力提供可读性强的代码,方便二次开发,核心库尽可能精简,分成了几个大的模块:

  1. 核心库:各个功能的核心算法实现;
  2. 样例:教你怎么用核心库实现高级算法;
  3. 工具链:也就是连起来用咯(无序影像特征匹配,完整SfM,影像色彩处理);

openMVG由Pierre Moulon 在2010年读博时开始设计,并于2013年在http://github.com网站发布v0.1版本,目前已改进到v1.5版本。GitHub统计数据有60多位contributors,处理252个requests、1184个issues,已成为Structure from Motion、Photogrammetry、3D reconstruction的活跃社区。源码由CMakeList工具组织,支持Windows和Linux系统,主要分为5个部分:

  1. /src/openMVG 是多视图几何(MVG)和SfM的核心库;
  2. /src/openMVG_Samples 展示如何使用核心库实现高级算法,主要涉及相对定向、特征匹配的鲁棒策略等;
  3. /src/software 提供用户使用的软件接口,主要实现了SfM及可视化,视觉里程计(Visual Odometry),地理坐标系转换,UI便于输入控制点数据;
  4. /src/dependencies 依赖库,包括GLFW, OPENEXIF, OSI CLP;
  5. /src/third_party 是底层第三方库,主要有ceres-solver,eigen,fast,stlplus3,jpeg等;

经过简单编译,无论是专业或非专业人员均可利用openMVG重建出一组无序影像的稀疏三维场景或模型。其三维重建的能力已应用于考古软件(Arc-Team [5]),医疗影像服务(Ebrafol [6]),地理信息系统的相关实验室(DHLAB [7])

2 代码分析

核心库的各个模块名称、功能、包含的文件数如下表所示:

2.1 外部第三方库

openMVG不鼓励重复造轮子,部分功能使用了已存在、设计良好的第三方软件库,并附带在openMVG的目录中方便编译和使用。这些库的名称及具体功能如下:

ceres-solver:一个便携式C++库,可用于建模和解决大型复杂的非线性最小二乘问题。cxsparse:为ceres-solver的稀疏矩阵计算提供支持。cmdLine:一个用于处理带有命名参数的C++命令行的轻量级的库。CppUnitLite:处理单元测试的轻量级库。Eigen:用于线性代数,矩阵和矢量运算,数值求解,仅由模板头文件组成的的高级C++库。flann:用于在高维空间中执行快速近似最近邻搜索的库。histogram:计算数据统计分布的轻量级类。htmlDoc:简化HTML数据导出的类。lemonLibrary for Efficient Modeling and Optimization in Networks,一个C ++模板库,为图网络计算提供提供常见的数据结构和算法。progress:用于处理应用程序的进度状态的轻量级类。stlplus3:是为熟悉STL的开发人员提供的可重用C++组件的集合。仅使用file_system组件:提供了一组独立于操作系统的文件和文件夹处理函数。jpeg/png/tiff/zlib:处理图像输入、输出,文件压缩的库。

2.2 代码特点

  • 丰富的代码测试。在正常代码之外,有不少文件("*_text.cpp")专门对算法进行测试,值得学习;
  • 多数情况下hpp头文件负责声明和具体实现。少数情况下hpp负责声明,cpp文件负责实现;
  • 详细的代码注释和参考文献注解。方便读者找到算法出处,了解算法原理;
  • C++ 11标准,用到了auto变量类型自动推导,简化for循环遍历;
  • 用到了标准模板类库STL常用数据结构array、vector、list等;
  • 用到了C++语言里的template模板,inline内联函数,override,class,namespace命名空间等特性。

除此外并未用到其他复杂代码特性,代码不算复杂,比较容易理解。

  • 使用了JSON格式的配置文件,格式简单,易于解析SfM各阶段主要数据结构,如sfm_data.json

2.3 代码量统计

openMVG核心算法库代码量统计如下:

平均每个文件代码量99行。

samples和software多个工程项目代码量统计如下("/"符号前后分别是samples和software文件夹的统计结果):

平均每个文件代码量146行。

考虑到文件中可能不止有一个函数,并且注释较为丰富。平均每个函数的实际代码量更低。函数短小精悍,读起来比较舒服和轻松,方便读者学习和深入理解算法。

2.4 代码优缺点

从笔者个人角度来看:

openMVG的函数可读性好、算法稳定性强、重要函数均有标明出处(比如标注了具体参考的是《计算机视觉中的多视图几何》哪一页内容)、变量命名的设计很严谨、符合计算机视觉领域的术语规范。其傻瓜式编译,加上贴心地设计了丰富的samples和softwares,可使非专业的初学者也能快速测试完整的影像三维重建、视觉里程计等功能,并附有中间结果文件输出。总之,openMVG极适合三维重建新手入门的学习及测试

但也存在一些缺点,个别模块函数嵌套较为冗杂,降低了灵活性,这给深入算法研究带来不便。举例来说,光束法平差的功能,从ceres-solver到用户接口调用设计了3-4层函数,不利于灵活使用。不过随着使用人员编程及算法功底的提升,以上缺点可以克服。至于算法完整性方面,更偏向于全局式SfM相关的state-of-the-art算法。对于传统的增量式SfM,并未集成较先进的算法。针对大规模SfM问题,学界和工业界提出很多较先进的算法,比如Hybrid SfM,hierarchical SfM,HyperSfM等。尽管开发者们正积极集成这类算法,但目前openMVG仍没有较稳定的大规模SfM处理算法。感兴趣的研究人员可以自己开发、增加该功能。

3. SfM技术

无论是摄影测量、计算机视觉,还是机器人(包括无人机)领域,往往需要从一组影像或视频中测量、观测或感知三维空间场景内物体的坐标信息,同时恢复相机拍摄时刻的空间状态,即相机外参数(旋转矩阵、平移矩阵)和内参数(主距、像主点坐标等)。计算机视觉提出的 SfM 正是满足此类需求的一门关键技术。它在摄影测量中用于空中三角测量(定向),特别适合近年来新型、轻巧、灵活的无人机摄影测量。在机器人视觉自主导航应用中称之为SLAM,也称作real-time SfM。

另外,最值得一提的是光束法平差(bundle adjustment),常作为SfM技术的最后一步执行全局优化。光束法平差最初由摄影测量专家Brown (就是常见相机畸变模型的Brown)在1964-1968发表论文中提出。后经Triggs 从计算机视觉角度进行全面理论解析,在视觉机视觉领域得到推广应用。再由于ceres, g2o等开源代码的普及,光束法平差开始在SLAM领域得到重点关注,称为optimization-based method(相对于传统的滤波算法,filter-based method)或graph-based method。

3.1 SfM pipeline

目前基本的 SfM 策略主要有2种,分别为增量式incremental和全局式global,如下图所示。增量式方法往往选择最优的种子像对建立初始场景(initialization),然后不添加新影像以扩展场景(image registration, triangulation, bundle adjustment),最后对整个场景光束法平差优化一次,调整所有相机的内、外参数和物方点(3D points)。而全局式方法是将输入所有影像,先同时解算相机的全局旋转矩阵(此过程称为rotation averaging),接着是全局平移矩阵(此过程称为translation averaging),再经前方交会(triangulation)初始化整个场景的物方点,最后对整个场景光束法平差,优化所有相机的内、外参数和物方点。一般而言,增量式方法多次光束法平差中会进行粗差探测与剔除(outlier filtering),整体较为鲁棒,缺点是时间效率低下且误差积累会产生场景偏移。而全局式方法整体同时解算,时间效率高,但严重依赖相对定向的质量,鲁棒性较差。

3.2 openMVG的SfM基本信息

针孔相机成像模型

相机内参数:Intrinsic parameters [f;cu,cv]。f是主距,focal plane到image plane的像素距离;ku, kv是比例系数,等价于分开定义fx, fy,但一般均为1。cu,cv是像主点,理想状态上为image的中心位置,坐标值定义为image左上角为原点,向右为u轴,向下为v轴。

相机外参数:Extrinsic parameters [R|t] = [R|-RC]。R: 相机的旋转矩阵;t: 相机的平移矩阵;C: 相机在某个世界坐标系下的位置

由此可建立三维场景点Xi 与像点观测xi的几何关系:

光束法平差

在摄影测量、多视图几何或SfM重建中,给定同一场景的不同位置角度拍摄的多张影像,光束法可同时优化三维物方点,相机内、外参数,可看作一个非线性优化问题。

SfM数据结构

struct SfM_Data
{Views views;   /// 储存影像物理性质、索引号等基本信息
Poses poses;   /// 储存影像外参数,包括旋转矩阵、平移矩阵
Intrinsics intrinsics; /// 储存影像内参数,支持多组不同内参数
Landmarks structure;   /// 物方点信息,物方点坐标及其tracks
}

4 SfM具体算例

以法国索镇城堡图片集(可在openMVG的GitHub获取)作为例子,执行SfM过程。

4.1 openMVG_main_SfMInit_ImageListing

第一步创建整个工程的描述文件sfm_data.json,用于准备SfM计算的数据结构。初始的sfm_data.json主要有views和intrinsics信息。

openMVG_main_SfMInit_ImageListing
-d ../src/openMVG/exif/sensor_width_database/sensor_width_camera_database.txt
-i ../Dataset/ImageDataset_SceauxCastle/images
-o ../Dataset/ImageDataset_SceauxCastle/matches

sfm_data.json文件细节展示:

4.2 openMVG_main_ComputeFeatures

对每张影像进行特征提取与特征描述,输出.feat, .desc结果文件,常用默认的SIFT算子。

openMVG_main_ComputeFeatures -i [..matchessfm_data.json] -o [...matches]

4.3 openMVG_main_ComputeMatches

特征提取后进行特征匹配,即建立重叠影像间的匹配点集(point correspondences),分为基于描述子相似度的初始匹配和几何滤波剔除错误匹配点两步。

openMVG_main_ComputeMatches -i [..matchessfm_data.json] -o [...matches]

​ 初始特征匹配 648个匹配点

​ 几何滤波(RANSAC+基础矩阵) 425个匹配点

4.4 执行SfM

主要有两种SfM策略,增量式openMVG_main_IncrementalSfM和全局式openMVG_main_GlobalSfM。

openMVG_main_IncrementalSfM -i Dataset/matches/sfm_data.json -m Dataset/matches/ -o Dataset/out_Incremental_Reconstruction/

其他命令: • [-a|–initialPairA NAME], [-b|–initialPairB NAME] 可用于手工指定种子像对 • [-c|–camera_model] 选择相机内参,一般与openMVG_main_SfMInit_ImageListing一致

• [-f|–refineIntrinsics] 可选择在光束法平差时需要调整的内参模块,使用‘|’组合多选 – ADJUST_ALL 默认调整所有内参数/内方位元素 – NONE 不调整内参,用于事先相机标定好的数据 – ADJUST_FOCAL_LENGTH 只调整主距 – ADJUST_PRINCIPAL_POINT 只调整像主点 – ADJUST_DISTORTION 只调整相机畸变参数

openMVG_main_GlobalSfM -i Dataset/matches/sfm_data.json -m Dataset/matches/ -o Dataset/out_Global_Reconstruction

其他命令: • [-r|–rotationAveraging] 选择旋转平均的算法 – 1: L1 rotation averaging – 2:(default) L2 rotation averaging • [-t|–translationAveraging] 选择平移平均的算法 – 1: L1 translation averaging – 2:L2 translation averaging – 3:(default) SoftL1 minimization • [-f|–refineIntrinsics] (同上) 可选择在光束法平差时需要调整的内参模块,使用‘|’组合多选**

4.5 执行光束法平差

此时数据结构sfm_data已有完整的views,intrinsics,extrinsics/poses, structure/landmark信息,将光束法平差作为SfM的最后一步,对整个场景物方点及影像内、外参数进行全局优化。光束法平差的实现已集成于openMVG_main_IncrementalSfM和openMVG_main_GlobalSfM,得到SfM重建效果如下图:

4.6 SfM精度评价

SfM完成后以html格式输出数据报告,精度评价主要以像点观测的重投影误差(像素为单位)作为统计指标。表格展示每张影像的像点观测的重投影误差分布。另外,统计直方图的横轴为重投影误差,纵轴为像点观测数目,表现整个最终SfM重建的所有像点观测的重投影误差分布,此次结果的RMSE小于0.5个像素,较为合理。

5 总结

openMVG具有完整的SfM流程,从一组影像序列重建出整个场景的稀疏物方点,同时得到拍摄相机的内、外参数,可用于摄影测量空三或相机定向过程。将openMVG的SfM结果输出,再经密集匹配、表面重建、纹理映射就能实现完整的三维重建。(学习openMVG小贴士)大家在学习和使用openMVG的过程中,遇到任何相关问题,建议第一时间登录GitHub issues(https://github.com/openMVG/openMVG/issues)查找,一般的问题都能快速解决。

本期关于openMVG开源代码的总结笔记就到这里了。如果觉得有用,欢迎转发、推荐给有需要的同学朋友们。

公众号后台写下你感兴趣的摄影测量、计算机视觉、GNSS数据处理等方向的开源软件名,笔者(我不是一个人:-))将搜集和统计,或许会成为下一期『源码阅读记』学习的对象。

[Reference]

[1] openMVG documentation : https://openmvg.readthedocs.io/en/latest/

[2] sfm pipelines in cvpr 2015 tutorial.

[3] 基于图像的三维重建研究(转): https://www.cnblogs.com/Joetao/articles/10275121.html

[4] 计算机视觉方向简介 | 基于单目视觉的三维重建算法 : https://new.qq.com/rain/a/20190409A0JQ7X

[5] http://www.arc-team.com/

[6] Brazilian Team of Forensic Anthropology and Legal Dentistry : http://ebrafol.org/

[7] http://dhlab.epfl.ch/


sfm三维重建源码_OpenMVG源码阅读小记相关推荐

  1. 目前ipad协议和安卓协议能实现微信百分之90功能 扫码进群 注册 阅读 关注支付功能等都能实现吗?ipad协议源码

    目前ipad协议和安卓协议能实现微信百分之90功能 扫码进群 注册 阅读 关注 支付功能等都能实现 需要协议 联系作者薇WLWCXKF 最新版本 功能强大 稳定一手 getLoginQRCode (获 ...

  2. 【Mybatis源码】源码分析

    [Mybatis源码]源码分析 (一)Mybatis重要组件 [1]四大核心组件 (1)SqlSessionFactoryBuilder (2)SqlSessionFactory (3)SqlSess ...

  3. 安卓调用日历提醒,并实现闹钟提醒功能,在miui上测试通过,日历提醒闹钟设置失败解决(附源码,源码已更新)

    不想看教程的可以直接走这里的后门去下载源码(源码已更新),源码小米手机亲测通过,有问题可以私信我:源码下载https://download.csdn.net/download/Spy003/87418 ...

  4. 【Android源码】源码分析深度好文+精编内核解析分享

    阅读Android源码的好处有很多,比如:可以加深我们对系统的了解:可以参考牛人优雅的代码实现:可以从根本上找出一些bug的原因-我们应该庆幸Android是开源的,所有的功能都可以看到实现,所有的b ...

  5. 【spring源码】源码分析

    [spring源码]源码分析 (一)mac版idea引入spring源码 (二)spring的学习流程 (三)spring源码分析 [1]refresh()方法概览(AbstractApplicati ...

  6. java 头尾 队列_源码|jdk源码之栈、队列及ArrayDeque分析

    栈.队列.双端队列都是非常经典的数据结构.和链表.数组不同,这三种数据结构的抽象层次更高.它只描述了数据结构有哪些行为,而并不关心数据结构内部用何种思路.方式去组织. 本篇博文重点关注这三种数据结构在 ...

  7. Flink源码分析 - 源码构建

    本篇文章首发于头条号Flink源码分析 - 源码构建,欢迎关注我的头条号和微信公众号"大数据技术和人工智能"(微信搜索bigdata_ai_tech)获取更多干货,也欢迎关注我的C ...

  8. Dapper源码学习和源码修改(下篇)

    继上篇Dapper源码学习和源码修改 讲了下自己学习Dapper的心得之后,下篇也随之而来,上篇主要讲的入参解析那下篇自然主打出参映射了. 好了,废话不多说,开始吧. 学习之前你的先学习怎么使用Dap ...

  9. [Android源码]Android源码之高仿飞鸽传书WIFI热点搜索与创建(一)

    (本文详情来源:android源码 http://www.eoeandroid.com/thread-296427-1-1.html   转载请注明出处!)  [Android源码分享]飞鸽传书的An ...

最新文章

  1. CTFshow 信息收集 web8
  2. AI:2020年6月21日北京智源大会演讲分享之14:50-15:15穗志方教授《从语言到知识——构建语言智能的基石》
  3. kernel中对文件的读写【学习笔记】【原创】
  4. 想要学好C++有哪些技巧?
  5. Linq to SQL 语法记录....并发写事务
  6. 【实用工具】GLIBC降级
  7. 2016中国地理信息产业百强企业公示名单(转)
  8. 二分法07:寻找峰值
  9. 北风设计模式课程---外观模式、代理模式和中介者模式的区别
  10. VScode插件C/C++ Project Generator产生的Makefile模板
  11. 存储服务器内的温度检测信号线 用线,常用的3线和4线电阻温度检测器介绍
  12. 白话空间统计之:空间自相关
  13. 2年CFA三级考试连过的我,全靠笔记多!(无金融背景)
  14. 整车CAN网络基本结构
  15. Unity自动设置keystore密匙库的信息
  16. ISP——AWB(Auto White Balance)
  17. win10计算机维护,Win10系统打开或关闭自动维护功能的方法
  18. HashSet线程不安全,1、 使用JUC中的CopyOnWriteArraySet底层还是使用CopyOnWriteArrayList进行实例化 2、使用工具类中的Collections.synch
  19. C语言编程练习之水仙花数
  20. 将word 转换为图片(word to pdf ->pdf to image)

热门文章

  1. 中国运算放大器行业市场供需与战略研究报告
  2. 可视化pytorch网络特征图
  3. VC操作Excel-Automation版
  4. 10-19带表情的聊天室
  5. 商用IC卡燃气智能表的全球与中国市场2022-2028年:技术、参与者、趋势、市场规模及占有率研究报告
  6. Pyqt5设置刻度尺
  7. Java实现窗体爱心移动特效
  8. phpcms模板生成原理
  9. 成都市 3D可视化 智能楼宇(智慧园区) H5 WebGL 开发总结(skycto JEEditor)
  10. multimap学习之查找操作count,find,lower_bound,lower_bound,upper_bound,key_comp, value_comp