Calibration Library 1.0.0
A C++ library for camera calibration and vision-related geometric transformations
Loading...
Searching...
No Matches
planarpose.cpp
Go to the documentation of this file.
2
3// std
4#include <algorithm>
5#include <array>
6#include <numeric>
7
8// ceres
9#include <ceres/ceres.h>
10#include <ceres/rotation.h>
11
14#include "detail/ceresutils.h"
16
17namespace calib {
18
19using Pose6 = Eigen::Matrix<double, 6, 1>;
20
21struct PlanarPoseBlocks final : public ProblemParamBlocks {
22 std::array<double, 6> pose6;
23 [[nodiscard]] std::vector<ParamBlock> get_param_blocks() const override {
24 return {{pose6.data(), pose6.size(), 6}};
25 }
26};
27
28// Residual functor used with AutoDiffCostFunction for planar pose
29// estimation. For a given pose (angle-axis + translation) it builds the
30// variable projection system to eliminate distortion coefficients.
35
36 PlanarPoseVPResidual(PlanarView obs, int num_radial, CameraMatrix intrinsics)
37 : obs_(std::move(obs)), intrinsics_(intrinsics), num_radial_(num_radial) {}
38
39 template <typename T>
40 bool operator()(const T* pose6, T* residuals) const {
41 const CameraMatrixT<T> intrinsics{T(intrinsics_.fx), T(intrinsics_.fy), T(intrinsics_.cx),
43
44 std::vector<Observation<T>> o(obs_.size());
45 std::transform(obs_.begin(), obs_.end(), o.begin(),
46 [pose6](const PlanarObservation& s) { return to_observation(s, pose6); });
47
48 auto dr = fit_distortion_full(o, intrinsics, num_radial_);
49 if (!dr) {
50 return false;
51 }
52 const auto& r = dr->residuals;
53 for (int i = 0; i < r.size(); ++i) {
54 residuals[i] = r[i];
55 }
56 return true;
57 }
58
59 // Helper used after optimization to compute best distortion coefficients.
60 [[nodiscard]] Eigen::VectorXd solve_distortion_for(const Pose6& pose6) const {
61 std::vector<Observation<double>> o(obs_.size());
62 std::transform(obs_.begin(), obs_.end(), o.begin(), [pose6](const PlanarObservation& s) {
63 return to_observation(s, pose6.data());
64 });
65
68 auto d = fit_distortion(o, intrinsics, num_radial_);
69 return d ? d->distortion : Eigen::VectorXd{};
70 }
71};
72
73static auto axisangle_to_pose(const Pose6& pose6) -> Eigen::Isometry3d {
74 Eigen::Matrix3d rotation_matrix;
75 ceres::AngleAxisToRotationMatrix(pose6.head<3>().data(), rotation_matrix.data());
76
77 Eigen::Isometry3d transform = Eigen::Isometry3d::Identity();
78 transform.linear() = rotation_matrix;
79 transform.translation() = pose6.tail<3>();
80
81 return transform;
82}
83
84auto optimize_planar_pose(const PlanarView& view, const CameraMatrix& intrinsics,
85 const Eigen::Isometry3d& init_pose, const PlanarPoseOptions& opts)
87 PlanarPoseResult result;
88 PlanarPoseBlocks blocks;
89 ceres::RotationMatrixToAngleAxis(reinterpret_cast<const double*>(init_pose.rotation().data()),
90 blocks.pose6.data());
91 blocks.pose6[3] = init_pose.translation().x();
92 blocks.pose6[4] = init_pose.translation().y();
93 blocks.pose6[5] = init_pose.translation().z();
94
95 auto* functor = new PlanarPoseVPResidual(view, opts.num_radial, intrinsics);
96 auto* cost = new ceres::AutoDiffCostFunction<PlanarPoseVPResidual, ceres::DYNAMIC, 6>(
97 functor, static_cast<int>(view.size()) * 2);
98
99 ceres::Problem problem;
100 problem.AddResidualBlock(
101 cost, opts.core.huber_delta > 0 ? new ceres::HuberLoss(opts.core.huber_delta) : nullptr,
102 blocks.pose6.data());
103
104 solve_problem(problem, opts.core, &result.core);
105
106 // Compute residuals for statistics and covariance
107 const int m = static_cast<int>(view.size()) * 2;
108 std::vector<double> residuals(m);
109 const std::array<const double*, 1> parameter_blocks = {blocks.pose6.data()};
110 cost->Evaluate(parameter_blocks.data(), residuals.data(), nullptr);
111
112 const double ssr = std::accumulate(residuals.begin(), residuals.end(), 0.0,
113 [](double sum, double r) { return sum + r * r; });
114 result.reprojection_error = std::sqrt(ssr / m);
115
116 if (opts.core.compute_covariance) {
117 auto optcov = compute_covariance(blocks, problem, ssr, residuals.size());
118 if (optcov.has_value()) {
119 result.core.covariance = std::move(optcov.value());
120 }
121 }
122
123 result.pose = axisangle_to_pose(Eigen::Map<const Pose6>(blocks.pose6.data()));
124 result.distortion = functor->solve_distortion_for(Eigen::Map<const Pose6>(blocks.pose6.data()));
125
126 return result;
127}
128
129} // namespace calib
Lens distortion models and correction algorithms.
Linear multi-camera extrinsics initialisation (DLT)
auto fit_distortion(const std::vector< Observation< T > > &observations, const CameraMatrixT< T > &intrinsics, int num_radial=2, std::span< const int > fixed_indices={}, std::span< const T > fixed_values={}) -> std::optional< DistortionWithResiduals< T > >
Definition distortion.h:366
auto optimize_planar_pose(const PlanarView &view, const CameraMatrix &intrinsics, const Eigen::Isometry3d &init_pose, const PlanarPoseOptions &opts={}) -> PlanarPoseResult
static auto axisangle_to_pose(const Pose6 &pose6) -> Eigen::Isometry3d
std::vector< PlanarObservation > PlanarView
Definition planarpose.h:26
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
Eigen::Matrix< double, 6, 1 > Pose6
auto fit_distortion_full(const std::vector< Observation< T > > &observations, const CameraMatrixT< T > &intrinsics, int num_radial=2, std::span< const int > fixed_indices={}, std::span< const T > fixed_values={}) -> std::optional< DistortionWithResiduals< T > >
Definition distortion.h:231
void solve_problem(ceres::Problem &problem, const OptimOptions &opts, OptimResult *result)
Definition ceresutils.h:27
Eigen::MatrixXd covariance
Definition optimize.h:37
std::vector< ParamBlock > get_param_blocks() const override
std::array< double, 6 > pose6
Eigen::Isometry3d pose
Estimated pose of the plane.
Definition planarpose.h:19
OptimResult core
Core optimization result.
Definition planarpose.h:18
Eigen::VectorXd distortion
Estimated distortion coefficients.
Definition planarpose.h:20
double reprojection_error
RMS reprojection error.
Definition planarpose.h:21
Eigen::VectorXd solve_distortion_for(const Pose6 &pose6) const
PlanarPoseVPResidual(PlanarView obs, int num_radial, CameraMatrix intrinsics)
bool operator()(const T *pose6, T *residuals) const
const CameraMatrix intrinsics_