OpenCV實現SfM(二) 雙目三維重建

2021-07-11 18:28:57 字數 3624 閱讀 5884

目錄:

在三維重建前,我們先研究一下同一點在兩個相機中的像的關係。假設在世界座標系中有一點

p ,座標為

x ,它在1相機中的像為x1

,在2相機中的像為x2

(注意x1

和x2 為齊次座標,最後乙個元素是1),如下圖。 

到兩個相機像面的垂直距離分別為s1

和s2 ,且這兩個相機具有相同的內參矩陣

k ,與世界座標系之間的變換關係分別為[r

1t1]

和[r2

t2] ,那麼我們可以得到下面兩個等式  s

1x1=

k(r1

x+t1

)s2x

2=k(

r2x+

t2)

由於k是可逆矩陣,兩式坐乘k的逆,有 s1

k−1x

1=r1

x+t1

s2k−

1x2=

r2x+

t2

設k−1

x1=x

′1 ,

k−1x

2=x′

2 ,則有 s1

x′1=

r1x+

t1s2

x′2=

r2x+

t2

我們一般稱x′

1 和x

′2為歸一化後的像座標,它們和影象的大小沒有關係,且原點位於影象中心。 

由於世界座標系可以任意選擇,我們將世界座標系選為第乙個相機的相機座標系,這時r1

=i,t

1=0

。上式則變為 s1

x′1=

xs2x

′2=r

2x+t

2 將第一式帶入第二式,有 s2

x′2=

s1r2

x′1+

t2

x′2

和t2

都是三維向量,它們做外積(叉積)之後得到另外乙個三維向量t2

ˆx′2

(其中t2

ˆ 為外積的矩陣形式,t2

ˆx′2

代表t2

×x′2

),且該向量垂直於x′

2 和t

2 ,再用該向量對等式兩邊做內積,有 0=

s1(t

2ˆx′

2)tr

2x′1

即 x′2t2

ˆr2x

′1=0

令e=t2ˆ

r2 有 

x′2e

x′1=

0 可以看出,上式是同一點在兩個相機中的像所滿足的關係,它和點的空間座標、點到相機的距離均沒有關係,我們稱之為極線約束,而矩陣e

則稱為關於這兩個相機的本徵矩陣。如果我們知道兩幅影象中的多個對應點(至少5對),則可以通過上式解出矩陣e

,又由於e

是由t2

和r2

構成的,可以從e中分解出t2

和r2。 

如何從e

中分解出兩個相機的相對變換關係(即t2

和r2),背後的數學原理比較複雜,好在opencv為我們提供了這樣的方法,在此就不談原理了。

void extract_features(

vector

& image_names,

vector

>& key_points_for_all,

vector

& descriptor_for_all,

vector

>& colors_for_all

)colors_for_all.push_back(colors);

}}void match_features(mat& query, mat& train, vector

& matches)

matches.clear();

for (size_t r = 0; r < knn_matches.size(); ++r)

}

需要重點說明的是,匹配結果往往有很多誤匹配,為了排除這些錯誤,這裡使用了ratio test方法,即使用knn演算法尋找與該特徵最匹配的2個特徵,若第乙個特徵的匹配距離與第二個特徵的匹配距離之比小於某一閾值,就接受該匹配,否則視為誤匹配。當然,也可以使用cross test(交叉驗證)方法來排除錯誤。

得到匹配點後,就可以使用opencv3.0中新加入的函式findessentialmat()來求取本徵矩陣了。得到本徵矩陣後,再使用另乙個函式對本徵矩陣進行分解,並返回兩相機之間的相對變換r和t。注意這裡的t是在第二個相機的座標系下表示的,也就是說,其方向從第二個相機指向第乙個相機(即世界座標系所在的相機),且它的長度等於1。

bool find_transform(mat& k, vector

& p1, vector

& p2, mat& r, mat& t, mat& mask)

現在已經知道了兩個相機之間的變換矩陣,還有每一對匹配點的座標。三維重建就是通過這些已知資訊還原匹配點在空間當中的座標。在前面的推導中,我們有  s

2x2=

k(r2

x+t2

) 這個等式中有兩個未知量,分別是s2

和x 。用x2

對等式兩邊做外積,可以消去s2

,得 0=

x2ˆk

(r2x

+t2)

整理一下可以得到乙個關於空間座標x的線性方程 x2

ˆkr2

x=−x

2ˆt2

解上述方程,即可求取x。其幾何意義相當於分別從兩個相機的光心作過x1

和x2的延長線,延長線的焦點即為方程的解,如文章最上方的圖所示。由於這種方法和三角測距類似,因此這種重建方式也被稱為三角化(triangulate)。opencv提供了該方法,可以直接使用。

void reconstruct(mat& k, mat& r, mat& t, vector

& p1, vector

& p2, mat& structure)

我用了下面兩幅影象進行測試 

得到了著色後的稀疏點雲,是否能看出一點輪廓呢?!

中的兩個彩色座標系分別代表兩個相機的位置。 

在接下來的文章中,會將相機的個數推廣到任意多個,成為乙個真正的sfm系統。

關於源**的使用

**是用vs2013寫的,opencv版本為3.0且包含擴充套件部分,如果不使用sift特徵,可以修改源**,然後使用官方未包含擴充套件部分的庫。軟體執行後會將三維重建的結果寫入viewer目錄下的structure.yml檔案中,在viewer目錄下有乙個sfmviewer程式,直接執行即可讀取yml檔案並顯示三維結構。

OpenCV實現SfM(一) 相機模型

注意 本文中的 必須使用opencv3.0或以上版本進行編譯,因為很多函式是3.0以後才加入的。目錄 sfm介紹 sfm的全稱為structure from motion,即通過相機的移動來確定目標的空間和幾何關係,是三維重建的一種常見方法。它與kinect這種3d攝像頭最大的不同在於,它只需要普通...

日常小結 opencv3 sfm

opencv3中間新增了額外的sfm模組。但是新版本還是有很多問題這裡說下配置。先貼幾個 首先opencv的就從官網下就完了 其次擴充套件包從github下 然後就是編譯安裝就行。如果要執行sfm的demo。viz需要先安裝。這裡提供幾個編譯選項 mkdir build cd build camke...

opencv雙閾值化

對於影象中有明顯的雙分界特徵,我們考慮用雙閾值方法進行二值化操作。根據雙閾值操作方法,對於8位灰度圖應用該閾值化方法操作時,預先設定好特 定的閾值量thresh1,thresh2,並且thresh 如下 include opencv2 highgui highgui.hpp include open...