Calico
A visual-inertial calibration library designed for rapid problem construction and debugging.
bspline.h
1 #ifndef CALICO_BSPLINE_H_
2 #define CALICO_BSPLINE_H_
3 
4 #include "calico/typedefs.h"
5 
6 #include "absl/status/statusor.h"
7 #include "ceres/problem.h"
8 #include "Eigen/Dense"
9 
10 
11 namespace calico {
12 
13 // Generic N-DOF spline fitter. This class implements the following paper:
14 // "General Matrix Representations for B-Splines", K. Qin.
15 // https://xiaoxingchen.github.io/2020/03/02/bspline_in_so3/general_matrix_representation_for_bsplines.pdf
16 template <int N, typename T = double>
17 class BSpline {
18  public:
19  ~BSpline() = default;
20 
21  // Add this spline's control points to a ceres problem. Returns the number of
22  // parameters added, which should be N * number of control points.
23  int AddParametersToProblem(ceres::Problem& problem);
24 
25  void EnableControlPointsEstimation(bool enable);
26 
27  // Fits an N-DOF uniform B-spline fitted to given timestamps
28  // and N-dimensional data. User also specifies the spline order and the knot
29  // frequency of the spline.
30  absl::Status FitToData(const std::vector<T>& time,
31  const std::vector<Eigen::Vector<T,N>>& data,
32  int spline_order, T knot_frequency);
33 
34  // Convenience function for getting the index of the active spline segement for
35  // a queried time.
36  int GetSplineIndex(T query_time) const;
37 
38  // Convenience function for getting the index of the appropriate beginning
39  // knot for a spline segment with index control_point_index.
40  int GetKnotIndexFromSplineIndex(int control_point_index) const;
41 
42  // Getter for the spline order.
43  int GetSplineOrder() const;
44 
45  // Interpolate the spline at given times for the given derivative. If no
46  // derivative is specified, it defaults to direct interpolation.
47  absl::StatusOr<std::vector<Eigen::Vector<T, N>>>
48  Interpolate(const std::vector<T>& times, int derivative = 0) const;
49 
50  // Interpolate the spline at single time for the given derivative.
51  absl::StatusOr<Eigen::Vector<T, N>>
52  Interpolate(T time, int derivative = 0) const {
53  const absl::StatusOr<std::vector<Eigen::Vector<T, N>>> statusor =
54  Interpolate(std::vector{time}, derivative);
55  if (!statusor.ok()) {
56  return statusor.status();
57  }
58  return statusor->front();
59  }
60 
61  // TODO(yangjames): Description
62  Eigen::MatrixX<T>
63  GetSplineBasis(int spline_idx, T stamp, int derivative) const;
64 
65 
66  static Eigen::Vector<T, N> Evaluate(
67  const Eigen::Ref<const Eigen::MatrixX<T>>& control_points_set, T knot0,
68  T knot1, const Eigen::MatrixX<T>& basis_matrix, T stamp, int derivative);
69 
70 
71  // Setter/getter for knot vector.
72  const std::vector<T>& knots() const { return knots_; }
73  std::vector<T>& knots() { return knots_; }
74 
75  // Setter/getter for control points.
76  const std::vector<Eigen::Vector<T, N>>& control_points() const {
77  return control_points_;
78  }
79  std::vector<Eigen::Vector<T, N>>& control_points() {
80  return control_points_;
81  }
82 
83  // Setter/getter for basis matrices.
84  const std::vector<Eigen::MatrixX<T>>& basis_matrices() const {
85  return Mi_;
86  }
87  std::vector<Eigen::MatrixX<T>>& basis_matrices() {
88  return Mi_;
89  }
90 
91  private:
92  // Data/parameters for fitting spline.
93  int spline_order_;
94  T knot_frequency_;
95  std::vector<Eigen::Vector<T,N>> data_;
96  std::vector<T> time_;
97 
98  // Derived properties of the spline.
99  int spline_degree_;
100  std::vector<T> knots_;
101  std::vector<T> valid_knots_;
102  Eigen::MatrixXd derivative_coeffs_;
103  std::vector<Eigen::MatrixXd> Mi_;
104  std::vector<Eigen::Vector<T,N>> control_points_;
105 
106  // Flag for estimating control points in optimization.
107  bool control_points_enabled_;
108 
109  // Convenience function for computing a knot vector.
110  void ComputeKnotVector();
111 
112  // Convenience function for computing the basis matrices for this spline.
113  void ComputeBasisMatrices();
114 
115  // Methods implementing the recursive algorithm for computing the basis
116  // matrix per Theorem 1 of "General Matrix Representations for B-Splines".
117  // M_k = [ M_km1 ] * A + [ 0^T ] * B
118  // = [ 0^T ] [ M_km1 ]
119  //
120  // A = [ 1-d_0,i-k+2 d_0,i-k+2 ]
121  // [ 1-d_0,i-k+3 d_0,i-k+3 ]
122  // [ ... ]
123  // [ 1-d_0,i d_0,i ]
124  //
125  // B = [ -d_1,i-k+2 d_1,i-k+2 ]
126  // [ -d_1,i-k+3 d_0,i-k+3 ]
127  // [ ... ]
128  // [ -d_1,i d_1,i ]
129  // where k is the spline order and i is the spline segment number.
130  Eigen::MatrixX<T> M(int k, int i);
131  T d_0(int k, int i, int j);
132  T d_1(int k, int i, int j);
133 
134  // Fit spline to data.
135  void FitSpline();
136 
137  // Check that inputs provided for spline fit are valid.
138  absl::Status CheckDataForSplineFit(
139  const std::vector<T>& time,
140  const std::vector<Eigen::Vector<T,N>>& data, int spline_order,
141  T knot_frequency);
142 };
143 
144 } // namespace calico
145 
146 #include "calico/bspline.hpp"
147 #endif // CALICO_BSPLINE_H_
Definition: bspline.h:17
Primary calico namespace.
Definition: __init__.py:1