
当相机仅绕光轴(如水平平移旋转)做纯旋转运动时,可通过相机内参矩阵与两次旋转矩阵的复合变换精确推导出图像间的单应矩阵 h,其完整 3×3 形式需显式引入内参校正,而非仅归一化旋转子块。
当相机仅绕光轴(如水平平移旋转)做纯旋转运动时,可通过相机内参矩阵与两次旋转矩阵的复合变换精确推导出图像间的单应矩阵 h,其完整 3×3 形式需显式引入内参校正,而非仅归一化旋转子块。
在纯旋转(即相机中心位置不变、仅姿态变化)条件下,两幅图像之间的几何关系由单应性(homography)完全刻画。关键前提是:场景为平面(通常设为世界坐标系中 Z = 0 平面),且相机无平移运动。此时,单应矩阵 H 描述了该平面上点在两视图间的投影映射关系。
理论核心在于:若第一帧相机姿态为旋转矩阵 ( R_1 ),第二帧为 ( R_2 ),相机内参为对角矩阵 ( K = \operatorname{diag}(f, f, 1) ),则从图像 1 到图像 2 的单应矩阵为:
[ H = K \, R_2 \, R_1^\top \, K^{-1} ]
⚠️ 注意:这不是简单的 ( R_2 R_1^\top ) 或其归一化版本,必须左乘 ( K )、右乘 ( K^{-1} )。因为单应性定义在像素坐标系下,而旋转矩阵作用于归一化相机坐标系;内参矩阵负责坐标系间的线性转换。
以题目中为例(焦距 ( f = 400 ),pan 角从 10° 变为 15°):
import numpy as np
from scipy.spatial.transform import Rotation as R
f = 400.0
K = np.diag([f, f, 1.0])
# 构造两次旋转(仅绕 Z 轴的 pan)
pan10 = R.from_euler('Z', 10 * np.pi/180).as_matrix()
pan15 = R.from_euler('Z', 15 * np.pi/180).as_matrix()
# 正确的单应矩阵计算
H = K @ pan15 @ pan10.T @ np.linalg.inv(K)
H = H / H[2, 2] # 归一化,使 H[2,2] = 1(齐次尺度自由度)
运行后可得:
[[ 9.97147963e-01, -7.56172873e-02, 1.73592176e+01], [ 7.54846993e-02, 9.98090883e-01, 1.87521001e+00], [-1.09070429e-04, -3.49361263e-06, 1.00000000e+00]]
该结果与 cv2.findHomography 实测值完全一致。
? 关键澄清:
- 前 2×2 子块(H[0:2, 0:2])近似等于 ( K R_2 R_1^\top K^{-1} ) 的对应部分,但不可直接用 ( R_2 R_1^\top ) 归一化替代;
- 平移项 H[0:2, 2](即最后一列前两个元素)并非零,它由内参缩放和旋转耦合产生,物理意义是:因焦距导致的视角偏移在像素平面上的体现;
- H[2, 0:2] 很小(量级 ~1e−4),源于 ( (K R_2 R1^\top K^{-1}){2,0:2} ) 的第三行非主对角项,反映像素坐标系下深度不变假设下的微小畸变补偿;
- 必须执行最终归一化(除以 H[2,2]),确保单应矩阵处于标准齐次表示。
✅ 总结步骤:
- 获取两次拍摄对应的旋转矩阵 ( R_1, R_2 )(推荐使用欧拉角或四元数统一参数化);
- 构造已知内参矩阵 ( K )(注意单位一致性,焦距单位需与世界坐标系匹配);
- 计算 ( H = K \, R_2 \, R_1^\top \, K^{-1} );
- 归一化:( H \leftarrow H / H_{2,2} );
- 验证:用 H 投影任意 Z=0 平面点,检查重投影误差是否在亚像素级。
此方法不依赖特征点匹配,适用于标定后纯旋转序列的解析建模、图像拼接初始化、虚拟视点生成等任务,兼具精度与可解释性。










