CostFunction

对于目标函数中的每个项,都有一个CostFunction 负责计算残差向量和 Jacobian 矩阵。考虑其中一项残差 f(x1,x2,...,xk)f(x_1,x_2,...,x_k) ,其取决于参数块 [x1,x2,...,xk][x_1,x_2,...,x_k]。给定参数 [x1,x2,...,xk][x_1,x_2,...,x_k]CostFunction 负责计算向量函数 f(x1,x2,...,xk)f(x_1,x_2,...,x_k) 和它对每个变量的 Jacobian 矩阵。

Ji=Dif(x1,...,xk) {1,...,k}J_i=D_if(x_1,...,x_k) \ \forall \in \{1,...,k\}
class CostFunction

Code Impl

class CostFunction {
 public:
  virtual bool Evaluate(double const* const* parameters,
                        double* residuals,
                        double** jacobians) const = 0;
  const std::vector<int32>& parameter_block_sizes();
  int num_residuals() const;

 protected:
  std::vector<int32>* mutable_parameter_block_sizes();
  void set_num_residuals(int num_residuals);
};

CostFunction 输入参数块的数量和大小以及输出的数量分别存储在 CostFunction::parameter_block_sizes_CostFunction::num_residuals_中。从该类继承的用户代码应使用相应的函数方法设置这两个成员。当使用 Problem::AddResidualBlock() 添加时,Problem 将验证这些信息。

bool CostFunction::Evaluate(double const *const *parameters, 
                            double *residuals, 
                            double **jacobians) const

上述函数用于计算残差向量和 Jacobian 矩阵。该函数为纯虚函数,需要在子类进行重写,因为 Ceres 不知道你的残差是如何计算的。对其中的参数做出一些解释和强调。

  • parameters 是一个数组,其大小为 CostFunction::parameter_block_sizes_.size()

  • parameters[i] 也是一个数组,其大小为 CostFunction::parameter_block_sizes_[i]

  • 从上面了两条可以看出 parameters 其实是一个二维数组。

  • parameters 永远不能为 nullptr

  • residuals 是一个数组,长度为 num_residuals

  • residuals 永远不能为 nullptr

  • jacobians 是一个数组,长度为 CostFunction::parameter_block_sizes_.size()

  • jacobians[i] 是一个 row-major 数组,长度为 num_residuals x parameter_block_sizes_[i]

  • 如果 jacobians[i] 不为 nullptr 的话,需要用户手动计算残差相对于 parameters[i] 的 Jacobian 矩阵,并存储在数组中,例如 jacobians[i][r * parameter_block_sizes_[i] + c] = residual[r]paramters[i][c]\frac{\partial \text{residual[r]}}{\partial \text{paramters[i][c]}}

  • 如果 jacobians[i]nullptr,那么它的计算过程可以跳过,这种情况发生在当参数块被设定为常数的时候。

  • 返回值表示残差和 Jacobian 的计算是否成功。这可用于检查 jacobian 计算中是否有数值问题。

Last updated