简 介: 应用棋盘格图片或者相机图片中与标准棋盘格之间的单应矩阵。其中应用到opencv中的findChessboardCorners, findHomographys等函数。 这位利用单应矩阵进行下步的矫正工作提供实验基础。

关键词 单应矩阵Homogrpaphy

背景说明
目 录
Contents
介绍
基本理论
什么是单应矩阵?
如何获得单应矩阵?
单应矩阵应用场合
应用代码
演示1:从共面点
阵进行姿态估计
测试总结

 

§00 景说明

  这是在 OpenCV网站 中给出的技术文章,讲述单应矩阵(Homography)的基本概念,并通过测试程序进行介绍。

0.1 介绍

  下面的辅导材料利用一些编程代码展示了单应变换(Homograpy)的一些基本概念。关于该理论的详细解释请参见机器视觉课程,或者计算机视觉参考书,比如:

  本文中的一些代码可以以下链接找到:

  实验中所使用的图片可以在 这个图片链接 下载,但在国内点击无法访问该网站。

 

§01 本理论


1.1 什么是单应矩阵?

  简单的讲,平面中的单应矩阵涉及到两个平面中的变换(相差一个比例因子)。


  其中3×3矩阵 H H H就是单应矩阵,由于在估计过程中可以相差一个比例因子,所以单应矩阵具有8个自由变量,通常情况下将该矩阵进行归一化,使得 h 33 = 1 h_{33} = 1 h33=1,或者
h 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 = 1 h_{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 = 1 h112+h122+h132+h212+h222+h232+h312+h322+h332=1

  下面的例子显示了不同的变换,但最终可以归纳到两个平面之间的转换矩阵。

  • 从平面到像平面(图片从像平面获取)

▲ 图1.1.1  从平面转换到像平面

▲ 图1.1.1 从平面转换到像平面

  • 两个相机对同一平面取像

▲ 图1.1.2  两个相机对同一平面取像

▲ 图1.1.2 两个相机对同一平面取像

  • 围绕投影轴旋转相机:

  等效考虑一个位于无穷远处的平面上的点。

▲ 图1.1.3  旋转的相机

▲ 图1.1.3 旋转的相机

1.2 如何获得单应矩阵?

  如果相应计算两个图片之间的单应矩阵,只有需要确定两个图片中四个以上的对应点的位置。OpenCV通过稳定的算法获得两个图片之间的单应矩阵。可以使用SIFT, 或者SURF算法来寻找两个图片之间对应的像素点。

  根据 CV2.findhomography: Things You Should Know 中给出的计算单应矩阵的方法:

  假设如下两个点是对应的像素点坐标:

x = ( u v 1 ) ,    x ′ = ( x y 1 ) x = \left( \begin{matrix} u\\v\\1\\\end{matrix} \right),\,\,x' = \left( \begin{matrix} x\\y\\1\\\end{matrix} \right) x=uv1,x=xy1

  它们之间的单应矩阵为:


  通过消去上述公式中的参数 c c c,可以得到如下方程:
A h = 0 Ah = 0 Ah=0

其中:


  利用cv2中的 findHomography(points1,points2)可以计算两个图片之间的单应矩阵。

1.3 单应矩阵应用场合

  • 利用共面点进行相机姿态估计,应用在基于某些标示(Apriltag)下的增强现实。
    ▲ 图1.2.1  在Apriltag上的增强虚拟现实

    ▲ 图1.2.1 在Apriltag上的增强虚拟现实

  • 消除透视效应/视角校正(参见前面第二个例子)

▲ 图1.2.2  透视校正

▲ 图1.2.2 透视校正

  • 全景图拼接(参见前面第二个、第三个例子)

▲ 图1.2.3 全景图拼接

▲ 图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 棋盘格中的角点

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 提取角点 后的图像

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: 镜头失真参数: k 1 , k 2 , p 1 , p 2 , k 3 k_1 ,k_2 ,p_1 ,p_2 ,k_3 k1,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等函数。 这位利用单应矩阵进行下步的矫正工作提供实验基础。


■ 相关文献链接:

● 相关图表链接:

#!/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
#============================================================
Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