Ocean
Loading...
Searching...
No Matches
HemiCube.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_CV_DETECTOR_HEMI_CUBE_H
9#define META_OCEAN_CV_DETECTOR_HEMI_CUBE_H
10
12
13#include "ocean/base/Frame.h"
14
16
18#include "ocean/math/Vector2.h"
19
20namespace Ocean
21{
22
23namespace CV
24{
25
26namespace Detector
27{
28
29/**
30 * Data structure used for efficient grouping to 2D line segments
31 * This data structure is inspired by and derived from the HemiCube of Rick Szeliski and Daniel Scharstein.
32 * @ingroup cvdetector
33 */
34class OCEAN_CV_DETECTOR_EXPORT HemiCube
35{
36 public:
37
38 /// The location of a line in the cube map is defined as the triple (binX, binY, faceIndex), faceIndex = {0, 1, 2}
40
41 /**
42 * Helper to compute hash values for map indices
43 */
45 {
46 /**
47 * Compute hash value for a map index
48 * @param mapIndex The map index to be hashed
49 * @return Hash value of the input map index
50 */
51 size_t operator()(const MapIndex& mapIndex) const noexcept;
52 };
53
54 /// The actual cube map: maps a line to a bin (set of line indices)
55 typedef std::unordered_map<MapIndex, IndexSet32, MapIndexHash> Map;
56
57 public:
58
59 /**
60 * Default constructor
61 */
62 HemiCube() = default;
63
64 /**
65 * Constructor
66 * @param bins Number of bins along one dimension (cube), range: [1, infinity) (suggested range: [1, 20])
67 * @param imageWidth Width of the image in which the above lines were found, range: [1, infinity)
68 * @param imageHeight Height of the image in which the above lines were found, range: [1, infinity)
69 * @param focalLength Focal length of the original camera; it's used to convert 2D image points into 3D rays; if unknown use something like 1.0; range: (0, infinity)
70 */
71 HemiCube(const unsigned int bins, const unsigned int imageWidth, const unsigned int imageHeight, const Scalar focalLength);
72
73 /**
74 * Check if the Hemi cube is fully initialized
75 * @return True if the Hemi cube has been fully initialized, otherwise false
76 */
77 inline bool isValid() const;
78
79 /**
80 * Add a line to the Hemi cube
81 * The line will be added as-is, it will not be merged with similar lines in the Hemi cube
82 * @note There are no checks for duplicate lines.
83 * @param newLine Line to be added to the map, line must be valid
84 */
85 inline void insert(const FiniteLine2& newLine);
86
87 /**
88 * Add multiple lines to the Hemi cube
89 * The lines will be added as-is, they will not be merged with similar lines in the Hemi cube
90 * The are no checks for duplicate lines.
91 * @param lines Lines to be added to the map, must be valid
92 */
93 inline void insert(const FiniteLines2& lines);
94
95 /**
96 * Merge a similar lines in set of line segments (brute-force search/no use of Hemi cubes, slow)
97 * Lines that cannot be merged will be added to the output as-is.
98 * @param lines Lines to be merged
99 * @param maxLineDistance Maximum allowed distance of the end-points of one line segment to infinite line of another line segment in order to be considered as collinear, range: [0, infinity)
100 * @param maxLineGap Maximum allowed distance between a pair of collinear line segments in order to be considered mergeable, range: [0, infinity)
101 * @param mapping If specified, this will be the mapping of indices of the lines in parameter `lines` to lines in the return value (i.e. input line i merged into output line j), identical size as parameter `lines`, will be ignored if set to `nullptr`
102 * @param cosAngle Cosine of the maximum angle that is allowed in order for the two line segments to be considered parallel; default: cos(weakEps()), i.e., approx. one, range: [0, 1]
103 * @return The merged lines
104 */
105 static FiniteLines2 mergeGreedyBruteForce(const FiniteLines2& lines, const Scalar maxLineDistance, const Scalar maxLineGap, Indices32* mapping = nullptr, const Scalar cosAngle = Numeric::cos(Numeric::weakEps()));
106
107 /**
108 * Merge a similar lines in set of line segments
109 * Lines will be added to a Hemi cube internally. For each new input line, retrieve similar lines from the Hemi cube and try to merge it. Then update the Hemi cube.
110 * Lines that cannot be merged will be added to the output as-is.
111 * @param lines Lines to be merged
112 * @param maxLineDistance Maximum allowed distance of the end-points of one line segment to infinite line of another line segment in order to be considered as collinear, range: [0, infinity)
113 * @param maxLineGap Maximum allowed distance between a pair of collinear line segments in order to be considered mergeable
114 * @param mapping If specified, this will be the mapping of indices of the lines in parameter `lines` to lines in the return value (i.e. input line i merged into output line j), identical size as parameter `lines`, will be ignored if set to `nullptr`
115 * @param cosAngle Cosine of the maximum angle that is allowed in order for the two line segments to be considered parallel; default: cos(weakEps()), i.e., approx. one, range: [0, 1]
116 */
117 void merge(const FiniteLines2& lines, const Scalar maxLineDistance, const Scalar maxLineGap, Indices32* mapping = nullptr, const Scalar cosAngle = Numeric::cos(Numeric::weakEps()));
118
119 /**
120 * Compute line segment that minimizes the distances to the endpoints of the input line segments
121 * Computes the infinite line that minimizes the weighted distances to the endpoints of the input line segments, `line0` and `line1`.
122 * The weights are computed as `w_i = len(line_i) / (len(line0) + len(line1))`
123 * The endpoints of the input lines are then projected on the infinite line to generate a new line segments such that the resulting length is maximized.
124 * @param line0 First line segment
125 * @param line1 Second line segment
126 * @return Merged line segment
127 */
128 static FiniteLine2 fuse(const FiniteLine2& line0, const FiniteLine2& line1);
129
130 /**
131 * Find similar lines in Hemi cube
132 * @param line Line for which similar lines are searched, must be valid
133 * @param radius Search radius in the Hemi cube, does not search across different faces of the Hemi cube, range: [1, infinity)
134 * @return Indices of the lines in `linesInMap` that are similar to input parameter `line`.
135 * @sa lines(), operator[]()
136 */
137 IndexSet32 find(const FiniteLine2& line, const Scalar radius = Scalar(1)) const;
138
139 /**
140 * Return the number of lines stored in the Hemi cube
141 * @return Number of lines stored in the Hemi cube
142 */
143 inline size_t size() const;
144
145 /**
146 * Return the number of bins in the Hemi cube which actually contain data
147 * @return Number of non-empty bins
148 */
149 inline size_t nonEmptyBins() const;
150
151 /**
152 * Clear this Hemi cube
153 */
154 inline void clear();
155
156 /**
157 * Get a reference to the lines stored in the Hemi cube
158 * @return All lines in the Hemi cube
159 * @sa find()
160 */
161 inline const FiniteLines2& lines() const;
162
163 /**
164 * Returns a reference to the internal map of lines indices
165 * @return The map with line indices
166 */
167 const Map& map() const;
168
169 /**
170 * Get a const reference to a line in the Hemi cube
171 * @param index Index of a line in the Hemi cube, range: [0, HemiCube::size())
172 * @return Const reference a line in the Hemi cube
173 * @sa find()
174 */
175 inline const FiniteLine2& operator[](const unsigned int index) const;
176
177 /**
178 * Get a reference to a line in the Hemi cube
179 * @param index Index of a line in the Hemi cube, range: [0, HemiCube::size())
180 * @return Reference a line in the Hemi cube
181 * @sa find()
182 */
183 inline FiniteLine2& operator[](const unsigned int index);
184
185 protected:
186
187 /**
188 * Given the map index of a line, compute its pixel location in a image representation of the cube map
189 * @param mapIndex The map index of a line segment with range [0, bins - 1]x[0, bins - 1]x[0, 2]
190 * @return The pixel location of the line segment in the cube map
191 * @sa computeMapIndex()
192 */
193 inline PixelPosition hemiCubeCoordinatesFrom(const MapIndex& mapIndex) const;
194
195 /**
196 * Given a 2D line segment, compute its location (map index) in the cube map
197 * @param line The line for which its map index is computed
198 * @return The map index of the input line
199 */
201
202 /**
203 * For a given 2D line segment compute its representation as a line equation (3D vector)
204 * The line equation is in normalized coordinates rather than image coordinates
205 * The line equation is the normal of the plane that intersects the line segment and the camera's center of projection
206 * @param line Line for which a line equation is computed
207 * @return The line equation represention of input line
208 * @tparam tScale If true, the line equation (3D vector) will be scaled to point to a face of the cube map, otherwise no scaling will be applied
209 */
210 template <bool tScale>
211 Vector3 lineEquationFrom(const FiniteLine2& line) const;
212
213 /**
214 * Compute the point on the ray at a specific depth (3D ray which points from the center of projection to the image point on the project plane)
215 * @param point Point that is converted into a 3D ray
216 * @return The 3D ray corresponding to the input point
217 */
218 inline Vector3 rayFrom(const Vector2& point) const;
219
220 /**
221 * Update a line segment stored in the Hemi cube
222 * Updates the line segment at index `index` and its map index in the Hemi cube.
223 * @param index Index of a line in the Hemi cube, range: [0, HemiCube::size())
224 * @param updatedLine Updated line segment that will be stored at index `index` in the Hemi cube
225 */
226 void updateLine(unsigned int index, const FiniteLine2& updatedLine);
227
228 protected:
229
230 /// All lines which are represented by their indices in the map
232
233 /// Width of the image in which the lines in the cube map have been found; used to convert 2D image points into 3D rays
234 unsigned int imageWidth_ = 0u;
235
236 /// Height of the image in which the lines in the cube map have been found; used to convert 2D image points into 3D rays
237 unsigned int imageHeight_ = 0u;
238
239 /// Principal point of the image in which the lines have have been found; using the image center should work just as fine
240 Vector2 principalPoint_ = Vector2(Scalar(0), Scalar(0));
241
242 /// Focal length of the original camera; used convert 2D image points into 3D rays.
243 Scalar focalLength_ = Scalar(0);
244
245 /// The actual map data structure
247
248 /// Number of bins along one dimension (cube)
249 unsigned int numberBins_ = 0u;
250};
251
252inline bool HemiCube::isValid() const
253{
255}
256
257inline void HemiCube::insert(const FiniteLine2& newLine)
258{
259 ocean_assert(isValid());
260 ocean_assert(newLine.isValid());
261
262 // Find or create the bin into which the new line will be placed
263 IndexSet32& bin = map_[mapIndexFrom(newLine)];
264
265 const unsigned int newLineIndex = (unsigned int)linesInMap_.size();
266 ocean_assert(bin.find(newLineIndex) == bin.end());
267
268 bin.insert(newLineIndex);
269 linesInMap_.emplace_back(newLine);
270}
271
272inline void HemiCube::insert(const FiniteLines2& lines)
273{
274 for (const FiniteLine2& line : lines)
275 {
276 insert(line);
277 }
278}
279
280inline size_t HemiCube::size() const
281{
282 return linesInMap_.size();
283}
284
285inline size_t HemiCube::nonEmptyBins() const
286{
287 return map_.size();
288}
289
290inline void HemiCube::clear()
291{
292 linesInMap_.clear();
293 map_.clear();
294}
295
296inline const FiniteLines2& HemiCube::lines() const
297{
298 return linesInMap_;
299}
300
301inline const HemiCube::Map& HemiCube::map() const
302{
303 return map_;
304}
305
306inline const FiniteLine2& HemiCube::operator[](const unsigned int index) const
307{
308 ocean_assert(index < (unsigned int)linesInMap_.size());
309 return linesInMap_[index];
310}
311
312inline FiniteLine2& HemiCube::operator[](const unsigned int index)
313{
314 ocean_assert(index < (unsigned int)linesInMap_.size());
315 return linesInMap_[index];
316}
317
319{
320 ocean_assert(isValid());
321 ocean_assert(mapIndex[0] < numberBins_ && mapIndex[1] < numberBins_ && mapIndex[2] <= 2u);
322 return CV::PixelPosition(mapIndex[2] * numberBins_ + mapIndex[0], mapIndex[1]);
323}
324
325template <bool tScale>
327{
328 ocean_assert(line.isValid());
329 const Vector3 ray0 = rayFrom(line.point0());
330 const Vector3 ray1 = rayFrom(line.point1());
331 ocean_assert(Numeric::isNotEqualEps(ray0.length()));
332 ocean_assert(Numeric::isNotEqualEps(ray1.length()));
333
334 const Vector3 lineEquation = ray0.cross(ray1);
335 ocean_assert(Numeric::isNotEqualEps(lineEquation.length()));
336
337 if constexpr (tScale)
338 {
339 const Scalar maxValue = std::max(std::abs(lineEquation[0]), std::max(std::abs(lineEquation[1]), std::abs(lineEquation[2])));
340 ocean_assert(Numeric::isNotEqualEps(maxValue));
341 return lineEquation * (Scalar(1.0) / maxValue);
342 }
343
344 return lineEquation;
345}
346
348{
349 const Scalar inPixels = Scalar(0.5) * Scalar(std::max(imageWidth_, imageHeight_));
350 return Vector3(point - principalPoint_, focalLength_ * inPixels);
351}
352
353}
354
355}
356
357}
358
359#endif // META_OCEAN_CV_DETECTOR_HEMI_CUBE_H
Data structure used for efficient grouping to 2D line segments This data structure is inspired by and...
Definition HemiCube.h:35
Vector2 principalPoint_
Principal point of the image in which the lines have have been found; using the image center should w...
Definition HemiCube.h:240
size_t size() const
Return the number of lines stored in the Hemi cube.
Definition HemiCube.h:280
Vector3 rayFrom(const Vector2 &point) const
Compute the point on the ray at a specific depth (3D ray which points from the center of projection t...
Definition HemiCube.h:347
unsigned int numberBins_
Number of bins along one dimension (cube)
Definition HemiCube.h:249
const FiniteLine2 & operator[](const unsigned int index) const
Get a const reference to a line in the Hemi cube.
Definition HemiCube.h:306
Map map_
The actual map data structure.
Definition HemiCube.h:246
HemiCube()=default
Default constructor.
std::unordered_map< MapIndex, IndexSet32, MapIndexHash > Map
The actual cube map: maps a line to a bin (set of line indices)
Definition HemiCube.h:55
bool isValid() const
Check if the Hemi cube is fully initialized.
Definition HemiCube.h:252
size_t nonEmptyBins() const
Return the number of bins in the Hemi cube which actually contain data.
Definition HemiCube.h:285
MapIndex mapIndexFrom(const FiniteLine2 &line) const
Given a 2D line segment, compute its location (map index) in the cube map.
FiniteLines2 linesInMap_
All lines which are represented by their indices in the map.
Definition HemiCube.h:231
PixelPosition hemiCubeCoordinatesFrom(const MapIndex &mapIndex) const
Given the map index of a line, compute its pixel location in a image representation of the cube map.
Definition HemiCube.h:318
VectorT3< unsigned int > MapIndex
The location of a line in the cube map is defined as the triple (binX, binY, faceIndex),...
Definition HemiCube.h:39
Vector3 lineEquationFrom(const FiniteLine2 &line) const
For a given 2D line segment compute its representation as a line equation (3D vector) The line equati...
Definition HemiCube.h:326
unsigned int imageWidth_
Width of the image in which the lines in the cube map have been found; used to convert 2D image point...
Definition HemiCube.h:234
const FiniteLines2 & lines() const
Get a reference to the lines stored in the Hemi cube.
Definition HemiCube.h:296
HemiCube(const unsigned int bins, const unsigned int imageWidth, const unsigned int imageHeight, const Scalar focalLength)
Constructor.
void insert(const FiniteLine2 &newLine)
Add a line to the Hemi cube The line will be added as-is, it will not be merged with similar lines in...
Definition HemiCube.h:257
unsigned int imageHeight_
Height of the image in which the lines in the cube map have been found; used to convert 2D image poin...
Definition HemiCube.h:237
void clear()
Clear this Hemi cube.
Definition HemiCube.h:290
void merge(const FiniteLines2 &lines, const Scalar maxLineDistance, const Scalar maxLineGap, Indices32 *mapping=nullptr, const Scalar cosAngle=Numeric::cos(Numeric::weakEps()))
Merge a similar lines in set of line segments Lines will be added to a Hemi cube internally.
IndexSet32 find(const FiniteLine2 &line, const Scalar radius=Scalar(1)) const
Find similar lines in Hemi cube.
const Map & map() const
Returns a reference to the internal map of lines indices.
Definition HemiCube.h:301
Scalar focalLength_
Focal length of the original camera; used convert 2D image points into 3D rays.
Definition HemiCube.h:243
static FiniteLine2 fuse(const FiniteLine2 &line0, const FiniteLine2 &line1)
Compute line segment that minimizes the distances to the endpoints of the input line segments Compute...
void updateLine(unsigned int index, const FiniteLine2 &updatedLine)
Update a line segment stored in the Hemi cube Updates the line segment at index index and its map ind...
static FiniteLines2 mergeGreedyBruteForce(const FiniteLines2 &lines, const Scalar maxLineDistance, const Scalar maxLineGap, Indices32 *mapping=nullptr, const Scalar cosAngle=Numeric::cos(Numeric::weakEps()))
Merge a similar lines in set of line segments (brute-force search/no use of Hemi cubes,...
bool isValid() const
Returns whether this line has valid parameters.
Definition FiniteLine2.h:622
const VectorT2< T > & point0() const
Returns the first end point of the line.
Definition FiniteLine2.h:348
const VectorT2< T > & point1() const
Returns the second end point of the line.
Definition FiniteLine2.h:354
static constexpr bool isNotEqualEps(const T value)
Returns whether a value is not smaller than or equal to a small epsilon.
Definition Numeric.h:2237
This class implements a vector with three elements.
Definition Vector3.h:97
VectorT3< T > cross(const VectorT3< T > &vector) const
Returns the cross product of two vectors.
Definition Vector3.h:609
T length() const
Returns the length of the vector.
Definition Vector3.h:676
std::set< Index32 > IndexSet32
Definition of a set holding 32 bit indices.
Definition Base.h:114
std::vector< Index32 > Indices32
Definition of a vector holding 32 bit index values.
Definition Base.h:96
PixelPositionT< unsigned int > PixelPosition
Definition of the default PixelPosition object with a data type allowing only positive coordinate val...
Definition PixelPosition.h:34
float Scalar
Definition of a scalar type.
Definition Math.h:129
VectorT3< Scalar > Vector3
Definition of a 3D vector.
Definition Vector3.h:29
std::vector< FiniteLine2 > FiniteLines2
Definition of a vector holding FiniteLine2 objects.
Definition FiniteLine2.h:57
VectorT2< Scalar > Vector2
Definition of a 2D vector.
Definition Vector2.h:28
The namespace covering the entire Ocean framework.
Definition Accessor.h:15
Helper to compute hash values for map indices.
Definition HemiCube.h:45
size_t operator()(const MapIndex &mapIndex) const noexcept
Compute hash value for a map index.