增量式SfM详细流程介绍及实现方法

article/2025/10/15 14:56:56

  目前主流的SfM(Structure from Motion,运动结构恢复)可以分为两大类型,一种是全局式的,一种是增量式的。全局式(Global)sfm能够一次性得出所有的相机姿态和场景点结构。它通常先求得所有相机的位姿,然后再通过三角化获得场景点。其中相机位姿求解也分为两步:第一步是求解全局旋转,第二步是根据全局旋转求解全局平移向量。因为第二步的计算依赖于第一步的输出,因此第一步输出结果的准确性直接决定了第二步的结果的优劣,也就是说,全局旋转的求解是相机姿态估计的核心关键问题。全局式sfm只需要在最后进行一次BA(Bundle Adjustment),因此效率较高,但是其鲁棒性差,很容易受到outlier的影响而导致重建失败。增量式(Incremental)sfm则是一边三角化(triangulation)和pnp(perspective-n-points),一边进行局部BA。这类方法在每次添加图像后都要进行一次BA,效率较低,而且由于误差累积,容易出现漂移问题;但是增量式sfm的鲁棒性较高。著名的开源库Colmap就是通过增量式sfm的pipeline实现的。而OpenMVG则同时实现了增量式和全局式两种pipeline。
  首先先上state-of-art开源库colmap的官方论文中的增量式sfm流程图:

在这里插入图片描述

增量式sfm流程图(来自论文《Structure-from-Motion Revisited》[1])


  感兴趣的小伙伴可以直接从这里下载原论文来看,免费。关于该论文的详细内容,可以参考我的这篇博客:Colmap论文——《Structure-from-Motion Revisited》论文阅读笔记。
  下图则是OpenMVG系统的详细流程。该流程与我下面介绍的自己复现增量式SfM的流程相似,只是它这里以图的方式对图像间的匹配关系进行了描述(感觉上更高大上了,但是这样描述也更容易劝退新人)。

在这里插入图片描述
  
  下面介绍一下我在复现增量式sfm后对该框架的理解。在实现过程中主要调用了opencv、siftgpu和ceres库,部分实现代码参考了colmap。流程及使用的库(用[]标出)主要如下:
  

1. 图像数据读取 [opencv]

  读取图像是为了可视化检查特征提取与匹配的正确性以及在三角化后获取三维点的颜色值,如果不需要这两步操作的话,可以直接跳过这一步,因为使用siftgpu库进行特征提取时只需要输入图像路径即可,不需要把图像数据读取到内存中。
  

2. 特征点提取和描述子计算 [siftgpu]

  有别于SLAM,sfm并不要求实时性,所以通常使用更为可靠稳健的SIFT(Scale-Invariant Feature Transform)特征点,对应的描述子也称为sift描述子。有想了解sift特征点提取原理流程的,可以从这里下载sift文档来看,也可以参考博客1、博客2。siftgpu可以同时提取特征点并计算描述子,其描述子类型为128维的float。
  

