单应性变换 Homography Estimation

应用背景:

已知同一个平面标定板在两个不同角度下的图像,根据图像上对应点的二维(u, v)坐标求解其变换矩阵。单应性变换是两个平面之间的几何变换,利用至少4对以上的同名点计算变换矩阵。

原理介绍

角度A下图像中一点的坐标 ( u 1 , v 1 ) (u_1, v_1) (u1,v1) , 对应的在角度B下的坐标为 ( u 2 , v 2 ) (u_2,v_2) (u2,v2), 两个点之间的单应性变换可以表示为: z c 2 [ u 2 v 2 1 ] = [ H 11 H 12 H 13 H 21 H 22 H 23 H 31 H 32 H 33 ] z c 1 [ u 1 v 1 1 ] z_{c2}\begin{bmatrix} u_2\\v_2\\1 \end{bmatrix} = \begin{bmatrix} H_{11}&H_{12}&H_{13}\\ H_{21}&H_{22}&H_{23}\\H_{31}&H_{32}&H_{33}\end{bmatrix}z_{c1}\begin{bmatrix} u_1\\v_1\\1 \end{bmatrix} zc2u2v21=H11H21H31H12H22H32H13H23H33zc1u1v11根据矩阵展开可以得到两个等式,即 u 2 ( H 31 u 1 + H 32 v 1 + H 33 ) = H 11 u 1 + H 12 v 1 + H 13 u_2(H_{31}u_1+H_{32}v_1+H_{33})=H_{11}u_1+H_{12}v_1+H_{13} u2(H31u1+H32v1+H33)=H11u1+H12v1+H13 v 2 ( H 31 u 1 + H 32 v 1 + H 33 ) = H 21 u 1 + H 22 v 1 + H 23 v_2(H_{31}u_1+H_{32}v_1+H_{33})=H_{21}u_1+H_{22}v_1+H_{23} v2(H31u1+H32v1+H33)=H21u1+H22v1+H23由此可见,1组对应点能提供2个等式。单应性矩阵虽然是3x3共9个参数,但是变量是8个,上式的左右两边可以同时除以一个变量,去除一个相关变量。对于8个变量需要提供4对以上的点对组合才能解算。
将上式的左边移到右边,可以得到类似 A x = 0 Ax=0 Ax=0的矩阵形式,利用SVD分解来求解 x = ( H 11 , H 12 , H 13 , H 21 , H 22 , H 23 , H 31 , H 32 , H 33 ) x=(H_{11},H_{12},H_{13},H_{21},H_{22},H_{23},H_{31},H_{32},H_{33}) x=(H11,H12,H13,H21,H22,H23,H31,H32,H33),其中 A = [ u 1 v 1 1 0 0 0 − u 1 ∗ u 2 − v 1 ∗ u 2 − u 2 0 0 0 u 1 v 1 1 − u 1 ∗ v 2 − v 1 ∗ v 2 − v 2 . . . . . . ] A=\begin{bmatrix} u_1&v_1&1&0&0&0&-u_1*u_2&-v_1*u_2&-u_2 \\ 0 & 0&0&u_1&v_1&1&-u_1*v_2&-v_1*v_2&-v_2 \\ ...\\...\end{bmatrix} A=u10......v10100u10v101u1u2u1v2v1u2v1v2u2v2

代码实现

使用EIGEN库的主要计算代码如下,

// 计算单应性矩阵
int nPairSize = vCodedPairPt.size();
if (nPairSize < 4)
{
	cout << "匹配对数少于4对" << endl;
	return 0;
}
MatrixXd MatrixA(2 * nPairSize, 9);
double u1, v1, u2, v2;
int index = 0;
for (int i = 0; i < nPairSize; i++)
{
	u1 = vCodedPairPt[i].first->pt.dX;
	v1 = vCodedPairPt[i].first->pt.dY;
	u2 = vCodedPairPt[i].second->pt.dX;
	v2 = vCodedPairPt[i].second->pt.dY;
	index = i * 2;
	MatrixA(index, 0) = u1,     	 MatrixA(index, 1) = v1, 		  MatrixA(index, 2) = 1;
	MatrixA(index, 3) = 0,  		 MatrixA(index, 4) = 0, 		  MatrixA(index, 5) = 0;
	MatrixA(index, 6) = -u1*u2,      MatrixA(index, 7) = -v1*u2,      MatrixA(index, 8) = -u2;
	MatrixA(index + 1, 0) = 0,       MatrixA(index + 1, 1) = 0,       MatrixA(index + 1, 2) = 0;
	MatrixA(index + 1, 3) = u1,      MatrixA(index + 1, 4) = v1,      MatrixA(index + 1, 5) = 1;
	MatrixA(index + 1, 6) = -u1*v2,  MatrixA(index + 1, 7) = -v1*v2,  MatrixA(index + 1, 8) = -v2;
}
//cout << "MatrixA: " << MatrixA << endl;
JacobiSVD<MatrixXd> svd(MatrixA, ComputeThinU | ComputeThinV);
MatrixXd MatrixU;
MatrixU = svd.matrixV();
int nCols = MatrixU.cols();
VectorXd vSolution = MatrixU.col(nCols - 1);
Matrix3d MatrixH = Map<Matrix3d>(vSolution.data()).transpose();
cout << "MatrixH: " << MatrixH << endl;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

leaf_csdn

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值