Structure from Motion (SfM):从运动中恢复结构,通俗地讲:从序列图像中重建目标三维结构,并估计相机及空间参数。html
用于SfM的主要有三个库:git
SfM输出的是稀疏点云以及相机参数,这些信息将用于后续的稠密重建。app
MultiView Stereo(MVS):多视点匹配,用于生成稠密点云。post
一般MVS能计匹配到更多的点,生成更稠密的点云,作到这一点须要用到对极几何的原理:一副图像上的一个像素点是空间上一条线(相机视点和该像素连起来的直线)的投影,而这条线在另一幅图像上每每会投影为一条线。SFM须要在整个二维图像上搜索匹配点,而MVS只须要在一条线上搜索。
以上是PMVS2作的事,作到这些须要大量复杂的计算,CMVS就是用于简化此的。CMVS把SfM输出的聚类为区域,PMVS2将在这些“区域”上匹配,最后CMVS将这些区域映射为三维模型。
关于两者的联系和区别性能
bundler是经典的单目重建公开库之一,不少工做都是在此基础上进行的,其运行过程大体分为三步:google
使用Perl脚本 extract_focal.pl
提取图像焦距信息并存储到 image list
中;命令行
在每幅图像上寻找SIFT特征点;
在各个图像中匹配特征点,匹配的特征存储在 matches.init.txt
中;
运行bundler,生成点云和相机参数;
配置(Windows):
配置的大体步骤是:下载bundler源码,Windows下安装cygwin,安装相关依赖,编译和运行。其中编译有两种方式:make
命令和VS编译,若是是在VS编译编译可参考:issue 26。
格式: bundle_<n>.out
;
包含内容:场景估计和相机几何参数;
具体:
版本信息:# Bundle file v0.3
;
<num_cameras> <num_points>:两个整数,分别表示相机总数(其实就是输入图像的数量)和匹配到的点数;
接下来依次是每一个相机的内参和外参信息;
内参:
<f> <k1> <k2>:焦距,两个径向畸变参数;
外参:
<R>:表示相机旋转的矩阵,3X3;
<T>:相机平移矩阵,1X3;
匹配点:
<position>:点空间位置的描述,1X3;
<color>:RGB信息,1X3;
<view list>:描述点可见性的向量,包括 view list 长度,<camera>第几个相机,<key>表示该相机中第几个sift特征点,<x>和<y>表示在二维图像上的坐标(以图像中心的原点);
--match_table
: 指定点匹配信息存储的文件,默认:matches.init.txt
;
--output
: 指定包含最终计算结果的文件名称,默认:bundle.out
;
--output_all
:指定中间结果存储的前缀,默认:bundle_
;
--output_dir
: 指定计算结果的保存目录,默认:bundle
;
--variable_focal_length
:为指定每张图片指定独立的焦距,默认:无(源码中为Option
结构);
--use_focal_estimate
:指定是否使用从EXIF中提取的焦距信息,默认:true
;
--constrain_focal
:指定计算出的相机焦距是否被初始焦距(从EXIF中提取)所约束,默认:true
;
--constrain_focal_weight
: 指定焦距约束条件的权重,一般一个较小的数可矣,默认:0.0001
;
--estimate_distortion
:指定是否为每一张图片估计畸变参数,默认:true
;
--ray_angle_threshold
: 默认:2.0;
--run_bundle
:指定是否运行SFM,默认:true
;
--init_pair1
,--init_pair2
:指定初始匹配的两张图像,一般由程序自动选择匹配点最多的一对图像,若是效果很差再启用此选项; - --sift_binary
: 指定计算SIFT特征的外部接口,通常是/usr/bin/sift
or /cygdrive/c/usr/bin/siftWin32.exe
;
--add_images
: 在已有重建基础上额外添加新图像时使用此选项;
options_file
:指定bundler参数文件,默认:options.txt
;
--help
:输出全部的选项信息;
PMVS是 Yasutaka Furukawa开发的 Patch-based Multi-view Stereo Software(PMVS)——分段式多视角匹配软件(目前是第二版)。PMVS的输入为一组图像和相应的相机参数,输出是“半稠密”的点云。须要注意的是,PMVS只重建刚性机构的目标,自动忽略行人等柔性目标。关于MVS有一个跑分排行。
images:要求jpeg
或者ppm
格式,命名必须是8位(兼容4位)的数字:%08d.jpg
;
camera parameters:命名格式与图像命名相同,内容含义:
------------------------------------------- CONTOUR //固定的header //P[3][4]表示投影矩阵(三维点和投影矩阵相乘获得二维坐标) P[0][0] P[0][1] P[0][2] P[0][3] P[1][0] P[1][1] P[1][2] P[1][3] P[2][0] P[2][1] P[2][2] P[2][3] -------------------------------------------
segmentation masks:以pgm
格式文件给定,灰度小于127是背景,不然为前景;
option file:指定使用的参数文件,具体选项以下:
timages:指定目标图像(必选项),能够用列举(timages 5 1 3 5 7 9
)或者范围(timages -1 0 6
)的方式指定;
oimages:other images(必选项),用于指定那些图片能输出重建结果(重建结果会等全部timages运算完输出,可是经过oimages指定的图像会在中间过程输出),指定方式和timages相同,若是不想用此选项,指定为0;
level:指定图像金字塔(降采样的层次)的高度,指定1(默认)表示降采样一半(宽高缩小一倍,总像素量为原来的四分之一),指定为0表示不进行降采样;
csize:指定重建的最小区块,用于控制重建结果的密度,默认为2(重建中每 2X2 个像素生成一个点云中的点);
threshold:区块重建可接受的最小阈值(默认0.7),总的范围是-1到1,算法有三次迭代,每次迭代自动减0.05;
wsize:指定光度一致性计算的视口大小,默认为7;
minImageNum:一个3D点必须至少在minImageNum张图像中可见才会被输出,默认为3(必须同时出如今三张以上的图像中才会被输出,选项应该和纹理密度成反比);
CPU:程序支持多线程,CPU表示线程数,默认为4;
useVisData:指定是否利用已知(从SFM计算而来)的图像关联信息加速重建过程,程序会利用SFM的输出生成vis.dat
文件生成PMVS须要的格式(0 2 1 2
:0的含义自定义,2表示后面共2个数,1和2表示相应的图像序列,若是这是第一行则表示,图像0和图像二、图像2将聚合到一起以重建点云)。默认为0表示不使用此信息,使用时设置为1;
sequence:用于序列化图像,默认为-1,表示不使用此选项,若是为3则表示当前图像的先后各3个图像将用于重建;
quad:重建的点周围的点中,与之类似的越多则该点越不可能被滤除。一般此选项不须要调节,可省略;
maxAngle:当两个相机的夹角大于此阈值则不被重建,减少maxAngle将容许更大范围的目标被重建出来,同时噪点也更多;
输出包含三种格式的文件:
.ply
:点云文件咯;
.patch
:包含全部重建信息:以PATCHS开头,包含全部重建点的信息
PATCHES 452393 //共452393个点 PATCHS -1.20727 -0.718245 -7.1088 1 //三维坐标 -0.0750093 -0.981341 -0.177041 0 //估计的法线 0.992487 0.0207491 0.385701 //第一个数表示光度一致性测度,后两个供debug 3 //该点在3张图像中可见且纹理匹配良好 2 0 1 //三张图像的index 15 //该点在15张图像中可见,可是纹理匹配不够好 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 //这15张图像的index
.pset
:简化版的重建信息,包括点坐标和法线信息;
由于最新的CMVS包含了PMVS2,并且我使用的Windows也很差编译,因此就不运行了。
Clustering Views for Multi-view Stereo (CMVS)也是 Yasutaka Furukawa (博士后时期)写的,它包含了PMVS2的内容,提高的地方在于:更高的性能,更好的效果。CMVS将SFM的输出分红一个个小的图片簇,而后独立并行的重建。几者的关系的关系:
Bundler->CMVS->PMVS2
ske.dat:包含集群信息;
vis.dat:可见性信息;
centers-%04d.ply:各个图片簇的相机位置;
centers-all.ply:全部的相机位置信息;
option-%04d:PMVS2配置文件;
pmvs.sh or pmvs.bat:用于执行PMVS2;
这里以 Pierre Moulon 开发的Windows版本 CMVS + genOption + PMVS2 为例说明(连接,github)。
首先,代码中包含自带的已经编译好的程序,目录:./binariesWin-Linux/Win64-VS2010
。如下是本身编译的过程:
使用CMake生成VS工程,CMake文件是 ./program/CMakeLists.txt
,打开CMake GUI,选择源码路径为program,配置好,点击生成,最后会生成一个叫作 CMVS-PMVS2.sln
的VS工程。
打开工程,使用VS编译,固然,通常都会报几个错误:
命令行 error D8016: “/O1”和“/RTC1”命令行选项不兼容:将 项目->C/C++->代码生成->基本运行时检查设置为default,问题解决(参考)。
解决了这个问题以后就没有遇到其余问题了!接下来就是将要用到的输出copy出来运行(在main的Debug目录下)。
运行bundler:cd到example下的ET或者kermit目录下,运行 ../../RunBundler.sh
,参数默认的就行,成功后会生成./bundle
目录,成功的话会有 bundle_XXX.out 和 pointsXXX.ply 文件;
转换bundler输出为PMVS所需格式:cd 到 kermit 目录下,运行:../../bin/Bundle2PMVS.exe prepare/list.txt bundle/bundle.out
,获得结果以下(可见的结果就是生成了一个pmvs的目录):
[ReadBundleFile] Bundle version: 0.300 [ReadBundleFile] Reading 11 images and 671 points... [GetJPEGDimensions] File ./kermit000.jpg: ( 640 , 480 ) ...... @@ Conversion complete, execute "sh pmvs/prep_pmvs.sh" to finalize @@ (you will first need to edit prep_pmvs.sh to specify your bundler path, @@ so that the script knows where to find your @@ RadialUndistort and Bundle2Vis binaries)
运行pmvs目录下的prep_pmvs.sh
校订和生成vis.dat文件:先修改prep_pmvs.sh
中BUNDLER_BIN_PATH
的值,我是在kermit路径下运行的,因此改成:"../../bin"
。
> 这里遇到一个bug:提示没法找到“XXXXX.rd.jpg”,实际pmvs目录下生成的图像不带“rd”。看了哈源代码,是**RadialUndistort.cpp**中出的问题,大概是C字符串和string转换形成的吧,将`file[i].rfint('.')`改为`file[i].fint('.',1)`,**file[i]**为list.txt下的一行,后面带的数字中有小数点,致使源代码提取basename出错。
执行CMVS:先执行CMVS prefix 20 2
,这里已经到了cmvs的部分了,须要先把编译好的三个文件copy过来(cmvs.exe
,genOption.exe
,pmvs2.exe
),参数的含义能够看cmvs自带的release路径下的readme。
生成pmvs的参数文件:通过cmvs以后,原来的图片被分红一个个的图片簇(若是你的图片较少则只会有一个簇),因此相应的pmvs参数也要改变,这正是这一步的意义。命令:genOption path
,这里的path建议和上一步的path一致。
生成稠密点云:最后执行pmvs.bat
生成稠密点云,运行前可能须要修改路径。
我是在Windows下运行的,全部用到的路径都是相对方式给定,若是运行指令没有获得正确结果,请着重检查你的路径!总结起来就是一句话:
正确的路径(相对) + 正确的参数(参数中的路径也是相对于执行命令所在目录的)
遇到问题能够这样作:
仔细查看readme -> 到github或者官网看issue和文档 -> google或者问答社区 -> 源代码(有基础能够直接看源码)。
个人codepen:连接