3. 匹配图像对搜索 [siftgpu]

  这里需要分为两个步骤,一个是可能存在匹配关系的图像对之间的匹配搜索,一个是图像对之间的特征点描述子之间的匹配。
  首先是匹配图像对的搜索方式,包括:

  • 穷举法:对所有图像进行两两匹配
  • 空间匹配:基于GPS信息,有些图像的EXIF信息里就会带有这个信息,然后通过GPS计算空间距离,来缩小搜索范围。这一方式在机载影像的匹配图像对搜索中最为常用。
  • 匹配关系传递:基于这么一个事实,若A与B匹配、B与C匹配,则A与C也很可能会存在匹配关系。
  • 视觉词袋(Bag of Words):基于视觉词袋模型的图像分类系统主要由四个部分组成,分别为:图像底层特征提取、视觉词典生成、视觉词汇特征构建和分类器。要完成图像分类,首先需要生成一个规模适当的视觉词典,又称为视觉码本;然后,对于一幅待处理图像,提取出相应的底层特征后,依据视觉词典来构建该图像的视觉词汇特征;最后,将该视觉词汇特征输入已训练好的分类器中,得到该图像类别。(参考)
  • 词汇树(Vocabulary Tree):在这种匹配模式下,每幅图像都会通过空间重新排序的词汇树与其视觉近邻进行匹配。这是大型图像集合(数千张)的推荐匹配模式(细节可参考)。与视觉词袋相比,词汇树利用层次kmeans得到尽可能多的特征。层次kmeans的意思是将空间中的点用普通kmeans得到k个聚类中心,每个点都属于一个聚类中心代表的类。对于一类中的所有点,再递归的进行kmeans,直到获得我们想要的聚类中心个数。这样的聚类方法相比普通kmeans聚类可以得到更多的聚类中心,同时花费的时间更加少。
  • 序列匹配:和SLAM中一样,若拍摄图像如视频一般是有序的,那么直接根据顺序信息进行匹配即可,当然,可能不同时序的图像之间也会存在匹配关系,所以通常会结合词汇树方式一同使用。

  上面的方式只是搜索出可能存在匹配关系的图像对,但是图像对内,哪些特征点之间是互相匹配的呢?这也需要进行计算(参考):

  • 暴力匹配(Brute Force Matching):对两张图像上的所有描述子之间都进行一个相似度计算,认为相似度最大的是一个匹配点对。描述子距离的度量有L1范数(差值的绝对值之和)、L2范数(差值的平方和)、汉明距离(针对二进制描述子,对应位相同为0,相异为1)等。
  • FLANN (Fast Library for Approximate Nearest Neighbors)快速最近邻匹配:FLANN训练了一种索引结构,用于遍历使用机器学习概念创建的潜在匹配候选对象。该库构建了非常有效的数据结构(KD树)来搜索匹配对,并避免了穷举法的穷举搜索。因此,速度更快,结果也非常好,但是仍然需要调试匹配参数。

  由于我重建的主要是无人机影像,然后每张影像有gps测得的经纬度坐标,所以我在图像匹配的时候,借助了经纬度坐标进行邻域搜索,只对一定范围内的图像进行匹配。
  

4. RANSAC精化匹配点对 [opencv]

  由于遮挡、重复纹理等因素,sift提取的特征点和描述子在匹配过程中会存在误匹配的情况,所以需要将错误的匹配点对剔除。这里的错误匹配点对剔除通常包含两个步骤,最初始的剔除通常使用比值测试(ratio test)和交叉验证( cross check)进行。其中基于最近距离和次近距离(这里的距离指描述子之间的相似性)比值的比值测试用于剔除不满足给定阈值的匹配对;其次,交叉验证用于选择两个方向能够互相为最近邻点的匹配。这两个步骤是最基本的剔除策略,之后还需要经过进一步的剔除。一个很简单粗暴的方法就是直接通过计算匹配点对的距离(这里的距离是指像素点坐标的距离),然后把距离大于一定阈值的匹配舍弃掉。但是这种方法只能剔除掉一部分错误匹配,比如距离小于阈值的错误匹配就无法剔除,且阈值的确定也是一个问题。由于该方法过于简陋且没有有力的理论依据,因此不应用于实际中。
  通常采用的方法可以分为两种,显式和隐式。显式方法一般是利用E矩阵(Essential Matrix,本质矩阵)或者F矩阵(Fundamental Matrix,基础矩阵)等,通过RANSAC来去除错误匹配。具体操作是,随机选取图像对的8对及以上匹配点,使用归一化八点算法求解基础矩阵F(相机内参K未知),然后统计满足(当然由于误差存在不可能完全满足,一般是将Sampson误差在一定阈值范围内的点对视为内点)对极几何关系x’TFx=0的点对数量,其中x和x’为图像点。重复该过程若干次,选取满足条件的点对数量最多的匹配为精化匹配结果。
  虽然RANSAC具有较强的抗外点能力,但是随着初始匹配外点率的提高(超过50%),RANSAC算法的性能出现显著下降。与基于RANSAC算法的显式参数估计不同,隐式参数估计方法具有更强的抗噪声能力,并在特征匹配粗差剔除中得到应用。其中霍夫变换(Hough transformation, HT)是常用方法,其基本思想是利用待估计的参数对投票空间进行划分、投票计数。
  

