struct ExponentialResidual {
ExponentialResidual(double x, double y)
: x_(x), y_(y) {}
// ()函数的参数为待求值和残差值
template bool operator()(const T* const m,
const T* const c,
T* residual) const {
residual[0] = y_ - exp(m[0] * x_ + c[0]);
return true;
}
private:
const double x_; // 保存观测值,本结构体创建进传入
const double y_;
};
为每个观测值创建一个CostFunction并加入Problem中
class CostFunction (残差对象)
这是用户和Ceres优化器之间的建模层。 函数的签名(输入参数块的数量和大小以及输出的数量)分别存储在parameter_block_sizes_和num_residuals_中。 从此类继承的用户代码应该使用相应的访问器设置这两个成员。 添加AddResidualBlock()时,将通过问题验证此信息。
class AutoDiffCostFunction
是CostFunction的派生类,它自动计算残差对每个参数的层数(即jacobian),它是一个模板类
template // Number of parameters in block 9.
// Takes ownership of functor. Uses the template-provided value for the
// number of residuals ("kNumResiduals").
// 支持残差个数为动态的:ceres::DYNAMIC
explicit AutoDiffCostFunction(CostFunctor* functor)
// Takes ownership of functor. Ignores the template-provided
// kNumResiduals in favor of the "num_residuals" argument provided.
// This allows for having autodiff cost functions which return varying
// numbers of residuals at runtime.
// 不支持残差个数为动态的:ceres::DYNAMIC
AutoDiffCostFunction(CostFunctor* functor, int num_residuals)
// Add a residual block to the overall cost function. The cost
// function carries with it information about the sizes of the
// parameter blocks it expects. The function checks that these match
// the sizes of the parameter blocks listed in parameter_blocks. The
// program aborts if a mismatch is detected. loss_function can be
// NULL, in which case the cost of the term is just the squared norm
// of the residuals.
ResidualBlockId AddResidualBlock(CostFunction* cost_function,
LossFunction* loss_function,
const std::vector& parameter_blocks);
// Convenience methods for adding residuals with a small number of
// parameters. This is the common case. Instead of specifying the
// parameter block arguments as a vector, list them as pointers.
ResidualBlockId AddResidualBlock(CostFunction* cost_function,
LossFunction* loss_function,
double* x0);
ResidualBlockId AddResidualBlock(CostFunction* cost_function,
LossFunction* loss_function,
double* x0, double* x1);
ResidualBlockId AddResidualBlock(CostFunction* cost_function,
LossFunction* loss_function,
double* x0, double* x1, double* x2,
double* x3, double* x4, double* x5,
double* x6, double* x7, double* x8,
double* x9);
// Add a parameter block with appropriate size to the problem.
// Repeated calls with the same arguments are ignored. Repeated
// calls with the same double pointer but a different size results
// in undefined behaviour.
void AddParameterBlock(double* values, int size);
// Add a parameter block with appropriate size and parameterization
// to the problem. Repeated calls with the same arguments are
// ignored. Repeated calls with the same double pointer but a
// different size results in undefined behaviour.
void AddParameterBlock(double* values,
int size,
LocalParameterization* local_parameterization);
// Hold the indicated parameter block constant during optimization.
void SetParameterBlockConstant(double* values);
// Allow the indicated parameter block to vary during optimization.
void SetParameterBlockVariable(double* values);
double m = 0.0;
double c = 0.0;
Problem problem;
for (int i = 0; i < kNumObservations; ++i) {
CostFunction* cost_function =
new AutoDiffCostFunction(
new ExponentialResidual(data[2 * i], data[2 * i + 1]));
problem.AddResidualBlock(cost_function,
new CauchyLoss(0.5),
&m, &c);
}
Solver::Options options;
options.linear_solver_type = ceres::DENSE_QR;
options.minimizer_progress_to_stdout = true;
Solver::Summary summary;
Solve(options, &problem, &summary);
std::cout << summary.BriefReport() << "\n";
std::cout << "Initial m: " << 0.0 << " c: " << 0.0 << "\n";
std::cout << "Final m: " << m << " c: " << c << "\n";
// For example, consider a scalar error e = k - x'y, where both x and y are
// two-dimensional column vector parameters, the prime sign indicates
// transposition, and k is a constant. The form of this error, which is the
// difference between a constant and an expression, is a common pattern in least
// squares problems. For example, the value x'y might be the model expectation
// for a series of measurements, where there is an instance of the cost function
// for each measurement k.
//
// The actual cost added to the total problem is e^2, or (k - x'k)^2; however,
// the squaring is implicitly done by the optimization framework.
//
// To write an auto-differentiable cost function for the above model, first
// define the object
class MyScalarCostFunctor {
MyScalarCostFunctor(double k): k_(k) {}
template
bool operator()(const T* const x , const T* const y, T* e) const {
e[0] = T(k_) - x[0] * y[0] + x[1] * y[1];
return true;
}
private:
double k_;
};
// Note that in the declaration of operator() the input parameters x and y come
// first, and are passed as const pointers to arrays of T. If there were three
// input parameters, then the third input parameter would come after y. The
// output is always the last parameter, and is also a pointer to an array. In
// the example above, e is a scalar, so only e[0] is set.
//
// Then given this class definition, the auto differentiated cost function for
// it can be constructed as follows.
CostFunction* cost_function
= new AutoDiffCostFunction(
new MyScalarCostFunctor(1.0));
// | | |
// Dimension of residual -----+ | |
// Dimension of x ---------------+ |
// Dimension of y ------------------+
//
// In this example, there is usually an instance for each measumerent of k.
//
// In the instantiation above, the template parameters following
// "MyScalarCostFunctor", "1, 2, 2", describe the functor as computing a
// 1-dimensional output from two arguments, both 2-dimensional.
//
// AutoDiffCostFunction also supports cost functions with a
// runtime-determined number of residuals. For example:
CostFunction* cost_function
= new AutoDiffCostFunction(
new CostFunctorWithDynamicNumResiduals(1.0), ^ ^ ^
runtime_number_of_residuals);
^ | | |
// | | | |
// | | | |
// Actual number of residuals ------+ | | |
// Indicate dynamic number of residuals --------+ | |
// Dimension of x ------------------------------------+ |
// Dimension of y ---------------------------------------+
//
// The framework can currently accommodate cost functions of up to 10
// independent variables, and there is no limit on the dimensionality
// of each of them.