计算机视觉 - python实现求解homography矩阵

这篇博客详细介绍了如何利用Python和Scipy库来计算图像处理中的Homography矩阵。通过构造矩阵A并进行奇异值分解,找到最小化||Ah||的解,并确保 Homography 矩阵H的归一化条件。代码示例展示了从对应点对数据构建A矩阵,然后应用SVD求解H的过程,最后将预测坐标与原始坐标进行可视化对比。
摘要由CSDN通过智能技术生成

计算机视觉 - python实现求解homography矩阵

要求

给定 P i ≡ [ x i , y i , 1 ] P_i \equiv [x_i,y_i,1] Pi[xi,yi,1] P i ′ ≡ [ x i ′ , y i ′ , 1 ] P_i^{'} \equiv [x_i^{'},y_i^{'},1] Pi[xi,yi,1],需要计算一个齐次变换矩阵 H ∈ R 3 H \in R^3 HR3满足 P i ′ ≡ H P i P_i^{'} \equiv HP_i PiHPi

而大部分的数据集不能准确地计算出 H H H,所以可以计算出最优的 H H H

计算方法如下: a r g m i n ∣ ∣ H ∣ ∣ 2 2 = 1 ∣ ∣ A h ∣ ∣ , h ∈ R 9 , A ∈ R 2 N × 9 \mathop{arg min}\limits_{||H||_2^2=1}||Ah||,h \in R^9,A\in R^{2N \times 9} H22=1argminAh,hR9,AR2N×9

使 A h Ah Ah的模最小的 h h h的参数则为所求的 H H H的九个参数

分析与求解

首先,我们来看看这里的 A A A是什么,
A = [ − x 1 − y 1 − 1 0 0 0 x 1 x 1 ′ y 1 x 1 ′ x 1 ′ 0 0 0 − x 1 − y 1 − 1 x 1 y 1 ′ y 1 y 1 ′ y 1 ′ − x 2 − y 2 − 1 0 0 0 x 2 x 2 ′ y 2 x 2 ′ x 2 ′ 0 0 0 − x 2 − y 2 − 1 x 2 y 2 ′ y 2 y 2 ′ y 2 ′ − x 3 − y 3 − 1 0 0 0 x 3 x 3 ′ y 3 x 3 ′ x 3 ′ 0 0 0 − x 3 − y 3 − 1 x 3 y 3 ′ y 3 y 3 ′ y 3 ′ − x 4 − y 4 − 1 0 0 0 x 4 x 4 ′ y 4 x 4 ′ x 4 ′ 0 0 0 − x 4 − y 4 − 1 x 4 y 4 ′ y 4 y 4 ′ y 4 ′ . . . ] A = \begin{bmatrix} -x_1 & -y_1 & -1 & 0 & 0 & 0 & x_1x_1^{'} & y_1x_1^{'} & x_1^{'} \\ 0 & 0 & 0 & -x_1 & -y_1 & -1 & x_1y_1^{'} & y_1y_1^{'} & y_1^{'} \\ -x_2 & -y_2 & -1 & 0 & 0 & 0 & x_2x_2^{'} & y_2x_2^{'} & x_2^{'} \\ 0 & 0 & 0 & -x_2 & -y_2 & -1 & x_2y_2^{'} & y_2y_2^{'} & y_2^{'} \\ -x_3 & -y_3 & -1 & 0 & 0 & 0 & x_3x_3^{'} & y_3x_3^{'} & x_3^{'} \\ 0 & 0 & 0 & -x_3 & -y_3 & -1 & x_3y_3^{'} & y_3y_3^{'} & y_3^{'} \\ -x_4 & -y_4 & -1 & 0 & 0 & 0 & x_4x_4^{'} & y_4x_4^{'} & x_4^{'} \\ 0 & 0 & 0 & -x_4 & -y_4 & -1 & x_4y_4^{'} & y_4y_4^{'} & y_4^{'} \\ ... \end{bmatrix} A=x10x20x30x40...y10y20y30y40101010100x10x20x30x40y10y20y30y401010101x1x1x1y1x2x2x2y2x3x3x3y3x4x4x4y4y1x1y1y1y2x2y2y2y3x3y3y3y4x4y4y4x1y1x2y2x3y3x4y4
矩阵 A A A就是将数据点按照上述规则进行构造的矩阵

我们再来看看h
h = [ H 00 H 01 H 02 H 10 H 11 H 12 H 20 H 21 H 22 ] T h = \begin{bmatrix} H_{00}& H_{01}&H_{02}& H_{10}& H_{11}&H_{12}& H_{20}&H_{21}& H_{22}& \end{bmatrix}^T h=[H00H01H02H10H11H12H20H21H22]T
这样,问题就转化为了齐次方程线性最小二乘的求解问题,我们期望找到 A h = 0 Ah=0 Ah=0 h h h不等于零的解。由于该方程的特殊形式我们发现:对于 h h h不等于零的解,我们乘上任意的尺度因子 k k k,使解变为 k h kh kh,都不会改变最终结果,因此我们可以将问题转化为求解 h h h,使得 ∣ ∣ A h ∣ ∣ ||Ah|| Ah值最小并且 ∣ ∣ h ∣ ∣ = 1 ||h||=1 h=1