5. 增量式sfm初始化

  初始化主要是指选取两张匹配的图像,设定其中一张图像的位姿为单位阵,然后通过它们之间的匹配点对估计出E矩阵,将E矩阵分解获得另一张图像的位姿。在估计出两张图像的位姿后,就可以通过三角化(triangulation)来生成三维点。初始图像对的选择是后续增量式重建的基础,如果这一步误差过大,通过误差的累积和传递效应,后续重建很可能会直接失败。因此,很多方法对该步骤进行了严格的要求。比如,OpenMVG在选取初始匹配图像对时,要求所有对应点三角化时射线夹角的中位数介于3°~60°之间。因为图像对的基线过长,容易出现遮挡的问题,导致对应关系不准确;而基线过短,则特征点点位的误差会被放大,导致重建精度降低。
  

6. 初始化后是一个循环,每次新加入一张图像

  每次循环包括如下四步:

   1. 获取下一最佳匹配图像(匹配点对数量最多),这里记为Inext
   2. 对Inext进行pnp估计位姿(pose)
   3. 对Inext进行三角化生成三维空间点
   4. 对所有已生成的三维点和已估计出的位姿进行ba优化 [ceres]

  这四步里面涉及到很多的trick,感觉是整个增量式sfm的核心所在。前三步的trick可以参考我的这篇博客:https://blog.csdn.net/weixin_44120025/article/details/111085028。ba部分我使用的是ceres库,在写ba的时候遇到了不少问题,有个小总结:https://blog.csdn.net/weixin_44120025/article/details/111052651。
  对于第一步,colmap中提出的一个trick是,对特征点在图像上的分布进行打分,特征点数量越多,越均匀分布于图像上,得分越高。因为特征点的分布情况也会影响恢复的精度。
   在这里,ba优化是通过最小化重投影误差实现的,待优化的变量包括三维空间点的坐标(x,y,z),相机内参(fx,fy,cx,cy),相机的畸变参数(k1,k2,k3,p1,p2),每张图像对应的相机位姿(R,t),在优化的时候,旋转矩阵R一般用四元数q(w,x,y,z)表示。需要注意的是,每轮ba过后都需要剔除误差过大的点(outliers)。
  

7. 对所有数据进行ba优化 [ceres]

  全局优化,包括所有生成的三维点、相机位姿及内参数。在colmap中,有个trick是分组优化。它将图像分组,分成很多小的,较多重叠的组。每组内认为是同一个相机。因为在优化过程中,优化较多的是那些新加入的图像,其它的则仅仅是减小漂移。因此将图像分组优化会更高效。
  

8. 再三角化(可选)

  再三角化的目的是因为刚开始的时候,由于加入的数据较少,优化的准确性较差,所以在使用ba进行重投影时,会剔除掉比较多的三维点(中间可能会有很多误剔除的)。随着加入图像数量的慢慢增多,优化的结果越来越准确,就可以重新对前面的图像进行三角化(把误剔除的点加回来),然后再进行ba优化。该trick由VisualSFM首次提出——当模型大小增加25%时,便re-triangulate这些失败的特征匹配。这一步不是必须的。
  
  最后,贴上我复现增量式sfm的结果及部分复现过程中需要注意的问题:https://blog.csdn.net/weixin_44120025/article/details/111076614
  以及,关于SfM的一些问题的答疑:https://blog.csdn.net/weixin_44120025/article/details/120530095
  
  
