Ocean
VocabularyTree.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_TRACKING_VOCABULAR_TREE_H
9 #define META_OCEAN_TRACKING_VOCABULAR_TREE_H
10 
12 
13 #include "ocean/base/Memory.h"
15 #include "ocean/base/RandomI.h"
16 #include "ocean/base/Utilities.h"
17 #include "ocean/base/Worker.h"
18 
19 #include "ocean/math/Numeric.h"
20 
21 namespace Ocean
22 {
23 
24 namespace Tracking
25 {
26 
27 // Forward declaration.
28 class VocabularyStructure;
29 
30 /**
31  * Definition of a shared pointer holding a VocabularyStructure object.
32  * @see VocabularyStructure.
33  * @ingroup tracking
34  */
35 using SharedVocabularyStructure = std::shared_ptr<VocabularyStructure>;
36 
37 /**
38  * This class implements the base class for all Vocabulary objects.
39  * @ingroup tracking
40  */
42 {
43  public:
44 
45  /**
46  * Returns an invalid matching index.
47  * @return The index of an invalid match
48  */
49  static constexpr Index32 invalidMatchIndex();
50 
51  /**
52  * Definition of individual strategies to initialize the clustering of each tree node.
53  */
54  enum InitializationStrategy : uint32_t
55  {
56  /// An invalid strategy.
57  IS_INVALID = 0u,
58  /// All initial clusters are chosen randomly.
60  /// The initial first cluster is chosen randomly, the remaining clusters are chosen with largest distance to each other.
62  };
63 
64  /**
65  * Definition of individual matching modes for descriptors.
66  */
67  enum MatchingMode : uint32_t
68  {
69  /// An invalid matching mode.
70  MM_INVALID = 0u,
71  /// Only descriptor from the first best tree leaf are considered for matching (the second+ leaf with identical best distance is skipped).
73  /// All descriptors from all best tree leafs are considered for matching (all leafs with identical best distances are considered).
75  /// All descriptors from all tree leafs are considered for matching which are within a 1% distance to the best leaf.
77  /// All descriptors from all tree leafs are considered for matching which are within a 2% distance to the best leaf.
79  };
80 
81  /**
82  * This class implements a simple container holding the index pairs of matching descriptors and their distance.
83  * @tparam TDistance The data type of the distance measure between two descriptors, e.g., 'unsigned int', 'float'
84  */
85  template <typename TDistance>
86  class Match
87  {
88  public:
89 
90  /**
91  * Default constructor for an invalid match.
92  */
93  Match() = default;
94 
95  /**
96  * Creates a new match object.
97  * @param candidateDescriptorIndex The index of the candidate descriptor, with range [0, infinity)
98  * @param queryDescriptorIndex The index of the query descriptor, with range [0, infinity)
99  * @param distance The distance between both descriptors, with range [0, infinity]
100  */
101  inline Match(const Index32 candidateDescriptorIndex, const Index32 queryDescriptorIndex, const TDistance distance);
102 
103  /**
104  * Returns the index of the candidate descriptor.
105  * @return The candidate descriptor's index, with range [0, infinity)
106  */
107  inline Index32 candidateDescriptorIndex() const;
108 
109  /**
110  * Returns the index of the query descriptor.
111  * @return The query descriptor's index, with range [0, infinity)
112  */
113  inline Index32 queryDescriptorIndex() const;
114 
115  /**
116  * Returns the distance between both descriptors.
117  * @return The distance, with range [0, infinity]
118  */
119  inline TDistance distance() const;
120 
121  /**
122  * Returns whether this match is valid.
123  * @return True, if so
124  */
125  inline bool isValid() const;
126 
127  protected:
128 
129  /// The index of the candidate descriptor, with range [0, infinity).
131 
132  /// The index of the query descriptor, with range [0, infinity).
134 
135  /// The distance between both descriptors, with range [0, infinity].
137  };
138 
139  /**
140  * Definition of a vector holding matches.
141  * @ingroup TDistance The data type of the distance measure between two descriptors, e.g., 'unsigned int', 'float'
142  */
143  template <typename TDistance>
144  using Matches = std::vector<Match<TDistance>>;
145 
146  /**
147  * This class stores construction parameters for a VocabularyStructure.
148  */
150  {
151  public:
152 
153  /**
154  * Default constructor.
155  */
156  Parameters() = default;
157 
158  /**
159  * Creates a new parameters object.
160  * @param maximalNumberClustersPerLevel The maximal number of clusters each tree level can have with range [2, infinity)
161  * @param maximalDescriptorsPerLeaf The maximal number of descriptors each leaf can have, with range [1, infinity)
162  * @param maximalLevels The maximal number of tree levels, at tree will never have more level regardless what has been specified in 'maximalNumberClustersPerLevel' or 'maximalDescriptorsPerLeaf'
163  * @param initializationStrategy The initialization strategy for initial clusters
164  */
165  inline Parameters(const unsigned int maximalNumberClustersPerLevel, const unsigned int maximalDescriptorsPerLeaf, const unsigned int maximalLevels = (unsigned int)(-1), const InitializationStrategy initializationStrategy = IS_LARGEST_DISTANCE);
166 
167  /**
168  * Returns whether this object holds valid parameters.
169  * @return True, if so
170  */
171  inline bool isValid() const;
172 
173  public:
174 
175  /// The maximal number of clusters each tree level can have with range [2, infinity).
176  unsigned int maximalNumberClustersPerLevel_ = 10u;
177 
178  /// The maximal number of descriptors each leaf can have, with range [1, infinity).
179  unsigned int maximalDescriptorsPerLeaf_ = 40u;
180 
181  /// The maximal number of tree levels, at tree will never have more level regardless what has been specified in 'maximalNumberClustersPerLevel_' or 'maximalDescriptorsPerLeaf_'.
182  unsigned int maximalLevels_ = (unsigned int)(-1);
183 
184  /// The initialization strategy for initial clusters.
186  };
187 
188  public:
189 
190  /**
191  * Destructs this object.
192  */
193  virtual ~VocabularyStructure() = default;
194 
195  protected:
196 
197  /**
198  * Default constructor.
199  */
200  VocabularyStructure() = default;
201 
202  /**
203  * Returns the lookup table which separates the bits of a byte into 8 individual bytes.
204  * The lookup table can be used e.g., during the calculation of the mean descriptor of several descriptors.
205  * @return The lookup table with 256 * 8 entries
206  */
207  static inline std::vector<uint8_t> generateBitSeparationLookup8();
208 };
209 
210 /**
211  * This class implements a Vocabulary Tree for feature descriptors.
212  * Trees will not own the memory of the provided descriptors.<br>
213  * Tree descriptors have to be provided as one memory array and trees store indices to these descriptors only.<br>
214  * The tree descriptors need to exist as long as the corresponding tree exists.
215  * @tparam TDescriptor The data type of the descriptors for which the tree will be created
216  * @tparam TDistance The data type of the distance measure between two descriptors, e.g., 'unsigned int', 'float'
217  * @tparam tDistanceFunction The pointers to the function able to calculate the distance between two descriptors
218  * @see VocabularyForest
219  * @ingroup tracking
220  */
221 template <typename TDescriptor, typename TDistance, TDistance(*tDistanceFunction)(const TDescriptor&, const TDescriptor&)>
223 {
224  public:
225 
226  /**
227  * The descriptor type of this tree.
228  */
229  typedef TDescriptor Descriptor;
230 
231  /**
232  * The distance data type of this tree.
233  */
234  typedef TDistance Distance;
235 
236  /**
237  * The data type of the sum of distances, uint64_t for uint32_t, and float for float.
238  */
240 
241  /**
242  * The pointer to the function determining the distance between two descriptors of this tree.
243  */
244  static constexpr TDistance(*distanceFunction)(const TDescriptor&, const TDescriptor&) = tDistanceFunction;
245 
246  /**
247  * Definition of a vector holding descriptors.
248  */
249  typedef std::vector<TDescriptor> TDescriptors;
250 
251  /**
252  * Definition of a vector holding distances.
253  */
254  typedef std::vector<TDistance> TDistances;
255 
256  /**
257  * Definition of a tree node which is just an alias for the tree (the root node).
258  */
260 
261  /**
262  * Definition of a vector holding tree nodes.
263  */
264  typedef std::vector<Node*> Nodes;
265 
266  /**
267  * Definition of a vector holding constant tree nodes.
268  */
269  typedef std::vector<const Node*> ConstNodes;
270 
271  /**
272  * Definition of a Match object using the distance data type of this tree.
273  */
275 
276  /**
277  * Definition of a vector holding Match objects.
278  */
280 
281  /**
282  * Definition of a function pointer allowing to determine the mean descriptors for individual clusters.
283  * @see determineClustersMeanForBinaryDescriptor(), determineClustersMeanForFloatDescriptor().
284  */
285  using ClustersMeanFunction = TDescriptors(*)(const unsigned int numberClusters, const TDescriptor* treeDescriptors, const Index32* descriptorIndices, const Index32* clusterIndicesForDescriptors, const size_t numberDescriptorIndices, Worker* worker);
286 
287  /**
288  * Definition of a function pointer to a function allowing to return individual descriptors from a multi-descriptor.
289  * A feature point can be described with a multi-descriptor if the feature point has been seen from individual distances (to be scale invariant to some extent).
290  * First function parameter is the multi-descriptor, second parameter is the index of the actual descriptor to return, returns nullptr if the index is out of range
291  */
292  template <typename TMultiDescriptor>
293  using MultiDescriptorFunction = const TDescriptor*(*)(const TMultiDescriptor&, const size_t);
294 
295  /**
296  * Definition of a function pointer to a function allowing to return individual multi-descriptors from a group of multi-descriptors.
297  * A feature point can be described with a group of multi-descriptors if the feature point has been seen from individual locations or at individual moments in time (e.g., day vs. night).
298  * First function parameter is the multi-descriptor group, second parameter is the index of the actual multi-descriptor to return, returns nullptr if the index is out of range
299  */
300  template <typename TMultiDescriptorGroup, typename TMultiDescriptor>
301  using MultiDescriptorGroupFunction = const TMultiDescriptor*(*)(const TMultiDescriptorGroup&, const size_t);
302 
303  /**
304  * Definition of a class which holds reusable data for internal use.
305  * This object can avoid reallocating memory when calling a matching function several times in a row.<br>
306  * Simply define this object outside of the loop and provide the object as parameter, e.g.,
307  * @code
308  * ReusableData reusableData;
309  * for (const TDescriptor& queryDescriptor : queryDescriptors)
310  * {
311  * const Index32 index = vocabularyTree.matchDescriptor(candidateDescriptors, queryDescriptor, nullptr, reusableData);
312  * ...
313  * }
314  * @endcode
315  */
317  {
318  friend class VocabularyTree<TDescriptor, TDistance, tDistanceFunction>;
319 
320  public:
321 
322  /**
323  * Creates a new object.
324  */
325  ReusableData() = default;
326 
327  protected:
328 
329  /// The internal reusable data.
330  mutable std::vector<const Indices32*> internalData_;
331  };
332 
333  public:
334 
335  /**
336  * Creates an empty vocabulary tree.
337  */
338  VocabularyTree() = default;
339 
340  /**
341  * Move constructor.
342  * @param vocabularyTree The vocabulary tree to be moved
343  */
344  VocabularyTree(VocabularyTree&& vocabularyTree);
345 
346  /**
347  * Creates a new tree for a known descriptors.
348  * The given descriptors must not change afterwards, the descriptors must exist as long as the tree exists.
349  * @param treeDescriptors The descriptors for which the new tree will be created, must be valid
350  * @param numberTreeDescriptors The number of tree descriptors, with range [1, infinity)
351  * @param clustersMeanFunction The function allowing to determine the mean descriptors for individual clusters, must be valid
352  * @param parameters The parameters used to construct the tree, must be valid
353  * @param worker Optional worker object to distribute the computation
354  * @param randomGenerator Optional explicit random generator object
355  */
356  VocabularyTree(const TDescriptor* treeDescriptors, const size_t numberTreeDescriptors, const ClustersMeanFunction& clustersMeanFunction, const Parameters& parameters = Parameters(), Worker* worker = nullptr, RandomGenerator* randomGenerator = nullptr);
357 
358  /**
359  * Destructs the vocabulary tree.
360  */
361  ~VocabularyTree();
362 
363  /**
364  * Determines the leaf best matching with a given descriptor.
365  * Actually this function returns the tree's descriptors within the leaf.
366  * @param descriptor The descriptor for which the best leaf will be determined
367  * @return The indices of the descriptors within the leaf
368  */
369  const Indices32& determineBestLeaf(const TDescriptor& descriptor) const;
370 
371  /**
372  * Determines the leafs best matching with a given descriptor.
373  * Actually this function returns the tree's descriptors within the leafs.
374  * @param descriptor The descriptor for which the best leafs will be determined
375  * @param leafs The resulting groups of indices of the descriptors within the leafs, must be empty when calling
376  * @param distanceEpsilon The epsilon distance between the currently best node and node candidates
377  */
378  void determineBestLeafs(const TDescriptor& descriptor, std::vector<const Indices32*>& leafs, const TDistance distanceEpsilon = TDistance(0)) const;
379 
380  /**
381  * Matches a query descriptor with all candidate descriptors in this tree.
382  * @param candidateDescriptors The entire set of tree candidate descriptors which have been used to create the tree, from which the best matching descriptor will be determined, must be valid
383  * @param queryDescriptor The query descriptor for which the best matching tree candidate descriptor will be determined
384  * @param distance Optional resulting distance, nullptr if not of interest
385  * @param reusableData An reusable object to speedup the search, should be located outside of the function call if several function calls are done after each other
386  * @return The index of the matched tree candidate descriptor, with range [0, 'numberTreeDescriptors' - 1], invalidMatchIndex() if no match could be determined
387  * @tparam tMatchingMode The mode which is used for matching
388  */
389  template <MatchingMode tMatchingMode = MM_FIRST_BEST_LEAF>
390  Index32 matchDescriptor(const TDescriptor* candidateDescriptors, const TDescriptor& queryDescriptor, TDistance* distance = nullptr, const ReusableData& reusableData = ReusableData()) const;
391 
392  /**
393  * Matches a query multi-descriptor with all candidate descriptors in this tree.
394  * @param candidateDescriptors The entire set of tree candidate descriptors which have been used to create the tree, from which the best matching descriptor will be determined, must be valid
395  * @param queryMultiDescriptor The first single descriptor of the query multi-descriptor for which the best matching tree candidate descriptor will be determined
396  * @param numberQuerySingleDescriptors The number of single descriptors within the multi-descriptor, with range [1, infinity)
397  * @param distance Optional resulting distance, nullptr if not of interest
398  * @param reusableData An reusable object to speedup the search, should be located outside of the function call if several function calls are done after each other
399  * @return The index of the matched tree candidate descriptor, with range [0, 'numberTreeDescriptors' - 1], invalidMatchIndex() if no match could be determined
400  * @tparam tMatchingMode The mode which is used for matching
401  */
402  template <MatchingMode tMatchingMode = MM_FIRST_BEST_LEAF>
403  Index32 matchMultiDescriptor(const TDescriptor* candidateDescriptors, const TDescriptor* queryMultiDescriptor, const size_t numberQuerySingleDescriptors, TDistance* distance = nullptr, const ReusableData& reusableData = ReusableData()) const;
404 
405  /**
406  * Matches a query multi-descriptor with all candidate descriptors in this tree.
407  * A feature point can be described with a multi-descriptor if the feature point has been seen from individual distances (to be scale invariant to some extent).
408  * @param candidateDescriptors The entire set of tree candidate descriptors which have been used to create the tree, from which the best matching descriptor will be determined, must be valid
409  * @param queryMultiDescriptor The query multi-descriptor for which the best matching tree candidate descriptor will be determined
410  * @param distance Optional resulting distance, nullptr if not of interest
411  * @param reusableData An reusable object to speedup the search, should be located outside of the function call if several function calls are done after each other
412  * @return The index of the matched tree candidate descriptor, with range [0, 'numberTreeDescriptors' - 1], invalidMatchIndex() if no match could be determined
413  * @tparam TMultiDescriptor The data type of the multi-descriptor
414  * @tparam tMultiDescriptorFunction The function pointer to a static function allowing to access one single-descriptor of a multi-descriptor, must be valid
415  * @tparam tMatchingMode The mode which is used for matching
416  */
417  template <typename TMultiDescriptor, MultiDescriptorFunction<TMultiDescriptor> tMultiDescriptorFunction, MatchingMode tMatchingMode = MM_FIRST_BEST_LEAF>
418  Index32 matchMultiDescriptor(const TDescriptor* candidateDescriptors, const TMultiDescriptor& queryMultiDescriptor, TDistance* distance = nullptr, const ReusableData& reusableData = ReusableData()) const;
419 
420  /**
421  * Matches a query group of multi-descriptors with all candidate descriptors in this tree.
422  * A feature point can be described with a group of multi-descriptors if the feature point has been seen from individual locations or at individual moments in time (e.g., day vs. night).
423  * @param candidateDescriptors The entire set of tree candidate descriptors which have been used to create the tree, from which the best matching descriptor will be determined, must be valid
424  * @param queryMultiDescriptorGroup The query group of multi-descriptors (all representing one query feature) for which the best matching tree candidate descriptor will be determined
425  * @param distance Optional resulting distance, nullptr if not of interest
426  * @param reusableData An reusable object to speedup the search, should be located outside of the function call if several function calls are done after each other
427  * @return The index of the matched tree candidate descriptor, with range [0, 'numberTreeDescriptors' - 1], invalidMatchIndex() if no match could be determined
428  * @tparam TMultiDescriptorGroup The data type of the multi-descriptor group
429  * @tparam TMultiDescriptor The data type of the multi-descriptor
430  * @tparam tMultiDescriptorGroupFunction The function pointer to a static function allowing to access one multi-descriptor of a group of multi-descriptors, must be valid
431  * @tparam tMultiDescriptorFunction The function pointer to a static function allowing to access one single-descriptor of a multi-descriptor, must be valid
432  * @tparam tMatchingMode The mode which is used for matching
433  */
434  template <typename TMultiDescriptorGroup, typename TMultiDescriptor, MultiDescriptorGroupFunction<TMultiDescriptorGroup, TMultiDescriptor> tMultiDescriptorGroupFunction, MultiDescriptorFunction<TMultiDescriptor> tMultiDescriptorFunction, MatchingMode tMatchingMode = MM_FIRST_BEST_LEAF>
435  Index32 matchMultiDescriptorGroup(const TDescriptor* candidateDescriptors, const TMultiDescriptorGroup& queryMultiDescriptorGroup, TDistance* distance = nullptr, const ReusableData& reusableData = ReusableData()) const;
436 
437  /**
438  * Matches several query descriptors with all candidate descriptors in this tree.
439  * @param candidateDescriptors The entire set of tree candidate descriptors which have been used to create the tree, from which the best matching descriptor will be determined, must be valid
440  * @param queryDescriptors The query descriptors for which the best matching tree candidate descriptors will be determined, can be nullptr if 'numberQueryDescriptors == 0'
441  * @param numberQueryDescriptors The number of given query descriptors, with range [0, infinity)
442  * @param maximalDistance The maximal distance between two matching descriptors, with range [0, infinity)
443  * @param matches The resulting matches
444  * @param worker Optional worker object to distribute the computation
445  * @tparam tMatchingMode The mode which is used for matching
446  */
447  template <MatchingMode tMatchingMode = MM_FIRST_BEST_LEAF>
448  void matchDescriptors(const TDescriptor* candidateDescriptors, const TDescriptor* queryDescriptors, const size_t numberQueryDescriptors, const TDistance maximalDistance, Matches& matches, Worker* worker = nullptr) const;
449 
450  /**
451  * Matches several query multi-descriptors with all candidate descriptors in this tree.
452  * @param candidateDescriptors The entire set of tree candidate descriptors which have been used to create the tree, from which the best matching descriptor will be determined, must be valid
453  * @param queryMultiDescriptors The query multi-descriptors for which the best matching tree candidate descriptors will be determined, can be nullptr if 'numberQueryMultiDescriptors == 0'
454  * @param numberQueryMultiDescriptors The number of given query multi-descriptors, with range [0, infinity)
455  * @param maximalDistance The maximal distance between two matching descriptors, with range [0, infinity)
456  * @param matches The resulting matches
457  * @param worker Optional worker object to distribute the computation
458  * @tparam TMultiDescriptor The data type of a multi-descriptor
459  * @tparam tMultiDescriptorFunction The function pointer to a static function allowing to access one single-descriptor of a multi-descriptor, must be valid
460  * @tparam tMatchingMode The mode which is used for matching
461  */
462  template <typename TMultiDescriptor, MultiDescriptorFunction<TMultiDescriptor> tMultiDescriptorFunction, MatchingMode tMatchingMode = MM_FIRST_BEST_LEAF>
463  void matchMultiDescriptors(const TDescriptor* candidateDescriptors, const TMultiDescriptor* queryMultiDescriptors, const size_t numberQueryMultiDescriptors, const TDistance maximalDistance, Matches& matches, Worker* worker = nullptr) const;
464 
465  /**
466  * Matches several query groups of multi-descriptors with all candidate descriptors in this tree.
467  * @param candidateDescriptors The entire set of tree candidate descriptors which have been used to create the tree, from which the best matching descriptor will be determined, must be valid
468  * @param queryMultiDescriptorGroups The query groups of multi-descriptors for which the best matching tree candidate descriptors will be determined, can be nullptr if 'numberQueryMultiDescriptors == 0'
469  * @param numberQueryMultiDescriptorGroups The number of given query groups of multi-descriptors, with range [0, infinity)
470  * @param maximalDistance The maximal distance between two matching descriptors, with range [0, infinity)
471  * @param matches The resulting matches
472  * @param worker Optional worker object to distribute the computation
473  * @tparam TMultiDescriptorGroup The data type of the multi-descriptor group
474  * @tparam TMultiDescriptor The data type of the multi-descriptor
475  * @tparam tMultiDescriptorGroupFunction The function pointer to a static function allowing to access one multi-descriptor of a group of multi-descriptors, must be valid
476  * @tparam tMultiDescriptorFunction The function pointer to a static function allowing to access one single-descriptor of a multi-descriptor, must be valid
477  * @tparam tMatchingMode The mode which is used for matching
478  */
479  template <typename TMultiDescriptorGroup, typename TMultiDescriptor, MultiDescriptorGroupFunction<TMultiDescriptorGroup, TMultiDescriptor> tMultiDescriptorGroupFunction, MultiDescriptorFunction<TMultiDescriptor> tMultiDescriptorFunction, MatchingMode tMatchingMode = MM_FIRST_BEST_LEAF>
480  void matchMultiDescriptorGroups(const TDescriptor* candidateDescriptors, const TMultiDescriptorGroup* queryMultiDescriptorGroups, const size_t numberQueryMultiDescriptorGroups, const TDistance maximalDistance, Matches& matches, Worker* worker = nullptr) const;
481 
482  /**
483  * Returns the descriptor representing this tree/node.
484  * @return The node's descriptor
485  */
486  inline const TDescriptor& nodeDescriptor() const;
487 
488  /**
489  * Returns all indices of descriptors which belong to this tree/node.
490  * @return The node's descriptors, empty in non-leaf nodes
491  */
492  inline const Indices32& descriptorIndices() const;
493 
494  /**
495  * Returns all child nodes of this node/tree.
496  * @return The node's child nodes, empty for leaf nodes
497  */
498  inline const Nodes& childNodes() const;
499 
500  /**
501  * Move operator.
502  * @param vocabularyTree The vocabulary tree to be moved
503  * @return Reference to this object
504  */
505  VocabularyTree& operator=(VocabularyTree&& vocabularyTree);
506 
507  /**
508  * Disabled assign operator.
509  * @param vocabularyTree The vocabulary tree to be copied
510  * @return Reference to this object
511  */
512  VocabularyTree& operator=(const VocabularyTree& vocabularyTree) = delete;
513 
514  /**
515  * Determines a binary mean descriptor for each cluster.
516  * @param numberClusters The number of clusters, with range [1, infinity)
517  * @param treeDescriptors The descriptors of the entire tree from which some will be part of the clusters, must be valid
518  * @param descriptorIndices The indices of the individual descriptors wrt. the given descriptors, must be valid
519  * @param clusterIndicesForDescriptors The indices of the clusters to which each individual descriptor belongs (a lookup table with cluster indices), one for each descriptor
520  * @param numberDescriptorIndices The number of provided descriptor indices (the number of descriptors which are part of all clusters), must be valid
521  * @param worker Optional worker to distribute the computation
522  * @return The resulting mean descriptors, one for each cluster
523  * @tparam tSize The number of bits per binary descriptor
524  */
525  template <unsigned int tSize>
526  static TDescriptors determineClustersMeanForBinaryDescriptor(const unsigned int numberClusters, const TDescriptor* treeDescriptors, const Index32* descriptorIndices, const Index32* clusterIndicesForDescriptors, const size_t numberDescriptorIndices, Worker* worker);
527 
528  /**
529  * Determines a float mean descriptor for each cluster.
530  * @param numberClusters The number of clusters, with range [1, infinity)
531  * @param treeDescriptors The descriptors of the entire tree from which some will be part of the clusters, must be valid
532  * @param descriptorIndices The indices of the individual descriptors wrt. the given descriptors, must be valid
533  * @param clusterIndicesForDescriptors The indices of the clusters to which each individual descriptor belongs (a lookup table with cluster indices), one for each descriptor
534  * @param numberDescriptorIndices The number of provided descriptor indices (the number of descriptors which are part of all clusters), must be valid
535  * @param worker Optional worker to distribute the computation
536  * @return The resulting mean descriptors, one for each cluster
537  * @tparam tSize The number of elements per float descriptor
538  */
539  template <unsigned int tSize>
540  static TDescriptors determineClustersMeanForFloatDescriptor(const unsigned int numberClusters, const TDescriptor* treeDescriptors, const Index32* descriptorIndices, const Index32* clusterIndicesForDescriptors, const size_t numberDescriptorIndices, Worker* worker);
541 
542  protected:
543 
544  /**
545  * Disabled copy constructor.
546  * @param vocabularyTree The vocabulary tree to be copied
547  */
548  VocabularyTree(const VocabularyTree& vocabularyTree) = delete;
549 
550  /**
551  * Creates a new intermediate tree node.
552  * @param level The current node level, with range [0, infinity)
553  * @param nodeDescriptor The descriptor of the new node
554  * @param parameters The parameters used to construct the tree node, must be valid
555  * @param treeDescriptors The descriptors of the entire tree from which some will be part of this new tree node, must be valid
556  * @param reusableDescriptorIndicesInput The indices of the descriptors for which the new node will be created, must be valid
557  * @param reusableDescriptorIndicesOutput Memory block of indices with same size as 'reusableDescriptorIndicesInput' which can be re-used internally, must be valid
558  * @param numberDescriptorsIndices The number of given indices in 'reusableDescriptorIndicesInput', with range [1, infinity)
559  * @param randomGenerator The random generator to be used
560  * @param reusableClusterIndicesForDescriptors Memory block of indices with same size as 'reusableDescriptorIndicesInput' which can be reused internally, must be valid
561  * @param clustersMeanFunction The function allowing to determine the mean descriptors for individual clusters, must be valid
562  * @param worker Optional worker object to distribute the computation
563  */
564  VocabularyTree(const unsigned int level, const TDescriptor& nodeDescriptor, const Parameters& parameters, const TDescriptor* treeDescriptors, Index32* reusableDescriptorIndicesInput, Index32* reusableDescriptorIndicesOutput, const size_t numberDescriptorsIndices, RandomGenerator& randomGenerator, Index32* reusableClusterIndicesForDescriptors, const ClustersMeanFunction& clustersMeanFunction, Worker* worker);
565 
566  /**
567  * Creates a new leaf node.
568  * @param level The level of the leaf node, with range [0, infinity)
569  * @param nodeDescriptor The descriptor of the leaf node
570  * @param descriptorIndices The indices of the descriptors which represent the leaf node, must be valid
571  * @param numberDescriptorsIndices The number of given descriptor indices, with range [1, infinity)
572  */
573  VocabularyTree(const unsigned int level, const TDescriptor& nodeDescriptor, Index32* descriptorIndices, size_t numberDescriptorsIndices);
574 
575  /**
576  * Creates the new child nodes.
577  * @param childNodeLevel The level of the child nodes, with range [1, infinity)
578  * @param parameters The parameters used to construct the tree node, must be valid
579  * @param treeDescriptors The descriptors of the entire tree from which some will be part of this new tree node, must be valid
580  * @param clusterCenters The descriptors of the individual child nodes (the centers of the clusters, one for each child node, must be valid
581  * @param clusterSizes The sizes of the individual clusters, one for each cluster, must be valid
582  * @param numberClusters The number of clusters and thus the number of child nodes, with range [1, infinity)
583  * @param reusableDescriptorIndicesInput The indices of the descriptors for which the new node will be created, must be valid
584  * @param reusableDescriptorIndicesOutput Memory block of indices with same size as 'reusableDescriptorIndicesInput' which can be re-used internally, must be valid
585  * @param numberDescriptorsIndices The number of given indices in 'reusableDescriptorIndicesInput', with range [1, infinity)
586  * @param randomGenerator The random generator to be used
587  * @param reusableClusterIndicesForDescriptors Memory block of indices with same size as 'reusableDescriptorIndicesInput' which can be reused internally, must be valid
588  * @param clustersMeanFunction The function allowing to determine the mean descriptors for individual clusters, must be valid
589  * @param worker Optional worker object to distribute the computation
590  */
591  void createChildNodes(const unsigned int childNodeLevel, const Parameters& parameters, const TDescriptor* treeDescriptors, const TDescriptor* clusterCenters, const unsigned int* clusterSizes, const size_t numberClusters, Index32* reusableDescriptorIndicesInput, Index32* reusableDescriptorIndicesOutput, const size_t numberDescriptorsIndices, RandomGenerator& randomGenerator, Index32* reusableClusterIndicesForDescriptors, const ClustersMeanFunction& clustersMeanFunction, Worker* worker);
592 
593  /**
594  * Distributes several descriptors into individual clusters.
595  * @param parameters The parameters used to construct the tree, must be valid
596  * @param treeDescriptors The descriptors of the entire tree from which some will be part of the clusters, must be valid
597  * @param reusableDescriptorIndicesInput The indices of the descriptors for which the new clusters will be created, must be valid
598  * @param reusableDescriptorIndicesOutput Memory block of indices with same size as 'reusableDescriptorIndicesInput' which can be re-used internally, must be valid
599  * @param numberDescriptorsIndices The number of provided indices of the tree descriptors, with range [1, infinity)
600  * @param randomGenerator The random generator to be used
601  * @param clusterIndicesForDescriptors The resulting cluster indices to which the descriptors have been assigned, must be valid
602  * @param clustersMeanFunction The function allowing to determine the mean descriptors for individual clusters, must be valid
603  * @param clusterSizes Optional resulting sizes of the individual resulting clusters
604  * @param worker Optional worker object to distribute the computation
605  * @return The descriptors of the centers of the resulting clusters
606  */
607  TDescriptors clusterDescriptors(const Parameters& parameters, const TDescriptor* treeDescriptors, Index32* reusableDescriptorIndicesInput, Index32* reusableDescriptorIndicesOutput, size_t numberDescriptorsIndices, RandomGenerator& randomGenerator, Index32* clusterIndicesForDescriptors, const ClustersMeanFunction& clustersMeanFunction, Indices32* clusterSizes = nullptr, Worker* worker = nullptr);
608 
609  /**
610  * Determines the initial clusters based on specified initialization strategy.
611  * @param parameters The parameters used to construct the tree, must be valid
612  * @param treeDescriptors The descriptors of the entire tree from which some will be part of the clusters, must be valid
613  * @param reusableDescriptorIndicesInput The indices of the descriptors for which the new clusters will be created, must be valid
614  * @param reusableDescriptorIndicesOutput Memory block of indices with same size as 'reusableDescriptorIndicesInput' which can be re-used internally, must be valid
615  * @param numberDescriptorsIndices The number of provided indices of the tree descriptors, with range [1, infinity)
616  * @param randomGenerator The random generator to be used
617  * @return The descriptors of the centers of the initial clusters
618  */
619  TDescriptors initialClusters(const Parameters& parameters, const TDescriptor* treeDescriptors, Index32* reusableDescriptorIndicesInput, Index32* reusableDescriptorIndicesOutput, size_t numberDescriptorsIndices, RandomGenerator& randomGenerator);
620 
621  /**
622  * Determines the initial clusters based on the largest distance between each other.
623  * The first cluster is selected randomly, the following clusters are selected so that they have the largest distance to the existing clusters.
624  * @param parameters The parameters used to construct the tree, must be valid
625  * @param treeDescriptors The descriptors of the entire tree from which some will be part of the clusters, must be valid
626  * @param descriptorIndices The indices of the tree descriptors for which the new clusters will be determined, must be valid
627  * @param reusableIndices Memory block of indices with same size as 'descsriptorIndices' which can be re-used internally, must be valid
628  * @param numberDescriptorsIndices The number of provided indices of the tree descriptors, with range [1, infinity)
629  * @param randomGenerator The random generator to be used
630  * @return The descriptors of the centers of the initial clusters
631  */
632  TDescriptors initialClustersLargestDistance(const Parameters& parameters, const TDescriptor* treeDescriptors, Index32* descriptorIndices, Index32* reusableIndices, const size_t numberDescriptorsIndices, RandomGenerator& randomGenerator) const;
633 
634  /**
635  * Determines the initial cluster based on a pure random choice.
636  * @param parameters The parameters used to construct the tree, must be valid
637  * @param treeDescriptors The descriptors of the entire tree from which some will be part of the clusters, must be valid
638  * @param descriptorIndices The indices of the tree descriptors for which the new clusters will be determined, must be valid
639  * @param numberDescriptorsIndices The number of provided indices of the tree descriptors, with range [1, infinity)
640  * @param randomGenerator The random generator to be used
641  * @return The descriptors of the centers of the initial clusters
642  */
643  TDescriptors initialClustersPureRandom(const Parameters& parameters, const TDescriptor* treeDescriptors, Index32* descriptorIndices, const size_t numberDescriptorsIndices, RandomGenerator& randomGenerator) const;
644 
645  /**
646  * Assigns descriptors to clusters.
647  * @param clusterCenters The centers of the clusters to which the descriptors will be assigned, must be valid
648  * @param numberClusters The number of clusters, with range [1, infinity)
649  * @param treeDescriptors The descriptors of the entire tree from which some will belong to the new clusters, must be valid
650  * @param descriptorIndices The indices of the descriptors which need to be assigned, must be valid
651  * @param clusterIndicesForDescriptors The resulting cluster indices to which the descriptors have been assigned, must be valid
652  * @param numberDescriptorIndices The number of given indices of descriptors which will be assigned to the clusters, with range [1, infinity)
653  * @param sumDistances Optional resulting sum of distances between all assigned descriptors and their corresponding cluster centers, nullptr if not of interest
654  * @param worker Optional worker to distribute the computation
655  */
656  static Indices32 assignDescriptorsToClusters(const TDescriptor* clusterCenters, const unsigned int numberClusters, const TDescriptor* treeDescriptors, const Index32* descriptorIndices, Index32* clusterIndicesForDescriptors, const size_t numberDescriptorIndices, TSumDistances* sumDistances = nullptr, Worker* worker = nullptr);
657 
658  /**
659  * Creates a subset of the new child nodes.
660  * @param childNodeLevel The level of the child nodes, with range [1, infinity)
661  * @param parameters The parameters used to construct the tree node, must be valid
662  * @param treeDescriptors The descriptors of the entire tree from which some will be part of this new tree node, must be valid
663  * @param clusterCenters The descriptors of the individual child nodes (the centers of the clusters, one for each child node, must be valid
664  * @param clusterSizes The sizes of the individual clusters, one for each cluster, must be valid
665  * @param numberClusters The number of clusters and thus the number of child nodes, with range [1, infinity)
666  * @param reusableDescriptorIndicesInput The indices of the descriptors for which the new node will be created, must be valid
667  * @param reusableDescriptorIndicesOutput Memory block of indices with same size as 'reusableDescriptorIndicesInput' which can be re-used internally, must be valid
668  * @param numberDescriptorsIndices The number of given indices in 'reusableDescriptorIndicesInput', with range [1, infinity)
669  * @param randomGenerator The random generator to be used
670  * @param reusableClusterIndicesForDescriptors Memory block of indices with same size as 'reusableDescriptorIndicesInput' which can be reused internally, must be valid
671  * @param clustersMeanFunction The function allowing to determine the mean descriptors for individual clusters, must be valid
672  * @param subsetFirstCluster The index of the first cluster (the first child node) to be handled, with range [0, numberClusters - 1]
673  * @param subsetNumberClusters The number of clusters (child nodes) to be handled, with range [1, numberClusters - subsetFirstCluster]
674  */
675  void createChildNodesSubset(const unsigned int childNodeLevel, const Parameters* parameters, const TDescriptor* treeDescriptors, const TDescriptor* clusterCenters, const unsigned int* clusterSizes, const size_t numberClusters, Index32* reusableDescriptorIndicesInput, Index32* reusableDescriptorIndicesOutput, const size_t numberDescriptorsIndices, RandomGenerator* randomGenerator, Index32* reusableClusterIndicesForDescriptors, const ClustersMeanFunction* clustersMeanFunction, const unsigned int subsetFirstCluster, const unsigned int subsetNumberClusters);
676 
677  /**
678  * Assigns a subset of descriptors to clusters.
679  * @param clusterCenters The centers of the clusters to which the descriptors will be assigned, must be valid
680  * @param numberClusters The number of clusters, with range [1, infinity)
681  * @param treeDescriptors The descriptors of the entire tree from which some will belong to the new clusters, must be valid
682  * @param descriptorIndices The indices of the descriptors which need to be assigned, must be valid
683  * @param clusterIndicesForDescriptors The resulting cluster indices to which the descriptors have been assigned, must be valid
684  * @param clusterSizes The sizes of the individual clusters, one for each cluster, must be valid
685  * @param sumDistances Optional resulting sum of distances between all assigned descriptors and their corresponding cluster centers, nullptr if not of interest
686  * @param lock Optional lock when executed in multiple threads in parallel, nullptr otherwise
687  * @param firstDescriptorIndex The first descriptor index to be handled, with range [0, infinity)
688  * @param numberDescriptorIndices The number of descriptor indices to be handled, with range [1, infinity)
689  */
690  static void assignDescriptorsToClustersSubset(const TDescriptor* clusterCenters, const unsigned int numberClusters, const TDescriptor* treeDescriptors, const Index32* descriptorIndices, Index32* clusterIndicesForDescriptors, Index32* clusterSizes, TSumDistances* sumDistances, Lock* lock, const unsigned int firstDescriptorIndex, const unsigned int numberDescriptorIndices);
691 
692  /**
693  * Matches a subset of several query descriptors with all tree candidate descriptors.
694  * @param candidateDescriptors The entire set of tree candidate descriptors which have been used to create the tree, from which the best matching descriptor will be determined, must be valid
695  * @param queryDescriptors The query descriptors for which the best matching tree candidate descriptors will be determined, must be valid
696  * @param maximalDistance The maximal distance between two matching descriptors, with range [0, infinity)
697  * @param matches The resulting matches
698  * @param lock Optional lock when executed in multiple threads in parallel, nullptr otherwise
699  * @param firstQueryDescriptor The index of the first query descriptor to be handled, with range [0, infinity)
700  * @param numberQueryDescriptors The number of query descriptors to be handled, with range [1, infinity)
701  * @tparam tMatchingMode The mode which is used for matching
702  */
703  template <MatchingMode tMatchingMode>
704  void matchDescriptorsSubset(const TDescriptor* candidateDescriptors, const TDescriptor* queryDescriptors, const TDistance maximalDistance, Matches* matches, Lock* lock, const unsigned int firstQueryDescriptor, const unsigned int numberQueryDescriptors) const;
705 
706  /**
707  * Matches a subset of several query multi-descriptors with all tree candidate descriptors.
708  * @param candidateDescriptors The entire set of tree candidate descriptors which have been used to create the tree, from which the best matching descriptor will be determined, must be valid
709  * @param queryMultiDescriptors The query multi-descriptors for which the best matching tree candidate descriptors will be determined, must be valid
710  * @param maximalDistance The maximal distance between two matching descriptors, with range [0, infinity)
711  * @param matches The resulting matches
712  * @param lock Optional lock when executed in multiple threads in parallel, nullptr otherwise
713  * @param firstQueryMultiDescriptor The index of the first query multi-descriptor to be handled, with range [0, infinity)
714  * @param numberQueryMultiDescriptors The number of query multi-descriptors to be handled, with range [1, infinity)
715  * @tparam TMultiDescriptor The data type of a multi-descriptor
716  * @tparam tMultiDescriptorFunction The function pointer to a static function allowing to access one single-descriptor of a multi-descriptor, must be valid
717  * @tparam tMatchingMode The mode which is used for matching
718  */
719  template <typename TMultiDescriptor, MultiDescriptorFunction<TMultiDescriptor> tMultiDescriptorFunction, MatchingMode tMatchingMode>
720  void matchMultiDescriptorsSubset(const TDescriptor* candidateDescriptors, const TMultiDescriptor* queryMultiDescriptors, const TDistance maximalDistance, Matches* matches, Lock* lock, const unsigned int firstQueryMultiDescriptor, const unsigned int numberQueryMultiDescriptors) const;
721 
722  /**
723  * Matches a subset of several query groups of multi-descriptors with all candidate descriptors in this tree.
724  * @param candidateDescriptors The entire set of tree candidate descriptors which have been used to create the tree, from which the best matching descriptor will be determined, must be valid
725  * @param queryMultiDescriptorGroups The query groups of multi-descriptors for which the best matching tree candidate descriptors will be determined, can be nullptr if 'numberQueryMultiDescriptors == 0'
726  * @param maximalDistance The maximal distance between two matching descriptors, with range [0, infinity)
727  * @param matches The resulting matches
728  * @param lock Optional lock when executed in multiple threads in parallel, nullptr otherwise
729  * @param firstQueryMultiDescriptorGroup The index of the first query group of multi-descriptors to be handled, with range [0, infinity)
730  * @param numberQueryMultiDescriptorGroups The number of query groups of multi-descriptors to be handled, with range [1, infinity)
731  * @tparam TMultiDescriptorGroup The data type of the multi-descriptor group
732  * @tparam TMultiDescriptor The data type of the multi-descriptor
733  * @tparam tMultiDescriptorGroupFunction The function pointer to a static function allowing to access one multi-descriptor of a group of multi-descriptors, must be valid
734  * @tparam tMultiDescriptorFunction The function pointer to a static function allowing to access one single-descriptor of a multi-descriptor, must be valid
735  * @tparam tMatchingMode The mode which is used for matching
736  */
737  template <typename TMultiDescriptorGroup, typename TMultiDescriptor, MultiDescriptorGroupFunction<TMultiDescriptorGroup, TMultiDescriptor> tMultiDescriptorGroupFunction, MultiDescriptorFunction<TMultiDescriptor> tMultiDescriptorFunction, MatchingMode tMatchingMode>
738  void matchMultiDescriptorGroupsSubset(const TDescriptor* candidateDescriptors, const TMultiDescriptorGroup* queryMultiDescriptorGroups, const TDistance maximalDistance, Matches* matches, Lock* lock, const unsigned int firstQueryMultiDescriptorGroup, const unsigned int numberQueryMultiDescriptorGroups) const;
739 
740  protected:
741 
742  /// The node's level.
743  unsigned int level_ = 0u;
744 
745  /// The node's descriptor.
746  TDescriptor nodeDescriptor_;
747 
748  /// The indices of the descriptors which are part of this node.
750 
751  /// The child-nodes of this node.
753 };
754 
755 /**
756  * This class implements a Vocabulary Forest holding several Vocabulary Trees.
757  * Using several trees with individual clustering can increase the probability to determine the correct descriptor.
758  * @tparam TDescriptor The data type of the descriptors for which the tree will be created
759  * @tparam TDistance The data type of the distance measure between two descriptors, e.g., 'unsigned int', 'float'
760  * @tparam tDistanceFunction The pointers to the function able to calculate the distance between two descriptors
761  * @see VocabularyTree
762  * @ingroup tracking
763  */
764 template <typename TDescriptor, typename TDistance, TDistance(*tDistanceFunction)(const TDescriptor&, const TDescriptor&)>
766 {
767  public:
768 
769  /**
770  * The descriptor type of this forest.
771  */
772  typedef TDescriptor Descriptor;
773 
774  /**
775  * The distance data type of this forest.
776  */
777  typedef TDistance Distance;
778 
779  /**
780  * The pointer to the function determining the distance between two descriptors of this forest.
781  */
782  static constexpr TDistance(*distanceFunction)(const TDescriptor&, const TDescriptor&) = tDistanceFunction;
783 
784  /**
785  * Definition of a vector holding descriptors.
786  */
787  typedef std::vector<TDescriptor> TDescriptors;
788 
789  /**
790  * Definition of a vector holding distances.
791  */
792  typedef std::vector<TDistance> TDistances;
793 
794  /**
795  * Definition of the Vocabulary Tree object.
796  */
798 
799  /**
800  * Definition of a Match object using the distance data type of this tree.
801  */
803 
804  /**
805  * Definition of a vector holding Match objects.
806  */
808 
809  /**
810  * Definition of a function pointer allowing to determine the mean descriptors for individual clusters.
811  * @see determineClustersMeanForBinaryDescriptor().
812  */
813  using ClustersMeanFunction = TDescriptors(*)(const unsigned int numberClusters, const TDescriptor* treeDescriptors, const Index32* descriptorIndices, const Index32* clusterIndicesForDescriptors, const size_t numberDescriptorIndices, Worker* worker);
814 
815  /**
816  * Definition of a function pointer to a function allowing to return individual descriptors from a multi-descriptor.
817  * A feature point can be described with a multi-descriptor if the feature point has been seen from individual distances (to be scale invariant to some extent).
818  * First function parameter is the multi-descriptor, second parameter is the index of the actual descriptor to return, returns nullptr if the index is out of range
819  */
820  template <typename TMultiDescriptor>
821  using MultiDescriptorFunction = const TDescriptor*(*)(const TMultiDescriptor&, const size_t);
822 
823  /**
824  * Definition of a function pointer to a function allowing to return individual multi-descriptors from a group of multi-descriptors.
825  * A feature point can be described with a group of multi-descriptors if the feature point has been seen from individual locations or at individual moments in time (e.g., day vs. night).
826  * First function parameter is the multi-descriptor group, second parameter is the index of the actual multi-descriptor to return, returns nullptr if the index is out of range
827  */
828  template <typename TMultiDescriptorGroup, typename TMultiDescriptor>
829  using MultiDescriptorGroupFunction = const TMultiDescriptor*(*)(const TMultiDescriptorGroup&, const size_t);
830 
831  /**
832  * Re-definition of the ReusableData object.
833  */
835 
836  protected:
837 
838  /**
839  * Definition of a vector holding VocabularyTree objects.
840  */
841  typedef std::vector<TVocabularyTree> TVocabularyTrees;
842 
843  public:
844 
845  /**
846  * Creates a new empty forest without trees.
847  */
848  VocabularyForest() = default;
849 
850  /**
851  * Creates a new forest with several trees for given descriptors.
852  * The given descriptors must not change afterwards, the descriptors must exist as long as the forest exists.
853  * @param numberTrees The number of trees to be created within the forest, with range [1, infinity)
854  * @param treeDescriptors The descriptors for which the new tree will be created, must be valid
855  * @param numberTreeDescriptors The number of tree descriptors, with range [1, infinity)
856  * @param clustersMeanFunction The function allowing to determine the mean descriptors for individual clusters, must be valid
857  * @param parameters The parameters used to construct the forest, must be valid
858  * @param worker Optional worker object to distribute the computation
859  * @param randomGenerator Optional explicit random generator object
860  */
861  VocabularyForest(const size_t numberTrees, const TDescriptor* treeDescriptors, const size_t numberTreeDescriptors, const ClustersMeanFunction& clustersMeanFunction, const Parameters& parameters = Parameters(), Worker* worker = nullptr, RandomGenerator* randomGenerator = nullptr);
862 
863  /**
864  * Matches a query descriptor with all candidate descriptors in this forest.
865  * @param candidateDescriptors The entire set of tree candidate descriptors which have been used to create the tree, from which the best matching descriptor will be determined, must be valid
866  * @param queryDescriptor The query descriptor for which the best matching tree candidate descriptor will be determined
867  * @param distance Optional resulting distance, nullptr if not of interest
868  * @param reusableData An reusable object to speedup the search, should be located outside of the function call if several function calls are done after each other
869  * @return The index of the matched tree candidate descriptor, with range [0, 'numberTreeDescriptors' - 1], invalidMatchIndex() if no match could be determined
870  * @tparam tMatchingMode The mode which is used for matching
871  * @see VocabularyTree::matchDescriptor().
872  */
873  template <MatchingMode tMatchingMode = MM_FIRST_BEST_LEAF>
874  Index32 matchDescriptor(const TDescriptor* candidateDescriptors, const TDescriptor& queryDescriptor, TDistance* distance = nullptr, const ReusableData& reusableData = ReusableData()) const;
875 
876  /**
877  * Matches a query multi-descriptor with all candidate descriptors in this forest.
878  * @param candidateDescriptors The entire set of tree candidate descriptors which have been used to create the tree, from which the best matching descriptor will be determined, must be valid
879  * @param queryMultiDescriptor The first single descriptor of the query multi-descriptor for which the best matching tree candidate descriptor will be determined
880  * @param numberQuerySingleDescriptors The number of single descriptors within the multi-descriptor, with range [1, infinity)
881  * @param distance Optional resulting distance, nullptr if not of interest
882  * @param reusableData An reusable object to speedup the search, should be located outside of the function call if several function calls are done after each other
883  * @return The index of the matched tree candidate descriptor, with range [0, 'numberTreeDescriptors' - 1], invalidMatchIndex() if no match could be determined
884  * @tparam tMatchingMode The mode which is used for matching
885  * @see VocabularyTree::matchMultiDescriptor().
886  */
887  template <MatchingMode tMatchingMode = MM_FIRST_BEST_LEAF>
888  Index32 matchMultiDescriptor(const TDescriptor* candidateDescriptors, const TDescriptor* queryMultiDescriptor, const size_t numberQuerySingleDescriptors, TDistance* distance = nullptr, const ReusableData& reusableData = ReusableData()) const;
889 
890  /**
891  * Matches a query multi-descriptor with all candidate descriptors in this forest.
892  * @param candidateDescriptors The entire set of tree candidate descriptors which have been used to create the tree, from which the best matching descriptor will be determined, must be valid
893  * @param queryMultiDescriptor The query multi-descriptor for which the best matching tree candidate descriptor will be determined
894  * @param distance Optional resulting distance, nullptr if not of interest
895  * @param reusableData An reusable object to speedup the search, should be located outside of the function call if several function calls are done after each other
896  * @return The index of the matched tree candidate descriptor, with range [0, 'numberTreeDescriptors' - 1], invalidMatchIndex() if no match could be determined
897  * @tparam TMultiDescriptor The data type of the multi-descriptor
898  * @tparam tMultiDescriptorFunction The function pointer to a static function allowing to access one single-descriptor of a multi-descriptor, must be valid
899  * @tparam tMatchingMode The mode which is used for matching
900  * @see VocabularyTree::matchMultiDescriptor().
901  */
902  template <typename TMultiDescriptor, MultiDescriptorFunction<TMultiDescriptor> tMultiDescriptorFunction, MatchingMode tMatchingMode = MM_FIRST_BEST_LEAF>
903  Index32 matchMultiDescriptor(const TDescriptor* candidateDescriptors, const TMultiDescriptor& queryMultiDescriptor, TDistance* distance = nullptr, const ReusableData& reusableData = ReusableData()) const;
904 
905  /**
906  * Matches a query group of multi-descriptors with all candidate descriptors in this forest.
907  * A feature point can be described with a group of multi-descriptors if the feature point has been seen from individual locations or at individual moments in time (e.g., day vs. night).
908  * @param candidateDescriptors The entire set of tree candidate descriptors which have been used to create the tree, from which the best matching descriptor will be determined, must be valid
909  * @param queryMultiDescriptorGroup The query group of multi-descriptors (all representing one query feature) for which the best matching tree candidate descriptor will be determined
910  * @param distance Optional resulting distance, nullptr if not of interest
911  * @param reusableData An reusable object to speedup the search, should be located outside of the function call if several function calls are done after each other
912  * @return The index of the matched tree candidate descriptor, with range [0, 'numberTreeDescriptors' - 1], invalidMatchIndex() if no match could be determined
913  * @tparam TMultiDescriptorGroup The data type of the multi-descriptor group
914  * @tparam TMultiDescriptor The data type of the multi-descriptor
915  * @tparam tMultiDescriptorGroupFunction The function pointer to a static function allowing to access one multi-descriptor of a group of multi-descriptors, must be valid
916  * @tparam tMultiDescriptorFunction The function pointer to a static function allowing to access one single-descriptor of a multi-descriptor, must be valid
917  * @tparam tMatchingMode The mode which is used for matching
918  */
919  template <typename TMultiDescriptorGroup, typename TMultiDescriptor, MultiDescriptorGroupFunction<TMultiDescriptorGroup, TMultiDescriptor> tMultiDescriptorGroupFunction, MultiDescriptorFunction<TMultiDescriptor> tMultiDescriptorFunction, MatchingMode tMatchingMode = MM_FIRST_BEST_LEAF>
920  Index32 matchMultiDescriptorGroup(const TDescriptor* candidateDescriptors, const TMultiDescriptorGroup& queryMultiDescriptorGroup, TDistance* distance = nullptr, const ReusableData& reusableData = ReusableData()) const;
921 
922  /**
923  * Matches several query descriptors with all candidate descriptors in this forest.
924  * @param candidateDescriptors The entire set of tree candidate descriptors which have been used to create the tree, from which the best matching descriptor will be determined, must be valid
925  * @param queryDescriptors The query descriptors for which the best matching tree candidate descriptors will be determined, can be nullptr if 'numberQueryDescriptors == 0'
926  * @param numberQueryDescriptors The number of given query descriptors, with range [0, infinity)
927  * @param maximalDistance The maximal distance between two matching descriptors, with range [0, infinity)
928  * @param matches The resulting matches
929  * @param worker Optional worker object to distribute the computation
930  * @tparam tMatchingMode The mode which is used for matching
931  * @see VocabularyTree::matchDescriptors().
932  */
933  template <MatchingMode tMatchingMode = MM_FIRST_BEST_LEAF>
934  void matchDescriptors(const TDescriptor* candidateDescriptors, const TDescriptor* queryDescriptors, const size_t numberQueryDescriptors, const TDistance maximalDistance, Matches& matches, Worker* worker = nullptr) const;
935 
936  /**
937  * Matches several query multi-descriptors with all candidate descriptors in this forest.
938  * @param candidateDescriptors The entire set of tree candidate descriptors which have been used to create the tree, from which the best matching descriptor will be determined, must be valid
939  * @param queryMultiDescriptors The query multi-descriptors for which the best matching tree candidate descriptors will be determined, can be nullptr if 'numberQueryMultiDescriptors == 0'
940  * @param numberQueryMultiDescriptors The number of given query multi-descriptors, with range [0, infinity)
941  * @param maximalDistance The maximal distance between two matching descriptors, with range [0, infinity)
942  * @param matches The resulting matches
943  * @param worker Optional worker object to distribute the computation
944  * @tparam TMultiDescriptor The data type of a multi-descriptor
945  * @tparam tMultiDescriptorFunction The function pointer to a static function allowing to access one single-descriptor of a multi-descriptor, must be valid
946  * @tparam tMatchingMode The mode which is used for matching
947  * @see VocabularyTree::matchMultiDescriptors().
948  */
949  template <typename TMultiDescriptor, MultiDescriptorFunction<TMultiDescriptor> tMultiDescriptorFunction, MatchingMode tMatchingMode = MM_FIRST_BEST_LEAF>
950  void matchMultiDescriptors(const TDescriptor* candidateDescriptors, const TMultiDescriptor* queryMultiDescriptors, const size_t numberQueryMultiDescriptors, const TDistance maximalDistance, Matches& matches, Worker* worker = nullptr) const;
951 
952  /**
953  * Matches several query groups of multi-descriptors with all candidate descriptors in this forest.
954  * @param candidateDescriptors The entire set of tree candidate descriptors which have been used to create the tree, from which the best matching descriptor will be determined, must be valid
955  * @param queryMultiDescriptorGroups The query groups of multi-descriptors for which the best matching tree candidate descriptors will be determined, can be nullptr if 'numberQueryMultiDescriptors == 0'
956  * @param numberQueryMultiDescriptorGroups The number of given query groups of multi-descriptors, with range [0, infinity)
957  * @param maximalDistance The maximal distance between two matching descriptors, with range [0, infinity)
958  * @param matches The resulting matches
959  * @param worker Optional worker object to distribute the computation
960  * @tparam TMultiDescriptorGroup The data type of the multi-descriptor group
961  * @tparam TMultiDescriptor The data type of the multi-descriptor
962  * @tparam tMultiDescriptorGroupFunction The function pointer to a static function allowing to access one multi-descriptor of a group of multi-descriptors, must be valid
963  * @tparam tMultiDescriptorFunction The function pointer to a static function allowing to access one single-descriptor of a multi-descriptor, must be valid
964  * @tparam tMatchingMode The mode which is used for matching
965  */
966  template <typename TMultiDescriptorGroup, typename TMultiDescriptor, MultiDescriptorGroupFunction<TMultiDescriptorGroup, TMultiDescriptor> tMultiDescriptorGroupFunction, MultiDescriptorFunction<TMultiDescriptor> tMultiDescriptorFunction, MatchingMode tMatchingMode = MM_FIRST_BEST_LEAF>
967  void matchMultiDescriptorGroups(const TDescriptor* candidateDescriptors, const TMultiDescriptorGroup* queryMultiDescriptorGroups, const size_t numberQueryMultiDescriptorGroups, const TDistance maximalDistance, Matches& matches, Worker* worker = nullptr) const;
968 
969  protected:
970 
971  /**
972  * Matches a subset of several query descriptors with all forest candidate descriptors.
973  * @param candidateDescriptors The entire set of tree candidate descriptors which have been used to create the tree, from which the best matching descriptor will be determined, must be valid
974  * @param queryDescriptors The query descriptors for which the best matching tree candidate descriptors will be determined, must be valid
975  * @param maximalDistance The maximal distance between two matching descriptors, with range [0, infinity)
976  * @param matches The resulting matches
977  * @param lock Optional lock when executed in multiple threads in parallel, nullptr otherwise
978  * @param firstQueryDescriptor The index of the first query descriptor to be handled, with range [0, infinity)
979  * @param numberQueryDescriptors The number of query descriptors to be handled, with range [1, infinity)
980  * @tparam tMatchingMode The mode which is used for matching
981  */
982  template <MatchingMode tMatchingMode>
983  void matchDescriptorsSubset(const TDescriptor* candidateDescriptors, const TDescriptor* queryDescriptors, const TDistance maximalDistance, Matches* matches, Lock* lock, const unsigned int firstQueryDescriptor, const unsigned int numberQueryDescriptors) const;
984 
985  /**
986  * Matches a subset of several query multi-descriptors with all forest candidate descriptors.
987  * @param candidateDescriptors The entire set of tree candidate descriptors which have been used to create the tree, from which the best matching descriptor will be determined, must be valid
988  * @param queryMultiDescriptors The query multi-descriptors for which the best matching tree candidate descriptors will be determined, must be valid
989  * @param maximalDistance The maximal distance between two matching descriptors, with range [0, infinity)
990  * @param matches The resulting matches
991  * @param lock Optional lock when executed in multiple threads in parallel, nullptr otherwise
992  * @param firstQueryMultiDescriptor The index of the first query multi-descriptor to be handled, with range [0, infinity)
993  * @param numberQueryMultiDescriptors The number of query multi-descriptors to be handled, with range [1, infinity)
994  * @tparam TMultiDescriptor The data type of a multi-descriptor
995  * @tparam tMultiDescriptorFunction The function pointer to a static function allowing to access one single-descriptor of a multi-descriptor, must be valid
996  * @tparam tMatchingMode The mode which is used for matching
997  */
998  template <typename TMultiDescriptor, MultiDescriptorFunction<TMultiDescriptor> tMultiDescriptorFunction, MatchingMode tMatchingMode>
999  void matchMultiDescriptorsSubset(const TDescriptor* candidateDescriptors, const TMultiDescriptor* queryMultiDescriptors, const TDistance maximalDistance, Matches* matches, Lock* lock, const unsigned int firstQueryMultiDescriptor, const unsigned int numberQueryMultiDescriptors) const;
1000 
1001  /**
1002  * Matches a subset of several query groups of multi-descriptors with all candidate descriptors in this forest.
1003  * @param candidateDescriptors The entire set of tree candidate descriptors which have been used to create the tree, from which the best matching descriptor will be determined, must be valid
1004  * @param queryMultiDescriptorGroups The query groups of multi-descriptors for which the best matching tree candidate descriptors will be determined, can be nullptr if 'numberQueryMultiDescriptors == 0'
1005  * @param maximalDistance The maximal distance between two matching descriptors, with range [0, infinity)
1006  * @param matches The resulting matches
1007  * @param lock Optional lock when executed in multiple threads in parallel, nullptr otherwise
1008  * @param firstQueryMultiDescriptorGroup The index of the first query group of multi-descriptors to be handled, with range [0, infinity)
1009  * @param numberQueryMultiDescriptorGroups The number of query groups of multi-descriptors to be handled, with range [1, infinity)
1010  * @tparam TMultiDescriptorGroup The data type of the multi-descriptor group
1011  * @tparam TMultiDescriptor The data type of the multi-descriptor
1012  * @tparam tMultiDescriptorGroupFunction The function pointer to a static function allowing to access one multi-descriptor of a group of multi-descriptors, must be valid
1013  * @tparam tMultiDescriptorFunction The function pointer to a static function allowing to access one single-descriptor of a multi-descriptor, must be valid
1014  * @tparam tMatchingMode The mode which is used for matching
1015  */
1016  template <typename TMultiDescriptorGroup, typename TMultiDescriptor, MultiDescriptorGroupFunction<TMultiDescriptorGroup, TMultiDescriptor> tMultiDescriptorGroupFunction, MultiDescriptorFunction<TMultiDescriptor> tMultiDescriptorFunction, MatchingMode tMatchingMode>
1017  void matchMultiDescriptorGroupsSubset(const TDescriptor* candidateDescriptors, const TMultiDescriptorGroup* queryMultiDescriptorGroups, const TDistance maximalDistance, Matches* matches, Lock* lock, const unsigned int firstQueryMultiDescriptorGroup, const unsigned int numberQueryMultiDescriptorGroups) const;
1018 
1019  protected:
1020 
1021  /// The trees of this forest.
1023 };
1024 
1026 {
1027  return Index32(-1);
1028 }
1029 
1030 template <typename TDistance>
1031 inline VocabularyStructure::Match<TDistance>::Match(const Index32 candidateDescriptorIndex, const Index32 queryDescriptorIndex, const TDistance distance) :
1032  candidateDescriptorIndex_(candidateDescriptorIndex),
1033  queryDescriptorIndex_(queryDescriptorIndex),
1034  distance_(distance)
1035 {
1036  // nothing to do here
1037 }
1038 
1039 template <typename TDistance>
1041 {
1042  return candidateDescriptorIndex_;
1043 }
1044 
1045 template <typename TDistance>
1047 {
1048  return queryDescriptorIndex_;
1049 }
1050 
1051 template <typename TDistance>
1053 {
1054  return distance_;
1055 }
1056 
1057 template <typename TDistance>
1059 {
1060  return candidateDescriptorIndex_ != invalidMatchIndex() && queryDescriptorIndex_ != invalidMatchIndex();
1061 }
1062 
1063 inline VocabularyStructure::Parameters::Parameters(const unsigned int maximalNumberClustersPerLevel, const unsigned int maximalDescriptorsPerLeaf, const unsigned int maximalLevels, const InitializationStrategy initializationStrategy) :
1064  maximalNumberClustersPerLevel_(maximalNumberClustersPerLevel),
1065  maximalDescriptorsPerLeaf_(maximalDescriptorsPerLeaf),
1066  maximalLevels_(maximalLevels),
1067  initializationStrategy_(initializationStrategy)
1068 {
1069  // nothing to do here
1070 }
1071 
1073 {
1074  return maximalNumberClustersPerLevel_ >= 2u && maximalDescriptorsPerLeaf_ >= 1u && maximalLevels_ >= 1u && initializationStrategy_ != IS_INVALID;
1075 }
1076 
1078 {
1079  std::vector<uint8_t> lookup(256 * 8);
1080 
1081  for (unsigned int n = 0u; n < 256u; ++n)
1082  {
1083  uint8_t* const lookupValues = lookup.data() + n * 8u;
1084 
1085  for (unsigned int i = 0; i < 8u; ++i)
1086  {
1087  if (n & (1 << i))
1088  {
1089  lookupValues[i] = 1u;
1090  }
1091  else
1092  {
1093  lookupValues[i] = 0u;
1094  }
1095  }
1096  }
1097 
1098  return lookup;
1099 }
1100 
1101 template <typename TDescriptor, typename TDistance, TDistance(*tDistanceFunction)(const TDescriptor&, const TDescriptor&)>
1103 {
1104  static_assert(tDistanceFunction != nullptr, "Invalid distance function!");
1105 
1106  *this = std::move(VocabularyTree);
1107 }
1108 
1109 template <typename TDescriptor, typename TDistance, TDistance(*tDistanceFunction)(const TDescriptor&, const TDescriptor&)>
1110 VocabularyTree<TDescriptor, TDistance, tDistanceFunction>::VocabularyTree(const TDescriptor* treeDescriptors, const size_t numberTreeDescriptors, const ClustersMeanFunction& clustersMeanFunction, const Parameters& parameters, Worker* worker, RandomGenerator* randomGenerator)
1111 {
1112  static_assert(tDistanceFunction != nullptr, "Invalid distance function!");
1113 
1114  ocean_assert(parameters.isValid());
1115 
1116  ocean_assert(numberTreeDescriptors > 0);
1117 
1118  Indices32 reusableDescriptorIndicesInput = Ocean::createIndices<Index32>(numberTreeDescriptors, 0u);
1119  Indices32 reusableDescriptorIndicesOutput(numberTreeDescriptors);
1120  Indices32 reusableClusterIndicesForDescriptors(numberTreeDescriptors);
1121 
1122  RandomGenerator localRandomGenerator(randomGenerator);
1123 
1124  memset(&nodeDescriptor_, 0, sizeof(nodeDescriptor_));
1125 
1126 
1127  if (numberTreeDescriptors < parameters.maximalNumberClustersPerLevel_)
1128  {
1129  *this = VocabularyTree<TDescriptor, TDistance, tDistanceFunction>(0u, treeDescriptors[0], reusableDescriptorIndicesInput.data(), reusableDescriptorIndicesInput.size());
1130  }
1131  else
1132  {
1133  *this = VocabularyTree<TDescriptor, TDistance, tDistanceFunction>(0u, nodeDescriptor_, parameters, treeDescriptors, reusableDescriptorIndicesInput.data(), reusableDescriptorIndicesOutput.data(), reusableDescriptorIndicesInput.size(), localRandomGenerator, reusableClusterIndicesForDescriptors.data(), clustersMeanFunction, worker);
1134  }
1135 }
1136 
1137 template <typename TDescriptor, typename TDistance, TDistance(*tDistanceFunction)(const TDescriptor&, const TDescriptor&)>
1138 VocabularyTree<TDescriptor, TDistance, tDistanceFunction>::VocabularyTree(const unsigned int level, const TDescriptor& nodeDescriptor, const Parameters& parameters, const TDescriptor* treeDescriptors, Index32* reusableDescriptorIndicesInput, Index32* reusableDescriptorIndicesOutput, const size_t numberDescriptorIndices, RandomGenerator& randomGenerator, Index32* reusableClusterIndicesForDescriptors, const ClustersMeanFunction& clustersMeanFunction, Worker* worker) :
1139  level_(level),
1140  nodeDescriptor_(nodeDescriptor)
1141 {
1142  static_assert(tDistanceFunction != nullptr, "Invalid distance function!");
1143 
1144  ocean_assert(parameters.isValid());
1145  ocean_assert(reusableDescriptorIndicesInput != nullptr && reusableDescriptorIndicesOutput != nullptr);
1146 
1147  const unsigned int childLevel = level + 1u;
1148  ocean_assert(childLevel < parameters.maximalLevels_);
1149 
1150  ocean_assert(parameters.maximalNumberClustersPerLevel_ <= numberDescriptorIndices);
1151 
1152  Indices32 clusterSizes;
1153  const TDescriptors clusterCenters = clusterDescriptors(parameters, treeDescriptors, reusableDescriptorIndicesInput, reusableDescriptorIndicesOutput, numberDescriptorIndices, randomGenerator, reusableClusterIndicesForDescriptors, clustersMeanFunction, &clusterSizes, worker);
1154  ocean_assert(clusterCenters.size() == clusterSizes.size());
1155 
1156  // now, we swap the reusable input and output index buffers
1157 
1158  Index32* const swappedReusableDescriptorIndicesInput = reusableDescriptorIndicesOutput;
1159  Index32* const swappedReusableDescriptorIndicesOutput = reusableDescriptorIndicesInput;
1160 
1161  createChildNodes(childLevel, parameters, treeDescriptors, clusterCenters.data(), clusterSizes.data(), clusterCenters.size(), swappedReusableDescriptorIndicesInput, swappedReusableDescriptorIndicesOutput, numberDescriptorIndices, randomGenerator, reusableClusterIndicesForDescriptors, clustersMeanFunction, worker);
1162 }
1163 
1164 template <typename TDescriptor, typename TDistance, TDistance(*tDistanceFunction)(const TDescriptor&, const TDescriptor&)>
1165 VocabularyTree<TDescriptor, TDistance, tDistanceFunction>::VocabularyTree(const unsigned int level, const TDescriptor& nodeDescriptor, Index32* descriptorIndices, size_t numberDescriptorsIndices) :
1166  level_(level),
1167  nodeDescriptor_(nodeDescriptor)
1168 {
1169  static_assert(tDistanceFunction != nullptr, "Invalid distance function!");
1170 
1171  ocean_assert(descriptorIndices != nullptr);
1172  ocean_assert(numberDescriptorsIndices != 0);
1173 
1174  descriptorIndices_ = Indices32(descriptorIndices, descriptorIndices + numberDescriptorsIndices);
1175 }
1176 
1177 template <typename TDescriptor, typename TDistance, TDistance(*tDistanceFunction)(const TDescriptor&, const TDescriptor&)>
1179 {
1180  for (VocabularyTree* childNode : childNodes_)
1181  {
1182  delete childNode;
1183  }
1184 }
1185 
1186 template <typename TDescriptor, typename TDistance, TDistance(*tDistanceFunction)(const TDescriptor&, const TDescriptor&)>
1187 void VocabularyTree<TDescriptor, TDistance, tDistanceFunction>::createChildNodes(const unsigned int childNodeLevel, const Parameters& parameters, const TDescriptor* treeDescriptors, const TDescriptor* clusterCenters, const unsigned int* clusterSizes, const size_t numberClusters, Index32* reusableDescriptorIndicesInput, Index32* reusableDescriptorIndicesOutput, size_t numberDescriptorsIndices, RandomGenerator& randomGenerator, Index32* reusableClusterIndicesForDescriptors, const ClustersMeanFunction& clustersMeanFunction, Worker* worker)
1188 {
1189  ocean_assert(clusterCenters != nullptr && clusterSizes != nullptr);
1190  ocean_assert(numberClusters >= 1);
1191  ocean_assert(reusableDescriptorIndicesInput != nullptr && reusableDescriptorIndicesOutput != nullptr);
1192 
1193  ocean_assert(childNodes_.empty());
1194  childNodes_.resize(numberClusters, nullptr);
1195 
1196  if (worker)
1197  {
1198  worker->executeFunction(Worker::Function::create(*this, &VocabularyTree<TDescriptor, TDistance, tDistanceFunction>::createChildNodesSubset, childNodeLevel, &parameters, treeDescriptors, clusterCenters, clusterSizes, numberClusters, reusableDescriptorIndicesInput, reusableDescriptorIndicesOutput, numberDescriptorsIndices, &randomGenerator, reusableClusterIndicesForDescriptors, &clustersMeanFunction, 0u, 0u), 0u, (unsigned int)(numberClusters));
1199  }
1200  else
1201  {
1202  createChildNodesSubset(childNodeLevel, &parameters, treeDescriptors, clusterCenters, clusterSizes, numberClusters, reusableDescriptorIndicesInput, reusableDescriptorIndicesOutput, numberDescriptorsIndices, &randomGenerator, reusableClusterIndicesForDescriptors, &clustersMeanFunction, 0u, (unsigned int)(numberClusters));
1203  }
1204 
1205 #ifdef OCEAN_DEBUG
1206  for (Node* childNode : childNodes_)
1207  {
1208  ocean_assert(childNode != nullptr);
1209  }
1210 #endif
1211 }
1212 
1213 template <typename TDescriptor, typename TDistance, TDistance(*tDistanceFunction)(const TDescriptor&, const TDescriptor&)>
1215 {
1216  const Node* bestChildNode;
1217  TDistance bestDistance;
1218 
1219  const Node* node = this;
1220 
1221  while (true)
1222  {
1223  ocean_assert(node != nullptr);
1224 
1225  bestChildNode = nullptr;
1226  bestDistance = NumericT<TDistance>::maxValue();
1227 
1228  for (const Node* childNode : node->childNodes_)
1229  {
1230  ocean_assert(childNode != nullptr);
1231 
1232  const TDistance distance = tDistanceFunction(descriptor, childNode->nodeDescriptor_);
1233 
1234  if (distance < bestDistance)
1235  {
1236  bestDistance = distance;
1237  bestChildNode = childNode;
1238  }
1239  }
1240 
1241  if (bestChildNode == nullptr)
1242  {
1243  return node->descriptorIndices_;
1244  }
1245 
1246  node = bestChildNode;
1247  }
1248 }
1249 
1250 template <typename TDescriptor, typename TDistance, TDistance(*tDistanceFunction)(const TDescriptor&, const TDescriptor&)>
1251 void VocabularyTree<TDescriptor, TDistance, tDistanceFunction>::determineBestLeafs(const TDescriptor& descriptor, std::vector<const Indices32*>& leafs, const TDistance distanceEpsilon) const
1252 {
1253  ocean_assert(leafs.empty());
1254 
1255  TDistance bestDistance;
1256 
1257  ConstNodes bestNodes;
1258  bestNodes.reserve(16);
1259 
1260  ConstNodes nodes;
1261  nodes.reserve(16);
1262 
1263  nodes.emplace_back(this);
1264 
1265  while (!nodes.empty())
1266  {
1267  const Node* node = nodes.back();
1268  nodes.pop_back();
1269 
1270  ocean_assert(node != nullptr);
1271 
1272  bestNodes.clear();
1273  bestDistance = NumericT<TDistance>::maxValue();
1274 
1275  for (const Node* childNode : node->childNodes_)
1276  {
1277  ocean_assert(childNode != nullptr);
1278 
1279  const TDistance distance = tDistanceFunction(descriptor, childNode->nodeDescriptor_);
1280 
1281  if (distance < bestDistance)
1282  {
1283  if (distance + distanceEpsilon < bestDistance)
1284  {
1285  // we have a significant improvements
1286  bestNodes.clear();
1287  }
1288 
1289  bestDistance = distance;
1290  bestNodes.emplace_back(childNode);
1291  }
1292  else if (distance + distanceEpsilon <= bestDistance)
1293  {
1294  bestNodes.emplace_back(childNode);
1295  }
1296  }
1297 
1298  if (bestNodes.empty())
1299  {
1300  ocean_assert(bestDistance == NumericT<TDistance>::maxValue());
1301 
1302  leafs.emplace_back(&node->descriptorIndices_);
1303  }
1304  else
1305  {
1306  if (bestNodes.size() == 1)
1307  {
1308  nodes.emplace_back(bestNodes.front());
1309  }
1310  else
1311  {
1312  nodes.insert(nodes.cend(), bestNodes.cbegin(), bestNodes.cend());
1313  }
1314  }
1315  }
1316 }
1317 
1318 template <typename TDescriptor, typename TDistance, TDistance(*tDistanceFunction)(const TDescriptor&, const TDescriptor&)>
1319 template <VocabularyStructure::MatchingMode tMatchingMode>
1320 Index32 VocabularyTree<TDescriptor, TDistance, tDistanceFunction>::matchDescriptor(const TDescriptor* candidateDescriptors, const TDescriptor& queryDescriptor, TDistance* distance, const ReusableData& reusableData) const
1321 {
1322  ocean_assert(candidateDescriptors != nullptr);
1323 
1324  Index32 bestCandidateDescriptorIndex = invalidMatchIndex();
1325  TDistance bestDistance = NumericT<TDistance>::maxValue();
1326 
1327  if constexpr (tMatchingMode == MM_FIRST_BEST_LEAF)
1328  {
1329  const Indices32& candidateIndices = determineBestLeaf(queryDescriptor);
1330 
1331  for (const Index32& candidateIndex : candidateIndices)
1332  {
1333  const TDistance candidateDistance = tDistanceFunction(candidateDescriptors[candidateIndex], queryDescriptor);
1334 
1335  if (candidateDistance < bestDistance)
1336  {
1337  bestDistance = candidateDistance;
1338  bestCandidateDescriptorIndex = candidateIndex;
1339  }
1340  }
1341  }
1342  else
1343  {
1344  ocean_assert(tMatchingMode == MM_ALL_BEST_LEAFS || tMatchingMode == MM_ALL_GOOD_LEAFS_1 || tMatchingMode == MM_ALL_GOOD_LEAFS_2);
1345 
1346  TDistance distanceEpsilon = TDistance(0);
1347 
1348  if constexpr (tMatchingMode == MM_ALL_GOOD_LEAFS_1)
1349  {
1350  if (std::is_floating_point<TDistance>::value)
1351  {
1352  distanceEpsilon = TDistance(0.25);
1353  }
1354  else
1355  {
1356  distanceEpsilon = TDistance((sizeof(TDescriptor) * 8 * 1 + 50) / 100);
1357  }
1358  }
1359  else if constexpr (tMatchingMode == MM_ALL_GOOD_LEAFS_2)
1360  {
1361  if (std::is_floating_point<TDistance>::value)
1362  {
1363  distanceEpsilon = TDistance(0.5);
1364  }
1365  else
1366  {
1367  distanceEpsilon = TDistance((sizeof(TDescriptor) * 8 * 2 + 50) / 100);
1368  }
1369  }
1370 
1371  reusableData.internalData_.clear();
1372 
1373  determineBestLeafs(queryDescriptor, reusableData.internalData_, distanceEpsilon);
1374 
1375  for (const Indices32* candidateLeaf : reusableData.internalData_)
1376  {
1377  for (const Index32& candidateIndex : *candidateLeaf)
1378  {
1379  const TDistance candidateDistance = tDistanceFunction(candidateDescriptors[candidateIndex], queryDescriptor);
1380 
1381  if (candidateDistance < bestDistance)
1382  {
1383  bestDistance = candidateDistance;
1384  bestCandidateDescriptorIndex = candidateIndex;
1385  }
1386  }
1387  }
1388  }
1389 
1390  if (distance != nullptr)
1391  {
1392  *distance = bestDistance;
1393  }
1394 
1395  return bestCandidateDescriptorIndex;
1396 }
1397 
1398 template <typename TDescriptor, typename TDistance, TDistance(*tDistanceFunction)(const TDescriptor&, const TDescriptor&)>
1399 template <VocabularyStructure::MatchingMode tMatchingMode>
1400 Index32 VocabularyTree<TDescriptor, TDistance, tDistanceFunction>::matchMultiDescriptor(const TDescriptor* candidateDescriptors, const TDescriptor* queryMultyDescriptor, const size_t numberQuerySingleDescriptors, TDistance* distance, const ReusableData& reusableData) const
1401 {
1402  ocean_assert(candidateDescriptors != nullptr);
1403  ocean_assert(queryMultyDescriptor != nullptr && numberQuerySingleDescriptors >= 1);
1404 
1405  Index32 bestCandidateDescriptorIndex = invalidMatchIndex();
1406  TDistance bestDistance = NumericT<TDistance>::maxValue();
1407 
1408  for (size_t nQuerySingle = 0; nQuerySingle < numberQuerySingleDescriptors; ++nQuerySingle)
1409  {
1410  TDistance candidateDistance;
1411  const Index32 candidateIndex = matchDescriptor<tMatchingMode>(candidateDescriptors, queryMultyDescriptor[nQuerySingle], &candidateDistance, reusableData);
1412 
1413  if (candidateDistance < bestDistance)
1414  {
1415  bestDistance = candidateDistance;
1416  bestCandidateDescriptorIndex = candidateIndex;
1417  }
1418  }
1419 
1420  if (distance != nullptr)
1421  {
1422  *distance = bestDistance;
1423  }
1424 
1425  return bestCandidateDescriptorIndex;
1426 }
1427 
1428 template <typename TDescriptor, typename TDistance, TDistance(*tDistanceFunction)(const TDescriptor&, const TDescriptor&)>
1429 template <typename TMultiDescriptor, const TDescriptor*(*tMultiDescriptorFunction)(const TMultiDescriptor&, const size_t), VocabularyStructure::MatchingMode tMatchingMode>
1430 Index32 VocabularyTree<TDescriptor, TDistance, tDistanceFunction>::matchMultiDescriptor(const TDescriptor* candidateDescriptors, const TMultiDescriptor& queryMultiDescriptor, TDistance* distance, const ReusableData& reusableData) const
1431 {
1432  static_assert(tMultiDescriptorFunction != nullptr, "Invalid function!");
1433 
1434  ocean_assert(candidateDescriptors != nullptr);
1435 
1436  Index32 bestCandidateDescriptorIndex = invalidMatchIndex();
1437  TDistance bestDistance = NumericT<TDistance>::maxValue();
1438 
1439  size_t nQueryIndex = 0;
1440 
1441  while (const TDescriptor* queryDescriptor = tMultiDescriptorFunction(queryMultiDescriptor, nQueryIndex++))
1442  {
1443  ocean_assert(queryDescriptor != nullptr);
1444 
1445  TDistance candidateDistance;
1446  const Index32 candidateIndex = matchDescriptor<tMatchingMode>(candidateDescriptors, *queryDescriptor, &candidateDistance, reusableData);
1447 
1448  if (candidateDistance < bestDistance)
1449  {
1450  bestDistance = candidateDistance;
1451  bestCandidateDescriptorIndex = candidateIndex;
1452  }
1453  }
1454 
1455  if (distance != nullptr)
1456  {
1457  *distance = bestDistance;
1458  }
1459 
1460  return bestCandidateDescriptorIndex;
1461 }
1462 
1463 template <typename TDescriptor, typename TDistance, TDistance(*tDistanceFunction)(const TDescriptor&, const TDescriptor&)>
1464 template <typename TMultiDescriptorGroup, typename TMultiDescriptor, const TMultiDescriptor*(*tMultiDescriptorGroupFunction)(const TMultiDescriptorGroup&, const size_t), const TDescriptor*(*tMultiDescriptorFunction)(const TMultiDescriptor&, const size_t), VocabularyStructure::MatchingMode tMatchingMode>
1465 Index32 VocabularyTree<TDescriptor, TDistance, tDistanceFunction>::matchMultiDescriptorGroup(const TDescriptor* candidateDescriptors, const TMultiDescriptorGroup& queryMultiDescriptorGroup, TDistance* distance, const ReusableData& reusableData) const
1466 {
1467  static_assert(tMultiDescriptorGroupFunction != nullptr, "Invalid function!");
1468  static_assert(tMultiDescriptorFunction != nullptr, "Invalid function!");
1469 
1470  ocean_assert(candidateDescriptors != nullptr);
1471 
1472  Index32 bestCandidateDescriptorIndex = invalidMatchIndex();
1473  TDistance bestDistance = NumericT<TDistance>::maxValue();
1474 
1475  size_t nQueryIndex = 0;
1476 
1477  while (const TMultiDescriptor* queryMultiDescriptor = tMultiDescriptorGroupFunction(queryMultiDescriptorGroup, nQueryIndex++))
1478  {
1479  ocean_assert(queryMultiDescriptor != nullptr);
1480 
1481  TDistance candidateDistance;
1482  const Index32 candidateIndex = matchMultiDescriptor<TMultiDescriptor, tMultiDescriptorFunction, tMatchingMode>(candidateDescriptors, *queryMultiDescriptor, &candidateDistance, reusableData);
1483 
1484  if (candidateDistance < bestDistance)
1485  {
1486  bestDistance = candidateDistance;
1487  bestCandidateDescriptorIndex = candidateIndex;
1488  }
1489  }
1490 
1491  if (distance != nullptr)
1492  {
1493  *distance = bestDistance;
1494  }
1495 
1496  return bestCandidateDescriptorIndex;
1497 }
1498 
1499 template <typename TDescriptor, typename TDistance, TDistance(*tDistanceFunction)(const TDescriptor&, const TDescriptor&)>
1500 template <VocabularyStructure::MatchingMode tMatchingMode>
1501 void VocabularyTree<TDescriptor, TDistance, tDistanceFunction>::matchDescriptors(const TDescriptor* candidateDescriptors, const TDescriptor* queryDescriptors, const size_t numberQueryDescriptors, const TDistance maximalDistance, Matches& matches, Worker* worker) const
1502 {
1503  matches.clear();
1504 
1505  ocean_assert(candidateDescriptors != nullptr);
1506  if (numberQueryDescriptors == 0)
1507  {
1508  return;
1509  }
1510 
1511  ocean_assert(queryDescriptors != nullptr);
1512 
1513  if (worker && numberQueryDescriptors >= 50)
1514  {
1515  Lock lock;
1516  worker->executeFunction(Worker::Function::create(*this, &VocabularyTree<TDescriptor, TDistance, tDistanceFunction>::matchDescriptorsSubset<tMatchingMode>, candidateDescriptors, queryDescriptors, maximalDistance, &matches, &lock, 0u, 0u), 0u, (unsigned int)(numberQueryDescriptors), 5u, 6u, 50u);
1517  }
1518  else
1519  {
1520  matchDescriptorsSubset<tMatchingMode>(candidateDescriptors, queryDescriptors, maximalDistance, &matches, nullptr, 0u, (unsigned int)(numberQueryDescriptors));
1521  }
1522 }
1523 
1524 template <typename TDescriptor, typename TDistance, TDistance(*tDistanceFunction)(const TDescriptor&, const TDescriptor&)>
1525 template <typename TMultiDescriptor, const TDescriptor*(*tMultiDescriptorFunction)(const TMultiDescriptor&, const size_t), VocabularyStructure::MatchingMode tMatchingMode>
1526 void VocabularyTree<TDescriptor, TDistance, tDistanceFunction>::matchMultiDescriptors(const TDescriptor* candidateDescriptors, const TMultiDescriptor* queryMultiDescriptors, const size_t numberQueryMultiDescriptors, const TDistance maximalDistance, Matches& matches, Worker* worker) const
1527 {
1528  static_assert(tMultiDescriptorFunction != nullptr, "Invalid function!");
1529 
1530  matches.clear();
1531 
1532  ocean_assert(candidateDescriptors != nullptr);
1533  if (numberQueryMultiDescriptors == 0)
1534  {
1535  return;
1536  }
1537 
1538  ocean_assert(queryMultiDescriptors != nullptr);
1539 
1540  if (worker && numberQueryMultiDescriptors >= 50)
1541  {
1542  Lock lock;
1543  worker->executeFunction(Worker::Function::create(*this, &VocabularyTree<TDescriptor, TDistance, tDistanceFunction>::matchMultiDescriptorsSubset<TMultiDescriptor, tMultiDescriptorFunction, tMatchingMode>, candidateDescriptors, queryMultiDescriptors, maximalDistance, &matches, &lock, 0u, 0u), 0u, (unsigned int)(numberQueryMultiDescriptors), 5u, 6u, 50u);
1544  }
1545  else
1546  {
1547  matchMultiDescriptorsSubset<TMultiDescriptor, tMultiDescriptorFunction, tMatchingMode>(candidateDescriptors, queryMultiDescriptors, maximalDistance, &matches, nullptr, 0u, (unsigned int)(numberQueryMultiDescriptors));
1548  }
1549 }
1550 
1551 template <typename TDescriptor, typename TDistance, TDistance(*tDistanceFunction)(const TDescriptor&, const TDescriptor&)>
1552 template <typename TMultiDescriptorGroup, typename TMultiDescriptor, const TMultiDescriptor*(*tMultiDescriptorGroupFunction)(const TMultiDescriptorGroup&, const size_t), const TDescriptor*(*tMultiDescriptorFunction)(const TMultiDescriptor&, const size_t), VocabularyStructure::MatchingMode tMatchingMode>
1553 void VocabularyTree<TDescriptor, TDistance, tDistanceFunction>::matchMultiDescriptorGroups(const TDescriptor* candidateDescriptors, const TMultiDescriptorGroup* queryMultiDescriptorGroups, const size_t numberQueryMultiDescriptorGroups, const TDistance maximalDistance, Matches& matches, Worker* worker) const
1554 {
1555  static_assert(tMultiDescriptorGroupFunction != nullptr, "Invalid function!");
1556  static_assert(tMultiDescriptorFunction != nullptr, "Invalid function!");
1557 
1558  matches.clear();
1559 
1560  ocean_assert(candidateDescriptors != nullptr);
1561  if (numberQueryMultiDescriptorGroups == 0)
1562  {
1563  return;
1564  }
1565 
1566  ocean_assert(queryMultiDescriptorGroups != nullptr);
1567 
1568  if (worker && numberQueryMultiDescriptorGroups >= 50)
1569  {
1570  Lock lock;
1571  worker->executeFunction(Worker::Function::create(*this, &VocabularyTree<TDescriptor, TDistance, tDistanceFunction>::matchMultiDescriptorGroupsSubset<TMultiDescriptorGroup, TMultiDescriptor, tMultiDescriptorGroupFunction, tMultiDescriptorFunction, tMatchingMode>, candidateDescriptors, queryMultiDescriptorGroups, maximalDistance, &matches, &lock, 0u, 0u), 0u, (unsigned int)(numberQueryMultiDescriptorGroups), 5u, 6u, 50u);
1572  }
1573  else
1574  {
1575  matchMultiDescriptorGroupsSubset<TMultiDescriptorGroup, TMultiDescriptor, tMultiDescriptorGroupFunction, tMultiDescriptorFunction, tMatchingMode>(candidateDescriptors, queryMultiDescriptorGroups, maximalDistance, &matches, nullptr, 0u, (unsigned int)(numberQueryMultiDescriptorGroups));
1576  }
1577 }
1578 
1579 template <typename TDescriptor, typename TDistance, TDistance(*tDistanceFunction)(const TDescriptor&, const TDescriptor&)>
1581 {
1582  return nodeDescriptor_;
1583 }
1584 
1585 template <typename TDescriptor, typename TDistance, TDistance(*tDistanceFunction)(const TDescriptor&, const TDescriptor&)>
1587 {
1588  return descriptorIndices_;
1589 }
1590 
1591 template <typename TDescriptor, typename TDistance, TDistance(*tDistanceFunction)(const TDescriptor&, const TDescriptor&)>
1593 {
1594  return childNodes_;
1595 }
1596 
1597 template <typename TDescriptor, typename TDistance, TDistance(*tDistanceFunction)(const TDescriptor&, const TDescriptor&)>
1598 typename VocabularyTree<TDescriptor, TDistance, tDistanceFunction>::TDescriptors VocabularyTree<TDescriptor, TDistance, tDistanceFunction>::clusterDescriptors(const Parameters& parameters, const TDescriptor* treeDescriptors, Index32* reusableDescriptorIndicesInput, Index32* reusableDescriptorIndicesOutput, size_t numberDescriptorsIndices, RandomGenerator& randomGenerator, Index32* reusableClusterIndicesForDescriptors, const ClustersMeanFunction& clustersMeanFunction, Indices32* clusterSizes, Worker* worker)
1599 {
1600  ocean_assert(parameters.isValid());
1601  ocean_assert(parameters.maximalNumberClustersPerLevel_ <= numberDescriptorsIndices);
1602  ocean_assert(reusableDescriptorIndicesInput != nullptr && reusableDescriptorIndicesOutput != nullptr);
1603 
1604  TDescriptors clusterCenters = initialClusters(parameters, treeDescriptors, reusableDescriptorIndicesInput, reusableDescriptorIndicesOutput, numberDescriptorsIndices, randomGenerator);
1605  const unsigned int numberClusters = (unsigned int)(clusterCenters.size());
1606  ocean_assert(numberClusters >= 1u && numberClusters * parameters.maximalDescriptorsPerLeaf_ <= numberDescriptorsIndices + parameters.maximalDescriptorsPerLeaf_);
1607 
1608  TSumDistances previousSumDistances = NumericT<TSumDistances>::maxValue();
1609  Indices32 internalClusterSizes;
1610 
1611  while (true)
1612  {
1613  if (!internalClusterSizes.empty()) // not in the first iteration
1614  {
1615  clusterCenters = clustersMeanFunction(numberClusters, treeDescriptors, reusableDescriptorIndicesInput, reusableClusterIndicesForDescriptors, numberDescriptorsIndices, worker);
1616  }
1617 
1619  internalClusterSizes = assignDescriptorsToClusters(clusterCenters.data(), numberClusters, treeDescriptors, reusableDescriptorIndicesInput, reusableClusterIndicesForDescriptors, numberDescriptorsIndices, &sumDistances, worker);
1620  ocean_assert(sumDistances != NumericT<TSumDistances>::maxValue());
1621 
1622  if (sumDistances >= previousSumDistances)
1623  {
1624  // we reached the optimal clustering
1625  break;
1626  }
1627 
1628  previousSumDistances = sumDistances;
1629  }
1630 
1631  ocean_assert(clusterCenters.size() >= 1);
1632  ocean_assert(internalClusterSizes.size() == clusterCenters.size());
1633 
1634  // now we move the descriptor indices based on the new clusters
1635 
1636  bool atLeastOneClusterEmpty = internalClusterSizes.front() == 0u;
1637 
1638  std::vector<Index32*> newDescriptorIndicesPerCluster;
1639  newDescriptorIndicesPerCluster.reserve(numberClusters);
1640 
1641  newDescriptorIndicesPerCluster.emplace_back(reusableDescriptorIndicesOutput);
1642  for (unsigned int nCluster = 1u; nCluster < numberClusters; ++nCluster)
1643  {
1644  newDescriptorIndicesPerCluster.emplace_back(newDescriptorIndicesPerCluster.back() + internalClusterSizes[nCluster - 1u]);
1645 
1646  if (internalClusterSizes[nCluster] == 0u)
1647  {
1648  atLeastOneClusterEmpty = true;
1649  }
1650  }
1651 
1652  for (size_t nDescriptor = 0; nDescriptor < numberDescriptorsIndices; ++nDescriptor)
1653  {
1654  const Index32& descriptorIndex = reusableDescriptorIndicesInput[nDescriptor];
1655 
1656  const Index32& clusterIndex = reusableClusterIndicesForDescriptors[descriptorIndex];
1657 
1658  *newDescriptorIndicesPerCluster[clusterIndex]++ = descriptorIndex;
1659  }
1660 
1661 #ifdef OCEAN_DEBUG
1662  const Index32* debugNewDescriptorIndicesPerCluster = reusableDescriptorIndicesOutput;
1663  for (unsigned int nCluster = 0u; nCluster < numberClusters; ++nCluster)
1664  {
1665  debugNewDescriptorIndicesPerCluster += internalClusterSizes[nCluster];
1666  ocean_assert(newDescriptorIndicesPerCluster[nCluster] == debugNewDescriptorIndicesPerCluster);
1667  }
1668 #endif
1669 
1670  if (atLeastOneClusterEmpty)
1671  {
1672  // we remove all empty clusters while keeping the order
1673 
1674  TDescriptors newClusterCenters;
1675  newClusterCenters.reserve(clusterCenters.size());
1676 
1677  Indices32 newInternalClusterSizes;
1678  newInternalClusterSizes.reserve(clusterCenters.size());
1679 
1680  for (size_t n = 0; n < clusterCenters.size(); ++n)
1681  {
1682  if (internalClusterSizes[n] != 0u)
1683  {
1684  newClusterCenters.emplace_back(clusterCenters[n]);
1685  newInternalClusterSizes.emplace_back(internalClusterSizes[n]);
1686  }
1687  }
1688 
1689  clusterCenters = std::move(newClusterCenters);
1690  internalClusterSizes = std::move(newInternalClusterSizes);
1691  }
1692 
1693  ocean_assert(internalClusterSizes.size() == clusterCenters.size());
1694 
1695  if (clusterSizes != nullptr)
1696  {
1697  *clusterSizes = std::move(internalClusterSizes);
1698  }
1699 
1700  return clusterCenters;
1701 }
1702 
1703 template <typename TDescriptor, typename TDistance, TDistance(*tDistanceFunction)(const TDescriptor&, const TDescriptor&)>
1704 typename VocabularyTree<TDescriptor, TDistance, tDistanceFunction>::TDescriptors VocabularyTree<TDescriptor, TDistance, tDistanceFunction>::initialClusters(const Parameters& parameters, const TDescriptor* treeDescriptors, Index32* reusableDescriptorIndicesInput, Index32* reusableDescriptorIndicesOutput, size_t numberDescriptorsIndices, RandomGenerator& randomGenerator)
1705 {
1706  ocean_assert(parameters.isValid());
1707  ocean_assert(parameters.maximalNumberClustersPerLevel_ <= numberDescriptorsIndices);
1708  ocean_assert(reusableDescriptorIndicesInput != nullptr);
1709 
1710  switch (parameters.initializationStrategy_)
1711  {
1712  case IS_LARGEST_DISTANCE:
1713  return initialClustersLargestDistance(parameters, treeDescriptors, reusableDescriptorIndicesInput, reusableDescriptorIndicesOutput, numberDescriptorsIndices, randomGenerator);
1714 
1715  default:
1716  ocean_assert(parameters.initializationStrategy_ == IS_PURE_RANDOM);
1717  return initialClustersPureRandom(parameters, treeDescriptors, reusableDescriptorIndicesInput, numberDescriptorsIndices, randomGenerator);
1718  };
1719 }
1720 
1721 template <typename TDescriptor, typename TDistance, TDistance(*tDistanceFunction)(const TDescriptor&, const TDescriptor&)>
1722 typename VocabularyTree<TDescriptor, TDistance, tDistanceFunction>::TDescriptors VocabularyTree<TDescriptor, TDistance, tDistanceFunction>::initialClustersLargestDistance(const Parameters& parameters, const TDescriptor* treeDescriptors, Index32* descriptorIndices, Index32* reusableIndices, const size_t numberDescriptorsIndices, RandomGenerator& randomGenerator) const
1723 {
1724  ocean_assert(parameters.isValid());
1725  ocean_assert(parameters.maximalNumberClustersPerLevel_ <= numberDescriptorsIndices);
1726  ocean_assert(treeDescriptors != nullptr && descriptorIndices != nullptr && reusableIndices != nullptr);
1727  ocean_assert(numberDescriptorsIndices >= 1);
1728 
1729  // the first cluster is selected randomly
1730  // afterwards, we determine the descriptors all having the largest distance too all existing clusters and we selected one of these descriptors as new cluster
1731  // we repeat this process until we have enough clusters
1732 
1733  const unsigned int maximalClusters = std::min(parameters.maximalNumberClustersPerLevel_, (unsigned int)(numberDescriptorsIndices + parameters.maximalDescriptorsPerLeaf_ - 1u) / parameters.maximalDescriptorsPerLeaf_);
1734 
1735  TDescriptors clusterCenters;
1736  clusterCenters.reserve(maximalClusters);
1737 
1738  clusterCenters.emplace_back(treeDescriptors[descriptorIndices[RandomI::random(randomGenerator, (unsigned int)(numberDescriptorsIndices) - 1u)]]);
1739 
1740  for (unsigned int nCluster = 1u; nCluster < maximalClusters; ++nCluster)
1741  {
1742  TDistance worstDistance = NumericT<TDistance>::minValue();
1743  unsigned int numberSameDistances = 0u;
1744 
1745  // now, we randomly select a descriptor with largest distance
1746 
1747  for (size_t nDescriptor = 0; nDescriptor < numberDescriptorsIndices; ++nDescriptor)
1748  {
1749  const Index32& descriptorIndex = descriptorIndices[nDescriptor];
1750 
1751  const TDescriptor& descriptor = treeDescriptors[descriptorIndex];
1752 
1753  TDistance localBestDistance = NumericT<TDistance>::maxValue();
1754 
1755  for (const TDescriptor& clusterCenter : clusterCenters)
1756  {
1757  const TDistance distance = tDistanceFunction(descriptor, clusterCenter);
1758 
1759  if (distance < localBestDistance)
1760  {
1761  localBestDistance = distance;
1762  }
1763  }
1764 
1765  if (localBestDistance > worstDistance)
1766  {
1767  worstDistance = localBestDistance;
1768 
1769  reusableIndices[0u] = descriptorIndex;
1770  numberSameDistances = 1u;
1771  }
1772  else if (localBestDistance == worstDistance)
1773  {
1774  reusableIndices[numberSameDistances++] = descriptorIndex;
1775  }
1776  }
1777 
1778  if (worstDistance == TDistance(0)) // other threshold
1779  {
1780  break;
1781  }
1782 
1783  if (numberSameDistances == 0u)
1784  {
1785  break;
1786  }
1787 
1788  const unsigned int randomIndex = RandomI::random(randomGenerator, numberSameDistances - 1u);
1789 
1790  const Index32& randomDescriptorIndex = reusableIndices[randomIndex];
1791 
1792  clusterCenters.emplace_back(treeDescriptors[randomDescriptorIndex]);
1793  }
1794 
1795  return clusterCenters;
1796 }
1797 
1798 template <typename TDescriptor, typename TDistance, TDistance(*tDistanceFunction)(const TDescriptor&, const TDescriptor&)>
1799 typename VocabularyTree<TDescriptor, TDistance, tDistanceFunction>::TDescriptors VocabularyTree<TDescriptor, TDistance, tDistanceFunction>::initialClustersPureRandom(const Parameters& parameters, const TDescriptor* treeDescriptors, Index32* descriptorIndices, const size_t numberDescriptorsIndices, RandomGenerator& randomGenerator) const
1800 {
1801  ocean_assert(parameters.isValid());
1802  ocean_assert(parameters.maximalNumberClustersPerLevel_ <= numberDescriptorsIndices);
1803  ocean_assert(treeDescriptors != nullptr && descriptorIndices != nullptr);
1804  ocean_assert(numberDescriptorsIndices >= 1);
1805 
1806  const unsigned int maximalClusters = std::min(parameters.maximalNumberClustersPerLevel_, (unsigned int)(numberDescriptorsIndices + parameters.maximalDescriptorsPerLeaf_ - 1u) / parameters.maximalDescriptorsPerLeaf_);
1807 
1808  // first, we select the cluster centers randomly
1809 
1810  UnorderedIndexSet32 initialCenterIndices;
1811  initialCenterIndices.reserve(maximalClusters);
1812 
1813  while ((unsigned int)(initialCenterIndices.size()) < maximalClusters)
1814  {
1815  initialCenterIndices.emplace(RandomI::random(randomGenerator, (unsigned int)(numberDescriptorsIndices) - 1u));
1816  }
1817 
1818  TDescriptors clusterCenters;
1819  clusterCenters.reserve(maximalClusters);
1820 
1821  for (const Index32& randomIndex : initialCenterIndices)
1822  {
1823  const Index32& descriptorIndex = descriptorIndices[randomIndex];
1824 
1825  clusterCenters.emplace_back(treeDescriptors[descriptorIndex]);
1826  }
1827 
1828  return clusterCenters;
1829 }
1830 
1831 template <typename TDescriptor, typename TDistance, TDistance(*tDistanceFunction)(const TDescriptor&, const TDescriptor&)>
1833 {
1834  if (this != &VocabularyTree)
1835  {
1836  nodeDescriptor_ = VocabularyTree.nodeDescriptor_;
1837  descriptorIndices_ = std::move(VocabularyTree.descriptorIndices_);
1838  childNodes_ = std::move(VocabularyTree.childNodes_);
1839  }
1840 
1841  return *this;
1842 }
1843 
1844 template <typename TDescriptor, typename TDistance, TDistance(*tDistanceFunction)(const TDescriptor&, const TDescriptor&)>
1845 template <unsigned int tSize>
1846 typename VocabularyTree<TDescriptor, TDistance, tDistanceFunction>::TDescriptors VocabularyTree<TDescriptor, TDistance, tDistanceFunction>::determineClustersMeanForBinaryDescriptor(const unsigned int numberClusters, const TDescriptor* treeDescriptors, const Index32* descriptorIndices, const Index32* clusterIndicesForDescriptors, const size_t numberDescriptorIndices, Worker* /*worker todo*/)
1847 {
1848  static_assert(tSize >= 1u && tSize % 8u == 0u, "Invalid descriptor size!");
1849 
1850 #ifndef OCEAN_DONT_USE_LOOKUP_TABLE_IN_VOCABULARY_TREE
1851  static const std::vector<uint8_t> lookup(generateBitSeparationLookup8());
1852 #endif
1853 
1854  constexpr unsigned int tBytes = tSize / 8u;
1855 
1856  ocean_assert(numberClusters >= 1u);
1857  ocean_assert(treeDescriptors != nullptr && descriptorIndices != nullptr);
1858  ocean_assert(numberDescriptorIndices >= 1u);
1859  ocean_assert(clusterIndicesForDescriptors != nullptr);
1860 
1861  Indices32 meanDescriptorsSum(numberClusters * tSize, 0u);
1862  Indices32 numberDescriptorsInClusters(numberClusters, 0u);
1863 
1864  for (size_t nDescriptor = 0; nDescriptor < numberDescriptorIndices; ++nDescriptor)
1865  {
1866  const Index32& descriptorIndex = descriptorIndices[nDescriptor];
1867 
1868  ocean_assert(clusterIndicesForDescriptors[descriptorIndex] < numberClusters);
1869 
1870  ++numberDescriptorsInClusters[clusterIndicesForDescriptors[descriptorIndex]];
1871  Index32* meanDescriptor = meanDescriptorsSum.data() + clusterIndicesForDescriptors[descriptorIndex] * tSize;
1872 
1873  const uint8_t* const descriptor = (const uint8_t*)(treeDescriptors + descriptorIndex);
1874 
1875  for (unsigned int nByte = 0u; nByte < tBytes; ++nByte)
1876  {
1877 #ifdef OCEAN_DONT_USE_LOOKUP_TABLE_IN_VOCABULARY_TREE
1878  for (unsigned int nBit = 0u; nBit < 8u; ++nBit)
1879  {
1880  if (descriptor[nByte] & (1u << nBit))
1881  {
1882  (*meanDescriptor)++;
1883  }
1884 
1885  ++meanDescriptor;
1886  }
1887 #else
1888  const uint8_t* lookupValues = lookup.data() + descriptor[nByte] * 8;
1889 
1890  for (unsigned int nBit = 0u; nBit < 8u; ++nBit)
1891  {
1892  *meanDescriptor++ += lookupValues[nBit];
1893  }
1894 #endif // OCEAN_DONT_USE_LOOKUP_TABLE_IN_VOCABULARY_TREE
1895  }
1896  }
1897 
1898  TDescriptors meanDescriptors(numberClusters);
1899 
1900  for (unsigned int nCluster = 0u; nCluster < numberClusters; ++nCluster)
1901  {
1902  const unsigned int* meanDescriptorSum = meanDescriptorsSum.data() + nCluster * tSize;
1903 
1904  uint8_t* meanDescriptor = (uint8_t*)(meanDescriptors.data() + nCluster);
1905 
1906  if (numberDescriptorsInClusters[nCluster] != 0u)
1907  {
1908  for (unsigned int nByte = 0u; nByte < tBytes; ++nByte)
1909  {
1910  uint8_t byte = 0u;
1911 
1912  for (unsigned int nBit = 0u; nBit < 8u; ++nBit)
1913  {
1914  const unsigned int meanBit = (*meanDescriptorSum + numberDescriptorsInClusters[nCluster] / 2u) / numberDescriptorsInClusters[nCluster];
1915  ocean_assert(meanBit == 0u || meanBit == 1u);
1916 
1917  byte = byte | uint8_t(meanBit << nBit);
1918 
1919  ++meanDescriptorSum;
1920  }
1921 
1922  meanDescriptor[nByte] = byte;
1923  }
1924  }
1925  else
1926  {
1927  // forcing the mean descriptor to be zero in case default constructor does not create a zero descriptor
1928  memset(meanDescriptor, 0, tBytes);
1929  }
1930  }
1931 
1932  return meanDescriptors;
1933 }
1934 
1935 template <typename TDescriptor, typename TDistance, TDistance(*tDistanceFunction)(const TDescriptor&, const TDescriptor&)>
1936 template <unsigned int tSize>
1937 typename VocabularyTree<TDescriptor, TDistance, tDistanceFunction>::TDescriptors VocabularyTree<TDescriptor, TDistance, tDistanceFunction>::determineClustersMeanForFloatDescriptor(const unsigned int numberClusters, const TDescriptor* treeDescriptors, const Index32* descriptorIndices, const Index32* clusterIndicesForDescriptors, const size_t numberDescriptorIndices, Worker* /*worker*/)
1938 {
1939  static_assert(tSize >= 1u, "Invalid descriptor size!");
1940 
1941  // **TODO** add multi-core implementation
1942 
1943  ocean_assert(numberClusters >= 1u);
1944  ocean_assert(treeDescriptors != nullptr && descriptorIndices != nullptr);
1945  ocean_assert(numberDescriptorIndices >= 1u);
1946  ocean_assert(clusterIndicesForDescriptors != nullptr);
1947 
1948  std::vector<float> meanDescriptorsSum(numberClusters * tSize, 0.0);
1949  Indices32 numberDescriptorsInClusters(numberClusters, 0u);
1950 
1951  for (size_t nDescriptor = 0; nDescriptor < numberDescriptorIndices; ++nDescriptor)
1952  {
1953  const Index32& descriptorIndex = descriptorIndices[nDescriptor];
1954 
1955  ocean_assert(clusterIndicesForDescriptors[descriptorIndex] < numberClusters);
1956 
1957  ++numberDescriptorsInClusters[clusterIndicesForDescriptors[descriptorIndex]];
1958  float* meanDescriptor = meanDescriptorsSum.data() + clusterIndicesForDescriptors[descriptorIndex] * tSize;
1959 
1960  const float* const descriptor = (const float*)(treeDescriptors + descriptorIndex);
1961 
1962  for (unsigned int nElement = 0u; nElement < tSize; ++nElement)
1963  {
1964  meanDescriptor[nElement] += descriptor[nElement];
1965  }
1966  }
1967 
1968  TDescriptors meanDescriptors(numberClusters);
1969 
1970  for (unsigned int nCluster = 0u; nCluster < numberClusters; ++nCluster)
1971  {
1972  const float* meanDescriptorSum = meanDescriptorsSum.data() + nCluster * tSize;
1973 
1974  float* meanDescriptor = (float*)(meanDescriptors.data() + nCluster);
1975 
1976  if (numberDescriptorsInClusters[nCluster] != 0u)
1977  {
1978  const float invDescriptorsInCluster = 1.0f / float(numberDescriptorsInClusters[nCluster]);
1979 
1980  for (unsigned int nElement = 0u; nElement < tSize; ++nElement)
1981  {
1982  meanDescriptor[nElement] = meanDescriptorSum[nElement] * invDescriptorsInCluster;
1983  }
1984  }
1985  else
1986  {
1987  memset(meanDescriptor, 0, sizeof(float) * tSize);
1988 
1989 #ifdef OCEAN_DEBUG
1990  for (unsigned int nElement = 0u; nElement < tSize; ++nElement)
1991  {
1992  ocean_assert(meanDescriptor[nElement] == 0.0f);
1993  }
1994 #endif
1995  }
1996  }
1997 
1998  return meanDescriptors;
1999 }
2000 
2001 template <typename TDescriptor, typename TDistance, TDistance(*tDistanceFunction)(const TDescriptor&, const TDescriptor&)>
2002 Indices32 VocabularyTree<TDescriptor, TDistance, tDistanceFunction>::assignDescriptorsToClusters(const TDescriptor* clusterCenters, const unsigned int numberClusters, const TDescriptor* treeDescriptors, const Index32* descriptorIndices, Index32* clusterIndicesForDescriptors, const size_t numberDescriptorIndices, TSumDistances* sumDistances, Worker* worker)
2003 {
2004  TSumDistances localSumDistances = TSumDistances(0);
2005  Indices32 clusterSizes(numberClusters, 0u);
2006 
2007  if (worker != nullptr && numberDescriptorIndices * numberClusters >= 50000)
2008  {
2009  Lock lock;
2010  worker->executeFunction(Worker::Function::createStatic(&VocabularyTree<TDescriptor, TDistance, tDistanceFunction>::assignDescriptorsToClustersSubset, clusterCenters, numberClusters, treeDescriptors, descriptorIndices, clusterIndicesForDescriptors, clusterSizes.data(), &localSumDistances, &lock, 0u, 0u), 0u, (unsigned int)(numberDescriptorIndices));
2011  }
2012  else
2013  {
2014  assignDescriptorsToClustersSubset(clusterCenters, numberClusters, treeDescriptors, descriptorIndices, clusterIndicesForDescriptors, clusterSizes.data(), &localSumDistances, nullptr, 0u, (unsigned int)(numberDescriptorIndices));
2015  }
2016 
2017  if (sumDistances != nullptr)
2018  {
2019  *sumDistances = localSumDistances;
2020  }
2021 
2022  return clusterSizes;
2023 }
2024 
2025 template <typename TDescriptor, typename TDistance, TDistance(*tDistanceFunction)(const TDescriptor&, const TDescriptor&)>
2026 void VocabularyTree<TDescriptor, TDistance, tDistanceFunction>::createChildNodesSubset(const unsigned int childNodeLevel, const Parameters* parameters, const TDescriptor* treeDescriptors, const TDescriptor* clusterCenters, const unsigned int* clusterSizes, const size_t numberClusters, Index32* reusableDescriptorIndicesInput, Index32* reusableDescriptorIndicesOutput, const size_t numberDescriptorsIndices, RandomGenerator* randomGenerator, Index32* reusableClusterIndicesForDescriptors, const ClustersMeanFunction* clustersMeanFunction, const unsigned int subsetFirstCluster, const unsigned int subsetNumberClusters)
2027 {
2028  ocean_assert(childNodeLevel >= 1u);
2029  ocean_assert(parameters != nullptr && parameters->isValid());
2030  ocean_assert(clusterCenters != nullptr && clusterSizes != nullptr);
2031  ocean_assert(numberClusters >= 1u && subsetNumberClusters >= 1);
2032  ocean_assert(reusableDescriptorIndicesInput != nullptr && reusableDescriptorIndicesOutput != nullptr);
2033 
2034  unsigned int descriptorClusterOffset = 0u;
2035 
2036  for (unsigned int nCluster = 0u; nCluster < subsetFirstCluster; ++nCluster)
2037  {
2038  descriptorClusterOffset += clusterSizes[nCluster];
2039  }
2040 
2041  for (unsigned int nCluster = subsetFirstCluster; nCluster < subsetFirstCluster + subsetNumberClusters; ++nCluster)
2042  {
2043  ocean_assert(nCluster < childNodes_.size());
2044 
2045  const size_t subsetNumberDescriptorIndices = clusterSizes[nCluster];
2046 
2047  if (subsetNumberDescriptorIndices > 0)
2048  {
2049  const TDescriptor& nodeDescriptor = clusterCenters[nCluster];
2050 
2051  ocean_assert_and_suppress_unused(descriptorClusterOffset + subsetNumberDescriptorIndices <= numberDescriptorsIndices, numberDescriptorsIndices);
2052 
2053  Index32* const subsetReusableDescriptorIndicesInput = reusableDescriptorIndicesInput + descriptorClusterOffset;
2054  Index32* const subsetReusableDescriptorIndicesOutput = reusableDescriptorIndicesOutput + descriptorClusterOffset;
2055 
2056  Node* childNode = nullptr;
2057 
2058  if (numberClusters == 1 || subsetNumberDescriptorIndices <= parameters->maximalDescriptorsPerLeaf_ || childNodeLevel + 1u >= parameters->maximalLevels_)
2059  {
2060  childNode = new Node(childNodeLevel, nodeDescriptor, subsetReusableDescriptorIndicesInput, subsetNumberDescriptorIndices);
2061  }
2062  else
2063  {
2064  constexpr Worker* noWorker = nullptr; // we apply a worker in the lowest level only
2065 
2066  childNode = new Node(childNodeLevel, nodeDescriptor, *parameters, treeDescriptors, subsetReusableDescriptorIndicesInput, subsetReusableDescriptorIndicesOutput, subsetNumberDescriptorIndices, *randomGenerator, reusableClusterIndicesForDescriptors, *clustersMeanFunction, noWorker);
2067  }
2068 
2069  ocean_assert(childNodes_[nCluster] == nullptr);
2070  childNodes_[nCluster] = childNode;
2071 
2072  descriptorClusterOffset += clusterSizes[nCluster];
2073  }
2074  }
2075 }
2076 
2077 template <typename TDescriptor, typename TDistance, TDistance(*tDistanceFunction)(const TDescriptor&, const TDescriptor&)>
2078 void VocabularyTree<TDescriptor, TDistance, tDistanceFunction>::assignDescriptorsToClustersSubset(const TDescriptor* clusterCenters, const unsigned int numberClusters, const TDescriptor* treeDescriptors, const Index32* descriptorIndices, Index32* clusterIndicesForDescriptors, Index32* clusterSizes, TSumDistances* sumDistances, Lock* lock, const unsigned int firstDescriptorIndex, const unsigned int numberDescriptorIndices)
2079 {
2080  ocean_assert(clusterCenters != nullptr && numberClusters >= 1u);
2081  ocean_assert(treeDescriptors != nullptr && descriptorIndices != nullptr);
2082  ocean_assert(clusterIndicesForDescriptors != nullptr);
2083  ocean_assert(clusterSizes != nullptr);
2084  ocean_assert(numberDescriptorIndices >= 1u);
2085 
2086  Indices32 localClusterSizes(numberClusters, 0u);
2087  TSumDistances localSumDistances = TSumDistances(0);
2088 
2089  TDistance bestDistance;
2090  unsigned int bestCluster;
2091 
2092  for (unsigned int nDescriptor = firstDescriptorIndex; nDescriptor < firstDescriptorIndex + numberDescriptorIndices; ++nDescriptor)
2093  {
2094  const Index32& descriptorIndex = descriptorIndices[nDescriptor];
2095  const TDescriptor& descriptor = treeDescriptors[descriptorIndex];
2096 
2097  bestDistance = NumericT<TDistance>::maxValue();
2098  bestCluster = (unsigned int)(-1);
2099 
2100  for (unsigned int nCluster = 0u; nCluster < numberClusters; ++nCluster)
2101  {
2102  const TDistance distance = tDistanceFunction(clusterCenters[nCluster], descriptor);
2103 
2104  if (distance < bestDistance)
2105  {
2106  bestDistance = distance;
2107  bestCluster = nCluster;
2108  }
2109  }
2110 
2111  ocean_assert(bestCluster < numberClusters);
2112 
2113  clusterIndicesForDescriptors[descriptorIndex] = bestCluster;
2114 
2115  ++localClusterSizes[bestCluster];
2116 
2117  localSumDistances += bestDistance;
2118  }
2119 
2120  const OptionalScopedLock scopedLock(lock);
2121 
2122  for (unsigned int n = 0u; n < numberClusters; ++n)
2123  {
2124  clusterSizes[n] += localClusterSizes[n];
2125  }
2126 
2127  if (sumDistances)
2128  {
2129  *sumDistances += localSumDistances;
2130  }
2131 }
2132 
2133 template <typename TDescriptor, typename TDistance, TDistance(*tDistanceFunction)(const TDescriptor&, const TDescriptor&)>
2134 template <VocabularyStructure::MatchingMode tMatchingMode>
2135 void VocabularyTree<TDescriptor, TDistance, tDistanceFunction>::matchDescriptorsSubset(const TDescriptor* candidateDescriptors, const TDescriptor* queryDescriptors, const TDistance maximalDistance, Matches* matches, Lock* lock, const unsigned int firstQueryDescriptor, const unsigned int numberQueryDescriptors) const
2136 {
2137  ocean_assert(candidateDescriptors != nullptr);
2138  ocean_assert(matches != nullptr);
2139  ocean_assert(numberQueryDescriptors >= 1u);
2140 
2141  ReusableData reusableData;
2142 
2143  Matches localMatches;
2144  localMatches.reserve(numberQueryDescriptors);
2145 
2146  for (unsigned int nQuery = firstQueryDescriptor; nQuery < firstQueryDescriptor + numberQueryDescriptors; ++nQuery)
2147  {
2148  TDistance distance = NumericT<TDistance>::maxValue();
2149  const Index32 matchingCandidateIndex = matchDescriptor<tMatchingMode>(candidateDescriptors, queryDescriptors[nQuery], &distance, reusableData);
2150 
2151  if (distance <= maximalDistance)
2152  {
2153  ocean_assert(matchingCandidateIndex != invalidMatchIndex());
2154 
2155  localMatches.emplace_back(matchingCandidateIndex, nQuery, distance);
2156  }
2157  }
2158 
2159  const OptionalScopedLock scopedLock(lock);
2160 
2161  matches->insert(matches->cend(), localMatches.cbegin(), localMatches.cend());
2162 }
2163 
2164 template <typename TDescriptor, typename TDistance, TDistance(*tDistanceFunction)(const TDescriptor&, const TDescriptor&)>
2165 template <typename TMultiDescriptor, const TDescriptor*(*tMultiDescriptorFunction)(const TMultiDescriptor&, const size_t), VocabularyStructure::MatchingMode tMatchingMode>
2166 void VocabularyTree<TDescriptor, TDistance, tDistanceFunction>::matchMultiDescriptorsSubset(const TDescriptor* candidateDescriptors, const TMultiDescriptor* queryMultiDescriptors, const TDistance maximalDistance, Matches* matches, Lock* lock, const unsigned int firstQueryMultiDescriptor, const unsigned int numberQueryMultiDescriptors) const
2167 {
2168  ocean_assert(candidateDescriptors != nullptr);
2169  ocean_assert(matches != nullptr);
2170  ocean_assert(numberQueryMultiDescriptors >= 1u);
2171 
2172  ReusableData reusableData;
2173 
2174  Matches localMatches;
2175  localMatches.reserve(numberQueryMultiDescriptors);
2176 
2177  for (unsigned int nQuery = firstQueryMultiDescriptor; nQuery < firstQueryMultiDescriptor + numberQueryMultiDescriptors; ++nQuery)
2178  {
2179  TDistance distance = NumericT<TDistance>::maxValue();
2180  const Index32 matchingCandidateIndex = matchMultiDescriptor<TMultiDescriptor, tMultiDescriptorFunction, tMatchingMode>(candidateDescriptors, queryMultiDescriptors[nQuery], &distance, reusableData);
2181 
2182  if (distance <= maximalDistance)
2183  {
2184  ocean_assert(matchingCandidateIndex != invalidMatchIndex());
2185 
2186  localMatches.emplace_back(matchingCandidateIndex, nQuery, distance);
2187  }
2188  }
2189 
2190  const OptionalScopedLock scopedLock(lock);
2191 
2192  matches->insert(matches->cend(), localMatches.cbegin(), localMatches.cend());
2193 }
2194 
2195 template <typename TDescriptor, typename TDistance, TDistance(*tDistanceFunction)(const TDescriptor&, const TDescriptor&)>
2196 template <typename TMultiDescriptorGroup, typename TMultiDescriptor, const TMultiDescriptor*(*tMultiDescriptorGroupFunction)(const TMultiDescriptorGroup&, const size_t), const TDescriptor*(*tMultiDescriptorFunction)(const TMultiDescriptor&, const size_t), VocabularyStructure::MatchingMode tMatchingMode>
2197 void VocabularyTree<TDescriptor, TDistance, tDistanceFunction>::matchMultiDescriptorGroupsSubset(const TDescriptor* candidateDescriptors, const TMultiDescriptorGroup* queryMultiDescriptorGroups, const TDistance maximalDistance, Matches* matches, Lock* lock, const unsigned int firstQueryMultiDescriptorGroup, const unsigned int numberQueryMultiDescriptorGroups) const
2198 {
2199  ocean_assert(candidateDescriptors != nullptr);
2200  ocean_assert(matches != nullptr);
2201  ocean_assert(numberQueryMultiDescriptorGroups >= 1u);
2202 
2203  ReusableData reusableData;
2204 
2205  Matches localMatches;
2206  localMatches.reserve(numberQueryMultiDescriptorGroups);
2207 
2208  for (unsigned int nQuery = firstQueryMultiDescriptorGroup; nQuery < firstQueryMultiDescriptorGroup + numberQueryMultiDescriptorGroups; ++nQuery)
2209  {
2210  TDistance distance = NumericT<TDistance>::maxValue();
2211  const Index32 matchingCandidateIndex = matchMultiDescriptorGroup<TMultiDescriptorGroup, TMultiDescriptor, tMultiDescriptorGroupFunction, tMultiDescriptorFunction, tMatchingMode>(candidateDescriptors, queryMultiDescriptorGroups[nQuery], &distance, reusableData);
2212 
2213  if (distance <= maximalDistance)
2214  {
2215  ocean_assert(matchingCandidateIndex != invalidMatchIndex());
2216 
2217  localMatches.emplace_back(matchingCandidateIndex, nQuery, distance);
2218  }
2219  }
2220 
2221  const OptionalScopedLock scopedLock(lock);
2222 
2223  matches->insert(matches->cend(), localMatches.cbegin(), localMatches.cend());
2224 }
2225 
2226 template <typename TDescriptor, typename TDistance, TDistance(*tDistanceFunction)(const TDescriptor&, const TDescriptor&)>
2227 VocabularyForest<TDescriptor, TDistance, tDistanceFunction>::VocabularyForest(const size_t numberTrees, const TDescriptor* treeDescriptors, const size_t numberDescriptors, const ClustersMeanFunction& clustersMeanFunction, const Parameters& parameters, Worker* worker, RandomGenerator* randomGenerator)
2228 {
2229  ocean_assert(numberTrees >= 1u);
2230 
2231  for (size_t n = 0; n < numberTrees; ++n)
2232  {
2233  vocabularyTrees_.emplace_back(treeDescriptors, numberDescriptors, clustersMeanFunction, parameters, worker, randomGenerator);
2234  }
2235 }
2236 
2237 template <typename TDescriptor, typename TDistance, TDistance(*tDistanceFunction)(const TDescriptor&, const TDescriptor&)>
2238 template <VocabularyStructure::MatchingMode tMatchingMode>
2239 Index32 VocabularyForest<TDescriptor, TDistance, tDistanceFunction>::matchDescriptor(const TDescriptor* candidateDescriptors, const TDescriptor& queryDescriptor, TDistance* distance, const ReusableData& reusableData) const
2240 {
2241  Index32 bestCandidateDescriptorIndex = invalidMatchIndex();
2242  TDistance bestDistance = NumericT<TDistance>::maxValue();
2243 
2244  for (const VocabularyTree<TDescriptor, TDistance, tDistanceFunction>& vocabularyTree : vocabularyTrees_)
2245  {
2246  TDistance candidateDistance;
2247  const Index32 candidateDescriptorIndex = vocabularyTree.template matchDescriptor<tMatchingMode>(candidateDescriptors, queryDescriptor, &candidateDistance, reusableData);
2248 
2249  if (candidateDistance < bestDistance)
2250  {
2251  bestDistance = candidateDistance;
2252  bestCandidateDescriptorIndex = candidateDescriptorIndex;
2253  }
2254  }
2255 
2256  if (distance != nullptr)
2257  {
2258  *distance = bestDistance;
2259  }
2260 
2261  return bestCandidateDescriptorIndex;
2262 }
2263 
2264 template <typename TDescriptor, typename TDistance, TDistance(*tDistanceFunction)(const TDescriptor&, const TDescriptor&)>
2265 template <VocabularyStructure::MatchingMode tMatchingMode>
2266 Index32 VocabularyForest<TDescriptor, TDistance, tDistanceFunction>::matchMultiDescriptor(const TDescriptor* candidateDescriptors, const TDescriptor* queryMultiDescriptor, const size_t numberQuerySingleDescriptors, TDistance* distance, const ReusableData& reusableData) const
2267 {
2268  Index32 bestCandidateDescriptorIndex = invalidMatchIndex();
2269  TDistance bestDistance = NumericT<TDistance>::maxValue();
2270 
2271  for (const TVocabularyTree& vocabularyTree : vocabularyTrees_)
2272  {
2273  TDistance candidateDistance;
2274  const Index32 candidateDescriptorIndex = vocabularyTree.template matchMultiDescriptor<tMatchingMode>(candidateDescriptors, queryMultiDescriptor, numberQuerySingleDescriptors, &candidateDistance, reusableData);
2275 
2276  if (candidateDistance < bestDistance)
2277  {
2278  bestDistance = candidateDistance;
2279  bestCandidateDescriptorIndex = candidateDescriptorIndex;
2280  }
2281  }
2282 
2283  if (distance != nullptr)
2284  {
2285  *distance = bestDistance;
2286  }
2287 
2288  return bestCandidateDescriptorIndex;
2289 }
2290 
2291 template <typename TDescriptor, typename TDistance, TDistance(*tDistanceFunction)(const TDescriptor&, const TDescriptor&)>
2292 template <typename TMultiDescriptor, const TDescriptor*(*tMultiDescriptorFunction)(const TMultiDescriptor&, const size_t), VocabularyStructure::MatchingMode tMatchingMode>
2293 Index32 VocabularyForest<TDescriptor, TDistance, tDistanceFunction>::matchMultiDescriptor(const TDescriptor* candidateDescriptors, const TMultiDescriptor& queryMultiDescriptor, TDistance* distance, const ReusableData& reusableData) const
2294 {
2295  static_assert(tMultiDescriptorFunction != nullptr, "Invalid function!");
2296 
2297  Index32 bestCandidateDescriptorIndex = invalidMatchIndex();
2298  TDistance bestDistance = NumericT<TDistance>::maxValue();
2299 
2300  for (const TVocabularyTree& vocabularyTree : vocabularyTrees_)
2301  {
2302  TDistance candidateDistance;
2303  const Index32 candidateDescriptorIndex = vocabularyTree.template matchMultiDescriptor<TMultiDescriptor, tMultiDescriptorFunction, tMatchingMode>(candidateDescriptors, queryMultiDescriptor, &candidateDistance, reusableData);
2304 
2305  if (candidateDistance < bestDistance)
2306  {
2307  bestDistance = candidateDistance;
2308  bestCandidateDescriptorIndex = candidateDescriptorIndex;
2309  }
2310  }
2311 
2312  if (distance != nullptr)
2313  {
2314  *distance = bestDistance;
2315  }
2316 
2317  return bestCandidateDescriptorIndex;
2318 }
2319 
2320 template <typename TDescriptor, typename TDistance, TDistance(*tDistanceFunction)(const TDescriptor&, const TDescriptor&)>
2321 template <typename TMultiDescriptorGroup, typename TMultiDescriptor, const TMultiDescriptor*(*tMultiDescriptorGroupFunction)(const TMultiDescriptorGroup&, const size_t), const TDescriptor*(*tMultiDescriptorFunction)(const TMultiDescriptor&, const size_t), VocabularyStructure::MatchingMode tMatchingMode>
2322 Index32 VocabularyForest<TDescriptor, TDistance, tDistanceFunction>::matchMultiDescriptorGroup(const TDescriptor* candidateDescriptors, const TMultiDescriptorGroup& queryMultiDescriptorGroup, TDistance* distance, const ReusableData& reusableData) const
2323 {
2324  static_assert(tMultiDescriptorGroupFunction != nullptr, "Invalid function!");
2325  static_assert(tMultiDescriptorFunction != nullptr, "Invalid function!");
2326 
2327  Index32 bestCandidateDescriptorIndex = invalidMatchIndex();
2328  TDistance bestDistance = NumericT<TDistance>::maxValue();
2329 
2330  for (const TVocabularyTree& vocabularyTree : vocabularyTrees_)
2331  {
2332  TDistance candidateDistance;
2333  const Index32 candidateDescriptorIndex = vocabularyTree.template matchMultiDescriptorGroup<TMultiDescriptorGroup, TMultiDescriptor, tMultiDescriptorGroupFunction, tMultiDescriptorFunction, tMatchingMode>(candidateDescriptors, queryMultiDescriptorGroup, &candidateDistance, reusableData);
2334 
2335  if (candidateDistance < bestDistance)
2336  {
2337  bestDistance = candidateDistance;
2338  bestCandidateDescriptorIndex = candidateDescriptorIndex;
2339  }
2340  }
2341 
2342  if (distance != nullptr)
2343  {
2344  *distance = bestDistance;
2345  }
2346 
2347  return bestCandidateDescriptorIndex;
2348 }
2349 
2350 template <typename TDescriptor, typename TDistance, TDistance(*tDistanceFunction)(const TDescriptor&, const TDescriptor&)>
2351 template <VocabularyStructure::MatchingMode tMatchingMode>
2352 void VocabularyForest<TDescriptor, TDistance, tDistanceFunction>::matchDescriptors(const TDescriptor* candidateDescriptors, const TDescriptor* queryDescriptors, const size_t numberQueryDescriptors, const TDistance maximalDistance, Matches& matches, Worker* worker) const
2353 {
2354  matches.clear();
2355 
2356  ocean_assert(candidateDescriptors != nullptr);
2357  if (numberQueryDescriptors == 0)
2358  {
2359  return;
2360  }
2361 
2362  ocean_assert(queryDescriptors != nullptr);
2363 
2364  if (worker && numberQueryDescriptors >= 50)
2365  {
2366  Lock lock;
2367  worker->executeFunction(Worker::Function::create(*this, &VocabularyForest<TDescriptor, TDistance, tDistanceFunction>::matchDescriptorsSubset<tMatchingMode>, candidateDescriptors, queryDescriptors, maximalDistance, &matches, &lock, 0u, 0u), 0u, (unsigned int)(numberQueryDescriptors), 5u, 6u, 50u);
2368  }
2369  else
2370  {
2371  matchDescriptorsSubset<tMatchingMode>(candidateDescriptors, queryDescriptors, maximalDistance, &matches, nullptr, 0u, (unsigned int)(numberQueryDescriptors));
2372  }
2373 }
2374 
2375 template <typename TDescriptor, typename TDistance, TDistance(*tDistanceFunction)(const TDescriptor&, const TDescriptor&)>
2376 template <typename TMultiDescriptor, const TDescriptor*(*tMultiDescriptorFunction)(const TMultiDescriptor&, const size_t), VocabularyStructure::MatchingMode tMatchingMode>
2377 void VocabularyForest<TDescriptor, TDistance, tDistanceFunction>::matchMultiDescriptors(const TDescriptor* candidateDescriptors, const TMultiDescriptor* queryMultiDescriptors, const size_t numberQueryMultiDescriptors, const TDistance maximalDistance, Matches& matches, Worker* worker) const
2378 {
2379  static_assert(tMultiDescriptorFunction != nullptr, "Invalid function!");
2380 
2381  matches.clear();
2382 
2383  ocean_assert(candidateDescriptors != nullptr);
2384  if (numberQueryMultiDescriptors == 0)
2385  {
2386  return;
2387  }
2388 
2389  ocean_assert(queryMultiDescriptors != nullptr);
2390 
2391  if (worker && numberQueryMultiDescriptors >= 50)
2392  {
2393  Lock lock;
2394  worker->executeFunction(Worker::Function::create(*this, &VocabularyForest<TDescriptor, TDistance, tDistanceFunction>::matchMultiDescriptorsSubset<TMultiDescriptor, tMultiDescriptorFunction, tMatchingMode>, candidateDescriptors, queryMultiDescriptors, maximalDistance, &matches, &lock, 0u, 0u), 0u, (unsigned int)(numberQueryMultiDescriptors), 5u, 6u, 50u);
2395  }
2396  else
2397  {
2398  matchMultiDescriptorsSubset<TMultiDescriptor, tMultiDescriptorFunction, tMatchingMode>(candidateDescriptors, queryMultiDescriptors, maximalDistance, &matches, nullptr, 0u, (unsigned int)(numberQueryMultiDescriptors));
2399  }
2400 }
2401 
2402 template <typename TDescriptor, typename TDistance, TDistance(*tDistanceFunction)(const TDescriptor&, const TDescriptor&)>
2403 template <typename TMultiDescriptorGroup, typename TMultiDescriptor, const TMultiDescriptor*(*tMultiDescriptorGroupFunction)(const TMultiDescriptorGroup&, const size_t), const TDescriptor*(*tMultiDescriptorFunction)(const TMultiDescriptor&, const size_t), VocabularyStructure::MatchingMode tMatchingMode>
2404 void VocabularyForest<TDescriptor, TDistance, tDistanceFunction>::matchMultiDescriptorGroups(const TDescriptor* candidateDescriptors, const TMultiDescriptorGroup* queryMultiDescriptorGroups, const size_t numberQueryMultiDescriptorGroups, const TDistance maximalDistance, Matches& matches, Worker* worker) const
2405 {
2406  static_assert(tMultiDescriptorGroupFunction != nullptr, "Invalid function!");
2407  static_assert(tMultiDescriptorFunction != nullptr, "Invalid function!");
2408 
2409  matches.clear();
2410 
2411  ocean_assert(candidateDescriptors != nullptr);
2412  if (numberQueryMultiDescriptorGroups == 0)
2413  {
2414  return;
2415  }
2416 
2417  ocean_assert(queryMultiDescriptorGroups != nullptr);
2418 
2419  if (worker && numberQueryMultiDescriptorGroups >= 50)
2420  {
2421  Lock lock;
2422  worker->executeFunction(Worker::Function::create(*this, &VocabularyForest<TDescriptor, TDistance, tDistanceFunction>::matchMultiDescriptorGroupsSubset<TMultiDescriptorGroup, TMultiDescriptor, tMultiDescriptorGroupFunction, tMultiDescriptorFunction, tMatchingMode>, candidateDescriptors, queryMultiDescriptorGroups, maximalDistance, &matches, &lock, 0u, 0u), 0u, (unsigned int)(numberQueryMultiDescriptorGroups), 5u, 6u, 50u);
2423  }
2424  else
2425  {
2426  matchMultiDescriptorGroupsSubset<TMultiDescriptorGroup, TMultiDescriptor, tMultiDescriptorGroupFunction, tMultiDescriptorFunction, tMatchingMode>(candidateDescriptors, queryMultiDescriptorGroups, maximalDistance, &matches, nullptr, 0u, (unsigned int)(numberQueryMultiDescriptorGroups));
2427  }
2428 }
2429 
2430 template <typename TDescriptor, typename TDistance, TDistance(*tDistanceFunction)(const TDescriptor&, const TDescriptor&)>
2431 template <VocabularyStructure::MatchingMode tMatchingMode>
2432 void VocabularyForest<TDescriptor, TDistance, tDistanceFunction>::matchDescriptorsSubset(const TDescriptor* candidateDescriptors, const TDescriptor* queryDescriptors, const TDistance maximalDistance, Matches* matches, Lock* lock, const unsigned int firstQueryDescriptor, const unsigned int numberQueryDescriptors) const
2433 {
2434  ocean_assert(candidateDescriptors != nullptr);
2435  ocean_assert(matches != nullptr);
2436  ocean_assert(numberQueryDescriptors >= 1u);
2437 
2438  ReusableData reusableData;
2439 
2440  Matches localMatches;
2441  localMatches.reserve(numberQueryDescriptors);
2442 
2443  for (unsigned int nQuery = firstQueryDescriptor; nQuery < firstQueryDescriptor + numberQueryDescriptors; ++nQuery)
2444  {
2445  TDistance distance = NumericT<TDistance>::maxValue();
2446  const Index32 matchingCandidateIndex = matchDescriptor<tMatchingMode>(candidateDescriptors, queryDescriptors[nQuery], &distance, reusableData);
2447 
2448  if (distance <= maximalDistance)
2449  {
2450  ocean_assert(matchingCandidateIndex != invalidMatchIndex());
2451 
2452  localMatches.emplace_back(matchingCandidateIndex, nQuery, distance);
2453  }
2454  }
2455 
2456  const OptionalScopedLock scopedLock(lock);
2457 
2458  matches->insert(matches->cend(), localMatches.cbegin(), localMatches.cend());
2459 }
2460 
2461 template <typename TDescriptor, typename TDistance, TDistance(*tDistanceFunction)(const TDescriptor&, const TDescriptor&)>
2462 template <typename TMultiDescriptor, const TDescriptor*(*tMultiDescriptorFunction)(const TMultiDescriptor&, const size_t), VocabularyStructure::MatchingMode tMatchingMode>
2463 void VocabularyForest<TDescriptor, TDistance, tDistanceFunction>::matchMultiDescriptorsSubset(const TDescriptor* candidateDescriptors, const TMultiDescriptor* queryMultiDescriptors, const TDistance maximalDistance, Matches* matches, Lock* lock, const unsigned int firstQueryMultiDescriptor, const unsigned int numberQueryMultiDescriptors) const
2464 {
2465  ocean_assert(candidateDescriptors != nullptr);
2466  ocean_assert(matches != nullptr);
2467  ocean_assert(numberQueryMultiDescriptors >= 1u);
2468 
2469  ReusableData reusableData;
2470 
2471  Matches localMatches;
2472  localMatches.reserve(numberQueryMultiDescriptors);
2473 
2474  for (unsigned int nQuery = firstQueryMultiDescriptor; nQuery < firstQueryMultiDescriptor + numberQueryMultiDescriptors; ++nQuery)
2475  {
2476  TDistance distance = NumericT<TDistance>::maxValue();
2477  const Index32 matchingCandidateIndex = matchMultiDescriptor<TMultiDescriptor, tMultiDescriptorFunction, tMatchingMode>(candidateDescriptors, queryMultiDescriptors[nQuery], &distance, reusableData);
2478 
2479  if (distance <= maximalDistance)
2480  {
2481  ocean_assert(matchingCandidateIndex != invalidMatchIndex());
2482 
2483  localMatches.emplace_back(matchingCandidateIndex, nQuery, distance);
2484  }
2485  }
2486 
2487  const OptionalScopedLock scopedLock(lock);
2488 
2489  matches->insert(matches->cend(), localMatches.cbegin(), localMatches.cend());
2490 }
2491 
2492 template <typename TDescriptor, typename TDistance, TDistance(*tDistanceFunction)(const TDescriptor&, const TDescriptor&)>
2493 template <typename TMultiDescriptorGroup, typename TMultiDescriptor, const TMultiDescriptor*(*tMultiDescriptorGroupFunction)(const TMultiDescriptorGroup&, const size_t), const TDescriptor*(*tMultiDescriptorFunction)(const TMultiDescriptor&, const size_t), VocabularyStructure::MatchingMode tMatchingMode>
2494 void VocabularyForest<TDescriptor, TDistance, tDistanceFunction>::matchMultiDescriptorGroupsSubset(const TDescriptor* candidateDescriptors, const TMultiDescriptorGroup* queryMultiDescriptorGroups, const TDistance maximalDistance, Matches* matches, Lock* lock, const unsigned int firstQueryMultiDescriptorGroup, const unsigned int numberQueryMultiDescriptorGroups) const
2495 {
2496  ocean_assert(candidateDescriptors != nullptr);
2497  ocean_assert(matches != nullptr);
2498  ocean_assert(numberQueryMultiDescriptorGroups >= 1u);
2499 
2500  ReusableData reusableData;
2501 
2502  Matches localMatches;
2503  localMatches.reserve(numberQueryMultiDescriptorGroups);
2504 
2505  for (unsigned int nQuery = firstQueryMultiDescriptorGroup; nQuery < firstQueryMultiDescriptorGroup + numberQueryMultiDescriptorGroups; ++nQuery)
2506  {
2507  TDistance distance = NumericT<TDistance>::maxValue();
2508  const Index32 matchingCandidateIndex = matchMultiDescriptorGroup<TMultiDescriptorGroup, TMultiDescriptor, tMultiDescriptorGroupFunction, tMultiDescriptorFunction, tMatchingMode>(candidateDescriptors, queryMultiDescriptorGroups[nQuery], &distance, reusableData);
2509 
2510  if (distance <= maximalDistance)
2511  {
2512  ocean_assert(matchingCandidateIndex != invalidMatchIndex());
2513 
2514  localMatches.emplace_back(matchingCandidateIndex, nQuery, distance);
2515  }
2516  }
2517 
2518  const OptionalScopedLock scopedLock(lock);
2519 
2520  matches->insert(matches->cend(), localMatches.cbegin(), localMatches.cend());
2521 }
2522 
2523 }
2524 
2525 }
2526 
2527 #endif // META_OCEAN_TRACKING_VOCABULAR_TREE_H
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
static Caller< void > create(CT &object, typename MemberFunctionPointerMaker< CT, 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 member function with no function parameter.
Definition: Caller.h:3023
This class implements a recursive lock object.
Definition: Lock.h:31
T TypePerformance
Definition of the data type for the next larger data type regarding performance.
Definition: DataType.h:261
This class provides basic numeric functionalities.
Definition: Numeric.h:57
static constexpr T minValue()
Returns the min scalar value.
Definition: Numeric.h:3250
static constexpr T maxValue()
Returns the max scalar value.
Definition: Numeric.h:3244
This class implements an optional recursive scoped lock object locking the lock object only if it's d...
Definition: Lock.h:325
This class implements a generator for random numbers.
Definition: RandomGenerator.h:42
static unsigned int random(const unsigned int maxValue)
Returns one random integer value with specified maximum value.
This class implements a Vocabulary Forest holding several Vocabulary Trees.
Definition: VocabularyTree.h:766
Index32 matchMultiDescriptor(const TDescriptor *candidateDescriptors, const TMultiDescriptor &queryMultiDescriptor, TDistance *distance=nullptr, const ReusableData &reusableData=ReusableData()) const
Matches a query multi-descriptor with all candidate descriptors in this forest.
Definition: VocabularyTree.h:2293
VocabularyForest(const size_t numberTrees, const TDescriptor *treeDescriptors, const size_t numberTreeDescriptors, const ClustersMeanFunction &clustersMeanFunction, const Parameters &parameters=Parameters(), Worker *worker=nullptr, RandomGenerator *randomGenerator=nullptr)
Creates a new forest with several trees for given descriptors.
Definition: VocabularyTree.h:2227
typename TVocabularyTree::ReusableData ReusableData
Re-definition of the ReusableData object.
Definition: VocabularyTree.h:834
const TDescriptor *(*)(const TMultiDescriptor &, const size_t) MultiDescriptorFunction
Definition of a function pointer to a function allowing to return individual descriptors from a multi...
Definition: VocabularyTree.h:821
std::vector< TVocabularyTree > TVocabularyTrees
Definition of a vector holding VocabularyTree objects.
Definition: VocabularyTree.h:841
TDescriptors(*)(const unsigned int numberClusters, const TDescriptor *treeDescriptors, const Index32 *descriptorIndices, const Index32 *clusterIndicesForDescriptors, const size_t numberDescriptorIndices, Worker *worker) ClustersMeanFunction
Definition of a function pointer allowing to determine the mean descriptors for individual clusters.
Definition: VocabularyTree.h:813
TVocabularyTrees vocabularyTrees_
The trees of this forest.
Definition: VocabularyTree.h:1022
TDistance Distance
The distance data type of this forest.
Definition: VocabularyTree.h:777
Index32 matchMultiDescriptorGroup(const TDescriptor *candidateDescriptors, const TMultiDescriptorGroup &queryMultiDescriptorGroup, TDistance *distance=nullptr, const ReusableData &reusableData=ReusableData()) const
Matches a query group of multi-descriptors with all candidate descriptors in this forest.
Definition: VocabularyTree.h:2322
static constexpr TDistance(* distanceFunction)(const TDescriptor &, const TDescriptor &)
The pointer to the function determining the distance between two descriptors of this forest.
Definition: VocabularyTree.h:782
Index32 matchDescriptor(const TDescriptor *candidateDescriptors, const TDescriptor &queryDescriptor, TDistance *distance=nullptr, const ReusableData &reusableData=ReusableData()) const
Matches a query descriptor with all candidate descriptors in this forest.
Definition: VocabularyTree.h:2239
VocabularyForest()=default
Creates a new empty forest without trees.
void matchMultiDescriptorGroupsSubset(const TDescriptor *candidateDescriptors, const TMultiDescriptorGroup *queryMultiDescriptorGroups, const TDistance maximalDistance, Matches *matches, Lock *lock, const unsigned int firstQueryMultiDescriptorGroup, const unsigned int numberQueryMultiDescriptorGroups) const
Matches a subset of several query groups of multi-descriptors with all candidate descriptors in this ...
Definition: VocabularyTree.h:2494
std::vector< TDistance > TDistances
Definition of a vector holding distances.
Definition: VocabularyTree.h:792
Match< TDistance > Match
Definition of a Match object using the distance data type of this tree.
Definition: VocabularyTree.h:802
void matchDescriptorsSubset(const TDescriptor *candidateDescriptors, const TDescriptor *queryDescriptors, const TDistance maximalDistance, Matches *matches, Lock *lock, const unsigned int firstQueryDescriptor, const unsigned int numberQueryDescriptors) const
Matches a subset of several query descriptors with all forest candidate descriptors.
Definition: VocabularyTree.h:2432
Index32 matchMultiDescriptor(const TDescriptor *candidateDescriptors, const TDescriptor *queryMultiDescriptor, const size_t numberQuerySingleDescriptors, TDistance *distance=nullptr, const ReusableData &reusableData=ReusableData()) const
Matches a query multi-descriptor with all candidate descriptors in this forest.
Definition: VocabularyTree.h:2266
void matchMultiDescriptorGroups(const TDescriptor *candidateDescriptors, const TMultiDescriptorGroup *queryMultiDescriptorGroups, const size_t numberQueryMultiDescriptorGroups, const TDistance maximalDistance, Matches &matches, Worker *worker=nullptr) const
Matches several query groups of multi-descriptors with all candidate descriptors in this forest.
Definition: VocabularyTree.h:2404
const TMultiDescriptor *(*)(const TMultiDescriptorGroup &, const size_t) MultiDescriptorGroupFunction
Definition of a function pointer to a function allowing to return individual multi-descriptors from a...
Definition: VocabularyTree.h:829
VocabularyTree< TDescriptor, TDistance, tDistanceFunction > TVocabularyTree
Definition of the Vocabulary Tree object.
Definition: VocabularyTree.h:797
void matchDescriptors(const TDescriptor *candidateDescriptors, const TDescriptor *queryDescriptors, const size_t numberQueryDescriptors, const TDistance maximalDistance, Matches &matches, Worker *worker=nullptr) const
Matches several query descriptors with all candidate descriptors in this forest.
Definition: VocabularyTree.h:2352
std::vector< TDescriptor > TDescriptors
Definition of a vector holding descriptors.
Definition: VocabularyTree.h:787
TDescriptor Descriptor
The descriptor type of this forest.
Definition: VocabularyTree.h:772
void matchMultiDescriptors(const TDescriptor *candidateDescriptors, const TMultiDescriptor *queryMultiDescriptors, const size_t numberQueryMultiDescriptors, const TDistance maximalDistance, Matches &matches, Worker *worker=nullptr) const
Matches several query multi-descriptors with all candidate descriptors in this forest.
Definition: VocabularyTree.h:2377
void matchMultiDescriptorsSubset(const TDescriptor *candidateDescriptors, const TMultiDescriptor *queryMultiDescriptors, const TDistance maximalDistance, Matches *matches, Lock *lock, const unsigned int firstQueryMultiDescriptor, const unsigned int numberQueryMultiDescriptors) const
Matches a subset of several query multi-descriptors with all forest candidate descriptors.
Definition: VocabularyTree.h:2463
This class implements a simple container holding the index pairs of matching descriptors and their di...
Definition: VocabularyTree.h:87
Index32 candidateDescriptorIndex_
The index of the candidate descriptor, with range [0, infinity).
Definition: VocabularyTree.h:130
Match()=default
Default constructor for an invalid match.
Index32 queryDescriptorIndex() const
Returns the index of the query descriptor.
Definition: VocabularyTree.h:1046
Index32 candidateDescriptorIndex() const
Returns the index of the candidate descriptor.
Definition: VocabularyTree.h:1040
Index32 queryDescriptorIndex_
The index of the query descriptor, with range [0, infinity).
Definition: VocabularyTree.h:133
bool isValid() const
Returns whether this match is valid.
Definition: VocabularyTree.h:1058
TDistance distance() const
Returns the distance between both descriptors.
Definition: VocabularyTree.h:1052
TDistance distance_
The distance between both descriptors, with range [0, infinity].
Definition: VocabularyTree.h:136
This class stores construction parameters for a VocabularyStructure.
Definition: VocabularyTree.h:150
unsigned int maximalDescriptorsPerLeaf_
The maximal number of descriptors each leaf can have, with range [1, infinity).
Definition: VocabularyTree.h:179
InitializationStrategy initializationStrategy_
The initialization strategy for initial clusters.
Definition: VocabularyTree.h:185
unsigned int maximalLevels_
The maximal number of tree levels, at tree will never have more level regardless what has been specif...
Definition: VocabularyTree.h:182
unsigned int maximalNumberClustersPerLevel_
The maximal number of clusters each tree level can have with range [2, infinity).
Definition: VocabularyTree.h:176
Parameters()=default
Default constructor.
bool isValid() const
Returns whether this object holds valid parameters.
Definition: VocabularyTree.h:1072
This class implements the base class for all Vocabulary objects.
Definition: VocabularyTree.h:42
InitializationStrategy
Definition of individual strategies to initialize the clustering of each tree node.
Definition: VocabularyTree.h:55
@ IS_INVALID
An invalid strategy.
Definition: VocabularyTree.h:57
@ IS_PURE_RANDOM
All initial clusters are chosen randomly.
Definition: VocabularyTree.h:59
@ IS_LARGEST_DISTANCE
The initial first cluster is chosen randomly, the remaining clusters are chosen with largest distance...
Definition: VocabularyTree.h:61
virtual ~VocabularyStructure()=default
Destructs this object.
std::vector< Match< TDistance > > Matches
Definition of a vector holding matches.
Definition: VocabularyTree.h:144
VocabularyStructure()=default
Default constructor.
MatchingMode
Definition of individual matching modes for descriptors.
Definition: VocabularyTree.h:68
@ MM_ALL_GOOD_LEAFS_1
All descriptors from all tree leafs are considered for matching which are within a 1% distance to the...
Definition: VocabularyTree.h:76
@ MM_ALL_GOOD_LEAFS_2
All descriptors from all tree leafs are considered for matching which are within a 2% distance to the...
Definition: VocabularyTree.h:78
@ MM_INVALID
An invalid matching mode.
Definition: VocabularyTree.h:70
@ MM_FIRST_BEST_LEAF
Only descriptor from the first best tree leaf are considered for matching (the second+ leaf with iden...
Definition: VocabularyTree.h:72
@ MM_ALL_BEST_LEAFS
All descriptors from all best tree leafs are considered for matching (all leafs with identical best d...
Definition: VocabularyTree.h:74
static constexpr Index32 invalidMatchIndex()
Returns an invalid matching index.
Definition: VocabularyTree.h:1025
static std::vector< uint8_t > generateBitSeparationLookup8()
Returns the lookup table which separates the bits of a byte into 8 individual bytes.
Definition: VocabularyTree.h:1077
Definition of a class which holds reusable data for internal use.
Definition: VocabularyTree.h:317
ReusableData()=default
Creates a new object.
std::vector< const Indices32 * > internalData_
The internal reusable data.
Definition: VocabularyTree.h:330
This class implements a Vocabulary Tree for feature descriptors.
Definition: VocabularyTree.h:223
void matchDescriptorsSubset(const TDescriptor *candidateDescriptors, const TDescriptor *queryDescriptors, const TDistance maximalDistance, Matches *matches, Lock *lock, const unsigned int firstQueryDescriptor, const unsigned int numberQueryDescriptors) const
Matches a subset of several query descriptors with all tree candidate descriptors.
Definition: VocabularyTree.h:2135
const TDescriptor & nodeDescriptor() const
Returns the descriptor representing this tree/node.
Definition: VocabularyTree.h:1580
TDescriptors(*)(const unsigned int numberClusters, const TDescriptor *treeDescriptors, const Index32 *descriptorIndices, const Index32 *clusterIndicesForDescriptors, const size_t numberDescriptorIndices, Worker *worker) ClustersMeanFunction
Definition of a function pointer allowing to determine the mean descriptors for individual clusters.
Definition: VocabularyTree.h:285
VocabularyTree & operator=(VocabularyTree &&vocabularyTree)
Move operator.
Definition: VocabularyTree.h:1832
void matchMultiDescriptorGroups(const TDescriptor *candidateDescriptors, const TMultiDescriptorGroup *queryMultiDescriptorGroups, const size_t numberQueryMultiDescriptorGroups, const TDistance maximalDistance, Matches &matches, Worker *worker=nullptr) const
Matches several query groups of multi-descriptors with all candidate descriptors in this tree.
Definition: VocabularyTree.h:1553
VocabularyTree()=default
Creates an empty vocabulary tree.
Match< TDistance > Match
Definition of a Match object using the distance data type of this tree.
Definition: VocabularyTree.h:274
Indices32 descriptorIndices_
The indices of the descriptors which are part of this node.
Definition: VocabularyTree.h:749
TDistance Distance
The distance data type of this tree.
Definition: VocabularyTree.h:234
static TDescriptors determineClustersMeanForBinaryDescriptor(const unsigned int numberClusters, const TDescriptor *treeDescriptors, const Index32 *descriptorIndices, const Index32 *clusterIndicesForDescriptors, const size_t numberDescriptorIndices, Worker *worker)
Determines a binary mean descriptor for each cluster.
Definition: VocabularyTree.h:1846
const Indices32 & determineBestLeaf(const TDescriptor &descriptor) const
Determines the leaf best matching with a given descriptor.
Definition: VocabularyTree.h:1214
const TMultiDescriptor *(*)(const TMultiDescriptorGroup &, const size_t) MultiDescriptorGroupFunction
Definition of a function pointer to a function allowing to return individual multi-descriptors from a...
Definition: VocabularyTree.h:301
VocabularyTree(const VocabularyTree &vocabularyTree)=delete
Disabled copy constructor.
void matchMultiDescriptorGroupsSubset(const TDescriptor *candidateDescriptors, const TMultiDescriptorGroup *queryMultiDescriptorGroups, const TDistance maximalDistance, Matches *matches, Lock *lock, const unsigned int firstQueryMultiDescriptorGroup, const unsigned int numberQueryMultiDescriptorGroups) const
Matches a subset of several query groups of multi-descriptors with all candidate descriptors in this ...
Definition: VocabularyTree.h:2197
Nodes childNodes_
The child-nodes of this node.
Definition: VocabularyTree.h:752
~VocabularyTree()
Destructs the vocabulary tree.
Definition: VocabularyTree.h:1178
TDescriptors initialClustersPureRandom(const Parameters &parameters, const TDescriptor *treeDescriptors, Index32 *descriptorIndices, const size_t numberDescriptorsIndices, RandomGenerator &randomGenerator) const
Determines the initial cluster based on a pure random choice.
Definition: VocabularyTree.h:1799
TDescriptor Descriptor
The descriptor type of this tree.
Definition: VocabularyTree.h:229
NextLargerTyper< TDistance >::TypePerformance TSumDistances
The data type of the sum of distances, uint64_t for uint32_t, and float for float.
Definition: VocabularyTree.h:239
void matchMultiDescriptorsSubset(const TDescriptor *candidateDescriptors, const TMultiDescriptor *queryMultiDescriptors, const TDistance maximalDistance, Matches *matches, Lock *lock, const unsigned int firstQueryMultiDescriptor, const unsigned int numberQueryMultiDescriptors) const
Matches a subset of several query multi-descriptors with all tree candidate descriptors.
Definition: VocabularyTree.h:2166
const Nodes & childNodes() const
Returns all child nodes of this node/tree.
Definition: VocabularyTree.h:1592
static constexpr TDistance(* distanceFunction)(const TDescriptor &, const TDescriptor &)
The pointer to the function determining the distance between two descriptors of this tree.
Definition: VocabularyTree.h:244
std::vector< TDistance > TDistances
Definition of a vector holding distances.
Definition: VocabularyTree.h:254
TDescriptor nodeDescriptor_
The node's descriptor.
Definition: VocabularyTree.h:746
VocabularyTree & operator=(const VocabularyTree &vocabularyTree)=delete
Disabled assign operator.
void determineBestLeafs(const TDescriptor &descriptor, std::vector< const Indices32 * > &leafs, const TDistance distanceEpsilon=TDistance(0)) const
Determines the leafs best matching with a given descriptor.
Definition: VocabularyTree.h:1251
VocabularyTree< TDescriptor, TDistance, tDistanceFunction > Node
Definition of a tree node which is just an alias for the tree (the root node).
Definition: VocabularyTree.h:259
Index32 matchMultiDescriptorGroup(const TDescriptor *candidateDescriptors, const TMultiDescriptorGroup &queryMultiDescriptorGroup, TDistance *distance=nullptr, const ReusableData &reusableData=ReusableData()) const
Matches a query group of multi-descriptors with all candidate descriptors in this tree.
Definition: VocabularyTree.h:1465
const Indices32 & descriptorIndices() const
Returns all indices of descriptors which belong to this tree/node.
Definition: VocabularyTree.h:1586
void createChildNodesSubset(const unsigned int childNodeLevel, const Parameters *parameters, const TDescriptor *treeDescriptors, const TDescriptor *clusterCenters, const unsigned int *clusterSizes, const size_t numberClusters, Index32 *reusableDescriptorIndicesInput, Index32 *reusableDescriptorIndicesOutput, const size_t numberDescriptorsIndices, RandomGenerator *randomGenerator, Index32 *reusableClusterIndicesForDescriptors, const ClustersMeanFunction *clustersMeanFunction, const unsigned int subsetFirstCluster, const unsigned int subsetNumberClusters)
Creates a subset of the new child nodes.
Definition: VocabularyTree.h:2026
Index32 matchDescriptor(const TDescriptor *candidateDescriptors, const TDescriptor &queryDescriptor, TDistance *distance=nullptr, const ReusableData &reusableData=ReusableData()) const
Matches a query descriptor with all candidate descriptors in this tree.
Definition: VocabularyTree.h:1320
void createChildNodes(const unsigned int childNodeLevel, const Parameters &parameters, const TDescriptor *treeDescriptors, const TDescriptor *clusterCenters, const unsigned int *clusterSizes, const size_t numberClusters, Index32 *reusableDescriptorIndicesInput, Index32 *reusableDescriptorIndicesOutput, const size_t numberDescriptorsIndices, RandomGenerator &randomGenerator, Index32 *reusableClusterIndicesForDescriptors, const ClustersMeanFunction &clustersMeanFunction, Worker *worker)
Creates the new child nodes.
Definition: VocabularyTree.h:1187
const TDescriptor *(*)(const TMultiDescriptor &, const size_t) MultiDescriptorFunction
Definition of a function pointer to a function allowing to return individual descriptors from a multi...
Definition: VocabularyTree.h:293
TDescriptors initialClustersLargestDistance(const Parameters &parameters, const TDescriptor *treeDescriptors, Index32 *descriptorIndices, Index32 *reusableIndices, const size_t numberDescriptorsIndices, RandomGenerator &randomGenerator) const
Determines the initial clusters based on the largest distance between each other.
Definition: VocabularyTree.h:1722
void matchMultiDescriptors(const TDescriptor *candidateDescriptors, const TMultiDescriptor *queryMultiDescriptors, const size_t numberQueryMultiDescriptors, const TDistance maximalDistance, Matches &matches, Worker *worker=nullptr) const
Matches several query multi-descriptors with all candidate descriptors in this tree.
Definition: VocabularyTree.h:1526
static void assignDescriptorsToClustersSubset(const TDescriptor *clusterCenters, const unsigned int numberClusters, const TDescriptor *treeDescriptors, const Index32 *descriptorIndices, Index32 *clusterIndicesForDescriptors, Index32 *clusterSizes, TSumDistances *sumDistances, Lock *lock, const unsigned int firstDescriptorIndex, const unsigned int numberDescriptorIndices)
Assigns a subset of descriptors to clusters.
Definition: VocabularyTree.h:2078
unsigned int level_
The node's level.
Definition: VocabularyTree.h:743
static Indices32 assignDescriptorsToClusters(const TDescriptor *clusterCenters, const unsigned int numberClusters, const TDescriptor *treeDescriptors, const Index32 *descriptorIndices, Index32 *clusterIndicesForDescriptors, const size_t numberDescriptorIndices, TSumDistances *sumDistances=nullptr, Worker *worker=nullptr)
Assigns descriptors to clusters.
Definition: VocabularyTree.h:2002
std::vector< Node * > Nodes
Definition of a vector holding tree nodes.
Definition: VocabularyTree.h:264
TDescriptors initialClusters(const Parameters &parameters, const TDescriptor *treeDescriptors, Index32 *reusableDescriptorIndicesInput, Index32 *reusableDescriptorIndicesOutput, size_t numberDescriptorsIndices, RandomGenerator &randomGenerator)
Determines the initial clusters based on specified initialization strategy.
Definition: VocabularyTree.h:1704
std::vector< const Node * > ConstNodes
Definition of a vector holding constant tree nodes.
Definition: VocabularyTree.h:269
void matchDescriptors(const TDescriptor *candidateDescriptors, const TDescriptor *queryDescriptors, const size_t numberQueryDescriptors, const TDistance maximalDistance, Matches &matches, Worker *worker=nullptr) const
Matches several query descriptors with all candidate descriptors in this tree.
Definition: VocabularyTree.h:1501
static TDescriptors determineClustersMeanForFloatDescriptor(const unsigned int numberClusters, const TDescriptor *treeDescriptors, const Index32 *descriptorIndices, const Index32 *clusterIndicesForDescriptors, const size_t numberDescriptorIndices, Worker *worker)
Determines a float mean descriptor for each cluster.
Definition: VocabularyTree.h:1937
Index32 matchMultiDescriptor(const TDescriptor *candidateDescriptors, const TDescriptor *queryMultiDescriptor, const size_t numberQuerySingleDescriptors, TDistance *distance=nullptr, const ReusableData &reusableData=ReusableData()) const
Matches a query multi-descriptor with all candidate descriptors in this tree.
Definition: VocabularyTree.h:1400
TDescriptors clusterDescriptors(const Parameters &parameters, const TDescriptor *treeDescriptors, Index32 *reusableDescriptorIndicesInput, Index32 *reusableDescriptorIndicesOutput, size_t numberDescriptorsIndices, RandomGenerator &randomGenerator, Index32 *clusterIndicesForDescriptors, const ClustersMeanFunction &clustersMeanFunction, Indices32 *clusterSizes=nullptr, Worker *worker=nullptr)
Distributes several descriptors into individual clusters.
Definition: VocabularyTree.h:1598
std::vector< TDescriptor > TDescriptors
Definition of a vector holding descriptors.
Definition: VocabularyTree.h:249
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::unordered_set< Index32 > UnorderedIndexSet32
Definition of an unordered_set holding 32 bit indices.
Definition: Base.h:126
uint32_t Index32
Definition of a 32 bit index value.
Definition: Base.h:84
std::shared_ptr< VocabularyStructure > SharedVocabularyStructure
Definition of a shared pointer holding a VocabularyStructure object.
Definition: VocabularyTree.h:35
The namespace covering the entire Ocean framework.
Definition: Accessor.h:15