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