Ocean
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 
41 #include "ocean/cv/FramePyramid.h"
42 #include "ocean/cv/FrameShrinker.h"
43 
46 
48 
49 #include <Eigen/Core>
50 #include <Eigen/Dense>
51 
52 namespace Ocean
53 {
54 
55 namespace CV
56 {
57 
58 namespace Detector
59 {
60 
61 /// Forward-declaration of the descriptor class.
62 template <size_t tSize>
63 class FREAKDescriptorT;
64 
65 /// Typedef for the 32-bytes long FREAK descriptor
67 
68 /// Vector of 32-bytes long FREAK descriptors
69 using FREAKDescriptors32 = std::vector<FREAKDescriptor32>;
70 
71 /// Typedef for the 64-bytes long FREAK descriptor
73 
74 /// Vector of 64-bytes long FREAK descriptors
75 using 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  */
82 template <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  */
254  inline MultilevelDescriptorData& data();
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 
498 template <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 
526 template <size_t tSize>
528 {
529  ocean_assert(pointPyramidLevel < cameras_.size());
531 }
532 
533 template <size_t tSize>
535 {
536  return (unsigned int)(cameras_.size());
537 }
538 
539 template <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 
563 template <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 
589 template <size_t tSize>
590 typename FREAKDescriptorT<tSize>::CameraDerivativeData FREAKDescriptorT<tSize>::AnyCameraDerivativeFunctor::computeCameraDerivativeData(const Eigen::Vector2f& point, const unsigned int pointPyramidLevel) const
591 {
592  ocean_assert(pointPyramidLevel < cameras_.size());
594 }
595 
596 template <size_t tSize>
598 {
599  return (unsigned int)(cameras_.size());
600 }
601 
602 template <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 
622 template <size_t tSize>
623 FREAKDescriptorT<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 
632 template <size_t tSize>
634 {
636  return orientation_;
637 }
638 
639 template <size_t tSize>
641 {
642  return data_;
643 }
644 
645 template <size_t tSize>
647 {
648  return data_;
649 }
650 
651 template <size_t tSize>
652 inline unsigned int FREAKDescriptorT<tSize>::descriptorLevels() const
653 {
654  ocean_assert(dataLevels_ <= 3u);
655  return dataLevels_;
656 }
657 
658 template <size_t tSize>
659 OCEAN_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 
687 template <size_t tSize>
689 {
691 }
692 
693 template <size_t tSize>
695 {
696  return tSize;
697 }
698 
699 template <size_t tSize>
700 inline 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 
718 template <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 
730 template <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 
742 template <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 
801 template <size_t tSize>
802 const int FREAKDescriptorT<tSize>::kernelRadius1X[kernelRadius1Elements] = { 0, -1, 0, 1, 0 };
803 
804 template <size_t tSize>
805 const int FREAKDescriptorT<tSize>::kernelRadius1Y[kernelRadius1Elements] = { -1, 0, 0, 0, 1 };
806 
807 template <size_t tSize>
808 const int FREAKDescriptorT<tSize>::kernelRadius2X[kernelRadius2Elements] = { 0, -1, 0, 1, -2, -1, 0, 1, 2, -1, 0, 1, 0 };
809 
810 template <size_t tSize>
811 const int FREAKDescriptorT<tSize>::kernelRadius2Y[kernelRadius2Elements] = { -2, -1, -1, -1, 0, 0, 0, 0, 0, 1, 1, 1, 2 };
812 
813 template <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 
823 template <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 
833 template <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 
855 template <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 
877 template <size_t tSize>
878 bool 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 
905  float warpedCellX[FREAKDescriptorT<tSize>::numberOfCells];
906  float warpedCellY[FREAKDescriptorT<tSize>::numberOfCells];
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 
1061 template <size_t tSize>
1062 template <bool tEnableBorderChecks>
1063 bool 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 
1116 template <size_t tSize>
1117 void 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 
1135 template <size_t tSize>
1136 bool 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());
1140  ocean_assert(pyramid.frameType().isPixelFormatCompatible(FrameType::FORMAT_Y8));
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 
1224 template <size_t tSize>
1225 FramePyramid 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 
1246 template <size_t tSize>
1247 bool 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 
1283 template <size_t tSize>
1284 bool 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 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.
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.
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 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 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
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 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
FREAKDescriptorT & operator=(const FREAKDescriptorT< tSize > &) noexcept=default
Copy assignment operator, needs to be defined since there is a custom copy constructor.
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:1760
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:4026
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:4136
const FrameType & frameType() const
Returns the frame type of this frame.
Definition: Frame.h:3743
T * data(const unsigned int planeIndex=0u)
Returns a pointer to the pixel data of a specific plane.
Definition: Frame.h:4127
bool isValid() const
Returns whether this frame is valid.
Definition: Frame.h:4416
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:4002
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:4010
@ 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:3111
uint32_t numberPlanes() const
Returns the number of planes of the pixel format of this frame.
Definition: Frame.h:3151
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:3121
@ 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:3116
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:3166
unsigned int channels() const
Returns the number of individual channels the frame has.
Definition: Frame.h:3141
DataType dataType() const
Returns the data type of the pixel format of this frame.
Definition: Frame.h:3131
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:812
const T & x() const noexcept
Returns the x value.
Definition: Vector3.h:800
VectorT3< T > normalized() const
Returns the normalized vector.
Definition: Vector3.h:605
const T & z() const noexcept
Returns the z value.
Definition: Vector3.h:824
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:24
float Scalar
Definition of a scalar type.
Definition: Math.h:128
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:22
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:37
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:21
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