一文详解bundle adjustment

本文详细介绍了bundle adjustment的历史发展,从大地测量学到摄影测量学再到机器人SLAM领域的重要应用。核心是通过最小二乘原理优化相机姿态和地标点。文章列举了四种不同的bundle adjustment算法代码实现,并提供了相关参考资料。
摘要由CSDN通过智能技术生成

点击上方“计算机视觉工坊”,选择“星标”

干货第一时间送达

bundle adjustment 的历史发展

bundle adjustment,中文名称是光束法平差,经典的BA目的是优化相机的pose和landmark,其在SfM和SLAM 领域中扮演者重要角色.目前大多数书籍或者参老文献将其翻译成"捆绑调整"是不太严谨的做法.bundle adjustment 最早是19世纪由搞大地测量学(测绘学科)的人提出来的,19世纪中期的时候,geodetics的学者就开始研究large scale triangulations(大型三角剖分)。20世纪中期,随着camera和computer的出现,photogrammetry(摄影测量学)也开始研究adjustment computation,所以他们给起了个名字叫bundle adjustment(隶属摄影测量学科前辈的功劳)。21世纪前后,robotics领域开始兴起SLAM,最早用的recursive bayesian filter(递归贝叶斯滤波),后来把问题搞成个graph然后用least squares方法求解,bundle adjusment历史发展图如下:

bundle adjustment 其本质还是离不开最小二乘原理(Gauss功劳)(几乎所有优化问题其本质都是最小二乘),目前bundle adjustment 优化框架最为代表的是ceres solver和g2o(这里主要介绍ceres solver).据说ceres的命名是天文学家Piazzi闲暇无事的时候观测一颗没有观测到的星星,最后用least squares算出了这个小行星的轨道,故将这个小行星命名为ceres.

Bundle adjustment 的算法理论

观测值:像点坐标 优化量(平差量):pose 和landmark 因为一旦涉及平差,就必定有如下公式:观测值+观测值改正数=近似值+近似值改正数,那么bundle adjustment 的公式还是从共线条件方程出发:

四种Bundle adjustment 算法代码

这里代码主要从四个方面来介绍:

  • 优化相机内参及畸变系数,相机的pose(6dof)和landmark 代价函数写法如下:

template <typename CameraModel>
class BundleAdjustmentCostFunction {
 public:
  explicit BundleAdjustmentCostFunction(const Eigen::Vector2d& point2D)
      : observed_x_(point2D(0)), observed_y_(point2D(1)) {}
//构造函数传入的是观测值
  static ceres::CostFunction* Create(const Eigen::Vector2d& point2D) {
    return (new ceres::AutoDiffCostFunction<
            BundleAdjustmentCostFunction<CameraModel>, 2, 4, 3, 3,
            CameraModel::kNumParams>(
        new BundleAdjustmentCostFunction(point2D)));
  }
//优化量:2代表误差方程个数;4代表pose中的姿态信息,用四元数表示;3代表pose中的位置信息;3代表landmark
自由度;CameraModel::kNumParams是相机内参和畸变系数,其取决于相机
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Bundle Adjustment 是一种用于同时估计多个相机位置,姿态和三维点云的优化算法。下面是一个用Python编写的简单的Bundle Adjustment玩具程序: ```python import numpy as np import scipy.sparse as sp import scipy.sparse.linalg as splinalg # 生成测试数据 num_cameras = 3 num_points = 5 num_observations = 10 noise_scale = 0.1 # 相机的位置和姿态 camera_positions = np.random.randn(num_cameras, 3) camera_orientations = np.random.randn(num_cameras, 3) # 三维点云 points_3d = np.random.randn(num_points, 3) # 观测到的2D点 observed_points = np.zeros((num_observations, 2)) camera_indices = np.zeros(num_observations, dtype=int) point_indices = np.zeros(num_observations, dtype=int) for i in range(num_observations): camera_idx = np.random.randint(num_cameras) point_idx = np.random.randint(num_points) observed_points[i] = np.random.randn(2) + \ np.dot(camera_orientations[camera_idx], points_3d[point_idx]) + \ camera_positions[camera_idx] observed_points[i] += np.random.randn(2) * noise_scale camera_indices[i] = camera_idx point_indices[i] = point_idx # 构建稀疏矩阵 A = sp.lil_matrix((num_observations * 2, num_cameras * 6 + num_points * 3)) b = np.zeros(num_observations * 2) for i in range(num_observations): camera_idx = camera_indices[i] point_idx = point_indices[i] point_3d = points_3d[point_idx] camera_pos = camera_positions[camera_idx] camera_orient = camera_orientations[camera_idx] # 计算重投影误差 projected_point = np.dot(camera_orient, point_3d) + camera_pos projected_point /= projected_point[2] projected_point = projected_point[:2] error = observed_points[i] - projected_point # 构建雅可比矩阵 J_camera = np.hstack((point_3d, np.zeros(3), np.eye(3))) J_point = np.hstack((np.zeros(2), camera_orient[:2].reshape(2, 1) * point_3d.reshape(1, 3))) J = np.vstack((J_camera, J_point)) A[i * 2: (i+1) * 2, camera_idx * 6: (camera_idx+1) * 6] = J[:, :6] A[i * 2: (i+1) * 2, num_cameras * 6 + point_idx * 3: num_cameras * 6 + (point_idx+1) * 3] = J[:, 6:] b[i * 2: (i+1) * 2] = error # 优化 x0 = np.hstack((camera_positions.ravel(), camera_orientations.ravel(), points_3d.ravel())) res = splinalg.lsmr(A, b, x0=x0) optimized_positions = res[0][:num_cameras * 3].reshape(num_cameras, 3) optimized_orientations = res[0][num_cameras * 3: num_cameras * 6].reshape(num_cameras, 3) optimized_points_3d = res[0][num_cameras * 6:].reshape(num_points, 3) print("Original Camera Positions:\n", camera_positions) print("Original Camera Orientations:\n", camera_orientations) print("Original 3D Points:\n", points_3d) print("Optimized Camera Positions:\n", optimized_positions) print("Optimized Camera Orientations:\n", optimized_orientations) print("Optimized 3D Points:\n", optimized_points_3d) ``` 这个程序生成了一些随机的相机位置、姿态和三维点云,然后随机生成了一些观测到的2D点,并添加了一些高斯噪声。程序使用Bundle Adjustment来估计相机和3D点云的位置,并输出优化后的结果。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值