Ocean
Loading...
Searching...
No Matches
StereoscopicGeometry.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_GEOMETRY_STEREOSCOPIC_GEOMETRY_H
9#define META_OCEAN_GEOMETRY_STEREOSCOPIC_GEOMETRY_H
10
13
14#include "ocean/base/Accessor.h"
16
19
20namespace Ocean
21{
22
23namespace Geometry
24{
25
26/**
27 * This class implements function for stereoscopic geometry.
28 * @ingroup geometry
29 */
30class OCEAN_GEOMETRY_EXPORT StereoscopicGeometry
31{
32 public:
33
34 /**
35 * Determines the pose transformation between two given camera frames from which corresponding image point pairs are given.
36 * For each image point in the first frame a corresponding image point in the second frame must be provided.<br>
37 * Further, this function determines the 3D object points which belong to the given image points.<br>
38 * The first camera pose is expected to be the identity camera pose (a default camera in the origin, pointing towards the negative z-space with y-axis upwards.<br>
39 * The function can support outliers in the given point correspondences (to some extend).
40 * @param camera The camera profile defining the projection, must be valid
41 * @param imagePoints0 The image points located in the first frame, at least 5
42 * @param imagePoints1 The image points located in the second frame, each point must have a corresponding image point in the first frame with same index
43 * @param randomGenerator Random generator object
44 * @param world_T_camera1 The resulting camera pose for the second camera, with a default camera pose pointing towards the negative z-space with y-axis upwards
45 * @param objectPoints Optional resulting 3D locations of the object points which are visible in both camera frames (the image points are the projections of these object points)
46 * @param validIndices Optional resulting indices of the given point correspondences which are valid regarding the defined error thresholds
47 * @param maxRotationalSqrError The maximal squared pixel error between a projected object point and a corresponding image point so that the pair counts as valid for rotational camera motion
48 * @param maxArbitrarySqrError The maximal squared pixel error between a projected object point and a corresponding image point so that the pair counts as valid for arbitrary camera motion
49 * @param iterations The number of iterations that will be applied finding a better pose result
50 * @param rotationalMotionMinimalValidCorrespondencesPercent The minimal number of valid correspondences (defined as percent of the entire number of correspondences) that are necessary so that the camera motion is accepted to be pure rotational, with range [0, 1]
51 * @param baselineDistance Optional fixed baseline distance between both cameras; if positive, the translation and object points will be scaled so that the distance between both cameras equals this value, with range (0, infinity), -1 to disable
52 * @return True, if succeeded
53 */
54 static inline bool cameraPose(const AnyCamera& camera, const ConstIndexedAccessor<Vector2>& imagePoints0, const ConstIndexedAccessor<Vector2>& imagePoints1, RandomGenerator& randomGenerator, HomogenousMatrix4& world_T_camera1, Vectors3* objectPoints = nullptr, Indices32* validIndices = nullptr, const Scalar maxRotationalSqrError = Scalar(1.5 * 1.5), const Scalar maxArbitrarySqrError = Scalar(3.5 * 3.5), const unsigned int iterations = 100u, const Scalar rotationalMotionMinimalValidCorrespondencesPercent = Scalar(0.9), const Scalar baselineDistance = Scalar(-1));
55
56 /**
57 * Determines the pose transformation between two given camera frames from which corresponding image point pairs are given.
58 * For each image point in the first frame a corresponding image point in the second frame must be provided.<br>
59 * Further, this function determines the 3D object points which belong to the given image points.<br>
60 * The function can support outliers in the given point correspondences (to some extend).
61 * @param camera The camera profile defining the projection, must be valid
62 * @param imagePoints0 The image points located in the first frame, at least 5
63 * @param imagePoints1 The image points located in the second frame, each point must have a corresponding image point in the first frame with same index
64 * @param randomGenerator Random generator object
65 * @param world_T_camera0 The camera pose for the first camera, with a default camera pose pointing towards the negative z-space with y-axis upwards; if valid it will be used as initial pose, may change if gravity constraints are defined; invalid to let the function determine the initial pose for the first camera pose
66 * @param world_T_camera1 The resulting camera pose for the second camera, with a default camera pose pointing towards the negative z-space with y-axis upwards
67 * @param gravityConstraints Optional gravity constraints ensure that the resulting camera poses are aligned with gravity, with two gravity vectors, nullptr otherwise
68 * @param objectPoints Optional resulting 3D locations of the object points which are visible in both camera frames (the image points are the projections of these object points)
69 * @param validIndices Optional resulting indices of the given point correspondences which are valid regarding the defined error thresholds
70 * @param maxRotationalSqrError The maximal squared pixel error between a projected object point and a corresponding image point so that the pair counts as valid for rotational camera motion
71 * @param maxArbitrarySqrError The maximal squared pixel error between a projected object point and a corresponding image point so that the pair counts as valid for arbitrary camera motion
72 * @param iterations The number of iterations that will be applied finding a better pose result
73 * @param rotationalMotionMinimalValidCorrespondencesPercent The minimal number of valid correspondences (defined as percent of the entire number of correspondences) that are necessary so that the camera motion is accepted to be pure rotational, with range [0, 1]
74 * @param baselineDistance Optional fixed baseline distance between both cameras; if positive, the translation and object points will be scaled so that the distance between both cameras equals this value, with range (0, infinity), -1 to disable
75 * @return True, if succeeded
76 */
77 static bool cameraPose(const AnyCamera& camera, const ConstIndexedAccessor<Vector2>& imagePoints0, const ConstIndexedAccessor<Vector2>& imagePoints1, RandomGenerator& randomGenerator, HomogenousMatrix4& world_T_camera0, HomogenousMatrix4& world_T_camera1, const GravityConstraints* gravityConstraints = nullptr, Vectors3* objectPoints = nullptr, Indices32* validIndices = nullptr, const Scalar maxRotationalSqrError = Scalar(1.5 * 1.5), const Scalar maxArbitrarySqrError = Scalar(3.5 * 3.5), const unsigned int iterations = 100u, const Scalar rotationalMotionMinimalValidCorrespondencesPercent = Scalar(0.9), const Scalar baselineDistance = Scalar(-1));
78
79 /**
80 * Determines valid correspondences between 2D image points and 3D camera points for two individual camera frames concurrently.
81 * Beware: The given camera matrices are not equal to a extrinsic matrix.<br>
82 * Instead, the camera matrices are the extrinsic camera matrix flipped around the x-axis and inverted afterwards.<br>
83 * @param camera The camera profile defining the projection, must be valid
84 * @param flippedCamera0_T_world The transformation between world and the flipped first camera (a camera pointing towards the positive z-space with y-axis downwards), must be valid
85 * @param flippedCamera1_T_world The transformation between world and the flipped second camera (a camera pointing towards the positive z-space with y-axis downwards), must be valid
86 * @param objectPoints Accessor providing the 3D object points
87 * @param imagePoints0 Accessor providing the 2D image points for the first camera frame, one image point for each 3D object point
88 * @param imagePoints1 Accessor providing the 2D image points for the second camera frame, on image point for each image point in the first frame (and for each 3D object point)
89 * @param validIndices Resulting indices of all valid correspondences
90 * @param maxSqrError The maximal square pixel error between a projected 3D object point and a corresponding 2D image point to count as valid, with range [0, infinity)
91 * @param onlyFrontObjectPoints True, to accept only object points lying in front of both camera frames
92 * @param totalSqrError Optional resulting sum of all square pixel errors for all valid point correspondences (for both frames)
93 * @param minimalValidCorrespondences Optional number of valid correspondences that must be reached, otherwise the function stops without providing a useful result, with range [0, objectPoints.size()]
94 * @return True, if succeeded; False, if the function stops due to the defined minimal number of thresholds, or if no valid correspondence could be found
95 * @tparam TAccessorObjectPoints The template type of the accessor for the object points
96 * @tparam TAccessorImagePoints0 The template type of the accessor for the first image points
97 * @tparam TAccessorImagePoints1 The template type of the accessor for the second image points
98 */
99 template <typename TAccessorObjectPoints, typename TAccessorImagePoints0, typename TAccessorImagePoints1>
100 static bool determineValidCorrespondencesIF(const AnyCamera& camera, const HomogenousMatrix4& flippedCamera0_T_world, const HomogenousMatrix4& flippedCamera1_T_world, const TAccessorObjectPoints& objectPoints, const TAccessorImagePoints0& imagePoints0, const TAccessorImagePoints1& imagePoints1, Indices32& validIndices, const Scalar maxSqrError = Scalar(3.5 * 3.5), const bool onlyFrontObjectPoints = true, Scalar* totalSqrError = nullptr, const size_t minimalValidCorrespondences = 0);
101};
102
103inline bool StereoscopicGeometry::cameraPose(const AnyCamera& camera, const ConstIndexedAccessor<Vector2>& accessorImagePoints0, const ConstIndexedAccessor<Vector2>& accessorImagePoints1, RandomGenerator& randomGenerator, HomogenousMatrix4& world_T_camera1, Vectors3* objectPoints, Indices32* validIndices, const Scalar maxRotationalSqrError, const Scalar maxArbitrarySqrError, const unsigned int iterations, const Scalar rotationalMotionMinimalValidCorrespondencesPercent, const Scalar baselineDistance)
104{
105 HomogenousMatrix4 world_T_camera0(false);
106
107 if (!cameraPose(camera, accessorImagePoints0, accessorImagePoints1, randomGenerator, world_T_camera0, world_T_camera1, nullptr /*gravityConstraints*/, objectPoints, validIndices, maxRotationalSqrError, maxArbitrarySqrError, iterations, rotationalMotionMinimalValidCorrespondencesPercent, baselineDistance))
108 {
109 return false;
110 }
111
112 ocean_assert(world_T_camera0.isIdentity());
113
114 return true;
115}
116
117template <typename TAccessorObjectPoints, typename TAccessorImagePoints0, typename TAccessorImagePoints1>
118bool StereoscopicGeometry::determineValidCorrespondencesIF(const AnyCamera& camera, const HomogenousMatrix4& flippedCamera0_T_world, const HomogenousMatrix4& flippedCamera1_T_world, const TAccessorObjectPoints& objectPoints, const TAccessorImagePoints0& imagePoints0, const TAccessorImagePoints1& imagePoints1, Indices32& validIndices, const Scalar maxSqrError, const bool onlyFrontObjectPoints, Scalar* totalSqrError, const size_t minimalValidCorrespondences)
119{
120 ocean_assert(camera.isValid());
121 ocean_assert(flippedCamera0_T_world.isValid());
122 ocean_assert(flippedCamera1_T_world.isValid());
123 ocean_assert(objectPoints.size() == imagePoints0.size() && imagePoints0.size() == imagePoints1.size());
124 ocean_assert(maxSqrError >= 0);
125
126 ocean_assert(validIndices.empty());
127 validIndices.clear();
128
129 Scalar error = 0;
130
131 for (size_t n = 0u; n < imagePoints0.size(); ++n)
132 {
133 // stop if we cannot reach a specified number of valid correspondences anymore
134 if (minimalValidCorrespondences != 0 && imagePoints0.size() + validIndices.size() - n < minimalValidCorrespondences)
135 {
136 return false;
137 }
138
139 if (onlyFrontObjectPoints)
140 {
141 // we do not count this object point if it is located behind at least one camera
142 if (AnyCamera::isObjectPointInFrontIF(flippedCamera0_T_world, objectPoints[n]) == false || AnyCamera::isObjectPointInFrontIF(flippedCamera1_T_world, objectPoints[n]) == false)
143 {
144 continue;
145 }
146 }
147
148 const Scalar sqrDistance0 = camera.projectToImageIF(flippedCamera0_T_world, objectPoints[n]).sqrDistance(imagePoints0[n]);
149 const Scalar sqrDistance1 = camera.projectToImageIF(flippedCamera1_T_world, objectPoints[n]).sqrDistance(imagePoints1[n]);
150
151 if (sqrDistance0 < maxSqrError && sqrDistance1 < maxSqrError)
152 {
153 validIndices.push_back(Index32(n));
154
155 error += sqrDistance0 + sqrDistance1;
156 }
157 }
158
159 if (totalSqrError != nullptr)
160 {
161 *totalSqrError = error;
162 }
163
164 return !validIndices.empty();
165}
166
167}
168
169}
170
171#endif // META_OCEAN_GEOMETRY_STEREOSCOPIC_GEOMETRY_H
This class implements the abstract base class for all AnyCamera objects.
Definition AnyCamera.h:131
virtual VectorT2< T > projectToImageIF(const VectorT3< T > &objectPoint) const =0
Projects a 3D object point into the camera frame.
virtual bool isValid() const =0
Returns whether this camera is valid.
static bool isObjectPointInFrontIF(const HomogenousMatrixT4< T > &flippedCamera_T_world, const VectorT3< T > &objectPoint, const T epsilon=NumericT< T >::eps())
Determines whether a given 3D object point lies in front of a camera while the location of the camera...
Definition Camera.h:855
This class implements a base class for all indexed-based accessors allowing a constant reference acce...
Definition Accessor.h:241
This class implements a container allowing to define gravity constraints during e....
Definition GravityConstraints.h:63
This class implements function for stereoscopic geometry.
Definition StereoscopicGeometry.h:31
static bool determineValidCorrespondencesIF(const AnyCamera &camera, const HomogenousMatrix4 &flippedCamera0_T_world, const HomogenousMatrix4 &flippedCamera1_T_world, const TAccessorObjectPoints &objectPoints, const TAccessorImagePoints0 &imagePoints0, const TAccessorImagePoints1 &imagePoints1, Indices32 &validIndices, const Scalar maxSqrError=Scalar(3.5 *3.5), const bool onlyFrontObjectPoints=true, Scalar *totalSqrError=nullptr, const size_t minimalValidCorrespondences=0)
Determines valid correspondences between 2D image points and 3D camera points for two individual came...
Definition StereoscopicGeometry.h:118
static bool cameraPose(const AnyCamera &camera, const ConstIndexedAccessor< Vector2 > &imagePoints0, const ConstIndexedAccessor< Vector2 > &imagePoints1, RandomGenerator &randomGenerator, HomogenousMatrix4 &world_T_camera1, Vectors3 *objectPoints=nullptr, Indices32 *validIndices=nullptr, const Scalar maxRotationalSqrError=Scalar(1.5 *1.5), const Scalar maxArbitrarySqrError=Scalar(3.5 *3.5), const unsigned int iterations=100u, const Scalar rotationalMotionMinimalValidCorrespondencesPercent=Scalar(0.9), const Scalar baselineDistance=Scalar(-1))
Determines the pose transformation between two given camera frames from which corresponding image poi...
Definition StereoscopicGeometry.h:103
static bool cameraPose(const AnyCamera &camera, const ConstIndexedAccessor< Vector2 > &imagePoints0, const ConstIndexedAccessor< Vector2 > &imagePoints1, RandomGenerator &randomGenerator, HomogenousMatrix4 &world_T_camera0, HomogenousMatrix4 &world_T_camera1, const GravityConstraints *gravityConstraints=nullptr, Vectors3 *objectPoints=nullptr, Indices32 *validIndices=nullptr, const Scalar maxRotationalSqrError=Scalar(1.5 *1.5), const Scalar maxArbitrarySqrError=Scalar(3.5 *3.5), const unsigned int iterations=100u, const Scalar rotationalMotionMinimalValidCorrespondencesPercent=Scalar(0.9), const Scalar baselineDistance=Scalar(-1))
Determines the pose transformation between two given camera frames from which corresponding image poi...
bool isValid() const
Returns whether this matrix is a valid homogeneous transformation.
Definition HomogenousMatrix4.h:1806
bool isIdentity() const
Returns whether this matrix is an identity matrix.
Definition HomogenousMatrix4.h:1812
This class implements a generator for random numbers.
Definition RandomGenerator.h:42
std::vector< Index32 > Indices32
Definition of a vector holding 32 bit index values.
Definition Base.h:96
uint32_t Index32
Definition of a 32 bit index value.
Definition Base.h:84
float Scalar
Definition of a scalar type.
Definition Math.h:129
std::vector< Vector3 > Vectors3
Definition of a vector holding Vector3 objects.
Definition Vector3.h:65
The namespace covering the entire Ocean framework.
Definition Accessor.h:15