Colmap中的SFM实现笔记

本文主要记录Colmap中增量重建SFM的一些基本框架。整个增量重建的框架大致都可以分为

  • 特征提取(Feature extraction)

  • 特征匹配(Feature matching)

  • 增量重建(Icremental mapping)

image.png

特征提取

Colmap中使用的主要是Sift特征及其变种DSP-Sift。输入的彩色图像在被读入时只保留灰度,之后先会进行一个resize的操作,colmap中有一个参数可控制最大能处理的像素数,默认是3200.这个resize操作可以使得针对不同的输入图像,内存(显存)以及运算时间可以大致控制在一定的范围内。特征提取部分的细节可以参见https://www.jianshu.com/p/94196a92cc18 。在完成特征提取之后,会有一个ScaleKeyPoints的操作,将resize后找到的特征点重新映射回原图的像素坐标。另外,对于有mask的情形,Colmap的做法是只保留在mask之内的特征点。

特征匹配

特征匹配模块干的事情是根据特征,去创造图与图之间的对应关系,这些对应关系将用来重建位姿及稀疏点云。本质上,特征匹配的结果是一个Scene graph,这个图的节点为单个图像,边代表这两张图能匹配上,而边的权重则可以是匹配的特征对数或者匹配的一致的特征对数。具体来说,需要解决几个问题

  1. 大量图的输入,采取何种匹配模式?

  2. 找到匹配图对后,如何构建匹配关系?

  3. 如何定义匹配是否成功?

匹配模式

这里主要介绍一下Colmap中两种常见的匹配模式:sequential和exhaustive。假设输入有n张图,我们要确定图与图之间的关联,一种直接的想法就是两两去计算匹配关系,这就对应了exhaustive模式,而另一种情形是,拍摄时图像是有空间关联的,即相邻拍摄的图像有很大概率是有大重叠的,这时我们就可以只计算相邻的一些图像之间的匹配关系,这也就是sequential模式。二者的区别在于计算匹配的数量,对应了不同的计算时间。特别地,如果采集的数据满足可以分成多组,每组内拍摄图像有空间关联,则可以创造出一个新的匹配模式,我们称之为mixed的模式。

匹配模式 匹配次数 备注
sequential k.n 一共n张图像,只跟前面k个和后面k个图像来匹配
exhaustive \frac{n(n-1)}{2} 一共n张图像
mixed ckn+\frac{c(c-1)}{2}n^2 一共c.n张图像,可以分成c组,每组n张,组内只跟前面和后面k个图像匹配,组与组之间采用exhaustive模式

如下为一个绕物体拍摄两圈的示例,采用了mixed模式,左边为scene graph,右边为对应的位姿恢复结果。


image.png
image.png

如何匹配?

Matcher: sift特征对应的是一个128维的向量,匹配的过程就是对于任意一个特征点,在另一张图中找另一个特征点使得他们之间的特征向量的差距最小,这是通过flann来实现在高维空间寻找最近邻来实现的。

匹配成功?

TwoViewGeometryVerify: 将上一步匹配上的匹配对,通过RANSAC去估计基础矩阵F或Homography矩阵H,然后计算inlier的数目,当inlier的数目超过设定阈值(默认15)时,即可认为匹配成功。

如果guided_matching设成了true,那会增加一步检查特征点匹配对的重投影误差,具体是估计x_2^T F x_1 和0的差距,差距过大的特征点匹配对会被剔除inlier。

增量重建

所谓增量重建是指位姿的估计,稀疏点云的重建都是逐步完成的,每次增加一个图像,获取其位姿,更新稀疏点云。具体而言,主要的步骤包括:

  • 寻找初始匹配对,并三角化求解位姿及稀疏点云

  • 寻找下一张用于重建的图像,并估计位姿,更新稀疏点云

  • 不定时的局部或全局优化

初始匹配对的确定

初始匹配对的寻找是基于上面提到的scene graph进行的。我们将匹配数目最多的图像,即在graph中边最多的节点当做初始匹配对的第一张图,然后再在其所有边连接的节点中寻找第二张图。基本原则是按照节点连接的边数来排序,对于每一个candidate,检查其与第一张图三角化的结果,只要内点数目大于一定阈值(默认100),角度大于一定阈值(默认16度)且不是沿垂直于相机方向前后移动(z分量<0.95),即可被选作第二张图像。如果不符合,则顺延找下一张,直到找到满足条件的为止。如果第一张图对应的匹配对都不满足条件,则按照边的数目排序找下一张图当第一张图,再重复上述的操作。初始匹配对的选择一般要求条件较好,它选择的不好的话,会影响后续所有的重建,因此条件会比较严格。

