【OpenCV-Python】教程:6-3 Epipolar Geometry 对极几何

news2024/12/23 23:52:26

OpenCV Python Epipolar Geometry 对极几何

【目标】

  • 学习多视图几何
  • 学习极点、对极线、对极约束等等;

【理论】

当我们使用针孔相机拍摄图像时,我们会丢失一个重要的信息,即图像的深度。或者图像中的每个点距离摄像机有多远,因为这是一个3d到2d的转换。因此,我们能否利用这些相机找到深度信息是一个重要的问题。答案是使用多个相机。我们眼睛的工作原理类似于我们使用两个摄像头(两只眼睛),这被称为立体视觉。那么让我们来看看OpenCV在这个领域提供了什么。

在讨论深度图像之前,让我们先了解多视图几何中的一些基本概念。在这一节中,我们将讨论极面几何。请看下面的图片,它显示了两个相机拍摄同一场景的基本设置。

在这里插入图片描述

如果我们只使用左侧摄像机,我们无法在图像中找到点 x x x对应的3D点,因为直线 O X OX OX上的每个点都投影到图像平面上的同一点。但也要考虑正确的图像。现在直线 O X OX OX上的不同点投影到右平面上的不同点 x ′ x' x。有了这两张图像,我们就能三角测量出正确的三维点。这就是整个想法。

各点在 O X OX OX上的投影在右平面上形成一条直线(直线 l ’ l’ l)。我们称它为对应于点 x x x对极线,意思是,要找到右边图像上的点x,就沿着这个对极线搜索。它应该在这条线上的某个地方(这样想,要在其他图像中找到匹配点,你不需要搜索整个图像,只需要沿着对极线搜索。因此它提供了更好的性能和准确性)。这被称为外极约束。同样地,在另一张图中,所有点都有相应的对极线。平面 X O O ′ XOO' XOO被称为对极平面

O O O O ′ O' O是相机中心。从上面给出的设置中,你可以看到右边相机 O ′ O' O的投影在左边图像的点 e e e上,它被称为极点。极点是相机中心与图像平面的交点。同理, e ′ e' e是左边相机的极点。在某些情况下,你将无法在图像中定位极点,它们可能在图像之外(这意味着,一个相机看不到另一个)。

所有的极线都经过它的极点。因此,为了找到极点的位置,我们可以找到许多的极线并找到它们的交点。

在这节中,我们将重点寻找偶极线和偶极。但要找到它们,我们还需要两个要素,基本矩阵( F F F)和本质矩阵( E E E)。本质矩阵包含关于平移和旋转的信息,它们描述了第二个摄像机相对于第一个摄像机在全局坐标中的位置。

在这里插入图片描述

但是我们更喜欢用像素坐标进行测量,对吧?基本矩阵除了包含与本质矩阵相同的信息外,还包含了两个相机的内在信息,因此我们可以将两个相机在像素坐标上联系起来。(如果我们使用校正图像,并通过除以焦距归一化点,F=E)。简单地说,基本矩阵 F F F将一个图像中的点映射到另一个图像中的一条线(极线)。这是根据两幅图像中的匹配点计算出来的。至少需要8个这样的点来找到基本矩阵(使用8点算法)。更多的点更好,然后使用RANSAC得到更鲁棒的结果。

【代码】

在这里插入图片描述

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

# 读入图片
img1 = cv2.imread("assets/left.jpg", 0)
img2 = cv2.imread("assets/right.jpg", 0)

# 定义SIFT算子
sift = cv2.SIFT_create()

# 找到特征点和计算特征
kp1, des1 = sift.detectAndCompute(img1,None)
kp2, des2 = sift.detectAndCompute(img2,None)

# FLANN 参数
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)

# 选择匹配点中匹配度比较好的点
pts1 = []
pts2 = []
for i, (m,n) in enumerate(matches):
    if m.distance < 0.76*n.distance:
        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)

# 选择内部的点
pts1 = pts1[mask.ravel()==1]
pts2 = pts2[mask.ravel()==1]

