OpenCV-Python教程:48.核面幾何

基礎概念

當我們使用針孔攝像機拍攝圖像時,我們會丟失重要信息,圖像的深度。或者圖像每個點離攝像機有多遠,因為這是一個3D到2D的轉換。所以我們是否能找到深度信息就變得很重要。回答是使用多個攝像機。我們的眼睛也是類似的方法,我們使用兩個攝像機(雙眼),這被叫做立體影像。所以我們看看OpenCV提供了什么。

在更進一步之前,我們先明白一些多視幾何的基礎概念。在本節里,我們會用核面幾何處理。看下面的圖像顯示了兩個攝像機對同一個場景拍攝圖像的基本設置。

如果我們只用左邊的攝像機,我們沒法找到點x的對應3D點。因為線OX上的每一個點在圖像平面都投影到同一個點。但是如果加上右邊的攝像機,現在OX線上的不同點在右邊的平面投影到了不同的點(x')。所以用兩個圖像,我們可以三角測量正確的3D點。這就是所有想法。

在右邊平面上不同點投影出來的直線(l')。我們叫做點x對應的極線。它表示,要找到右邊圖像里的點x,沿著這根直線找就行。它應該在這條線上的某出(這么想,要找到在另一張圖上的對應點,你不需要搜索整張圖片,只需要在這根直線上找就行。所以它提供了更好的性能和準確性)。這被叫做極限約束。類似的所有的點都會在另一張圖上有對應的極線。平面XOO'背景叫做偏斜面。

O和O'是攝像機中心,從上面可以看到右邊攝像機的O'的投影可以在左邊圖片看到,e點。這被叫做極點。極點是通過兩個攝像機中心的直線與圖片平面的焦點。類似的,e'是左邊攝像機的極點。在某些情況下,你沒法在圖像內定位極點,他們可能在圖像外(這表示攝像機沒法看見彼此)。

所有的極線都通過極點。所以要找到極點的位置,我們可以找多條極線,然后找他們的交點。

我們要找到極線和極點,需要兩個東西,基礎矩陣(F)和本質矩陣(E)。本質矩陣包含平移和旋轉的信息,描述了第二個攝像機相對于第一個在全局坐標系里的位置。看下圖:

基礎矩陣包含了和本質矩陣一樣的信息,另外還有兩個攝像機內聯信息,這樣我們可以把兩個攝像機在像素坐標系內關聯起來。(如果我們使用修正過的圖像并按焦距把點分開正規化了,F=E)。簡單的說,基礎矩陣F把一個圖像里的點映射到另一個圖里的線(極線)。這是通過兩個圖像里的匹配點計算的。最少需要8個點來得到基礎矩陣(使用8點算法),最好能有多個點來使用RANSAC來得到更健壯得到結果。

編碼:

所以我們需要找到兩張圖像里盡可能多的匹配來找基礎矩陣。為了這個,我們使用基于FLANN匹配子的SIFT描述子和比率測試

import cv2
import numpy as np
from matplotlib import pyplot as plt

img1 = cv2.imread('myleft.jpg',0)? #queryimage # left image
img2 = cv2.imread('myright.jpg',0) #trainimage # right image

sift = cv2.SIFT()

# find the keypoints and descriptors with SIFT
kp1, des1 = sift.detectAndCompute(img1,None)
kp2, des2 = sift.detectAndCompute(img2,None)

# FLANN parameters
FLANN_INDEX_KDTREE = 0
index_params = dict(algorithm = FLANN_INDEX_KDTREE, trees = 5)
search_params = dict(checks=50)

flann = cv2.FlannBasedMatcher(index_params,search_params)
matches = flann.knnMatch(des1,des2,k=2)

good = []
pts1 = []
pts2 = []

# ratio test as per Lowe's paper
for i,(m,n) in enumerate(matches):
? ? if m.distance < 0.8*n.distance:
? ? ? ? good.append(m)
? ? ? ? pts2.append(kp2[m.trainIdx].pt)
? ? ? ? pts1.append(kp1[m.queryIdx].pt)

現在我們有兩個圖片里最佳匹配的列表,我們來找基礎矩陣

pts1 = np.int32(pts1)
pts2 = np.int32(pts2)
F, mask = cv2.findFundamentalMat(pts1,pts2,cv2.FM_LMEDS)

# We select only inlier points
pts1 = pts1[mask.ravel()==1]
pts2 = pts2[mask.ravel()==1]

下面我們找極線,極線在第一個圖像里對應的點畫在第二個圖像里。我們得到線的數組,我們定義一個新的函數來在圖像里畫這些線。

def drawlines(img1,img2,lines,pts1,pts2):
? ? ''' img1 - image on which we draw the epilines for the points in img2?lines - corresponding epilines '''
? ? r,c = img1.shape
? ? img1 = cv2.cvtColor(img1,cv2.COLOR_GRAY2BGR)
? ? img2 = cv2.cvtColor(img2,cv2.COLOR_GRAY2BGR)
? ? for r,pt1,pt2 in zip(lines,pts1,pts2):
? ? ? ? color = tuple(np.random.randint(0,255,3).tolist())
? ? ? ? x0,y0 = map(int, [0, -r[2]/r[1] ])
? ? ? ? x1,y1 = map(int, [c, -(r[2]+r[0]*c)/r[1] ])
? ? ? ? img1 = cv2.line(img1, (x0,y0), (x1,y1), color,1)
? ? ? ? img1 = cv2.circle(img1,tuple(pt1),5,color,-1)
? ? ? ? img2 = cv2.circle(img2,tuple(pt2),5,color,-1)
? ? return img1,img2

現在我們找同時在兩個圖像里的極線并畫出他們:

# Find epilines corresponding to points in right image (second image) and
# drawing its lines on left image

lines1 = 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 image
lines2 = 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()

下面是我們得到的結果

你可以看到在左邊的圖像里所有的極線匯聚在圖像外的點。那個匯聚點就是極點。

要得到更好的結果,應該用有好的分辨率的圖像,有很多非平面的點

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,428評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,024評論 3 413
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,285評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,548評論 1 307
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,328評論 6 404
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 54,878評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 42,971評論 3 439
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,098評論 0 286
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,616評論 1 331
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,554評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,725評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,243評論 5 355
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 43,971評論 3 345
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,361評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,613評論 1 280
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,339評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,695評論 2 370

推薦閱讀更多精彩內容