Calibration Library 1.0.0
A C++ library for camera calibration and vision-related geometric transformations
Loading...
Searching...
No Matches
scheimpflug.h
Go to the documentation of this file.
1#pragma once
2
3// std
4#include <cmath>
5
6// eigen
7#include <ceres/ceres.h>
8
9#include <Eigen/Core>
10#include <Eigen/Geometry>
11#include <array>
12
15
16namespace calib {
17
18struct ScheimpflugAngles final {
19 double tau_x{0};
20 double tau_y{0};
21};
22
34template <camera_model CameraT>
35struct ScheimpflugCamera final {
36 using Scalar = typename CameraT::Scalar;
37 CameraT camera;
40
43
49 ScheimpflugCamera(const CameraT& cam, ScheimpflugAngles angles)
50 : camera(cam), tau_x(angles.tau_x), tau_y(angles.tau_y) {}
51
60 template <camera_model OtherCamT, typename T>
61 ScheimpflugCamera(OtherCamT cam, T tau_x_angle, T tau_y_angle)
62 : camera(std::move(cam)), tau_x(Scalar(tau_x_angle)), tau_y(Scalar(tau_y_angle)) {}
63
66 : camera(other.camera), tau_x(other.tau_x), tau_y(other.tau_y) {}
67
70 if (this != &other) {
71 camera = other.camera;
72 tau_x = other.tau_x;
73 tau_y = other.tau_y;
74 }
75 return *this;
76 }
77
80 : camera(std::move(other.camera)), tau_x(other.tau_x), tau_y(other.tau_y) {}
81
84 if (this != &other) {
85 camera = std::move(other.camera);
86 tau_x = other.tau_x;
87 tau_y = other.tau_y;
88 }
89 return *this;
90 }
91
103 template <typename T>
104 [[nodiscard]]
105 Eigen::Matrix<T, 2, 1> apply_intrinsics(const Eigen::Matrix<T, 2, 1>& plane_point) const {
106 return camera.template apply_intrinsics<T>(plane_point);
107 }
108
119 template <typename T>
120 [[nodiscard]]
121 Eigen::Matrix<T, 2, 1> remove_intrinsics(const Eigen::Matrix<T, 2, 1>& pixel) const {
122 return camera.template remove_intrinsics<T>(pixel);
123 }
124
139 template <typename T>
140 [[nodiscard]]
141 auto project(const Eigen::Matrix<T, 3, 1>& x_camera) const -> Eigen::Matrix<T, 2, 1> {
142 // Build rotation that aligns the tilted sensor basis
143 const T tau_x_val = T(tau_x);
144 const T tau_y_val = T(tau_y);
145 const T cos_tau_x = ceres::cos(tau_x_val);
146 const T sin_tau_x = ceres::sin(tau_x_val);
147 const T cos_tau_y = ceres::cos(tau_y_val);
148 const T sin_tau_y = ceres::sin(tau_y_val);
149
150 Eigen::Matrix<T, 3, 3> rot_sensor;
151 rot_sensor << cos_tau_y, sin_tau_x * sin_tau_y, cos_tau_x * sin_tau_y, T(0), cos_tau_x,
152 -sin_tau_x, -sin_tau_y, sin_tau_x * cos_tau_y, cos_tau_x * cos_tau_y;
153
154 // Basis vectors of the tilted sensor plane
155 Eigen::Matrix<T, 3, 1> axis_sensor = rot_sensor.col(0);
156 Eigen::Matrix<T, 3, 1> base_sensor = rot_sensor.col(1);
157 Eigen::Matrix<T, 3, 1> normal_sensor = rot_sensor.col(2);
158
159 // Ray-plane intersection (d=1)
160 T sden = normal_sensor.dot(x_camera);
161 T mx = axis_sensor.dot(x_camera) / sden;
162 T my = base_sensor.dot(x_camera) / sden;
163
164 // Principal ray intersection with the plane
165 const T s0 = normal_sensor.z();
166 const T mx0 = axis_sensor.z() / s0;
167 const T my0 = base_sensor.z() / s0;
168
169 // Distort only local delta in plane coords (about principal intersection)
170 Eigen::Matrix<T, 2, 1> dxy(mx - mx0, my - my0);
171
172 // Distort+intrinsics of the local delta via the base model:
173 Eigen::Matrix<T, 2, 1> px_delta =
174 camera.template project<T>(Eigen::Matrix<T, 3, 1>(dxy.x(), dxy.y(), T(1)));
175
176 // Linear shift from principal-ray intersection (no cx,cy inside):
177 Eigen::Matrix<T, 2, 1> base_shift =
178 CameraTraits<CameraT>::template apply_linear_intrinsics<T>(camera, {mx0, my0});
179
180 return px_delta + base_shift;
181 }
182
196 template <typename T>
197 [[nodiscard]]
198 auto unproject(const Eigen::Matrix<T, 2, 1>& pixel) const -> Eigen::Matrix<T, 2, 1> {
199 const T tau_x_val = T(tau_x);
200 const T tau_y_val = T(tau_y);
201 const T cos_tau_x = ceres::cos(tau_x_val);
202 const T sin_tau_x = ceres::sin(tau_x_val);
203 const T cos_tau_y = ceres::cos(tau_y_val);
204 const T sin_tau_y = ceres::sin(tau_y_val);
205
206 Eigen::Matrix<T, 3, 3> rot_x;
207 rot_x << T(1), T(0), T(0), T(0), cos_tau_x, -sin_tau_x, T(0), sin_tau_x, cos_tau_x;
208 Eigen::Matrix<T, 3, 3> rot_y;
209 rot_y << cos_tau_y, T(0), sin_tau_y, T(0), T(1), T(0), -sin_tau_y, T(0), cos_tau_y;
210 Eigen::Matrix<T, 3, 3> rot_sensor = rot_y * rot_x;
211
212 Eigen::Matrix<T, 3, 1> axis_sensor = rot_sensor.col(0);
213 Eigen::Matrix<T, 3, 1> base_sensor = rot_sensor.col(1);
214 Eigen::Matrix<T, 3, 1> normal_sensor = rot_sensor.col(2);
215
216 const T s0 = normal_sensor.z();
217 const T mx0 = axis_sensor.z() / s0;
218 const T my0 = base_sensor.z() / s0;
219
220 // Remove principal-offset *linear* shift via traits
221 Eigen::Matrix<T, 2, 1> base_shift =
222 CameraTraits<CameraT>::template apply_intrinsics_linear<T>(camera, {mx0, my0});
223
224 // Invert base camera mapping for the delta (distortion + intrinsics)
225 // Your base unproject returns the *canonical* [dx, dy] on z=1
226 Eigen::Matrix<T, 2, 1> dxy = camera.template unproject<T>(pixel - base_shift);
227
228 // Return plane coords around the actual plane origin
229 return {dxy.x() + mx0, dxy.y() + my0};
230 }
231};
232
233// Traits specialisation for Scheimpflug camera
234template <camera_model CameraT>
236 static constexpr size_t param_count = CameraTraits<CameraT>::param_count + 2;
237 static constexpr int idx_fx = CameraTraits<CameraT>::idx_fx;
238 static constexpr int idx_fy = CameraTraits<CameraT>::idx_fy;
239 static constexpr int idx_skew = CameraTraits<CameraT>::idx_skew;
240
241 static constexpr int k_tau_x_idx = CameraTraits<CameraT>::param_count;
242 static constexpr int k_tau_y_idx = CameraTraits<CameraT>::param_count + 1;
243
244 template <typename T>
245 static auto from_array(const T* intr)
248 return ScheimpflugCamera<decltype(cam)>(cam, intr[k_tau_x_idx], intr[k_tau_y_idx]);
249 }
250
252 std::array<double, param_count>& arr) {
253 std::array<double, CameraTraits<CameraT>::param_count> inner{};
255 for (size_t i = 0; i < CameraTraits<CameraT>::param_count; ++i) {
256 arr[i] = inner[i];
257 }
258 arr[k_tau_x_idx] = cam.tau_x;
259 arr[k_tau_y_idx] = cam.tau_y;
260 }
261};
262
263} // namespace calib
std::vector< Eigen::Isometry3d > cam
Linear multi-camera extrinsics initialisation (DLT)
static void to_array(const ScheimpflugCamera< CameraT > &cam, std::array< double, param_count > &arr)
static auto from_array(const T *intr) -> ScheimpflugCamera< decltype(CameraTraits< CameraT >::from_array(intr))>
Type traits template for camera model implementations.
Definition cameramodel.h:64
double tau_x
Tilt around the X axis (radians)
Definition scheimpflug.h:19
double tau_y
Tilt around the Y axis (radians)
Definition scheimpflug.h:20
Camera model with a tilted sensor plane (Scheimpflug configuration).
Definition scheimpflug.h:35
ScheimpflugCamera(ScheimpflugCamera &&other) noexcept
Move constructor.
Definition scheimpflug.h:79
ScheimpflugCamera(const CameraT &cam, ScheimpflugAngles angles)
Construct from camera and angle structure.
Definition scheimpflug.h:49
ScheimpflugCamera & operator=(ScheimpflugCamera &&other) noexcept
Move assignment operator.
Definition scheimpflug.h:83
typename CameraT::Scalar Scalar
Definition scheimpflug.h:36
auto unproject(const Eigen::Matrix< T, 2, 1 > &pixel) const -> Eigen::Matrix< T, 2, 1 >
Unproject pixel coordinates to sensor plane coordinates.
Eigen::Matrix< T, 2, 1 > apply_intrinsics(const Eigen::Matrix< T, 2, 1 > &plane_point) const
Apply linear intrinsic parameters to plane coordinates.
ScheimpflugCamera & operator=(const ScheimpflugCamera &other)
Copy assignment operator.
Definition scheimpflug.h:69
CameraT camera
Underlying camera model.
Definition scheimpflug.h:37
ScheimpflugCamera(const ScheimpflugCamera &other)
Copy constructor.
Definition scheimpflug.h:65
Scalar tau_y
Tilt around the Y axis (radians)
Definition scheimpflug.h:39
Eigen::Matrix< T, 2, 1 > remove_intrinsics(const Eigen::Matrix< T, 2, 1 > &pixel) const
Remove linear intrinsic parameters from pixel coordinates.
ScheimpflugCamera(OtherCamT cam, T tau_x_angle, T tau_y_angle)
Construct from different camera type and individual angles.
Definition scheimpflug.h:61
Scalar tau_x
Tilt around the X axis (radians)
Definition scheimpflug.h:38
auto project(const Eigen::Matrix< T, 3, 1 > &x_camera) const -> Eigen::Matrix< T, 2, 1 >
Project a 3D point in the camera frame to pixel coordinates.
ScheimpflugCamera()
Default constructor - creates camera with zero tilt angles.
Definition scheimpflug.h:42