参考文献:
[1] Schonberger J L , Frahm J M . Structure-from-Motion Revisited[C]// IEEE Conference on Computer Vision & Pattern Recognition. IEEE, 2016:4104-4113.
[2] Moulon P , Monasse P , Marlet R , et al. Global Fusion of Relative Motions for Robust, Accurate and Scalable Structure from Motion[C]// IEEE International Conference on Computer Vision. IEEE, 2013.


http://chatgpt.dhexx.cn/article/jtQ1TmtF.shtml

相关文章

SLAM和SFM有什么区别?

点击上方“3D视觉工坊”,选择“星标” 干货第一时间送达 自古以来,人们惆怅千年要解决的问题: 定位、定向. 当然了还有我是谁?我在哪里? 在这个时候, SLAM与SFM 横空出世. 这两兄弟叱咤乾坤,成为人们解决上述问题的得力帮手. SFM SFM即Struct…

SFM问题简介

最近在学习opencv的知识,遇到的一些知识点和理解记录下来,由于还是小白,有所不对的地方,大家一起交流沟通 Structure from motion,简称为SFM,是单目相机在物体周围不同的角度拍摄不同的图片,而相…

SfM详细流程介绍

增量式(Incremental)sfm则是一边三角化(triangulation)和pnp(perspective-n-points),一边进行局部BA。这类方法在每次添加图像后都要进行一次BA,效率较低,而且由于误差累积,容易出现漂移问题;但是增量式sfm的鲁棒性较高。 增量式sfm初始化 初始化主要是指选取两张匹…

主流SFM处理方式的梳理

SFM是什么? SFM即Structure-from-motion运动结构重建,从大批量图像数据出发,通过相关处理,获取目标图像集3D几何(结构)和摄像机姿态(运动)信息,主要处理流程可分为如下几…

SFM过程(一)

以图像为基础的三维重建过程SFM基本如下图所示&#xff1a; 以SfM-Toy-Library代码为例&#xff0c;如下&#xff1a; ErrorCode SfM::runSfM() {if (mImages.size() < 0) {cerr << "No images to work on." << endl;return ErrorCode::ERROR;}//in…

SfM算法

参考 https://blog.csdn.net/kokerf/article/details/72630863 https://blog.csdn.net/qq_42399848/article/details/89348740 https://blog.csdn.net/lpj822/article/details/82716971 《基于无序图像集的运动恢复结构研究与实现》 Structure from Motion可以认为一个相机在运…

SFM算法流程

SFM算法流程 Figure1:Block diagram of structure from motion 1. 算法简介 SFM算法是一种基于各种收集到的无序图片进行三维重建的离线算法。在进行核心的算法structure-from-motion之前需要一些准备工作&#xff0c;挑选出合适的图片。 首先从图片中提取焦距信息(之后初始化…

Sfm方法过程及原理

1. 算法简介 SFM算法是一种基于各种收集到的无序图片进行三维重建的离线算法。在进行核心的算法structure-from-motion之前需要一些准备工作&#xff0c;挑选出合适的图片。 先从图片中提取焦距信息(之后初始化BA( Bundle adjust)需要)&#xff0c;然后利用SIFT等特征提取算法去…

SFM原理简介

Structure From Motion SFM简介 通过相机的移动来确定目标的空间和几何关系&#xff0c;是三维重建的一种常见方法。 它与Kinect这种3D摄像头最大的不同在于&#xff0c;它只需要普通的RGB摄像头即可&#xff0c;因此成本更低廉&#xff0c;且受环境约束较小&#xff0c; 在室…

SFM(Structure from Motion)一点总结

SFM&#xff08;Structure from Motion&#xff09;一点总结 运动结构恢复(Structure from motion)数十年来一直是计算机视觉领域的热门研究方向之一&#xff0c;实现了众多实际应用&#xff0c;尤其在近景三维重建中&#xff0c;该算法从获取的目标物系列影像出发&#xff0c…

sfm从运动到结构

