9#include <ceres/ceres.h>
18 std::array<double, 4>
quat;
19 std::array<double, 3>
tran;
23 Eigen::Quaterniond quat_init(init_pose.linear());
24 blocks.
quat = {quat_init.w(), quat_init.x(), quat_init.y(), quat_init.z()};
25 blocks.
tran = {init_pose.translation().x(), init_pose.translation().y(),
26 init_pose.translation().z()};
37 quat_final.normalize();
38 Eigen::Isometry3d pose = Eigen::Isometry3d::Identity();
39 pose.linear() = quat_final.toRotationMatrix();
40 pose.translation() = Eigen::Vector3d(
tran[0],
tran[1],
tran[2]);
45static auto build_problem(
const std::vector<MotionPair>& pairs,
const OptimOptions& opts,
47 ceres::Problem problem;
48 for (
const auto& motion_pair : pairs) {
50 ceres::LossFunction* loss =
52 ?
static_cast<ceres::LossFunction*
>(
new ceres::HuberLoss(opts.huber_delta))
54 problem.AddResidualBlock(cost, loss, blocks.quat.data(), blocks.tran.data());
56 problem.SetManifold(blocks.quat.data(),
new ceres::QuaternionManifold());
61 const std::vector<Eigen::Isometry3d>& camera_se3_target,
62 const Eigen::Isometry3d& init_gripper_se3_ref,
const OptimOptions& options)
64 constexpr double k_min_angle_deg = 0.5;
65 auto pairs =
build_all_pairs(base_se3_gripper, camera_se3_target, k_min_angle_deg);
67 ceres::Problem problem =
build_problem(pairs, options, blocks);
70 blocks.populate_result(result);
71 if (options.compute_covariance) {
73 if (optcov.has_value()) {
81 const std::vector<Eigen::Isometry3d>& camera_se3_target,
82 double min_angle_deg,
const OptimOptions& options)
84 Eigen::Isometry3d init_pose =
86 return optimize_handeye(base_se3_gripper, camera_se3_target, init_pose, options);
Hand-eye calibration algorithms and utilities.
Linear multi-camera extrinsics initialisation (DLT)
auto optimize_handeye(const std::vector< Eigen::Isometry3d > &base_se3_gripper, const std::vector< Eigen::Isometry3d > &camera_se3_target, const Eigen::Isometry3d &init_gripper_se3_ref, const OptimOptions &options={}) -> HandeyeResult
Refines the hand-eye calibration transformation using an optimization process.
auto estimate_and_optimize_handeye(const std::vector< Eigen::Isometry3d > &base_se3_gripper, const std::vector< Eigen::Isometry3d > &camera_se3_target, double min_angle_deg=1.0, const OptimOptions &options={}) -> HandeyeResult
Estimates and refines the hand-eye transformation.
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 >
auto estimate_handeye_dlt(const std::vector< Eigen::Isometry3d > &base_se3_gripper, const std::vector< Eigen::Isometry3d > &camera_se3_target, double min_angle_deg=1.0) -> Eigen::Isometry3d
Estimates the hand-eye transformation using the Tsai-Lenz algorithm with all pairs of input transform...
static auto build_problem(const std::vector< BundleObservation > &observations, const BundleOptions &opts, BundleBlocks< CameraT > &blocks) -> ceres::Problem
auto build_all_pairs(const std::vector< Eigen::Isometry3d > &base_se3_gripper, const std::vector< Eigen::Isometry3d > &cam_se3_target, double min_angle_deg=1.0, bool reject_axis_parallel=true, double axis_parallel_eps=1e-3) -> std::vector< MotionPair >
Generate all valid motion pairs from pose sequences.
void solve_problem(ceres::Problem &problem, const OptimOptions &opts, OptimResult *result)
static auto create(const MotionPair &mp)
auto get_param_blocks() const -> std::vector< ParamBlock > override
static auto create(const Eigen::Isometry3d &init_pose) -> HandeyeBlocks
void populate_result(HandeyeResult &result) const
std::array< double, 4 > quat
std::array< double, 3 > tran
Eigen::Isometry3d g_se3_c
Estimated hand-eye transform (gripper -> camera)
OptimResult core
Core optimization result.
Eigen::MatrixXd covariance