Ocean
Loading...
Searching...
No Matches
FisheyeCamera.h
Go to the documentation of this file.
1/*
2 * Copyright (c) Meta Platforms, Inc. and affiliates.
3 *
4 * This source code is licensed under the MIT license found in the
5 * LICENSE file in the root directory of this source tree.
6 */
7
8#ifndef META_OCEAN_MATH_FISHEYE_CAMERA_H
9#define META_OCEAN_MATH_FISHEYE_CAMERA_H
10
11#include "ocean/math/Math.h"
12#include "ocean/math/Camera.h"
14#include "ocean/math/Numeric.h"
17#include "ocean/math/Vector2.h"
18#include "ocean/math/Vector3.h"
19
20namespace Ocean
21{
22
23// Forward declaration.
24template <typename T> class FisheyeCameraT;
25
26/**
27 * Definition of a FisheyeCamera object using Scalar as data type.
28 * @see FisheyeCameraT
29 * @ingroup math
30 */
32
33/**
34 * Definition of a FisheyeCamera object using 'float'' as data type.
35 * @see FisheyeCameraT
36 * @ingroup math
37 */
39
40/**
41 * Definition of a FisheyeCamera object using 'double'' as data type.
42 * @see FisheyeCameraT
43 * @ingroup math
44 */
46
47/**
48 * Definition of a typename alias for vectors with FisheyeCameraT objects.
49 * @see FisheyeCameraT
50 * @ingroup math
51 */
52template <typename T>
53using FisheyeCamerasT = std::vector<FisheyeCameraT<T>>;
54
55/**
56 * Definition of a vector holding camera objects.
57 * @ingroup math
58 */
59typedef std::vector<FisheyeCamera> FisheyeCameras;
60
61/**
62 * Class representing a fisheye camera.<br>
63 * The class holds the intrinsic and distortion parameters of a camera.<br>
64 * <pre>
65 * The camera holds:
66 *
67 * 1) Width and height of the camera image.
68 *
69 * 2) Intrinsic camera matrix:
70 * | Fx 0 mx |
71 * | 0 Fy my |
72 * | 0 0 1 |
73 * with mx and my as principal point,
74 * and with Fx = f / sx, Fy = f / sy, with focus f and pixel sizes sx and sy.
75 *
76 * 3) Six radial distortion parameters k3, k5, k7, k9, k11, k13
77 *
78 * 4) Two tangential distortion parameters p1 and p2.
79 *
80 * An undistorted image point (x, y), is transformed to the corresponding distorted image point (x', y') as follows:
81 * x' = x_r + x_t
82 * y' = y_r + y_t
83
84 * radial distortion:
85 * x_r = x * (theta + k3 * theta^3 + k5 * theta^5 + k7 * theta^7 + k9 * theta^9 + k11 * theta^11 + k13 * theta^13) / r
86 * y_r = y * (theta + k3 * theta^3 + k5 * theta^5 + k7 * theta^7 + k9 * theta^9 + k11 * theta^11 + k13 * theta^13) / r
87 *
88 * tangential distortion:
89 * x_t = p1 * (2 * x_r^2 + radial^2) + p2 * 2 * x_r * y_r,
90 * y_t = p2 * (2 * y_r^2 + radial^2) + p1 * 2 * x_r * y_r.
91 *
92 * with
93 * r = sqrt(x^2 + y^2)
94 * theta = atan(r)
95 * radial^2 = x_r^2 + y_r^2
96 *
97 * With x, y undistorted normalized coordinates
98 * With x', y' distorted normalized coordinates
99 *
100 * </pre>
101 * @ingroup math
102 * @tparam T The data type of a scalar, 'float' or 'double'
103 */
104template <typename T>
105class FisheyeCameraT : public CameraT<T>
106{
107 template <typename U> friend class FisheyeCameraT;
108
109 public:
110
111 /**
112 * Definition of the used data type.
113 */
114 typedef T Type;
115
116 /**
117 * Definition of individual parameter configurations.
118 */
120 {
121 /**
122 * An unknown parameter configuration.
123 */
125
126 /**
127 * 3 parameters with order:
128 * focal length (one identical value for horizontal and vertical direction),
129 * horizontal principal point,
130 * vertical principal point
131 */
133
134 /**
135 * 4 parameters with order:
136 * horizontal focal length,
137 * vertical focal length,
138 * horizontal principal point,
139 * vertical principal point
140 */
142
143 /**
144 * 11 parameters with order:
145 * focal length (one identical value for horizontal and vertical direction),
146 * horizontal principal point,
147 * vertical principal point,
148 * six radial distortion parameters k3, k5, k7, k9, k11, k13
149 * two tangential distortion parameters p1, p2
150 */
152
153 /**
154 * 12 parameters with order:
155 * horizontal focal length,
156 * vertical focal length,
157 * horizontal principal point,
158 * vertical principal point,
159 * six radial distortion parameters k3, k5, k7, k9, k11, k13
160 * two tangential distortion parameters p1, p2
161 */
163 };
164
165 public:
166
167 /**
168 * Default constructor creating an invalid camera object.
169 */
170 FisheyeCameraT() = default;
171
172 /**
173 * Copy constructor.
174 * @param fisheyeCamera The fisheye camera profile to be copied
175 */
177
178 /**
179 * Copy constructor for a fisheye camera with difference element data type than T.
180 * @param fisheyeCamera The fisheye camera profile to be copied
181 * @tparam U The element data type of the given fisheye camera
182 */
183 template <typename U>
185
186 /**
187 * Creates a new camera object with known field of view.
188 * @param width The width of the camera image (in pixel), with range [1, infinity)
189 * @param height The height of the camera image (in pixel), with range [1, infinity)
190 * @param fovX Field of view in x-direction (in radian), with range (0, PI]
191 */
192 inline FisheyeCameraT(const unsigned int width, const unsigned int height, const T fovX);
193
194 /**
195 * Creates a new camera object without distortion parameters.
196 * @param width The width of the camera image (in pixel), with range [1, infinity)
197 * @param height The height of the camera image (in pixel), with range [1, infinity)
198 * @param focalX Focal parameter of the horizontal axis, with range (0, infinity)
199 * @param focalY Focal parameter of the vertical axis, with range (0, infinity)
200 * @param principalX Principal point of the horizontal axis (in pixel)
201 * @param principalY Principal point of the vertical axis (in pixel)
202 */
203 inline FisheyeCameraT(const unsigned int width, const unsigned int height, const T focalX, const T focalY, const T principalX, const T principalY);
204
205 /**
206 * Creates a new camera object with distortion parameters.
207 * @param width The width of the camera image (in pixel), with range [1, infinity)
208 * @param height The height of the camera image (in pixel), with range [1, infinity)
209 * @param focalX Focal parameter of the horizontal axis, with range (0, infinity)
210 * @param focalY Focal parameter of the vertical axis, with range (0, infinity)
211 * @param principalX Principal point of the horizontal axis (in pixel), with range (0, width)
212 * @param principalY Principal point of the vertical axis (in pixel), with range (0, height)
213 * @param radialDistortion Six radial distortion values, with order k3, k5, k7, k9, k11, 13, must be valid
214 * @param tangentialDistortion Two tangential distortion values, with order p1, p2, must be valid
215 * @tparam TParameter The scalar data type in which the intrinsic camera parameters are provided, will be converted to 'T' internally, 'float' or 'double'
216 */
217 template <typename TParameter>
218 inline FisheyeCameraT(const unsigned int width, const unsigned int height, const TParameter focalX, const TParameter focalY, const TParameter principalX, const TParameter principalY, const TParameter* radialDistortion, const TParameter* tangentialDistortion);
219
220 /**
221 * Creates a new camera object with parameters with specific configuration.
222 * @param width The width of the camera image (in pixel), with range [1, infinity)
223 * @param height The height of the camera image (in pixel), with range [1, infinity)
224 * @param parameterConfiguration The configuration of the given parameter, must be valid
225 * @param parameters The parameters matching with the specific configuration, must be valid
226 * @tparam TParameter The scalar data type in which the intrinsic camera parameters are provided, will be converted to 'T' internally, 'float' or 'double'
227 */
228 template <typename TParameter>
229 inline FisheyeCameraT(const unsigned int width, const unsigned int height, const ParameterConfiguration parameterConfiguration, const TParameter* parameters);
230
231 /**
232 * Returns whether this camera object has specified distortion parameters.
233 * @return True, if so
234 */
235 inline bool hasDistortionParameters() const;
236
237 /**
238 * Returns the width of the camera image.
239 * @return Width of the camera image, in pixel, with range [0, infinity)
240 */
241 inline unsigned int width() const;
242
243 /**
244 * Returns the height of the camera image.
245 * @return Height of the camera image, in pixel, with range [0, infinity)
246 */
247 inline unsigned int height() const;
248
249 /**
250 * Returns the coordinate of the principal point of the camera image in the pixel domain.
251 * @return The 2D location of the principal point, with range [0, width)x[0, height)
252 */
254
255 /**
256 * Returns the x-value of the principal point of the camera image in the pixel domain.
257 * @return x-value of the principal point, with range [0, width)
258 */
259 inline T principalPointX() const;
260
261 /**
262 * Returns the y-value of the principal point of the camera image in the pixel domain.
263 * @return y-value of the principal point, with range [0, height)
264 */
265 inline T principalPointY() const;
266
267 /**
268 * Returns the horizontal focal length parameter.
269 * @return Horizontal focal length parameter
270 */
271 inline T focalLengthX() const;
272
273 /**
274 * Returns the vertical focal length parameter.
275 * @return Vertical focal length parameter
276 */
277 inline T focalLengthY() const;
278
279 /**
280 * Returns the inverse horizontal focal length parameter.
281 * @return Inverse horizontal focal length parameter
282 */
283 inline T inverseFocalLengthX() const;
284
285 /**
286 * Returns the inverse vertical focal length parameter.
287 * @return Inverse vertical focal length parameter
288 */
289 inline T inverseFocalLengthY() const;
290
291 /**
292 * Returns the six radial distortion parameters of the camera model.
293 * @return The six radial distortion parameters, with order k3, k5, k7, k9, k11, k13
294 */
295 inline const T* radialDistortion() const;
296
297 /**
298 * Returns the two tangential distortion parameters of the camera model.
299 * @return The two tangential distortion parameters, with order p1, p2
300 */
301 inline const T* tangentialDistortion() const;
302
303 /**
304 * Returns the field of view in x direction of the camera.
305 * The fov is the sum of the left and right part of the camera.
306 * @return Field of view (in radian), with range (0, PI]
307 */
308 T fovX() const;
309
310 /**
311 * Returns the field of view in x direction of the camera.
312 * The fov is the sum of the top and bottom part of the camera.
313 * @return Field of view (in radian), with range (0, PI)
314 */
315 T fovY() const;
316
317 /**
318 * Returns the diagonal field of view of the camera
319 * @return Diagonal field of view (in radian), with range (0, PI]
320 */
321 T fovDiagonal() const;
322
323 /**
324 * Copies the parameters of this camera.
325 * @param width The resulting width of the camera, in pixel, with range [0, infinity)
326 * @param height The resulting height of the camera, in pixel, with range [0, infinity)
327 * @param parameters The resulting parameters of the camera
328 * @param parameterConfiguration The resulting configuration of the resulting parameters
329 */
330 template <typename TParameter>
331 void copyParameters(unsigned int& width, unsigned int& height, std::vector<TParameter>& parameters, ParameterConfiguration& parameterConfiguration) const;
332
333 /**
334 * Returns whether a given 2D image point lies inside the camera frame.
335 * Optional an explicit border can be defined to allow points slightly outside the camera image, or further inside the image.<br>
336 * Defined a negative border size to allow image points outside the camera frame, or a positive border size to prevent points within the camera frame but close to the boundary.
337 * @param imagePoint Image point to be checked, must be valid
338 * @param signedBorder The optional border increasing or decreasing the rectangle in which the image point must be located, in pixels, with range (-infinity, std::min(width() / 2, height() / 2)
339 * @return True, if the image point lies in the ranges [0, width())x[0, height())
340 */
341 inline bool isInside(const VectorT2<T>& imagePoint, const T signedBorder = T(0)) const;
342
343 /**
344 * Returns the normalized distorted position of a given undistorted normalized position.
345 * @param undistortedNormalized Undistorted normalized position to be distorted
346 * @return Resulting distorted normalized position
347 * @tparam tUseDistortionParameters True, to use the camera's distortion parameter; False, to just scale the normalized image due to theta
348 */
349 template <bool tUseDistortionParameters = true>
351
352 /**
353 * Returns the normalized undistorted position of a given distorted normalized position.
354 * @param distortedNormalized Distorted normalized position to be undistorted
355 * @return Resulting undistorted normalized position
356 * @tparam tUseDistortionParameters True, to use the camera's distortion parameter; False, to just scale the normalized image due to theta
357 */
358 template <bool tUseDistortionParameters = true>
360
361 /**
362 * Projects a 3D object point into the camera's image of the fisheye camera.
363 * The 3D object point must be defined in relation to the (standard) camera coordinate system.<br>
364 * The default viewing direction of the standard camera is into the negative z-space with x-axis to the right, and y-axis upwards.
365 * @param worldObjectPoint 3D object point which is located in the world
366 * @return Resulting 2D image point within the camera frame
367 * @tparam tUseDistortionParameters True, to use the camera's distortion parameter; False, to just scale the normalized image due to theta
368 * @see projectToImageIF().
369 */
370 template <bool tUseDistortionParameters = true>
372
373 /**
374 * Projects a 3D object point into the camera's image of the fisheye camera.
375 * The extrinsic matrix transforms a 3D point given in camera coordinates into 3D world coordinates (world from camera).<br>
376 * The default viewing direction of the camera is into the negative z-space with x-axis to the right, and y-axis upwards.
377 * @param world_T_camera The extrinsic camera matrix, must be valid
378 * @param worldObjectPoint 3D object point which is located in the world
379 * @return Resulting 2D image point within the camera frame
380 * @tparam tUseDistortionParameters True, to use the camera's distortion parameter; False, to just scale the normalized image due to theta
381 * @see projectToImageIF().
382 */
383 template <bool tUseDistortionParameters = true>
385
386 /**
387 * Projects a 3D object point to the 2D image plane of the fisheye camera by a given inverted (and flipped) extrinsic camera matrix.
388 * The inverted (and flipped) extrinsic matrix transforms a 3D point given in 3D world coordinates into 3D (flipped) camera coordinates (flipped camera from world).<br>
389 * The default viewing direction of the flipped camera is into the positive z-space with x-axis to the right, and y-axis downwards.
390 * @param flippedCamera_T_world Inverted and flipped extrinsic camera matrix, must be valid
391 * @param worldObjectPoint 3D object point which is located in the world
392 * @return Resulting 2D image point within the camera frame
393 * @tparam tUseDistortionParameters True, to use the camera's distortion parameter; False, to just scale the normalized image due to theta
394 * @see projectToImage().
395 */
396 template <bool tUseDistortionParameters = true>
398
399 /**
400 * Projects a 3D object point to the 2D image plane of the fisheye camera.
401 * The 3D object point must be defined in relation to the (flipped) camera coordinate system.<br>
402 * The default viewing direction of the flipped camera is into the positive z-space with x-axis to the right, and y-axis downwards.
403 * @param cameraFlippedObjectPoint 3D object point which is located in the flipped camera coordinate system
404 * @return Resulting 2D image point within the camera frame
405 * @tparam tUseDistortionParameters True, to use the camera's distortion parameter; False, to just scale the normalized image due to theta
406 * @see projectToImage().
407 */
408 template <bool tUseDistortionParameters = true>
410
411 /**
412 * Returns a unit vector (with length 1) starting at the camera's center and intersecting a given 2D point in the image.
413 * The vector is determined for the default camera looking into the negative z-space with y-axis up.
414 * @param distortedImagePoint 2D (distorted) position within the image, with range [0, width())x[0, height())
415 * @param makeUnitVector True, to return a vector with length 1; False, to return a vector with any length
416 * @return Unit vector pointing into the negative z-space
417 * @tparam tUseDistortionParameters True, to use the camera's distortion parameter; False, to just scale the normalized image due to theta
418 * @see vectorIF(), ray().
419 */
420 template <bool tUseDistortionParameters = true>
421 inline VectorT3<T> vector(const VectorT2<T>& distortedImagePoint, const bool makeUnitVector = true) const;
422
423 /**
424 * Returns a normalized vector (with length 1) starting at the camera's center and intersecting a given 2D point on the image plane.
425 * The vector is determined for the default camera looking into the positive z-space with y-axis down.
426 * @param distortedImagePoint 2D (distorted) position within the image, with range [0, width())x[0, height())
427 * @param makeUnitVector True, to return a vector with length 1; False, to return a vector with any length
428 * @return Normalized vector into the negative z-space
429 * @tparam tUseDistortionParameters True, to use the camera's distortion parameter; False, to just scale the normalized image due to theta
430 * @see vector().
431 */
432 template <bool tUseDistortionParameters = true>
433 inline VectorT3<T> vectorIF(const VectorT2<T>& distortedImagePoint, const bool makeUnitVector = true) const;
434
435 /**
436 * Returns a ray starting at the camera's center and intersecting a given 2D point in the image.
437 * @param distortedImagePoint 2D (distorted) position within the image, with range [0, width())x[0, height())
438 * @param world_T_camera The pose of the camera, the extrinsic camera matrix, must be valid
439 * @return The specified ray with direction pointing into the camera's negative z-space
440 * @tparam tUseDistortionParameters True, to use the camera's distortion parameter; False, to just scale the normalized image due to theta
441 * @see vector().
442 */
443 template <bool tUseDistortionParameters = true>
445
446 /**
447 * Returns a ray starting at the camera's center and intersecting a given 2D point in the image.
448 * @param distortedImagePoint 2D (distorted) position within the image, with range [0, width())x[0, height())
449 * @return The specified ray with direction pointing into the camera's negative z-space
450 * @tparam tUseDistortionParameters True, to use the camera's distortion parameter; False, to just scale the normalized image due to theta
451 * @see vector().
452 */
453 template <bool tUseDistortionParameters = true>
455
456 /**
457 * Calculates the 2x3 jacobian matrix for the 3D object point projection into the camera frame.
458 * The resulting jacobian matrix has the following layout:
459 * <pre>
460 * | dfu / dx, dfu / dy, dfu / dz |
461 * | dfv / dx, dfv / dy, dfv / dz |
462 * with projection function
463 * q = f(p)
464 * q_u = fu(p), q_y = fv(p)
465 * with 2D image point q = (q_u, q_v) and 3D object point p = (x, y, z)
466 * </pre>
467 * @param flippedCameraObjectPoint The 3D object point defined in relation to the inverted and flipped camera pose (camera looking into the positive z-space with y-axis pointing down).
468 * @param jx The resulting first row of the Jacobian matrix, must contain three elements, must be valid
469 * @param jy The resulting second row of the Jacobian matrix, must contain three elements, must be valid
470 * @tparam tUseDistortionParameters True, to use the camera's distortion parameter; False, to just scale the normalized image due to theta
471 */
472 template <bool tUseDistortionParameters = true>
474
475 /**
476 * Returns whether two camera profiles are identical up to a given epsilon.
477 * The image resolution must always be identical.
478 * @param fisheyeCamera The second camera profile to be used for comparison, can be invalid
479 * @param eps The epsilon threshold to be used, with range [0, infinity)
480 * @return True, if so
481 */
482 bool isEqual(const FisheyeCameraT<T>& fisheyeCamera, const T eps = NumericT<T>::eps()) const;
483
484 /**
485 * Returns whether this camera is valid.
486 * @return True, if so
487 */
488 inline bool isValid() const;
489
490 /**
491 * Returns whether two fisheye cameras are identical.
492 * @param fisheyeCamera The second fisheye camera to be check
493 * @return True, if so
494 */
496
497 /**
498 * Returns whether two fisheye cameras are not identical.
499 * @param fisheyeCamera The second fisheye camera to be check
500 * @return True, if so
501 */
502 inline bool operator!=(const FisheyeCameraT<T>& fisheyeCamera) const;
503
504 /**
505 * Copy assignment operator.
506 * @param fisheyeCamera The fisheye camera profile to be copied
507 * @return A reference to this object
508 */
510
511 /**
512 * Returns whether the camera holds valid parameters.
513 * @return True, if so
514 */
515 explicit inline operator bool() const;
516
517 protected:
518
519 /**
520 * Calculates the tangential-free distortion of a normalized (distorted) image point.
521 * @param distortedNormalized The distorted normalized image point from which the tangential distortion will be removed
522 * @return The normalized image point containing radial distortion only
523 */
525
526 /**
527 * Determines the 2x2 Jacobian of distorting a normalized image point in a fisheye camera with radial and tangential distortion.
528 * The resulting jacobian has the following form:
529 * <pre>
530 * | dfx / dx, dfx / dy |
531 * | dfy / dx, dfy / dy |
532 * </pre>
533 * @param x The horizontal coordinate of the normalized image point to be distorted
534 * @param y The vertical coordinate of the normalized image point to be distorted
535 * @param radialDistortion The six radial distortion parameters, must be valid
536 * @param tangentialDistortion The two radial distortion parameters, must be valid
537 * @param jx First row of the jacobian, with 2 column entries, must be valid
538 * @param jy Second row of the jacobian, with 2 column entries, must be valid
539 */
540 static OCEAN_FORCE_INLINE void jacobianDistortNormalized2x2(const T x, const T y, const T* radialDistortion, const T* tangentialDistortion, T* jx, T* jy);
541
542 protected:
543
544 /// Width of the camera image, in pixel.
545 unsigned int cameraWidth_ = 0u;
546
547 /// Height of the camera image, in pixel.
548 unsigned int cameraHeight_ = 0u;
549
550 /// The horizontal focal length of the camera, with range (0, infinity)
552
553 /// The vertical focal length of the camera, with range (0, infinity)
555
556 /// The horizontal inverse focal length of the camera, with range (0, infinity)
558
559 /// The vertical inverse focal length of the camera, with range (0, infinity)
561
562 /// The horizontal principal point of the camera, in pixels, with range [0, width())
564
565 /// The vertical principal point of the camera, in pixels, with range [0, width())
567
568 /// True, if the distortion parameters are defined.
570
571 /// The six radial distortion parameters.
572 T radialDistortion_[6] = {T(0), T(0), T(0), T(0), T(0), T(0)};
573
574 /// The two tangential distortion parameters.
575 T tangentialDistortion_[2] = {T(0), T(0)};
576};
577
578template <typename T>
579template <typename U>
581 cameraWidth_(fisheyeCamera.cameraWidth_),
582 cameraHeight_(fisheyeCamera.cameraHeight_),
583 focalLengthX_(T(fisheyeCamera.focalLengthX_)),
584 focalLengthY_(T(fisheyeCamera.focalLengthY_)),
585 principalPointX_(T(fisheyeCamera.principalPointX_)),
586 principalPointY_(T(fisheyeCamera.principalPointY_)),
587 hasDistortionParameters_(fisheyeCamera.hasDistortionParameters_)
588{
589 static_assert(sizeof(radialDistortion_) / 6u == sizeof(T), "Invalid parameter");
590 static_assert(sizeof(tangentialDistortion_) / 2u == sizeof(T), "Invalid parameter");
591
594
595 for (unsigned int n = 0u; n < 6u; ++n)
596 {
597 radialDistortion_[n] = T(fisheyeCamera.radialDistortion_[n]);
598 }
599
600 tangentialDistortion_[0] = T(fisheyeCamera.tangentialDistortion_[0]);
601 tangentialDistortion_[1] = T(fisheyeCamera.tangentialDistortion_[1]);
602}
603
604template <typename T>
605inline FisheyeCameraT<T>::FisheyeCameraT(const unsigned int width, const unsigned int height, const T fovX) :
606 cameraWidth_(width),
607 cameraHeight_(height),
608 focalLengthX_(0),
609 focalLengthY_(0),
610 invFocalLengthX_(0),
611 invFocalLengthY_(0),
612 principalPointX_(0),
613 principalPointY_(0),
614 hasDistortionParameters_(false)
615{
618
619 const T principalX = T(cameraWidth_) * T(0.5);
620 const T principalY = T(cameraHeight_) * T(0.5);
621
622 const T focalLength = principalX / NumericT<T>::tan(fovX * T(0.5));
623
626
628 const T invFocalLength = T(1) / focalLength;
631
634
635 for (unsigned int n = 0u; n < 6u; ++n)
636 {
637 radialDistortion_[n] = T(0);
638 }
639
640 tangentialDistortion_[0] = T(0);
641 tangentialDistortion_[1] = T(0);
642}
643
644template <typename T>
645inline FisheyeCameraT<T>::FisheyeCameraT(const unsigned int width, const unsigned int height, const T focalX, const T focalY, const T principalX, const T principalY) :
646 cameraWidth_(width),
647 cameraHeight_(height),
648 focalLengthX_(focalX),
649 focalLengthY_(focalY),
650 invFocalLengthX_(0),
651 invFocalLengthY_(0),
652 principalPointX_(principalX),
653 principalPointY_(principalY),
654 hasDistortionParameters_(false)
655{
657
662
663 for (unsigned int n = 0u; n < 6u; ++n)
664 {
665 radialDistortion_[n] = T(0);
666 }
667
668 tangentialDistortion_[0] = T(0);
669 tangentialDistortion_[1] = T(0);
670}
671
672template <typename T>
673template <typename TParameter>
674inline FisheyeCameraT<T>::FisheyeCameraT(const unsigned int width, const unsigned int height, const TParameter focalX, const TParameter focalY, const TParameter principalX, const TParameter principalY, const TParameter* radialDistortion, const TParameter* tangentialDistortion) :
675 cameraWidth_(width),
676 cameraHeight_(height),
677 focalLengthX_(T(focalX)),
678 focalLengthY_(T(focalY)),
679 invFocalLengthX_(0),
680 invFocalLengthY_(0),
681 principalPointX_(T(principalX)),
682 principalPointY_(T(principalY)),
683 hasDistortionParameters_(true)
684{
685 static_assert((std::is_same<TParameter, float>::value) || (std::is_same<TParameter, double>::value), "Invalid TParameter, must be 'float' or 'double'!");
686
691
692 for (unsigned int n = 0u; n < 6u; ++n)
693 {
695 }
696
699}
700
701template <typename T>
702template <typename TParameter>
703inline FisheyeCameraT<T>::FisheyeCameraT(const unsigned int width, const unsigned int height, const ParameterConfiguration parameterConfiguration, const TParameter* parameters) :
704 cameraWidth_(width),
705 cameraHeight_(height),
706 focalLengthX_(0),
707 focalLengthY_(0),
708 invFocalLengthX_(0),
709 invFocalLengthY_(0),
710 principalPointX_(0),
711 principalPointY_(0),
712 hasDistortionParameters_(false)
713{
714 static_assert((std::is_same<TParameter, float>::value) || (std::is_same<TParameter, double>::value), "Invalid TParameter, must be 'float' or 'double'!");
715
717 ocean_assert(parameters != nullptr);
718
720 {
722 {
723 focalLengthX_ = T(parameters[0]);
724 focalLengthY_ = T(parameters[0]);
725
726 principalPointX_ = T(parameters[1]);
727 principalPointY_ = T(parameters[2]);
728
730
731 break;
732 }
733
734 case PC_4_PARAMETERS:
735 {
736 focalLengthX_ = T(parameters[0]);
737 focalLengthY_ = T(parameters[1]);
738
739 principalPointX_ = T(parameters[2]);
740 principalPointY_ = T(parameters[3]);
741
743
744 break;
745 }
746
748 {
749 focalLengthX_ = T(parameters[0]);
750 focalLengthY_ = T(parameters[0]);
751
752 principalPointX_ = T(parameters[1]);
753 principalPointY_ = T(parameters[2]);
754
755 radialDistortion_[0] = T(parameters[3]);
756 radialDistortion_[1] = T(parameters[4]);
757 radialDistortion_[2] = T(parameters[5]);
758 radialDistortion_[3] = T(parameters[6]);
759 radialDistortion_[4] = T(parameters[7]);
760 radialDistortion_[5] = T(parameters[8]);
761
762 tangentialDistortion_[0] = T(parameters[9]);
763 tangentialDistortion_[1] = T(parameters[10]);
764
766
767 break;
768 }
769
770 case PC_12_PARAMETERS:
771 {
772 focalLengthX_ = T(parameters[0]);
773 focalLengthY_ = T(parameters[1]);
774
775 principalPointX_ = T(parameters[2]);
776 principalPointY_ = T(parameters[3]);
777
778 radialDistortion_[0] = T(parameters[4]);
779 radialDistortion_[1] = T(parameters[5]);
780 radialDistortion_[2] = T(parameters[6]);
781 radialDistortion_[3] = T(parameters[7]);
782 radialDistortion_[4] = T(parameters[8]);
783 radialDistortion_[5] = T(parameters[9]);
784
785 tangentialDistortion_[0] = T(parameters[10]);
786 tangentialDistortion_[1] = T(parameters[11]);
787
789
790 break;
791 }
792
793 default:
794 ocean_assert(false && "Invalid parameter configuration!");
795 return;
796 }
797
801}
802
803template <typename T>
805{
806 return hasDistortionParameters_;
807}
808
809template <typename T>
810inline unsigned int FisheyeCameraT<T>::width() const
811{
812 return cameraWidth_;
813}
814
815template <typename T>
816inline unsigned int FisheyeCameraT<T>::height() const
817{
818 return cameraHeight_;
819}
820
821template <typename T>
823{
824 return VectorT2<T>(principalPointX(), principalPointY());
825}
826
827template <typename T>
829{
830 return principalPointX_;
831}
832
833template <typename T>
835{
836 return principalPointY_;
837}
838
839template <typename T>
841{
842 return focalLengthX_;
843}
844
845template <typename T>
847{
848 return focalLengthY_;
849}
850
851template <typename T>
853{
854 return invFocalLengthX_;
855}
856
857template <typename T>
859{
860 return invFocalLengthY_;
861}
862
863template <typename T>
865{
866 return radialDistortion_;
867}
868
869template <typename T>
871{
872 return tangentialDistortion_;
873}
874
875template <typename T>
877{
878 ocean_assert(isValid());
879
880 /**
881 * x = Fx * X / Z + mx
882 *
883 * (x - mx) / Fx = X / Z
884 */
885
886 if (NumericT<T>::isEqualEps(focalLengthX()))
887 {
888 return T(0);
889 }
890
891 const T leftAngle = NumericT<T>::abs(NumericT<T>::atan(-principalPointX() * invFocalLengthX_));
892
893 if (T(cameraWidth_) <= principalPointX())
894 {
895 ocean_assert(false && "Invalid principal point");
896 return T(2) * leftAngle;
897 }
898
899 const T rightAngle = NumericT<T>::atan((T(cameraWidth_) - principalPointX()) * invFocalLengthX_);
900
901 return leftAngle + rightAngle;
902}
903
904template <typename T>
906{
907 ocean_assert(isValid());
908
909 /**
910 * y = Fy * Y / Z + my
911 *
912 * (y - my) / Fy = Y / Z
913 */
914
915 if (NumericT<T>::isEqualEps(focalLengthY()))
916 {
917 return T(0);
918 }
919
920 const T topAngle = NumericT<T>::abs(NumericT<T>::atan(-principalPointY() * invFocalLengthY_));
921
922 if (T(cameraHeight_) <= principalPointY())
923 {
924 ocean_assert(false && "Invalid principal point");
925 return T(2) * topAngle;
926 }
927
928 const T bottomAngle = NumericT<T>::atan((T(cameraHeight_) - principalPointY()) * invFocalLengthY_);
929
930 return topAngle + bottomAngle;
931}
932
933template <typename T>
935{
936 const VectorT2<T> topLeft(-principalPointX(), -principalPointY());
937 const VectorT2<T> bottomRight(principalPointX(), principalPointY());
938
939 const T diagonal = (topLeft - bottomRight).length();
940 const T halfDiagonal = diagonal * T(0.5);
941
942 const T invFocalLength = (invFocalLengthX_ + invFocalLengthY_) * T(0.5);
943
944 return T(2) * NumericT<T>::abs(NumericT<T>::atan(halfDiagonal * invFocalLength));
945}
946
947template <typename T>
948template <typename TParameter>
949void FisheyeCameraT<T>::copyParameters(unsigned int& width, unsigned int& height, std::vector<TParameter>& parameters, ParameterConfiguration& parameterConfiguration) const
950{
951 if (isValid())
952 {
953 width = cameraWidth_;
954 height = cameraHeight_;
955
956 parameters =
957 {
958 TParameter(focalLengthX_),
959 TParameter(focalLengthY_),
960
961 TParameter(principalPointX_),
962 TParameter(principalPointY_),
963
964 TParameter(radialDistortion_[0]),
965 TParameter(radialDistortion_[1]),
966 TParameter(radialDistortion_[2]),
967 TParameter(radialDistortion_[3]),
968 TParameter(radialDistortion_[4]),
969 TParameter(radialDistortion_[5]),
970
971 TParameter(tangentialDistortion_[0]),
972 TParameter(tangentialDistortion_[1]),
973 };
974
975 ocean_assert(parameters.size() == 12);
976
977 parameterConfiguration = PC_12_PARAMETERS;
978 }
979 else
980 {
981 width = 0u;
982 height = 0u;
983
984 parameters.clear();
985
986 parameterConfiguration = PC_UNKNOWN;
987 }
988}
989
990template <typename T>
991inline bool FisheyeCameraT<T>::isInside(const VectorT2<T>& imagePoint, const T signedBorder) const
992{
993 ocean_assert(isValid());
994 ocean_assert(signedBorder < T(std::min(cameraWidth_ / 2u, cameraHeight_ / 2u)));
995
996 return imagePoint.x() >= signedBorder && imagePoint.y() >= signedBorder
997 && imagePoint.x() < T(cameraWidth_) - signedBorder && imagePoint.y() < T(cameraHeight_) - signedBorder;
998}
999
1000template <typename T>
1001template <bool tUseDistortionParameters>
1003{
1004 ocean_assert(isValid());
1005
1006 /*
1007 * 3) Two radial distortion parameters k3, k5, k7, k9, k11, k13
1008 *
1009 * 4) Two tangential distortion parameters p1 and p2.
1010 *
1011 * An undistorted image point (x, y), is transformed to the corresponding distorted image point (x', y') as follows:
1012 * x' = x_r + x_t
1013 * y' = y_r + y_t
1014
1015 * radial distortion:
1016 * x_r = x * (theta + k3 * theta^3 + k5 * theta^5 + k7 * theta^7 + k9 * theta^9 + k11 * theta^11 + k13 * theta^13) / r
1017 * y_r = y * (theta + k3 * theta^3 + k5 * theta^5 + k7 * theta^7 + k9 * theta^9 + k11 * theta^11 + k13 * theta^13) / r
1018 *
1019 * tangential distortion:
1020 * x_t = p1 * (2 * x_r^2 + radial^2) + p2 * 2 * x_r * y_r,
1021 * y_t = p2 * (2 * y_r^2 + radial^2) + p1 * 2 * x_r * y_r.
1022 *
1023 * with
1024 * r = sqrt(x^2 + y^2)
1025 * theta = atan(r)
1026 * radial^2 = x_r^2 + y_r^2
1027 *
1028 * With x, y undistorted normalized coordinates
1029 * With x', y' distorted normalized coordinates
1030 */
1031
1032 const T r2 = undistortedNormalized.sqr();
1033 const T r = NumericT<T>::sqrt(r2);
1034
1036 {
1037 return VectorT2<T>(0, 0);
1038 }
1039
1040 const T theta = NumericT<T>::atan(r);
1041
1042 if (tUseDistortionParameters && hasDistortionParameters_)
1043 {
1044 const T theta2 = theta * theta;
1045 const T theta3 = theta2 * theta;
1046 const T theta5 = theta2 * theta3;
1047 const T theta7 = theta2 * theta5;
1048 const T theta9 = theta2 * theta7;
1049 const T theta11 = theta2 * theta9;
1050 const T theta13 = theta2 * theta11;
1051
1052 const T& k3 = radialDistortion_[0];
1053 const T& k5 = radialDistortion_[1];
1054 const T& k7 = radialDistortion_[2];
1055 const T& k9 = radialDistortion_[3];
1056 const T& k11 = radialDistortion_[4];
1057 const T& k13 = radialDistortion_[5];
1058
1059 const T radialDistortionFactor = (theta + k3 * theta3 + k5 * theta5 + k7 * theta7 + k9 * theta9 + k11 * theta11 + k13 * theta13) / r;
1060
1061 const T x_r = undistortedNormalized.x() * radialDistortionFactor;
1062 const T y_r = undistortedNormalized.y() * radialDistortionFactor;
1063
1064 const T radius_r2 = x_r * x_r + y_r * y_r;
1065
1066 const T& p1 = tangentialDistortion_[0];
1067 const T& p2 = tangentialDistortion_[1];
1068
1069 const T x_t = p1 * (T(2) * x_r * x_r + radius_r2) + p2 * T(2) * x_r * y_r;
1070 const T y_t = p2 * (T(2) * y_r * y_r + radius_r2) + p1 * T(2) * x_r * y_r;
1071
1072 return VectorT2<T>(x_r + x_t, y_r + y_t);
1073 }
1074 else
1075 {
1076 const T scale = theta / r;
1077
1078 return VectorT2<T>(undistortedNormalized.x() * scale, undistortedNormalized.y() * scale);
1079 }
1080}
1081
1082template <typename T>
1083template <bool tUseDistortionParameters>
1085{
1086 ocean_assert(isValid());
1087
1088 if constexpr (tUseDistortionParameters)
1089 {
1090 const VectorT2<T> distortedTangentialFree = tangentialFreeDistortion(distortedNormalized);
1091
1092 const T& k3 = radialDistortion_[0];
1093 const T& k5 = radialDistortion_[1];
1094 const T& k7 = radialDistortion_[2];
1095 const T& k9 = radialDistortion_[3];
1096 const T& k11 = radialDistortion_[4];
1097 const T& k13 = radialDistortion_[5];
1098
1099 const T r = distortedTangentialFree.length();
1100
1102 {
1103 return VectorT2<T>(0, 0);
1104 }
1105
1106 T theta = NumericT<T>::pow(r, T(0.3333333333333));
1107
1108 for (unsigned int n = 0u; n < 10u; ++n)
1109 {
1110 const T theta2 = theta * theta;
1111 const T theta4 = theta2 * theta2;
1112 const T theta6 = theta4 * theta2;
1113 const T theta8 = theta6 * theta2;
1114 const T theta10 = theta8 * theta2;
1115 const T theta12 = theta10 * theta2;
1116
1117 const T error = theta * (T(1) + k3 * theta2 + k5 * theta4 + k7 * theta6 + k9 * theta8 + k11 * theta10 + k13 * theta12) - r;
1118
1119 const T df = T(1) + T(3) * k3 * theta2 + T(5) * k5 * theta4 + T(7) * k7 * theta6 + T(9) * k9 * theta8 + T(11) * k11 * theta10 + T(13) * k13 * theta12;
1120
1121 if constexpr (std::is_same_v<T, float>)
1122 {
1124 {
1125 break;
1126 }
1127 }
1128 else
1129 {
1131 {
1132 break;
1133 }
1134 }
1135
1136 const T delta = error / df;
1137
1138 if constexpr (std::is_same_v<T, float>)
1139 {
1140 if (NumericT<T>::isNan(delta) || NumericT<T>::isInf(delta) || NumericT<T>::isEqualEps(delta))
1141 {
1142 break;
1143 }
1144 }
1145 else
1146 {
1147 if (NumericT<T>::isEqualEps(delta))
1148 {
1149 break;
1150 }
1151 }
1152
1153 theta -= delta;
1154 }
1155
1156 const T scale = NumericT<T>::tan(theta) / r;
1157
1158 return distortedTangentialFree * scale;
1159 }
1160 else
1161 {
1162 const T r = distortedNormalized.length();
1163
1165 {
1166 return VectorT2<T>(0, 0);
1167 }
1168
1169 const T scale = NumericT<T>::tan(r) / r;
1170
1171 return distortedNormalized * scale;
1172 }
1173}
1174
1175template <typename T>
1176template <bool tUseDistortionParameters>
1177inline VectorT2<T> FisheyeCameraT<T>::projectToImage(const VectorT3<T>& worldObjectPoint) const
1178{
1179 ocean_assert(isValid());
1180
1181 return projectToImageIF<tUseDistortionParameters>(VectorT3<T>(worldObjectPoint.x(), -worldObjectPoint.y(), -worldObjectPoint.z()));
1182}
1183
1184template <typename T>
1185template <bool tUseDistortionParameters>
1186inline VectorT2<T> FisheyeCameraT<T>::projectToImage(const HomogenousMatrixT4<T>& world_T_camera, const VectorT3<T>& worldObjectPoint) const
1187{
1188 ocean_assert(isValid());
1189
1190 ocean_assert(world_T_camera.isValid());
1191 return projectToImageIF<tUseDistortionParameters>(CameraT<T>::standard2InvertedFlipped(world_T_camera), worldObjectPoint);
1192}
1193
1194template <typename T>
1195template <bool tUseDistortionParameters>
1196VectorT2<T> FisheyeCameraT<T>::projectToImageIF(const HomogenousMatrixT4<T>& flippedCamera_T_world, const VectorT3<T>& worldObjectPoint) const
1197{
1198 ocean_assert(isValid());
1199
1200 ocean_assert(flippedCamera_T_world.isValid());
1201 return projectToImageIF<tUseDistortionParameters>(flippedCamera_T_world * worldObjectPoint);
1202}
1203
1204template <typename T>
1205template <bool tUseDistortionParameters>
1207{
1208 ocean_assert(isValid());
1209 ocean_assert(NumericT<T>::isNotEqualEps(cameraFlippedObjectPoint.z()));
1210
1211 const T invZ = T(1) / cameraFlippedObjectPoint.z();
1212
1213 const VectorT2<T> undistortedNormalized(cameraFlippedObjectPoint.x() * invZ, cameraFlippedObjectPoint.y() * invZ);
1214 const VectorT2<T> distortedNormalizedImagePoint = distortNormalized<tUseDistortionParameters>(undistortedNormalized);
1215
1216 return VectorT2<T>(distortedNormalizedImagePoint.x() * focalLengthX() + principalPointX(), distortedNormalizedImagePoint.y() * focalLengthY() + principalPointY());
1217}
1218
1219template <typename T>
1220template <bool tUseDistortionParameters>
1221inline VectorT3<T> FisheyeCameraT<T>::vector(const VectorT2<T>& distortedImagePoint, const bool makeUnitVector) const
1222{
1223 ocean_assert(isValid());
1224
1225 const VectorT2<T> distortedNormalized((distortedImagePoint.x() - principalPointX_) * invFocalLengthX_, (distortedImagePoint.y() - principalPointY_) * invFocalLengthY_);
1226 const VectorT2<T> undistortedNormalized = undistortNormalized<tUseDistortionParameters>(distortedNormalized);
1227
1228 if (makeUnitVector)
1229 {
1230 return VectorT3<T>(undistortedNormalized.x(), -undistortedNormalized.y(), T(-1)).normalized();
1231 }
1232 else
1233 {
1234 return VectorT3<T>(undistortedNormalized.x(), -undistortedNormalized.y(), T(-1));
1235 }
1236}
1237
1238template <typename T>
1239template <bool tUseDistortionParameters>
1240inline VectorT3<T> FisheyeCameraT<T>::vectorIF(const VectorT2<T>& distortedImagePoint, const bool makeUnitVector) const
1241{
1242 ocean_assert(isValid());
1243
1244 const VectorT2<T> distortedNormalized((distortedImagePoint.x() - principalPointX_) * invFocalLengthX_, (distortedImagePoint.y() - principalPointY_) * invFocalLengthY_);
1245 const VectorT2<T> undistortedNormalized = undistortNormalized<tUseDistortionParameters>(distortedNormalized);
1246
1247 if (makeUnitVector)
1248 {
1249 return VectorT3<T>(undistortedNormalized.x(), undistortedNormalized.y(), T(1)).normalized();
1250 }
1251 else
1252 {
1253 return VectorT3<T>(undistortedNormalized.x(), undistortedNormalized.y(), T(1));
1254 }
1255}
1256
1257template <typename T>
1258template <bool tUseDistortionParameters>
1259inline LineT3<T> FisheyeCameraT<T>::ray(const VectorT2<T>& distortedImagePoint, const HomogenousMatrixT4<T>& world_T_camera) const
1260{
1261 ocean_assert(isValid() && world_T_camera.isValid());
1262
1263 return LineT3<T>(world_T_camera.translation(), world_T_camera.rotationMatrix(vector<tUseDistortionParameters>(distortedImagePoint)));
1264}
1265
1266template <typename T>
1267template <bool tUseDistortionParameters>
1268inline LineT3<T> FisheyeCameraT<T>::ray(const VectorT2<T>& distortedImagePoint) const
1269{
1270 ocean_assert(isValid());
1271
1272 return LineT3<T>(Vector3(0, 0, 0), vector<tUseDistortionParameters>(distortedImagePoint));
1273}
1274
1275template <typename T>
1276template <bool tUseDistortionParameters>
1277inline void FisheyeCameraT<T>::pointJacobian2x3IF(const VectorT3<T>& flippedCameraObjectPoint, T* jx, T* jy) const
1278{
1279 ocean_assert(isValid());
1280 ocean_assert(jx != nullptr && jy != nullptr);
1281
1282 const T fx = focalLengthX();
1283 const T fy = focalLengthY();
1284
1285 const T u = flippedCameraObjectPoint.x();
1286 const T v = flippedCameraObjectPoint.y();
1287 const T w = flippedCameraObjectPoint.z();
1288
1289 ocean_assert(NumericT<T>::isNotEqualEps(w));
1290 const T invW = T(1) / w;
1291
1292 const T u_invW = u * invW;
1293 const T v_invW = v * invW;
1294
1295 if constexpr (tUseDistortionParameters)
1296 {
1297 T jDistX[2];
1298 T jDistY[2];
1299
1300 jacobianDistortNormalized2x2(u_invW, v_invW, radialDistortion_, tangentialDistortion_, jDistX, jDistY);
1301
1302 const T fx_jDistXx_invW = fx * jDistX[0] * invW;
1303 const T fy_jDistYx_invW = fy * jDistY[0] * invW;
1304
1305 const T fx_jDistXy_invW = fx * jDistX[1] * invW;
1306 const T fy_jDistYy_invW = fy * jDistY[1] * invW;
1307
1308 const T u_fx_jDistXx__ = u_invW * fx_jDistXx_invW + v_invW * fx_jDistXy_invW;
1309 const T u_fy_jDistYx__ = u_invW * fy_jDistYx_invW + v_invW * fy_jDistYy_invW;
1310
1311 jx[0] = fx_jDistXx_invW;
1312 jx[1] = fx_jDistXy_invW;
1313 jx[2] = -u_fx_jDistXx__;
1314
1315 jy[0] = fy_jDistYx_invW;
1316 jy[1] = fy_jDistYy_invW;
1317 jy[2] = -u_fy_jDistYx__;
1318 }
1319 else
1320 {
1321 const T fx_jDistXx_invW = fx * invW;
1322 const T fy_jDistYx_invW = fy * invW;
1323
1324 const T fx_jDistXy_invW = fx * invW;
1325 const T fy_jDistYy_invW = fy * invW;
1326
1327 const T u_fx_jDistXx__ = u_invW * fx_jDistXx_invW + v_invW * fx_jDistXy_invW;
1328 const T u_fy_jDistYx__ = u_invW * fy_jDistYx_invW + v_invW * fy_jDistYy_invW;
1329
1330 jx[0] = fx_jDistXx_invW;
1331 jx[1] = fx_jDistXy_invW;
1332 jx[2] = -u_fx_jDistXx__;
1333
1334 jy[0] = fy_jDistYx_invW;
1335 jy[1] = fy_jDistYy_invW;
1336 jy[2] = -u_fy_jDistYx__;
1337 }
1338}
1339
1340template <typename T>
1341bool FisheyeCameraT<T>::isEqual(const FisheyeCameraT<T>& fisheyeCamera, const T eps) const
1342{
1343 return cameraWidth_ == fisheyeCamera.cameraWidth_ && cameraHeight_ == fisheyeCamera.cameraHeight_ && hasDistortionParameters_ == fisheyeCamera.hasDistortionParameters_
1344 && NumericT<T>::isEqual(focalLengthX_, fisheyeCamera.focalLengthX_, eps) && NumericT<T>::isEqual(focalLengthY_, fisheyeCamera.focalLengthY_, eps)
1345 && NumericT<T>::isEqual(principalPointX_, fisheyeCamera.principalPointX_, eps) && NumericT<T>::isEqual(principalPointY_, fisheyeCamera.principalPointY_, eps)
1346 && NumericT<T>::isEqual(radialDistortion_[0], fisheyeCamera.radialDistortion_[0], eps) && NumericT<T>::isEqual(radialDistortion_[1], fisheyeCamera.radialDistortion_[1], eps)
1347 && NumericT<T>::isEqual(radialDistortion_[2], fisheyeCamera.radialDistortion_[2], eps) && NumericT<T>::isEqual(radialDistortion_[3], fisheyeCamera.radialDistortion_[3], eps)
1348 && NumericT<T>::isEqual(radialDistortion_[4], fisheyeCamera.radialDistortion_[4], eps) && NumericT<T>::isEqual(radialDistortion_[5], fisheyeCamera.radialDistortion_[5], eps)
1349 && NumericT<T>::isEqual(tangentialDistortion_[0], fisheyeCamera.tangentialDistortion_[0], eps) && NumericT<T>::isEqual(tangentialDistortion_[1], fisheyeCamera.tangentialDistortion_[1], eps);
1350}
1351
1352template <typename T>
1354{
1355 ocean_assert(NumericT<T>::isEqualEps(focalLengthX_) || NumericT<T>::isEqual(T(1) / focalLengthX_, invFocalLengthX_));
1356 ocean_assert(NumericT<T>::isEqualEps(focalLengthY_) || NumericT<T>::isEqual(T(1) / focalLengthY_, invFocalLengthY_));
1357
1358 return cameraWidth_ != 0u && cameraHeight_ != 0u;
1359}
1360
1361template <typename T>
1362bool FisheyeCameraT<T>::operator==(const FisheyeCameraT<T>& fisheyeCamera) const
1363{
1364 return cameraWidth_ == fisheyeCamera.cameraWidth_ && cameraHeight_ == fisheyeCamera.cameraHeight_
1365 && focalLengthX_ == fisheyeCamera.focalLengthX_ && focalLengthY_ == fisheyeCamera.focalLengthY_
1366 && invFocalLengthX_ == fisheyeCamera.invFocalLengthX_ && invFocalLengthY_ == fisheyeCamera.invFocalLengthY_
1367 && principalPointX_ == fisheyeCamera.principalPointX_ && principalPointY_ == fisheyeCamera.principalPointY_
1368 && hasDistortionParameters_ == fisheyeCamera.hasDistortionParameters_
1369 && memcmp(radialDistortion_, fisheyeCamera.radialDistortion_, sizeof(T) * 6) == 0
1370 && memcmp(tangentialDistortion_, fisheyeCamera.tangentialDistortion_, sizeof(T) * 2) == 0;
1371}
1372
1373template <typename T>
1374inline bool FisheyeCameraT<T>::operator!=(const FisheyeCameraT<T>& fisheyeCamera) const
1375{
1376 return !(*this == fisheyeCamera);
1377}
1378
1379template <typename T>
1381{
1382 return isValid();
1383}
1384
1385template <typename T>
1387{
1388 // x' = x_r + x_t
1389 // y' = y_r + y_t
1390
1391 // x_t = p1 * (2 * x_r^2 + radial^2) + p2 * 2 * x_r * y_r
1392 // y_t = p2 * (2 * y_r^2 + radial^2) + p1 * 2 * x_r * y_r
1393
1394 // newton-based solving for x_r, y_r:
1395 // x' = p1 * (2 * x_r^2 + radial^2) + p2 * 2 * x_r * y_r + x_r
1396 // y' = p2 * (2 * y_r^2 + radial^2) + p1 * 2 * x_r * y_r + y_r
1397
1398 const T& p1 = tangentialDistortion_[0];
1399 const T& p2 = tangentialDistortion_[1];
1400
1402 {
1403 return distortedNormalized;
1404 }
1405
1406 VectorT2<T> distortedTangentialFree(distortedNormalized);
1407
1408 for (unsigned int n = 0u; n < 2u; ++n)
1409 {
1410 const T& x_r = distortedTangentialFree.x();
1411 const T& y_r = distortedTangentialFree.y();
1412
1413 const T resultX = p1 * T(3) * x_r * x_r + p1 * y_r * y_r + T(2) * p2 * x_r * y_r + x_r - distortedNormalized.x();
1414 const T resultY = p2 * T(3) * y_r * y_r + p2 * x_r * x_r + T(2) * p1 * x_r * y_r + y_r - distortedNormalized.y();
1415
1416 const T dxx = p1 * T(6) * x_r + T(2) * p2 * y_r + T(1);
1417 const T dxy = p1 * T(2) * y_r + T(2) * p2 * x_r;
1418
1419 const T& dyx = dxy; // dxy == p2 * T(2) * y_r + T(2) * p1 * y_r;
1420 const T dyy = p2 * T(6) * y_r + T(2) * p1 * x_r + T(1);
1421
1422 VectorT2<T> delta(0, 0);
1423 SquareMatrixT2<T>(dxx, dyx, dxy, dyy).solve(VectorT2<T>(resultX, resultY), delta);
1424
1425 distortedTangentialFree -= delta;
1426
1427 if (delta.sqr() < Numeric::eps())
1428 {
1429 break;
1430 }
1431 }
1432
1433 return distortedTangentialFree;
1434}
1435
1436template <typename T>
1437OCEAN_FORCE_INLINE void FisheyeCameraT<T>::jacobianDistortNormalized2x2(const T x, const T y, const T* radialDistortion, const T* tangentialDistortion, T* jx, T* jy)
1438{
1439 ocean_assert(jx != nullptr && jy != nullptr);
1440 ocean_assert(radialDistortion != nullptr && tangentialDistortion != nullptr);
1441
1442 const T& k3 = radialDistortion[0];
1443 const T& k5 = radialDistortion[1];
1444 const T& k7 = radialDistortion[2];
1445 const T& k9 = radialDistortion[3];
1446 const T& k11 = radialDistortion[4];
1447 const T& k13 = radialDistortion[5];
1448
1449 const T& p1 = tangentialDistortion[0];
1450 const T& p2 = tangentialDistortion[1];
1451
1452 const T x2 = x * x;
1453 const T y2 = y * y;
1454
1455 const T xy2 = x2 + y2;
1456
1457 const T r = NumericT<T>::sqrt(xy2);
1458 const T r3 = r * r * r;
1459
1460 const T t = NumericT<T>::atan(r);
1461 const T t2 = t * t;
1462 const T t3 = t2 * t;
1463 const T t4 = t3 * t;
1464 const T t5 = t4 * t;
1465 const T t6 = t5 * t;
1466 const T t7 = t6 * t;
1467 const T t8 = t7 * t;
1468 const T t9 = t8 * t;
1469 const T t10 = t9 * t;
1470 const T t11 = t10 * t;
1471 const T t12 = t11 * t;
1472 const T t13 = t12 * t;
1473
1474 const T term0 = k13 * t13 + k11 * t11 + k9 * t9 + k7 * t7 + k5 * t5 + k3 * t3 + t;
1475 const T term1 = 13 * k13 * t12 + 11 * k11 * t10 + 9 * k9 * t8 + 7 * k7 * t6 + 5 * k5 * t4 + 3 * k3 * t2 + 1;
1476
1477 const T term2 = (xy2 + 1) * term0;
1478 const T term3 = r3 * (xy2 + 1);
1479 const T invTerm3 = T(1) / term3;
1480
1481 const T xDistortion_dx = (xy2 * term2 - x2 * term2 + x2 * r * term1) * invTerm3;
1482 const T xDistortion_dy = (x * term1 * y) / (xy2 * (xy2 + 1)) - (x * y * term0) / r3;
1483
1484 //const T yDistortion_dx = (y * term1 * x) / (xy2 * (xy2 + 1)) - (y * x * term0) / r3; == xDistortion_dy
1485 const T& yDistortion_dx = xDistortion_dy;
1486 const T yDistortion_dy = (xy2 * term2 - y2 * term2 + y2 * r * term1) * invTerm3;
1487
1488 const T radialDistortionFactor = term0 / r;
1489
1490 const T rx = x * radialDistortionFactor;
1491 const T ry = y * radialDistortionFactor;
1492
1493 const T xTangential_dx = 6 * p1 * rx + 2 * p2 * ry + 1;
1494 const T xTangential_dy = 2 * p1 * ry + 2 * p2 * rx;
1495
1496 // const T yTangential_dx = 2 * p2 * rx + 2 * p1 * ry; // == yTangential_dx
1497 const T& yTangential_dx = xTangential_dy;
1498 const T yTangential_dy = 6 * p2 * ry + 2 * p1 * rx + 1;
1499
1500 // chain rule
1501 // | xTangential_dx xTangential_dy | | xDistortion_dx xDistortion_dy |
1502 // | yTangential_dx yTangential_dy | * | yDistortion_dx yDistortion_dy |
1503
1504 jx[0] = xTangential_dx * xDistortion_dx + xTangential_dy * yDistortion_dx;
1505 jx[1] = xTangential_dx * xDistortion_dy + xTangential_dy * yDistortion_dy;
1506
1507 jy[0] = yTangential_dx * xDistortion_dx + yTangential_dy * yDistortion_dx;
1508 jy[1] = yTangential_dx * xDistortion_dy + yTangential_dy * yDistortion_dy;
1509}
1510
1511}
1512
1513#endif // META_OCEAN_MATH_FISHEYE_CAMERA_H
This class implements the base class for all cameras.
Definition Camera.h:54
Class representing a fisheye camera.
Definition FisheyeCamera.h:106
bool isValid() const
Returns whether this camera is valid.
Definition FisheyeCamera.h:1353
FisheyeCameraT(const unsigned int width, const unsigned int height, const T fovX)
Creates a new camera object with known field of view.
Definition FisheyeCamera.h:605
const T * radialDistortion() const
Returns the six radial distortion parameters of the camera model.
Definition FisheyeCamera.h:864
T invFocalLengthX_
The horizontal inverse focal length of the camera, with range (0, infinity)
Definition FisheyeCamera.h:557
T principalPointX() const
Returns the x-value of the principal point of the camera image in the pixel domain.
Definition FisheyeCamera.h:828
bool operator!=(const FisheyeCameraT< T > &fisheyeCamera) const
Returns whether two fisheye cameras are not identical.
Definition FisheyeCamera.h:1374
FisheyeCameraT(const FisheyeCameraT< T > &fisheyeCamera)=default
Copy constructor.
unsigned int height() const
Returns the height of the camera image.
Definition FisheyeCamera.h:816
VectorT2< T > projectToImage(const VectorT3< T > &worldObjectPoint) const
Projects a 3D object point into the camera's image of the fisheye camera.
Definition FisheyeCamera.h:1177
LineT3< T > ray(const VectorT2< T > &distortedImagePoint, const HomogenousMatrixT4< T > &world_T_camera) const
Returns a ray starting at the camera's center and intersecting a given 2D point in the image.
Definition FisheyeCamera.h:1259
VectorT2< T > principalPoint() const
Returns the coordinate of the principal point of the camera image in the pixel domain.
Definition FisheyeCamera.h:822
T Type
Definition of the used data type.
Definition FisheyeCamera.h:114
FisheyeCameraT(const unsigned int width, const unsigned int height, const ParameterConfiguration parameterConfiguration, const TParameter *parameters)
Creates a new camera object with parameters with specific configuration.
Definition FisheyeCamera.h:703
VectorT2< T > projectToImage(const HomogenousMatrixT4< T > &world_T_camera, const VectorT3< T > &worldObjectPoint) const
Projects a 3D object point into the camera's image of the fisheye camera.
Definition FisheyeCamera.h:1186
T fovY() const
Returns the field of view in x direction of the camera.
Definition FisheyeCamera.h:905
VectorT2< T > projectToImageIF(const HomogenousMatrixT4< T > &flippedCamera_T_world, const VectorT3< T > &worldObjectPoint) const
Projects a 3D object point to the 2D image plane of the fisheye camera by a given inverted (and flipp...
Definition FisheyeCamera.h:1196
const T * tangentialDistortion() const
Returns the two tangential distortion parameters of the camera model.
Definition FisheyeCamera.h:870
VectorT3< T > vector(const VectorT2< T > &distortedImagePoint, const bool makeUnitVector=true) const
Returns a unit vector (with length 1) starting at the camera's center and intersecting a given 2D poi...
Definition FisheyeCamera.h:1221
T focalLengthY_
The vertical focal length of the camera, with range (0, infinity)
Definition FisheyeCamera.h:554
T principalPointX_
The horizontal principal point of the camera, in pixels, with range [0, width())
Definition FisheyeCamera.h:563
T fovX() const
Returns the field of view in x direction of the camera.
Definition FisheyeCamera.h:876
friend class FisheyeCameraT
Definition FisheyeCamera.h:107
T focalLengthX_
The horizontal focal length of the camera, with range (0, infinity)
Definition FisheyeCamera.h:551
T radialDistortion_[6]
The six radial distortion parameters.
Definition FisheyeCamera.h:572
T inverseFocalLengthX() const
Returns the inverse horizontal focal length parameter.
Definition FisheyeCamera.h:852
VectorT3< T > vectorIF(const VectorT2< T > &distortedImagePoint, const bool makeUnitVector=true) const
Returns a normalized vector (with length 1) starting at the camera's center and intersecting a given ...
Definition FisheyeCamera.h:1240
bool hasDistortionParameters() const
Returns whether this camera object has specified distortion parameters.
Definition FisheyeCamera.h:804
T tangentialDistortion_[2]
The two tangential distortion parameters.
Definition FisheyeCamera.h:575
T principalPointY_
The vertical principal point of the camera, in pixels, with range [0, width())
Definition FisheyeCamera.h:566
T invFocalLengthY_
The vertical inverse focal length of the camera, with range (0, infinity)
Definition FisheyeCamera.h:560
bool operator==(const FisheyeCameraT< T > &fisheyeCamera) const
Returns whether two fisheye cameras are identical.
Definition FisheyeCamera.h:1362
unsigned int cameraWidth_
Width of the camera image, in pixel.
Definition FisheyeCamera.h:545
FisheyeCameraT(const unsigned int width, const unsigned int height, const T focalX, const T focalY, const T principalX, const T principalY)
Creates a new camera object without distortion parameters.
Definition FisheyeCamera.h:645
T focalLengthX() const
Returns the horizontal focal length parameter.
Definition FisheyeCamera.h:840
void copyParameters(unsigned int &width, unsigned int &height, std::vector< TParameter > &parameters, ParameterConfiguration &parameterConfiguration) const
Copies the parameters of this camera.
Definition FisheyeCamera.h:949
unsigned int cameraHeight_
Height of the camera image, in pixel.
Definition FisheyeCamera.h:548
FisheyeCameraT(const unsigned int width, const unsigned int height, const TParameter focalX, const TParameter focalY, const TParameter principalX, const TParameter principalY, const TParameter *radialDistortion, const TParameter *tangentialDistortion)
Creates a new camera object with distortion parameters.
Definition FisheyeCamera.h:674
VectorT2< T > distortNormalized(const VectorT2< T > &undistortedNormalized) const
Returns the normalized distorted position of a given undistorted normalized position.
Definition FisheyeCamera.h:1002
FisheyeCameraT< T > & operator=(const FisheyeCameraT< T > &fisheyeCamera)=default
Copy assignment operator.
VectorT2< T > undistortNormalized(const VectorT2< T > &distortedNormalized) const
Returns the normalized undistorted position of a given distorted normalized position.
Definition FisheyeCamera.h:1084
FisheyeCameraT()=default
Default constructor creating an invalid camera object.
LineT3< T > ray(const VectorT2< T > &distortedImagePoint) const
Returns a ray starting at the camera's center and intersecting a given 2D point in the image.
Definition FisheyeCamera.h:1268
bool isEqual(const FisheyeCameraT< T > &fisheyeCamera, const T eps=NumericT< T >::eps()) const
Returns whether two camera profiles are identical up to a given epsilon.
Definition FisheyeCamera.h:1341
unsigned int width() const
Returns the width of the camera image.
Definition FisheyeCamera.h:810
T fovDiagonal() const
Returns the diagonal field of view of the camera.
Definition FisheyeCamera.h:934
T focalLengthY() const
Returns the vertical focal length parameter.
Definition FisheyeCamera.h:846
static OCEAN_FORCE_INLINE void jacobianDistortNormalized2x2(const T x, const T y, const T *radialDistortion, const T *tangentialDistortion, T *jx, T *jy)
Determines the 2x2 Jacobian of distorting a normalized image point in a fisheye camera with radial an...
Definition FisheyeCamera.h:1437
FisheyeCameraT(const FisheyeCameraT< U > &fisheyeCamera)
Copy constructor for a fisheye camera with difference element data type than T.
Definition FisheyeCamera.h:580
bool hasDistortionParameters_
True, if the distortion parameters are defined.
Definition FisheyeCamera.h:569
VectorT2< T > tangentialFreeDistortion(const VectorT2< T > &distortedNormalized) const
Calculates the tangential-free distortion of a normalized (distorted) image point.
Definition FisheyeCamera.h:1386
bool isInside(const VectorT2< T > &imagePoint, const T signedBorder=T(0)) const
Returns whether a given 2D image point lies inside the camera frame.
Definition FisheyeCamera.h:991
T inverseFocalLengthY() const
Returns the inverse vertical focal length parameter.
Definition FisheyeCamera.h:858
ParameterConfiguration
Definition of individual parameter configurations.
Definition FisheyeCamera.h:120
@ PC_12_PARAMETERS
12 parameters with order: horizontal focal length, vertical focal length, horizontal principal point,...
Definition FisheyeCamera.h:162
@ PC_11_PARAMETERS_ONE_FOCAL_LENGTH
11 parameters with order: focal length (one identical value for horizontal and vertical direction),...
Definition FisheyeCamera.h:151
@ PC_3_PARAMETERS_ONE_FOCAL_LENGTH
3 parameters with order: focal length (one identical value for horizontal and vertical direction),...
Definition FisheyeCamera.h:132
@ PC_4_PARAMETERS
4 parameters with order: horizontal focal length, vertical focal length, horizontal principal point,...
Definition FisheyeCamera.h:141
@ PC_UNKNOWN
An unknown parameter configuration.
Definition FisheyeCamera.h:124
void pointJacobian2x3IF(const VectorT3< T > &flippedCameraObjectPoint, T *jx, T *jy) const
Calculates the 2x3 jacobian matrix for the 3D object point projection into the camera frame.
Definition FisheyeCamera.h:1277
T principalPointY() const
Returns the y-value of the principal point of the camera image in the pixel domain.
Definition FisheyeCamera.h:834
VectorT2< T > projectToImageIF(const VectorT3< T > &cameraFlippedObjectPoint) const
Projects a 3D object point to the 2D image plane of the fisheye camera.
Definition FisheyeCamera.h:1206
This class implements a 4x4 homogeneous transformation matrix using floating point values with the pr...
Definition HomogenousMatrix4.h:110
SquareMatrixT3< T > rotationMatrix() const
Returns the rotation matrix of the transformation.
Definition HomogenousMatrix4.h:1493
VectorT3< T > translation() const
Returns the translation of the transformation.
Definition HomogenousMatrix4.h:1381
bool isValid() const
Returns whether this matrix is a valid homogeneous transformation.
Definition HomogenousMatrix4.h:1806
This class implements an infinite line in 3D space.
Definition Line3.h:68
This class provides basic numeric functionalities.
Definition Numeric.h:57
static T atan(const T value)
Returns the arctangent of a given value.
Definition Numeric.h:1616
static bool isInf(const T value)
Returns whether a given value is positive or negative infinity.
Definition Numeric.h:3111
static T pow(const T x, const T y)
Returns x raised to the power of y.
Definition Numeric.h:1860
static T abs(const T value)
Returns the absolute value of a given value.
Definition Numeric.h:1220
static T sqrt(const T value)
Returns the square root of a given value.
Definition Numeric.h:1533
static constexpr T eps()
Returns a small epsilon.
static bool isEqual(const T first, const T second)
Returns whether two values are equal up to a small epsilon.
Definition Numeric.h:2386
static T tan(const T value)
Returns the tangent of a given value.
Definition Numeric.h:1600
static constexpr bool isEqualEps(const T value)
Returns whether a value is smaller than or equal to a small epsilon.
Definition Numeric.h:2087
This class implements a 2x2 square matrix.
Definition SquareMatrix2.h:73
bool solve(const VectorT2< T > &b, VectorT2< T > &x) const
Solve a simple 2x2 system of linear equations: Ax = b Beware: The system of linear equations is assum...
Definition SquareMatrix2.h:766
This class implements a vector with two elements.
Definition Vector2.h:96
const T & x() const noexcept
Returns the x value.
Definition Vector2.h:710
const T & y() const noexcept
Returns the y value.
Definition Vector2.h:722
T sqr() const
Returns the square of the vector length.
Definition Vector2.h:633
T length() const
Returns the length of the vector.
Definition Vector2.h:627
This class implements a vector with three elements.
Definition Vector3.h:97
const T & y() const noexcept
Returns the y value.
Definition Vector3.h:824
const T & x() const noexcept
Returns the x value.
Definition Vector3.h:812
VectorT3< T > normalized() const
Returns the normalized vector.
Definition Vector3.h:617
const T & z() const noexcept
Returns the z value.
Definition Vector3.h:836
FisheyeCameraT< float > FisheyeCameraF
Definition of a FisheyeCamera object using 'float'' as data type.
Definition FisheyeCamera.h:38
std::vector< FisheyeCamera > FisheyeCameras
Definition of a vector holding camera objects.
Definition FisheyeCamera.h:59
FisheyeCameraT< Scalar > FisheyeCamera
Definition of a FisheyeCamera object using Scalar as data type.
Definition FisheyeCamera.h:31
VectorT3< Scalar > Vector3
Definition of a 3D vector.
Definition Vector3.h:29
FisheyeCameraT< double > FisheyeCameraD
Definition of a FisheyeCamera object using 'double'' as data type.
Definition FisheyeCamera.h:45
std::vector< FisheyeCameraT< T > > FisheyeCamerasT
Definition of a typename alias for vectors with FisheyeCameraT objects.
Definition FisheyeCamera.h:53
The namespace covering the entire Ocean framework.
Definition Accessor.h:15