Bundle Adjustment到底是什么?

转载自知乎:https://www.zhihu.com/question/29082659/answer/62472382

作者:versatran01
链接:https://www.zhihu.com/question/29082659/answer/62472382
来源:知乎
著作权归作者所有,转载请联系作者获得授权。

Adjustment computation最早是由geodesy的人搞出来的。19世纪中期的时候,geodetics的学者就开始研究large scale triangulations了。20世纪中期,随着camera和computer的出现,photogrammetry也开始研究adjustment computation,所以他们给起了个名字叫bundle adjustment,bundle的意思我不知道中文怎么解释好,大家意会吧。20世纪下半段,computer vision community开始兴起reconstruction,也开始研究bundle adjustment,一开始重复造轮子,后来triggs的modern synthesis及时出现。21世纪前后,robotics领域开始兴起SLAM,最早用的recursive bayesian filter,后来把问题搞成个graph然后用least squares方法解。

这些东西归根结底就是Gauss大神“发明”的least squares method。当年天文学家Piazzi整天闲得没事看星星,在1801年1月1号早上发现了一个从来没观测到的星星,再接下来的42天里做了19次观测之后这个星星就消失了。当时的天文学家为了确定这玩意到底是什么绞尽了脑汁,这时候Gauss出现了,(最初)只用了3个观察数据,就用least squares算出了这个小行星的轨道,接下来天文学家根据Gauss的预测,也重新发现了这个小行星(虽然有小小的偏差),并将其命名为Ceres,也就是谷神星。Google的ceres-solver就是根据这个来命名的。
ref: How Gauss Determined the Orbit of Ceres

关于究竟是谁发明了Least Squares历史上有争论,Legendre是最早publish这个方法的(1805),但是几年后(1809)Gauss跳出来说:“你太naive了,我1795年就开始用least squares了,微不足道”。虽然有人认为Gauss这样的大神没必要说谎来和Legendre这种小叼丝(相对,长了一副反派脸)抢成果,但是至今没有definitive的证据证明确实是Gauss最早发明Least Squares。有人认为least squares的方法对Gauss来说太简单以至于Gauss根本没觉得有必要把它publish出来(hehe)。
Gauss Gauss
Legendre Legendre

ref: Gauss and the Invention of Least Squares

我们再来看看19,20世纪连电脑都没有的情况下,geodesy的人们面对的是什么样的问题吧。1927年的North American Datum有25000个观测塔,1983年的NAD有270000个观测塔。再来看看robotics community,最大的real-world SLAM datasets有21,000个pose[Johannsson13],最大的simulation datasets有200,000个pose[Grisetti10]。看看时间,都是2010年以后的。拿NAD83来说,虽然1983年已经有电脑了,但是优化这样一个network,需要解1,800,000个equations。也就是说如果如果用Least Squares的话,每一步的normal equation J^T * J * x = J^T y 或者Ax = b,里面这个A的dimension是900,000 x 900,000。用dense method光是存这么一个matrix就要3000 Gb[Agarwal14]。

Bundle adjustment优化的是sum of reprojection error,这是一个geometric distance(为什么要minimize geometric distance可以参考[Hartley00]),问题可以formulate成一个least squares problem, 如果nosie是gaussian的话,那就是一个maximum likelihood estimator,是这种情况下所能得到的最优解了。

这个reprojection error的公式是非线性的,所以这个least squares problem得用iterative method来求解。最简单的是Newton, 但是要算Hessian,并不是很好算,所以pass。接下来是Gauss-Newton,用J^T J 来近似Hessian,但是convergence速度不给力,也pass。再下来是Levenberg-Marquardt,是一个damping method,改一个lambda来控制到底是偏向steepest descent还是偏向Gauss-Newton,如果算出来更渣的一步就不接受,改个lambda重算,这样一来做了很多无用功,所以也pass。再下来还有Powell's dogleg,是一个trust region method,在这个小区间内搞一个新的function来近objective function,不论好坏都走一步,但是步幅不会超过所谓的trust region,再根据表现调整这个region,总的来说在large scale问题上比Levenberg-Marquardt的表现要好。再往后问题再大就得用前面所说的算法的sparse版本,再大下去得换conjugate gradient方法,这块我就不怎么了解了。

不论GN,LM,DL,中间都要解一个Ax=b形式的linear system,一般情况下算法的效率就取决于解这个linear system的效率。所以说到底这些nonlinear least squares problem最后也就是解一个linear system。这个linear system你可以直接inverse,也可以用QR,或者Choleskey,或者Schur complement trick来解,爱谁谁。说到这个Choleskey decomposition,当初就是为了Geodetic mapping而发明的。

现实中,并不是所有observation都服从i.i.d. gaussian noise的(或者可以说几乎没有),遇到有outlier的情况,这些方法非常容易挂掉,这时候就得用到robust statistics里面的robust cost (*cost也可以叫做loss, 统计学那边喜欢叫risk) function了,比较常用的有huber, cauchy等等。

总的来说bundle adjustment这个东西搞了这么多年也搞得差不多了,不能说state-of-the-art,但是可以算是gold standard。大点的问题诸如earth-scale reconstruction也被google的人搞过了,用了2 billion张谷歌街景,reconstruct了整个地球,真不知道接下来还能reconstruct什么。

[Triggs00] Bundle Adjustment - A Modern Synthesis, Bill Triggs, et al.
[Hartley00] Multiple View Geometry in Computer Vision, Richard Hartley, Andrew Zisserman
[Johannsson13] H. Johannsson, M. Kaess, M. Fallon, and J. J. Leonard, “Temporally scalable visual slam using a reduced pose graph,” in Proceedings of the IEEE International Conference on Robotics and Automation (ICRA), 2013, pp. 54–61.
[Grisetti10] G. Grisetti, R. Kummerle, C. Stachniss, and W. Burgard, “A tutorial on graph-based SLAM,” IEEE Transactions on Intelligent Transportation Systems Magazine, vol. 2, pp. 32–43, 2010.
[Agarwal14] A Survey of Geodetic Approaches to Mapping and the Relationship to Graph-based SLAM

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。
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、付费专栏及课程。

余额充值