Bundle Adjustment using Ceres-Solver
Bundle Adjustment (BA) has a broad application in Structure From Motion (SFM) problems, which further optimize the location of points to achieve 3D reconstruction. In recent years, traditional filter-based SLAM algorithms have been taken place by optimization-based SLAM, in which BA is the core part. BA can simultaneously optimize camera poses as well as the locations of 3D points by minimizing the reprojection error.
Ceres-Solver is an optimization library that can be used to solve least-squares problems. There is an example program of solving BA on its official documents: http://ceres-solver.org/nnls_tutorial.html#bundle-adjustment
BAL Dataset
The example program uses Bundle Adjustment in the Large (BAL) dataset. This dataset uses a pinhole camera model, which has 9 parameters. There are 3 parameters for rotation R, 3 parameters for translation T, 1 parameter for focal length f, and two radial distortion parameters k1 and k2.
The data format in each file is described as follows:
- The first line includes 3 numbers, which are <num_cameras>, <num_points>, and <num_observations>.
- There are 4 numbers in each line of the following num_observations lines, representing <camera_id>, <point_id>, \
, and \ , respectively. - The next 9 * <num_cameras> lines represents the camera parameters. Every 9 lines represent 1 camera. The order is the same with <camera_id>.
- The last 3 * <num_points> lines are the point locations. Every 3 lines represent 1 point. The order is the same with <point_id>.
The following Python script can be used to visualize the points in a BAL data file. Here I took the first file in the LadyBug dataset as an example.
1 | import numpy as np |
Compilation
The following CMakeLists.txt file can be used to build the program.
1 | # cmake version to be used |
Reprojection Error
If we know the 3D coordinates of a point plus the intrinsic and extrinsic parameters of the camera, we can calculate the projection location of that point in the pixel frame. Ideally, the line from the optical center of the camera and the 3D point should overlap with this projection point. However, the measurement and the calculation are not perfect, there is an error in the projection. By optimizing camera parameters and the location of the 3D point, we can minimize the reprojection error, which is the idea of BA.
The cost function of BA is shown in the following formula:
$$
\frac{1}{2} \sum_i \sum_j | z_{ij} - h(T_i, p_j) |^2
$$
Where z is the measurement (point in the image plane) of point p at pose T. h is the measurement function, which converts the 3D coordinate of the given point into the 2D image frame. In the example program, we first convert the point from the world frame into the camera frame, using the extrinsic parameters (R and T). Then, undistortion is applied. Finally, we calculate the difference between the prediction with the observation and use it as the residual.
1 | struct SnavelyReprojectionError { |
In the main function, the corresponding camera parameters and the 3D coordinates of each measurement are retrieved. All residual blocks are added into ceres::Problem and jointly optimized.
1 | ceres::Problem problem; |
Note that we can speed up the procedure of solving BA problems by utilizing its sparsity. However, it’s not demonstrated in this simple example.