sfm&#xff0c;即structure from motion。从一堆同一场景的照片中恢复场景的三维结构和照片拍摄时相机的位置&#xff0c;可分为全局sfm和增量式sfm。 全局sfm主要包括以下步骤&#xff1a; 1.提取各张照片上的特征点及其描述&#xff1b; 2.对所有照片相互进行特征点匹配&a…

猿创征文|SfM(Structure from Motion)学习之路

文章目录 0 前言1 理论基础1.1 书籍推荐1.2 SfM概述 2 动手实践2.1 增量式SfM复现总结2.2 部分复现结果2.3 遇到问题与解决 3 后续学习3.1 前沿论文阅读笔记3.2 Colmap使用问题3.3 三维旋转3.4 场景对齐 0 前言 一转眼&#xff0c;研究生生活已经过去两年了。开始接触SfM也是两…

SFM综述

Structure from Motion&#xff08;SfM&#xff09;是一个估计相机参数及三维点位置的问题。SfM方法可以分为增量式&#xff08;incremental/sequential&#xff09;,全局式&#xff08;global&#xff09;&#xff0c;混合式&#xff08;hybrid&#xff09;,层次式&#xff08…

计算机视觉之三维重建-SFM系统

SFM系统 1.PnP问题2. RANSAC拟合3.本质矩阵与单应矩阵4.sift特征提取*2视图欧式结构恢复求解流程*openMVG系统Tracks联通图计算流程 北邮三维重建课笔记 1.PnP问题 PnP问题&#xff1a;就是利用其中两个相机算出三维点坐标&#xff0c;再利用三维点坐标和第三个相机的像平面坐标…

java中浮点数表示方式

java虚拟机中的浮点数分为float和double两种&#xff0c;分别为32位和64位.它参考了IEEE 754的规范对浮点数进行处理。下面以float为例 &#xff0c;分析一下float数的表示方法. float的32位分成三个部分来表示一个浮点数: 浮点数的取值计算公式为: 解析: 1&#xff09; 当…

一文读懂 IEEE754 浮点数的表示方法

FBI WARNING&#xff1a;鄙人首个开源电子书 《Go 编码建议》已经上线啦&#xff0c;欢迎各位大佬斧正指导&#xff0c;协同共建。 文章目录 1.浮点数的存储格式2.移码3.浮点数的规格化3.1 单精度浮点数真值3.2 双精度浮点数真值 4.浮点数的具体表示4.1 十进制到机器码4.2 机器…

浮点数表示(IEEE 754)

引入 N S r j N Sr^j NSrj N&#xff1a;浮点数S&#xff1a;尾数r&#xff1a;基数j&#xff1a;阶码 举个例子&#xff1a; 123.456 1.23456 1 0 2 123.456 1.2345610^{2} 123.4561.23456102 其中123.456是浮点数&#xff0c;1.23456是尾数&#xff0c;10是基数(10进…

c++ 浮点数表示

1.为何称为浮点数 对于一个浮点数来说&#xff0c;其通常可以科学计数法来表示&#xff0c;而对于一个浮点数来说&#xff0c;由于次方可变&#xff0c;故小数点可以左右移动。 eg&#xff1a;-36.5 &#xff0c;及可以表示为&#xff1a;&#xff0c;也可以表示为&#xff0…

Java中浮点数的表示方法

Java中浮点数的表示方法 Java中浮点数的表示方法 1.计算机中的表示方法2.具体分析表示方法 小结 3.移位存储 小结 1.计算机中的表示方法 对于float来说&#xff0c;4个字节&#xff0c;32位&#xff0c;0-22位表示尾数&#xff0c;23-30(8位)表示指数&#xff0c;31位表示符…

浮点数的表示

科学计数法 浮点数的表示 阶码E反映表示范围及小数点的实际位置 位数M的数值部分的位数n反映浮点数的精度 浮点数尾数的规格化 左移三位 0.110&#xff1b;1.0100000 表示范围 浮点数标准 IEEE 754 移码 阶码真值移码-偏移量