1:google 官网 http://ceres-solver.org/
2:一篇中文博客讲的很好:http://m.blog.csdn.net/HUAJUN998/article
简单的总结一下ceres solver
google的ceres-slover 个人感觉和g2o差不多。
(1)最重要的就是构建CostFunction。根据选择的微分模型的不同有三种构建方式(自动微分,数值微分,手动微分)
1:对于AutoDiffCostFunction类型的CostFunction,我们构造一个结构体,重写template operator(),注意类型为模板类型,重新定义了()函数,将结构体作为AutoDiffCostFunction的参数。
// structstruct CostFunctor {
template <typename T>
bool operator()(const T* const x, T* residual) const {
residual[0] = T(10.0) - x[0]; return true; }};
// make CostFunction
CostFunction* cost_function = new AutoDiffCostFunction<CostFunctor, 1, 1>(new CostFunctor);
problem.AddResidualBlock(cost_function, NULL, &x);
2:对于NumericDiffCostFunction类型的CostFunction,与AutoDiffCostFunction类似,只不过将结构体的接收类型不再是模板类型,用double类型代替了模板类型
// struct
struct NumericDiffCostFunctor {
bool operator()(const double* const x, double* residual) const {
residual[0] = 10.0 - x[0];
return true;
}
};
// make CostFunction
CostFunction* cost_function =
new NumericDiffCostFunction<NumericDiffCostFunctor, ceres::CENTRAL, 1, 1>(
new NumericDiffCostFunctor);
problem.AddResidualBlock(cost_function, NULL, &x);
3:
在有些情况下,不使用AutoDiffCostFunction,例如我们用近似的方式计算导数,而不是用AutoDiff的链式法则,我们需要自己的残差和Jacobin计算。这时我们定义一个CostFunction或者SizedCostFunction的子类。
class QuadraticCostFunction : public ceres::SizedCostFunction<1, 1> {
public:
virtual ~QuadraticCostFunction() {}
virtual bool Evaluate(double const* const* parameters,
double* residuals,
double** jacobians) const {
const double x = parameters[0][0];
residuals[0] = 10 - x;
// Compute the Jacobian if asked for.
if (jacobians != NULL && jacobians[0] != NULL) {
jacobians[0][0] = -1;
}
return true;
}
};
基本都用自动微分(链式求导法则)。数值微分是有线性误差的,而且这也会导致收敛比较慢。手动求导容易出错(g2o用的就是手动求导,有没有感觉很麻烦)
(2)添加误差项Problem.AddResidualBlock(cost_fuction,NULL/loss_function,input_param1,input_param2,...)
其中loss_function的目的是排除外点。即误差较大的项被剔除。除此之外,还有个函数和Problem.AddResidualBlock类似
void Problem::AddParameterBlock(double *values, int size, LocalParameterization*local_parameterization)
或
void Problem::AddParameterBlock(double *values, int size)
这个函数的目的是告诉Problem在目标函数中有哪些是变量。其实这个可以不添加。Google的官网有说明:
The user has the option of explicitly adding the parameter blocks using AddParameterBlock. This causes additional correctness checking; however, AddResidualBlock implicitly adds the parameter blocks if they are not present, so calling AddParameterBlock explicitly is not required.
但也不是完全没用,比如要固定一些变量,就需要设定Problem::SetParametersBlockConstant(&x),x为你要设定的固定变量。
这里还需要注意的是在构建cost_function时,例如
CostFunction* cost_function = new AutoDiffCostFunction<CostFunctor, 1, 1,1>(new CostFunctor); CostFunction* cost_function = new AutoDiffCostFunction<CostFunctor, 1, 1,1>(new CostFunctor);
这里的第一个1代表误差项的个数,第二个1代表 input_param1的 维数。第三个1代表input_param2的维数。即cost_function 要和AddResidualBlock相对应
(3)求解器的构建
Solver::Options options;
options.minimizer_progress_to_stdout = true;
Solver::Summary summary;
Solve(options, &problem, &summary);
以上几步骤是必须的。以下部分是根据需要选择的部分(主要是BA时的一些选项)
DEFINE_string(trust_region_strategy, "levenberg_marquardt",
"Options are: levenberg_marquardt, dogleg.");
DEFINE_string(dogleg, "traditional_dogleg", "Options are: traditional_dogleg,"
"subspace_dogleg.");
DEFINE_bool(inner_iterations, false, "Use inner iterations to non-linearly "
"refine each successful trust region step.");
DEFINE_string(blocks_for_inner_iterations, "automatic", "Options are: "
"automatic, cameras, points, cameras,points, points,cameras");
DEFINE_string(linear_solver, "sparse_schur", "Options are: "
"sparse_schur, dense_schur, iterative_schur, sparse_normal_cholesky, "
"dense_qr, dense_normal_cholesky and cgnr.");
DEFINE_bool(explicit_schur_complement, false, "If using ITERATIVE_SCHUR "
"then explicitly compute the Schur complement.");
DEFINE_string(preconditioner, "jacobi", "Options are: "
"identity, jacobi, schur_jacobi, cluster_jacobi, "
"cluster_tridiagonal.");
DEFINE_string(visibility_clustering, "canonical_views",
"single_linkage, canonical_views");
DEFINE_string(sparse_linear_algebra_library, "suite_sparse",
"Options are: suite_sparse and cx_sparse.");
DEFINE_string(dense_linear_algebra_library, "eigen",
"Options are: eigen and lapack.");
DEFINE_string(ordering, "automatic", "Options are: automatic, user.");
DEFINE_bool(use_quaternions, false, "If true, uses quaterni