Calico
A visual-inertial calibration library designed for rapid problem construction and debugging.
imager_cost_functor.h
1 #ifndef CALICO_SENSORS_IMAGER_COST_FUNCTOR_H_
2 #define CALICO_SENSORS_IMAGER_COST_FUNCTOR_H_
3 
4 #include <memory>
5 #include <vector>
6 
7 #include "Eigen/Dense"
8 #include "calico/sensors/camera_models.h"
9 #include "calico/trajectory.h"
10 #include "ceres/cost_function.h"
11 
12 namespace calico::sensors {
13 
14 // Enum listing the positions of parameters for a camera cost function.
15 enum class ImagerParameterIndices : int {
16  // Camera intrinsics.
17  kIntrinsicsIndex = 0,
18  // Extrinsic parameters of the imager relative to its sensor module.
19  kImagerExtrinsicsRotationIndex = 1,
20  kImagerExtrinsicsTranslationIndex = 2,
21  // Extrinsic parameters of the sensor module relative to the sensor rig.
22  kSensorExtrinsicsRotationIndex = 3,
23  kSensorExtrinsicsTranslationIndex = 4,
24  // Sensor latency.
25  kLatencyIndex = 5,
26  // Parameters related to some detected "model" object in the world:
27  // 1. The point resolved in the model frame.
28  // 2. The rotation portion of the model pose resolved in the world
29  // frame.
30  // 3. The translation portion of the model pose resolved in the world
31  // frame.
32  kModelPointIndex = 6,
33  kModelRotationIndex = 7,
34  kModelTranslationIndex = 8,
35  // Rotation and position control points of the associated spline segment as
36  // two Nx3 matrices (rotation then position) where N is the spline order.
37  kSensorRigPoseSplineControlPointsIndex = 9,
38 };
39 
40 // Generic auto-differentiation camera cost functor. Residuals will be based on
41 // how the camera model is initialized.
43  public:
44  static constexpr int kCameraResidualSize = 2;
46  const Eigen::Vector2d& pixel, double sigma, double stamp,
47  const Trajectory& sp_T_world_sensorrig);
48 
49  // Convenience function for creating a camera cost function.
50  static ceres::CostFunction* CreateCostFunction(
51  const Eigen::Vector2d& pixel, double sigma,
52  CameraIntrinsicsModel camera_model, Eigen::VectorXd& intrinsics,
53  Pose3d& imager_extrinsics, Pose3d& sensor_extrinsics, double& latency,
54  Eigen::Vector3d& t_model_point, Pose3d& T_world_model,
55  Trajectory& trajectory_world_sensorrig, double stamp,
56  std::vector<double*>& parameters);
57 
58  // Parameters to the cost function:
59  // intrinsics:
60  // All parameters in the intrinsics model as an Eigen column vector.
61  // Order of the parameters will need to be in agreement with the model
62  // being used.
63  // q_sensor_imager:
64  // Rotation from sensor frame to camera frame as a quaternion.
65  // t_sensor_imager:
66  // Position of camera relative to sensor origin resolved in the
67  // sensor frame.
68  // q_sensorrig_sensor:
69  // Rotation from sensor rig frame to sensor frame as a quaternion.
70  // t_sensorrig_sensor:
71  // Position of sensor relative to sensor rig origin resolved in the
72  // sensor rig frame.
73  // latency:
74  // Sensor latency in seconds.
75  // q_world_model:
76  // Rotation from world frame to model frame as a quaternion.
77  // t_model_point:
78  // Position of the point in the model resolved in the model frame.
79  // t_world_model:
80  // Position of model relative to world origin resolved in the world frame.
81  // control_points:
82  // Control points for the entire pose trajectory.
83  template <typename T>
84  bool operator()(T const* const* parameters, T* residual) {
85  // Parse intrinsics.
86  const T* intrinsics_ptr = static_cast<const T*>(
87  &(parameters[static_cast<int>(ImagerParameterIndices::kIntrinsicsIndex)]
88  [0]));
89  const int parameter_size = camera_model_->NumberOfParameters();
90  const Eigen::VectorX<T> intrinsics =
91  Eigen::Map<const Eigen::VectorX<T>>(intrinsics_ptr, parameter_size);
92  // Parse imager extrinsics.
93  const Eigen::Map<const Eigen::Quaternion<T>> q_sensor_imager(
94  &(parameters[static_cast<int>(
95  ImagerParameterIndices::kImagerExtrinsicsRotationIndex)][0]));
96  const Eigen::Map<const Eigen::Vector3<T>> t_sensor_imager(
97  &(parameters[static_cast<int>(
98  ImagerParameterIndices::kImagerExtrinsicsTranslationIndex)][0]));
99  // Parse sensor extrinsics.
100  const Eigen::Map<const Eigen::Quaternion<T>> q_sensorrig_sensor(
101  &(parameters[static_cast<int>(
102  ImagerParameterIndices::kSensorExtrinsicsRotationIndex)][0]));
103  const Eigen::Map<const Eigen::Vector3<T>> t_sensorrig_sensor(
104  &(parameters[static_cast<int>(
105  ImagerParameterIndices::kSensorExtrinsicsTranslationIndex)][0]));
106  // Parse latency.
107  const T latency =
108  parameters[static_cast<int>(ImagerParameterIndices::kLatencyIndex)][0];
109  // Parse model point and model pose resolved in the world frame.
110  const Eigen::Map<const Eigen::Vector3<T>> t_model_point(
111  &(parameters[static_cast<int>(ImagerParameterIndices::kModelPointIndex)]
112  [0]));
113  const Eigen::Map<const Eigen::Quaternion<T>> q_world_model(
114  &(parameters[static_cast<int>(
115  ImagerParameterIndices::kModelRotationIndex)][0]));
116  const Eigen::Map<const Eigen::Vector3<T>> t_world_model(
117  &(parameters[static_cast<int>(
118  ImagerParameterIndices::kModelTranslationIndex)][0]));
119  // Parse sensor rig spline resolved in the world frame.
120  const int num_rotation_control_points =
121  rotation_trajectory_evaluation_params_.num_control_points;
122  Eigen::MatrixX<T> rotation_control_points(num_rotation_control_points, 3);
123  for (int i = 0; i < num_rotation_control_points; ++i) {
124  rotation_control_points.row(i) = Eigen::Map<const Eigen::Vector3<T>>(
125  &(parameters[static_cast<int>(
126  ImagerParameterIndices::
127  kSensorRigPoseSplineControlPointsIndex) +
128  i][0]));
129  }
130  const int num_position_control_points =
131  position_trajectory_evaluation_params_.num_control_points;
132  Eigen::MatrixX<T> position_control_points(num_position_control_points, 3);
133  for (int i = 0; i < num_position_control_points; ++i) {
134  position_control_points.row(i) = Eigen::Map<const Eigen::Vector3<T>>(
135  &(parameters[static_cast<int>(
136  ImagerParameterIndices::
137  kSensorRigPoseSplineControlPointsIndex) +
138  i + num_rotation_control_points][0]));
139  }
140 
141  const Eigen::MatrixX<T> rotation_basis_matrix =
142  rotation_trajectory_evaluation_params_.basis_matrix.template cast<T>();
143  const T rotation_knot0 =
144  static_cast<T>(rotation_trajectory_evaluation_params_.knot0);
145  const T rotation_knot1 =
146  static_cast<T>(rotation_trajectory_evaluation_params_.knot1);
147  const T rotation_stamp =
148  static_cast<T>(rotation_trajectory_evaluation_params_.stamp) - latency;
149 
150  const Eigen::MatrixX<T> position_basis_matrix =
151  position_trajectory_evaluation_params_.basis_matrix.template cast<T>();
152  const T position_knot0 =
153  static_cast<T>(position_trajectory_evaluation_params_.knot0);
154  const T position_knot1 =
155  static_cast<T>(position_trajectory_evaluation_params_.knot1);
156  const T position_stamp =
157  static_cast<T>(position_trajectory_evaluation_params_.stamp) - latency;
158  // Evaluate the pose.
159  const Eigen::Vector3<T> phi_sensorrig_world = -BSpline<3, T>::Evaluate(
160  rotation_control_points, rotation_knot0, rotation_knot1,
161  rotation_basis_matrix, rotation_stamp, 0);
162  T q_sensorrig_world_array[4];
163  ceres::AngleAxisToQuaternion(phi_sensorrig_world.data(),
164  q_sensorrig_world_array);
165  const Eigen::Quaternion<T> q_sensorrig_world(
166  q_sensorrig_world_array[0], q_sensorrig_world_array[1],
167  q_sensorrig_world_array[2], q_sensorrig_world_array[3]);
168  const Eigen::Vector3<T> t_world_sensorrig = BSpline<3, T>::Evaluate(
169  position_control_points, position_knot0, position_knot1,
170  position_basis_matrix, position_stamp, 0);
171 
172  // Resolve the model point in the camera frame.
173  const Eigen::Quaternion<T> q_sensorrig_imager =
174  q_sensorrig_sensor * q_sensor_imager;
175  const Eigen::Vector3<T> t_sensorrig_imager =
176  t_sensorrig_sensor + q_sensorrig_sensor * t_sensor_imager;
177  const Eigen::Quaternion<T> q_imager_model =
178  q_sensorrig_imager.inverse() * q_sensorrig_world * q_world_model;
179  const Eigen::Vector3<T> t_world_imager =
180  t_world_sensorrig + q_sensorrig_world.inverse() * t_sensorrig_imager;
181  const Eigen::Vector3<T> t_model_imager =
182  q_world_model.inverse() * (t_world_imager - t_world_model);
183  const Eigen::Vector3<T> t_camera_point =
184  q_imager_model * (t_model_point - t_model_imager);
185  // Project the point through the camera model.
186  const absl::StatusOr<Eigen::Vector2<T>> projection =
187  camera_model_->ProjectPoint(intrinsics, t_camera_point);
188  // Assign the residual, or return boolean indicating success/failure.
189  if (projection.ok()) {
190  Eigen::Map<Eigen::Vector2<T>> error(residual);
191  const Eigen::Vector2<T> pixel = pixel_.template cast<T>();
192  error = (pixel - *projection) * static_cast<T>(information_);
193  return true;
194  }
195  return false;
196  }
197 
198  private:
199  Eigen::Vector2d pixel_;
200  double information_;
201  std::unique_ptr<CameraModel> camera_model_;
202  TrajectoryEvaluationParams position_trajectory_evaluation_params_;
203  TrajectoryEvaluationParams rotation_trajectory_evaluation_params_;
204 };
205 } // namespace calico::sensors
206 
207 #endif // CALICO_SENSORS_IMAGER_COST_FUNCTOR_H_
Definition: bspline.h:17
Definition: trajectory.h:25
Definition: imager_cost_functor.h:42
Sensors namespace.
Definition: accelerometer.cpp:8
CameraIntrinsicsModel
Camera model types.
Definition: camera_models.h:16
Definition: trajectory.h:14