vSLAM学习笔记——最小化重投影误差求解PnP

博客详细探讨了Bundle Adjustment的概念,它是摄影测量中用于优化相机参数和三维点坐标的过程。内容涉及重投影误差及其关于相机位姿和空间点的导数,强调了误差定义的方向对矩阵形式的影响,并给出了相关数学公式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

BA的定义

通常称把相机和三维点放在一起进行最小化的问题为Bundle Adjustment。

重投影误差关于相机位姿李代数的一阶变化关系

∂ e ∂ δ ξ = lim ⁡ δ ξ → 0 e ( δ ξ ⨁ ξ ) − e ( ξ ) δ ξ = ∂ e ∂ P ′ ∂ P ′ ∂ δ ξ = − [ f x Z ′ 0 − f x X ′ Z ′ 2 − f x X ′ Y ′ Z ′ 2 f x + f x X ′ 2 Z ′ 2 − f x Y ′ Z ′ 0 f y Z ′ − f y Y ′ Z ′ 2 − f y − f y Y ′ 2 Z ′ 2 f y X ′ Y ′ Z ′ 2 f y X ′ Z ′ ] \frac{\partial e}{\partial \delta \xi}=\lim_{\delta\xi\to0}\frac{e(\delta\xi\bigoplus\xi)-e(\xi)}{\delta\xi}=\frac{\partial e}{\partial P'}\frac{\partial P'}{\partial \delta\xi}=-\begin{bmatrix}\frac{f_x}{Z'}&0&-\frac{f_xX'}{Z'^2}&-\frac{f_xX'Y'}{Z'^2}&f_x+\frac{f_xX'^2}{Z'^2}&-\frac{f_xY'}{Z'}\\\\0&\frac{f_y}{Z'}&-\frac{f_yY'}{Z'^2}&-f_y-\frac{f_yY'^2}{Z'^2}&\frac{f_yX'Y'}{Z'^2}&\frac{f_yX'}{Z'}\end{bmatrix} δξe=δξ0limδξe(δξξ)e(ξ)=PeδξP=Zfx00ZfyZ2fxXZ2fyYZ2fxXYfyZ2fyY2fx+Z2fxX2Z2fyXYZfxYZfyX
这里保留了前面的负号,因为误差是由观测值减预测值定义的。也可以反过来,将其定义成“预测值减观测值”的形式,只需要去掉前面的负号即可。此外,如果 s e ( 3 ) se(3) se(3)的定义方式是旋转在前,平移在后,则只要把这个矩阵的前 3 3 3列与后 3 3 3列对调即可。

重投影误差关于空间点P的导数

∂ e ∂ P = ∂ e ∂ P ′ ∂ P ′ ∂ P = − [ f x Z ′ 0 − f x X ′ Z ′ 2 0 f y Z ′ − f y Y ′ Z ′ 2 ] R \frac{\partial e}{\partial P}=\frac{\partial e}{\partial P'}\frac{\partial P'}{\partial P}=-\begin{bmatrix}\frac{f_x}{Z'}&0&-\frac{f_xX'}{Z'^2}\\\\0&\frac{f_y}{Z'}&-\frac{f_yY'}{Z'^2}\end{bmatrix}R Pe=PePP=Zfx00ZfyZ2fxXZ2fyYR