## 画极线
def drawepilines(img1, img2, lines, pts1, pts2):
    r,c = img1.shape 
    img1_temp = cv2.cvtColor(img1, cv2.COLOR_GRAY2BGR)
    img2_temp = 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_temp = cv2.line(img1_temp,(x0,y0),(x1,y1),color,1)
        img1_temp = cv2.circle(img1_temp, tuple(pt1), 5, color, -1)
        img2_temp = cv2.circle(img2_temp, tuple(pt2), 5, color, -1)
    return img1_temp, img2_temp


# 根据右图的点找到左图的极线
lines1 = cv2.computeCorrespondEpilines(pts2.reshape(-1,1,2),2,F)
lines1 = lines1.reshape(-1,3)
img5, img6 = drawepilines(img1,img2,lines1,pts1,pts2)

# 根据左图的点找到右图的极线
lines2 = cv2.computeCorrespondEpilines(pts1.reshape(-1,1,2),1,F)
lines2 = lines2.reshape(-1,3)
img3, img4 = drawepilines(img2,img1,lines2,pts2,pts1)

res = np.hstack((img5, img3))
cv2.imshow("res", res)


# res1 = np.hstack((img5,img6))
# res2 = np.hstack((img4,img3))

# cv2.imshow("res1", res1)
# cv2.imshow("res2", res2)


cv2.waitKey(0)
cv2.destroyAllWindows()

NOTE: 这里极线的计算与选择的特征点有非常大的关系,要有足够好的特征来表明是同一个位置。

【接口】

  • findFundamentalMat
cv2.findFundamentalMat(	points1, points2, method, ransacReprojThreshold, confidence, maxIters[, mask]	) ->	retval, mask
cv2.findFundamentalMat(	points1, points2[, method[, ransacReprojThreshold[, confidence[, mask]]]]	) ->	retval, mask
cv2.findFundamentalMat(	points1, points2, params[, mask]	) ->	retval, mask

通过两个图像中对应的点,计算基本矩阵

  • points1: 第一幅图像的 N 个点集合,点的坐标必须是浮点数,单精度或双精度都可以
  • points2: 第二幅图像的 N 个点集合
  • method: 计算基本矩阵的方法
    • FM_7POINT: 7 个点的算法. N=7
    • FM_8POINT: 8 个点的算法. N≥8
    • FM_RANSAC: RANSAC 算法 N≥8
    • FM_LMEDS: LMedS 算法 N≥8
  • ransacReprojThreshold: RANSAC 方法的参数. 它是一个点到极线的最大距离(单位为像素),超过这个距离的点被认为是一个离群值,不用于计算最终的基本矩阵。它可以设置为1-3,这取决于点定位的精度、图像分辨率和图像噪声。
  • confidence: 仅用于RANSAC和lmed方法。它指定了估计矩阵正确的理想置信水平(概率)。
  • [out] mask: 可选的输出 mask
  • maxIters: 最多迭代次数

对极几何是这么描述的:

[ p 2 ; 1 ] T F [ p 1 ; 1 ] = 0 [p_2;1]^TF[p_1;1]=0 [p2;1]TF[p1;1]=0

F F F 是基础矩阵, p 2 p_2 p2 p 1 p_1 p1 分别对应第二张和第一张图像的点;

  • computeCorrespondEpilines
cv2.computeCorrespondEpilines(	points, whichImage, F[, lines]	) ->	lines

通过一个图像中的点找到另一幅图像中的极线

  • points: 输入的点集, N × 1 N×1 N×1 1 × N 1×N 1×N,类型为 CV_32FC2或者 Point2f的vector都可以
  • whichImage: 包含那些点的图像的索引(1或2)
  • F: 基础矩阵,用 findFundamentalMat 或 stereoRectify 计算;
  • lines: 输出的极线, a x + b y + c = 0 ax+by+c=0 ax+by+c=0, 直线方程通过 ( a , b , c ) (a,b,c) (a,b,c)描述。

