Calibration Library 1.0.0
A C++ library for camera calibration and vision-related geometric transformations
Loading...
Searching...
No Matches
bundle.cpp
Go to the documentation of this file.
2
3// std
4#include <algorithm>
5#include <array>
6#include <iterator>
7#include <numeric>
8
13#include "detail/ceresutils.h"
16
17namespace calib {
18
19template <camera_model CameraT>
20struct BundleBlocks final : public ProblemParamBlocks {
22 std::array<double, 4> b_quat_t;
23 std::array<double, 3> b_tra_t;
24 std::vector<std::array<double, 4>> g_quat_c;
25 std::vector<std::array<double, 3>> g_tra_c;
26 std::vector<std::array<double, k_intr_size>> intr;
27
28 explicit BundleBlocks(size_t numcams)
29 : b_quat_t{0.0, 0.0, 0.0, 1.0},
30 b_tra_t{0.0, 0.0, 0.0},
31 g_quat_c(numcams),
32 g_tra_c(numcams),
33 intr(numcams) {}
34
35 static auto create(const std::vector<CameraT>& cameras,
36 const std::vector<Eigen::Isometry3d>& g_se3_c,
37 const Eigen::Isometry3d& b_se3_t) -> BundleBlocks {
38 const size_t num_cams = g_se3_c.size();
39 BundleBlocks blocks(num_cams);
40 populate_quat_tran(b_se3_t, blocks.b_quat_t, blocks.b_tra_t);
41 for (size_t idx = 0; idx < num_cams; ++idx) {
42 populate_quat_tran(g_se3_c[idx], blocks.g_quat_c[idx], blocks.g_tra_c[idx]);
43 CameraTraits<CameraT>::to_array(cameras[idx], blocks.intr[idx]);
44 }
45 return blocks;
46 }
47
48 [[nodiscard]]
49 auto get_param_blocks() const -> std::vector<ParamBlock> override {
50 std::vector<ParamBlock> blocks;
51 blocks.reserve(intr.size() + g_quat_c.size() + g_tra_c.size() + 2U);
52 std::transform(intr.begin(), intr.end(), std::back_inserter(blocks),
53 [](const auto& intr_block) {
54 return ParamBlock(intr_block.data(), intr_block.size(), k_intr_size);
55 });
56 std::transform(g_quat_c.begin(), g_quat_c.end(), std::back_inserter(blocks),
57 [](const auto& quat_block) {
58 return ParamBlock(quat_block.data(), quat_block.size(),
59 3); // 3 dof in unit quaternion
60 });
61 std::transform(g_tra_c.begin(), g_tra_c.end(), std::back_inserter(blocks),
62 [](const auto& tran_block) {
63 return ParamBlock(tran_block.data(), tran_block.size(), 3);
64 });
65 blocks.emplace_back(b_quat_t.data(), b_quat_t.size(), 3); // 3 dof in unit quaternion
66 blocks.emplace_back(b_tra_t.data(), b_tra_t.size(), 3);
67 return blocks;
68 }
69
72 const size_t num_cams = intr.size();
73 result.g_se3_c.resize(num_cams);
74 result.cameras.resize(num_cams);
75 for (size_t cam_idx = 0; cam_idx < num_cams; ++cam_idx) {
76 result.g_se3_c[cam_idx] = restore_pose(g_quat_c[cam_idx], g_tra_c[cam_idx]);
77 result.cameras[cam_idx] =
78 CameraTraits<CameraT>::template from_array<double>(intr[cam_idx].data());
79 }
80 }
81};
82
83template <camera_model CameraT>
84static auto build_problem(const std::vector<BundleObservation>& observations,
85 const BundleOptions& opts, BundleBlocks<CameraT>& blocks)
86 -> ceres::Problem {
87 ceres::Problem problem;
88 for (const auto& obs : observations) {
89 const size_t cam_idx = obs.camera_index;
90 auto* loss =
91 opts.core.huber_delta > 0 ? new ceres::HuberLoss(opts.core.huber_delta) : nullptr;
92 problem.AddResidualBlock(BundleReprojResidual<CameraT>::create(obs.view, obs.b_se3_g), loss,
93 blocks.b_quat_t.data(), blocks.b_tra_t.data(),
94 blocks.g_quat_c[cam_idx].data(), blocks.g_tra_c[cam_idx].data(),
95 blocks.intr[cam_idx].data());
96 }
97
98 problem.SetManifold(blocks.b_quat_t.data(), new ceres::QuaternionManifold());
99 for (size_t cam_idx = 0; cam_idx < blocks.g_quat_c.size(); ++cam_idx) {
100 problem.SetManifold(blocks.g_quat_c[cam_idx].data(), new ceres::QuaternionManifold());
101 }
102
103 if (!opts.optimize_target_pose) {
104 problem.SetParameterBlockConstant(blocks.b_quat_t.data());
105 problem.SetParameterBlockConstant(blocks.b_tra_t.data());
106 }
107 if (!opts.optimize_hand_eye) {
108 for (auto& quat_block : blocks.g_quat_c) {
109 problem.SetParameterBlockConstant(quat_block.data());
110 }
111 for (auto& tran_block : blocks.g_tra_c) {
112 problem.SetParameterBlockConstant(tran_block.data());
113 }
114 }
115 if (!opts.optimize_intrinsics) {
116 for (auto& intr_block : blocks.intr) {
117 problem.SetParameterBlockConstant(intr_block.data());
118 }
119 } else {
120 for (size_t cam_idx = 0; cam_idx < blocks.intr.size(); ++cam_idx) {
121 problem.SetParameterLowerBound(blocks.intr[cam_idx].data(),
123 problem.SetParameterLowerBound(blocks.intr[cam_idx].data(),
125 if (!opts.optimize_skew) {
126 problem.SetManifold(blocks.intr[cam_idx].data(),
127 new ceres::SubsetManifold(BundleBlocks<CameraT>::k_intr_size,
129 }
130 }
131 }
132 return problem;
133}
134
135template <camera_model CameraT>
136void validate_input(const std::vector<BundleObservation>& observations,
137 const std::vector<CameraT>& initial_cameras) {
138 const size_t num_cams = initial_cameras.size();
139 if (num_cams == 0) {
140 throw std::invalid_argument("No camera intrinsics provided");
141 }
142 if (observations.empty()) {
143 throw std::invalid_argument("No observations provided");
144 }
145}
146
147template <camera_model CameraT>
148BundleResult<CameraT> optimize_bundle(const std::vector<BundleObservation>& observations,
149 const std::vector<CameraT>& initial_cameras,
150 const std::vector<Eigen::Isometry3d>& init_g_se3_c,
151 const Eigen::Isometry3d& init_b_se3_t,
152 const BundleOptions& opts) {
153 validate_input(observations, initial_cameras);
154
155 auto blocks = BundleBlocks<CameraT>::create(initial_cameras, init_g_se3_c, init_b_se3_t);
156 ceres::Problem problem = build_problem(observations, opts, blocks);
157
159 solve_problem(problem, opts.core, &result.core);
160
161 blocks.populate_results(result);
162 if (opts.core.compute_covariance) {
163 auto optcov = compute_covariance(blocks, problem);
164 if (optcov.has_value()) {
165 result.core.covariance = std::move(optcov.value());
166 }
167 }
168
169 return result;
170}
171
173 const std::vector<BundleObservation>&, const std::vector<PinholeCamera<BrownConradyd>>&,
174 const std::vector<Eigen::Isometry3d>&, const Eigen::Isometry3d&, const BundleOptions&);
175
177 const std::vector<BundleObservation>&,
179 const std::vector<Eigen::Isometry3d>&, const Eigen::Isometry3d&, const BundleOptions&);
180
181} // namespace calib
Pinhole camera model with intrinsics and distortion correction.
Definition pinhole.h:39
Lens distortion models and correction algorithms.
Linear multi-camera extrinsics initialisation (DLT)
void populate_quat_tran(const Eigen::Isometry3d &pose, std::array< double, 4 > &quat, std::array< double, 3 > &translation)
void validate_input(const std::vector< BundleObservation > &observations, const std::vector< CameraT > &initial_cameras)
Definition bundle.cpp:136
Eigen::Isometry3d restore_pose(const std::array< double, 4 > &quat, const std::array< double, 3 > &translation)
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
static auto build_problem(const std::vector< BundleObservation > &observations, const BundleOptions &opts, BundleBlocks< CameraT > &blocks) -> ceres::Problem
Definition bundle.cpp:84
auto optimize_bundle(const std::vector< BundleObservation > &observations, const std::vector< CameraT > &initial_cameras, const std::vector< Eigen::Isometry3d > &init_g_se3_c, const Eigen::Isometry3d &init_b_se3_t, const BundleOptions &opts={}) -> BundleResult< CameraT >
Perform bundle-adjustment style optimisation of the hand-eye calibration problem.
Definition bundle.cpp:148
void solve_problem(ceres::Problem &problem, const OptimOptions &opts, OptimResult *result)
Definition ceresutils.h:27
Pinhole camera model with intrinsics and distortion.
std::array< double, 3 > b_tra_t
Definition bundle.cpp:23
std::vector< std::array< double, k_intr_size > > intr
Definition bundle.cpp:26
std::vector< std::array< double, 3 > > g_tra_c
Definition bundle.cpp:25
BundleBlocks(size_t numcams)
Definition bundle.cpp:28
static auto create(const std::vector< CameraT > &cameras, const std::vector< Eigen::Isometry3d > &g_se3_c, const Eigen::Isometry3d &b_se3_t) -> BundleBlocks
Definition bundle.cpp:35
auto get_param_blocks() const -> std::vector< ParamBlock > override
Definition bundle.cpp:49
void populate_results(BundleResult< CameraT > &result) const
Definition bundle.cpp:70
static constexpr size_t k_intr_size
Definition bundle.cpp:21
std::vector< std::array< double, 4 > > g_quat_c
Definition bundle.cpp:24
std::array< double, 4 > b_quat_t
Definition bundle.cpp:22
Options controlling the hand-eye calibration optimisation.
Definition bundle.h:30
OptimOptions core
Non-linear optimization options.
Definition bundle.h:31
Result returned by hand-eye calibration.
Definition bundle.h:40
OptimResult core
Optimization result details.
Definition bundle.h:41
std::vector< Eigen::Isometry3d > g_se3_c
Estimated camera->gripper extrinsics.
Definition bundle.h:43
Eigen::Isometry3d b_se3_t
Pose of target in base frame.
Definition bundle.h:44
std::vector< CameraT > cameras
Estimated camera parameters per camera.
Definition bundle.h:42
Type traits template for camera model implementations.
Definition cameramodel.h:64
Eigen::MatrixXd covariance
Definition optimize.h:37
Camera model with a tilted sensor plane (Scheimpflug configuration).
Definition scheimpflug.h:35