下一张重建图的确定

在挑选下一张图进行重建时,主要是根据当前三维稀疏点云在该图上的可见点信息来确定的。一种容易想到的方式是根据可见点的个数或者占总特征点的比例来选择,而Colmap中默认是通过VisibilityUncertainty来做排序选择的。这个所谓的不确定性其实描述的是可见点的二维投影点(特征点)在图上的分布,越分布得开,越分布得广,对应认为结果更为鲁棒。具体而言,会在不同的图像分辨率上根据可见特征点所占有的像素个数打分,然后对不同分辨率加权,最终得到一个分布的分数。根据上述分数,对所有图进行排序,按顺序选择图来进行尝试。当然,被选中的图需要满足一些基本的特征,比如可见点的个数至少要达到10个。

确定好下一张图后,就需要对其进行增量式重建了,主要是恢复其位姿并补充稀疏点云。

位姿恢复的方法就是基于PnP(Perspective n points)。之前重建出的稀疏点云,每一个点都对应着一个track,这个track中记录了该三维点对应于哪张图像的哪个2D像素。根据2D的对应关系,可以知道当前图哪些点和稀疏点云的点有对应关系,因此问题转化为优化相机内参和外参,以保证这些3D点能正确投影到其对应的2D点。优化的过程大致可分为三步,第一步是确定内参。以pinhole模型为例,Colmap中需要优化的内参只有焦距,中心默认是在图像的中心。如果焦距信息能从图像EXIF中获取,则直接获取,如不能则需要额外优化。Colmap的优化其实是在可能的焦距取值空间均匀采样,对于每个采样点的焦距,再去优化外参(旋转及平移)。在所有的这些优化结果里边,挑一个最好的当做焦距,对应的优化外参也就确定了。第二步是外参的优化,外参的优化是采用RANSAC来完成的,在焦距固定的情况下,找出内点数最多的一组参数。第三步是一个重投影误差的优化,这一步以上两步得到的结果为初值,再进行一轮非线性的优化,以找到更好的参数组合。

有了位姿之后,就需要根据2D的对应关系,进行三角化,补充生成稀疏点云,以及更新对应点的track。

当所有的图像都尝试了,却仍然找不到满足条件的下一张图,则自动进入上一个流程,重新寻找初始匹配对,这样的结果会导致稀疏重建出现多个孤立的重建结果。

局部及全局的优化

SFM由于累积误差,在进行一段时间的增量重建以后,重建的位姿就将偏离真实的位置,需要通过局部和全局的优化(Bundle adjustment)来解决。不管局部还是全局的Bundle adjustment,优化的都是重投影误差,代价函数可以写成

E = \sum_i\sum_k w_{ki} \left(\|\pi(P_{c_i}, X_k)-x_{ki}\|^2_2\right)

其中,P_{c_i}~代表第~i~个相机的投影矩阵(内外参),X_k~代表第~k~个三维点,\pi~代表投影映射,即将3D点~X_k~投影到第~i~个相机平面,x_{ki}~为三维点~X_k~在第~i~个相机的对应点,\|\cdot\|_2~代表常用的二范数,w_{ki}~代表权重。局部与全局的区别在于代价函数中参与求和的相机个数和3D点的个数。

Colmap中每次加入一张新的图进行重建以后,都会进行一次局部的优化(IterativeLocalRefinement)。此时局部的定义是指,代价函数中只使用与新加的这张图共有3D点数最多的几张图,同时只使用track长度小于15(即能看到该3D点的2D图像数目<15)的3D点。后面这个限制的考虑在于,track长度够长的点,普遍认为它已经比较稳定,不需要再有过多的优化。另外,iterative是指说上述优化迭代进行多次,colmap中设置的是最多两次,迭代的退出条件是看数据的变化情况,即有多少点发生了改变。

全局的优化(IterativeGlobalRefinement)一般是隔一段时间进行一次,一般是以重建的图像数目,3D点的数目等为条件去设置间隔。Colmap中会保证重建的结束最后一次优化必须是全局的优化。全局的优化就会使用已有的所有图像和3D点。同时,在优化前会对所有的track进行一次清理,比如完善track的长度(CompleteTracks),合并一些很近的3D点(MergeTracks)等。优化后也会根据重投影误差删掉一些点(FilterPoints),甚至删掉一些图像(FilterImage)。同上,这里也是iterative的,colmap中设置的最大迭代次数为5次。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,189评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,577评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,857评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,703评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,705评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,620评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,995评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,656评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,898评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,639评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,720评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,395评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,982评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,953评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,195评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,907评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,472评论 2 342

推荐阅读更多精彩内容