CostFunctionToFunctor

class CostFunctionToFunctor

CostFunctionToFunctor 是一个适配器类,允许用户在用于自动微分的模板函数中使用 CostFunction 对象。这样,用户就可以将分析、数值和自动微分无缝地结合起来。使用自动微分的时候,一般的步骤是我们只需要定义一个类(结构体)然后重载 operator() 运算符计算残差,将这个类作为自动微分的模板参数传入即可。

例如,我们构造一个 CostFunction

class IntrinsicProjection : public SizedCostFunction<2, 5, 3> {
  public:
    IntrinsicProjection(const double* observation);
    virtual bool Evaluate(double const* const* parameters,
                          double* residuals,
                          double** jacobians) const;
};

上述 CostFunction 实现了一个点在其本地(相机)坐标系中对其图像平面的投影,计算不涉及相机外参,并将其观测点和投影点相减,计算残差,同时可以通过解析或者数值微分进行导数的计算。现在我们想要将该 CostFunction 和相机外参结合起来,例如旋转和平移,实现完整的重投影误差的计算,假设我们有如下模板函数

template<typename T>
void RotateAndTranslatePoint(const T* rotation,
                             const T* translation,
                             const T* point,
                             T* result);

如下为相机重投影误差的 struct

struct CameraProjection {
  explicit CameraProjection(double* observation)
  : intrinsic_projection_(std::make_unique<IntrinsicProjection>(observation)) {
  }

  template <typename T>
  bool operator()(const T* rotation,
                  const T* translation,
                  const T* intrinsics,
                  const T* point,
                  T* residual) const {
    T transformed_point[3];
    RotateAndTranslatePoint(rotation, translation, point, transformed_point);

    // Note that we call intrinsic_projection_, just like it was
    // any other templated functor.
    return intrinsic_projection_(intrinsics, transformed_point, residual);
  }

 private:
  CostFunctionToFunctor<2, 5, 3> intrinsic_projection_;
};

注意,CostFunctionToFunctor 拥有传入构造函数的 CostFunction 的所有权。在上面的示例中,我们假设 IntrinsicProjection 是一个能够评估其残差及其导数的 CostFunction。假设情况并非如此,IntrinsicProjection 的定义如下:

这里的 ThirdPartyProjectionFunction 是我们无法控制的第三方库函数。因此,该函数可以计算残差,但是无法计算导数,我们希望使用数值微分来计算其导数。在这种情况下,我们可以使用 NumericDiffCostFunctionCostFunctionToFunctor 的组合来完成工作。

至于 CameraProjection 的创建,我们可以使用自动求导即可。

Last updated