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阅读 159,015评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,262评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,727评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,986评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,363评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,610评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,871评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,582评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,297评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,551评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,053评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,385评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,035评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,079评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,841评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,648评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,550评论 2 270

推荐阅读更多精彩内容