NASA Astrobee Robot Software  0.19.1
Flight software for the Astrobee robots operating inside the International Space Station.
camera_target_based_intrinsics_calibrator.h
Go to the documentation of this file.
1 /* Copyright (c) 2017, United States Government, as represented by the
2  * Administrator of the National Aeronautics and Space Administration.
3  *
4  * All rights reserved.
5  *
6  * The Astrobee platform is licensed under the Apache License, Version 2.0
7  * (the "License"); you may not use this file except in compliance with the
8  * License. You may obtain a copy of the License at
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
14  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
15  * License for the specific language governing permissions and limitations
16  * under the License.
17  */
18 #ifndef CALIBRATION_CAMERA_TARGET_BASED_INTRINSICS_CALIBRATOR_H_
19 #define CALIBRATION_CAMERA_TARGET_BASED_INTRINSICS_CALIBRATOR_H_
20 
22 #include <calibration/match_set.h>
24 #include <calibration/utilities.h>
32 
33 #include <Eigen/Core>
34 #include <Eigen/Geometry>
35 
36 #include <ceres/ceres.h>
37 #include <ceres/solver.h>
38 
39 #include <utility>
40 #include <vector>
41 
42 namespace calibration {
43 template <typename DISTORTER>
45  public:
47  : params_(params) {}
48 
50  const std::vector<localization_common::ImageCorrespondences>& correspondences_set,
51  const StateParameters& initial_state_parameters, StateParameters& calibrated_state_parameters,
52  StateParametersCovariances& covariances);
53 
54  bool Calibrate(const std::vector<MatchSet>& match_sets, const StateParameters& initial_state_parameters,
55  StateParameters& calibrated_state_parameters, StateParametersCovariances& covariances);
56 
58 
59  private:
60  void Initialize(const StateParameters& initial_state_parameters);
61  boost::optional<StateParametersCovariances> Covariances();
62  void AddCameraTTargetParameter(const Eigen::Isometry3d& camera_T_target);
63  double RadialScaleFactor(const Eigen::Vector2d& image_point, const Eigen::Vector2i& image_size) const;
64  void SaveResults(const StateParameters& calibrated_state_parameters, const std::vector<MatchSet>& match_sets) const;
66  const std::vector<int>& inliers) const;
67 
69  OptimizationStateParameters state_parameters_;
70  ceres::Problem problem_;
71  // Keep track of correspondences used to create final reprojection image
72  std::vector<localization_common::ImageCorrespondences> valid_correspondences_set_;
73 };
74 
75 template <typename DISTORTER>
77  const std::vector<localization_common::ImageCorrespondences>& correspondences_set,
78  const StateParameters& initial_state_parameters, StateParameters& calibrated_state_parameters,
79  StateParametersCovariances& covariances) {
80  std::vector<MatchSet> match_sets;
81  const Eigen::Matrix3d initial_intrinsics =
82  optimization_common::Intrinsics(initial_state_parameters.focal_lengths, initial_state_parameters.principal_points);
83  for (const auto& correspondences : correspondences_set) {
84  const auto camera_T_target = vision_common::ReprojectionPoseEstimate<DISTORTER>(
85  correspondences.image_points, correspondences.points_3d, initial_state_parameters.focal_lengths,
86  initial_state_parameters.principal_points, initial_state_parameters.distortion,
87  params_.reprojection_pose_estimate);
88 
89  if (!camera_T_target) {
90  LogError("Failed to get camera_T_target with " << correspondences.size() << " matches.");
91  continue;
92  }
93 
94  match_sets.emplace_back(correspondences, camera_T_target->pose, camera_T_target->inliers);
95  if (params_.save_individual_initial_reprojection_images) {
96  static int image_count = 0;
97  const auto& match_set = match_sets.back();
98  SaveReprojectionImage<DISTORTER>(match_set.correspondences.image_points, match_set.correspondences.points_3d,
99  match_set.inliers, initial_intrinsics, initial_state_parameters.distortion,
100  match_set.pose_estimate, params_.individual_max_visualization_error_norm,
101  "reprojection_image_" + std::to_string(image_count++) + ".png");
102  }
103  }
104 
105  return Calibrate(match_sets, initial_state_parameters, calibrated_state_parameters, covariances);
106 }
107 
108 template <typename DISTORTER>
109 bool CameraTargetBasedIntrinsicsCalibrator<DISTORTER>::Calibrate(const std::vector<MatchSet>& match_sets,
110  const StateParameters& initial_state_parameters,
111  StateParameters& calibrated_state_parameters,
112  StateParametersCovariances& covariances) {
113  Initialize(initial_state_parameters);
114  // Reserve so that pointers aren't modified while new target poses are added.
115  // This can mess up ceres::Problem since it relies on pointers of add parameters.
116  state_parameters_.camera_T_targets.reserve(match_sets.size());
117  // Add residuals to problem
118  for (const auto& match_set : match_sets) {
119  AddCameraTTargetParameter(match_set.pose_estimate);
120  localization_common::ImageCorrespondences valid_correspondences =
121  params_.only_use_inliers ? InlierMatches(match_set.correspondences, match_set.inliers)
122  : match_set.correspondences;
123  valid_correspondences_set_.emplace_back(valid_correspondences);
124  for (int i = 0; i < static_cast<int>(valid_correspondences.size()) && i < params_.max_num_match_sets; ++i) {
125  const double radial_scale_factor = RadialScaleFactor(valid_correspondences.image_points[i], params_.image_size);
127  valid_correspondences.image_points[i], valid_correspondences.points_3d[i],
128  state_parameters_.camera_T_targets.back(), state_parameters_.focal_lengths, state_parameters_.principal_points,
129  state_parameters_.distortion, problem_, radial_scale_factor, params_.optimization.huber_loss);
130  }
131  }
132 
133  ceres::Solver::Summary summary;
134  ceres::Solve(params_.optimization.solver_options, &problem_, &summary);
135  if (params_.optimization.verbose) std::cout << summary.FullReport() << std::endl;
136  if (!summary.IsSolutionUsable()) {
137  LogError("Calibrate: Calibration failed.");
138  return false;
139  }
140 
141  calibrated_state_parameters = state_parameters_.OptimizedStateParameters();
142  SaveResults(calibrated_state_parameters, match_sets);
143 
144  const auto state_covariances = Covariances();
145  if (!state_covariances) {
146  LogError("Calibrate: Failed to get covariances");
147  return false;
148  }
149  covariances = *state_covariances;
150 
151  return true;
152 }
153 
154 template <typename DISTORTER>
156  state_parameters_.SetInitialStateParameters(initial_state_parameters);
157  optimization_common::AddParameterBlock(2, state_parameters_.focal_lengths.data(), problem_,
158  !params_.calibrate_focal_lengths);
159  optimization_common::AddParameterBlock(2, state_parameters_.principal_points.data(), problem_,
160  !params_.calibrate_principal_points);
161  optimization_common::AddParameterBlock(DISTORTER::kNumParams, state_parameters_.distortion.data(), problem_,
162  !params_.calibrate_distortion);
163  if (params_.optimization.verbose) {
164  if (params_.calibrate_focal_lengths) LogInfo("Calibrating focal lengths.");
165  if (params_.calibrate_principal_points) LogInfo("Calibrating principal points.");
166  if (params_.calibrate_distortion) LogInfo("Calibrating distortion.");
167  if (params_.calibrate_target_poses) LogInfo("Calibrating target poses.");
168  }
169 }
170 
171 template <typename DISTORTER>
172 boost::optional<StateParametersCovariances> CameraTargetBasedIntrinsicsCalibrator<DISTORTER>::Covariances() {
173  ceres::Covariance::Options options;
174  ceres::Covariance covariance(options);
175 
176  std::vector<std::pair<const double*, const double*> > covariance_blocks;
177  covariance_blocks.push_back(
178  std::make_pair(state_parameters_.focal_lengths.data(), state_parameters_.focal_lengths.data()));
179  covariance_blocks.push_back(
180  std::make_pair(state_parameters_.principal_points.data(), state_parameters_.principal_points.data()));
181  covariance_blocks.push_back(std::make_pair(state_parameters_.distortion.data(), state_parameters_.distortion.data()));
182 
183  if (!covariance.Compute(covariance_blocks, &problem_)) {
184  LogError("Covariances: Failed to compute covariances.");
185  return boost::none;
186  }
187 
188  StateParametersCovariances covariances;
189  covariance.GetCovarianceBlock(state_parameters_.focal_lengths.data(), state_parameters_.focal_lengths.data(),
190  covariances.focal_lengths.data());
191  covariance.GetCovarianceBlock(state_parameters_.principal_points.data(), state_parameters_.principal_points.data(),
192  covariances.principal_points.data());
193  covariances.distortion = Eigen::MatrixXd(state_parameters_.distortion.size(), state_parameters_.distortion.size());
194  covariance.GetCovarianceBlock(state_parameters_.distortion.data(), state_parameters_.distortion.data(),
195  covariances.distortion.data());
196  return covariances;
197 }
198 
199 template <typename DISTORTER>
200 void CameraTargetBasedIntrinsicsCalibrator<DISTORTER>::AddCameraTTargetParameter(
201  const Eigen::Isometry3d& camera_T_target) {
202  state_parameters_.AddCameraTTarget(camera_T_target);
203  optimization_common::AddParameterBlock(6, state_parameters_.camera_T_targets.back().data(), problem_,
204  !params_.calibrate_target_poses);
205  ceres::LocalParameterization* se3_local_parameterization = new optimization_common::SE3LocalParameterization;
206  problem_.SetParameterization(state_parameters_.camera_T_targets.back().data(), se3_local_parameterization);
207 }
208 
209 template <typename DISTORTER>
210 double CameraTargetBasedIntrinsicsCalibrator<DISTORTER>::RadialScaleFactor(const Eigen::Vector2d& image_point,
211  const Eigen::Vector2i& image_size) const {
212  if (!params_.scale_loss_radially) return 1.0;
213  const Eigen::Vector2d centered_image_point = image_point - image_size.cast<double>() / 2.0;
214  const double radius = centered_image_point.norm();
215  return std::pow(radius, params_.radial_scale_power);
216 }
217 
218 template <typename DISTORTER>
219 localization_common::ImageCorrespondences CameraTargetBasedIntrinsicsCalibrator<DISTORTER>::InlierMatches(
220  const localization_common::ImageCorrespondences& match_set, const std::vector<int>& inliers) const {
221  std::vector<Eigen::Vector2d> inlier_image_points;
222  std::vector<Eigen::Vector3d> inlier_points_3d;
223  for (const int inlier_index : inliers) {
224  inlier_image_points.emplace_back(match_set.image_points[inlier_index]);
225  inlier_points_3d.emplace_back(match_set.points_3d[inlier_index]);
226  }
227  return localization_common::ImageCorrespondences(inlier_image_points, inlier_points_3d);
228 }
229 
230 template <typename DISTORTER>
231 void CameraTargetBasedIntrinsicsCalibrator<DISTORTER>::SaveResults(const StateParameters& calibrated_state_parameters,
232  const std::vector<MatchSet>& match_sets) const {
233  if (!(params_.calibrate_target_poses && params_.optimization.verbose) && !params_.save_final_reprojection_image)
234  return;
235 
236  const auto calibrated_camera_T_targets = state_parameters_.OptimizedCameraTTargets();
237  if (params_.calibrate_target_poses && params_.optimization.verbose)
238  PrintCameraTTargetsStats(match_sets, calibrated_camera_T_targets);
239 
240  if (params_.save_final_reprojection_image) {
241  const Eigen::Matrix3d calibrated_intrinsics = optimization_common::Intrinsics(
242  calibrated_state_parameters.focal_lengths, calibrated_state_parameters.principal_points);
243  SaveReprojectionFromAllTargetsImage<DISTORTER>(calibrated_camera_T_targets, valid_correspondences_set_,
244  calibrated_intrinsics, calibrated_state_parameters.distortion,
245  params_.image_size, params_.max_visualization_error_norm);
246  }
247 }
248 } // namespace calibration
249 
250 #endif // CALIBRATION_CAMERA_TARGET_BASED_INTRINSICS_CALIBRATOR_H_
LogInfo
#define LogInfo(msg)
Definition: logger.h:41
calibration::CameraTargetBasedIntrinsicsCalibrator
Definition: camera_target_based_intrinsics_calibrator.h:44
node_adders::Covariance
gtsam::Matrix Covariance(const gtsam::SharedNoiseModel &robust_gaussian_noise)
Definition: utilities.cc:22
state_parameters.h
optimization_common::SE3LocalParameterization
ceres::AutoDiffLocalParameterization< SE3Plus, 6, 6 > SE3LocalParameterization
Definition: se3_local_parameterization.h:42
calibration::StateParametersCovariances
Definition: state_parameters.h:76
se3_local_parameterization.h
calibration::StateParameters::principal_points
Eigen::Vector2d principal_points
Definition: state_parameters.h:39
logger.h
calibration::CameraTargetBasedIntrinsicsCalibrator::params
const CameraTargetBasedIntrinsicsCalibratorParams & params()
Definition: camera_target_based_intrinsics_calibrator.h:57
calibration::CameraTargetBasedIntrinsicsCalibratorParams
Definition: camera_target_based_intrinsics_calibrator_params.h:31
LogError
#define LogError(msg)
Definition: logger.h:55
calibration::CameraTargetBasedIntrinsicsCalibrator::EstimateInitialTargetPosesAndCalibrate
bool EstimateInitialTargetPosesAndCalibrate(const std::vector< localization_common::ImageCorrespondences > &correspondences_set, const StateParameters &initial_state_parameters, StateParameters &calibrated_state_parameters, StateParametersCovariances &covariances)
Definition: camera_target_based_intrinsics_calibrator.h:76
calibration::CameraTargetBasedIntrinsicsCalibrator::Calibrate
bool Calibrate(const std::vector< MatchSet > &match_sets, const StateParameters &initial_state_parameters, StateParameters &calibrated_state_parameters, StateParametersCovariances &covariances)
Definition: camera_target_based_intrinsics_calibrator.h:109
utilities.h
calibration::StateParameters::focal_lengths
Eigen::Vector2d focal_lengths
Definition: state_parameters.h:38
localization_common::ImageCorrespondences
Definition: image_correspondences.h:26
pose_estimation.h
optimization_common::Intrinsics
Eigen::Matrix3d Intrinsics(const Eigen::Vector2d &focal_lengths, const Eigen::Vector2d &principal_points)
Definition: utilities.cc:45
localization_common::Isometry3d
Eigen::Isometry3d Isometry3d(const Eigen::Vector3d &translation, const RotationType &rotation)
Definition: utilities.h:226
optimization_common::AddParameterBlock
void AddParameterBlock(const int num_parameters, double *const parameters, ceres::Problem &problem, const bool set_constant=false)
Definition: utilities.cc:54
residuals.h
localization_common::ImageCorrespondences::size
size_t size() const
Definition: image_correspondences.h:36
calibration::StateParameters
Definition: state_parameters.h:31
localization_common::ImageCorrespondences::image_points
std::vector< Eigen::Vector2d > image_points
Definition: image_correspondences.h:38
camera_target_based_intrinsics_calibrator_params.h
utilities.h
eigen_vectors.h
calibration::CameraTargetBasedIntrinsicsCalibrator::CameraTargetBasedIntrinsicsCalibrator
CameraTargetBasedIntrinsicsCalibrator(const CameraTargetBasedIntrinsicsCalibratorParams &params)
Definition: camera_target_based_intrinsics_calibrator.h:46
optimization_common::ReprojectionError::AddCostFunction
static void AddCostFunction(const Eigen::Vector2d &image_point, const Eigen::Vector3d &point_3d, Eigen::Matrix< double, 6, 1 > &camera_T_target, Eigen::Vector2d &focal_lengths, Eigen::Vector2d &principal_points, Eigen::VectorXd &distortion, ceres::Problem &problem, const double scale_factor=1, const double huber_threshold=1.345)
Definition: residuals.h:201
calibration
Definition: camera_target_based_intrinsics_calibrator.h:42
calibration::OptimizationStateParameters
Definition: state_parameters.h:44
localization_common::ImageCorrespondences::points_3d
std::vector< Eigen::Vector3d > points_3d
Definition: image_correspondences.h:39
calibration::StateParameters::distortion
Eigen::VectorXd distortion
Definition: state_parameters.h:40
Calibrate
bool Calibrate(const ca::RunCalibratorParams &params, const std::vector< lc::ImageCorrespondences > &target_matches, const std::string &output_file)
Definition: run_camera_target_based_intrinsics_calibrator.cc:91
image_correspondences.h
match_set.h
calibration::PrintCameraTTargetsStats
void PrintCameraTTargetsStats(const std::vector< MatchSet > &match_sets, const std::vector< Eigen::Isometry3d > &optimized_camera_T_targets)
Definition: utilities.cc:30