我们可以采取奇异值分解的方法,对A进行SVD分解有:
∣ ∣ A h ∣ ∣ = ∣ ∣ U D V T h ∣ ∣ = ∣ ∣ D V T h ∣ ∣ ||Ah|| = ||UDV^Th|| = ||DV^Th|| Ah=UDVTh=DVTh
∣ ∣ h ∣ ∣ = ∣ ∣ V T h ∣ ∣ ||h|| = ||V^Th|| h=VTh,可将问题进一步转化为,最小化 ∣ ∣ D V T h ∣ ∣ ||DV^Th|| DVTh,且 ∣ ∣ V T h ∣ ∣ = 1 ||V^Th||=1 VTh=1

又令 y = V T h y=V^Th y=VTh,有: ∣ ∣ D y ∣ ∣ ||Dy|| Dy ∣ ∣ y ∣ ∣ = 1 ||y||=1 y=1

对于当前问题,A列满秩,则D是对角阵,V是方阵

在奇异值分解中D的对角线元素是递减排列的,那么只需取 = ( 0 , 0 , 0 , . . . , 0 , 1 ) =(0,0,0,...,0,1) =(0,0,0,...,0,1),则 ∣ ∣ A h ∣ ∣ = ∣ ∣ D y ∣ ∣ = σ n ||Ah||=||Dy||= \sigma_n Ah=Dy=σn σ n \sigma_n σn是A最小的奇异值

此时: h = V y h=Vy h=Vy

h h h的值为矩阵 V V V的最后一列,即为矩阵 V T V^T VT的最后一行。

这样,我们就可以解决问题了:先构造出A,然后调用scipy库中的svd函数进行奇异值分解,然后利用h构造出H即可,代码如下:

注:

  1. 最好不要用numpy库里的svd函数,当数据量较大时,会显示init_dgesdd failed init报错
  2. scipy库里的svd函数的第三个返回值为 V T V^T VT,而不是 V V V,因此是取它的最后一行,而不是最后一列
  3. 可视化时,注意是H左乘齐次坐标 [ x i , y i , 1 ] [x_i,y_i,1] [xi,yi,1]

具体代码如下:

import numpy as np
import matplotlib.pyplot as plt
import scipy.linalg as linalg


def fit_homography(XY):
	'''
	Given a set of N correspondences XY of the form [x,y,x',y'],
	fit a homography from [x,y,1] to [x',y',1].
	
	Input - XY: an array with size(N,4), each row contains two
			points in the form [x_i, y_i, x'_i, y'_i] (1,4)
	Output -H: a (3,3) homography matrix that (if the correspondences can be
			described by a homography) satisfies [x',y',1]^T === H [x,y,1]^T

	'''

	A = np.zeros(shape=(XY.shape[0] * 2,9),dtype=np.float32)
	for i in range(XY.shape[0]):
		A[2 * i,0] = -1.0 * XY[i,0]
		A[2 * i,1] = -1.0 * XY[i,1]
		A[2 * i,2] = -1
		A[2 * i,6] = XY[i,0] * XY[i,2]
		A[2 * i,7] = XY[i,1] * XY[i,2]
		A[2 * i,8] = XY[i,2]
		A[2 * i + 1,3] = -1.0 * XY[i,0]
		A[2 * i + 1,4] = -1.0 * XY[i,1]
		A[2 * i + 1,5] = -1
		A[2 * i + 1,6] = XY[i,0] * XY[i,3]
		A[2 * i + 1,7] = XY[i,1] * XY[i,3]
		A[2 * i + 1,8] = XY[i,3]
	_, _, vt = linalg.svd(A)
	H = vt[-1].reshape(3,3) # 注意是-1行,不是-1列
	H = H / H[2,2] # 第三行第三列为1
	return H 

if __name__ == "__main__":
    file = 'file.npy'
	data = np.load(file) # 数据每一行为[x,y,x',y']

	plt.clf()
	plt.rcParams['font.sans-serif']=['SimHei'] #用来正常显示中文标签
	plt.rcParams['axes.unicode_minus']=False #用来正常显示负号
	xy = data[:,0:2]
	xy_pie = data[:,2:]
    # 添加一列1,转化为齐次坐标
    A = np.c_[xy,np.ones(len(xy))] 
	H = fit_homography(data)
	print(H)
	xy_pred = np.dot(H, A.T).T
    # 转化为二维坐标
	xy_pred[:,0] = xy_pred[:,0] / xy_pred[:,2]
	xy_pred[:,1] = xy_pred[:,1] / xy_pred[:,2]
    plt.scatter(xy[:,0], xy[:,1], 1, color='orange', label='x,y')
	plt.scatter(xy_pie[:,0], xy_pie[:,1], 1, color='blue', label='x\',y\'')
	plt.scatter(xy_pred[:,0], xy_pred[:,1], 1, color='red', label='x_pred,y_pred')
	plt.legend()
	plt.show()
  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值