单应矩阵(Homography)基本概念和代码测试
简 介: 应用棋盘格图片或者相机图片中与标准棋盘格之间的单应矩阵。其中应用到opencv中的findChessboardCorners, findHomographys等函数。 这位利用单应矩阵进行下步的矫正工作提供实验基础。
关键词
: 单应矩阵,Homogrpaphy
Contents
阵进行姿态估计
§00 背景说明
这是在 OpenCV网站 中给出的技术文章,讲述单应矩阵(Homography)的基本概念,并通过测试程序进行介绍。
- 文章链接: Basic concepts of the homography explained with code
0.1 介绍
下面的辅导材料利用一些编程代码展示了单应变换(Homograpy)的一些基本概念。关于该理论的详细解释请参见机器视觉课程,或者计算机视觉参考书,比如:
- Multiple View in Computer Vision .
- An tinviation to 3D vision: From images to Geometric Models
- Computer Vision: Algorithms and Applications .
本文中的一些代码可以以下链接找到:
- C++代码 ;
- Python代码 ;
- Java代码 。
实验中所使用的图片可以在 这个图片链接 下载,但在国内点击无法访问该网站。
§01 基本理论
1.1 什么是单应矩阵?
简单的讲,平面中的单应矩阵涉及到两个平面中的变换(相差一个比例因子)。
其中3×3矩阵HHH就是单应矩阵,由于在估计过程中可以相差一个比例因子,所以单应矩阵具有8个自由变量,通常情况下将该矩阵进行归一化,使得h33=1h_{33} = 1h33=1,或者
h112+h122+h132+h212+h222+h232+h312+h322+h332=1h_{11}^2 + h_{12}^2 + h_{13}^2 + h_{21}^2 + h_{22}^2 + h_{23}^2 + h_{31}^2 + h_{32}^2 + h_{33}^2 = 1h112+h122+h132+h212+h222+h232+h312+h322+h332=1
下面的例子显示了不同的变换,但最终可以归纳到两个平面之间的转换矩阵。
- 从平面到像平面(图片从像平面获取)
▲ 图1.1.1 从平面转换到像平面
- 两个相机对同一平面取像
▲ 图1.1.2 两个相机对同一平面取像
- 围绕投影轴旋转相机:
等效考虑一个位于无穷远处的平面上的点。
▲ 图1.1.3 旋转的相机
1.2 如何获得单应矩阵?
如果相应计算两个图片之间的单应矩阵,只有需要确定两个图片中四个以上的对应点的位置。OpenCV通过稳定的算法获得两个图片之间的单应矩阵。可以使用SIFT, 或者SURF算法来寻找两个图片之间对应的像素点。
根据 CV2.findhomography: Things You Should Know 中给出的计算单应矩阵的方法:
假设如下两个点是对应的像素点坐标:
x=(uv1),x′=(xy1)x = \left( \begin{matrix} u\\v\\1\\\end{matrix} \right),\,\,x' = \left( \begin{matrix} x\\y\\1\\\end{matrix} \right)x=⎝⎛uv1⎠⎞,x′=⎝⎛xy1⎠⎞
它们之间的单应矩阵为:
通过消去上述公式中的参数 ccc,可以得到如下方程:
Ah=0Ah = 0Ah=0
其中:
利用cv2
中的 findHomography(points1,points2)
可以计算两个图片之间的单应矩阵。
1.3 单应矩阵应用场合
利用共面点进行相机姿态估计,应用在基于某些标示(Apriltag)下的增强现实。
▲ 图1.2.1 在Apriltag上的增强虚拟现实
消除透视效应/视角校正(参见前面第二个例子)
▲ 图1.2.2 透视校正
- 全景图拼接(参见前面第二个、第三个例子)
▲ 图1.2.3 全景图拼接
§02 应用代码
2.1 演示1:从共面点阵进行姿态估计
请注意下面从单应矩阵估计相机姿态是一个应用例子,你需要使用 cv2::solvePnP 来对来自同一平面或者任意物体上的点来估计相机姿态。
单应矩阵可以使用 直接线性变换(DLT)算法来进行估计(见前面理论部分1)。由于对象是在同一平面,所以物体上的点都在同一平面上,在归一化相机成像框架中,描述共面点与像平面上成像位置之间的变换就是单应矩阵。只有当物体是平面,相机内参已知的情况下,相机的姿态才可以从单应矩阵中估计出来。
可以使用棋盘格以及cv2. findChessboardCorners() 得到图片中的角点。
要检测棋盘格角点,首先需要确认棋盘格尺寸(pattenSize),下图是9×6,:
vector<Point2f> corners;
bool found = findChessboardCorners(img, patternSize, corners);
▲ 图2.1.1 棋盘格中的角点
2.1.1 提取棋盘格角点
img = cv2.imread(outfile)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
ret, corners = cv2.findChessboardCorners(gray, (9, 6), None)if ret:cv2.drawChessboardCorners(img, (9, 6), corners, ret)
else: print('Error:%s'%ret)plt.clf()
plt.figure(figsize=(15,15))
plt.axis("off")
plt.imshow(img)
len(corners): 54
▲ 图2.1.2 提取角点 后的图像
2.1.2 计算相机校正参数
obj_p = zeros((9*6, 3), float32)
obj_p[:,:2] = mgrid[0:9, 0:6].T.reshape(-1, 2)obj_points = []
obj_points.append(obj_p)img_points = []
img_points.append(corners.reshape(-1, 2))print(shape(obj_points), shape(img_points))
(1, 54, 3)
(1, 54, 2)
ret,mtx,dist,rvevs,twecs = cv2.calibrateCamera(obj_points, img_points, (9, 6), None, None)
print("ret: {}".format(ret), "mtx: {}".format(mtx), "dist: {}".format(dist), "rvevs: {}".format(rvevs), "twecs: {}".format(twecs))
ret: 0.4988758679961617 mtx: [[1.32143507e+03 0.00000000e+00 3.47757768e+01][0.00000000e+00 1.40656199e+03 7.85365051e+01][0.00000000e+00 0.00000000e+00 1.00000000e+00]]dist: [[ -3.15645355 11.01014726 0.21957824 0.5021844 -66.56563905]]rvevs: [array([[-0.4002855 ],[ 0.73265038],[ 0.00263827]])]twecs: [array([[ 3.79424711],[ 0.96399769],[37.96708 ]])]
calibrateCamera返回参数
- ret: 表示所有理想角点映射到图片上的距离与图片对应点之间距离的平方和。参见: Camera Calibration and 3D Reconstruction?
- mtx: 摄像头内部的参数;
- dist: 镜头失真参数:k1,k2,p1,p2,k3k_1 ,k_2 ,p_1 ,p_2 ,k_3k1,k2,p1,p2,k3
- rvecs: 旋转矢量;可以通过Rodrigues转换成旋转矩阵;
- tvecs: 平移矢量。
2.1.3 计算单应矩阵
bps = obj_points[0][:,:2].reshape(-1, 1, 2)
ips = img_points[0].reshape(-1, 1, 2)
print(shape(bps), shape(ips))
matrix, mask = cv2.findHomography(bps, ips, cv2.RANSAC, 5.0)print("matrix: {}".format(matrix), "mask: {}".format(mask))
(54, 1, 2)
(54, 1, 2)matrix: [[ 3.13837780e+01 -3.42332647e+00 1.83431598e+02][-5.11097467e+00 3.73001120e+01 1.19897742e+02][-2.01067307e-02 -8.73882962e-03 1.00000000e+00]]mask: [[1][1][1][1][1][1][0][0][0][1][1][1][1][1][1][1][0][0][1][1][1][1][1][1][1][1][0][1][1][1][1][1][1][1][1][0][1][1][1][1][1][1][1][1][0][1][1][1][1][1][1][1][0][0]]
※ 测试总结 ※
应用棋盘格图片或者相机图片中与标准棋盘格之间的单应矩阵。其中应用到opencv中的findChessboardCorners, findHomographys等函数。 这位利用单应矩阵进行下步的矫正工作提供实验基础。
■ 相关文献链接:
- OpenCV网站
- Basic concepts of the homography explained with code
- Multiple View in Computer Vision
- An tinviation to 3D vision: From images to Geometric Models
- Computer Vision: Algorithms and Applications
- C++代码
- Python代码
- Java代码
- 这个图片链接
- CV2.findhomography: Things You Should Know
- cv2::solvePnP
- findChessboardCorners()
● 相关图表链接:
- 图1.1.1 从平面转换到像平面
- 图1.1.2 两个相机对同一平面取像
- 图1.1.3 旋转的相机
- 图1.2.1 在Apriltag上的增强虚拟现实
- 图1.2.2 透视校正
- 图1.2.3 全景图拼接
- 图2.1.1 棋盘格中的角点
- 图2.1.2 提取角点 后的图像
#!/usr/local/bin/python
# -*- coding: gbk -*-
#============================================================
# TEST1.PY -- by Dr. ZhuoQing 2021-12-30
#
# Note:
#============================================================from headm import * # =
import wget
import cv2#------------------------------------------------------------
imageurl = 'https://docs.opencv.org/3.4/homography_pose.jpg'
outfile = '/home/aistudio/work/chessbimg1.jpg'if not os.path.isfile(outfile):wget.download(imageurl, outfile)#------------------------------------------------------------img = cv2.imread(outfile)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)#------------------------------------------------------------
'''
plt.clf()
plt.figure(figsize=(10,10))
plt.axis("off")
plt.imshow(gray, cmap=plt.cm.gray)'''
#------------------------------------------------------------
ret, corners = cv2.findChessboardCorners(gray, (9, 6), None)if ret:cv2.drawChessboardCorners(img, (9, 6), corners, ret)
else: print('Error:%s'%ret)plt.clf()
plt.figure(figsize=(15,15))
plt.axis("off")
plt.imshow(img)#------------------------------------------------------------
obj_p = zeros((9*6, 3), float32)
obj_p[:,:2] = mgrid[0:9, 0:6].T.reshape(-1, 2)obj_points = []
obj_points.append(obj_p)img_points = []
img_points.append(corners.reshape(-1,2))printt(shape(obj_points), shape(img_points))#------------------------------------------------------------
ret,mtx,dist,rvevs,twecs = cv2.calibrateCamera(obj_points, img_points, (9, 6), None, None)
printt(ret:, mtx:, dist:)
printt(rvevs:, twecs:)#------------------------------------------------------------
bps = obj_points[0][:,:2].reshape(-1, 1, 2)
ips = img_points[0].reshape(-1, 1, 2)
printt(shape(bps), shape(ips))
matrix, mask = cv2.findHomography(bps, ips, cv2.RANSAC, 5.0)printt(matrix:, mask:)#------------------------------------------------------------
matches_mask = mask.ravel().tolist()
printt(matches_mask)#------------------------------------------------------------
# END OF FILE : TEST1.PY
#============================================================
单应矩阵(Homography)基本概念和代码测试相关推荐
- H(单应矩阵homography),本质矩阵(Essential Matrix)和F(基础矩阵fundamental)
文章目录 A x = 0 Ax=0 Ax=0 问题的求解 H(单应矩阵homography),本质矩阵(Essential Matrix)和F(基础矩阵fundamental) 单应矩阵 求解H步骤 ...
- OpenCV用代码解释单应性的基本概念
OpenCV用代码解释单应性的基本概念 用代码解释单应性的基本概念 基础理论 单应矩阵是什么? 单应变换如何有用? 示范代码 从共面点估计姿势 用代码解释单应性的基本概念 基础理论 单应矩阵是什么? ...
- Colmap学习三:后端Initialization部分(基础矩阵F、本质矩阵E和单应矩阵H)
算矩阵的基础知识 解析本质.基础.单应矩阵的自由度 1 寻找初始像对 1.1手动选择ID 1.2自动筛选 ①prior focal length存在情况下,开始筛选 匹配点数由小到大排序 第二张候选影 ...
- 单应性矩阵和仿射变换_单应矩阵 基本矩阵 本质矩阵的区别与联系
1. 叉乘 2. 双目系统 3. 对极几何 (Epipolar Geometry) 对极几何定义:是两个视图间的内部射影几何,它只与摄像机的内部参数和相对位姿有关,与场景结构无关. 基线(baseli ...
- 单应矩阵,基本矩阵,本质矩阵
1.归一化图像坐标 2.本质矩阵 essential matrix 2.1 本质矩阵的推导 2.2特点 3.相机内参 4.基本矩阵 fundamental matrix 4.2基本矩阵推导 4.1特点 ...
- 视觉SLAM 第7讲 本质矩阵 基础矩阵 单应矩阵 知识点/证明/理解/秩/自由度
视觉SLAM 第7讲 本质矩阵 基础矩阵 单应矩阵 证明/理解/秩/自由度 1. 基础知识 2. 本质矩阵E 2.1 本质矩阵的秩为什么是2 2.2 本质矩阵的自由度为什么是5 3. 基础矩阵F 3. ...
- 透视变换 单应性矩阵怎么求 matlab,单应性(homography)变换的推导
矩阵的一个重要作用是将空间中的点变换到另一个空间中.这个作用在国内的<线性代数>教学中基本没有介绍.要能形像地理解这一作用,比较直观的方法就是图像变换,图像变换的方法很多,单应性变换是其中 ...
- 单应性Homography梳理,概念解释,传统方法,深度学习方法
Homography 这篇博客比较清晰准确的介绍了关于刚性变换,仿射变换,透视投影变换的理解 单应性变换 的 条件和表示 用 [无镜头畸变] 的相机从不同位置拍摄 [同一平面物体] 的图像之间存在单应 ...
- ORB-SLAM2从理论到代码实现(四):相机成像原理、基本矩阵、本质矩阵、单应矩阵、三角测量详解
由于ORBmatcher.cc中有三角化和重投影等内容,所有我先写相机成像等多视图几何内容. 1. 相机的成像原理 假设空间中有一点P,它在世界坐标系中的坐标为,在相机坐标系中的坐标为,在图片中的像素 ...
最新文章
- 阿里面试官:接口的幂等性怎么设计?
- 《JAVA练习题目10》请对图书馆系统中的CatalogItem类、Book类和Recording类进行改造,实现其code属性的自动编码。
- graal java_使用SparkJava和Graal的本机微服务
- eclipse编写wordcount提交spark运行
- nemesis什么车_狂野飙车9TrionNemesis介绍 S级车Trion复仇女神属性详解
- 信息学奥赛一本通(2043:【例5.11】杨辉三角形)
- magento 获取产品存货量以及configurable product 下associated children product信息
- CakePHP 2.x十分钟博客教程
- 【算法】剑指 Offer 25. 合并两个排序的链表
- 今天给同学写5个数据结构算法的题...感觉很有价值的几个题..感兴趣的坐下。。...
- openwrt编译基本教程
- 如何解决VC 应用程序无法启动,因为应用程序的并行配置不正确 sxstrace.exe问题...
- JUC- 常用的辅助类
- PV-RCNN: Point-Voxel Feature Set Abstraction for 3D Object Detection阅读
- Gateway统一网关(2021-11-14)
- qq无法启动此程序计算机中丢失dll,Win7系统打开QQ提示丢失DLL文件怎么办
- 可跨页字符串:使用Spans设置文本样式
- Sublime Text 设置中文版
- 键盘VK键值(java键盘监听)
- 可交换债券是特殊的公司债