Ocean
Loading...
Searching...
No Matches
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"
17#include "ocean/base/Worker.h"
18
19#include "ocean/math/Numeric.h"
20
21namespace Ocean
22{
23
24namespace Tracking
25{
26
27// Forward declaration.
28class VocabularyStructure;
29
30/**
31 * Definition of a shared pointer holding a VocabularyStructure object.
32 * @see VocabularyStructure.
33 * @ingroup tracking
34 */
35using 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.
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.
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).
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 */
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 */
221template <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 */
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 */
764template <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
1030template <typename TDistance>
1031inline 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
1039template <typename TDistance>
1041{
1042 return candidateDescriptorIndex_;
1043}
1044
1045template <typename TDistance>
1047{
1048 return queryDescriptorIndex_;
1049}
1050
1051template <typename TDistance>
1053{
1054 return distance_;
1055}
1056
1057template <typename TDistance>
1059{
1060 return candidateDescriptorIndex_ != invalidMatchIndex() && queryDescriptorIndex_ != invalidMatchIndex();
1061}
1062
1063inline 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
1101template <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
1109template <typename TDescriptor, typename TDistance, TDistance(*tDistanceFunction)(const TDescriptor&, const TDescriptor&)>
1110VocabularyTree<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
1137template <typename TDescriptor, typename TDistance, TDistance(*tDistanceFunction)(const TDescriptor&, const TDescriptor&)>
1138VocabularyTree<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
1164template <typename TDescriptor, typename TDistance, TDistance(*tDistanceFunction)(const TDescriptor&, const TDescriptor&)>
1165VocabularyTree<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
1177template <typename TDescriptor, typename TDistance, TDistance(*tDistanceFunction)(const TDescriptor&, const TDescriptor&)>
1179{
1180 for (VocabularyTree* childNode : childNodes_)
1181 {
1182 delete childNode;
1183 }
1184}
1185
1186template <typename TDescriptor, typename TDistance, TDistance(*tDistanceFunction)(const TDescriptor&, const TDescriptor&)>
1187void 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
1213template <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
1250template <typename TDescriptor, typename TDistance, TDistance(*tDistanceFunction)(const TDescriptor&, const TDescriptor&)>
1251void 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
1318template <typename TDescriptor, typename TDistance, TDistance(*tDistanceFunction)(const TDescriptor&, const TDescriptor&)>
1319template <VocabularyStructure::MatchingMode tMatchingMode>
1320Index32 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
1398template <typename TDescriptor, typename TDistance, TDistance(*tDistanceFunction)(const TDescriptor&, const TDescriptor&)>
1399template <VocabularyStructure::MatchingMode tMatchingMode>
1400Index32 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
1428template <typename TDescriptor, typename TDistance, TDistance(*tDistanceFunction)(const TDescriptor&, const TDescriptor&)>
1429template <typename TMultiDescriptor, const TDescriptor*(*tMultiDescriptorFunction)(const TMultiDescriptor&, const size_t), VocabularyStructure::MatchingMode tMatchingMode>
1430Index32 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
1463template <typename TDescriptor, typename TDistance, TDistance(*tDistanceFunction)(const TDescriptor&, const TDescriptor&)>
1464template <typename TMultiDescriptorGroup, typename TMultiDescriptor, const TMultiDescriptor*(*tMultiDescriptorGroupFunction)(const TMultiDescriptorGroup&, const size_t), const TDescriptor*(*tMultiDescriptorFunction)(const TMultiDescriptor&, const size_t), VocabularyStructure::MatchingMode tMatchingMode>
1465Index32 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
1499template <typename TDescriptor, typename TDistance, TDistance(*tDistanceFunction)(const TDescriptor&, const TDescriptor&)>
1500template <VocabularyStructure::MatchingMode tMatchingMode>
1501void 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
1524template <typename TDescriptor, typename TDistance, TDistance(*tDistanceFunction)(const TDescriptor&, const TDescriptor&)>
1525template <typename TMultiDescriptor, const TDescriptor*(*tMultiDescriptorFunction)(const TMultiDescriptor&, const size_t), VocabularyStructure::MatchingMode tMatchingMode>
1526void 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
1551template <typename TDescriptor, typename TDistance, TDistance(*tDistanceFunction)(const TDescriptor&, const TDescriptor&)>
1552template <typename TMultiDescriptorGroup, typename TMultiDescriptor, const TMultiDescriptor*(*tMultiDescriptorGroupFunction)(const TMultiDescriptorGroup&, const size_t), const TDescriptor*(*tMultiDescriptorFunction)(const TMultiDescriptor&, const size_t), VocabularyStructure::MatchingMode tMatchingMode>
1553void 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
1579template <typename TDescriptor, typename TDistance, TDistance(*tDistanceFunction)(const TDescriptor&, const TDescriptor&)>
1581{
1582 return nodeDescriptor_;
1583}
1584
1585template <typename TDescriptor, typename TDistance, TDistance(*tDistanceFunction)(const TDescriptor&, const TDescriptor&)>
1587{
1588 return descriptorIndices_;
1589}
1590
1591template <typename TDescriptor, typename TDistance, TDistance(*tDistanceFunction)(const TDescriptor&, const TDescriptor&)>
1596
1597template <typename TDescriptor, typename TDistance, TDistance(*tDistanceFunction)(const TDescriptor&, const TDescriptor&)>
1598typename 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
1703template <typename TDescriptor, typename TDistance, TDistance(*tDistanceFunction)(const TDescriptor&, const TDescriptor&)>
1704typename 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
1721template <typename TDescriptor, typename TDistance, TDistance(*tDistanceFunction)(const TDescriptor&, const TDescriptor&)>
1722typename 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
1798template <typename TDescriptor, typename TDistance, TDistance(*tDistanceFunction)(const TDescriptor&, const TDescriptor&)>
1799typename 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
1831template <typename TDescriptor, typename TDistance, TDistance(*tDistanceFunction)(const TDescriptor&, const TDescriptor&)>
1843
1844template <typename TDescriptor, typename TDistance, TDistance(*tDistanceFunction)(const TDescriptor&, const TDescriptor&)>
1845template <unsigned int tSize>
1846typename 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
1935template <typename TDescriptor, typename TDistance, TDistance(*tDistanceFunction)(const TDescriptor&, const TDescriptor&)>
1936template <unsigned int tSize>
1937typename 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
2001template <typename TDescriptor, typename TDistance, TDistance(*tDistanceFunction)(const TDescriptor&, const TDescriptor&)>
2002Indices32 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
2025template <typename TDescriptor, typename TDistance, TDistance(*tDistanceFunction)(const TDescriptor&, const TDescriptor&)>
2026void 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
2077template <typename TDescriptor, typename TDistance, TDistance(*tDistanceFunction)(const TDescriptor&, const TDescriptor&)>
2078void 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
2133template <typename TDescriptor, typename TDistance, TDistance(*tDistanceFunction)(const TDescriptor&, const TDescriptor&)>
2134template <VocabularyStructure::MatchingMode tMatchingMode>
2135void 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
2164template <typename TDescriptor, typename TDistance, TDistance(*tDistanceFunction)(const TDescriptor&, const TDescriptor&)>
2165template <typename TMultiDescriptor, const TDescriptor*(*tMultiDescriptorFunction)(const TMultiDescriptor&, const size_t), VocabularyStructure::MatchingMode tMatchingMode>
2166void 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
2195template <typename TDescriptor, typename TDistance, TDistance(*tDistanceFunction)(const TDescriptor&, const TDescriptor&)>
2196template <typename TMultiDescriptorGroup, typename TMultiDescriptor, const TMultiDescriptor*(*tMultiDescriptorGroupFunction)(const TMultiDescriptorGroup&, const size_t), const TDescriptor*(*tMultiDescriptorFunction)(const TMultiDescriptor&, const size_t), VocabularyStructure::MatchingMode tMatchingMode>
2197void 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
2226template <typename TDescriptor, typename TDistance, TDistance(*tDistanceFunction)(const TDescriptor&, const TDescriptor&)>
2227VocabularyForest<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
2237template <typename TDescriptor, typename TDistance, TDistance(*tDistanceFunction)(const TDescriptor&, const TDescriptor&)>
2238template <VocabularyStructure::MatchingMode tMatchingMode>
2239Index32 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
2264template <typename TDescriptor, typename TDistance, TDistance(*tDistanceFunction)(const TDescriptor&, const TDescriptor&)>
2265template <VocabularyStructure::MatchingMode tMatchingMode>
2266Index32 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
2291template <typename TDescriptor, typename TDistance, TDistance(*tDistanceFunction)(const TDescriptor&, const TDescriptor&)>
2292template <typename TMultiDescriptor, const TDescriptor*(*tMultiDescriptorFunction)(const TMultiDescriptor&, const size_t), VocabularyStructure::MatchingMode tMatchingMode>
2293Index32 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
2320template <typename TDescriptor, typename TDistance, TDistance(*tDistanceFunction)(const TDescriptor&, const TDescriptor&)>
2321template <typename TMultiDescriptorGroup, typename TMultiDescriptor, const TMultiDescriptor*(*tMultiDescriptorGroupFunction)(const TMultiDescriptorGroup&, const size_t), const TDescriptor*(*tMultiDescriptorFunction)(const TMultiDescriptor&, const size_t), VocabularyStructure::MatchingMode tMatchingMode>
2322Index32 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
2350template <typename TDescriptor, typename TDistance, TDistance(*tDistanceFunction)(const TDescriptor&, const TDescriptor&)>
2351template <VocabularyStructure::MatchingMode tMatchingMode>
2352void 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
2375template <typename TDescriptor, typename TDistance, TDistance(*tDistanceFunction)(const TDescriptor&, const TDescriptor&)>
2376template <typename TMultiDescriptor, const TDescriptor*(*tMultiDescriptorFunction)(const TMultiDescriptor&, const size_t), VocabularyStructure::MatchingMode tMatchingMode>
2377void 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
2402template <typename TDescriptor, typename TDistance, TDistance(*tDistanceFunction)(const TDescriptor&, const TDescriptor&)>
2403template <typename TMultiDescriptorGroup, typename TMultiDescriptor, const TMultiDescriptor*(*tMultiDescriptorGroupFunction)(const TMultiDescriptorGroup&, const size_t), const TDescriptor*(*tMultiDescriptorFunction)(const TMultiDescriptor&, const size_t), VocabularyStructure::MatchingMode tMatchingMode>
2404void 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
2430template <typename TDescriptor, typename TDistance, TDistance(*tDistanceFunction)(const TDescriptor&, const TDescriptor&)>
2431template <VocabularyStructure::MatchingMode tMatchingMode>
2432void 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
2461template <typename TDescriptor, typename TDistance, TDistance(*tDistanceFunction)(const TDescriptor&, const TDescriptor&)>
2462template <typename TMultiDescriptor, const TDescriptor*(*tMultiDescriptorFunction)(const TMultiDescriptor&, const size_t), VocabularyStructure::MatchingMode tMatchingMode>
2463void 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
2492template <typename TDescriptor, typename TDistance, TDistance(*tDistanceFunction)(const TDescriptor&, const TDescriptor&)>
2493template <typename TMultiDescriptorGroup, typename TMultiDescriptor, const TMultiDescriptor*(*tMultiDescriptorGroupFunction)(const TMultiDescriptorGroup&, const size_t), const TDescriptor*(*tMultiDescriptorFunction)(const TMultiDescriptor&, const size_t), VocabularyStructure::MatchingMode tMatchingMode>
2494void 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
Matches< TDistance > Matches
Definition of a vector holding Match objects.
Definition VocabularyTree.h:807
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.
VocabularyTree & operator=(const VocabularyTree &vocabularyTree)=delete
Disabled assign operator.
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
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
Matches< TDistance > Matches
Definition of a vector holding Match objects.
Definition VocabularyTree.h:279
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