19template <camera_model CameraT>
25 std::vector<std::array<double, 3>>
g_tra_c;
26 std::vector<std::array<double, k_intr_size>>
intr;
35 static auto create(
const std::vector<CameraT>& cameras,
36 const std::vector<Eigen::Isometry3d>& g_se3_c,
38 const size_t num_cams = g_se3_c.size();
41 for (
size_t idx = 0; idx < num_cams; ++idx) {
50 std::vector<ParamBlock> blocks;
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);
57 [](
const auto& quat_block) {
58 return ParamBlock(quat_block.data(), quat_block.size(),
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);
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) {
83template <camera_model CameraT>
84static auto build_problem(
const std::vector<BundleObservation>& observations,
87 ceres::Problem problem;
88 for (
const auto& obs : observations) {
89 const size_t cam_idx = obs.camera_index;
91 opts.core.huber_delta > 0 ?
new ceres::HuberLoss(opts.core.huber_delta) :
nullptr;
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());
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());
103 if (!opts.optimize_target_pose) {
104 problem.SetParameterBlockConstant(blocks.b_quat_t.data());
105 problem.SetParameterBlockConstant(blocks.b_tra_t.data());
107 if (!opts.optimize_hand_eye) {
108 for (
auto& quat_block : blocks.g_quat_c) {
109 problem.SetParameterBlockConstant(quat_block.data());
111 for (
auto& tran_block : blocks.g_tra_c) {
112 problem.SetParameterBlockConstant(tran_block.data());
115 if (!opts.optimize_intrinsics) {
116 for (
auto& intr_block : blocks.intr) {
117 problem.SetParameterBlockConstant(intr_block.data());
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(),
135template <camera_model CameraT>
137 const std::vector<CameraT>& initial_cameras) {
138 const size_t num_cams = initial_cameras.size();
140 throw std::invalid_argument(
"No camera intrinsics provided");
142 if (observations.empty()) {
143 throw std::invalid_argument(
"No observations provided");
147template <camera_model CameraT>
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,
156 ceres::Problem problem =
build_problem(observations, opts, blocks);
161 blocks.populate_results(result);
162 if (opts.
core.compute_covariance) {
164 if (optcov.has_value()) {
174 const std::vector<Eigen::Isometry3d>&,
const Eigen::Isometry3d&,
const BundleOptions&);
177 const std::vector<BundleObservation>&,
179 const std::vector<Eigen::Isometry3d>&,
const Eigen::Isometry3d&,
const BundleOptions&);
Pinhole camera model with intrinsics and distortion correction.
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)
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 >
static auto build_problem(const std::vector< BundleObservation > &observations, const BundleOptions &opts, BundleBlocks< CameraT > &blocks) -> ceres::Problem
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.
void solve_problem(ceres::Problem &problem, const OptimOptions &opts, OptimResult *result)
Pinhole camera model with intrinsics and distortion.
std::array< double, 3 > b_tra_t
std::vector< std::array< double, k_intr_size > > intr
std::vector< std::array< double, 3 > > g_tra_c
BundleBlocks(size_t numcams)
static auto create(const std::vector< CameraT > &cameras, const std::vector< Eigen::Isometry3d > &g_se3_c, const Eigen::Isometry3d &b_se3_t) -> BundleBlocks
auto get_param_blocks() const -> std::vector< ParamBlock > override
void populate_results(BundleResult< CameraT > &result) const
static constexpr size_t k_intr_size
std::vector< std::array< double, 4 > > g_quat_c
std::array< double, 4 > b_quat_t
Options controlling the hand-eye calibration optimisation.
OptimOptions core
Non-linear optimization options.
Result returned by hand-eye calibration.
OptimResult core
Optimization result details.
std::vector< Eigen::Isometry3d > g_se3_c
Estimated camera->gripper extrinsics.
Eigen::Isometry3d b_se3_t
Pose of target in base frame.
std::vector< CameraT > cameras
Estimated camera parameters per camera.
Type traits template for camera model implementations.
Eigen::MatrixXd covariance
Camera model with a tilted sensor plane (Scheimpflug configuration).