目标

在本节中

  • 我们将学习多视图几何的基础知识
  • 我们将了解什么是极点,极线,极线约束等。

基础概念

当我们使用针孔相机拍摄图像时,我们失去了重要信息,即图像深度。 或者图像中的每个点距相机多远,因为它是3D到2D转换。 因此,是否能够使用这些摄像机找到深度信息是一个重要的问题。 答案是使用不止一台摄像机。 在使用两台摄像机(两只眼睛)的情况下,我们的眼睛工作方式相似,这称为立体视觉。 因此,让我们看看OpenCV在此字段中提供了什么。

(通过Gary Bradsky学习OpenCV在该领域有很多信息。)

在深入图像之前,让我们首先了解多视图几何中的一些基本概念。在本节中,我们将讨论对极几何。请参见下图,该图显示了使用两台摄像机拍摄同一场景的图像的基本设置。

如果仅使用左摄像机,则无法找到与图像中的点相对应的3D点,因为线上的每个点都投影到图像平面上的同一点。但也要考虑正确的形象。现在,直线OXOXOX上的不同点投射到右侧平面上的不同点(x′x'x′)。因此,使用这两个图像,我们可以对正确的3D点进行三角剖分。这就是整个想法。

不同点的投影在右平面OXOXOX上形成一条线(linel′l'l′)。我们称其为对应于该点的Epiline。这意味着,要在正确的图像上找到该点,请沿着该轮廓线搜索。它应该在这条线上的某处(以这种方式考虑,可以在其他图像中找到匹配点,而无需搜索整个图像,只需沿着Epiline搜索即可。因此,它可以提供更好的性能和准确性)。这称为对极约束。类似地,所有点在另一幅图像中将具有其对应的Epiline。该平面称为对极面

OOO和O′O'O′是相机中心。从上面给出的设置中,您可以看到在点处的左侧图像上可以看到右侧摄像机O′O'O′的投影。它称为极点。极点是穿过相机中心和图像平面的线的交点。左摄像机的极点也同理。在某些情况下,您将无法在图像中找到极点,它们可能位于图像外部(这意味着一个摄像机看不到另一个摄像机)。

所有的极线都通过其极点。因此,要找到中心线的位置,我们可以找到许多中心线并找到它们的交点。

因此,在节中,我们将重点放在寻找对极线和极线。但是要找到它们,我们需要另外两种成分,即基础矩阵(F)基本矩阵(E),基础矩阵包含有关平移和旋转的信息,这些信息在全局坐标中描述了第二个摄像头相对于第一个摄像头的位置。参见下图(图像由Gary Bradsky提供:Learning OpenCV):

但是我们会更喜欢在像素坐标中进行测量,对吧? 基本矩阵除包含有关两个摄像头的内在信息之外,还包含与基本矩阵相同的信息,因此我们可以将两个摄像头的像素坐标关联起来。(如果我们使用的是校正后的图像,并用焦距除以标准化该点,F=EF=EF=E)。简而言之,基本矩阵F将一个图像中的点映射到另一图像中的线(上)。这是从两个图像的匹配点计算得出的。 至少需要8个这样的点才能找到基本矩阵(使用8点算法时)。 选择更多点并使用RANSAC将获得更可靠的结果。

代码

因此,首先我们需要在两个图像之间找到尽可能多的匹配项,以找到基本矩阵。为此,我们将SIFT描述符与基于FLANN的匹配器和比率测试结合使用。

  1. import numpy as np
  2. import cv2 as cv
  3. from matplotlib import pyplot as plt
  4. img1 = cv.imread('myleft.jpg',0) #索引图像 # left image
  5. img2 = cv.imread('myright.jpg',0) #训练图像 # right image
  6. sift = cv.SIFT()
  7. # 使用SIFT查找关键点和描述符
  8. kp1, des1 = sift.detectAndCompute(img1,None)
  9. kp2, des2 = sift.detectAndCompute(img2,None)
  10. # FLANN 参数
  11. FLANN_INDEX_KDTREE = 1
  12. index_params = dict(algorithm = FLANN_INDEX_KDTREE, trees = 5)
  13. search_params = dict(checks=50)
  14. flann = cv.FlannBasedMatcher(index_params,search_params)
  15. matches = flann.knnMatch(des1,des2,k=2)
  16. good = []
  17. pts1 = []
  18. pts2 = []
  19. # 根据Lowe的论文进行比率测试
  20. for i,(m,n) in enumerate(matches):
  21. if m.distance < 0.8*n.distance:
  22. good.append(m)
  23. pts2.append(kp2[m.trainIdx].pt)
  24. pts1.append(kp1[m.queryIdx].pt)

现在,我们获得了两张图片的最佳匹配列表。 让我们找到基本面矩阵。

  1. pts1 = np.int32(pts1)
  2. pts2 = np.int32(pts2)
  3. F, mask = cv.findFundamentalMat(pts1,pts2,cv.FM_LMEDS)
  4. # 我们只选择内点
  5. pts1 = pts1[mask.ravel()==1]
  6. pts2 = pts2[mask.ravel()==1]

接下来,我们找到Epilines。在第二张图像上绘制与第一张图像中的点相对应的Epilines。因此,在这里提到正确的图像很重要。我们得到了一行线。因此,我们定义了一个新功能来在图像上绘制这些线条。

  1. def drawlines(img1,img2,lines,pts1,pts2):
  2. ''' img1 - 我们在img2相应位置绘制极点生成的图像
  3. lines - 对应的极点 '''
  4. r,c = img1.shape
  5. img1 = cv.cvtColor(img1,cv.COLOR_GRAY2BGR)
  6. img2 = cv.cvtColor(img2,cv.COLOR_GRAY2BGR)
  7. for r,pt1,pt2 in zip(lines,pts1,pts2):
  8. color = tuple(np.random.randint(0,255,3).tolist())
  9. x0,y0 = map(int, [0, -r[2]/r[1] ])
  10. x1,y1 = map(int, [c, -(r[2]+r[0]*c)/r[1] ])
  11. img1 = cv.line(img1, (x0,y0), (x1,y1), color,1)
  12. img1 = cv.circle(img1,tuple(pt1),5,color,-1)
  13. img2 = cv.circle(img2,tuple(pt2),5,color,-1)
  14. return img1,img2

现在,我们在两个图像中都找到了Epiline并将其绘制。

  1. # 在右图(第二张图)中找到与点相对应的极点,然后在左图绘制极线
  2. lines1 = cv.computeCorrespondEpilines(pts2.reshape(-1,1,2), 2,F)
  3. lines1 = lines1.reshape(-1,3)
  4. img5,img6 = drawlines(img1,img2,lines1,pts1,pts2)
  5. # 在左图(第一张图)中找到与点相对应的Epilines,然后在正确的图像上绘制极线
  6. lines2 = cv.computeCorrespondEpilines(pts1.reshape(-1,1,2), 1,F)
  7. lines2 = lines2.reshape(-1,3)
  8. img3,img4 = drawlines(img2,img1,lines2,pts2,pts1)
  9. plt.subplot(121),plt.imshow(img5)
  10. plt.subplot(122),plt.imshow(img3)
  11. plt.show()

以下是我们得到的结果:

您可以在左侧图像中看到所有极点都收敛在右侧图像的外部。那个汇合点就是极点。

为了获得更好的结果,应使用具有良好分辨率和许多非平面点的图像。

附加资源

练习

  1. 一个重要的主题是相机的前移。然后,将在两个位置的相同位置看到极点,并且从固定点出现极点。 请参阅此讨论。
  2. 基本矩阵估计对匹配,离群值等的质量敏感。如果所有选定的匹配都位于同一平面上,则情况会变得更糟。检查此讨论。

欢迎关注磐创博客资源汇总站:

http://docs.panchuang.net/

欢迎关注PyTorch官方中文教程站:

http://pytorch.panchuang.net/

OpenCV中文官方文档:

http://woshicver.com/

OpenCV-Python 对极几何 | 五十一的更多相关文章

  1. 第三百五十一节,Python分布式爬虫打造搜索引擎Scrapy精讲—将selenium操作谷歌浏览器集成到scrapy中

    第三百五十一节,Python分布式爬虫打造搜索引擎Scrapy精讲—将selenium操作谷歌浏览器集成到scrapy中 1.爬虫文件 dispatcher.connect()信号分发器,第一个参数信 ...

  2. 孤荷凌寒自学python第五十一天初次尝试使用python连接Firebase数据库

    孤荷凌寒自学python第五十一天初次尝试使用python连接Firebase数据库 (完整学习过程屏幕记录视频地址在文末) 今天继续研究Firebase数据库,利用google免费提供的这个数据库服 ...

  3. Python第五十一天 python2升级为python3

    Python第五十一天  python2升级为python3 公司使用的生产环境系统是centos7,所以这里以centos7系统为基础,讲解将python2升级为python3的方法 centos7 ...

  4. 【图像处理】OpenCV+Python图像处理入门教程(五)阈值处理

    这篇随笔介绍使用OpenCV进行图像处理的第五章 阈值处理. 5  阈值处理 阈值是指像素到达某临界值.阈值处理表示像素到达某临界值后,对该像素点进行操作和处理. 例如:设定一幅图像素阈值为200,则 ...

  5. OpenCV Python教程(3、直方图的计算与显示)

    转载请详细注明原作者及出处,谢谢! 本篇文章介绍如何用OpenCV Python来计算直方图,并简略介绍用NumPy和Matplotlib计算和绘制直方图 直方图的背景知识.用途什么的就直接略过去了. ...

  6. 孤荷凌寒自学python第六十五天学习mongoDB的基本操作并进行简单封装4

    孤荷凌寒自学python第六十五天学习mongoDB的基本操作并进行简单封装4 (完整学习过程屏幕记录视频地址在文末) 今天是学习mongoDB数据库的第十一天. 今天继续学习mongoDB的简单操作 ...

  7. Ubuntu系统---安装Caffe (+OpenCV+Python+CPU-only)

    安装配置Ubuntu14.04+Caffe (+OpenCV+Python+CPU-only) 记录 [作者:Wu Ping.时间:20180428.] 本人已经安装很多次的Caffe了:从开始的初探 ...

  8. 自学笔记系列:《Python学习手册 第五版》 -写在开始之前

    今年双十一,在当当网上买了这本书,很厚很厚的一本书,大概有将近1700页左右,的确是一个“大工程”, 关于这本书的学习,我想采用一种博客的方式进行,既是写给自己,也想分享给每一个对Python学习感兴 ...

  9. python学习心得第五章

    python学习心得第五章 1.冒泡排序: 冒泡是一种基础的算法,通过这算法可以将一堆值进行有效的排列,可以是从大到小,可以从小到大,条件是任意给出的. 冒泡的原理: 将需要比较的数(n个)有序的两个 ...

随机推荐

  1. Ado.net01

    ------------恢复内容开始------------ 1.ExcuteReader using System; using System.Data.SqlClient; using Syste ...

  2. localstorage浏览器储存

    需求 a.html页面生成订单信息,b.html中调用. 通过不操作数据库,直接在浏览器自带的数据库中进行操作,当然主要是对Json数据的操作. a.html代码部分: <!--html--&g ...

  3. Linux学习资料地址汇总-不定时更(一)

    https://linux.linuxidc.com/ 用户名和密码都是www.linuxidc.com

  4. 4,Java中的多线程

    1,创建线程 ··· 继承Thread类:     必须覆写Thread的run方法. ··· 实现Runnable接口:     必须实现run方法,再传入到Thread(Runnable t)构造 ...

  5. W3C的盒子模型和IE的盒子模型

    盒子模型分为两种:W3C盒子模型(标准盒子模型)和IE盒子模型 盒子模型组成:content+padding+border+margin 标准盒子模型的width就是content 而IE盒子模型的w ...

  6. 【转】Maven详细

    Maven maven 中央仓库 网站 https://mvnrepository.com/ 全世界 发布到Maven仓库 供用类着使用 maven 本质上下载工具和构建工具 下载工具 迅雷 只能下载 ...

  7. python使用for循环打印9*9乘法表。

    代码如下: for a in range(1, 10): for b in range(1, 10): if b <= a: print("%d*%d=%d\t" % (b, ...

  8. php+apache 环境配置(window环境)

    最近,小主从事PHP开发.特将最近如何搭建php7的过程记录在此!希望有需要,可以借鉴!( 电脑必须win7 sp1以上, .netframework4 ) Windows7安装php7,Win7+p ...

  9. java中的对象 方法 引用 等一些抽象的概念是什么意思呢?

    2020-03-14 最近这一段时间有点忙,好久都没有更新博客了,之后我会一直坚持下去的,和大家一同进步的. 这段时间一直在学java,相信刚开始学习java的小白,刚开始接触那么些抽象的概念一定和我 ...

  10. spark打包详解

    spark打包还是比较复杂的,特别的其中有关R语言的模块.在本章,我就将其中遇到的所有问题为大家一一讲解,为大家提供一点经验. 这里的打包命令是直接从官网中找的,这里我们最后得到的是tgz格式的包.打 ...