Calibration Library 1.0.0
A C++ library for camera calibration and vision-related geometric transformations
Loading...
Searching...
No Matches
ceresutils.h
Go to the documentation of this file.
1
3#pragma once
4
5// std
6#include <cmath>
7#include <map>
8#include <optional>
9#include <thread>
10
11// eigen
12#include <Eigen/Core>
13
14// ceres
16#include "ceres/covariance.h"
17#include "ceres/solver.h"
18
19namespace calib {
20
21static const std::map<OptimizerType, ceres::LinearSolverType> optim_to_ceres = {
22 {OptimizerType::DEFAULT, ceres::SPARSE_NORMAL_CHOLESKY},
23 {OptimizerType::SPARSE_SCHUR, ceres::SPARSE_SCHUR},
24 {OptimizerType::DENSE_SCHUR, ceres::DENSE_SCHUR},
25 {OptimizerType::DENSE_QR, ceres::DENSE_QR}};
26
27inline void solve_problem(ceres::Problem& problem, const OptimOptions& opts, OptimResult* result) {
28 ceres::Solver::Options copts;
29 copts.linear_solver_type = optim_to_ceres.at(opts.optimizer);
30 copts.num_threads = static_cast<int>(std::max(1U, std::thread::hardware_concurrency()));
31 copts.minimizer_progress_to_stdout = opts.verbose;
32 copts.function_tolerance = opts.epsilon;
33 copts.gradient_tolerance = opts.epsilon;
34 copts.parameter_tolerance = opts.epsilon;
35 copts.max_num_iterations = opts.max_iterations;
36
37 ceres::Solver::Summary summary;
38 ceres::Solve(copts, &problem, &summary);
39
40 result->final_cost = summary.final_cost;
41 result->report = summary.BriefReport();
42 result->success = summary.termination_type == ceres::CONVERGENCE;
43}
44
45struct ParamBlock final {
46 const double* data;
47 size_t size;
48 size_t dof;
49
50 // NOLINTNEXTLINE(bugprone-easily-swappable-parameters)
51 ParamBlock(const double* data_ptr, size_t block_size, size_t block_dof)
52 : data(data_ptr), size(block_size), dof(block_dof) {}
53};
54
56 [[nodiscard]]
57 virtual auto get_param_blocks() const -> std::vector<ParamBlock> = 0;
58
59 [[nodiscard]]
60 auto total_params() const -> size_t {
61 const auto blocks = get_param_blocks();
62 return std::accumulate(
63 blocks.begin(), blocks.end(), size_t{0},
64 [](size_t sum, const ParamBlock& block) { return sum + block.size; });
65 }
66};
67
68// Compute and populate the covariance matrix
69inline auto compute_covariance(const ProblemParamBlocks& problem_param_blocks,
70 ceres::Problem& problem, double sum_squared_residuals = 0,
71 size_t total_residuals = 0)
72 -> std::optional<Eigen::MatrixXd> { // NOLINT(bugprone-easily-swappable-parameters)
73 auto param_blocks = problem_param_blocks.get_param_blocks();
74 const size_t total_params = problem_param_blocks.total_params();
75
76 ceres::Covariance::Options cov_options;
77 ceres::Covariance covariance(cov_options);
78 std::vector<std::pair<const double*, const double*>> cov_blocks;
79
80 for (size_t block_i = 0; block_i < param_blocks.size(); ++block_i) {
81 for (size_t block_j = 0; block_j <= block_i; ++block_j) {
82 cov_blocks.emplace_back(param_blocks[block_i].data, param_blocks[block_j].data);
83 }
84 }
85
86 if (!covariance.Compute(cov_blocks, &problem)) {
87 return std::nullopt;
88 }
89
90 Eigen::MatrixXd cov_matrix = Eigen::MatrixXd::Zero(static_cast<Eigen::Index>(total_params),
91 static_cast<Eigen::Index>(total_params));
92 size_t row_offset = 0;
93 for (size_t block_i = 0; block_i < param_blocks.size(); ++block_i) {
94 size_t block_i_size = param_blocks[block_i].size;
95 size_t col_offset = 0;
96 for (size_t block_j = 0; block_j <= block_i; ++block_j) {
97 size_t block_j_size = param_blocks[block_j].size;
98 std::vector<double> block_cov(block_i_size * block_j_size);
99 covariance.GetCovarianceBlock(param_blocks[block_i].data, param_blocks[block_j].data,
100 block_cov.data());
101 for (size_t row_idx = 0; row_idx < block_i_size; ++row_idx) {
102 for (size_t col_idx = 0; col_idx < block_j_size; ++col_idx) {
103 double value = block_cov[row_idx * block_j_size + col_idx];
104 cov_matrix(static_cast<Eigen::Index>(row_offset + row_idx),
105 static_cast<Eigen::Index>(col_offset + col_idx)) = value;
106 if (block_j < block_i) {
107 cov_matrix(static_cast<Eigen::Index>(col_offset + col_idx),
108 static_cast<Eigen::Index>(row_offset + row_idx)) = value;
109 }
110 }
111 }
112 col_offset += block_j_size;
113 }
114 row_offset += block_i_size;
115 }
116
117 if (total_residuals > 0) {
118 // Scale covariance by variance factor
119 int degrees_of_freedom =
120 std::max(1, static_cast<int>(total_residuals) - static_cast<int>(total_params));
121 double variance_factor = sum_squared_residuals / degrees_of_freedom;
122 cov_matrix *= variance_factor;
123 }
124
125 return cov_matrix;
126}
127
128} // namespace calib
nlohmann::json summary
Linear multi-camera extrinsics initialisation (DLT)
static const std::map< OptimizerType, ceres::LinearSolverType > optim_to_ceres
Definition ceresutils.h:21
auto compute_covariance(const ProblemParamBlocks &problem_param_blocks, ceres::Problem &problem, double sum_squared_residuals=0, size_t total_residuals=0) -> std::optional< Eigen::MatrixXd >
Definition ceresutils.h:69
void solve_problem(ceres::Problem &problem, const OptimOptions &opts, OptimResult *result)
Definition ceresutils.h:27
std::string report
Definition optimize.h:38
ParamBlock(const double *data_ptr, size_t block_size, size_t block_dof)
Definition ceresutils.h:51
const double * data
Definition ceresutils.h:46
virtual auto get_param_blocks() const -> std::vector< ParamBlock >=0
auto total_params() const -> size_t
Definition ceresutils.h:60