### PnP算法实现精确姿态估计 PnP(Perspective-nPoint)问题是计算机视觉中的经典问题之一,目标是从一组已知的3D点及其对应的2D图像投影中恢复相机的姿态(即旋转矩阵 \( R \) 和平移向量 \( T \))。以下是基于最小化重投影误差的方法来解决PnP问题的具体方式。 #### 投影模型与重投影误差 在针孔相机模型下,给定世界坐标系下的3D点 \( P_i = [x_i, y_i, z_i]^T \),以及它们在图像平面中的对应2D投影点 \( p_i = [u_i, v_i]^T \),可以通过如下方程描述成像关系: \[ p_i = K[R|t]P_i, \] 其中 \( K \) 是相机内参矩阵,\( R \) 表示旋转矩阵,\( t \) 表示平移向量。为了简化优化过程,通常将上述非线性约束转化为重投影误差的形式,具体表达为: \[ e_i = \| \pi(K(RP_i + t)) - p_i \|^2, \] 这里 \( e_i \) 表示第 \( i \) 对应点的重投影误差,而 \( \pi(\cdot) \) 表示归一化的射影映射操作[^2]。 #### 非线性优化求解 由于重投影误差是非线性的,因此可以采用数值优化技术对其进行最小化处理。常用的优化方法包括Levenberg-Marquardt (LM) 或 Gauss-Newton 法。这些方法的核心在于迭代更新当前估计参数直至收敛于局部最优解。下面是一个具体的Python代码示例展示如何构建并求解这一问题: ```python import numpy as np from scipy.optimize import least_squares def reprojection_error(params, points_3d, points_2d, camera_matrix): """ 计算重投影误差. :param params: 当前待估参数(包含旋转向量和平移向量). :param points_3d: 已知的世界坐标系下的3D点集(Nx3数组). :param points_2d: 图像上的相应2D点集(Nx2数组). :param camera_matrix: 相机内参矩阵(3x3数组). :return: 所有点的重投影误差组成的列向量. """ rvec = params[:3].reshape((3, 1)) tvec = params[3:].reshape((3, 1)) # 将旋转向量转换为旋转矩阵 rotation_mat, _ = cv2.Rodrigues(rvec) # 构造外参矩阵 extrinsic = np.hstack((rotation_mat, tvec)) projected_points = [] for point in points_3d: hom_point = np.array([[point[0], point[1], point[2], 1]]).T img_point_hom = camera_matrix @ extrinsic @ hom_point img_point = img_point_hom / img_point_hom[-1] projected_points.append(img_point[:-1]) errors = [] for pt_estimated, pt_gt in zip(projected_points, points_2d): error = np.linalg.norm(pt_estimated.flatten() - pt_gt) errors.append(error) return np.array(errors).flatten() def estimate_pose(points_3d, points_2d, camera_matrix, initial_guess=None): """ 使用非线性优化估计相机姿态. :param points_3d: 输入的3D点集合. :param points_2d: 对应的2D图像点集合. :param camera_matrix: 相机内参矩阵. :param initial_guess: 初始猜测值,默认随机初始化. :return: 最优的旋转向量rvec和翻译向量tvec. """ if not initial_guess: initial_rvec = np.zeros((3,)) initial_tvec = np.zeros((3,)) initial_guess = np.concatenate([initial_rvec, initial_tvec]) result = least_squares( fun=reprojection_error, x0=initial_guess, args=(points_3d, points_2d, camera_matrix), method='lm' ) optimized_params = result.x rvec_optimized = optimized_params[:3] tvec_optimized = optimized_params[3:] return rvec_optimized.reshape(-1), tvec_optimized.reshape(-1) # 示例用法 if __name__ == "__main__": from mpl_toolkits.mplot3d import Axes3D import matplotlib.pyplot as plt # 假设数据... points_3d = ... # Nx3 array of world coordinates points_2d = ... # Nx2 array of image pixel locations camera_matrix = ... # Camera intrinsic matrix rvec_initial, tvec_initial = estimate_pose(points_3d, points_2d, camera_matrix) print(f"Estimated Rotation Vector:\n{rvec_initial}") print(f"Estimated Translation Vector:\n{tvec_initial}") ``` 此脚本定义了两个主要功能:`reprojection_error()` 函数用来量化每一对匹配点之间的偏差;`estimate_pose()` 方法则负责执行实际的最优化流程以找到最佳的 \( R \) 和 \( T \)[^1]. #### 结果评估与改进策略 当获得初步的结果之后,还可以进一步采取措施提高精度,比如引入鲁棒损失函数减少异常值影响、增加正则项防止过拟合等手段。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

卑微小岳在线debug

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

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

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

打赏作者

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

抵扣说明:

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

余额充值