1. SFM
Structure from Motion (SfM):從運動中恢復結構,通俗地講:從序列影像中重建目標三維結構,並估計相機及空間引數。
用於SfM的主要有三個庫:
SfM輸出的是稀疏點雲以及相機引數,這些資訊將用於後續的稠密重建。
2. MVS
MultiView Stereo(MVS):多視點匹配,用於生成稠密點雲。
通常MVS能計匹配到更多的點,生成更稠密的點雲,做到這一點需要用到對極幾何的原理:一副影像上的一個畫素點是空間上一條線(相機視點和該畫素連起來的直線)的投影,而這條線在另外一幅影像上往往會投影為一條線。SFM需要在整個二維影像上搜尋匹配點,而MVS只需要在一條線上搜尋。
以上是PMVS2做的事,做到這些需要大量複雜的計算,CMVS就是用於簡化此的。CMVS把SfM輸出的聚類為區域,PMVS2將在這些“區域”上匹配,最後CMVS將這些區域對映為三維模型。
關於二者的聯絡和區別
3. bundler
3.1 配置
bundler是經典的單目重建公開庫之一,很多工作都是在此基礎上進行的,其執行過程大致分為三步:
-
使用Perl指令碼
extract_focal.pl
提取影像焦距資訊並儲存到image list
中; -
在每幅影像上尋找SIFT特徵點;
-
在各個影像中匹配特徵點,匹配的特徵儲存在
matches.init.txt
中; -
執行bundler,生成點雲和相機引數;
-
配置(Windows):
配置的大致步驟是:下載bundler原始碼,Windows下安裝cygwin,安裝相關依賴,編譯和執行。其中編譯有兩種方式:make
命令和VS編譯,如果是在VS編譯編譯可參考:issue 26。
3.2 輸出
-
格式:
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>表示在二維影像上的座標(以影像中心的原點);
-
-
3.3 選項
options.txt預設包含的選項
-
--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
:輸出所有的選項資訊;
4. PMVS2
PMVS是 Yasutaka Furukawa開發的 Patch-based Multi-view Stereo Software(PMVS)——分段式多視角匹配軟體(目前是第二版)。PMVS的輸入為一組影像和相應的相機引數,輸出是“半稠密”的點雲。需要注意的是,PMVS只重建剛性機構的目標,自動忽略行人等柔性目標。關於MVS有一個跑分排行。
4.1 輸入
-
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、影像2將聚合到一塊兒以重建點雲)。預設為0表示不使用此資訊,使用時設定為1; -
sequence:用於序列化影像,預設為-1,表示不使用此選項,如果為3則表示當前影像的前後各3個影像將用於重建;
-
quad:重建的點周圍的點中,與之相似的越多則該點越不可能被濾除。通常此選項不需要調節,可省略;
-
maxAngle:當兩個相機的夾角大於此閾值則不被重建,減小maxAngle將允許更大範圍的目標被重建出來,同時噪點也更多;
-
4.2 輸出
輸出包含三種格式的檔案:
-
.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也不好編譯,所以就不執行了。
5. CMVS
Clustering Views for Multi-view Stereo (CMVS)也是 Yasutaka Furukawa (博士後時期)寫的,它包含了PMVS2的內容,提升的地方在於:更高的效能,更好的效果。CMVS將SFM的輸出分成一個個小的圖片簇,然後獨立並行的重建。幾者的關係的關係:
Bundler->CMVS->PMVS2
5.1 輸出
-
ske.dat:包含叢集資訊;
-
vis.dat:可見性資訊;
-
centers-%04d.ply:各個圖片簇的相機位置;
-
centers-all.ply:所有的相機位置資訊;
-
option-%04d:PMVS2配置檔案;
-
pmvs.sh or pmvs.bat:用於執行PMVS2;
5.2 編譯(Windows & VS2013)
這裡以 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目錄下)。
5.3 執行
-
執行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
生成稠密點雲,執行前可能需要修改路徑。
5.4 關於路徑
我是在Windows下執行的,所有用到的路徑都是相對方式給定,如果執行指令沒有得到正確結果,請著重檢查你的路徑!總結起來就是一句話:
正確的路徑(相對) + 正確的引數(引數中的路徑也是相對於執行命令所在目錄的)
遇到問題可以這樣做:
仔細檢視readme -> 到github或者官網看issue和文件 -> google或者問答社群 -> 原始碼(有基礎可以直接看原始碼)。
我的codepen:連結