【参考】

  1. OpenCV: Epipolar Geometry
  2. OpenCV: Camera Calibration and 3D Reconstruction
  3. One important topic is the forward movement of camera. Then epipoles will be seen at the same locations in both with epilines emerging from a fixed point. See this discussion.
  4. Fundamental Matrix estimation is sensitive to quality of matches, outliers etc. It becomes worse when all selected matches lie on the same plane. Check this discussion.
  5. 对极几何原理_阿升1990的博客-CSDN博客_对极几何
  6. 对极几何与基本矩阵 - 知乎 (zhihu.com)
  7. 从零开始一起学习SLAM | 不推公式,如何真正理解对极约束?_计算机视觉life的博客-CSDN博客_从零开始一起学习slam | 不推公式,如何真正理解对极约束?

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/95698.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

下一个AI舞台,名叫煤矿

如果大海给贝壳下的定义是珍珠&#xff0c;那么时间给煤的定义就是钻石。2020年初&#xff0c;我们曾经探访过山西一家大型矿山。矿山中的工程师对我们说&#xff0c;现在矿上特别需要新技术&#xff0c;需要数字化、智能化。但现在年轻人&#xff0c;尤其是懂AI、懂云计算的人…

Stm32旧版库函数16——stm32 超声波测距

/******************** (C) COPYRIGHT 2012 ELC ******************** * File Name : main.c * Author : ELCWHUT * Version : V1.0 * Date : 2012-12-05 * Description : 超声波测距的STM32代码&#xff0c;采用HC-HR04…

Git全栈体系(一)

第一章 Git 概述 Git 是一个免费的、开源的分布式版本控制系统&#xff0c;可以快速高效地处理从小型到大型的各种项目。Git 易于学习&#xff0c;占地面积小&#xff0c;性能极快。 它具有廉价的本地库&#xff0c;方便的暂存区域和多个工作流分支等特性。其性能优于 Subvers…

ArcGIS创建地理处理包!让你制作的工具自由分享

喜欢就关注我们吧&#xff01; 0 前言 当用模型做好工具 分享到其他电脑 出现的模型不可用的情况 就如我们上期制作分享 的提取四至点的工具 有这个红叉的情况 因为他用到了子模型 所以发生路径不一致的情况 只要编辑配置就好了 那如何从根本上解决这个问题呢 答案是…

大数据Kudu(八):Kudu与Impala整合

文章目录 Kudu与Impala整合 一、​​​​​​​Kudu与Impala整合配置

乌班图(ubantu)部署.NET Core 6web项目(保姆教程)

1、新建文件夹&#xff0c;给读写权限 $ cd / #移动根目录&#xff08;方便好找&#xff09; 文件夹授权方式1&#xff1a;命令 $ sudo mkdir www #新建文件夹 $ cd /www $ sudo chmod 777 * -R #给读写权限 2、上传打包的项目文件&#xff0c;并解压 安装解压工具 $ sudo …

线性代数之N维向量

向量空间是线性代数的重要研究对象&#xff0c;具有广泛的应用。 1 n维向量运算 向量既有大小又有方向&#xff0c;如下表示&#xff1a; m*n个数aij(i1,2,...,m;j1,2,...,n)排成m行n列的矩形数表 若向量大小相当&#xff0c;方向相同则着两个向量相等 n个数a1,a2,...,an组成的…

SQL执行顺序

目录 1.执行顺序 2.SELECT查询时的两个顺序 3.关联过程 1.执行顺序 我们先执行from,join来确定表之间的连接关系&#xff0c;得到初步的数据 where对数据进行普通的初步的筛选 group by 分组 各组分别执行having中的普通筛选或者聚合函数筛选。 然后把再根据我们要的数据进…

00后女记者的一场直播挑战,触动了多少城市年轻打工人的心

一、00后的女记者&#xff0c;在浙江的一个小镇做了一场直播挑战&#xff0c;几天的体验并不轻松&#xff0c;却打开了一个新世界。又或者说&#xff0c;她发现了生活的另一面&#xff0c;人生的另一种可能。这个名叫濮院的小镇&#xff0c;位于浙江北部&#xff0c;桐乡辖下&a…

测试员求职路漫漫其修远兮,HR眼中的你,为什么无人问津

&#x1f4cc; 博客主页&#xff1a; 程序员二黑 &#x1f4cc; 专注于软件测试领域相关技术实践和思考&#xff0c;持续分享自动化软件测试开发干货知识&#xff01; &#x1f4cc; 公号同名&#xff0c;欢迎加入我的测试交流群&#xff0c;我们一起交流学习&#xff01; 许多…

GrapeCity Documents .NET Bundle 6.0.0 Crack

GrapeCity 文档 .NET 包 6.0.0 添加新的图像查看器和数据查看器以及将 HTML 呈现为 PDF 的能力。2022 年 12 月 16 日 - 15:27 新版本特征 GrapeCity Word文档 您现在可以添加反射、发光、模糊、柔化边缘和填充叠加效果。报告模板 SVG 图像现在可以用作图像模板中的数据。有条件…

SOFA Weekly|Tongsuo 8.3.2 版本发布、C 位大咖说、本周 Contributor QA

SOFA WEEKLY | 每周精选 筛选每周精华问答&#xff0c;同步开源进展欢迎留言互动&#xff5e;SOFAStack&#xff08;Scalable Open Financial Architecture Stack&#xff09;是蚂蚁集团自主研发的金融级云原生架构&#xff0c;包含了构建金融级云原生架构所需的各个组件&#…

[附源码]Python计算机毕业设计Django宁财二手物品交易网站

项目运行 环境配置&#xff1a; Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术&#xff1a; django python Vue 等等组成&#xff0c;B/S模式 pychram管理等等。 环境需要 1.运行环境&#xff1a;最好是python3.7.7&#xff0c;…

换种方式看后端参数接收、建议躺着看!!!

持续创作&#xff0c;加速成长&#xff01;这是我参与「掘金日新计划 10 月更文挑战」的第1天&#xff0c;点击查看活动详情 常用的接收参数注解RequestParam PathVariable RequestBody 先看个例子RestController public class testController { RequestMapping(value "…

C++ Reference: Standard C++ Library reference: Containers: map: map: operator=

C官网参考链接&#xff1a;https://cplusplus.com/reference/map/map/operator/ 公有成员函数 <map> std::map::operator C98 copy (1) map& operator (const map& x); C11 copy (1) map& operator (const map& x); move (2) map& oper…

Linux学习04-文件权限与目录配置

1 用户和用户组的概念 Linux中的用户划分很有意义。分为用户、用户组与非本用户组。模式类似于学校的机房。 2 文件权限 使用ls -al查看文件权限&#xff1a; [rootstudy ~]# ls -al -rw-r--r--. 1 root root 1864 May 4 18:01 initial-setup-ks.cfg [ 1…

vue3表单输入绑定 v-model

vue3表单输入绑定 v-model 一、基本使用 1.1、v-model 使用 <template><input type"text" v-model"msg"/><h2>{{msg}}</h2> </template><script setup> import { ref} from vue const msgref("Hello World&quo…

Vue中路由守卫的具体应用

目录 &#x1f53d; 概述 1. 全局守卫——全局钩子函数 1.1 全局前置守卫——beforeEach 1.2 全局后置路由守卫 1.3 整合 2. 路由独享的守卫——路由独享的钩子函数 3.组件内的守卫——组件内的钩子函数 &#x1f53d; 参考资料 Vue-Router导航&#xff08;路由&#x…

卫龙上市酿成资本惨剧:CPE损失上亿美元 高瓴浮亏5000万美元

雷帝网 雷建平 12月16日本是年度最受期待的新消费企业上市&#xff0c;却酿成资本惨剧。“辣条一哥”卫龙&#xff08;股票代码为&#xff1a;“09985”&#xff09;昨日在港交所上市&#xff0c;发行价为10.56港元&#xff0c;募资净额为8.99亿港元&#xff1b;卫龙食品首日开…

大数据中的数据安全

数据安全体系全貌 在数据仓库平台中&#xff0c;对应数据的请求必须严格尊属数据安全体系 数据使用安全 数据安全 认证 授权 认证主要是对用户的身份确认&#xff0c;比如最简单的用户的登录需要账户和密码&#xff1b;像你登录Mysql需要输出用户名和密码。比如大数据中使用…