本文中我們準(zhǔn)備探索允許3D重建在實(shí)踐中工作的核心概念。具體來說,我們將了解多視圖或?qū)O幾何的基礎(chǔ)知識(shí)。
讓我們來看一下現(xiàn)代針孔相機(jī)的功能。當(dāng)一幅圖像被拍攝時(shí),它的信息呈現(xiàn)在二維平面上,在二維平面上,每個(gè)點(diǎn)(或像素)與相機(jī)鏡頭之間的距離是不存在的。但這正是我們?yōu)榱耸褂?D圖像執(zhí)行3D重建所需的信息。我們的解決方案的關(guān)鍵在于使用第二個(gè)攝像頭拍攝同一物體的照片,并比較每個(gè)圖像來提取深度信息。我們的眼睛在類似的情況下執(zhí)行著同樣的任務(wù)。不過,OpenCV包含的工具可以幫助我們?cè)诜侨祟愥樋紫鄼C(jī)拍攝的圖像中看到深度。
我們先分析下面這張圖,該圖說明了兩個(gè)攝像機(jī)拍攝同一場(chǎng)景照片的場(chǎng)景中多視圖幾何的一些基本概念。
通過檢查從左側(cè)攝像機(jī)的中心點(diǎn)發(fā)出的上圖所示的OX線,我們可以看到該沿線有3個(gè)點(diǎn),我們需要知道它們與O點(diǎn)的距離。如前所述我們并不能夠僅從左側(cè)相機(jī)中提取此信息。然而,對(duì)于右側(cè)相機(jī),我們可以看到X的3個(gè)點(diǎn)可以沿其圖像平面上的一條直線投影(直線用:l '表示)。這條線被稱為核線(epiline); 必須出現(xiàn)沿著OX線的任何點(diǎn)X的線。重要的是,當(dāng)我們?cè)谟覀?cè)相機(jī)的圖像中搜索X的匹配點(diǎn)時(shí),我們已經(jīng)知道它將沿著該核線出現(xiàn),因此大大減少了我們的搜索工作量。此外,我們可以假設(shè)在左側(cè)圖像中出現(xiàn)的每個(gè)點(diǎn)將始終具有在右側(cè)圖像中找到的伴隨的核線。這被稱為極線約束。
需要注意的另一個(gè)重要方面是核點(diǎn)(epipole)。核點(diǎn)是連接到每個(gè)攝像機(jī)中心點(diǎn)的線在核面內(nèi)的交點(diǎn)。在上面的圖中,0和0 '分別表示在兩端。點(diǎn)e和e'是對(duì)方相機(jī)的中心點(diǎn)出現(xiàn)在對(duì)應(yīng)圖像中的點(diǎn)。通過將點(diǎn)X(我們?cè)噲D提取其深度值的點(diǎn))包含在核點(diǎn)線上,我們可以導(dǎo)出這個(gè)平面表示為X00'的平面。該平面稱為極線平面。
我們還可以在上圖中看到,右側(cè)圖像中的X點(diǎn)的投影與相對(duì)的相機(jī)(e')的核點(diǎn)相交。這顯示了所有的極線將如何通過圖像中找到的核點(diǎn)(相對(duì)照相機(jī)的真實(shí)中心點(diǎn)將出現(xiàn)的圖像點(diǎn))。這一點(diǎn)的重要性在于我們能夠通過找到多個(gè)核線相交的圖像點(diǎn)來精確計(jì)算出核點(diǎn)在我們的圖像中的位置。我們還應(yīng)該注意,在很多情況下,在相對(duì)圖像的幀中可能沒有捕獲一個(gè)或兩個(gè)相機(jī)中心點(diǎn),這意味著該極點(diǎn)將落在其2D像素矩陣之外。盡管如此,我們?nèi)匀豢梢酝ㄟ^分析核線精確地計(jì)算出虛構(gòu)的核點(diǎn)位置,從而達(dá)到提取深度信息的最終目標(biāo)。
由于我們現(xiàn)在已經(jīng)涵蓋了對(duì)極幾何的基礎(chǔ)知識(shí),我們現(xiàn)在可以解決另外兩個(gè)元素,以便找到核點(diǎn)和核線。
基本矩陣包含有關(guān)平移和旋轉(zhuǎn)的信息,它描述了相機(jī)相對(duì)于其對(duì)應(yīng)物的位置。下圖展示了基本矩陣。
但是對(duì)于我們的解決方案,我們希望根據(jù)相機(jī)像素坐標(biāo)進(jìn)行計(jì)算。這是基本矩陣發(fā)揮作用的地方,因?yàn)樗c實(shí)際矩陣相同的信息,但也包括關(guān)于兩個(gè)相機(jī)的內(nèi)在信息,以便我們可以用這樣的術(shù)語將兩者聯(lián)系起來。雖然基本矩陣中的信息來源于我們相機(jī)的真實(shí)世界定位,但實(shí)際矩陣必須自己計(jì)算?;揪仃囋试S我們做的是將一個(gè)圖像中的單個(gè)點(diǎn)映射到另一個(gè)圖像中的相應(yīng)的極線,為我們提供一個(gè)起點(diǎn),以便之后找到兩個(gè)攝像機(jī)中心點(diǎn)和極平面之間的核線。
但是我們?nèi)绾斡?jì)算實(shí)際矩陣?我們可以使用OpenCV從每個(gè)圖像中的一組已知匹配點(diǎn)推導(dǎo)出這個(gè)矩陣。這基本上是一個(gè)校準(zhǔn)過程,建議從圖像中找到最少8個(gè)匹配點(diǎn),并用于達(dá)到所需的準(zhǔn)確度。為此,我們使用OpenCV分析兩個(gè)圖像并提取其最佳匹配像素坐標(biāo)。在下面的Python代碼中,我們使用SIFT描述符和基于FLANN的matcher和ratio文本提取這些點(diǎn)。
這將為我們提供兩個(gè)圖像中最佳像素匹配的列表,然后可以將其發(fā)送以計(jì)算實(shí)際矩陣,我們將在下面使用OpenCV的功能進(jìn)行計(jì)算。Python代碼如下:
pts1 = np.int32(pts1)pts2 = np.int32(pts2)F, mask = cv2.findFundamentalMat(pts1,pts2,cv2.FM_LMEDS)# We select only inlier pointspts1 = pts1[mask.ravel()==1]pts2 = pts2[mask.ravel()==1]
讓我們花點(diǎn)時(shí)間創(chuàng)建一個(gè)Python函數(shù),它將在我們的圖像上繪制線條,這些線條稍后將用于可視化核線。
現(xiàn)在我們繼續(xù)計(jì)算與相對(duì)圖像中的點(diǎn)相對(duì)應(yīng)的核線。在這個(gè)階段,我們還需要注意我們正在使用哪個(gè)相機(jī),因?yàn)槲覀儗⒃谝粋€(gè)圖像中找到點(diǎn),并在其對(duì)應(yīng)物上繪制核線。下面的代碼將生成一個(gè)行數(shù)組,我們可以隨后將其發(fā)送到繪圖函數(shù)。Python代碼如下:
# Find epilines corresponding to points in right image (second image) and# drawing its lines on left imagelines1 = cv2.computeCorrespondEpilines(pts2.reshape(-1,1,2), 2,F)lines1 = lines1.reshape(-1,3)img5,img6 = drawlines(img1,img2,lines1,pts1,pts2)# Find epilines corresponding to points in left image (first image) and# drawing its lines on right imagelines2 = cv2.computeCorrespondEpilines(pts1.reshape(-1,1,2), 1,F)lines2 = lines2.reshape(-1,3)img3,img4 = drawlines(img2,img1,lines2,pts2,pts1)plt.subplot(121),plt.imshow(img5)plt.subplot(122),plt.imshow(img3)plt.show()
結(jié)果顯示兩幅帶有核線的圖像,它們代表了來自相反圖像的點(diǎn)數(shù)組。我們可以注意到,每一組線的集合點(diǎn)都在攝像機(jī)視圖之外。這個(gè)虛構(gòu)的點(diǎn)是核點(diǎn)(即在三維空間中,相對(duì)攝像機(jī)的中心點(diǎn))。
最后,我們應(yīng)該認(rèn)識(shí)到在嘗試進(jìn)行3D重建時(shí)相機(jī)分辨率的重要性。這是由于在我們的過程中,第一步我們必須使用一種算法來識(shí)別每幅圖像中非常匹配的像素,這樣我們就可以產(chǎn)生一個(gè)精確的基本矩陣。分辨率越低,我們處理的信息就越少,因此極大地阻礙了保持精度的能力。盡管如此,我們?nèi)栽谟昧Ⅲw圖像進(jìn)行全面三維重建的,我們的最后一步是使用第二個(gè)相應(yīng)的極線計(jì)算第一個(gè)圖像上的點(diǎn)的深度。
聯(lián)系客服