-
ceres::Problem problem 生成一个非线性最小二乘problem
2. struct/class costFunctor{
代价函数,用以计算jacobin矩阵
template<typename t> bool operator(){}
}
3.probelm.AddResidualBlock(new AutoDiffCostFunction<costFunctor,1,1,1>(new costFunctor())); 生成jacobin
4.Solver::Options 非线性最小二乘求解时的选项,如迭代次数,矩阵分解方法等
5.Solver::Summary summary
6.Solve(options,&problem,&summary)
总体来说,ceres库就像是一个黑盒,只需要把测量值和观测值输入代价函数中,即可自动求解jacobin矩阵,并进行非线性最小二乘迭代。
//1.构造代价函数
// Templated pinhole camera model for used with Ceres. The camera is
// parameterized using 9 parameters: 3 for rotation, 3 for translation, 1 for
// focal length and 2 for radial distortion. The principal point is not modeled
// (i.e. it is assumed be located at the image center).
/*该简易simple_bundle_adjuster只优化9个参数,包括3个旋转,3个平移,1个焦距,2个径向畸变因子等。主点被认为是在图像中心,
该结构体用来描述代价函数,其中待优化的未知数为camera,包括之前所说的9个参数;point表示三维点,structure*/
struct SnavelyReprojectionError {
SnavelyReprojectionError(double observed_x, double observed_y)
: observed_x(observed_x), observed_y(observed_y) {}
template <typename T>
bool operator()(const T* const camera,
const T* const point,
T* residuals) const {
// camera[0,1,2] are the angle-axis rotation.
T p[3];
ceres::AngleAxisRotatePoint(camera, point, p);
// camera[3,4,5] are the translation.
p[0] += camera[3];
p[1] += camera[4];
p[2] += camera[5];
// Compute the center of distortion. The sign change comes from
// the camera model that Noah Snavely's Bundler assumes, whereby
// the camera coordinate system has a negative z axis.
T xp = - p[0] / p[2];
T yp = - p[1] / p[2];
// Apply second and fourth order radial distortion.
const T& l1 = camera[7];
const T& l2 = camera[8];
T r2 = xp*xp + yp*yp;
T distortion = 1.0 + r2 * (l1 + l2 * r2);
// Compute final projected point position.
const T& focal = camera[6];
T predicted_x = focal * distortion * xp;
T predicted_y = focal * distortion * yp;
// The error is the difference between the predicted and observed position.
residuals[0] = predicted_x - observed_x;
residuals[1] = predicted_y - observed_y;
return true;
}
//该代价函数实现了重投影过程。
//2.构造代价函数的偏导数
// Factory to hide the construction of the CostFunction object from
// the client code.
//对构造生成的代价函数求偏导
static ceres::CostFunction* Create(const double observed_x,
const double observed_y) {
return (new ceres::AutoDiffCostFunction<SnavelyReprojectionError, 2, 9, 3>(
new SnavelyReprojectionError(observed_x, observed_y)));
}
double observed_x;
double observed_y;
};
3.在构造好代价函数的偏导数后,利用solve求解非线性最小二乘
// Create residuals for each observation in the bundle adjustment problem. The
// parameters for cameras and points are added automatically.
//读取文件中的相机参数和三维点,按照costFunction计算梯度
ceres::Problem problem;
for (int i = 0; i < bal_problem.num_observations(); ++i) {
// Each Residual block takes a point and a camera as input and outputs a 2
// dimensional residual. Internally, the cost function stores the observed
// image location and compares the reprojection against the observation.
ceres::CostFunction* cost_function =
SnavelyReprojectionError::Create(observations[2 * i + 0],
observations[2 * i + 1]);
problem.AddResidualBlock(cost_function,
NULL /* squared loss */,
bal_problem.mutable_camera_for_observation(i),
bal_problem.mutable_point_for_observation(i));
}
// Make Ceres automatically detect the bundle structure. Note that the
// standard solver, SPARSE_NORMAL_CHOLESKY, also works fine but it is slower
// for standard bundle adjustment problems.
ceres::Solver::Options options;
options.linear_solver_type = ceres::DENSE_SCHUR;
options.minimizer_progress_to_stdout = true;
ceres::Solver::Summary summary;
ceres::Solve(options, &problem, &summary);
std::cout << summary.FullReport() << "\n";
结论:
目前对ceres的理解只到达整体框架的程度,但是对于
1)其内部如何求偏导
2)选用何种非线性最小二乘算法
等具体的内部如何实现还不清晰。
清晰一发:
对于一个BA问题,如有p个相机,q个三维点。变量向量x有如下的块结构:
x = [y1,...,yp,z1,...,zq].
其中,y对应相机参数,相机参数块个数c=6/9
z对应三维点参数,参数个数s=3
对于BA问题,求解的是 JTJ * X = b
针对JTJ=H
H矩阵又可以写成上述形式,其中B是一个pc*pc的块稀疏矩阵
C是一个qs*qs的块对焦矩阵
E是一个pc*qs的块稀疏矩阵
上述线性方程求解可写成:
对上述系数矩阵进行高斯消元,可以得到C是一个块对角矩阵,并且每个块也是对焦矩阵。因此,求解C的逆是非常简单,并且运算代价非常小的。因此,利用C矩阵这一特性,可以消去Δz。
,将其带入分块矩阵第一行,可得,
则最终就简化成,只需要计算pc*pc大小的系数矩阵块的线性方程组了。而且在一般情况下,相机数量p是远小于三维点数量q的。
还有两处不理解:
为什么三维点对应的矩阵块C是块对角的?
回答上头的问题:
BA中正规方程的稀疏性分析
这里以一个例子进行说明:
如图所示,以两个相机和六个三维点的对应作为样例,说明BA的稀疏性,首先列写jacobin矩阵J,并计算JTJ,可以看出,对应相机元素的矩阵块,是块对角矩阵,对应三维点元素的矩阵块,也是块对角矩阵,对三维点的元素的块进行高斯消元,可以得到一个3x3的对角矩阵,因此,整个三维点元素对应的分块矩阵就是一个对角矩阵,因此在求解时,可以直接求倒数得到矩阵块的逆。