4#include <Eigen/Geometry>
8#include <unordered_map>
20[[nodiscard]]
auto build_point_lookup(
const PlanarDetections&
detections)
21 -> std::unordered_map<std::string, const PlanarImageDetections*> {
22 std::unordered_map<std::string, const PlanarImageDetections*> lookup;
24 lookup.emplace(image.file, &image);
29[[nodiscard]]
auto to_dual_camera(
const PinholeCamera<BrownConradyd>&
cam)
30 -> PinholeCamera<DualDistortion> {
34 return PinholeCamera<DualDistortion>(
cam.kmtx, dual);
43 -> std::vector<MulticamPlanarView> {
44 const auto reference_lookup = build_point_lookup(reference_detections);
45 const auto target_lookup = build_point_lookup(target_detections);
47 std::vector<MulticamPlanarView> views;
48 views.reserve(cfg.views.size());
50 for (
const auto& view_cfg : cfg.views) {
53 summary.target_image = view_cfg.target_image;
55 const auto ref_it = reference_lookup.find(view_cfg.reference_image);
56 const auto tgt_it = target_lookup.find(view_cfg.target_image);
58 if (ref_it == reference_lookup.end()) {
59 summary.status =
"missing_reference_image";
60 result.view_summaries.push_back(std::move(
summary));
63 if (tgt_it == target_lookup.end()) {
64 summary.status =
"missing_target_image";
65 result.view_summaries.push_back(std::move(
summary));
69 auto reference_view = make_planar_view(*ref_it->second);
70 auto target_view = make_planar_view(*tgt_it->second);
71 summary.reference_points = reference_view.size();
72 summary.target_points = target_view.size();
74 if (reference_view.size() < 4U || target_view.size() < 4U) {
75 summary.status =
"insufficient_points";
76 result.view_summaries.push_back(std::move(
summary));
81 multi_view.push_back(std::move(reference_view));
82 multi_view.push_back(std::move(target_view));
83 views.push_back(std::move(multi_view));
85 result.view_summaries.push_back(std::move(
summary));
100 if (reference_intrinsics.refine_result.camera.distortion.coeffs.size() == 0 ||
101 target_intrinsics.refine_result.camera.distortion.coeffs.size() == 0) {
102 throw std::runtime_error(
"StereoCalibrationFacade: camera intrinsics are not available.");
105 const auto views =
compute_views(cfg, reference_detections, target_detections, result);
114 std::vector<PinholeCamera<BrownConradyd>> init_cameras = {
115 reference_intrinsics.refine_result.camera, target_intrinsics.refine_result.camera};
117 std::vector<PinholeCamera<DualDistortion>> dlt_cameras;
118 dlt_cameras.reserve(init_cameras.size());
119 std::transform(init_cameras.begin(), init_cameras.end(), std::back_inserter(dlt_cameras),
120 [](
const auto&
cam) { return to_dual_camera(cam); });
135 const std::unordered_map<std::string, PlanarDetections>& dets)
136 -> std::vector<MulticamPlanarView> {
138 std::unordered_map<std::string, std::unordered_map<std::string, const PlanarImageDetections*>>
140 for (
const auto& [sid, d] : dets) {
141 std::unordered_map<std::string, const PlanarImageDetections*> map;
142 for (
const auto& img : d.images) map.emplace(img.file, &img);
143 lookup.emplace(sid, std::move(map));
146 std::vector<MulticamPlanarView> views;
147 views.reserve(cfg.views.size());
148 for (
const auto& view_sel : cfg.views) {
150 multi.resize(cfg.sensors.size());
152 for (std::size_t i = 0; i < cfg.sensors.size(); ++i) {
153 const auto& sid = cfg.sensors[i];
154 auto img_it = view_sel.images.find(sid);
155 if (img_it == view_sel.images.end()) {
159 auto det_cam_it = dets.find(sid);
160 if (det_cam_it == dets.end()) {
164 const auto& img_lookup = lookup.at(sid);
165 auto img_det_it = img_lookup.find(img_it->second);
166 if (img_det_it == img_lookup.end()) {
170 auto view = make_planar_view(*img_det_it->second);
171 if (view.size() < 4U) {
175 multi[i] = std::move(view);
178 views.push_back(std::move(multi));
186 const std::unordered_map<std::string, PlanarDetections>& detections_by_sensor,
187 const std::unordered_map<std::string, IntrinsicCalibrationOutputs>& intrinsics_by_sensor)
const
194 for (
const auto& sid : cfg.sensors) {
195 auto it = intrinsics_by_sensor.find(sid);
196 if (it == intrinsics_by_sensor.end() ||
197 it->second.refine_result.camera.distortion.coeffs.size() == 0) {
198 throw std::runtime_error(
199 "MultiCameraCalibrationFacade: intrinsics not available for sensor: " + sid);
211 std::vector<PinholeCamera<BrownConradyd>> init_cameras(cfg.sensors.size());
212 std::transform(cfg.sensors.begin(), cfg.sensors.end(), init_cameras.begin(),
213 [&intrinsics_by_sensor](
const auto& sid) {
214 return intrinsics_by_sensor.at(sid).refine_result.camera;
217 std::vector<PinholeCamera<DualDistortion>> dlt_cameras;
218 dlt_cameras.reserve(init_cameras.size());
219 std::transform(init_cameras.begin(), init_cameras.end(), std::back_inserter(dlt_cameras),
220 [](
const auto&
cam) { return to_dual_camera(cam); });
auto calibrate(const MultiCameraRigConfig &cfg, const std::unordered_map< std::string, PlanarDetections > &detections_by_sensor, const std::unordered_map< std::string, IntrinsicCalibrationOutputs > &intrinsics_by_sensor) const -> MultiCameraCalibrationRunResult
auto calibrate(const StereoPairConfig &cfg, const PlanarDetections &reference_detections, const PlanarDetections &target_detections, const IntrinsicCalibrationOutputs &reference_intrinsics, const IntrinsicCalibrationOutputs &target_intrinsics) const -> StereoCalibrationRunResult
Lens distortion models and correction algorithms.
std::vector< Eigen::Isometry3d > cam
PlanarDetections detections
auto make_planar_view(const PlanarImageDetections &detections) -> PlanarView
auto compute_views(const StereoPairConfig &cfg, const PlanarDetections &reference_detections, const PlanarDetections &target_detections, StereoCalibrationRunResult &result) -> std::vector< MulticamPlanarView >
std::vector< PlanarView > MulticamPlanarView
auto estimate_extrinsic_dlt(const std::vector< MulticamPlanarView > &views, const std::vector< CameraT > &cameras) -> ExtrinsicPoses
DualBrownConrady< double > DualDistortion
auto optimize_extrinsics(const std::vector< MulticamPlanarView > &views, const std::vector< CameraT > &init_cameras, const std::vector< Eigen::Isometry3d > &init_c_se3_r, const std::vector< Eigen::Isometry3d > &init_r_se3_t, const ExtrinsicOptions &opts={}) -> ExtrinsicOptimizationResult< CameraT >
auto invert_brown_conrady(const Eigen::Matrix< Scalar, Eigen::Dynamic, 1 > &forward) -> Eigen::Matrix< Scalar, Eigen::Dynamic, 1 >
Eigen::Matrix< Scalar, Eigen::Dynamic, 1 > forward
Coefficients for distortion.
bool optimize_intrinsics
Solve for camera intrinsics.
std::vector< Eigen::Isometry3d > c_se3_r
std::vector< Eigen::Isometry3d > r_se3_t
std::vector< std::string > sensors
ExtrinsicPoses initial_guess
ExtrinsicOptimizationResult< PinholeCamera< BrownConradyd > > optimization
std::size_t requested_views
ExtrinsicPoses initial_guess
std::size_t requested_views
ExtrinsicOptimizationResult< PinholeCamera< BrownConradyd > > optimization
std::string reference_image