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 * @return True, if succeeded
52 */
53 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));
54
55 /**
56 * Determines the pose transformation between two given camera frames from which corresponding image point pairs are given.
57 * For each image point in the first frame a corresponding image point in the second frame must be provided.<br>
58 * Further, this function determines the 3D object points which belong to the given image points.<br>
59 * The function can support outliers in the given point correspondences (to some extend).
60 * @param camera The camera profile defining the projection, must be valid
61 * @param imagePoints0 The image points located in the first frame, at least 5
62 * @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
63 * @param randomGenerator Random generator object
64 * @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
65 * @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
66 * @param gravityConstraints Optional gravity constraints ensure that the resulting camera poses are aligned with gravity, with two gravity vectors, nullptr otherwise
67 * @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)
68 * @param validIndices Optional resulting indices of the given point correspondences which are valid regarding the defined error thresholds
69 * @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
70 * @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
71 * @param iterations The number of iterations that will be applied finding a better pose result
72 * @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]
73 * @return True, if succeeded
74 */
75 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));
76
77 /**
78 * Determines valid correspondences between 2D image points and 3D camera points for two individual camera frames concurrently.
79 * Beware: The given camera matrices are not equal to a extrinsic matrix.<br>
80 * Instead, the camera matrices are the extrinsic camera matrix flipped around the x-axis and inverted afterwards.<br>
81 * @param camera The camera profile defining the projection, must be valid
82 * @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
83 * @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
84 * @param objectPoints Accessor providing the 3D object points
85 * @param imagePoints0 Accessor providing the 2D image points for the first camera frame, one image point for each 3D object point
86 * @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)
87 * @param validIndices Resulting indices of all valid correspondences
88 * @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)
89 * @param onlyFrontObjectPoints True, to accept only object points lying in front of both camera frames
90 * @param totalSqrError Optional resulting sum of all square pixel errors for all valid point correspondences (for both frames)
91 * @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()]
92 * @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
93 * @tparam TAccessorObjectPoints The template type of the accessor for the object points
94 * @tparam TAccessorImagePoints0 The template type of the accessor for the first image points
95 * @tparam TAccessorImagePoints1 The template type of the accessor for the second image points
96 */
97 template <typename TAccessorObjectPoints, typename TAccessorImagePoints0, typename TAccessorImagePoints1>
98 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);
99};
100
101inline 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)
102{
103 HomogenousMatrix4 world_T_camera0(false);
104
105 if (!cameraPose(camera, accessorImagePoints0, accessorImagePoints1, randomGenerator, world_T_camera0, world_T_camera1, nullptr /*gravityConstraints*/, objectPoints, validIndices, maxRotationalSqrError, maxArbitrarySqrError, iterations, rotationalMotionMinimalValidCorrespondencesPercent))
106 {
107 return false;
108 }
109
110 ocean_assert(world_T_camera0.isIdentity());
111
112 return true;
113}
114
115template <typename TAccessorObjectPoints, typename TAccessorImagePoints0, typename TAccessorImagePoints1>
116bool 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)
117{
118 ocean_assert(camera.isValid());
119 ocean_assert(flippedCamera0_T_world.isValid());
120 ocean_assert(flippedCamera1_T_world.isValid());
121 ocean_assert(objectPoints.size() == imagePoints0.size() && imagePoints0.size() == imagePoints1.size());
122 ocean_assert(maxSqrError >= 0);
123
124 ocean_assert(validIndices.empty());
125 validIndices.clear();
126
127 Scalar error = 0;
128
129 for (size_t n = 0u; n < imagePoints0.size(); ++n)
130 {
131 // stop if we cannot reach a specified number of valid correspondences anymore
132 if (minimalValidCorrespondences != 0 && imagePoints0.size() + validIndices.size() - n < minimalValidCorrespondences)
133 {
134 return false;
135 }
136
137 if (onlyFrontObjectPoints)
138 {
139 // we do not count this object point if it is located behind at least one camera
140 if (AnyCamera::isObjectPointInFrontIF(flippedCamera0_T_world, objectPoints[n]) == false || AnyCamera::isObjectPointInFrontIF(flippedCamera1_T_world, objectPoints[n]) == false)
141 {
142 continue;
143 }
144 }
145
146 const Scalar sqrDistance0 = camera.projectToImageIF(flippedCamera0_T_world, objectPoints[n]).sqrDistance(imagePoints0[n]);
147 const Scalar sqrDistance1 = camera.projectToImageIF(flippedCamera1_T_world, objectPoints[n]).sqrDistance(imagePoints1[n]);
148
149 if (sqrDistance0 < maxSqrError && sqrDistance1 < maxSqrError)
150 {
151 validIndices.push_back(Index32(n));
152
153 error += sqrDistance0 + sqrDistance1;
154 }
155 }
156
157 if (totalSqrError != nullptr)
158 {
159 *totalSqrError = error;
160 }
161
162 return !validIndices.empty();
163}
164
165}
166
167}
168
169#endif // META_OCEAN_GEOMETRY_STEREOSCOPIC_GEOMETRY_H
This class implements the abstract base class for all AnyCamera objects.
Definition AnyCamera.h:130
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:811
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 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))
Determines the pose transformation between two given camera frames from which corresponding image poi...
Definition StereoscopicGeometry.h:101
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:116
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))
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