Ocean
ORBFeatureDescriptor.h
Go to the documentation of this file.
1 /*
2  * Copyright (c) Meta Platforms, Inc. and affiliates.
3  *
4  * This source code is licensed under the MIT license found in the
5  * LICENSE file in the root directory of this source tree.
6  */
7 
8 #ifndef META_OCEAN_CV_DETECTOR_ORB_FEATURE_DESCRIPTOR_H
9 #define META_OCEAN_CV_DETECTOR_ORB_FEATURE_DESCRIPTOR_H
10 
14 
15 #include "ocean/base/Frame.h"
16 #include "ocean/base/Worker.h"
17 
19 #include "ocean/cv/FramePyramid.h"
20 
21 #if defined(OCEAN_HARDWARE_SSE_VERSION) && OCEAN_HARDWARE_SSE_VERSION >= 30
22  #include "ocean/cv/SSE.h"
23 #endif
24 
25 #if defined(OCEAN_HARDWARE_NEON_VERSION) && OCEAN_HARDWARE_NEON_VERSION >= 10
26  #include "ocean/cv/NEON.h"
27 #endif
28 
29 namespace Ocean
30 {
31 
32 namespace CV
33 {
34 
35 namespace Detector
36 {
37 
38 /**
39  * This class implements all necessary functions for the ORB feature descriptor and matcher.
40  * @ingroup cvdetector
41  */
42 class OCEAN_CV_DETECTOR_EXPORT ORBFeatureDescriptor
43 {
44  public:
45 
46  /**
47  * Calculate the ORB descriptor for all given feature points.
48  * If sub layers are used, three descriptors are determined per feature. One for the unmodified frame size, one for a resizing factor of sqrt(2) and one for a resizing factor of 1/sqrt(2).
49  * @param linedIntegralFrame Pointer to the (lined) integral frame of the actual 8 bit frame for which the feature descriptors will be calculated, the integral frame has an extra line with zero pixels on the left and top of the integral frame
50  * @param width The width of the original frame in pixel (not the width of the lined-integral frame), with range [43, infinity)
51  * @param height The height of the original frame in pixel (not the height of the lined-integral frame), with range [43, infinity)
52  * @param featurePoints Feature points to calculate the descriptors for, with range [21, width - 22]x[21, height - 22] for 'useMultiLayers == false', with range [31, width - 32]x[31, height - 32] for 'useMultiLayers == true'
53  * @param useMultiLayers True, if two additional sub layers for descriptors are use, create three descriptors per feature point; otherwise, only one layer is used
54  * @param worker Optional worker object to distribute the computation to several CPU cores
55  */
56  static inline void determineDescriptors(const uint32_t* linedIntegralFrame, const unsigned int width, const unsigned int height, ORBFeatures& featurePoints, const bool useMultiLayers = false, Worker* worker = nullptr);
57 
58  /**
59  * Detect feature points of the reference frame and calculate the ORB descriptors for them.
60  * Feature points are detect within individual pyramid layers separately, and for each of this feature points three descriptors are calculated.
61  * @param frame The reference frame for which the feature points will be determined, must be valid
62  * @param featurePoints The resulting feature points
63  * @param pyramidLayers The number of pyramid layers to use, with range [1, infinity)
64  * @param useHarrisFeatures True, to use Harris corners; False, to use FAST features
65  * @param featureThreshold The threshold to be used during feature detection, with range [0, 255]
66  * @param worker Optional worker object to distribute the computation to several CPU cores
67  * @return True, if succeeded
68  */
69  static inline bool detectReferenceFeaturesAndDetermineDescriptors(const Frame& frame, ORBFeatures& featurePoints, const unsigned int pyramidLayers, const bool useHarrisFeatures, const unsigned int featureThreshold, Worker* worker);
70 
71  /**
72  * Detect feature points in a reference frame and calculate the ORB descriptors for them.
73  * Feature points are detect within individual pyramid layers separately, and for each of this feature points three descriptors are calculated.
74  * @param framePyramid Frame pyramid of the reference frame
75  * @param featurePoints The resulting feature points
76  * @param useHarrisFeatures True, to use Harris corners; False, to use FAST features
77  * @param featureThreshold The threshold to be used during feature detection, with range [0, 255]
78  * @param worker Optional worker object to distribute the computation to several CPU cores
79  */
80  static void detectReferenceFeaturesAndDetermineDescriptors(const FramePyramid& framePyramid, ORBFeatures& featurePoints, const bool useHarrisFeatures, const unsigned int featureThreshold, Worker* worker);
81 
82  /**
83  * Determines feature correspondences - one backward feature point for each given forward feature point.
84  * @param forwardFeatures The forward feature points for which corresponding backward features will be determined, at least one
85  * @param backwardFeatures The backward feature points, at least one
86  * @param correspondences The resulting feature correspondences, pairs of feature indices (forward to backward indices)
87  * @param threshold The percentage (in relation to the number of descriptor bits) of the maximal hamming distance so that two descriptors count as similar, with range [0, 1]
88  * @param worker Optional worker object to distribute the computation to several CPU cores
89  */
90  static inline void determineNonBijectiveCorrespondences(const ORBFeatures& forwardFeatures, const ORBFeatures& backwardFeatures, IndexPairs32& correspondences, const float threshold = 0.15f, Worker* worker = nullptr);
91 
92  /**
93  * Calculate the hamming distance between two feature descriptors (the number of different bits).
94  * @param referenceDescriptor Reference descriptor
95  * @param featureDescriptor Feature descriptor
96  * @return Hamming distance, with range [0, 256]
97  */
98  static OCEAN_FORCE_INLINE unsigned int calculateHammingDistance(const ORBDescriptor& referenceDescriptor, const ORBDescriptor& featureDescriptor);
99 
100  protected:
101 
102  /**
103  * Calculate the ORB descriptor for all given feature points.
104  * If sub layers are used, three descriptors are determined per feature. One for the unmodified frame size, one for a resizing factor of sqrt(2) and one for a resizing factor of 1/sqrt(2).
105  * @param linedIntegralFrame Pointer to the (lined) integral frame of the actual 8 bit frame for which the feature descriptors will be calculated, the integral frame has an extra line with zero pixels on the left and top of the integral frame
106  * @param width The width of the original frame in pixel (not the width of the lined-integral frame), with range [43, infinity)
107  * @param height The height of the original frame in pixel (not the height of the lined-integral frame), with range [43, infinity)
108  * @param featurePoints Feature points to calculate the descriptors for, with range [21, width - 22]x[21, height - 22] for 'useMultiLayers == false', with range [31, width - 32]x[31, height - 32] for 'useMultiLayers == true'
109  * @param useMultiLayers True, if two additional sub layers for descriptors are use, create three descriptors per feature point; otherwise, only one layer is used
110  * @param firstFeaturePoint The first feature points to be handled, with range [0, size)
111  * @param numberFeaturePoints The number of feature points to be handled, with range [1, size]
112  */
113  static void determineDescriptorsSubset(const uint32_t* linedIntegralFrame, const unsigned int width, const unsigned int height, ORBFeature* featurePoints, const bool useMultiLayers, const unsigned int firstFeaturePoint, const unsigned int numberFeaturePoints);
114 
115  /**
116  * Determines feature correspondences for a subset of forward feature points - one backward feature point for each given forward feature point.
117  * @param forwardFeatures The forward feature points for which corresponding backward features will be determined, must be valid
118  * @param numberForwardFeatures The number of forward feature points, with range [0, infinity)
119  * @param backwardFeatures The backward feature points, must be valid
120  * @param numberBackwardFeatures The number of backward feature points, with range [0, infinity)
121  * @param threshold The percentage (in relation to the number of descriptor bits) of the maximal hamming distance so that two descriptors count as similar, with range [0, 1]
122  * @param correspondences The resulting feature correspondences, pairs of feature indices (forward to backward indices)
123  * @param lock The lock for thread save adding of the match indices, nullptr if the function is executed single-threaded
124  * @param firstIndex First index of the feature point vector to be handled
125  * @param numberIndices Number of feature points to be handled
126  */
127  static void determineNonBijectiveCorrespondencesSubset(const ORBFeature* forwardFeatures, const size_t numberForwardFeatures, const ORBFeature* backwardFeatures, const size_t numberBackwardFeatures, const float threshold, IndexPairs32* correspondences, Lock* lock, const unsigned int firstIndex, const unsigned int numberIndices);
128 };
129 
130 inline void ORBFeatureDescriptor::determineDescriptors(const uint32_t* linedIntegralFrame, const unsigned int width, const unsigned int height, ORBFeatures& featurePoints, const bool useMultiLayers, Worker* worker)
131 {
132  ocean_assert(linedIntegralFrame != nullptr);
133  ocean_assert(width >= 43u && height >= 43u);
134 
135  if (worker)
136  {
137  worker->executeFunction(Worker::Function::createStatic(&ORBFeatureDescriptor::determineDescriptorsSubset, linedIntegralFrame, width, height, featurePoints.data(), useMultiLayers, 0u, 0u), 0u, (unsigned int)(featurePoints.size()));
138  }
139  else
140  {
141  determineDescriptorsSubset(linedIntegralFrame, width, height, featurePoints.data(), useMultiLayers, 0u, (unsigned int)(featurePoints.size()));
142  }
143 }
144 
145 inline bool ORBFeatureDescriptor::detectReferenceFeaturesAndDetermineDescriptors(const Frame& frame, ORBFeatures& featurePoints, const unsigned int pyramidLayers, const bool useHarrisFeatures, const unsigned int featureThreshold, Worker* worker)
146 {
147  Frame yFrame;
149  {
150  return false;
151  }
152 
153  const unsigned int maxLayerNumber = FramePyramid::idealLayers(frame.width(), frame.height(), 64u, 64u);
154 
155  if (maxLayerNumber == 0u)
156  {
157  return false;
158  }
159 
160  const FramePyramid framePyramid(yFrame, std::min(pyramidLayers, maxLayerNumber), false /*copyFirstLayer*/, worker);
161 
162  if (!framePyramid.isValid())
163  {
164  return false;
165  }
166 
167  detectReferenceFeaturesAndDetermineDescriptors(framePyramid, featurePoints, useHarrisFeatures, featureThreshold, worker);
168 
169  return true;
170 }
171 
172 inline void ORBFeatureDescriptor::determineNonBijectiveCorrespondences(const ORBFeatures& forwardFeatures, const ORBFeatures& backwardFeatures, IndexPairs32& correspondences, const float threshold, Worker* worker)
173 {
174  ocean_assert(threshold >= 0.0f && threshold <= 1.0f);
175 
176  correspondences.reserve(forwardFeatures.size());
177 
178  if (worker != nullptr)
179  {
180  Lock lock;
181  worker->executeFunction(Worker::Function::createStatic(&ORBFeatureDescriptor::determineNonBijectiveCorrespondencesSubset, forwardFeatures.data(), forwardFeatures.size(), backwardFeatures.data(), backwardFeatures.size(), threshold, &correspondences, &lock, 0u, 0u), 0u, (unsigned int)(forwardFeatures.size()));
182  }
183  else
184  {
185  determineNonBijectiveCorrespondencesSubset(forwardFeatures.data(), forwardFeatures.size(), backwardFeatures.data(), backwardFeatures.size(), threshold, &correspondences, nullptr, 0u, (unsigned int)(forwardFeatures.size()));
186  }
187 }
188 
189 OCEAN_FORCE_INLINE unsigned int ORBFeatureDescriptor::calculateHammingDistance(const ORBDescriptor& referenceDescriptor, const ORBDescriptor& featureDescriptor)
190 {
191  static_assert(sizeof(ORBDescriptor::DescriptorBitset) == 256 / 8, "Invalid descriptor size!");
192 
193  return Descriptor::calculateHammingDistance<256>(&referenceDescriptor, &featureDescriptor);
194 }
195 
196 }
197 
198 }
199 
200 }
201 
202 #endif // META_OCEAN_CV_DETECTOR_ORB_FEATURE_DESCRIPTOR_H
This class implement the descriptor for ORB features.
Definition: ORBDescriptor.h:41
std::bitset< descriptorLengthInBits > DescriptorBitset
Definition of a bitset with 256 bits.
Definition: ORBDescriptor.h:50
This class implements all necessary functions for the ORB feature descriptor and matcher.
Definition: ORBFeatureDescriptor.h:43
static void determineNonBijectiveCorrespondencesSubset(const ORBFeature *forwardFeatures, const size_t numberForwardFeatures, const ORBFeature *backwardFeatures, const size_t numberBackwardFeatures, const float threshold, IndexPairs32 *correspondences, Lock *lock, const unsigned int firstIndex, const unsigned int numberIndices)
Determines feature correspondences for a subset of forward feature points - one backward feature poin...
static void detectReferenceFeaturesAndDetermineDescriptors(const FramePyramid &framePyramid, ORBFeatures &featurePoints, const bool useHarrisFeatures, const unsigned int featureThreshold, Worker *worker)
Detect feature points in a reference frame and calculate the ORB descriptors for them.
static void determineNonBijectiveCorrespondences(const ORBFeatures &forwardFeatures, const ORBFeatures &backwardFeatures, IndexPairs32 &correspondences, const float threshold=0.15f, Worker *worker=nullptr)
Determines feature correspondences - one backward feature point for each given forward feature point.
Definition: ORBFeatureDescriptor.h:172
static void determineDescriptorsSubset(const uint32_t *linedIntegralFrame, const unsigned int width, const unsigned int height, ORBFeature *featurePoints, const bool useMultiLayers, const unsigned int firstFeaturePoint, const unsigned int numberFeaturePoints)
Calculate the ORB descriptor for all given feature points.
static void determineDescriptors(const uint32_t *linedIntegralFrame, const unsigned int width, const unsigned int height, ORBFeatures &featurePoints, const bool useMultiLayers=false, Worker *worker=nullptr)
Calculate the ORB descriptor for all given feature points.
Definition: ORBFeatureDescriptor.h:130
static OCEAN_FORCE_INLINE unsigned int calculateHammingDistance(const ORBDescriptor &referenceDescriptor, const ORBDescriptor &featureDescriptor)
Calculate the hamming distance between two feature descriptors (the number of different bits).
Definition: ORBFeatureDescriptor.h:189
static bool detectReferenceFeaturesAndDetermineDescriptors(const Frame &frame, ORBFeatures &featurePoints, const unsigned int pyramidLayers, const bool useHarrisFeatures, const unsigned int featureThreshold, Worker *worker)
Detect feature points of the reference frame and calculate the ORB descriptors for them.
Definition: ORBFeatureDescriptor.h:145
This class implements a ORB feature.
Definition: ORBFeature.h:40
static bool convert(const Frame &source, const FrameType::PixelFormat targetPixelFormat, const FrameType::PixelOrigin targetPixelOrigin, Frame &target, const bool forceCopy=true, Worker *worker=nullptr, const Options &options=Options())
Converts a frame with arbitrary dimension, pixel format and pixel origin into a frame with the same d...
@ CP_AVOID_COPY_IF_POSSIBLE
Tries to avoid copying the frame data whenever possible.
Definition: FrameConverter.h:96
This class implements a frame pyramid.
Definition: FramePyramid.h:37
static unsigned int idealLayers(const unsigned int width, const unsigned int height, const unsigned int invalidCoarsestWidthOrHeight, unsigned int *coarsestLayerWidth=nullptr, unsigned int *coarsestLayerHeight=nullptr)
Determines the number of layers until an invalid frame size would be reached in the next layer.
bool isValid() const
Returns whether this pyramid holds at least one frame layer.
Definition: FramePyramid.h:863
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
@ 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
unsigned int height() const
Returns the height of the frame in pixel.
Definition: Frame.h:3116
This class implements a recursive lock object.
Definition: Lock.h:31
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< IndexPair32 > IndexPairs32
Definition of a vector holding 32 bit index pairs.
Definition: Base.h:144
std::vector< ORBFeature > ORBFeatures
Definition of a vector holding ORB features.
Definition: ORBFeature.h:26
The namespace covering the entire Ocean framework.
Definition: Accessor.h:15