Ocean
Loading...
Searching...
No Matches
FREAKDescriptor.h
Go to the documentation of this file.
1/*
2 * Portions 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/*
9 * This file contains derived work from
10 *
11 * https://github.com/opencv/opencv_contrib/blob/70b5d209a85b33096312bc6498c4553c1b9112dc/modules/xfeatures2d/src/freak.cpp
12 *
13 * Copyright (C) 2011-2012 Signal processing laboratory 2, EPFL,
14 * Kirell Benzi (kirell.benzi@epfl.ch),
15 * Raphael Ortiz (raphael.ortiz@a3.epfl.ch)
16 * Alexandre Alahi (alexandre.alahi@epfl.ch)
17 * and Pierre Vandergheynst (pierre.vandergheynst@epfl.ch)
18 *
19 * Licensed under the Apache License, Version 2.0 (the "License");
20 * you may not use this file except in compliance with the License.
21 * You may obtain a copy of the License at
22 *
23 * https://github.com/opencv/opencv_contrib/blob/70b5d209a85b33096312bc6498c4553c1b9112dc/LICENSE
24 *
25 * Unless required by applicable law or agreed to in writing, software
26 * distributed under the License is distributed on an "AS IS" BASIS,
27 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
28 * See the License for the specific language governing permissions and
29 * limitations under the License.
30 */
31
32#ifndef META_OCEAN_CV_DETECTOR_FREAK_DESCRIPTOR_H
33#define META_OCEAN_CV_DETECTOR_FREAK_DESCRIPTOR_H
34
39
43
46
48
49#include <Eigen/Core>
50#include <Eigen/Dense>
51
52namespace Ocean
53{
54
55namespace CV
56{
57
58namespace Detector
59{
60
61/// Forward-declaration of the descriptor class.
62template <size_t tSize>
63class FREAKDescriptorT;
64
65/// Typedef for the 32-bytes long FREAK descriptor
67
68/// Vector of 32-bytes long FREAK descriptors
69using FREAKDescriptors32 = std::vector<FREAKDescriptor32>;
70
71/// Typedef for the 64-bytes long FREAK descriptor
73
74/// Vector of 64-bytes long FREAK descriptors
75using FREAKDescriptors64 = std::vector<FREAKDescriptor64>;
76
77/**
78 * Implementation of the Fast Retina Keypoint descriptors (FREAK).
79 * @tparam tSize The length of the FREAK descriptor in bytes. Set of valid values: {32, 64}
80 * @ingroup cvdetector
81 */
82template <size_t tSize>
84{
85 static_assert(tSize == 32 || tSize == 64, "Invalid size!");
86
87 public:
88
89 /// Typedef for the selected pixel type. This might be turned into a template parameter at some point.
90 using PixelType = std::uint8_t;
91
92 /// The Jacobian of the projection matrix at a specific 3D location (ray from projection center to pixel in image plane)
93 using PointJacobianMatrix2x3 = Eigen::Matrix<float, 2, 3>;
94
95 /// Single-level FREAK descriptor.
96 using SinglelevelDescriptorData = std::array<PixelType, tSize>;
97
98 /// Multi-level FREAK descriptor data; if possible, this implementation computes the descriptor at three different scales: 1.0, 1.2599, and 1.5874, cf. `descriptorLevels()`
99 using MultilevelDescriptorData = std::array<SinglelevelDescriptorData, 3>;
100
101 /**
102 * The camera data that is required to compute the FREAK descriptor of a image point
103 */
105 {
106 /// The normalized ray that points from projection center to a 2D pixel location in the image plane of camera (this is in inverted-flipped coordinates)
107 Eigen::Vector3f unprojectRayIF;
108
109 /// The 2-by-3 Jacobian matrix of a projection matrix wrt. to the above 2D pixel location in the image plane of a camera (this is in inverted-flipped coordinates)
111 };
112
113 /**
114 * Base class to compute the Jacobian of the camera projection matrix wrt. to a 2D point and the corresponding unprojection ray of an arbitrary camera model
115 */
117 {
118 public:
119
120 /**
121 * Default destructor
122 */
123 virtual ~CameraDerivativeFunctor() = default;
124
125 /**
126 * Purely virtual function to compute the camera derivative data; has to be implemented in any derived class
127 * @param point A 2D point in the image plane of a camera
128 * @param pointPyramidLevel Level of the frame pyramid at which the input point is located, range: [0, supportedPyramidLevels())
129 * @return The 2x3 Jacobian matrix of the projection matrix and the unprojection ray (normalized to length 1)
130 */
131 virtual FREAKDescriptorT<tSize>::CameraDerivativeData computeCameraDerivativeData(const Eigen::Vector2f& point, const unsigned int pointPyramidLevel = 0u) const = 0;
132
133 /**
134 * Returns the maximum number of pyramid levels for which camera derivative data can be computed
135 * @return Number of pyramid levels for which camera derivative data can be computed, range: [1, infinity)
136 */
137 virtual unsigned int supportedPyramidLevels() const = 0;
138 };
139
140 /**
141 * Functor that can be used to obtain the 2x3 Jacobian of the camera projection matrix wrt. to a 2D point and the corresponding unprojection ray of a pinhole camera
142 */
144 {
145 public:
146
147 /**
148 * Constructs a valid functor to compute pinhole camera derivative data
149 * @param pinholeCamera A pinhole camera that is defined at the finest layer of an image pyramid, must be valid
150 * @param pyramidLevels Number of pyramid levels that this functor instance will be prepared for, range: [1, infinity), note: actual supported number may be lower depending on the image resolution
151 */
152 inline PinholeCameraDerivativeFunctor(const PinholeCamera& pinholeCamera, const unsigned int pyramidLevels = 1u);
153
154 /**
155 * Computes the point Jacobian of the projection matrix and unprojection ray for a specified point
156 * @param point A 2D point in the image plane of a camera
157 * @param pointPyramidLevel Level of the frame pyramid at which the input point is located, range: [0, supportedPyramidLevels())
158 * @return The 2x3 Jacobian matrix of the projection matrix and the unprojection ray (normalized to length 1)
159 */
160 FREAKDescriptorT<tSize>::CameraDerivativeData computeCameraDerivativeData(const Eigen::Vector2f& point, const unsigned int pointPyramidLevel) const override;
161
162 /**
163 * Returns the maximum number of pyramid levels for which camera derivative data can be computed
164 * @return Number of pyramid levels for which camera derivative data can be computed, range: [1, infinity)
165 */
166 unsigned int supportedPyramidLevels() const override;
167
168 /**
169 * Computes the point Jacobian of the projection matrix and unprojection ray for a specified point
170 * @param pinholeCamera The pinhole camera which is used to compute the 2x3 Jacobian of its projection matrix
171 * @param point A 2D point in the image plane of the camera
172 * @return The 2x3 Jacobian matrix of the projection matrix and the unprojection ray (normalized to length 1)
173 */
174 static typename FREAKDescriptorT<tSize>::CameraDerivativeData computeCameraDerivativeData(const PinholeCamera& pinholeCamera, const Eigen::Vector2f& point);
175
176 protected:
177
178 /// The camera instance used to compute the Jacobian matrix and unprojection ray at the finest layer of an image pyramid
180 };
181
182 /**
183 * Functor that can be used to obtain the 2x3 Jacobian of the camera projection matrix wrt. to a 2D point and the corresponding unprojection ray of a camera
184 */
186 {
187 public:
188
189 /**
190 * Constructs a valid functor to compute pinhole camera derivative data
191 * @param camera A pinhole camera that is defined at the finest layer of an image pyramid, must be valid
192 * @param pyramidLevels Number of pyramid levels that this functor instance will be prepared for, range: [1, infinity), note: actual supported number may be lower depending on the image resolution
193 */
194 inline AnyCameraDerivativeFunctor(const SharedAnyCamera& camera, const unsigned int pyramidLevels = 1u);
195
196 /**
197 * Computes the point Jacobian of the projection matrix and unprojection ray for a specified point
198 * @param point A 2D point in the image plane of a camera
199 * @param pointPyramidLevel Level of the frame pyramid at which the input point is located, range: [0, supportedPyramidLevels())
200 * @return The 2x3 Jacobian matrix of the projection matrix and the unprojection ray (normalized to length 1)
201 */
202 FREAKDescriptorT<tSize>::CameraDerivativeData computeCameraDerivativeData(const Eigen::Vector2f& point, const unsigned int pointPyramidLevel) const override;
203
204 /**
205 * Returns the maximum number of pyramid levels for which camera derivative data can be computed
206 * @return Number of pyramid levels for which camera derivative data can be computed, range: [1, infinity)
207 */
208 unsigned int supportedPyramidLevels() const override;
209
210 /**
211 * Computes the point Jacobian of the projection matrix and unprojection ray for a specified point
212 * @param camera The camera which is used to compute the 2x3 Jacobian of its projection matrix
213 * @param point A 2D point in the image plane of the camera
214 * @return The 2x3 Jacobian matrix of the projection matrix and the unprojection ray (normalized to length 1)
215 */
216 static typename FREAKDescriptorT<tSize>::CameraDerivativeData computeCameraDerivativeData(const AnyCamera& camera, const Eigen::Vector2f& point);
217
218 protected:
219
220 /// The camera instance used to compute the Jacobian matrix and unprojection ray at the finest layer of an image pyramid
222 };
223
224 public:
225
226 /**
227 * Creates a new and invalid FREAK descriptor object
228 */
229 FREAKDescriptorT() = default;
230
231 /**
232 * Creates a new FREAK descriptor object by copying from an existing one
233 */
235
236 /**
237 * Creates a new FREAK descriptor object that will be initialized to all zeros
238 * @param data The data of this descriptor, will be moved, must be valid
239 * @param levels The number of valid levels in the descriptor data, range: [1, 3]
240 * @param orientation The orientation of the descriptor in Radian, range: (-pi, pi]
241 */
242 inline FREAKDescriptorT(MultilevelDescriptorData&& data, const unsigned int levels, const float orientation) noexcept;
243
244 /**
245 * Returns the orientation of the descriptor in Radian
246 * @return The orientation of the descriptor in Radian, range: (-pi, pi]
247 */
248 inline float orientation() const;
249
250 /**
251 * Returns the descriptor data (writable)
252 * @return A non-const reference to the descriptor data of this instance
253 */
255
256 /**
257 * Returns the descriptor data
258 * @return A const reference to the descriptor data of this instance
259 */
260 inline const MultilevelDescriptorData& data() const;
261
262 /**
263 * Returns the number of levels stored in the multi-level descriptor
264 * @return The index of the descriptor level, range: [0, 2]
265 */
266 inline unsigned int descriptorLevels() const;
267
268 /**
269 * Returns the distance between this descriptor and a second descriptor.
270 * The resulting distance is the minimal distance between all existing level/single descriptors.
271 * @param descriptor The second descriptor, must be valid
272 * @return The distance between both descriptors (the hamming distance), with range [0, tSize * 8]
273 */
274 OCEAN_FORCE_INLINE unsigned int distance(const FREAKDescriptorT<tSize>& descriptor) const;
275
276 /**
277 * Returns true if this is a valid descriptor
278 * @return True if this is a valid descriptor, otherwise false
279 */
280 inline bool isValid() const;
281
282 /**
283 * Returns the length of this descriptor in bytes.
284 * @reutrn The descriptor's length in bytes
285 */
286 static constexpr size_t size();
287
288 /**
289 * Copy assignment operator, needs to be defined since there is a custom copy constructor.
290 * @return Reference to this object
291 */
292 inline FREAKDescriptorT& operator=(const FREAKDescriptorT<tSize>&) noexcept = default;
293
294 /**
295 * Compute a FREAK descriptor for a single point
296 * @param framePyramid Frame pyramid in which the location `point` has been defined, must be valid
297 * @param point Point defined at level `pointPyramidLevel` in `framePyramid` for which a descriptor will be computed, must be valid
298 * @param pointPyramidLevel Level of the frame pyramid at which the input point is located, range: [0, framePyramid.layers() - 1)
299 * @param freakDescriptor The FREAK descriptor that will be computed for the input point, will be valid only if this function returns true
300 * @param unprojectRayIF This is the 3D vector that connects the projection center of the camera with image point `point` in the image plane, must be valid
301 * @param inverseFocalLength The inverse focal length (assumes identical vertical and horizontal focal lengths), range: (0, infinity)
302 * @param pointJacobianMatrix2x3 The 2-by-3 Jacobian of the camera projection matrix, cf. `Geometry::Jacobian::calculatePointJacobian2x3()`, must be valid
303 * @return True if the descriptor was successfully computed, otherwise false
304 */
305 static bool computeDescriptor(const FramePyramid& framePyramid, const Eigen::Vector2f& point, const unsigned int pointPyramidLevel, FREAKDescriptorT<tSize>& freakDescriptor, const Eigen::Vector3f& unprojectRayIF, const float inverseFocalLength, const PointJacobianMatrix2x3& pointJacobianMatrix2x3);
306
307 /**
308 * Compute a FREAK descriptor for a single point
309 * This function requires a callback function which is used internally to determine the (normalized) ray from the
310 * camera projection center to a 2D image location in the image plane and the corresponding 2-by-3 Jacobian matrix
311 * of projection matrix wrt. to the 2D image location.
312 *
313 * Example usage:
314 *
315 * @code
316 * class YourCameraDerivativeFunctor : public CameraDerivativeFunctor
317 * {
318 * typename FREAKDescriptorT<tSize>::CameraDerivativeData computeCameraDerivativeData(const Eigen::Vector2f& point, const unsigned int pointPyramidLevel)
319 * {
320 * FREAKDescriptorT<tSize>::CameraDerivativeData data;
321 *
322 * data.pointJacobianMatrixIF = ... // Add your computation here
323 * data.unprojectRayIF = ... // Add your computation here
324 *
325 * return data;
326 * }
327 * };
328 *
329 * YourCameraDerivativeFunctor YourCameraDerivativeFunctor;
330 * FREAKDescriptorT<tSize>::computeDescriptors(yFramePyramid, points.data(), points.size(), level, oceanFreakDescriptorsMulticore.data(), inverseFocalLengthX, yourCameraDerivativeFunctor, &worker);
331 * @endcode
332 *
333 * @param framePyramid Frame pyramid in which the location `point` has been defined, must be valid
334 * @param points A pointer to the 2D image points which are defined at level `pointPyramidLevel` in `framePyramid` for which descriptors will be computed, must be valid
335 * @param pointsSize The number of elements in `points`, range: [0, infinity)
336 * @param pointsPyramidLevel Level of the frame pyramid at which the input point is located, range: [0, framePyramid.layers() - 1)
337 * @param freakDescriptors Pointer to the FREAK descriptors that will be computed for the input point, must be valid and have `pointsSize` elements. Final descriptors can be invalid, e.g., if they are too close to the image border
338 * @param inverseFocalLength The inverse focal length (assumes identical vertical and horizontal focal lengths), range: (0, infinity)
339 * @param cameraDerivativeFunctor A functor that is called for each input point and which must return its corresponding 2x3 Jacobian of the projection matrix and normalized unprojection ray.
340 * @param worker Optional worker instance for parallelization
341 */
342 static inline void computeDescriptors(const FramePyramid& framePyramid, const Eigen::Vector2f* points, const size_t pointsSize, const unsigned int pointsPyramidLevel, FREAKDescriptorT<tSize>* freakDescriptors, const float inverseFocalLength, const CameraDerivativeFunctor& cameraDerivativeFunctor, Worker* worker = nullptr);
343
344 /**
345 * Extract Harris corners from an image pyramid and compute FREAK descriptors
346 * @param yFrame The 8-bit grayscale image for which Harris corners and FREAK descriptors will be computed, must be valid
347 * @param maxFrameArea This value determines the first layer of the frame pyramid for which corners and descriptors will be computed, range: (minFrameArea, infinity)
348 * @param minFrameArea This value determines the last layer of the frame pyramid for which corners and descriptors will be computed, range: [0, maxFrameArea)
349 * @param expectedHarrisCorners640x480 Expected number of Harris corners if the resolution of the image were 640 x 480 pixels. The actual number of expected corners is scaled to the size first layer in the image pyramid that is used for the extraction and then distributed over the range of pyramid layers that is used, range: [1, infinity)
350 * @param harrisCornersReductionScale Scale factor that determines the rate with which the number of corners is reduced as the function climbs through the image pyramid, range: (0, 1)
351 * @param harrisCornerThreshold Threshold value for the Harris corner detector, range: [0, 512]
352 * @param inverseFocalLength The inverse focal length (assumes identical vertical and horizontal focal lengths) , range: (0, infinity)
353 * @param cameraDerivativeFunctor A functor that is called for each input point and which must return its corresponding 2x3 Jacobian of the projection matrix and normalized unprojection ray
354 * @param corners The Harris corners that have been extracted from the frame pyramid, will be initialized by this function, will have the same size as `cornerPyramidLevels` and `descriptors`
355 * @param cornerPyramidLevels Will hold for each Harris corner the level index of the pyramid level where it was extracted, will have the same size as `corners` and `descriptors`
356 * @param descriptors Will hold the FREAK descriptors of each Harris corners. Descriptors may be invalid. Will have the same size as `corners` and `cornerPyramidLevels`
357 * @param removeInvalid If true, all invalid descriptors (and corresponding corners and entries of pyramid levels) will be removed, otherwise all results will be remain as-is
358 * @param border Minimum distance in pixels from the image border (same value on all levels of the pyramid) that all Harris corners must have in order to be accepted, otherwise they will be discarded, range: [0, min(yFrame.width(), yFrame.height())/2)
359 * @param determineExactHarrisCornerPositions If true, force the subpixel interpolation to determine the exact position of the extracted Harris corners
360 * @param yFrameIsUndistorted If true the original input frame is undistorted and all extracted 2D feature positions will be marked as undistorted, too
361 * @param worker Optional worker instance for parallelization
362 */
363 static bool extractHarrisCornersAndComputeDescriptors(const Frame& yFrame, const unsigned int maxFrameArea, const unsigned int minFrameArea, const unsigned int expectedHarrisCorners640x480, const Scalar harrisCornersReductionScale, const unsigned int harrisCornerThreshold, const float inverseFocalLength, const CameraDerivativeFunctor& cameraDerivativeFunctor, HarrisCorners& corners, Indices32& cornerPyramidLevels, std::vector<FREAKDescriptorT<tSize>>& descriptors, const bool removeInvalid = false, const Scalar border = Scalar(20), const bool determineExactHarrisCornerPositions = false, const bool yFrameIsUndistorted = true, Worker* worker = nullptr);
364
365 protected:
366
367 /**
368 * Compute a FREAK descriptor for a single point
369 * @param framePyramid Frame pyramid in which the location `point` has been defined, must be valid
370 * @param points A pointer to the 2D image points which are defined at level `pointPyramidLevel` in `framePyramid` for which descriptors will be computed, must be valid
371 * @param pointsSize The number of elements in `points`, range: [1, infinity)
372 * @param pointPyramidLevel Level of the frame pyramid at which the input point is located, range: [0, framePyramid.layers() - 1)
373 * @param freakDescriptors Pointer to the FREAK descriptors that will be computed for the input point, must be valid and have `pointsSize` elements. Final descriptors can be invalid, e.g., if they are too close to the image border
374 * @param inverseFocalLength The inverse focal length (assumes identical vertical and horizontal focal lengths), range: (0, infinity)
375 * @param cameraDerivativeFunctor A callback function that is called for each input point and which must return its corresponding 2x3 Jacobian of the projection matrix and normalized unprojection ray
376 * @param firstPoint The index of the first point that will be processed by this function, rand: [0, pointsSize)
377 * @param numberOfPoints Number of points that should be processed in this function starting at `firstIndex`, range: [1, pointsSize - firstIndex]
378 */
379 static void computeDescriptorsSubset(const FramePyramid* framePyramid, const Eigen::Vector2f* points, const size_t pointsSize, const unsigned int pointPyramidLevel, FREAKDescriptorT<tSize>* freakDescriptors, const float inverseFocalLength, const CameraDerivativeFunctor* cameraDerivativeFunctor, const unsigned int firstPoint, const unsigned int numberOfPoints);
380
381 /**
382 * Computes the transformation to deform receptive fields and the orientation of the descriptor
383 * @param framePyramid Frame pyramid in which the location `point` has been defined, must be valid
384 * @param point The point defined at level `pointPyramidLevel` in `framePyramid` for which a descriptor will be computed, must be valid
385 * @param pointPyramidLevel Level of the frame pyramid at which the input point is located, range: [0, framePyramid.layers() - 1)
386 * @param unprojectRayIF This is the 3D vector that connects the projection center of the camera with image point `point` in the image plane, must be valid and inside the image
387 * @param inverseFocalLength The inverse focal length (assumes identical vertical and horizontal focal lengths), range: (0, infinity)
388 * @param pointJacobianMatrix2x3 The 2-by-3 Jacobian of the camera projection matrix, cf. `Geometry::Jacobian::calculatePointJacobian2x3()`, must be valid
389 * @param deformationMatrix The deformation transformation is a 2-by-2 matrix that is computed from the Jacobian of the camera projection matrix, the unprojection ray and the (inverse of the) focal length
390 * @param orientation The orientation of this descriptor in radian, range: [-pi, pi]
391 * @return True if this is a valid descriptor, otherwise false
392 */
393 static bool computeLocalDeformationMatrixAndOrientation(const FramePyramid& framePyramid, const Eigen::Vector2f& point, const unsigned int pointPyramidLevel, const Eigen::Vector3f& unprojectRayIF, const float inverseFocalLength, const PointJacobianMatrix2x3& pointJacobianMatrix2x3, Eigen::Matrix<float, 2, 2>& deformationMatrix, float& orientation);
394
395 /**
396 * Computes the average intensity of a cell
397 * @param framePyramidLayer Layer of a frame pyramid in which the location `(x, y)` has been defined, must be valid
398 * @param x The pixel-accurate horizontal coordinate of the cell, range: [0 + u, width - u), u = kernel_radius / 2 if `tEnableBorderChecks == true`, otherwise u = kernel_radius
399 * @param y The pixel-accurate vertical coordinate of the cell, range: [0 + v, height - v), v = kernel_radius / 2 if `tEnableBorderChecks == true`, otherwise v = kernel_radius
400 * @param kernelX Pointer to the horizontal offsets of the kernel elements (relative to `x`), must be valid and have `kernelElements` elements
401 * @param kernelY Pointer to the vertical offsets of the kernel elements (relative to `y`), must be valid and have `kernelElements` elements
402 * @param kernelElements Number of elements in the kernel, range: [1, infinity]
403 * @param averageIntensity The average intensity of the selected cell
404 * @tparam tEnableBorderChecks If true, only kernel values inside the input image will be added, otherwise the check will be disabled and the entire kernel is assumed to fit inside the image (for performance)
405 * @return True if the average intensity was successfully computed, otherwise false (e.g. location (x, y) too close to the image border)
406 */
407 template <bool tEnableBorderChecks>
408 static bool computeAverageCellIntensity(const Frame& framePyramidLayer, int x, int y, const int* kernelX, const int* kernelY, const size_t kernelElements, PixelType& averageIntensity);
409
410 /**
411 * Creates a new pyramid frame for a specific pixel format (a specific number of channels) and applies a Gaussian blur before each down-size step.
412 * @param frame The frame pyramid will be built using this frame, must be valid and use 8 bits per channel
413 * @param kernelWidth Width of the Gaussian kernel that is applied before a down-size step, range: [1, infinity), value must be odd
414 * @param kernelHeight Height of the Gaussian kernel that is applied before a down-size step, range: [1, infinity), value must be odd
415 * @param layers The number of pyramid layers to be created, with range [1, infinity)
416 * @param worker Optional worker object to distribute the computation
417 * @return The created frame pyramid (will be invalid in case of a failure)
418 */
419 static FramePyramid createFramePyramidWithBlur8BitsPerChannel(const Frame& frame, const unsigned int kernelWidth, const unsigned int kernelHeight, const unsigned int layers, Worker* worker = nullptr);
420
421 /**
422 * Downsamples a frame by two applying a 1-1 filter after applying a Gaussian blur to the source layer.
423 * @param finerLayer The finer pyramid layer, must be valid
424 * @param coarserLayer The coarser pyramid layer, must be valid
425 * @param worker The optional worker to distribute the computation
426 * @param kernelWidth The width of the Gaussian kernel, in pixel, with range [1, infinity), must odd
427 * @param kernelHeight The height of the Gaussian kernel, in pixel, with range [1, infinity), must odd
428 * @param reusableFrame A reusable frame which can be used internally
429 * @return True, if succeeded
430 */
431 static bool blurAndDownsampleByTwo11(const Frame& finerLayer, Frame& coarserLayer, Worker* worker, const unsigned int kernelWidth, const unsigned int kernelHeight, Frame& reusableFrame);
432
433 private:
434
435 /// The number of cells per keypoint that this implementation is using
436 static constexpr size_t numberOfCells = 43;
437
438 /// The pre-defined horizontal coordinates of the cells
439 static const float cellsX[numberOfCells];
440
441 /// The pre-defined vertical coordinates of the cells
442 static const float cellsY[numberOfCells];
443
444 /// The number of pre-defined pairs of cell indices that are used to compute the actual binary descriptor
445 static constexpr size_t numberOfCellPairs = 512;
446
447 /// The pre-defined pairs of cell indices that uare used to compute the actual binary descriptor (pairs have been randomly shuffled)
448 static const std::uint8_t cellPairs[numberOfCellPairs][2];
449
450 /// Number of elements in the circular kernel with radius 1
451 static constexpr size_t kernelRadius1Elements = 5;
452
453 /// The pre-defined horizontal coordinates of the circular kernel with radius 1
455
456 /// The pre-defined vertical coordinates of the circular kernel with radius 1
458
459 /// Number of elements in the circular kernel with radius 2
460 static constexpr size_t kernelRadius2Elements = 13;
461
462 /// The pre-defined horizontal coordinates of the circular kernel with radius 2
464
465 /// The pre-defined vertical coordinates of the circular kernel with radius 2
467
468 /// Number of elements in the circular kernel with radius 3
469 static constexpr size_t kernelRadius3Elements = 29;
470
471 /// The pre-defined horizontal coordinates of the circular kernel with radius 3
473
474 /// The pre-defined vertical coordinates of the circular kernel with radius 3
476
477 /// Number of elements in the circular kernel with radius 7
478 static constexpr size_t kernelRadius7Elements = 149;
479
480 /// The pre-defined horizontal coordinates of the circular kernel with radius 7
482
483 /// The pre-defined vertical coordinates of the circular kernel with radius 7
485
486 protected:
487
488 /// The orientation of this descriptor in radian, range: [-pi, pi]
489 float orientation_ = 0.0f;
490
491 /// The actual FREAK descriptor data
493
494 /// Number of valid levels in the multi-level descriptor data above, range: [0, 3]
495 unsigned int dataLevels_ = 0u;
496};
497
498template <size_t tSize>
500{
501 ocean_assert(pinholeCamera.isValid());
502 ocean_assert(pyramidLevels != 0u);
503
504 cameras_.reserve(pyramidLevels);
505 cameras_.emplace_back(pinholeCamera);
506
507 unsigned int width = pinholeCamera.width();
508 unsigned int height = pinholeCamera.height();
509
510 for (unsigned int level = 1u; level < pyramidLevels; ++level)
511 {
512 width /= 2u;
513 height /= 2u;
514
515 if (width == 0u || height == 0u)
516 {
517 break;
518 }
519
520 cameras_.emplace_back(width, height, pinholeCamera);
521 }
522
523 cameras_.shrink_to_fit();
524}
525
526template <size_t tSize>
528{
529 ocean_assert(pointPyramidLevel < cameras_.size());
531}
532
533template <size_t tSize>
535{
536 return (unsigned int)(cameras_.size());
537}
538
539template <size_t tSize>
541{
542 const Vector3 unprojectRayIF = pinholeCamera.vectorIF(Vector2(point.x(), point.y()));
543 ocean_assert(Numeric::isEqualEps((Vector3((Scalar(point.x()) - pinholeCamera.principalPointX()) * pinholeCamera.inverseFocalLengthX(), (Scalar(point.y()) - pinholeCamera.principalPointY()) * pinholeCamera.inverseFocalLengthY(), 1.0f).normalized() - unprojectRayIF).length()));
544
545 // TODOX Revisit this when enabling camera distortions
546 ocean_assert(pinholeCamera.hasDistortionParameters() == false);
547
548 Scalar jacobianX[3];
549 Scalar jacobianY[3];
550 Geometry::Jacobian::calculatePointJacobian2x3(jacobianX, jacobianY, pinholeCamera, HomogenousMatrix4(true), unprojectRayIF, /* distort */ false);
551
553
554 data.unprojectRayIF = Eigen::Vector3f(float(unprojectRayIF.x()), float(unprojectRayIF.y()), float(unprojectRayIF.z()));
555
556 // Note: the assignment below is row-major order but Eigen memory will be column-major. I know ...
557 data.pointJacobianMatrixIF << float(jacobianX[0]), float(jacobianX[1]), float(jacobianX[2]), float(jacobianY[0]), float(jacobianY[1]), float(jacobianY[2]);
558 ocean_assert(data.pointJacobianMatrixIF.IsRowMajor == false);
559
560 return data;
561}
562
563template <size_t tSize>
565{
566 ocean_assert(camera && camera->isValid());
567 ocean_assert(pyramidLevels != 0u);
568
569 cameras_.reserve(pyramidLevels);
570 cameras_.emplace_back(camera);
571
572 unsigned int width = camera->width();
573 unsigned int height = camera->height();
574
575 for (unsigned int level = 1u; level < pyramidLevels; ++level)
576 {
577 width /= 2u;
578 height /= 2u;
579
580 if (width == 0u || height == 0u)
581 {
582 break;
583 }
584
585 cameras_.emplace_back(cameras_.back()->clone(width, height));
586 }
587}
588
589template <size_t tSize>
591{
592 ocean_assert(pointPyramidLevel < cameras_.size());
594}
595
596template <size_t tSize>
598{
599 return (unsigned int)(cameras_.size());
600}
601
602template <size_t tSize>
604{
605 const Vector3 unprojectRayIF = camera.vectorIF(Vector2(point.x(), point.y()));
606
607 Scalar jacobianX[3];
608 Scalar jacobianY[3];
609 camera.pointJacobian2x3IF(unprojectRayIF, jacobianX, jacobianY);
610
612
613 data.unprojectRayIF = Eigen::Vector3f(float(unprojectRayIF.x()), float(unprojectRayIF.y()), float(unprojectRayIF.z()));
614
615 // Note: the assignment below is row-major order but Eigen memory will be column-major. I know ...
616 data.pointJacobianMatrixIF << float(jacobianX[0]), float(jacobianX[1]), float(jacobianX[2]), float(jacobianY[0]), float(jacobianY[1]), float(jacobianY[2]);
617 ocean_assert(data.pointJacobianMatrixIF.IsRowMajor == false);
618
619 return data;
620}
621
622template <size_t tSize>
623FREAKDescriptorT<tSize>::FREAKDescriptorT(MultilevelDescriptorData&& data, const unsigned int levels, const float orientation) noexcept :
625 data_(std::move(data)),
626 dataLevels_(levels)
627{
628 ocean_assert(levels >= 1u && levels <= 3u);
630}
631
632template <size_t tSize>
638
639template <size_t tSize>
644
645template <size_t tSize>
650
651template <size_t tSize>
653{
654 ocean_assert(dataLevels_ <= 3u);
655 return dataLevels_;
656}
657
658template <size_t tSize>
659OCEAN_FORCE_INLINE unsigned int FREAKDescriptorT<tSize>::distance(const FREAKDescriptorT<tSize>& descriptor) const
660{
661 ocean_assert(isValid() && descriptor.isValid());
662
663 unsigned int bestDistance = (unsigned int)(-1);
664
665 for (unsigned int nOuter = 0u; nOuter < dataLevels_; ++nOuter)
666 {
667 const SinglelevelDescriptorData& outerData = data_[nOuter];
668
669 for (unsigned int nInner = 0u; nInner < descriptor.dataLevels_; ++nInner)
670 {
671 const SinglelevelDescriptorData& innerData = descriptor.data_[nInner];
672
673 const unsigned int distance = Descriptor::calculateHammingDistance<tSize * 8u>(outerData.data(), innerData.data());
674
675 if (distance < bestDistance)
676 {
677 bestDistance = distance;
678 }
679 }
680 }
681
682 ocean_assert(bestDistance != (unsigned int)(-1));
683
684 return bestDistance;
685}
686
687template <size_t tSize>
692
693template <size_t tSize>
695{
696 return tSize;
697}
698
699template <size_t tSize>
700inline void FREAKDescriptorT<tSize>::computeDescriptors(const FramePyramid& framePyramid, const Eigen::Vector2f* points, const size_t pointsSize, const unsigned int pointsPyramidLevel, FREAKDescriptorT<tSize>* freakDescriptors, const float inverseFocalLength, const CameraDerivativeFunctor& projectionDerivativeDataCallback, Worker* worker)
701{
702 ocean_assert(framePyramid.isValid());
703 ocean_assert(points != nullptr && pointsSize != 0u);
704 ocean_assert(pointsPyramidLevel < framePyramid.layers());
705 ocean_assert(freakDescriptors != nullptr);
706 ocean_assert(inverseFocalLength > 0.0f);
707
708 if (worker)
709 {
710 worker->executeFunction(Worker::Function::createStatic(&FREAKDescriptorT<tSize>::computeDescriptorsSubset, &framePyramid, points, pointsSize, pointsPyramidLevel, freakDescriptors, inverseFocalLength, &projectionDerivativeDataCallback, 0u, 0u), 0u, (unsigned int)pointsSize);
711 }
712 else
713 {
714 FREAKDescriptorT<tSize>::computeDescriptorsSubset(&framePyramid, points, pointsSize, pointsPyramidLevel, freakDescriptors, inverseFocalLength, &projectionDerivativeDataCallback, 0u, (unsigned int)pointsSize);
715 }
716}
717
718template <size_t tSize>
720{
721 // clang-format off
722 0.0f, -14.7216f, -14.7216f, 0.0f, 14.7216f, 14.7216f, -6.3745f, -12.749f, -6.3745f, 6.3745f,
723 12.749f, 6.3745f, 0.0f, -7.97392f, -7.97392f, 0.0f, 7.97392f, 7.97392f, -3.18725f, -6.3745f,
724 -3.18725f, 3.18725f, 6.3745f, 3.18725f, 0.0f, -3.67983f, -3.67983f, 0.0f, 3.67983f, 3.67983f,
725 -1.4163f, -2.8326f, -1.4163f, 1.4163f, 2.8326f, 1.4163f, 0.0f, -1.84049f, -1.84049f, 0.0f,
726 1.84049f, 1.84049f, 0.0f
727 // clang-format on
728};
729
730template <size_t tSize>
732{
733 // clang-format off
734 16.9991f, 8.49895f, -8.49895f, -16.9991f, -8.49895f, 8.49895f, 11.0406f, 0.0f, -11.0406f, -11.0406f,
735 0.0f, 11.0406f, 9.2071f, 4.60355f, -4.60355f, -9.2071f, -4.60355f, 4.60355f, 5.52032f, 0.0f,
736 -5.52032f, -5.52032f, 0.0f, 5.52032f, 4.25005f, 2.12445f, -2.12445f, -4.25005f, -2.12445f, 2.12445f,
737 2.4536f, 0.0f, -2.4536f, -2.4536f, 0.0f, 2.4536f, 2.12445f, 1.0628f, -1.0628f, -2.12445f,
738 -1.0628f, 1.0628f, 0.0f
739 // clang-format on
740};
741
742template <size_t tSize>
744{
745 // clang-format off
746 {37, 4}, {38, 4}, {12, 0}, {39,10}, {27, 7}, {37,29}, {20,16}, {33,16}, {14, 0}, {31, 3},
747 {17, 4}, {24,12}, {33,22}, {31, 7}, {35,30}, {25, 6}, {34,31}, {20,19}, {22,17}, {16, 6},
748 {23, 5}, {26,10}, {13, 5}, {31,17}, {17,10}, {31,28}, {22, 4}, {29,11}, {28, 2}, {29,19},
749 {30, 6}, {37,10}, {31, 2}, {41,13}, {14, 7}, {15, 3}, {33, 4}, {18,17}, {23,19}, {33,28},
750 {41,24}, {34,16}, { 7, 1}, {26, 5}, {36,13}, {42, 9}, {20,14}, {27,26}, {41, 6}, {40,19},
751 {26, 3}, {36,29}, {23,13}, {40, 7}, {18, 0}, {28,22}, {22, 9}, {26,16}, {21,16}, {39,20},
752 { 8, 3}, {14, 1}, {12,11}, {31,25}, {29, 4}, {15, 1}, {41,22}, {35, 1}, {26, 2}, {34,14},
753 {25, 1}, {34,17}, {34,29}, {16,14}, {19, 3}, {26,14}, {15, 5}, {25,17}, {25, 5}, {34,25},
754 { 6, 0}, {23,10}, {29,24}, {28,16}, {20, 3}, { 7, 4}, {25,11}, {36,24}, {27, 9}, {11,10},
755 {23, 7}, {32,19}, {32,16}, {37,18}, {25,24}, {19, 1}, {22,20}, {38,14}, {41,31}, {16,10},
756 {19, 6}, {16,11}, {31,20}, { 8, 0}, {14, 2}, {19, 0}, {37,13}, {34, 4}, {31,14}, { 6, 1},
757 {40, 1}, {24,18}, {41, 1}, {41, 7}, {36,23}, {40,20}, {40,27}, {13, 0}, {19,12}, {42,38},
758 {16, 7}, {34, 7}, { 9, 2}, {28, 4}, {11, 5}, {40,38}, {17, 2}, { 5, 0}, {19,14}, {12, 6},
759 {19,17}, {40,22}, {26, 7}, {19, 5}, {19,11}, {28,26}, {12, 1}, {34, 0}, { 5, 1}, {27,16},
760 {21,15}, {29,25}, {19, 8}, {32,26}, {37,17}, {11, 6}, {22, 6}, {39,27}, {41,37}, {21, 5},
761 {14,11}, {31,16}, {38,28}, {16, 0}, {29,10}, {31,26}, {10, 1}, {22,13}, {10, 3}, {17, 3},
762 {42,30}, { 8, 4}, {26, 6}, {22, 8}, {38,27}, {26,22}, {41,10}, {42,13}, {40,34}, {13, 7},
763 {30,11}, {38,22}, {33,27}, {19,15}, {29, 7}, {31,10}, {26,15}, {13,12}, {29, 2}, { 5, 3},
764 {15, 7}, {28,10}, {29,17}, {40,10}, {21, 1}, {15,10}, {37,11}, {40,13}, {26, 1}, {39,21},
765 {34,21}, {40,31}, {19, 7}, {16, 5}, {40,39}, {37, 7}, {30,23}, {10, 9}, {36,30}, {38, 0},
766 {18, 6}, {40,32}, {38,10}, {22, 3}, {26,19}, {18,13}, {39,22}, {35,17}, {31,19}, {18,11},
767 {28,19}, {28, 0}, {37,31}, {30, 7}, {27,20}, {34,10}, {38, 3}, {37,23}, {18, 7}, {38,20},
768 {25,19}, {20, 7}, {22,18}, { 7, 3}, {15, 2}, {23,12}, {26,13}, {38, 7}, {11, 1}, {20, 8},
769 {33,21}, {37,36}, {17,16}, {36,35}, {41, 2}, {37,35}, {37, 2}, {15,14}, {10, 7}, {41,29},
770 { 7, 6}, {32,22}, {34,26}, {33, 2}, {38,26}, {31, 0}, {11, 3}, {24,23}, {13,11}, {41,19},
771 {41,25}, {30,13}, {27,10}, {39,38}, {21, 3}, {31, 4}, {27,14}, {37,24}, {20, 2}, {25,23},
772 {29, 1}, {39,28}, {17, 0}, { 7, 0}, { 9, 5}, {22, 2}, {33,32}, {27,21}, {30,25}, {41,23},
773 {41,30}, {15, 9}, {22,10}, {31,22}, {29, 5}, {34,20}, {24,13}, {31,11}, {36,25}, {21,19},
774 {19,13}, {30,29}, {33, 5}, { 6, 4}, { 5, 2}, { 8, 2}, {10, 2}, {25,13}, {37,19}, {28,14},
775 {15, 4}, {10, 8}, {12, 5}, {14,13}, {24, 1}, {31,12}, {14,10}, {32,27}, {19,18}, {32, 4},
776 {22, 1}, {39,26}, {17,14}, { 2, 1}, { 1, 0}, {35,23}, {34, 2}, {33,19}, {13, 3}, {39,16},
777 {25, 2}, {41, 4}, {28, 7}, {31,21}, {26, 4}, {39,19}, {24,17}, {28,20}, {21, 8}, {25, 7},
778 {34,15}, {41,36}, {16, 3}, {21,20}, {31,15}, {26,20}, {14, 5}, {38,16}, {40, 2}, {18,10},
779 {27, 8}, {29,13}, {41,18}, {18,12}, {40,26}, {36, 0}, {21,14}, {22, 0}, {27, 2}, {11, 0},
780 {21,10}, {20,10}, {23, 6}, {13, 4}, {28,21}, {22,16}, {25,22}, {35,24}, { 4, 0}, {31, 1},
781 {32,21}, {21, 4}, {37, 6}, {15, 8}, { 8, 7}, {29,22}, {28,15}, {25,18}, {41,35}, {39,14},
782 {34,12}, {23,17}, {25,10}, {39, 9}, {34,13}, {22,14}, { 7, 2}, {20, 9}, {28,11}, {10, 4},
783 {40, 0}, {35,13}, {38,32}, {13, 2}, {39, 1}, { 2, 0}, {38,19}, {41,11}, {32,28}, {39,33},
784 {30,17}, {16, 2}, {17, 6}, {13,10}, { 4, 1}, {10, 0}, {22,19}, { 4, 3}, {12, 7}, {26,21},
785 { 9, 0}, {19,16}, {34,28}, {16, 9}, { 9, 8}, {23, 0}, { 7, 5}, {10, 5}, {34,18}, {14, 6},
786 {30, 5}, {31,18}, {20,15}, {34,22}, {35,12}, {23, 1}, {35,10}, { 9, 3}, {27,15}, {17,13},
787 {37,30}, {26, 0}, {28,17}, {38,33}, {38, 5}, {16, 4}, {13, 1}, {28, 3}, { 5, 4}, {12, 2},
788 {17, 9}, {31,29}, {22,11}, {40,17}, {25, 4}, {28,27}, {29, 6}, {34, 1}, {14, 8}, {32,15},
789 {39,32}, { 6, 5}, {19, 4}, {18, 5}, {32,20}, {38,13}, {12,10}, {24, 0}, {22,15}, {36,18},
790 { 6, 3}, {34,23}, {33,15}, {22, 7}, {22,12}, {40,28}, {35,18}, {22, 5}, {29,23}, {37,34},
791 {16,13}, {23,18}, {37,22}, {29,12}, {19, 2}, {14, 9}, {34,19}, {19,10}, {25,12}, {38,21},
792 {28, 1}, {33,20}, {27, 4}, {11, 7}, {31,23}, {17, 7}, {17, 8}, {39, 8}, {40,21}, {16,15},
793 {17, 5}, {30,18}, {39, 7}, {37,25}, {41,34}, {30,24}, {18, 1}, { 3, 1}, { 9, 4}, {22,21},
794 {31, 5}, {40, 3}, {35,25}, {32, 2}, { 4, 2}, {38,31}, {14, 3}, {21, 9}, {17,12}, {16, 1},
795 {35,29}, {23,22}, {20, 1}, {34, 3}, {17, 1}, {13, 6}, {40,14}, {17,11}, {38,17}, {40,16},
796 {20, 4}, {23,11}, {12, 4}, { 3, 2}, {40,33}, {14, 4}, {21, 2}, {33,26}, {38,34}, {29,18},
797 {21, 7}, {16, 8}
798 // clang-format on
799};
800
801template <size_t tSize>
803
804template <size_t tSize>
806
807template <size_t tSize>
808const int FREAKDescriptorT<tSize>::kernelRadius2X[kernelRadius2Elements] = { 0, -1, 0, 1, -2, -1, 0, 1, 2, -1, 0, 1, 0 };
809
810template <size_t tSize>
811const int FREAKDescriptorT<tSize>::kernelRadius2Y[kernelRadius2Elements] = { -2, -1, -1, -1, 0, 0, 0, 0, 0, 1, 1, 1, 2 };
812
813template <size_t tSize>
815{
816 // clang-format off
817 0, -2, -1, 0, 1, 2, -2, -1, 0, 1,
818 2, -3, -2, -1, 0, 1, 2, 3, -2, -1,
819 0, 1, 2, -2, -1, 0, 1, 2, 0
820 // clang-format on
821};
822
823template <size_t tSize>
825{
826 // clang-format off
827 -3, -2, -2, -2, -2, -2, -1, -1, -1, -1,
828 -1, 0, 0, 0, 0, 0, 0, 0, 1, 1,
829 1, 1, 1, 2, 2, 2, 2, 2, 3
830 // clang-format on
831};
832
833template <size_t tSize>
835{
836 // clang-format off
837 0, -3, -2, -1, 0, 1, 2, 3, -4, -3,
838 -2, -1, 0, 1, 2, 3, 4, -5, -4, -3,
839 -2, -1, 0, 1, 2, 3, 4, 5, -6, -5,
840 -4, -3, -2, -1, 0, 1, 2, 3, 4, 5,
841 6, -6, -5, -4, -3, -2, -1, 0, 1, 2,
842 3, 4, 5, 6, -6, -5, -4, -3, -2, -1,
843 0, 1, 2, 3, 4, 5, 6, -7, -6, -5,
844 -4, -3, -2, -1, 0, 1, 2, 3, 4, 5,
845 6, 7, -6, -5, -4, -3, -2, -1, 0, 1,
846 2, 3, 4, 5, 6, -6, -5, -4, -3, -2,
847 -1, 0, 1, 2, 3, 4, 5, 6, -6, -5,
848 -4, -3, -2, -1, 0, 1, 2, 3, 4, 5,
849 6, -5, -4, -3, -2, -1, 0, 1, 2, 3,
850 4, 5, -4, -3, -2, -1, 0, 1, 2, 3,
851 4, -3, -2, -1, 0, 1, 2, 3, 0
852 // clang-format on
853};
854
855template <size_t tSize>
857{
858 // clang-format off
859 -7, -6, -6, -6, -6, -6, -6, -6, -5, -5,
860 -5, -5, -5, -5, -5, -5, -5, -4, -4, -4,
861 -4, -4, -4, -4, -4, -4, -4, -4, -3, -3,
862 -3, -3, -3, -3, -3, -3, -3, -3, -3, -3,
863 -3, -2, -2, -2, -2, -2, -2, -2, -2, -2,
864 -2, -2, -2, -2, -1, -1, -1, -1, -1, -1,
865 -1, -1, -1, -1, -1, -1, -1, 0, 0, 0,
866 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
867 0, 0, 1, 1, 1, 1, 1, 1, 1, 1,
868 1, 1, 1, 1, 1, 2, 2, 2, 2, 2,
869 2, 2, 2, 2, 2, 2, 2, 2, 3, 3,
870 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
871 3, 4, 4, 4, 4, 4, 4, 4, 4, 4,
872 4, 4, 5, 5, 5, 5, 5, 5, 5, 5,
873 5, 6, 6, 6, 6, 6, 6, 6, 7
874 // clang-format on
875};
876
877template <size_t tSize>
878bool FREAKDescriptorT<tSize>::computeDescriptor(const FramePyramid& pyramid, const Eigen::Vector2f& point, const unsigned int pointPyramidLevel, FREAKDescriptorT<tSize>& freakDescriptor, const Eigen::Vector3f& unprojectRayIF, const float inverseFocalLength, const PointJacobianMatrix2x3& pointJacobianMatrixIF)
879{
880 ocean_assert(pointPyramidLevel < pyramid.layers());
881 ocean_assert(inverseFocalLength > 0.0f);
882
883 // No descriptors can be computed for points in the coarsest layer of the frame pyramid
884
885 if (pointPyramidLevel + 1u >= pyramid.layers())
886 {
887 return false;
888 }
889
890 // Invalidate the descriptor for now
891
892 freakDescriptor.dataLevels_ = 0u;
893 ocean_assert(freakDescriptor.isValid() == false);
894
895 // Compute the deformation matrix from the position of the image point (and its Jacobian, etc)
896
897 Eigen::Matrix<float, 2, 2> cellDeformationMatrix;
898 if (computeLocalDeformationMatrixAndOrientation(pyramid, point, pointPyramidLevel, unprojectRayIF, inverseFocalLength, pointJacobianMatrixIF, cellDeformationMatrix, freakDescriptor.orientation_) == false)
899 {
900 return false;
901 }
902
903 // Apply the deformation matrix to the locations of all cells
904
907
908 for (size_t i = 0; i < FREAKDescriptorT<tSize>::numberOfCells; ++i)
909 {
910 const Eigen::Vector2f warpedCell = cellDeformationMatrix * Eigen::Vector2f(FREAKDescriptorT<tSize>::cellsX[i], FREAKDescriptorT<tSize>::cellsY[i]);
911 warpedCellX[i] = warpedCell[0];
912 warpedCellY[i] = warpedCell[1];
913 }
914
915 // Compute a descriptor for each intra-level:
916 //
917 // 2^(0/3) = 1,
918 // 2^(1/3) = 1.2599,
919 // 2^(2/3) = 1.5874
920 //
921 const float scaleFactors[3] = { 1.0f, 1.2599f, 1.5874f };
922 for (size_t scaleLevel = 0; scaleLevel < 3; ++scaleLevel)
923 {
925 bool computationFailed = false;
926
927 // Compute the average intensity per cell
928 //
929 // In order to reduce the number of if-branches, we'll split the range of cell IDs such that they are partitioned into groups with identical conditions, cf. table below:
930 //
931 // Cell ID: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
932 // Pyramid evel offsets: 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
933 // Radii: 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
934 // Check pixel in image: T, T, T, T, T, T, T, T, T, T, T, T, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F
935 // for-loop ID: |--- 0 ------------------------->| |--- 1 -------------------------->| |--- 2 -------->| |--- 3 ----------------------------->|
936
937 unsigned int cellId = 0u;
938
939 // Loop 0
940 for (; cellId < 12u; ++cellId)
941 {
942 ocean_assert(pointPyramidLevel + 1u < pyramid.layers());
943 const Frame& nextFramePyramidLayer = pyramid.layer(pointPyramidLevel + 1u);
944
945 const float cellX = point[0] + scaleFactors[scaleLevel] * warpedCellX[cellId];
946 const float cellY = point[1] + scaleFactors[scaleLevel] * warpedCellY[cellId];
947
948 const int cellXi = NumericF::round32(((cellX + 0.5f) * 0.5f) - 0.5f);
949 const int cellYi = NumericF::round32(((cellY + 0.5f) * 0.5f) - 0.5f);
950
951 // Check if the (half-)radius fits into the image, radius = 3, radius / 2 = 1
952 if (cellXi - 1 < 0 || cellXi + 1 >= int(nextFramePyramidLayer.width()) || cellYi - 1 < 0 || cellYi + 1 >= int(nextFramePyramidLayer.height()))
953 {
954 computationFailed = true;
955 break;
956 }
957
958 ocean_assert(cellXi >= 0 && cellXi < int(nextFramePyramidLayer.width()) && cellYi >= 0 && cellYi < int(nextFramePyramidLayer.height()));
959
960 if (computeAverageCellIntensity<true>(nextFramePyramidLayer, cellXi, cellYi, kernelRadius3X, kernelRadius3Y, kernelRadius3Elements, cellIntensities[cellId]) == false)
961 {
962 computationFailed = true;
963 break;
964 }
965 }
966
967 // Loop 1
968 const Frame& currentFramePyramidLayer = pyramid.layer(pointPyramidLevel);
969
970 ocean_assert(cellId == 12u || computationFailed == true);
971 for (; computationFailed == false && cellId < 24u; ++cellId)
972 {
973 const float cellX = point[0] + scaleFactors[scaleLevel] * warpedCellX[cellId];
974 const float cellY = point[1] + scaleFactors[scaleLevel] * warpedCellY[cellId];
975
976 const int cellXi = NumericF::round32(cellX);
977 const int cellYi = NumericF::round32(cellY);
978
979 ocean_assert(cellXi >= 0 && cellXi < int(currentFramePyramidLayer.width()) && cellYi >= 0 && cellYi < int(currentFramePyramidLayer.height()));
980
981 if (computeAverageCellIntensity<false>(currentFramePyramidLayer, cellXi, cellYi, kernelRadius3X, kernelRadius3Y, kernelRadius3Elements, cellIntensities[cellId]) == false)
982 {
983 computationFailed = true;
984 break;
985 }
986 }
987
988 // Loop 2
989 ocean_assert(cellId == 24u || computationFailed == true);
990 for (; computationFailed == false && cellId < 30u; ++cellId)
991 {
992 const float cellX = point[0] + scaleFactors[scaleLevel] * warpedCellX[cellId];
993 const float cellY = point[1] + scaleFactors[scaleLevel] * warpedCellY[cellId];
994
995 const int cellXi = NumericF::round32(cellX);
996 const int cellYi = NumericF::round32(cellY);
997
998 ocean_assert(cellXi >= 0 && cellXi < int(currentFramePyramidLayer.width()) && cellYi >= 0 && cellYi < int(currentFramePyramidLayer.height()));
999 if (computeAverageCellIntensity<false>(currentFramePyramidLayer, cellXi, cellYi, kernelRadius2X, kernelRadius2Y, kernelRadius2Elements, cellIntensities[cellId]) == false)
1000 {
1001 computationFailed = true;
1002 break;
1003 }
1004 }
1005
1006 // Loop 3
1007 ocean_assert(cellId == 30u || computationFailed == true);
1008 for (; computationFailed == false && cellId < FREAKDescriptorT<tSize>::numberOfCells; ++cellId)
1009 {
1010 const float cellX = point[0] + scaleFactors[scaleLevel] * warpedCellX[cellId];
1011 const float cellY = point[1] + scaleFactors[scaleLevel] * warpedCellY[cellId];
1012
1013 const int cellXi = NumericF::round32(cellX);
1014 const int cellYi = NumericF::round32(cellY);
1015
1016 ocean_assert(cellXi >= 0 && cellXi < int(currentFramePyramidLayer.width()) && cellYi >= 0 && cellYi < int(currentFramePyramidLayer.height()));
1017
1018 if (computeAverageCellIntensity<false>(currentFramePyramidLayer, cellXi, cellYi, kernelRadius1X, kernelRadius1Y, kernelRadius1Elements, cellIntensities[cellId]) == false)
1019 {
1020 computationFailed = true;
1021 break;
1022 }
1023 }
1024
1025 if (computationFailed)
1026 {
1027 break;
1028 }
1029
1030 // Compute the binary descriptor for the current scale level
1031
1032 for (size_t i = 0; i < tSize; ++i)
1033 {
1034 uint8_t partialDescriptor = 0u;
1035
1036 for (size_t j = 0; j < 8; ++j)
1037 {
1038 partialDescriptor = uint8_t(partialDescriptor << 1u);
1039
1040 const size_t pair = i * 8 + j;
1041 ocean_assert(pair < FREAKDescriptorT<tSize>::numberOfCellPairs);
1044
1045 if (cellIntensities[FREAKDescriptorT<tSize>::cellPairs[pair][0]] > cellIntensities[FREAKDescriptorT<tSize>::cellPairs[pair][1]])
1046 {
1047 partialDescriptor = partialDescriptor | 1u;
1048 }
1049 }
1050 freakDescriptor.data_[scaleLevel][i] = partialDescriptor;
1051 }
1052
1053 freakDescriptor.dataLevels_ = (unsigned int)(scaleLevel + 1);
1054 }
1055
1056 ocean_assert(freakDescriptor.isValid() == false || (NumericF::isInsideRange(-NumericF::pi(), freakDescriptor.orientation_, NumericF::pi()) && freakDescriptor.dataLevels_ <= 3u));
1057
1058 return freakDescriptor.isValid();
1059}
1060
1061template <size_t tSize>
1062template <bool tEnableBorderChecks>
1063bool FREAKDescriptorT<tSize>::computeAverageCellIntensity(const Frame& framePyramidLayer, int cellX, int cellY, const int* kernelX, const int* kernelY, const size_t kernelElements, PixelType& averageIntensity)
1064{
1065 ocean_assert(framePyramidLayer.isValid());
1066 ocean_assert(kernelX != nullptr && kernelY != nullptr && kernelElements != 0u);
1067
1068 const unsigned int width = framePyramidLayer.width();
1069 const unsigned int height = framePyramidLayer.height();
1070 const unsigned int frameStrideElements = framePyramidLayer.strideElements();
1071 const PixelType* frame = framePyramidLayer.constdata<PixelType>();
1072
1073 if constexpr (tEnableBorderChecks)
1074 {
1075 unsigned int sum = 0u;
1076 unsigned int sumElements = 0u;
1077
1078 for (size_t i = 0; i < kernelElements; ++i)
1079 {
1080 const int x = cellX + kernelX[i];
1081 const int y = cellY + kernelY[i];
1082
1083 if (x >= 0 && x < int(width) && y >= 0 && y < int(height))
1084 {
1085 sum += frame[(unsigned int)y * frameStrideElements + (unsigned int)x];
1086 sumElements++;
1087 }
1088 }
1089
1090 ocean_assert(sumElements != 0u);
1091 ocean_assert(float(sum) / float(sumElements) <= 255.0f);
1092
1093 averageIntensity = PixelType(float(sum) / float(sumElements)); // TODOX No rounding in original. Add it here?
1094 }
1095 else
1096 {
1097 unsigned int sum = 0u;
1098
1099 for (size_t i = 0; i < kernelElements; ++i)
1100 {
1101 const int x = cellX + kernelX[i];
1102 const int y = cellY + kernelY[i];
1103 ocean_assert_and_suppress_unused(x >= 0 && x < int(width) && y >= 0 && y < int(height), height);
1104
1105 sum += frame[(unsigned int)y * frameStrideElements + (unsigned int)x];
1106 }
1107
1108 ocean_assert(float(sum) / float(kernelElements) <= 255.0f);
1109
1110 averageIntensity = PixelType(float(sum) / float(kernelElements)); // TODOX No rounding in original. Add it here?
1111 }
1112
1113 return true;
1114}
1115
1116template <size_t tSize>
1117void FREAKDescriptorT<tSize>::computeDescriptorsSubset(const FramePyramid* framePyramid, const Eigen::Vector2f* points, const size_t pointsSize, const unsigned int pointsPyramidLevel, FREAKDescriptorT<tSize>* freakDescriptor, const float inverseFocalLength, const CameraDerivativeFunctor* cameraDerivativeFunctor, const unsigned int firstPoint, const unsigned int numberOfPoints)
1118{
1119 ocean_assert(framePyramid != nullptr && framePyramid->isValid());
1120 ocean_assert(points != nullptr && pointsSize != 0u);
1121 ocean_assert(pointsPyramidLevel < framePyramid->layers());
1122 ocean_assert(freakDescriptor != nullptr);
1123 ocean_assert(inverseFocalLength > 0.0f);
1124 ocean_assert(cameraDerivativeFunctor != nullptr);
1125 ocean_assert_and_suppress_unused(firstPoint + numberOfPoints <= pointsSize && numberOfPoints != 0u, pointsSize);
1126
1127 for (unsigned int i = firstPoint; i < firstPoint + numberOfPoints; ++i)
1128 {
1129 ocean_assert(i < pointsSize);
1130 const CameraDerivativeData data = cameraDerivativeFunctor->computeCameraDerivativeData(points[i], pointsPyramidLevel);
1131 computeDescriptor(*framePyramid, points[i], pointsPyramidLevel, freakDescriptor[i], data.unprojectRayIF, inverseFocalLength, data.pointJacobianMatrixIF);
1132 }
1133}
1134
1135template <size_t tSize>
1136bool FREAKDescriptorT<tSize>::computeLocalDeformationMatrixAndOrientation(const FramePyramid& pyramid, const Eigen::Vector2f& point, const unsigned int pointPyramidLevel, const Eigen::Vector3f& unprojectRayIF, const float inverseFocalLengthX, const PointJacobianMatrix2x3& projectionJacobianMatrix, Eigen::Matrix<float, 2, 2> & deformationMatrix, float& orientation)
1137{
1138 ocean_assert(pyramid.isValid());
1139 ocean_assert(pointPyramidLevel < pyramid.layers());
1141 ocean_assert(NumericF::isEqualEps(unprojectRayIF.norm() - 1.0f));
1142 ocean_assert(inverseFocalLengthX > 0);
1143 ocean_assert(projectionJacobianMatrix.IsRowMajor == false);
1144
1145 // In the plane perpendicular to the unprojection ray, determine two arbitrary but perpendicular vectors
1146
1147 const Eigen::Vector3f directionY(0, 1, 0);
1148 const Eigen::Vector3f nx = directionY.cross(unprojectRayIF).normalized() * inverseFocalLengthX;
1149 const Eigen::Vector3f ny = unprojectRayIF.cross(nx);
1150
1151 // Compute an initial warping matrix from the perpendicular vectors
1152
1153 Eigen::Matrix<float, 3, 2> N;
1154 N.col(0) = nx;
1155 N.col(1) = ny;
1156 const Eigen::Matrix<float, 2, 2> initialDeformationMatrix = projectionJacobianMatrix * N;
1157
1158 // Make sure that the orientation kernel (radius 7) fits inside the current pyramid layer
1159
1160 constexpr float cornerX[4] = {-7.0f, -7.0f, 7.0f, 7.0f};
1161 constexpr float cornerY[4] = {-7.0f, 7.0f, -7.0f, 7.0f};
1162 const Frame& framePyramidLevel = pyramid.layer(pointPyramidLevel);
1163
1164 for (size_t i = 0; i < 4; ++i)
1165 {
1166 const Eigen::Vector2f warpedCorner = point + initialDeformationMatrix * Eigen::Vector2f(cornerX[i], cornerY[i]);
1167
1168 const unsigned int x = (unsigned int)(NumericF::round32(warpedCorner.x()));
1169 const unsigned int y = (unsigned int)(NumericF::round32(warpedCorner.y()));
1170
1171 if (x >= framePyramidLevel.width() || y >= framePyramidLevel.height())
1172 {
1173 return false;
1174 }
1175 }
1176
1177 // Compute weighted intensity over the kernel
1178
1179 int magnitudeX = 0;
1180 int magnitudeY = 0;
1181 const unsigned int strideElements = framePyramidLevel.strideElements();
1182 const PixelType* data = framePyramidLevel.constdata<PixelType>();
1183
1184 for (size_t i = 0; i < FREAKDescriptorT<tSize>::kernelRadius7Elements; ++i)
1185 {
1186 const Eigen::Vector2f p = point + initialDeformationMatrix * Eigen::Vector2f(float(FREAKDescriptorT<tSize>::kernelRadius7X[i]), float(FREAKDescriptorT<tSize>::kernelRadius7Y[i]));
1187
1188 const int u = NumericF::round32(p[0]);
1189 const int v = NumericF::round32(p[1]);
1190
1191 ocean_assert(((unsigned int)(v) * strideElements + (unsigned int)(u)) < framePyramidLevel.size());
1192 const int intensity = int(data[(unsigned int)(v) * strideElements + (unsigned int)(u)]);
1193
1194 // TODOX Is weighting with the relative x-/y-offsets of the kernel correct? Pixels on the border of kernel have much larger weight (up to +/-7) than ones closer to the kernel center (as low as 0 for the center)
1195 magnitudeX += FREAKDescriptorT<tSize>::kernelRadius7X[i] * intensity;
1196 magnitudeY += FREAKDescriptorT<tSize>::kernelRadius7Y[i] * intensity;
1197 }
1198
1199 if (magnitudeX == 0 && magnitudeY == 0)
1200 {
1201 return false;
1202 }
1203
1204 // Compute axes aligned with keypoint orientation and use them to compute the deformation matrix
1205
1206 const Eigen::Vector3f gy = (nx * float(magnitudeX) + ny * float(magnitudeY)).normalized() * inverseFocalLengthX;
1207 const Eigen::Vector3f gx = gy.cross(unprojectRayIF);
1208
1209 Eigen::Matrix<float, 3, 2> G;
1210 G.col(0) = gx;
1211 G.col(1) = gy;
1212
1213 deformationMatrix = projectionJacobianMatrix * G;
1214
1215 // Compute angle in image coordinates
1216
1217 const Eigen::Vector2f patchY = projectionJacobianMatrix * gy;
1218 orientation = NumericF::atan2(patchY[1], patchY[0]);
1219 ocean_assert(-NumericF::pi() < orientation && orientation <= NumericF::pi());
1220
1221 return true;
1222}
1223
1224template <size_t tSize>
1225FramePyramid FREAKDescriptorT<tSize>::createFramePyramidWithBlur8BitsPerChannel(const Frame& frame, const unsigned int kernelWidth, const unsigned int kernelHeight, const unsigned int layers, Worker* worker)
1226{
1227 ocean_assert(frame.isValid() && frame.dataType() == FrameType::DT_UNSIGNED_INTEGER_8);
1228 ocean_assert(kernelWidth != 0u && kernelWidth % 2u == 1u);
1229 ocean_assert(kernelHeight != 0u && kernelHeight % 2u == 1u);
1230 ocean_assert(layers >= 1u);
1231
1232 Frame reusableFrame;
1233
1234 const FramePyramid::DownsamplingFunction downsamplingFunction = std::bind(&FREAKDescriptorT<tSize>::blurAndDownsampleByTwo11, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, kernelWidth, kernelHeight, reusableFrame);
1235
1236 FramePyramid framePyramid(frame, downsamplingFunction, layers, true /*copyFirstLayer*/, worker);
1237
1238 if (framePyramid.layers() != layers)
1239 {
1240 return FramePyramid();
1241 }
1242
1243 return framePyramid;
1244}
1245
1246template <size_t tSize>
1247bool FREAKDescriptorT<tSize>::blurAndDownsampleByTwo11(const Frame& finerLayer, Frame& coarserLayer, Worker* worker, const unsigned int kernelWidth, const unsigned int kernelHeight, Frame& reusableFrame)
1248{
1249 ocean_assert(finerLayer.isValid());
1250 ocean_assert(coarserLayer.isValid());
1251
1252 ocean_assert(kernelWidth >= 1u && kernelWidth % 2u == 1u);
1253 ocean_assert(kernelHeight >= 1u && kernelHeight % 2u == 1u);
1254
1255 ocean_assert(finerLayer.numberPlanes() == 1u && finerLayer.dataType() == FrameType::DT_UNSIGNED_INTEGER_8);
1256 ocean_assert(finerLayer.isPixelFormatCompatible(coarserLayer.pixelFormat()));
1257
1258 if (!reusableFrame.set(finerLayer.frameType(), false /*forceOwner*/, true /*forceWritable*/))
1259 {
1260 ocean_assert(false && "This should never happen!");
1261 return false;
1262 }
1263
1264 ocean_assert(reusableFrame.isValid());
1265
1266 const Frame* sourceLayer = &finerLayer;
1267
1268 if (kernelWidth <= finerLayer.width() && kernelHeight <= finerLayer.height())
1269 {
1270 if (!CV::FrameFilterGaussian::filter<uint8_t, uint32_t>(finerLayer.constdata<uint8_t>(), reusableFrame.data<uint8_t>(), finerLayer.width(), finerLayer.height(), finerLayer.channels(), finerLayer.paddingElements(), reusableFrame.paddingElements(), kernelWidth, kernelHeight, -1.0f, worker))
1271 {
1272 return false;
1273 }
1274
1275 sourceLayer = &reusableFrame;
1276 }
1277
1278 CV::FrameShrinker::downsampleByTwo8BitPerChannel11(sourceLayer->constdata<uint8_t>(), coarserLayer.data<uint8_t>(), sourceLayer->width(), sourceLayer->height(), sourceLayer->channels(), sourceLayer->paddingElements(), coarserLayer.paddingElements(), worker);
1279
1280 return true;
1281}
1282
1283template <size_t tSize>
1284bool FREAKDescriptorT<tSize>::extractHarrisCornersAndComputeDescriptors(const Frame& yFrame, const unsigned int maxFrameArea, const unsigned int minFrameArea, const unsigned int expectedHarrisCorners640x480, const Scalar harrisCornersReductionScale, const unsigned int harrisCornerThreshold, const float inverseFocalLength, const CameraDerivativeFunctor& cameraDerivativeFunctor, HarrisCorners& corners, Indices32& cornerPyramidLevels, std::vector<FREAKDescriptorT<tSize>>& descriptors, const bool removeInvalid, const Scalar border, const bool determineExactHarrisCornerPositions, const bool yFrameIsUndistorted, Worker* worker)
1285{
1286 ocean_assert(yFrame.isValid() && FrameType::arePixelFormatsCompatible(yFrame.pixelFormat(), FrameType::genericPixelFormat<std::uint8_t, 1u>()));
1287 ocean_assert(minFrameArea != 0u && minFrameArea <= maxFrameArea);
1288 ocean_assert(expectedHarrisCorners640x480 != 0u);
1289 ocean_assert(harrisCornersReductionScale > Scalar(0) && harrisCornersReductionScale < Scalar(1));
1290 ocean_assert(harrisCornerThreshold <= 512u);
1291 ocean_assert(inverseFocalLength > 0.0f);
1292 ocean_assert(border > Scalar(0) && Scalar(2) * border < Scalar(yFrame.width()) && Scalar(2) * border < Scalar(yFrame.height()));
1293
1294 corners.clear();
1295 cornerPyramidLevels.clear();
1296 descriptors.clear();
1297
1298 // Determine the range of layers in the pyramid that are of interest (expressed as a range of minimum and maximum area of the frames). Note: area shrinks by a factor of 4 with each coarser layer
1299
1300 const unsigned int frameArea = yFrame.width() * yFrame.height();
1301 const unsigned int startLayerIndex = (unsigned int)std::max(0, Numeric::round32((Numeric::log10(Scalar(frameArea) / Scalar(maxFrameArea)) / Numeric::log10(Scalar(4)))));
1302 const unsigned int lastLayerIndex = (unsigned int)(Numeric::log10(Scalar(frameArea) / Scalar(minFrameArea)) / Numeric::log10(Scalar(4)));
1303 ocean_assert(startLayerIndex <= lastLayerIndex);
1304
1305 // Generate a frame pyramid (+1 extra layer)
1306
1307 const FramePyramid pyramid = FREAKDescriptorT<tSize>::createFramePyramidWithBlur8BitsPerChannel(yFrame, 5u, 5u, lastLayerIndex + 2u, worker);
1308
1309 if (pyramid.isValid() == false || pyramid.layers() <= lastLayerIndex || cameraDerivativeFunctor.supportedPyramidLevels() <= lastLayerIndex)
1310 {
1311 return false;
1312 }
1313
1314 // The number of expected Harris corners is defined at a reference image size of 640x480 pixels. So, it necessary to scale this number
1315 // to the actual size of the first pyramid layer that will be used and then scale it such that the total number of requested points is
1316 // distributed over all used pyramid layers.
1317
1318 const unsigned int startLayerArea = pyramid[startLayerIndex].width() * pyramid[startLayerIndex].height();
1319
1320#if 0
1321 // Disabled but leaving it here as reference
1322 unsigned int expectedHarrisCornersOnLevel = (unsigned int)(Numeric::round32(Scalar(expectedHarrisCorners640x480) * Scalar(startLayerArea) / Scalar(640u * 480u)));
1323 expectedHarrisCornersOnLevel = (unsigned int)(Scalar(expectedHarrisCornersOnLevel) * (Scalar(1) - harrisCornersReductionScale) / (Scalar(1) - std::pow(harrisCornersReductionScale, Scalar(lastLayerIndex - startLayerIndex))));
1324#else
1325 const Scalar expectedHarrisCornersOnStartLayerF = Scalar(expectedHarrisCorners640x480) * Scalar(startLayerArea) / Scalar(640u * 480u);
1326 unsigned int expectedHarrisCornersOnLevel = (unsigned int)Numeric::round32(expectedHarrisCornersOnStartLayerF * (Scalar(1) - harrisCornersReductionScale) / (Scalar(1) - std::pow(harrisCornersReductionScale, Scalar(lastLayerIndex - startLayerIndex))));
1327#endif
1328
1329 // For each layer of the pyramid, extract Harris corners and compute their descriptors
1330
1331 for (unsigned int layer = startLayerIndex; layer <= lastLayerIndex; ++layer)
1332 {
1333 ocean_assert(layer + 1u < pyramid.layers());
1334 ocean_assert(corners.size() == descriptors.size());
1335 ocean_assert(corners.size() == cornerPyramidLevels.size());
1336
1337 if (expectedHarrisCornersOnLevel == 0u)
1338 {
1339 break;
1340 }
1341
1342 const Frame& pyramidLayer = pyramid[layer];
1343
1344 if (pyramidLayer.width() < Scalar(2) * border + Scalar(10) || pyramidLayer.height() < Scalar(2) * border + Scalar(10))
1345 {
1346 break;
1347 }
1348
1349 HarrisCorners harrisCornersOnLevel;
1350 if (CV::Detector::HarrisCornerDetector::detectCorners(pyramidLayer.constdata<uint8_t>(), pyramidLayer.width(), pyramidLayer.height(), pyramidLayer.paddingElements(), harrisCornerThreshold, yFrameIsUndistorted, harrisCornersOnLevel, determineExactHarrisCornerPositions, worker) == false)
1351 {
1352 return false;
1353 }
1354
1355 if (harrisCornersOnLevel.empty())
1356 {
1357 continue;
1358 }
1359
1360 // Select new corners. Make sure they are distributed approximately equal. Append them to the corresponding return value (corners)
1361
1362 ocean_assert(corners.size() == descriptors.size());
1363 ocean_assert(corners.size() == cornerPyramidLevels.size());
1364 const size_t firstNewCornerIndex = corners.size();
1365
1366 if (harrisCornersOnLevel.size() > expectedHarrisCornersOnLevel)
1367 {
1368 // Sort corners by the corner strength in descending order and distribute them over a regular grid of bins
1369
1370 std::sort(harrisCornersOnLevel.begin(), harrisCornersOnLevel.end());
1371
1372 unsigned int horizontalBins = 0u;
1373 unsigned int verticalBins = 0u;
1374 Geometry::SpatialDistribution::idealBins(pyramidLayer.width(), pyramidLayer.height(), expectedHarrisCornersOnLevel / 2u, horizontalBins, verticalBins);
1375 ocean_assert(horizontalBins != 0u && verticalBins != 0u);
1376
1377 const HarrisCorners newCorners = Geometry::SpatialDistribution::distributeAndFilter<HarrisCorner, HarrisCorner::corner2imagePoint>(harrisCornersOnLevel.data(), harrisCornersOnLevel.size(), border, border, Scalar(pyramidLayer.width()) - Scalar(2) * border, Scalar(pyramidLayer.height()) - Scalar(2) * border, horizontalBins, verticalBins, size_t(expectedHarrisCornersOnLevel));
1378
1379 corners.insert(corners.end(), newCorners.begin(), newCorners.end());
1380 }
1381 else
1382 {
1383 for (const HarrisCorner& corner : harrisCornersOnLevel)
1384 {
1385 if (corner.observation().x() >= border && corner.observation().x() < Scalar(pyramidLayer.width()) - border &&
1386 corner.observation().y() >= border && corner.observation().y() < Scalar(pyramidLayer.height()) - border)
1387 {
1388 corners.emplace_back(corner);
1389 }
1390 }
1391 }
1392
1393 ocean_assert(firstNewCornerIndex <= corners.size());
1394 const size_t newCornersAdded = corners.size() - firstNewCornerIndex;
1395
1396 if (newCornersAdded == 0)
1397 {
1398 continue;
1399 }
1400
1401 ocean_assert(firstNewCornerIndex + newCornersAdded == corners.size());
1402
1403#if defined(OCEAN_DEBUG)
1404 for (size_t i = firstNewCornerIndex; i < corners.size(); ++i)
1405 {
1406 ocean_assert(corners[i].observation().x() >= border && corners[i].observation().x() <= Scalar(pyramidLayer.width()) - border);
1407 ocean_assert(corners[i].observation().y() >= border && corners[i].observation().y() <= Scalar(pyramidLayer.height()) - border);
1408 }
1409#endif // OCEAN_DEBUG
1410
1411 // Store the pyramid level of the newly detected corners
1412
1413 cornerPyramidLevels.insert(cornerPyramidLevels.end(), newCornersAdded, layer);
1414
1415 // Extract the locations of the detected corners for the computation of their descriptors
1416
1417 std::vector<Eigen::Vector2f> observations;
1418 observations.reserve(newCornersAdded);
1419
1420 for (size_t i = firstNewCornerIndex; i < corners.size(); ++i)
1421 {
1422 observations.emplace_back(float(corners[i].observation().x()), float(corners[i].observation().y()));
1423 }
1424
1425 // Scale inverse focal length defined at the finest pyramid layer to current pyramid layer:
1426 //
1427 // f - focal length at finest level of the image pyramid
1428 // l - current pyramid level
1429 // scale_l = 2^l - pyramid scale
1430 // f_l - scaled focal length at pyramid level l
1431 //
1432 // f_l = f / scale_l
1433 // <=> 1 / f_l = scale_l * (1 / f)
1434 const float inverseFocalLengthAtLayer = float(1u << layer) * inverseFocalLength;
1435
1436 // Compute the descriptors (and directly append them to the return value)
1437
1438 ocean_assert(corners.size() > descriptors.size());
1439 descriptors.resize(corners.size());
1440
1441 ocean_assert(descriptors.begin() + size_t(firstNewCornerIndex) + observations.size() == descriptors.end());
1442 FREAKDescriptorT<tSize>::computeDescriptors(pyramid, observations.data(), observations.size(), layer, descriptors.data() + firstNewCornerIndex, inverseFocalLengthAtLayer, cameraDerivativeFunctor, worker);
1443
1444 expectedHarrisCornersOnLevel = (unsigned int)Numeric::round32(Scalar(expectedHarrisCornersOnLevel) * harrisCornersReductionScale);
1445
1446 ocean_assert(corners.size() == descriptors.size());
1447 ocean_assert(corners.size() == cornerPyramidLevels.size());
1448 }
1449
1450 ocean_assert(corners.size() == descriptors.size());
1451 ocean_assert(corners.size() == cornerPyramidLevels.size());
1452
1453 if (removeInvalid && corners.empty() == false)
1454 {
1455 size_t i = 0;
1456 while (i < corners.size())
1457 {
1458 if (descriptors[i].isValid())
1459 {
1460 i++;
1461 }
1462 else
1463 {
1464 ocean_assert(corners.empty() == false);
1465 corners[i] = corners.back();
1466 corners.pop_back();
1467
1468 cornerPyramidLevels[i] = cornerPyramidLevels.back();
1469 cornerPyramidLevels.pop_back();
1470
1471 descriptors[i] = descriptors.back();
1472 descriptors.pop_back();
1473 }
1474 }
1475 }
1476
1477 ocean_assert(corners.size() == descriptors.size());
1478 ocean_assert(corners.size() == cornerPyramidLevels.size());
1479
1480 return true;
1481}
1482
1483} // namespace Detector
1484
1485} // namespace CV
1486
1487} // namespace Ocean
1488
1489#endif // META_OCEAN_CV_DETECTOR_FREAK_DESCRIPTOR_H
This class implements the abstract base class for all AnyCamera objects.
Definition AnyCamera.h:130
virtual void pointJacobian2x3IF(const VectorT3< T > &flippedCameraObjectPoint, T *jx, T *jy) const =0
Calculates the 2x3 jacobian matrix for the 3D object point projection into the camera frame.
virtual VectorT3< T > vectorIF(const VectorT2< T > &distortedImagePoint, const bool makeUnitVector=true) const =0
Returns a vector starting at the camera's center and intersecting a given 2D point in the image.
Functor that can be used to obtain the 2x3 Jacobian of the camera projection matrix wrt.
Definition FREAKDescriptor.h:186
SharedAnyCameras cameras_
The camera instance used to compute the Jacobian matrix and unprojection ray at the finest layer of a...
Definition FREAKDescriptor.h:221
unsigned int supportedPyramidLevels() const override
Returns the maximum number of pyramid levels for which camera derivative data can be computed.
Definition FREAKDescriptor.h:597
AnyCameraDerivativeFunctor(const SharedAnyCamera &camera, const unsigned int pyramidLevels=1u)
Constructs a valid functor to compute pinhole camera derivative data.
Definition FREAKDescriptor.h:564
FREAKDescriptorT< tSize >::CameraDerivativeData computeCameraDerivativeData(const Eigen::Vector2f &point, const unsigned int pointPyramidLevel) const override
Computes the point Jacobian of the projection matrix and unprojection ray for a specified point.
Definition FREAKDescriptor.h:590
Base class to compute the Jacobian of the camera projection matrix wrt.
Definition FREAKDescriptor.h:117
virtual ~CameraDerivativeFunctor()=default
Default destructor.
virtual FREAKDescriptorT< tSize >::CameraDerivativeData computeCameraDerivativeData(const Eigen::Vector2f &point, const unsigned int pointPyramidLevel=0u) const =0
Purely virtual function to compute the camera derivative data; has to be implemented in any derived c...
virtual unsigned int supportedPyramidLevels() const =0
Returns the maximum number of pyramid levels for which camera derivative data can be computed.
Functor that can be used to obtain the 2x3 Jacobian of the camera projection matrix wrt.
Definition FREAKDescriptor.h:144
PinholeCameraDerivativeFunctor(const PinholeCamera &pinholeCamera, const unsigned int pyramidLevels=1u)
Constructs a valid functor to compute pinhole camera derivative data.
Definition FREAKDescriptor.h:499
unsigned int supportedPyramidLevels() const override
Returns the maximum number of pyramid levels for which camera derivative data can be computed.
Definition FREAKDescriptor.h:534
FREAKDescriptorT< tSize >::CameraDerivativeData computeCameraDerivativeData(const Eigen::Vector2f &point, const unsigned int pointPyramidLevel) const override
Computes the point Jacobian of the projection matrix and unprojection ray for a specified point.
Definition FREAKDescriptor.h:527
PinholeCameras cameras_
The camera instance used to compute the Jacobian matrix and unprojection ray at the finest layer of a...
Definition FREAKDescriptor.h:179
Forward-declaration of the descriptor class.
Definition FREAKDescriptor.h:84
MultilevelDescriptorData data_
The actual FREAK descriptor data.
Definition FREAKDescriptor.h:492
static const float cellsY[numberOfCells]
The pre-defined vertical coordinates of the cells.
Definition FREAKDescriptor.h:442
static const std::uint8_t cellPairs[numberOfCellPairs][2]
The pre-defined pairs of cell indices that uare used to compute the actual binary descriptor (pairs h...
Definition FREAKDescriptor.h:448
static constexpr size_t kernelRadius3Elements
Number of elements in the circular kernel with radius 3.
Definition FREAKDescriptor.h:469
static const float cellsX[numberOfCells]
The pre-defined horizontal coordinates of the cells.
Definition FREAKDescriptor.h:439
static bool computeLocalDeformationMatrixAndOrientation(const FramePyramid &framePyramid, const Eigen::Vector2f &point, const unsigned int pointPyramidLevel, const Eigen::Vector3f &unprojectRayIF, const float inverseFocalLength, const PointJacobianMatrix2x3 &pointJacobianMatrix2x3, Eigen::Matrix< float, 2, 2 > &deformationMatrix, float &orientation)
Computes the transformation to deform receptive fields and the orientation of the descriptor.
Definition FREAKDescriptor.h:1136
static constexpr size_t numberOfCellPairs
The number of pre-defined pairs of cell indices that are used to compute the actual binary descriptor...
Definition FREAKDescriptor.h:445
FREAKDescriptorT(const FREAKDescriptorT< tSize > &)=default
Creates a new FREAK descriptor object by copying from an existing one.
FREAKDescriptorT()=default
Creates a new and invalid FREAK descriptor object.
static const int kernelRadius1Y[kernelRadius1Elements]
The pre-defined vertical coordinates of the circular kernel with radius 1.
Definition FREAKDescriptor.h:457
OCEAN_FORCE_INLINE unsigned int distance(const FREAKDescriptorT< tSize > &descriptor) const
Returns the distance between this descriptor and a second descriptor.
Definition FREAKDescriptor.h:659
static void computeDescriptorsSubset(const FramePyramid *framePyramid, const Eigen::Vector2f *points, const size_t pointsSize, const unsigned int pointPyramidLevel, FREAKDescriptorT< tSize > *freakDescriptors, const float inverseFocalLength, const CameraDerivativeFunctor *cameraDerivativeFunctor, const unsigned int firstPoint, const unsigned int numberOfPoints)
Compute a FREAK descriptor for a single point.
Definition FREAKDescriptor.h:1117
float orientation() const
Returns the orientation of the descriptor in Radian.
Definition FREAKDescriptor.h:633
static void computeDescriptors(const FramePyramid &framePyramid, const Eigen::Vector2f *points, const size_t pointsSize, const unsigned int pointsPyramidLevel, FREAKDescriptorT< tSize > *freakDescriptors, const float inverseFocalLength, const CameraDerivativeFunctor &cameraDerivativeFunctor, Worker *worker=nullptr)
Compute a FREAK descriptor for a single point This function requires a callback function which is use...
Definition FREAKDescriptor.h:700
FREAKDescriptorT & operator=(const FREAKDescriptorT< tSize > &) noexcept=default
Copy assignment operator, needs to be defined since there is a custom copy constructor.
float orientation_
The orientation of this descriptor in radian, range: [-pi, pi].
Definition FREAKDescriptor.h:489
unsigned int descriptorLevels() const
Returns the number of levels stored in the multi-level descriptor.
Definition FREAKDescriptor.h:652
std::array< SinglelevelDescriptorData, 3 > MultilevelDescriptorData
Multi-level FREAK descriptor data; if possible, this implementation computes the descriptor at three ...
Definition FREAKDescriptor.h:99
static const int kernelRadius7X[kernelRadius7Elements]
The pre-defined horizontal coordinates of the circular kernel with radius 7.
Definition FREAKDescriptor.h:481
static bool blurAndDownsampleByTwo11(const Frame &finerLayer, Frame &coarserLayer, Worker *worker, const unsigned int kernelWidth, const unsigned int kernelHeight, Frame &reusableFrame)
Downsamples a frame by two applying a 1-1 filter after applying a Gaussian blur to the source layer.
Definition FREAKDescriptor.h:1247
std::array< PixelType, tSize > SinglelevelDescriptorData
Single-level FREAK descriptor.
Definition FREAKDescriptor.h:96
std::uint8_t PixelType
Typedef for the selected pixel type. This might be turned into a template parameter at some point.
Definition FREAKDescriptor.h:90
static const int kernelRadius7Y[kernelRadius7Elements]
The pre-defined vertical coordinates of the circular kernel with radius 7.
Definition FREAKDescriptor.h:484
static constexpr size_t numberOfCells
The number of cells per keypoint that this implementation is using.
Definition FREAKDescriptor.h:436
static FramePyramid createFramePyramidWithBlur8BitsPerChannel(const Frame &frame, const unsigned int kernelWidth, const unsigned int kernelHeight, const unsigned int layers, Worker *worker=nullptr)
Creates a new pyramid frame for a specific pixel format (a specific number of channels) and applies a...
Definition FREAKDescriptor.h:1225
unsigned int dataLevels_
Number of valid levels in the multi-level descriptor data above, range: [0, 3].
Definition FREAKDescriptor.h:495
MultilevelDescriptorData & data()
Returns the descriptor data (writable)
Definition FREAKDescriptor.h:640
static bool extractHarrisCornersAndComputeDescriptors(const Frame &yFrame, const unsigned int maxFrameArea, const unsigned int minFrameArea, const unsigned int expectedHarrisCorners640x480, const Scalar harrisCornersReductionScale, const unsigned int harrisCornerThreshold, const float inverseFocalLength, const CameraDerivativeFunctor &cameraDerivativeFunctor, HarrisCorners &corners, Indices32 &cornerPyramidLevels, std::vector< FREAKDescriptorT< tSize > > &descriptors, const bool removeInvalid=false, const Scalar border=Scalar(20), const bool determineExactHarrisCornerPositions=false, const bool yFrameIsUndistorted=true, Worker *worker=nullptr)
Extract Harris corners from an image pyramid and compute FREAK descriptors.
Definition FREAKDescriptor.h:1284
static const int kernelRadius3X[kernelRadius3Elements]
The pre-defined horizontal coordinates of the circular kernel with radius 3.
Definition FREAKDescriptor.h:472
static const int kernelRadius3Y[kernelRadius3Elements]
The pre-defined vertical coordinates of the circular kernel with radius 3.
Definition FREAKDescriptor.h:475
static const int kernelRadius2Y[kernelRadius2Elements]
The pre-defined vertical coordinates of the circular kernel with radius 2.
Definition FREAKDescriptor.h:466
static const int kernelRadius2X[kernelRadius2Elements]
The pre-defined horizontal coordinates of the circular kernel with radius 2.
Definition FREAKDescriptor.h:463
static constexpr size_t kernelRadius2Elements
Number of elements in the circular kernel with radius 2.
Definition FREAKDescriptor.h:460
static bool computeAverageCellIntensity(const Frame &framePyramidLayer, int x, int y, const int *kernelX, const int *kernelY, const size_t kernelElements, PixelType &averageIntensity)
Computes the average intensity of a cell.
Definition FREAKDescriptor.h:1063
static constexpr size_t size()
Returns the length of this descriptor in bytes.
Definition FREAKDescriptor.h:694
static bool computeDescriptor(const FramePyramid &framePyramid, const Eigen::Vector2f &point, const unsigned int pointPyramidLevel, FREAKDescriptorT< tSize > &freakDescriptor, const Eigen::Vector3f &unprojectRayIF, const float inverseFocalLength, const PointJacobianMatrix2x3 &pointJacobianMatrix2x3)
Compute a FREAK descriptor for a single point.
Definition FREAKDescriptor.h:878
static const int kernelRadius1X[kernelRadius1Elements]
The pre-defined horizontal coordinates of the circular kernel with radius 1.
Definition FREAKDescriptor.h:454
static constexpr size_t kernelRadius1Elements
Number of elements in the circular kernel with radius 1.
Definition FREAKDescriptor.h:451
bool isValid() const
Returns true if this is a valid descriptor.
Definition FREAKDescriptor.h:688
Eigen::Matrix< float, 2, 3 > PointJacobianMatrix2x3
The Jacobian of the projection matrix at a specific 3D location (ray from projection center to pixel ...
Definition FREAKDescriptor.h:93
static constexpr size_t kernelRadius7Elements
Number of elements in the circular kernel with radius 7.
Definition FREAKDescriptor.h:478
static bool detectCorners(const uint8_t *yFrame, const unsigned int width, const unsigned int height, const unsigned int yFramePaddingElements, const unsigned int threshold, const bool frameIsUndistorted, HarrisCorners &corners, const bool determineExactPosition=false, Worker *worker=nullptr)
Detects Harris corners inside a given 8 bit grayscale image.
Definition HarrisCornerDetector.h:397
This class implements a Harris corner.
Definition HarrisCorner.h:37
This class implements a frame pyramid.
Definition FramePyramid.h:37
bool isValid() const
Returns whether this pyramid holds at least one frame layer.
Definition FramePyramid.h:863
std::function< bool(const Frame &sourceLayer, Frame &targetLayer, Worker *worker)> DownsamplingFunction
Definition of a function allowing to downsample a frame.
Definition FramePyramid.h:82
unsigned int width(const unsigned int layer) const
Returns the width of a given layer.
Definition FramePyramid.h:766
unsigned int layers() const
Returns the number of layers this pyramid holds.
Definition FramePyramid.h:761
const FrameType & frameType() const
Returns the frame type of the finest layer.
Definition FramePyramid.h:811
unsigned int height(const unsigned int layer) const
Returns the height of a given layer.
Definition FramePyramid.h:772
const Frame & layer(const unsigned int layer) const
Returns the frame of a specified layer.
Definition FramePyramid.h:723
static void downsampleByTwo8BitPerChannel11(const uint8_t *source, uint8_t *target, const unsigned int sourceWidth, const unsigned int sourceHeight, const unsigned int channels, const unsigned int sourcePaddingElements, const unsigned int targetPaddingElements, Worker *worker=nullptr)
Reduces the resolution of a given frame by two, applying a 1-1 downsampling.
Definition FrameShrinker.h:508
static Caller< void > createStatic(typename StaticFunctionPointerMaker< void, NullClass, NullClass, NullClass, NullClass, NullClass, NullClass, NullClass, NullClass, NullClass, NullClass, NullClass, NullClass, NullClass, NullClass, NullClass, NullClass, NullClass, NullClass, NullClass, NullClass >::Type function)
Creates a new caller container for a static function with no function parameter.
Definition Caller.h:2876
This class implements Ocean's image class.
Definition Frame.h:1808
unsigned int strideElements(const unsigned int planeIndex=0u) const
Returns the number of elements within one row, including optional padding at the end of a row for a s...
Definition Frame.h:4138
const T * constdata(const unsigned int planeIndex=0u) const
Returns a pointer to the read-only pixel data of a specific plane.
Definition Frame.h:4248
const FrameType & frameType() const
Returns the frame type of this frame.
Definition Frame.h:3855
T * data(const unsigned int planeIndex=0u)
Returns a pointer to the pixel data of a specific plane.
Definition Frame.h:4239
bool isValid() const
Returns whether this frame is valid.
Definition Frame.h:4528
bool set(const FrameType &frameType, const bool forceOwner, const bool forceWritable=false, const Indices32 &planePaddingElements=Indices32(), const Timestamp &timestamp=Timestamp(false), bool *reallocated=nullptr)
Sets a new frame type for this frame.
unsigned int size(const unsigned int planeIndex=0u) const
Returns the number of bytes necessary for a specific plane including optional padding at the end of p...
Definition Frame.h:4114
unsigned int paddingElements(const unsigned int planeIndex=0u) const
Returns the optional number of padding elements at the end of each row for a specific plane.
Definition Frame.h:4122
@ FORMAT_Y8
Pixel format for grayscale images with byte order Y and 8 bits per pixel.
Definition Frame.h:594
unsigned int width() const
Returns the width of the frame format in pixel.
Definition Frame.h:3170
uint32_t numberPlanes() const
Returns the number of planes of the pixel format of this frame.
Definition Frame.h:3210
static bool arePixelFormatsCompatible(const PixelFormat pixelFormatA, const PixelFormat pixelFormatB)
Returns whether two given pixel formats are compatible.
PixelFormat pixelFormat() const
Returns the pixel format of the frame.
Definition Frame.h:3180
@ DT_UNSIGNED_INTEGER_8
Unsigned 8 bit integer data type (uint8_t).
Definition Frame.h:41
unsigned int height() const
Returns the height of the frame in pixel.
Definition Frame.h:3175
bool isPixelFormatCompatible(const PixelFormat pixelFormat) const
Returns whether the pixel format of this frame type is compatible with a given pixel format.
Definition Frame.h:3227
unsigned int channels() const
Returns the number of individual channels the frame has.
Definition Frame.h:3200
DataType dataType() const
Returns the data type of the pixel format of this frame.
Definition Frame.h:3190
static void calculatePointJacobian2x3(Scalar *jx, Scalar *jy, const PinholeCamera &pinholeCamera, const HomogenousMatrix4 &flippedCamera_P_world, const Vector3 &objectPoint, const bool distortImagePoint)
Calculates the two jacobian rows for a given pose and dynamic object point.
static void idealBins(const unsigned int width, const unsigned int height, const size_t numberBins, unsigned int &horizontalBins, unsigned int &verticalBins, const unsigned int minimalHorizontalBins=2u, const unsigned int minimalVerticalBins=2u)
Calculates the ideal number of horizontal and vertical bins for an array if the overall number of bin...
static constexpr bool isInsideRange(const T lower, const T value, const T upper, const T epsilon=NumericT< T >::eps())
Returns whether a value lies between a given range up to a provided epsilon border.
Definition Numeric.h:2872
static T atan2(const T y, const T x)
Returns the arctangent of a given value in radian.
Definition Numeric.h:1632
static constexpr T pi()
Returns PI which is equivalent to 180 degree.
Definition Numeric.h:926
static T log10(const T value)
Returns the logarithm to base 10 of a given value.
Definition Numeric.h:1711
static constexpr int32_t round32(const T value)
Returns the rounded 32 bit integer value of a given value.
Definition Numeric.h:2064
static constexpr bool isEqualEps(const T value)
Returns whether a value is smaller than or equal to a small epsilon.
Definition Numeric.h:2087
unsigned int width() const
Returns the width of the camera image.
Definition PinholeCamera.h:1300
T principalPointX() const
Returns the x-value of the principal point of the camera image in the pixel domain.
Definition PinholeCamera.h:1318
bool isValid() const
Returns whether this camera is valid.
Definition PinholeCamera.h:1572
bool hasDistortionParameters() const
Returns whether this camera object has specified distortion parameters.
Definition PinholeCamera.h:1293
VectorT3< T > vectorIF(const VectorT2< T > &position, const bool makeUnitVector=true) const
Returns a normalized vector (with length 1) starting at the camera's center and intersecting a given ...
Definition PinholeCamera.h:2335
unsigned int height() const
Returns the height of the camera image.
Definition PinholeCamera.h:1306
T inverseFocalLengthX() const
Returns the inverse horizontal focal length parameter.
Definition PinholeCamera.h:1342
T principalPointY() const
Returns the y-value of the principal point of the camera image in the pixel domain.
Definition PinholeCamera.h:1324
T inverseFocalLengthY() const
Returns the inverse vertical focal length parameter.
Definition PinholeCamera.h:1351
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
This class implements a worker able to distribute function calls over different threads.
Definition Worker.h:33
bool executeFunction(const Function &function, const unsigned int first, const unsigned int size, const unsigned int firstIndex=(unsigned int)(-1), const unsigned int sizeIndex=(unsigned int)(-1), const unsigned int minimalIterations=1u, const unsigned int threadIndex=(unsigned int)(-1))
Executes a callback function separable by two function parameters.
std::vector< Index32 > Indices32
Definition of a vector holding 32 bit index values.
Definition Base.h:96
std::vector< HarrisCorner > HarrisCorners
Definition of a vector holding Harris corners.
Definition HarrisCorner.h:30
float Scalar
Definition of a scalar type.
Definition Math.h:129
std::shared_ptr< AnyCamera > SharedAnyCamera
Definition of a shared pointer holding an AnyCamera object with Scalar precision.
Definition AnyCamera.h:60
VectorT3< Scalar > Vector3
Definition of a 3D vector.
Definition Vector3.h:29
PinholeCamerasT< Scalar > PinholeCameras
Definition of a vector holding pinhole camera objects.
Definition PinholeCamera.h:68
HomogenousMatrixT4< Scalar > HomogenousMatrix4
Definition of the HomogenousMatrix4 object, depending on the OCEAN_MATH_USE_SINGLE_PRECISION flag eit...
Definition HomogenousMatrix4.h:44
SharedAnyCamerasT< Scalar > SharedAnyCameras
Definition of a vector holding AnyCamera objects.
Definition AnyCamera.h:90
VectorT2< Scalar > Vector2
Definition of a 2D vector.
Definition Vector2.h:28
std::vector< FREAKDescriptor32 > FREAKDescriptors32
Vector of 32-bytes long FREAK descriptors.
Definition FREAKDescriptor.h:69
FREAKDescriptorT< 32 > FREAKDescriptor32
Typedef for the 32-bytes long FREAK descriptor.
Definition FREAKDescriptor.h:66
std::vector< FREAKDescriptor64 > FREAKDescriptors64
Vector of 64-bytes long FREAK descriptors.
Definition FREAKDescriptor.h:75
The namespace covering the entire Ocean framework.
Definition Accessor.h:15
The camera data that is required to compute the FREAK descriptor of a image point.
Definition FREAKDescriptor.h:105
Eigen::Vector3f unprojectRayIF
The normalized ray that points from projection center to a 2D pixel location in the image plane of ca...
Definition FREAKDescriptor.h:107
PointJacobianMatrix2x3 pointJacobianMatrixIF
The 2-by-3 Jacobian matrix of a projection matrix wrt. to the above 2D pixel location in the image pl...
Definition FREAKDescriptor.h:110