You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

关于cv2.recoverPose坐标系转换功能的疑问

关于cv2.recoverPose结果与预期不符的问题分析

问题描述

测试cv2.recoverPose时发现返回的旋转矩阵与平移向量和预设参数差异较大,但solvePnP可正常恢复位姿。测试逻辑为:人工生成3D点,通过已知相机变换得到两个相机的2D投影点,再用cv2.findEssentialMat+cv2.recoverPose恢复位姿,结果不符合预期。

测试代码:

import cv2
import numpy as np

def calc_projection(K_c, transform, pt_3d):
    p_projected = np.hstack((K_c, np.zeros((3,1)))) @ np.vstack((transform, [0,0,0,1])) @ np.vstack((pt_3d.reshape(3,1), 1))
    p_projected = p_projected[:2,:] / p_projected[2,:]
    p_projected = p_projected.ravel()
    return p_projected

points_3d = np.random.rand(100, 3)

K_c = np.eye(3)

T_0 = np.hstack((np.eye(3), np.zeros((3,1))))
rot_vec = np.array([0.2, 0.1, 0.3])
R_1_0, _ = cv2.Rodrigues(np.array(rot_vec))
t_0_10 = np.array([0.2, 0.4, 0.1])
T_1_0 = np.hstack((R_1_0, t_0_10.reshape(3,1)))
points1 = []
points2 = []

for pt_3d in points_3d:
    points1.append(calc_projection(K_c, T_0, pt_3d))
    points2.append(calc_projection(K_c, T_1_0, pt_3d))

points1 = np.array(points1)
points2 = np.array(points2)

E, mask = cv2.findEssentialMat(points1, points2, method=cv2.RANSAC)
inliers1 = points1[mask]
inliers2 = points2[mask]
_, R, t, _ = cv2.recoverPose(E, inliers1, inliers2)

r, _ = cv2.Rodrigues(R)
assert np.allclose(r, rot_vec)
assert np.allclose(t, t_0_10)

实际返回结果:

r = [[0.20329041]
 [0.15711541]
 [0.37188371]]
t = [[0.50969714]
 [0.79593836]
 [0.32663581]]

solvePnP验证结果正常:

_, r, t = cv2.solvePnP(points_3d, points2, K_c, None)
assert np.allclose(r, rot_vec.reshape(3, 1), rtol=0.15)
assert np.allclose(t, t_0_10.reshape(3, 1), rtol=0.15)

原因分析

1. 平移向量的尺度不确定性

本质矩阵E仅编码旋转信息和平移的方向,无法恢复平移的绝对尺度。cv2.recoverPose返回的t是单位化后的向量,而预设的t_0_10是带有实际尺度的平移量,直接对比数值必然不匹配。正确验证方式是检查方向一致性:

# 验证平移方向一致
assert np.allclose(t / np.linalg.norm(t), t_0_10 / np.linalg.norm(t_0_10), rtol=1e-2)

2. 旋转矩阵的误差来源

  • 本质矩阵估计噪声:cv2.findEssentialMat用RANSAC估计本质矩阵,若测试3D点分布不理想(如随机点存在共面、分布集中等情况),会导致本质矩阵估计偏差,进而影响位姿恢复精度。
  • 多解性选择误差:本质矩阵分解会得到4种位姿解,cv2.recoverPose通过三角化点检查是否在相机前方选择正确解,但如果点深度分布不合理,可能引入微小误差。

3. 变换逻辑的一致性

cv2.recoverPose返回的R和t满足:相机2坐标系下的点P2 = R * P1 + t(P1为相机1坐标系下的空间点),与预设的T_1_0(相机1相对于相机0的变换)逻辑一致,但需确保投影过程无坐标系混淆。

修正后的验证示例

修改断言逻辑,允许微小误差并验证方向:

# 验证旋转向量(允许5%以内的相对误差)
assert np.allclose(r, rot_vec.reshape(3,1), rtol=5e-2)
# 验证平移方向一致
assert np.allclose(t / np.linalg.norm(t), t_0_10 / np.linalg.norm(t_0_10), rtol=1e-2)

solvePnP能正常恢复位姿是因为直接使用3D点与2D投影的对应关系,无需依赖本质矩阵分解,且能恢复带尺度的平移量(输入了真实3D坐标)。

内容的提问来源于stack exchange,提问作者patwis

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.05 16:42:35