Ocean
Loading...
Searching...
No Matches
SpatialDistribution.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_GEOMETRY_SPATIAL_DISTRIBUTION_H
9#define META_OCEAN_GEOMETRY_SPATIAL_DISTRIBUTION_H
10
12
14
15#include "ocean/math/Box2.h"
16
17#include <algorithm>
18
19namespace Ocean
20{
21
22namespace Geometry
23{
24
25/**
26 * This class implements spatial distribution function for 2D geometric data.
27 * @ingroup geometry
28 */
29class OCEAN_GEOMETRY_EXPORT SpatialDistribution
30{
31 public:
32
33 /**
34 * This class implements a base class for data arrays.
35 */
36 class OCEAN_GEOMETRY_EXPORT Array
37 {
38 public:
39
40 /**
41 * Returns the left position of the distribution area.
42 * @return Left position
43 */
44 inline Scalar left() const;
45
46 /**
47 * Returns the top position of the distribution area.
48 * @return Top position
49 */
50 inline Scalar top() const;
51
52 /**
53 * Returns the width of the distribution area.
54 * @return Area width
55 */
56 inline Scalar width() const;
57
58 /**
59 * Returns the height of the distribution area.
60 * @return Area height
61 */
62 inline Scalar height() const;
63
64 /**
65 * Returns the number of horizontal distribution bins.
66 * @return Number of bins
67 */
68 inline unsigned int horizontalBins() const;
69
70 /**
71 * Returns the number of vertical distribution bins.
72 * @return Number of bins
73 */
74 inline unsigned int verticalBins() const;
75
76 /**
77 * Returns the number of bins this distribution holds.
78 * @return Bin number
79 */
80 inline unsigned int bins() const;
81
82 /**
83 * Returns the bin index for a given position.
84 * Beware: Make sure that the given position is inside the specified range!
85 * @param x Horizontal position, with range [0, width())
86 * @param y Vertical position, with range [0, height())
87 * @return Resulting bin index
88 */
89 inline unsigned int index(const Scalar x, const Scalar y) const;
90
91 /**
92 * Returns the horizontal bin of a given horizontal position.
93 * Beware: The resulting bin can exceed the bin-ranges of the array.<br>
94 * @param x Horizontal position, with range (-infinity, infinity)
95 * @return Horizontal bin, with range (-infinity, infinity)
96 * @see clampedHorizontalBin().
97 */
98 inline int horizontalBin(const Scalar x) const;
99
100 /**
101 * Returns the vertical bin of a given vertical position.
102 * Beware: The resulting bin can exceed the bin-ranges of the array.<br>
103 * @param y Vertical position, with range (-infinity, infinity)
104 * @return Vertical bin, with range (-infinity, infinity)
105 * @see clampedVerticalBin().
106 */
107 inline int verticalBin(const Scalar y) const;
108
109 /**
110 * Returns the horizontal bin of a given horizontal position.
111 * Beware: The resulting bin is clamped into the range [0, number of bins - 1).<br>
112 * @param x Horizontal position, with range (-infinity, infinity)
113 * @return Horizontal bin, with range [0, horizontalBins() - 1]
114 * @see horizontalBin().
115 */
116 inline int clampedHorizontalBin(const Scalar x) const;
117
118 /**
119 * Returns the vertical bin of a given vertical position.
120 * Beware: The resulting bin is clamped into the range [0, number of bins - 1).<br>
121 * @param y Vertical position, with range (-infinity, infinity)
122 * @return Vertical bin, with range [0, verticalBins() - 1]
123 * @see clampedVerticalBin().
124 */
125 inline int clampedVerticalBin(const Scalar y) const;
126
127 /**
128 * Returns the (inclusive) begin bin in horizontal direction for a neighborhood search.
129 * The resulting bin is clamped to the valid range [0, horizontalBins()).
130 * @param centerBinX The center horizontal bin, with range [0, horizontalBins() - 1]
131 * @return The (inclusive) begin horizontal bin, with range [0, horizontalBins() - 1]
132 * @tparam tRadius The radius of the neighborhood, in bins, with range [1, infinity)
133 * @see endBinHorizontal(), beginBinVertical(), endBinVertical().
134 */
135 template <unsigned int tRadius>
136 inline unsigned int beginBinHorizontal(const unsigned int centerBinX) const;
137
138 /**
139 * Returns the (exclusive) end bin in horizontal direction for a neighborhood search.
140 * The resulting bin is clamped to the valid range [0, horizontalBins()].
141 * @param centerBinX The center horizontal bin, with range [0, horizontalBins() - 1]
142 * @return The (exclusive) end horizontal bin, with range [1, horizontalBins()]
143 * @tparam tRadius The radius of the neighborhood, in bins, with range [1, infinity)
144 * @see beginBinHorizontal(), beginBinVertical(), endBinVertical().
145 */
146 template <unsigned int tRadius>
147 inline unsigned int endBinHorizontal(const unsigned int centerBinX) const;
148
149 /**
150 * Returns the (inclusive) begin bin in vertical direction for a neighborhood search.
151 * The resulting bin is clamped to the valid range [0, verticalBins()).
152 * @param centerBinY The center vertical bin, with range [0, verticalBins() - 1]
153 * @return The (inclusive) begin vertical bin, with range [0, verticalBins() - 1]
154 * @tparam tRadius The radius of the neighborhood, in bins, with range [1, infinity)
155 * @see endBinVertical(), beginBinHorizontal(), endBinHorizontal().
156 */
157 template <unsigned int tRadius>
158 inline unsigned int beginBinVertical(const unsigned int centerBinY) const;
159
160 /**
161 * Returns the (exclusive) end bin in vertical direction for a neighborhood search.
162 * The resulting bin is clamped to the valid range [0, verticalBins()].
163 * @param centerBinY The center vertical bin, with range [0, verticalBins() - 1]
164 * @return The (exclusive) end vertical bin, with range [1, verticalBins()]
165 * @tparam tRadius The radius of the neighborhood, in bins, with range [1, infinity)
166 * @see beginBinVertical(), beginBinHorizontal(), endBinHorizontal().
167 */
168 template <unsigned int tRadius>
169 inline unsigned int endBinVertical(const unsigned int centerBinY) const;
170
171 /**
172 * Returns whether this object holds a valid distribution.
173 * @return True, if so
174 */
175 inline bool isValid() const;
176
177 /**
178 * Returns whether two Array objects are identical.
179 * @param right The second array object to compare
180 * @return True, if so
181 */
182 inline bool operator==(const Array& right) const;
183
184 /**
185 * Returns whether two Array objects are not identical.
186 * @param right The second array object to compare
187 * @return True, if so
188 */
189 inline bool operator!=(const Array& right) const;
190
191 /**
192 * Returns whether this object holds a valid distribution.
193 * @return True, if so
194 */
195 explicit inline operator bool() const;
196
197 protected:
198
199 /**
200 * Creates an empty array object.
201 */
202 Array() = default;
203
204 /**
205 * Copy constructor.
206 * @param object The array object to be copied
207 */
208 Array(const Array& object) = default;
209
210 /**
211 * Move constructor.
212 * @param object The array object to be moved
213 */
214 inline Array(Array&& object) noexcept;
215
216 /**
217 * Creates a new array object.
218 * @param left The left area position, with range (-infinity, infinity)
219 * @param top The top area position, with range (-infinity, infinity)
220 * @param width The width of the distribution area, with range (0, infinity)
221 * @param height The height of the distribution area, with range (0, infinity)
222 * @param horizontalBins Number of horizontal distribution bins, with range [1, infinity)
223 * @param verticalBins Number of vertical distribution bins, with range [1, infinity)
224 */
225 inline Array(const Scalar left, const Scalar top, const Scalar width, const Scalar height, const unsigned int horizontalBins, const unsigned int verticalBins);
226
227 /**
228 * Assign operator.
229 * @param object The object to be assigned
230 * @return Reference to this object
231 */
232 inline Array& operator=(const Array& object);
233
234 /**
235 * Move operator.
236 * @param object The object to be moved
237 * @return Reference to this object
238 */
239 inline Array& operator=(Array&& object) noexcept;
240
241 protected:
242
243 /// Left position of the distribution area.
244 Scalar areaLeft_ = Scalar(0);
245
246 /// Top position of the distribution area.
247 Scalar areaTop_ = Scalar(0);
248
249 /// Width of the distribution area.
250 Scalar areaWidth_ = Scalar(0);
251
252 /// Height of the distribution area.
253 Scalar areaHeight_ = Scalar(0);
254
255 /// Number of horizontal distribution bins.
256 unsigned int horizontalBins_ = 0u;
257
258 /// Number of vertical distribution bins.
259 unsigned int verticalBins_ = 0u;
260
261 /// Horizontal position to bin factor.
262 Scalar horizontalPoint2Bin_ = Scalar(0);
263
264 /// Vertical position to bin factor.
265 Scalar verticalPoint2Bin_ = Scalar(0);
266 };
267
268 /**
269 * This class implements a distribution array.
270 */
271 class OCEAN_GEOMETRY_EXPORT DistributionArray : public Array
272 {
273 public:
274
275 /**
276 * Creates an empty distribution array object.
277 */
278 DistributionArray() = default;
279
280 /**
281 * Copy constructor.
282 * @param object The object to be copied
283 */
284 DistributionArray(const DistributionArray& object) = default;
285
286 /**
287 * Move constructor.
288 * @param object The object to be copied
289 */
290 inline DistributionArray(DistributionArray&& object) noexcept;
291
292 /**
293 * Creates a new distribution array object.
294 * @param left The left area position, with range (-infinity, infinity)
295 * @param top The top area position, with range (-infinity, infinity)
296 * @param width The width of the distribution area, with range (0, infinity)
297 * @param height The height of the distribution area, with range (0, infinity)
298 * @param horizontalBins Number of horizontal distribution bins, with range [1, infinity)
299 * @param verticalBins Number of vertical distribution bins, with range [1, infinity)
300 */
301 inline DistributionArray(const Scalar left, const Scalar top, const Scalar width, const Scalar height, const unsigned int horizontalBins, const unsigned int verticalBins);
302
303 /**
304 * Copies a given distribution array and optional copies the indices from the 8-neighborhood of each individual bin to the bin in the center of the neighborhood.
305 * The resulting distribution array can be used to speed-up the search for nearest neighbors if the distribution array is reused several times.<br>
306 * Instead of gathering neighboring indices via indicesNeighborhood9(), each bin contains all indices of the 9 neighborhood already.
307 * @param distributionArray The distribution array to be copied
308 * @param copyNeighborhood8 True, to copy the 8-neighborhood of each individual bin to the bin in the center of the neighborhood; False to create a simple copy of the distribution array
309 * @see hasCopiedNeighborhood8().
310 */
311 DistributionArray(const DistributionArray& distributionArray, const bool copyNeighborhood8);
312
313 /**
314 * Returns the indices of the 8-neighborhood and the specified bin itself.
315 * @param horizontal The horizontal distribution bin, with range [0, horizontalBins() - 1]
316 * @param vertical The vertical distribution bin, with range [0, verticalBins() - 1]
317 * @return Indices of the 9 neighboring bins
318 * @see hasCopiedNeighborhood8().
319 */
320 Indices32 indicesNeighborhood9(const unsigned int horizontal, const unsigned int vertical) const;
321
322 /**
323 * Returns the indices of the 8-neighborhood and the specified bin itself.
324 * @param horizontal The horizontal distribution bin, with range [0, horizontalBins() - 1]
325 * @param vertical The vertical distribution bin, with range [0, verticalBins() - 1]
326 * @param indices Resulting indices of the 9 neighboring bins
327 * @see hasCopiedNeighborhood8().
328 */
329 void indicesNeighborhood9(const unsigned int horizontal, const unsigned int vertical, Indices32& indices) const;
330
331 /**
332 * Returns whether this distribution array contains copies of indices within the 8-neighborhood of each individual bin.
333 * @return True, if so
334 */
335 inline bool hasCopiedNeighborhood8() const;
336
337 /**
338 * Removes all elements form this array.
339 */
340 void clear();
341
342 /**
343 * Returns the distribution indices of a specified bin.
344 * @param horizontal The horizontal distribution bin, with range [0, horizontalBins() - 1]
345 * @param vertical The vertical distribution bin, with range [0, verticalBins() - 1]
346 * @return Specified distribution indices
347 */
348 inline const Indices32& operator()(const unsigned int horizontal, const unsigned int vertical) const;
349
350 /**
351 * Returns the distribution indices of a specified bin.
352 * @param horizontal The horizontal distribution bin, with range [0, horizontalBins() - 1]
353 * @param vertical The vertical distribution bin, with range [0, verticalBins() - 1]
354 * @return Specified distribution indices
355 */
356 inline Indices32& operator()(const unsigned int horizontal, const unsigned int vertical);
357
358 /**
359 * Returns the distribution indices of a specified bin.
360 * The bins are stored in a row aligned order.
361 * @param index The index of the specified bin, with range [0, horizontalBins() * verticalBins() - 1]
362 * @return Specified distribution indices
363 */
364 inline const Indices32& operator[](const unsigned int index) const;
365
366 /**
367 * Returns the distribution indices of a specified bin.
368 * The bins are stored in a row aligned order.
369 * @param index The index of the specified bin, with range [0, horizontalBins() * verticalBins() - 1]
370 * @return Specified distribution indices
371 */
372 inline Indices32& operator[](const unsigned int index);
373
374 /**
375 * Assign operator.
376 * @param object The object to be assigned
377 * @return Reference to this object
378 */
379 inline DistributionArray& operator=(const DistributionArray& object);
380
381 /**
382 * Move operator.
383 * @param object The object to be moved
384 */
385 inline DistributionArray& operator=(DistributionArray&& object) noexcept;
386
387 /**
388 * Returns whether two DistributionArray objects are identical.
389 * @param distributionArray The second array object to compare
390 * @return True, if so
391 */
392 inline bool operator==(const DistributionArray& distributionArray) const;
393
394 /**
395 * Returns whether two DistributionArray objects are not identical.
396 * @param distributionArray The second array object to compare
397 * @return True, if so
398 */
399 inline bool operator!=(const DistributionArray& distributionArray) const;
400
401 private:
402
403 /// Distribution array with point indices.
405
406 /// True, if the array contains copies of indices within the 8-neighborhood of each individual bin; False, if each bin contains the indices of the actual bin only
407 bool hasCopiedNeighborhood8_ = false;
408 };
409
410 /**
411 * This class implements an occupancy array.
412 */
413 class OCEAN_GEOMETRY_EXPORT OccupancyArray : public Array
414 {
415 public:
416
417 /**
418 * Creates an empty distribution array object.
419 */
420 OccupancyArray() = default;
421
422 /**
423 * Copy constructor.
424 * @param object Occupancy array object to be copied
425 */
426 OccupancyArray(const OccupancyArray& object) = default;
427
428 /**
429 * Move constructor.
430 * @param object Occupancy array object to be move
431 */
432 inline OccupancyArray(OccupancyArray&& object) noexcept;
433
434 /**
435 * Creates a new distribution array object.
436 * @param boundingBox The bounding box defining the position and dimension of the area, must be valid
437 * @param horizontalBins Number of horizontal distribution bins, with range [1, infinity)
438 * @param verticalBins Number of vertical distribution bins, with range [1, infinity)
439 * @param allFree True, to set all bins as free; False, to set all bins as occupied
440 */
441 inline OccupancyArray(const Box2& boundingBox, const unsigned int horizontalBins, const unsigned int verticalBins, const bool allFree = true);
442
443 /**
444 * Creates a new distribution array object.
445 * @param left The left area position, with range (-infinity, infinity)
446 * @param top The top area position, with range (-infinity, infinity)
447 * @param width The width of the distribution area, with range (0, infinity)
448 * @param height The height of the distribution area, with range (0, infinity)
449 * @param horizontalBins Number of horizontal distribution bins, with range [1, infinity)
450 * @param verticalBins Number of vertical distribution bins, with range [1, infinity)
451 * @param allFree True, to set all bins as free; False, to set all bins as occupied
452 */
453 inline OccupancyArray(const Scalar left, const Scalar top, const Scalar width, const Scalar height, const unsigned int horizontalBins, const unsigned int verticalBins, const bool allFree = true);
454
455 /**
456 * Returns whether at least one bin in the 8-neighborhood or the specified bin itself is occupied.
457 * @param horizontal The horizontal distribution bin, with range [0, horizontalBins() - 1]
458 * @param vertical The vertical distribution bin, with range [0, verticalBins() - 1]
459 * @return True, if so
460 */
461 inline bool isOccupiedNeighborhood9(const unsigned int horizontal, const unsigned int vertical) const;
462
463 /**
464 * Returns whether at least one bin in the 8-neighborhood or the specified bin itself is occupied.
465 * @param point The point for that the 9-neighborhood bins have to be checked, with range (-infinity, infinity)x(-infinity, infinity)
466 * @return True, if so
467 */
468 inline bool isOccupiedNeighborhood9(const Vector2& point) const;
469
470 /**
471 * Returns whether at least one bin in the 8-neighborhood or the specified bin itself is not occupied.
472 * @param horizontal The horizontal distribution bin, with range [0, horizontalBins() - 1]
473 * @param vertical The vertical distribution bin, with range [0, verticalBins() - 1]
474 * @return True, if so
475 */
476 inline bool isNotOccupiedNeighborhood9(const unsigned int horizontal, const unsigned int vertical) const;
477
478 /**
479 * Returns whether at least one bin in the 8-neighborhood or the specified bin itself is not occupied.
480 * @param point The point for that the 9-neighborhood bins have to be checked, with range (-infinity, infinity)x(-infinity, infinity)
481 * @return True, if so
482 */
483 inline bool isNotOccupiedNeighborhood9(const Vector2& point) const;
484
485 /**
486 * Returns the number of occupied bins in the 9-neighborhood (so the specified bin is included).
487 * @param horizontal The horizontal distribution bin, with range [0, horizontalBins() - 1]
488 * @param vertical The vertical distribution bin, with range [0, verticalBins() - 1]
489 * @return The number of occupied bins
490 */
491 inline unsigned int countOccupiedNeighborhood9(const unsigned int horizontal, const unsigned int vertical) const;
492
493 /**
494 * Returns the number of occupied bins.
495 * @return Bin number
496 */
497 inline unsigned int occupiedBins() const;
498
499 /**
500 * Returns the number of free bins.
501 * @return Bin number
502 */
503 inline unsigned int freeBins() const;
504
505 /**
506 * Adds an image point and returns whether the corresponding bin was not occupied before (was free before).
507 * If the point lies outside the array, False is returned.
508 * @param point The point to be added, with range (-infinity, infinity)x(-infinity, infinity)
509 * @return True, if the point was added to an empty bin; False, if the bin was already occupied or the point was outside the array
510 */
511 inline bool addPoint(const Vector2& point);
512
513 /**
514 * Adds an image point and returns whether the occupancy counter of the corresponding bin was equal or below a specified value.
515 * If the point lies outside the array False is returned.<br>
516 * The occupancy counter of the bin (if valid) to which the given point belongs will be incremented.<br>
517 * Beware: This function should not be used in conjunction with any other addPoint(), removePoint() function not leveraging a occupancy counter.
518 * @param point The point to be added, with range (-infinity, infinity)x(-infinity, infinity)
519 * @param maximalOccupancyCounter The maximal occupancy counter the corresponding bin may have to add the point.
520 * @return True, if so
521 */
522 inline bool addPointWithCounter(const Vector2& point, const unsigned int maximalOccupancyCounter);
523
524 /**
525 * Removes an image point and returns whether the corresponding bin was occupied before.
526 * If the point lies outside the array False is returned.<br>
527 * The bin (if valid) which belongs to the given point is free (not occupied) after the function returns.
528 * @param point The point to be removed, with range (-infinity, infinity)x(-infinity, infinity)
529 * @return True, if so
530 */
531 inline bool removePoint(const Vector2& point);
532
533 /**
534 * Resets all occupied bins so that all bins a free afterwards.
535 */
536 inline void reset();
537
538 /**
539 * Adds an image point to this occupancy array.
540 * The bin (if valid) which belongs to the given point is occupied after the function returns.
541 * @param point The point to be added, with range (-infinity, infinity)x(-infinity, infinity)
542 * @return Reference to this object
543 */
544 inline OccupancyArray& operator+=(const Vector2& point);
545
546 /**
547 * Removes an image point from this occupancy array.
548 * The bin (if valid) which belongs to the given point is free (not occupied) after the function returns.
549 * @return Reference to this object
550 */
551 inline OccupancyArray& operator-=(const Vector2& point);
552
553 /**
554 * Returns whether a specified bin is occupied.
555 * @param horizontal The horizontal distribution bin, with range [0, horizontalBins() - 1]
556 * @param vertical The vertical distribution bin, with range [0, verticalBins() - 1]
557 * @return True, if so
558 */
559 inline bool operator()(const unsigned int horizontal, const unsigned int vertical) const;
560
561 /**
562 * Returns whether the bin corresponding to a given point is occupied.
563 * @param point The point for which the bin has to be checked, with range (-infinity, infinity)x(-infinity, infinity)
564 * @return True, if so
565 */
566 inline bool operator()(const Vector2& point) const;
567
568 /**
569 * Returns whether a specified bin is occupied.
570 * @param horizontal The horizontal distribution bin, with range [0, horizontalBins() - 1]
571 * @param vertical The vertical distribution bin, with range [0, verticalBins() - 1]
572 * @return Non-zero, if so
573 */
574 inline unsigned int& operator()(const unsigned int horizontal, const unsigned int vertical);
575
576 /**
577 * Returns whether a specified bin is occupied.
578 * @param index The index of the specified bin, with range [0, horizontalBins() * verticalBins() - 1]
579 * @return True, if so
580 */
581 inline bool operator[](const unsigned int index) const;
582
583 /**
584 * Returns whether a specified bin is occupied.
585 * @param index The index of the specified bin, with range [0, horizontalBins() * verticalBins() - 1]
586 * @return Non-zero, if so
587 */
588 inline unsigned int& operator[](const unsigned int index);
589
590 /**
591 * Assign operator.
592 * @param object Occupancy array object to be assigned
593 * @return Reference to this object
594 */
595 inline OccupancyArray& operator=(const OccupancyArray& object);
596
597 /**
598 * Move operator.
599 * @param object Occupancy array object to be moved
600 * @return Reference to this object
601 */
602 inline OccupancyArray& operator=(OccupancyArray&& object) noexcept;
603
604 /**
605 * Returns whether two OccupancyArray objects are identical.
606 * @param occupancyArray The second array object to compare
607 * @return True, if so
608 */
609 inline bool operator==(const OccupancyArray& occupancyArray) const;
610
611 /**
612 * Returns whether two OccupancyArray objects are not identical.
613 * @param occupancyArray The second array object to compare
614 * @return True, if so
615 */
616 inline bool operator!=(const OccupancyArray& occupancyArray) const;
617
618 private:
619
620 /// Occupancy array.
622 };
623
624 /**
625 * Definition of a class holding an index and a distance.
626 */
627 class OCEAN_GEOMETRY_EXPORT DistanceElement
628 {
629 public:
630
631 /**
632 * Creates a new distance element.
633 * @param index Interest index to be stored
634 * @param candidateIndex Index of the candidate to be stored
635 * @param distance The distance to be stored
636 */
637 inline DistanceElement(const unsigned int index, const unsigned int candidateIndex, const Scalar distance);
638
639 /**
640 * Returns the interest index of this element.
641 * @return Stored index
642 */
643 inline unsigned int index() const;
644
645 /**
646 * Returns the candidate index of this element.
647 * @return Stored candidate index
648 */
649 inline unsigned int candidateIndex() const;
650
651 /**
652 * Returns the distance of this element.
653 * @return Stored distance
654 */
655 inline Scalar distance() const;
656
657 /**
658 * Compares two distance elements.
659 * @param left The left element to compare
660 * @param right The right element to compare
661 * @return True, if the left element has a smaller distance value than the right one
662 */
663 static inline bool compareLeftSmaller(const DistanceElement& left, const DistanceElement& right);
664
665 /**
666 * Compares two distance elements.
667 * @param left The left element to compare
668 * @param right The right element to compare
669 * @return True, if the left element has a higher distance value than the right one
670 */
671 static inline bool compareLeftHigher(const DistanceElement& left, const DistanceElement& right);
672
673 /**
674 * Returns whether the left element holds a higher distance than the right one.
675 * @return True, if so
676 */
677 inline bool operator<(const DistanceElement& element) const;
678
679 private:
680
681 /// Interest index.
682 unsigned int index_ = 0u;
683
684 /// Candidate index.
685 unsigned int candidateIndex_ = 0u;
686
687 /// Distance value.
688 Scalar distance_ = Scalar(-1);
689 };
690
691 /**
692 * Definition of a vector holding distance elements.
693 */
694 using DistanceElements = std::vector<DistanceElement>;
695
696 public:
697
698 /**
699 * Calculates the ideal number of horizontal and vertical bins for an array if the overall number of bins is known.
700 * This function tries to get bins with almost identical horizontal and vertical size.
701 * @param width The width of the area the array covers, with range [1, infinity)
702 * @param height The height of the area the array covers, with range [1, infinity)
703 * @param numberBins The number of bins that would be perfect, with range [1, infinity)
704 * @param horizontalBins The resulting number of horizontal bins that fit best with the given parameters, with range [minimalHorizontalBins, width]
705 * @param verticalBins The resulting number of vertical bins that fit best with the given parameters, with range [minimalVerticalBins, height]
706 * @param minimalHorizontalBins The minimal number of horizontal bins, with range [1, width]
707 * @param minimalVerticalBins The minimal number of vertical bins, with range [1, height]
708 */
709 static void idealBins(const unsigned int width, const unsigned int height, const size_t numberBins, unsigned int& horizontalBins, unsigned int& verticalBins, const unsigned int minimalHorizontalBins = 2u, const unsigned int minimalVerticalBins = 2u);
710
711 /**
712 * Calculates the ideal number of horizontal and vertical bins for an array if bin elements within a certain distance should be guaranteed to be located in the 9 neighborhood of that bin
713 * This function tries to get bins with almost identical horizontal and vertical size.
714 * @param width The width of the area the array covers, with range [1, infinity)
715 * @param height The height of the area the array covers, with range [1, infinity)
716 * @param distance The distance to other bin elements that should be guaranteed to be located in the 9 neighborhood, with range [1, infinity)
717 * @param horizontalBins The resulting number of horizontal bins that fit best with the given parameters, with range [minimalHorizontalBins, width]
718 * @param verticalBins The resulting number of vertical bins that fit best with the given parameters, with range [minimalVerticalBins, height]
719 * @param minimalHorizontalBins The minimal number of horizontal bins, with range [1, maximalHorizontalBins]
720 * @param minimalVerticalBins The minimal number of vertical bins, with range [1, maximalVerticalBins]
721 * @param maximalHorizontalBins The maximal number of horizontal bins, with range [minimalHorizontalBins, width]
722 * @param maximalVerticalBins The maximal number of vertical bins, with range [minimalVerticalBins, height]
723 */
724 static void idealBinsNeighborhood9(const unsigned int width, const unsigned int height, const Scalar distance, unsigned int& horizontalBins, unsigned int& verticalBins, const unsigned int minimalHorizontalBins = 2u, const unsigned int minimalVerticalBins = 2u, const unsigned int maximalHorizontalBins = 20u, const unsigned int maximalVerticalBins = 20u);
725
726 /**
727 * Distributes the given 2D image points into a spatial array.
728 * The number of used horizontal and vertical bins are calculated automatically.
729 * Instead of creating a 2D array a 1D array is returned with the first n elements for the top bins and the second n elements for the second top bins and so on.<br>
730 * Image points not fitting into the array bins are discarded.<br>
731 * @param imagePoints Image points to be distributed, may be nullptr if number==0
732 * @param number The number of given image points, with range [0, infinity)
733 * @param left Horizontal position of the area, may be 0 for e.g. an entire image, with range (-infinity, infinity)
734 * @param top Vertical position of the area, may be 0 for e.g. an entire image, with range (-infinity, infinity)
735 * @param width The width of the area holding the elements, with range (0, infinity)
736 * @param height The height of the area holding the elements, with range (0, infinity)
737 * @param averagePointsPerBin Average number of points per bin, with range [1, infinity)
738 * @param maxHorizontalBins Maximal number of horizontal bins, with range [1, infinity)
739 * @param maxVerticalBins Maximal number of vertical bins, with range [1, infinity)
740 * @param horizontalBins Resulting horizontal bins, with range [1, infinity)
741 * @param verticalBins Resulting vertical bins, with range [1, infinity)
742 * @return Resulting array holding the indices of the distributed image points, will be cleared before usage
743 */
744 static inline DistributionArray distributeToArray(const Vector2* imagePoints, const size_t number, const Scalar left, const Scalar top, const Scalar width, const Scalar height, const unsigned int averagePointsPerBin, const unsigned int maxHorizontalBins, const unsigned int maxVerticalBins, unsigned int& horizontalBins, unsigned int& verticalBins);
745
746 /**
747 * Distributes a set of given 2D image points into a spatial array.
748 * Image points not fitting into the array bins are discarded.
749 * @param imagePoints Image points to be distributed, with range (-infinity, infinity)x(-infinity, infinity), may be nullptr if number==0
750 * @param number The number of given image points, with range [0, infinity)
751 * @param left Horizontal position of the area, may be 0 for e.g. an entire image, with range (-infinity, infinity)
752 * @param top Vertical position of the area, may be 0 for e.g. an entire image, with range (-infinity, infinity)
753 * @param width The width of the area holding the points, with range (0, infinity)
754 * @param height The height of the area holding the points, with range (0, infinity)
755 * @param horizontalBins Number of horizontal bins to distribute the image points into, with range [1, infinity)
756 * @param verticalBins Number of vertical bins to distribute the image points into, with range [1, infinity)
757 * @return Resulting array holding the indices of the distributed image points
758 */
759 static DistributionArray distributeToArray(const Vector2* imagePoints, const size_t number, const Scalar left, const Scalar top, const Scalar width, const Scalar height, const unsigned int horizontalBins, const unsigned int verticalBins);
760
761 /**
762 * Distributes the given elements into a spatial array.
763 * Elements not fitting into the array bins are discarded.
764 * @param elements The elements (e.g. holding image points) to be distributed
765 * @param number The number of given image points
766 * @param left Horizontal position of the area, may be 0 for e.g. an entire image, with range (-infinity, infinity)
767 * @param top Vertical position of the area, may be 0 for e.g. an entire image, with range (-infinity, infinity)
768 * @param width The width of the area holding the elements, with range (0, infinity)
769 * @param height The height of the area holding the elements, with range (0, infinity)
770 * @param horizontalBins Number of horizontal bins to distribute the image points into, with range [1, width]
771 * @param verticalBins Number of vertical bins to distribute the image points into, with range [1, height]
772 * @return Resulting array holding the indices of the distributed elements
773 * @tparam T Data type of the given elements
774 * @tparam tFunction Function pointer type of a function returning the 2D position of any element
775 */
776 template <typename T, const Vector2& (*tFunction)(const T&)>
777 static DistributionArray distributeToArray(const T* elements, const size_t number, const Scalar left, const Scalar top, const Scalar width, const Scalar height, const unsigned int horizontalBins, const unsigned int verticalBins);
778
779 /**
780 * Distributes the given 2D image points into a spatial array.
781 * Instead of creating a 2D array a 1D array is returned with the first n elements for the top bins and the second n elements for the second top bins and so on.
782 * Image points not fitting into the array bins are discarded.<br>
783 * @param imagePoints Image points to be distributed
784 * @param number The number of given image points
785 * @param left Horizontal position of the area, may be 0 for e.g. an entire image, with range (-infinity, infinity)
786 * @param top Vertical position of the area, may be 0 for e.g. an entire image, with range (-infinity, infinity)
787 * @param width The width of the area holding the points, with range (0, infinity)
788 * @param height The height of the area holding the points, with range (0, infinity)
789 * @param searchDistance Search distance that will be applied (minimal size of each bin)
790 * @return Resulting array holding the indices of the distributed image points
791 * @tparam tMaximalBins Number of maximal bins in each direction (horizontal and vertical), width range [1, infinity)
792 */
793 template <unsigned int tMaximalBins>
794 static inline DistributionArray distributeToArray(const Vector2* imagePoints, const size_t number, const Scalar left, const Scalar top, const Scalar width, const Scalar height, const Scalar searchDistance);
795
796 /**
797 * Distributes the given 2D image points into a spatial array.
798 * Instead of creating a 2D array a 1D array is returned with the first n elements for the top bins and the second n elements for the second top bins and so on.
799 * Image points not fitting into the array bins are discarded.<br>
800 * @param imagePoints Image points to be distributed, must be valid if the specified number is not zero
801 * @param number The number of given image points, with range [0, infinity)
802 * @param left Horizontal position of the area, may be 0 for e.g. an entire image, with range (-infinity, infinity)
803 * @param top Vertical position of the area, may be 0 for e.g. an entire image, with range (-infinity, infinity)
804 * @param width The width of the area holding the points, with range (0, infinity)
805 * @param height The height of the area holding the points, with range (0, infinity)
806 * @param horizontalBins Number of horizontal bins to distribute the image points into, with range [1, width]
807 * @param verticalBins Number of vertical bins to distribute the image points into, with range [1, height]
808 * @return Resulting array holding the indices of the distributed image points
809 */
810 static OccupancyArray createOccupancyArray(const Vector2* imagePoints, const size_t number, const Scalar left, const Scalar top, const Scalar width, const Scalar height, const unsigned int horizontalBins, const unsigned int verticalBins);
811
812 /**
813 * Filters the given 2D image points according to their distance to neighboring image points.
814 * @param imagePoints Image points (e.g. holding image points) to be filtered
815 * @param number The number of given image points
816 * @param width The width of the area holding the points in pixel, with range [1, infinity)
817 * @param height The height of the area holding the points in pixel, with range [1, infinity)
818 * @param distance The distance threshold to be used for filtering
819 * @return Resulting vector holding the indices of the found image points
820 */
821 static Indices32 filterAccordingDistance(const Vector2* imagePoints, const size_t number, const unsigned int width, const unsigned int height, const Scalar distance);
822
823 /**
824 * Filters the given 2D candidate points according to the distance to the given image points.
825 * @param imagePoints Image points for that the filtered candidate points have to be found
826 * @param numberImagePoints Number of image points
827 * @param candidatePoints Candidate points that will be filtered
828 * @param numberCandidatePoints Number of candidate points
829 * @param width The width of the area holding the image points, with range [1, infinity)
830 * @param height The height of the area holding the image points, with range [1, infinity)
831 * @param filterDistance Distance threshold that define whether a candidate point belongs to one image point
832 * @param filterSize Number of candidate points that can belong to one image point
833 * @param filteredIndices Resulting indices of the filtered candidate points, if defined
834 * @param filteredCandidates Resulting filtered candidate points, if defined
835 */
836 static void filterCandidatePoint(const Vector2* imagePoints, const size_t numberImagePoints, const Vector2* candidatePoints, const size_t numberCandidatePoints, const unsigned int width, const unsigned int height, const Scalar filterDistance, const unsigned int filterSize, Indices32* filteredIndices = nullptr, Vectors2* filteredCandidates = nullptr);
837
838 /**
839 * Sorts the given 2D image points according to their minimal distance to neighboring image points.
840 * Points with higher distances will be returned before points with lower distances.
841 * @param imagePoints Image points (e.g. holding image points) to be sorted
842 * @param number The number of given image points
843 * @param minimalDistanceFirst True, to sort minimal distance to the front
844 * @return Resulting vector holding the indices and distances of the sorted image points
845 */
846 static DistanceElements sortAccordingDistance(const Vector2* imagePoints, const size_t number, const bool minimalDistanceFirst);
847
848 /**
849 * Sorts the given 2D image points according to their minimal distance to neighboring image points.
850 * Points with higher distances will be returned before points with lower distances.
851 * This function first distributes all points to array bins to speed up the computation.<br>
852 * @param imagePoints Image points (e.g. holding image points) to be sorted
853 * @param number The number of given image points
854 * @param width The width of the area holding the image points in pixel, with range [1, infinity)
855 * @param height The height of the area holding the image points in pixel, with range [1, infinity)
856 * @param bins Number of bins in each direction used for image point distribution
857 * @param minimalDistanceFirst True, to sort minimal distance to the front
858 * @return Resulting vector holding the indices and distances of the sorted image points
859 */
860 static DistanceElements sortAccordingDistance(const Vector2* imagePoints, const size_t number, const unsigned int width, const unsigned int height, const unsigned int bins, const bool minimalDistanceFirst);
861
862 /**
863 * Determines the minimal square distance for one given 2D image point to all other points in the same set.
864 * This function uses an already create point distribution to speed up the computation.<br>
865 * Candidates for nearest neighbors are all points lying in the 9-bin-neighborhood of a point, thus the result technically is an approximation and not correct in any case.
866 * @param imagePoints Image points to calculate the distances for
867 * @param numberImagePoints Number of given image points
868 * @param index The index of the image point to find the minimal square distance for, with range [0, numberImagePoints)
869 * @param distributionImagePoints Already created distribution array of the image points
870 * @return Resulting square distances calculated for the given image point
871 */
872 static Scalar determineMinimalSqrDistance(const Vector2* imagePoints, const size_t numberImagePoints, const unsigned int index, const DistributionArray& distributionImagePoints);
873
874 /**
875 * Determines the minimal square distances for each given 2D image point to all other points in the same set.
876 * This function first distributes all points to array bins to speed up the computation.<br>
877 * Candidates for nearest neighbors are all points lying in the 9-bin-neighborhood of a point, thus the result technically is an approximation and not correct in any case.
878 * @param imagePoints Image points to calculate the distances for, may be nullptr if numberImagePoints==0
879 * @param numberImagePoints Number of given image points, with range [0, infinity)
880 * @param width The width of the area holding the image points in pixel, with range [1, infinity)
881 * @param height The height of the area holding the image points in pixel, with range [1, infinity)
882 * @param bins Number of bins in each direction used for image point distribution, with range [1, infinity)
883 * @param sqrDistances Resulting square distances calculated for each given image point, make sure that this buffer holds enough space
884 */
885 static void determineMinimalSqrDistances(const Vector2* imagePoints, const size_t numberImagePoints, const unsigned int width, const unsigned int height, const unsigned int bins, Scalar* sqrDistances);
886
887 /**
888 * Determines the minimal square distances for each given 2D image point to another given set of 2D image points.
889 * This function first distributes all points to array bins to speed up the computation.<br>
890 * Candidates for nearest neighbors are all points lying in the 9-bin-neighborhood of a point, thus the result technically is an approximation and not correct in any case.
891 * @param imagePoints Image points to calculate the distances for, may be nullptr if numberImagePoints==0
892 * @param numberImagePoints Number of given image points, with range [0, infinity)
893 * @param candidates Image points being candidates as nearest neighbors for the given image points
894 * @param numberCandidates Number of given candidates
895 * @param width The width of the area holding the image points in pixel, with range [1, infinity)
896 * @param height The height of the area holding the image points in pixel, with range [1, infinity)
897 * @param bins Number of bins in each direction used for image point distribution
898 * @param sqrDistances Resulting square distances calculated for each given image point, make sure that this buffer holds enough space
899 */
900 static void determineMinimalSqrDistances(const Vector2* imagePoints, const size_t numberImagePoints, const Vector2* candidates, const size_t numberCandidates, const unsigned int width, const unsigned int height, const unsigned int bins, Scalar* sqrDistances);
901
902 /**
903 * Determines the minimal square distances for each given image point to another given set of image points.
904 * Candidates for nearest neighbors are all points lying in the 9-bin-neighborhood of a point, thus the result technically is an approximation and not correct in any case.
905 * @param imagePoints Image points to calculate the distances for, may be nullptr if numberImagePoints==0
906 * @param numberImagePoints Number of given image points, with range [0, infinity)
907 * @param candidates Image points being candidates as nearest neighbors for the given image points
908 * @param numberCandidates Number of given candidates
909 * @param distributionCandidates Already created distribution array of the candidates
910 * @param sqrDistances Resulting square distances calculated for each given element, make sure that this buffer holds enough space
911 * @param candidateIndices Optional resulting indices of the candidate with minimal distance, make sure that this buffer holds enough space (if defined)
912 */
913 static void determineMinimalSqrDistances(const Vector2* imagePoints, const size_t numberImagePoints, const Vector2* candidates, const size_t numberCandidates, const DistributionArray& distributionCandidates, Scalar* sqrDistances, unsigned int* candidateIndices = nullptr);
914
915 /**
916 * Determines the minimal square distances for each specified image point inside their neighborhood.
917 * This function first distributes all image points to array bins to speed up the computation.<br>
918 * Candidates for nearest neighbors are all points lying in the 9-bin-neighborhood of a point, thus the result technically is an approximation and not correct in any case.
919 * @param imagePoints Image points holding the entire set, may be nullptr if numberImagePoints==0
920 * @param numberImagePoints Number of given image points, with range [0, infinity)
921 * @param interestIndices Indices of all interest image points to calculate the minimal distance for
922 * @param numberInterestIndices Number of given interest indices
923 * @param width The width of the area holding the elements in pixel, with range [1, infinity)
924 * @param height The height of the area holding the elements in pixel, with range [1, infinity)
925 * @param bins Number of bins in each direction used for element distribution
926 * @param sqrDistances Resulting square distances calculated for each given interest index, make sure that this buffer holds enough space
927 */
928 static void determineMinimalSqrDistances(const Vector2* imagePoints, const size_t numberImagePoints, const unsigned int* interestIndices, const size_t numberInterestIndices, const unsigned int width, const unsigned int height, const unsigned int bins, Scalar* sqrDistances);
929
930 /**
931 * Determines all candidate points for a given image point (interest point) lying inside a specified circle around the interest point.
932 * @param imagePoint The interest image point to find the neighboring candidate points for, with range (-infinity, infinity)x(-infinity, infinity)
933 * @param candidatePoints Candidate points to find the neighbors in
934 * @param numberCandidatePoints Number of given candidate points
935 * @param radius The radius specifying the circle around the interest point, with range [0, infinity)
936 * @param distributionCandidatePoints Already created distribution array of the candidate points
937 * @return Resulting indices of all neighbors out the candidate set lying within the specified circle.
938 */
939 static Indices32 determineNeighbors(const Vector2& imagePoint, const Vector2* candidatePoints, const size_t numberCandidatePoints, const Scalar radius, const DistributionArray& distributionCandidatePoints);
940
941 /**
942 * Determines the nearest image point between an interest point and a set of given image point lying inside a specified circle around the interest point.
943 * @param interestPoint The interest image point for which the nearest neighbor will be determined, with range (-infinity, infinity)x(-infinity, infinity)
944 * @param imagePoints The set of image points from which the nearest neighbor will be determined
945 * @param numberImagePoints Number of given image points, with range [0, infinity)
946 * @param radius The radius specifying the circle around the interest point, with range [0, infinity)
947 * @param distributionImagePoints Already created distribution array of the image points
948 * @param sqrDistance Optional resulting square distance of the nearest image point, if any
949 * @return Resulting index of the nearest neighbor image point, -1 if no image point lies within the specified radius
950 */
951 static Index32 determineNearestNeighbor(const Vector2& interestPoint, const Vector2* imagePoints, const size_t numberImagePoints, const Scalar radius, const DistributionArray& distributionImagePoints, Scalar* sqrDistance = nullptr);
952
953 /**
954 * Distributes the given image points into an array of specified size and returns (at most) one point from each bin.
955 * @param imagePoints Image points to be distributed and filtered, may be nullptr if numberImagePoints==0
956 * @param numberImagePoints Number of given image points, with range [0, infinity)
957 * @param left Horizontal position of the area, may be 0 for e.g. an entire image, with range (-infinity, infinity)
958 * @param top Vertical position of the area, may be 0 for e.g. an entire image, with range (-infinity, infinity)
959 * @param width The width of the area holding the elements, with range (0, infinity)
960 * @param height The height of the area holding the elements, with range (0, infinity)
961 * @param horizontalBins Number of horizontal bins to be used for distribution, with range [1, infinity)
962 * @param verticalBins Number of vertical bins to be used for distribution, with range [1, infinity)
963 * @return Resulting filtered elements
964 */
965 static inline Vectors2 distributeAndFilter(const Vector2* imagePoints, const size_t numberImagePoints, const Scalar left, const Scalar top, const Scalar width, const Scalar height, const unsigned int horizontalBins, const unsigned int verticalBins);
966
967 /**
968 * Distributes the given image points into an array of specified size and returns as much points as requested by first selecting the first point from each bin, then the second point from each bin, and so on.
969 * @param imagePoints Image points to be distributed and filtered, may be nullptr if numberImagePoints==0
970 * @param numberImagePoints Number of given image points, with range [0, infinity)
971 * @param left Horizontal position of the area, may be 0 for e.g. an entire image, with range (-infinity, infinity)
972 * @param top Vertical position of the area, may be 0 for e.g. an entire image, with range (-infinity, infinity)
973 * @param width The width of the area holding the elements, with range (0, infinity)
974 * @param height The height of the area holding the elements, with range (0, infinity)
975 * @param horizontalBins Number of horizontal bins to be used for distribution, with range [1, infinity)
976 * @param verticalBins Number of vertical bins to be used for distribution, with range [1, infinity)
977 * @param size The number of requested feature points, with range [0, numberImagePoints]
978 * @return Resulting filtered elements
979 */
980 static Vectors2 distributeAndFilter(const Vector2* imagePoints, const size_t numberImagePoints, const Scalar left, const Scalar top, const Scalar width, const Scalar height, const unsigned int horizontalBins, const unsigned int verticalBins, const size_t size);
981
982 /**
983 * Distributes the given image points into an array of specified size and returns (at most) one point index from each bin.
984 * The resulting indices can be used to filter the actual set of image points.<br>
985 * @param imagePoints Image points to be distributed and filtered, may be nullptr if numberImagePoints==0
986 * @param numberImagePoints Number of given image points, with range [0, infinity)
987 * @param left Horizontal position of the area, may be 0 for e.g. an entire image, with range (-infinity, infinity)
988 * @param top Vertical position of the area, may be 0 for e.g. an entire image, with range (-infinity, infinity)
989 * @param width The width of the area holding the elements, with range (0, infinity)
990 * @param height The height of the area holding the elements, with range (0, infinity)
991 * @param horizontalBins Number of horizontal bins to be used for distribution, with range [1, infinity)
992 * @param verticalBins Number of vertical bins to be used for distribution, with range [1, infinity)
993 * @return Resulting indices of the filtered elements
994 * @tparam TIndex The data type of the indices (e.g., may be Index32 or Index64)
995 */
996 template <typename TIndex>
997 static inline std::vector<TIndex> distributeAndFilterIndices(const Vector2* imagePoints, const size_t numberImagePoints, const Scalar left, const Scalar top, const Scalar width, const Scalar height, const unsigned int horizontalBins, const unsigned int verticalBins);
998
999 /**
1000 * Distributes the given elements into an array of specified size and returns (at most) one element from each bin.
1001 * @param elements The elements to be distributed and filtered, may be nullptr if numberImagePoints==0
1002 * @param numberElements Number of given elements, with range [0, infinity)
1003 * @param left Horizontal position of the area, may be 0 for e.g. an entire image, with range (-infinity, infinity)
1004 * @param top Vertical position of the area, may be 0 for e.g. an entire image, with range (-infinity, infinity)
1005 * @param width The width of the area holding the elements, with range (0, infinity)
1006 * @param height The height of the area holding the elements, with range (0, infinity)
1007 * @param horizontalBins Number of horizontal bins to be used for distribution, with range [1, infinity)
1008 * @param verticalBins Number of vertical bins to be used for distribution, with range [1, infinity)
1009 * @return Resulting filtered elements
1010 * @tparam T The data type of the elements to be distributed
1011 * @tparam tFunction The function pointer that returns the 2D position of each element
1012 */
1013 template <typename T, Vector2 (*tFunction)(const T&)>
1014 static std::vector<T> distributeAndFilter(const T* elements, const size_t numberElements, const Scalar left, const Scalar top, const Scalar width, const Scalar height, const unsigned int horizontalBins, const unsigned int verticalBins);
1015
1016 /**
1017 * Distributes the given elements into an array of specified size but returns as much elements per bin necessary to reach the specified amount of desired elements.
1018 * This function should be used whenever the given elements are not distributed equally while a specified amount of feature points is desired.
1019 * The function applies several filter iterations until the desired number of elements is reached.<br>
1020 * After the first iteration each bin will contain at most one element, after the second iteration at most two elements, and so on.
1021 * @param elements The elements to be distributed and filtered, may be nullptr if numberImagePoints==0
1022 * @param numberElements Number of given elements, with range [0, infinity)
1023 * @param left Horizontal position of the area, may be 0 for e.g. an entire image, with range (-infinity, infinity)
1024 * @param top Vertical position of the area, may be 0 for e.g. an entire image, with range (-infinity, infinity)
1025 * @param width The width of the area holding the elements, with range (0, infinity)
1026 * @param height The height of the area holding the elements, with range (0, infinity)
1027 * @param horizontalBins Number of horizontal bins to be used for distribution, with range [1, infinity)
1028 * @param verticalBins Number of vertical bins to be used for distribution, with range [1, infinity)
1029 * @param numberDesiredFilteredElements The desired number of filtered elements, with range [1, numberElements]
1030 * @param indices Optional resulting indices of the selected keypoints, if defined indices will be pushed at the back.
1031 * @return Resulting filtered elements
1032 * @tparam T The data type of the elements to be distributed
1033 * @tparam tFunction The function pointer that returns the 2D position of each element
1034 */
1035 template <typename T, Vector2 (*tFunction)(const T&)>
1036 static std::vector<T> distributeAndFilter(const T* elements, const size_t numberElements, const Scalar left, const Scalar top, const Scalar width, const Scalar height, const unsigned int horizontalBins, const unsigned int verticalBins, const size_t numberDesiredFilteredElements, Indices32 *indices = nullptr);
1037
1038 /**
1039 * Distributes the given elements into an array of specified size and returns (at most) one point index from each bin.
1040 * The resulting indices can be used to filter the actual set of image points.<br>
1041 * @param elements The elements to be distributed and filtered, may be nullptr if numberImagePoints==0
1042 * @param numberElements Number of given elements, with range [0, infinity)
1043 * @param left Horizontal position of the area, may be 0 for e.g. an entire image, with range (-infinity, infinity)
1044 * @param top Vertical position of the area, may be 0 for e.g. an entire image, with range (-infinity, infinity)
1045 * @param width The width of the area holding the elements, with range (0, infinity)
1046 * @param height The height of the area holding the elements, with range (0, infinity)
1047 * @param horizontalBins Number of horizontal bins to be used for distribution, with range [1, infinity)
1048 * @param verticalBins Number of vertical bins to be used for distribution, with range [1, infinity)
1049 * @return Resulting indices of the filtered elements
1050 * @tparam T The data type of the elements to be distributed
1051 * @tparam TIndex The data type of the indices (e.g., may be Index32 or Index64)
1052 * @tparam tFunction The function pointer that returns the 2D position of each element
1053 */
1054 template <typename T, typename TIndex, Vector2 (*tFunction)(const T&)>
1055 static std::vector<TIndex> distributeAndFilterIndices(const T* elements, const size_t numberElements, const Scalar left, const Scalar top, const Scalar width, const Scalar height, const unsigned int horizontalBins, const unsigned int verticalBins);
1056
1057 protected:
1058
1059 /**
1060 * This function simply returns the given object (actually a copy of the object).
1061 * @param value The value to be returned
1062 * @return The given value
1063 * @tparam T The data type of the value
1064 */
1065 template <typename T>
1066 static inline T identity(const T& value);
1067};
1068
1069inline SpatialDistribution::Array::Array(Array&& object) noexcept :
1070 areaLeft_(object.areaLeft_),
1071 areaTop_(object.areaTop_),
1072 areaWidth_(object.areaWidth_),
1073 areaHeight_(object.areaHeight_),
1074 horizontalBins_(object.horizontalBins_),
1075 verticalBins_(object.verticalBins_),
1076 horizontalPoint2Bin_(object.horizontalPoint2Bin_),
1077 verticalPoint2Bin_(object.verticalPoint2Bin_)
1078{
1079 object.areaLeft_ = Scalar(0);
1080 object.areaTop_ = Scalar(0);
1081 object.areaWidth_ = Scalar(0);
1082 object.areaHeight_ = Scalar(0);
1083 object.horizontalBins_ = 0u;
1084 object.verticalBins_ = 0u;
1085 object.horizontalPoint2Bin_ = Scalar(0);
1086 object.verticalPoint2Bin_ = Scalar(0);
1087}
1088
1089inline SpatialDistribution::Array::Array(const Scalar left, const Scalar top, const Scalar width, const Scalar height, const unsigned int horizontalBins, const unsigned int verticalBins) :
1090 areaLeft_(left),
1091 areaTop_(top),
1092 areaWidth_(width),
1093 areaHeight_(height),
1094 horizontalBins_(horizontalBins),
1095 verticalBins_(verticalBins),
1096 horizontalPoint2Bin_(width > Numeric::eps() ? (Scalar(horizontalBins) / (Scalar(width) + Numeric::eps())) : Scalar(0)),
1097 verticalPoint2Bin_(height > Numeric::eps() ? (Scalar(verticalBins) / (Scalar(height) + Numeric::eps())) : Scalar(0))
1098{
1099 ocean_assert(width > Numeric::eps() && height > Numeric::eps());
1100}
1101
1103{
1104 return areaLeft_;
1105}
1106
1108{
1109 return areaTop_;
1110}
1111
1113{
1114 return areaWidth_;
1115}
1116
1118{
1119 return areaHeight_;
1120}
1121
1123{
1124 return horizontalBins_;
1125}
1126
1128{
1129 return verticalBins_;
1130}
1131
1132inline unsigned int SpatialDistribution::Array::bins() const
1133{
1134 return horizontalBins_ * verticalBins_;
1135}
1136
1137inline unsigned int SpatialDistribution::Array::index(const Scalar x, const Scalar y) const
1138{
1139 const int xBin = horizontalBin(x);
1140 const int yBin = verticalBin(y);
1141
1142 ocean_assert(xBin >= 0 && xBin < int(horizontalBins_));
1143 ocean_assert(yBin >= 0 && yBin < int(verticalBins_));
1144
1145 return yBin * horizontalBins_ + xBin;
1146}
1147
1149{
1150 // for positive values we could avoid to use floor(), however for negative values we e.g., need -0.2 to be -1
1151 return int(Numeric::floor((x - areaLeft_) * horizontalPoint2Bin_));
1152}
1153
1155{
1156 // for positive values we could avoid to use floor(), however for negative values we e.g., need -0.2 to be -1
1157 return int(Numeric::floor((y - areaTop_) * verticalPoint2Bin_));
1158}
1159
1161{
1162 ocean_assert(isValid());
1163 return minmax<int>(0, horizontalBin(x), horizontalBins_ - 1);
1164}
1165
1167{
1168 ocean_assert(isValid());
1169 return minmax<int>(0, verticalBin(y), verticalBins_ - 1);
1170}
1171
1172template <unsigned int tRadius>
1173inline unsigned int SpatialDistribution::Array::beginBinHorizontal(const unsigned int centerBinX) const
1174{
1175 static_assert(tRadius >= 1u, "Invalid radius");
1176
1177 ocean_assert(centerBinX < horizontalBins_);
1178
1179 return centerBinX >= tRadius ? centerBinX - tRadius : 0u;
1180}
1181
1182template <unsigned int tRadius>
1183inline unsigned int SpatialDistribution::Array::endBinHorizontal(const unsigned int centerBinX) const
1184{
1185 static_assert(tRadius >= 1u, "Invalid radius");
1186
1187 ocean_assert(centerBinX < horizontalBins_);
1188
1189 return std::min(centerBinX + tRadius + 1u, horizontalBins_);
1190}
1191
1192template <unsigned int tRadius>
1193inline unsigned int SpatialDistribution::Array::beginBinVertical(const unsigned int centerBinY) const
1194{
1195 static_assert(tRadius >= 1u, "Invalid radius");
1196
1197 ocean_assert(centerBinY < verticalBins_);
1198
1199 return centerBinY >= tRadius ? centerBinY - tRadius : 0u;
1200}
1201
1202template <unsigned int tRadius>
1203inline unsigned int SpatialDistribution::Array::endBinVertical(const unsigned int centerBinY) const
1204{
1205 static_assert(tRadius >= 1u, "Invalid radius");
1206
1207 ocean_assert(centerBinY < verticalBins_);
1208
1209 return std::min(centerBinY + tRadius + 1u, verticalBins_);
1210}
1211
1213{
1214 return horizontalBins_ != 0u && verticalBins_ != 0u;
1215}
1216
1217inline bool SpatialDistribution::Array::operator==(const Array& right) const
1218{
1219 return areaLeft_ == right.areaLeft_
1220 && areaTop_ == right.areaTop_
1221 && areaWidth_ == right.areaWidth_
1222 && areaHeight_ == right.areaHeight_
1223 && horizontalBins_ == right.horizontalBins_
1224 && verticalBins_ == right.verticalBins_
1225 && horizontalPoint2Bin_ == right.horizontalPoint2Bin_
1226 && verticalPoint2Bin_ == right.verticalPoint2Bin_;
1227}
1228
1229inline bool SpatialDistribution::Array::operator!=(const Array& right) const
1230{
1231 return !(*this == right);
1232}
1233
1234inline SpatialDistribution::Array::operator bool() const
1235{
1236 return isValid();
1237}
1238
1240{
1241 if (this != &object)
1242 {
1243 areaLeft_ = object.areaLeft_;
1244 areaTop_ = object.areaTop_;
1245 areaWidth_ = object.areaWidth_;
1246 areaHeight_ = object.areaHeight_;
1247 horizontalBins_ = object.horizontalBins_;
1248 verticalBins_ = object.verticalBins_;
1249 horizontalPoint2Bin_ = object.horizontalPoint2Bin_;
1250 verticalPoint2Bin_ = object.verticalPoint2Bin_;
1251 }
1252
1253 return *this;
1254}
1255
1257{
1258 if (this != &object)
1259 {
1260 areaLeft_ = object.areaLeft_;
1261 areaTop_ = object.areaTop_;
1262 areaWidth_ = object.areaWidth_;
1263 areaHeight_ = object.areaHeight_;
1264 horizontalBins_ = object.horizontalBins_;
1265 verticalBins_ = object.verticalBins_;
1266 horizontalPoint2Bin_ = object.horizontalPoint2Bin_;
1267 verticalPoint2Bin_ = object.verticalPoint2Bin_;
1268
1269 object.areaLeft_ = Scalar(0);
1270 object.areaTop_ = Scalar(0);
1271 object.areaWidth_ = Scalar(0);
1272 object.areaHeight_ = Scalar(0);
1273 object.horizontalBins_ = 0u;
1274 object.verticalBins_ = 0u;
1275 object.horizontalPoint2Bin_ = Scalar(0);
1276 object.verticalPoint2Bin_ = Scalar(0);
1277 }
1278
1279 return *this;
1280}
1281
1283 Array(object),
1284 indexGroups_(std::move(object.indexGroups_)),
1285 hasCopiedNeighborhood8_(object.hasCopiedNeighborhood8_)
1286{
1287 object = DistributionArray();
1288}
1289
1290inline SpatialDistribution::DistributionArray::DistributionArray(const Scalar left, const Scalar top, const Scalar width, const Scalar height, const unsigned int horizontalBins, const unsigned int verticalBins) :
1291 Array(left, top, width, height, horizontalBins, verticalBins),
1292 indexGroups_(horizontalBins * verticalBins),
1293 hasCopiedNeighborhood8_(false)
1294{
1295 // nothing to do here
1296}
1297
1299{
1300 return hasCopiedNeighborhood8_;
1301}
1302
1303inline const Indices32& SpatialDistribution::DistributionArray::operator()(const unsigned int horizontal, const unsigned int vertical) const
1304{
1305 ocean_assert(horizontal < horizontalBins_);
1306 ocean_assert(vertical < verticalBins_);
1307
1308 return indexGroups_[vertical * horizontalBins_ + horizontal];
1309}
1310
1311inline Indices32& SpatialDistribution::DistributionArray::operator()(const unsigned int horizontal, const unsigned int vertical)
1312{
1313 ocean_assert(horizontal < horizontalBins_);
1314 ocean_assert(vertical < verticalBins_);
1315
1316 return indexGroups_[vertical * horizontalBins_ + horizontal];
1317}
1318
1319inline const Indices32& SpatialDistribution::DistributionArray::operator[](const unsigned int index) const
1320{
1321 ocean_assert(index < horizontalBins_ * verticalBins_);
1322 return indexGroups_[index];
1323}
1324
1326{
1327 ocean_assert(index < horizontalBins_ * verticalBins_);
1328 return indexGroups_[index];
1329}
1330
1332{
1333 Array::operator=((Array&)object);
1334 indexGroups_ = object.indexGroups_;
1335 hasCopiedNeighborhood8_ = object.hasCopiedNeighborhood8_;
1336
1337 return *this;
1338}
1339
1341{
1342 if (this != &object)
1343 {
1344 Array::operator=(std::move((Array&)object));
1345 indexGroups_ = std::move(object.indexGroups_);
1346 hasCopiedNeighborhood8_ = object.hasCopiedNeighborhood8_;
1347
1348 object.hasCopiedNeighborhood8_ = false;
1349 }
1350
1351 return *this;
1352}
1353
1355{
1356 if (!Array::operator==(distributionArray))
1357 {
1358 return false;
1359 }
1360
1361 return indexGroups_ == distributionArray.indexGroups_ && hasCopiedNeighborhood8_ == distributionArray.hasCopiedNeighborhood8_;
1362}
1363
1365{
1366 return !(*this == distributionArray);
1367}
1368
1370 Array(std::move((Array&)object)),
1371 occupancy_(std::move(object.occupancy_))
1372{
1373 // nothing to do here
1374}
1375
1376inline SpatialDistribution::OccupancyArray::OccupancyArray(const Box2& boundingBox, const unsigned int horizontalBins, const unsigned int verticalBins, const bool allFree) :
1377 Array(boundingBox.left(), boundingBox.top(), boundingBox.width(), boundingBox.height(), horizontalBins, verticalBins),
1378 occupancy_(horizontalBins * verticalBins, allFree ? 0u : 1u)
1379{
1380 ocean_assert(NumericT<unsigned int>::isInsideValueRange(uint64_t(horizontalBins) * uint64_t(verticalBins)));
1381}
1382
1383inline SpatialDistribution::OccupancyArray::OccupancyArray(const Scalar left, const Scalar top, const Scalar width, const Scalar height, const unsigned int horizontalBins, const unsigned int verticalBins, const bool allFree) :
1384 Array(left, top, width, height, horizontalBins, verticalBins),
1385 occupancy_(horizontalBins * verticalBins, allFree ? 0u : 1u)
1386{
1387 ocean_assert(NumericT<unsigned int>::isInsideValueRange(uint64_t(horizontalBins) * uint64_t(verticalBins)));
1388}
1389
1390inline unsigned int SpatialDistribution::OccupancyArray::countOccupiedNeighborhood9(const unsigned int horizontal, const unsigned int vertical) const
1391{
1392 ocean_assert(horizontal < horizontalBins_);
1393 ocean_assert(vertical < verticalBins_);
1394
1395 unsigned int number = 0u;
1396
1397 for (unsigned int y = max(0, int(vertical) - 1); y < min(vertical + 2u, verticalBins_); ++y)
1398 {
1399 for (unsigned int x = max(0, int(horizontal) - 1); x < min(horizontal + 2u, horizontalBins_); ++x)
1400 {
1401 if ((*this)(x, y))
1402 {
1403 number++;
1404 }
1405 }
1406 }
1407
1408 return number;
1409}
1410
1411inline bool SpatialDistribution::OccupancyArray::isOccupiedNeighborhood9(const unsigned int horizontal, const unsigned int vertical) const
1412{
1413 ocean_assert(horizontal < horizontalBins_);
1414 ocean_assert(vertical < verticalBins_);
1415
1416 for (unsigned int y = max(0, int(vertical) - 1); y < min(vertical + 2u, verticalBins_); ++y)
1417 {
1418 for (unsigned int x = max(0, int(horizontal) - 1); x < min(horizontal + 2u, horizontalBins_); ++x)
1419 {
1420 if ((*this)(x, y))
1421 {
1422 return true;
1423 }
1424 }
1425 }
1426
1427 return false;
1428}
1429
1431{
1432 const unsigned int horizontal = horizontalBin(point.x());
1433 const unsigned int vertical = verticalBin(point.y());
1434
1435 if (horizontal < horizontalBins_ && vertical < verticalBins_)
1436 {
1437 for (unsigned int y = max(0, int(vertical) - 1); y < min(vertical + 2u, verticalBins_); ++y)
1438 {
1439 for (unsigned int x = max(0, int(horizontal) - 1); x < min(horizontal + 2u, horizontalBins_); ++x)
1440 {
1441 if ((*this)(x, y))
1442 {
1443 return true;
1444 }
1445 }
1446 }
1447 }
1448
1449 return false;
1450}
1451
1452inline bool SpatialDistribution::OccupancyArray::isNotOccupiedNeighborhood9(const unsigned int horizontal, const unsigned int vertical) const
1453{
1454 ocean_assert(horizontal < horizontalBins_);
1455 ocean_assert(vertical < verticalBins_);
1456
1457 for (unsigned int y = max(0, int(vertical) - 1); y < min(vertical + 2u, verticalBins_); ++y)
1458 {
1459 for (unsigned int x = max(0, int(horizontal) - 1); x < min(horizontal + 2u, horizontalBins_); ++x)
1460 {
1461 if (!(*this)(x, y))
1462 {
1463 return true;
1464 }
1465 }
1466 }
1467
1468 return false;
1469}
1470
1472{
1473 const unsigned int horizontal = horizontalBin(point.x());
1474 const unsigned int vertical = verticalBin(point.y());
1475
1476 if (horizontal < horizontalBins_ && vertical < verticalBins_)
1477 {
1478 for (unsigned int y = max(0, int(vertical) - 1); y < min(vertical + 2u, verticalBins_); ++y)
1479 {
1480 for (unsigned int x = max(0, int(horizontal) - 1); x < min(horizontal + 2u, horizontalBins_); ++x)
1481 {
1482 if (!(*this)(x, y))
1483 {
1484 return true;
1485 }
1486 }
1487 }
1488 }
1489
1490 return false;
1491}
1492
1494{
1495 unsigned int count = 0u;
1496
1497 for (const Index32& bin : occupancy_)
1498 {
1499 if (bin != 0u)
1500 {
1501 ++count;
1502 }
1503 }
1504
1505 return count;
1506}
1507
1509{
1510 unsigned int count = 0u;
1511
1512 for (const Index32& bin : occupancy_)
1513 {
1514 if (bin == 0u)
1515 {
1516 ++count;
1517 }
1518 }
1519
1520 return count;
1521}
1522
1524{
1525 const unsigned int horizontal = (unsigned int)(horizontalBin(point.x()));
1526 const unsigned int vertical = (unsigned int)(verticalBin(point.y()));
1527
1528 if (horizontal < horizontalBins_ && vertical < verticalBins_)
1529 {
1530 const unsigned int index = vertical * horizontalBins_ + horizontal;
1531
1532 if (!occupancy_[index])
1533 {
1534 occupancy_[index] = 1u;
1535 return true;
1536 }
1537 }
1538
1539 return false;
1540}
1541
1542inline bool SpatialDistribution::OccupancyArray::addPointWithCounter(const Vector2& point, const unsigned int maximalOccupancyCounter)
1543{
1544 const unsigned int horizontal = (unsigned int)(horizontalBin(point.x()));
1545 const unsigned int vertical = (unsigned int)(verticalBin(point.y()));
1546
1547 if (horizontal < horizontalBins_ && vertical < verticalBins_)
1548 {
1549 const unsigned int index = vertical * horizontalBins_ + horizontal;
1550
1551 if (occupancy_[index] <= maximalOccupancyCounter)
1552 {
1553 occupancy_[index]++;
1554 return true;
1555 }
1556 }
1557
1558 return false;
1559}
1560
1562{
1563 const unsigned int horizontal = (unsigned int)(horizontalBin(point.x()));
1564 const unsigned int vertical = (unsigned int)(verticalBin(point.y()));
1565
1566 if (horizontal < horizontalBins_ && vertical < verticalBins_)
1567 {
1568 const unsigned int index = vertical * horizontalBins_ + horizontal;
1569
1570 if (occupancy_[index])
1571 {
1572 occupancy_[index] = 0u;
1573 return true;
1574 }
1575 }
1576
1577 return false;
1578}
1579
1581{
1582 std::fill(occupancy_.begin(), occupancy_.end(), 0u);
1583}
1584
1586{
1587 const unsigned int horizontal = (unsigned int)(horizontalBin(point.x()));
1588 const unsigned int vertical = (unsigned int)(verticalBin(point.y()));
1589
1590 if (horizontal < horizontalBins_ && vertical < verticalBins_)
1591 {
1592 occupancy_[vertical * horizontalBins_ + horizontal] = 1u;
1593 }
1594
1595 return *this;
1596}
1597
1599{
1600 const unsigned int horizontal = (unsigned int)(horizontalBin(point.x()));
1601 const unsigned int vertical = (unsigned int)(verticalBin(point.y()));
1602
1603 if (horizontal < horizontalBins_ && vertical < verticalBins_)
1604 {
1605 occupancy_[vertical * horizontalBins_ + horizontal] = 0u;
1606 }
1607
1608 return *this;
1609}
1610
1611inline bool SpatialDistribution::OccupancyArray::operator()(const unsigned int horizontal, const unsigned int vertical) const
1612{
1613 ocean_assert(horizontal < horizontalBins_);
1614 ocean_assert(vertical < verticalBins_);
1615
1616 return occupancy_[vertical * horizontalBins_ + horizontal] != 0u;
1617}
1618
1619inline unsigned int& SpatialDistribution::OccupancyArray::operator()(const unsigned int horizontal, const unsigned int vertical)
1620{
1621 ocean_assert(horizontal < horizontalBins_);
1622 ocean_assert(vertical < verticalBins_);
1623
1624 return occupancy_[vertical * horizontalBins_ + horizontal];
1625}
1626
1628{
1629 const unsigned int xBin = horizontalBin(point.x());
1630 const unsigned int yBin = verticalBin(point.y());
1631
1632 return xBin < horizontalBins_ && yBin < verticalBins_ && occupancy_[yBin * horizontalBins_ + xBin] != 0u;
1633}
1634
1635inline bool SpatialDistribution::OccupancyArray::operator[](const unsigned int index) const
1636{
1637 ocean_assert(index < horizontalBins_ * verticalBins_);
1638 return occupancy_[index] != 0u;
1639}
1640
1641inline unsigned int& SpatialDistribution::OccupancyArray::operator[](const unsigned int index)
1642{
1643 ocean_assert(index < horizontalBins_ * verticalBins_);
1644 return occupancy_[index];
1645}
1646
1648{
1649 Array::operator=((Array&)object);
1650 occupancy_ = object.occupancy_;
1651
1652 return *this;
1653}
1654
1656{
1657 if (this != &object)
1658 {
1659 Array::operator=(std::move((Array&)object));
1660 occupancy_ = std::move(object.occupancy_);
1661 }
1662
1663 return *this;
1664}
1665
1667{
1668 if (!Array::operator==(occupancyArray))
1669 {
1670 return false;
1671 }
1672
1673 return occupancy_ == occupancyArray.occupancy_;
1674}
1675
1677{
1678 return !(*this == occupancyArray);
1679}
1680
1681inline SpatialDistribution::DistanceElement::DistanceElement(const unsigned int index, const unsigned int candidateIndex, const Scalar distance) :
1682 index_(index),
1683 candidateIndex_(candidateIndex),
1684 distance_(distance)
1685{
1686 // nothing to do here
1687}
1688
1690{
1691 return index_;
1692}
1693
1695{
1696 return candidateIndex_;
1697}
1698
1700{
1701 return distance_;
1702}
1703
1705{
1706 return left.distance_ < right.distance_;
1707}
1708
1710{
1711 return left.distance_ > right.distance_;
1712}
1713
1715{
1716 // ** TODO** this mismatch between comparison operators should be fixed
1717
1718 return distance_ > element.distance_;
1719}
1720
1721template <unsigned int tMaximalBins>
1722inline SpatialDistribution::DistributionArray SpatialDistribution::distributeToArray(const Vector2* imagePoints, const size_t number, const Scalar left, const Scalar top, const Scalar width, const Scalar height, const Scalar searchDistance)
1723{
1724 static_assert(tMaximalBins > 0u, "Invalid maximal bin parameter!");
1725
1726 const unsigned int horizontalBins = min(tMaximalBins, (unsigned int)Numeric::ceil(width / max(searchDistance, Scalar(2))));
1727 const unsigned int verticalBins = min(tMaximalBins, (unsigned int)Numeric::ceil(height / max(searchDistance, Scalar(2))));
1728
1729 return distributeToArray(imagePoints, number, left, top, width, height, horizontalBins, verticalBins);
1730}
1731
1732template <typename T, const Vector2& (*tFunction)(const T&)>
1733SpatialDistribution::DistributionArray SpatialDistribution::distributeToArray(const T* elements, const size_t number, const Scalar left, const Scalar top, const Scalar width, const Scalar height, const unsigned int horizontalBins, const unsigned int verticalBins)
1734{
1735 ocean_assert(elements);
1736 ocean_assert(width > 0 && height > 0);
1737
1738 ocean_assert(horizontalBins > 0);
1739 ocean_assert(verticalBins > 0);
1740
1741 ocean_assert(Scalar(horizontalBins) <= width);
1742 ocean_assert(Scalar(verticalBins) <= height);
1743
1744 // reserve enough array elements
1745 DistributionArray indexArray(left, top, width, height, horizontalBins, verticalBins);
1746
1747 for (size_t n = 0; n < number; ++n)
1748 {
1749 const Vector2& point = tFunction(*elements);
1750
1751 const unsigned int horizontal = (unsigned int)(indexArray.horizontalBin(point.x()));
1752 const unsigned int vertical = (unsigned int)(indexArray.verticalBin(point.y()));
1753
1754 // discard points with negative bin value or bin value larger than the smallest allowed one (due to unsigned int negative values are discarded as well)
1755 if (horizontal < indexArray.horizontalBins() && vertical < indexArray.verticalBins())
1756 {
1757 indexArray(horizontal, vertical).push_back((unsigned int)n);
1758 }
1759
1760 ++elements;
1761 }
1762
1763 return indexArray;
1764}
1765
1766inline SpatialDistribution::DistributionArray SpatialDistribution::distributeToArray(const Vector2* imagePoints, const size_t number, const Scalar left, const Scalar top, const Scalar width, const Scalar height, const unsigned int averagePointsPerBin, const unsigned int maxHorizontalBins, const unsigned int maxVerticalBins, unsigned int& horizontalBins, unsigned int& verticalBins)
1767{
1768 ocean_assert(imagePoints || number == 0);
1769
1770 ocean_assert(width > 0 && height > 0);
1771 ocean_assert(averagePointsPerBin > 0);
1772
1773 ocean_assert(maxHorizontalBins >= 1u);
1774 ocean_assert(maxVerticalBins >= 1u);
1775
1776 if (number == 0)
1777 {
1778 return DistributionArray(left, top, width, height, horizontalBins, verticalBins);
1779 }
1780
1781 /**
1782 * averagePointsPerBin * horizontalBins * verticalBins = number
1783 * horizontalBins / verticalBins = width / height
1784 */
1785
1786 const Scalar sqr = max(Scalar(1), (Scalar(number) * width) / (Scalar(averagePointsPerBin) * height));
1787
1788 horizontalBins = min(maxHorizontalBins, max(1u, (unsigned int)(Numeric::sqrt(sqr))));
1789 verticalBins = min(maxVerticalBins, max(1u, (unsigned int)(Scalar(horizontalBins) * height / width)));
1790
1791 return distributeToArray(imagePoints, number, left, top, width, height, horizontalBins, verticalBins);
1792}
1793
1794inline Vectors2 SpatialDistribution::distributeAndFilter(const Vector2* imagePoints, const size_t numberImagePoints, const Scalar left, const Scalar top, const Scalar width, const Scalar height, const unsigned int horizontalBins, const unsigned int verticalBins)
1795{
1796 return distributeAndFilter<Vector2, &SpatialDistribution::identity>(imagePoints, numberImagePoints, left, top, width, height, horizontalBins, verticalBins);
1797}
1798
1799template <typename TIndex>
1800inline std::vector<TIndex> SpatialDistribution::distributeAndFilterIndices(const Vector2* imagePoints, const size_t numberImagePoints, const Scalar left, const Scalar top, const Scalar width, const Scalar height, const unsigned int horizontalBins, const unsigned int verticalBins)
1801{
1802 return distributeAndFilterIndices<Vector2, TIndex, &SpatialDistribution::identity>(imagePoints, numberImagePoints, left, top, width, height, horizontalBins, verticalBins);
1803}
1804
1805template <typename T, Vector2 (*tFunction)(const T&)>
1806typename std::vector<T> SpatialDistribution::distributeAndFilter(const T* elements, const size_t numberElements, const Scalar left, const Scalar top, const Scalar width, const Scalar height, const unsigned int horizontalBins, const unsigned int verticalBins)
1807{
1808 ocean_assert(elements || numberElements == 0);
1809 ocean_assert(width >= 0 && height >= 0);
1810 ocean_assert(horizontalBins >= 1u && verticalBins >= 1u);
1811
1812 if (numberElements == 0)
1813 {
1814 return std::vector<T>();
1815 }
1816
1817 OccupancyArray occupancyArray(left, top, width, height, horizontalBins, verticalBins);
1818
1819 const size_t bins = occupancyArray.bins();
1820
1821 std::vector<T> result;
1822 result.reserve(bins);
1823
1824 for (size_t n = 0; n < numberElements && result.size() < bins; ++n)
1825 {
1826 if (occupancyArray.addPoint(tFunction(elements[n])))
1827 {
1828 result.push_back(elements[n]);
1829 }
1830 }
1831
1832 return result;
1833}
1834
1835template <typename T, Vector2 (*tFunction)(const T&)>
1836typename std::vector<T> SpatialDistribution::distributeAndFilter(const T* elements, const size_t numberElements, const Scalar left, const Scalar top, const Scalar width, const Scalar height, const unsigned int horizontalBins, const unsigned int verticalBins, const size_t numberDesiredFilteredElements, Indices32* indices)
1837{
1838 ocean_assert(elements != nullptr || numberElements == 0);
1839 ocean_assert(width >= 0 && height >= 0);
1840 ocean_assert(horizontalBins >= 1u && verticalBins >= 1u);
1841 ocean_assert(numberDesiredFilteredElements <= numberElements);
1842
1843 if (numberElements == 0 || numberDesiredFilteredElements == 0)
1844 {
1845 return std::vector<T>();
1846 }
1847
1848 OccupancyArray occupancyArray(left, top, width, height, horizontalBins, verticalBins);
1849
1850 std::vector<unsigned char> usedElements(numberElements, 0u);
1851
1852 const size_t bins = occupancyArray.bins();
1853
1854 std::vector<T> result;
1855 result.reserve(bins);
1856
1857 unsigned int filterIteration = 0u;
1858
1859 while (result.size() < numberDesiredFilteredElements && filterIteration < (unsigned int)numberDesiredFilteredElements)
1860 {
1861 for (size_t n = 0; n < numberElements && result.size() < numberDesiredFilteredElements; ++n)
1862 {
1863 if (usedElements[n] == 0u && occupancyArray.addPointWithCounter(tFunction(elements[n]), filterIteration))
1864 {
1865 result.push_back(elements[n]);
1866 usedElements[n] = 1u;
1867 }
1868 }
1869
1870 filterIteration++;
1871 }
1872
1873 if (indices)
1874 {
1875 for (size_t n = 0; n < numberElements; ++n)
1876 {
1877 if(usedElements[n])
1878 {
1879 indices->push_back(Index32(n));
1880 }
1881 }
1882 }
1883
1884 return result;
1885}
1886
1887template <typename T, typename TIndex, Vector2 (*tFunction)(const T&)>
1888typename std::vector<TIndex> SpatialDistribution::distributeAndFilterIndices(const T* elements, const size_t numberElements, const Scalar left, const Scalar top, const Scalar width, const Scalar height, const unsigned int horizontalBins, const unsigned int verticalBins)
1889{
1890 ocean_assert(elements || numberElements == 0);
1891 ocean_assert(width >= 0 && height >= 0);
1892 ocean_assert(horizontalBins >= 1u && verticalBins >= 1u);
1893
1894 if (numberElements == 0)
1895 {
1896 return std::vector<TIndex>();
1897 }
1898
1899 ocean_assert((unsigned long long)(numberElements) <= (unsigned long long)(NumericT<TIndex>::maxValue()));
1900
1901 OccupancyArray occupancyArray(left, top, width, height, horizontalBins, verticalBins);
1902
1903 const size_t bins = occupancyArray.bins();
1904
1905 std::vector<TIndex> result;
1906 result.reserve(bins);
1907
1908 for (size_t n = 0; n < numberElements && result.size() < bins; ++n)
1909 {
1910 if (occupancyArray.addPoint(tFunction(elements[n])))
1911 {
1912 result.push_back(TIndex(n));
1913 }
1914 }
1915
1916 return result;
1917}
1918
1919template <typename T>
1920inline T SpatialDistribution::identity(const T& value)
1921{
1922 return value;
1923}
1924
1925}
1926
1927}
1928
1929#endif // META_OCEAN_GEOMETRY_SPATIAL_DISTRIBUTION_H
This class implements a base class for data arrays.
Definition SpatialDistribution.h:37
unsigned int horizontalBins() const
Returns the number of horizontal distribution bins.
Definition SpatialDistribution.h:1122
Scalar width() const
Returns the width of the distribution area.
Definition SpatialDistribution.h:1112
int horizontalBin(const Scalar x) const
Returns the horizontal bin of a given horizontal position.
Definition SpatialDistribution.h:1148
int verticalBin(const Scalar y) const
Returns the vertical bin of a given vertical position.
Definition SpatialDistribution.h:1154
Scalar horizontalPoint2Bin_
Horizontal position to bin factor.
Definition SpatialDistribution.h:262
unsigned int endBinHorizontal(const unsigned int centerBinX) const
Returns the (exclusive) end bin in horizontal direction for a neighborhood search.
Definition SpatialDistribution.h:1183
Array & operator=(const Array &object)
Assign operator.
Definition SpatialDistribution.h:1239
Scalar areaTop_
Top position of the distribution area.
Definition SpatialDistribution.h:247
Scalar top() const
Returns the top position of the distribution area.
Definition SpatialDistribution.h:1107
unsigned int verticalBins() const
Returns the number of vertical distribution bins.
Definition SpatialDistribution.h:1127
unsigned int beginBinHorizontal(const unsigned int centerBinX) const
Returns the (inclusive) begin bin in horizontal direction for a neighborhood search.
Definition SpatialDistribution.h:1173
int clampedVerticalBin(const Scalar y) const
Returns the vertical bin of a given vertical position.
Definition SpatialDistribution.h:1166
Scalar areaLeft_
Left position of the distribution area.
Definition SpatialDistribution.h:244
Scalar areaHeight_
Height of the distribution area.
Definition SpatialDistribution.h:253
Array()=default
Creates an empty array object.
int clampedHorizontalBin(const Scalar x) const
Returns the horizontal bin of a given horizontal position.
Definition SpatialDistribution.h:1160
bool isValid() const
Returns whether this object holds a valid distribution.
Definition SpatialDistribution.h:1212
Scalar height() const
Returns the height of the distribution area.
Definition SpatialDistribution.h:1117
Scalar verticalPoint2Bin_
Vertical position to bin factor.
Definition SpatialDistribution.h:265
bool operator==(const Array &right) const
Returns whether two Array objects are identical.
Definition SpatialDistribution.h:1217
unsigned int beginBinVertical(const unsigned int centerBinY) const
Returns the (inclusive) begin bin in vertical direction for a neighborhood search.
Definition SpatialDistribution.h:1193
bool operator!=(const Array &right) const
Returns whether two Array objects are not identical.
Definition SpatialDistribution.h:1229
Scalar areaWidth_
Width of the distribution area.
Definition SpatialDistribution.h:250
unsigned int verticalBins_
Number of vertical distribution bins.
Definition SpatialDistribution.h:259
Array(const Array &object)=default
Copy constructor.
unsigned int endBinVertical(const unsigned int centerBinY) const
Returns the (exclusive) end bin in vertical direction for a neighborhood search.
Definition SpatialDistribution.h:1203
unsigned int horizontalBins_
Number of horizontal distribution bins.
Definition SpatialDistribution.h:256
Scalar left() const
Returns the left position of the distribution area.
Definition SpatialDistribution.h:1102
unsigned int index(const Scalar x, const Scalar y) const
Returns the bin index for a given position.
Definition SpatialDistribution.h:1137
unsigned int bins() const
Returns the number of bins this distribution holds.
Definition SpatialDistribution.h:1132
Definition of a class holding an index and a distance.
Definition SpatialDistribution.h:628
Scalar distance_
Distance value.
Definition SpatialDistribution.h:688
unsigned int candidateIndex() const
Returns the candidate index of this element.
Definition SpatialDistribution.h:1694
static bool compareLeftSmaller(const DistanceElement &left, const DistanceElement &right)
Compares two distance elements.
Definition SpatialDistribution.h:1704
unsigned int index() const
Returns the interest index of this element.
Definition SpatialDistribution.h:1689
static bool compareLeftHigher(const DistanceElement &left, const DistanceElement &right)
Compares two distance elements.
Definition SpatialDistribution.h:1709
DistanceElement(const unsigned int index, const unsigned int candidateIndex, const Scalar distance)
Creates a new distance element.
Definition SpatialDistribution.h:1681
bool operator<(const DistanceElement &element) const
Returns whether the left element holds a higher distance than the right one.
Definition SpatialDistribution.h:1714
Scalar distance() const
Returns the distance of this element.
Definition SpatialDistribution.h:1699
This class implements a distribution array.
Definition SpatialDistribution.h:272
DistributionArray()=default
Creates an empty distribution array object.
bool hasCopiedNeighborhood8() const
Returns whether this distribution array contains copies of indices within the 8-neighborhood of each ...
Definition SpatialDistribution.h:1298
DistributionArray & operator=(const DistributionArray &object)
Assign operator.
Definition SpatialDistribution.h:1331
bool hasCopiedNeighborhood8_
True, if the array contains copies of indices within the 8-neighborhood of each individual bin; False...
Definition SpatialDistribution.h:407
void clear()
Removes all elements form this array.
DistributionArray(const DistributionArray &object)=default
Copy constructor.
const Indices32 & operator()(const unsigned int horizontal, const unsigned int vertical) const
Returns the distribution indices of a specified bin.
Definition SpatialDistribution.h:1303
IndexGroups32 indexGroups_
Distribution array with point indices.
Definition SpatialDistribution.h:404
const Indices32 & operator[](const unsigned int index) const
Returns the distribution indices of a specified bin.
Definition SpatialDistribution.h:1319
DistributionArray(const DistributionArray &distributionArray, const bool copyNeighborhood8)
Copies a given distribution array and optional copies the indices from the 8-neighborhood of each ind...
bool operator!=(const DistributionArray &distributionArray) const
Returns whether two DistributionArray objects are not identical.
Definition SpatialDistribution.h:1364
bool operator==(const DistributionArray &distributionArray) const
Returns whether two DistributionArray objects are identical.
Definition SpatialDistribution.h:1354
void indicesNeighborhood9(const unsigned int horizontal, const unsigned int vertical, Indices32 &indices) const
Returns the indices of the 8-neighborhood and the specified bin itself.
Indices32 indicesNeighborhood9(const unsigned int horizontal, const unsigned int vertical) const
Returns the indices of the 8-neighborhood and the specified bin itself.
This class implements an occupancy array.
Definition SpatialDistribution.h:414
OccupancyArray & operator+=(const Vector2 &point)
Adds an image point to this occupancy array.
Definition SpatialDistribution.h:1585
bool operator!=(const OccupancyArray &occupancyArray) const
Returns whether two OccupancyArray objects are not identical.
Definition SpatialDistribution.h:1676
unsigned int freeBins() const
Returns the number of free bins.
Definition SpatialDistribution.h:1508
bool isNotOccupiedNeighborhood9(const unsigned int horizontal, const unsigned int vertical) const
Returns whether at least one bin in the 8-neighborhood or the specified bin itself is not occupied.
Definition SpatialDistribution.h:1452
OccupancyArray & operator-=(const Vector2 &point)
Removes an image point from this occupancy array.
Definition SpatialDistribution.h:1598
unsigned int occupiedBins() const
Returns the number of occupied bins.
Definition SpatialDistribution.h:1493
unsigned int countOccupiedNeighborhood9(const unsigned int horizontal, const unsigned int vertical) const
Returns the number of occupied bins in the 9-neighborhood (so the specified bin is included).
Definition SpatialDistribution.h:1390
OccupancyArray()=default
Creates an empty distribution array object.
OccupancyArray & operator=(const OccupancyArray &object)
Assign operator.
Definition SpatialDistribution.h:1647
bool isOccupiedNeighborhood9(const unsigned int horizontal, const unsigned int vertical) const
Returns whether at least one bin in the 8-neighborhood or the specified bin itself is occupied.
Definition SpatialDistribution.h:1411
void reset()
Resets all occupied bins so that all bins a free afterwards.
Definition SpatialDistribution.h:1580
bool removePoint(const Vector2 &point)
Removes an image point and returns whether the corresponding bin was occupied before.
Definition SpatialDistribution.h:1561
bool addPointWithCounter(const Vector2 &point, const unsigned int maximalOccupancyCounter)
Adds an image point and returns whether the occupancy counter of the corresponding bin was equal or b...
Definition SpatialDistribution.h:1542
bool addPoint(const Vector2 &point)
Adds an image point and returns whether the corresponding bin was not occupied before (was free befor...
Definition SpatialDistribution.h:1523
OccupancyArray(const OccupancyArray &object)=default
Copy constructor.
bool operator()(const unsigned int horizontal, const unsigned int vertical) const
Returns whether a specified bin is occupied.
Definition SpatialDistribution.h:1611
bool operator==(const OccupancyArray &occupancyArray) const
Returns whether two OccupancyArray objects are identical.
Definition SpatialDistribution.h:1666
Indices32 occupancy_
Occupancy array.
Definition SpatialDistribution.h:621
bool operator[](const unsigned int index) const
Returns whether a specified bin is occupied.
Definition SpatialDistribution.h:1635
This class implements spatial distribution function for 2D geometric data.
Definition SpatialDistribution.h:30
static Indices32 determineNeighbors(const Vector2 &imagePoint, const Vector2 *candidatePoints, const size_t numberCandidatePoints, const Scalar radius, const DistributionArray &distributionCandidatePoints)
Determines all candidate points for a given image point (interest point) lying inside a specified cir...
static void determineMinimalSqrDistances(const Vector2 *imagePoints, const size_t numberImagePoints, const Vector2 *candidates, const size_t numberCandidates, const DistributionArray &distributionCandidates, Scalar *sqrDistances, unsigned int *candidateIndices=nullptr)
Determines the minimal square distances for each given image point to another given set of image poin...
static Vectors2 distributeAndFilter(const Vector2 *imagePoints, const size_t numberImagePoints, const Scalar left, const Scalar top, const Scalar width, const Scalar height, const unsigned int horizontalBins, const unsigned int verticalBins)
Distributes the given image points into an array of specified size and returns (at most) one point fr...
Definition SpatialDistribution.h:1794
static Vectors2 distributeAndFilter(const Vector2 *imagePoints, const size_t numberImagePoints, const Scalar left, const Scalar top, const Scalar width, const Scalar height, const unsigned int horizontalBins, const unsigned int verticalBins, const size_t size)
Distributes the given image points into an array of specified size and returns as much points as requ...
static std::vector< TIndex > distributeAndFilterIndices(const Vector2 *imagePoints, const size_t numberImagePoints, const Scalar left, const Scalar top, const Scalar width, const Scalar height, const unsigned int horizontalBins, const unsigned int verticalBins)
Distributes the given image points into an array of specified size and returns (at most) one point in...
Definition SpatialDistribution.h:1800
static DistributionArray distributeToArray(const Vector2 *imagePoints, const size_t number, const Scalar left, const Scalar top, const Scalar width, const Scalar height, const unsigned int horizontalBins, const unsigned int verticalBins)
Distributes a set of given 2D image points into a spatial array.
static Scalar determineMinimalSqrDistance(const Vector2 *imagePoints, const size_t numberImagePoints, const unsigned int index, const DistributionArray &distributionImagePoints)
Determines the minimal square distance for one given 2D image point to all other points in the same s...
static void determineMinimalSqrDistances(const Vector2 *imagePoints, const size_t numberImagePoints, const unsigned int width, const unsigned int height, const unsigned int bins, Scalar *sqrDistances)
Determines the minimal square distances for each given 2D image point to all other points in the same...
static void idealBins(const unsigned int width, const unsigned int height, const size_t numberBins, unsigned int &horizontalBins, unsigned int &verticalBins, const unsigned int minimalHorizontalBins=2u, const unsigned int minimalVerticalBins=2u)
Calculates the ideal number of horizontal and vertical bins for an array if the overall number of bin...
std::vector< DistanceElement > DistanceElements
Definition of a vector holding distance elements.
Definition SpatialDistribution.h:694
static Index32 determineNearestNeighbor(const Vector2 &interestPoint, const Vector2 *imagePoints, const size_t numberImagePoints, const Scalar radius, const DistributionArray &distributionImagePoints, Scalar *sqrDistance=nullptr)
Determines the nearest image point between an interest point and a set of given image point lying ins...
static void determineMinimalSqrDistances(const Vector2 *imagePoints, const size_t numberImagePoints, const unsigned int *interestIndices, const size_t numberInterestIndices, const unsigned int width, const unsigned int height, const unsigned int bins, Scalar *sqrDistances)
Determines the minimal square distances for each specified image point inside their neighborhood.
static Indices32 filterAccordingDistance(const Vector2 *imagePoints, const size_t number, const unsigned int width, const unsigned int height, const Scalar distance)
Filters the given 2D image points according to their distance to neighboring image points.
static DistanceElements sortAccordingDistance(const Vector2 *imagePoints, const size_t number, const bool minimalDistanceFirst)
Sorts the given 2D image points according to their minimal distance to neighboring image points.
static DistributionArray distributeToArray(const Vector2 *imagePoints, const size_t number, const Scalar left, const Scalar top, const Scalar width, const Scalar height, const unsigned int averagePointsPerBin, const unsigned int maxHorizontalBins, const unsigned int maxVerticalBins, unsigned int &horizontalBins, unsigned int &verticalBins)
Distributes the given 2D image points into a spatial array.
Definition SpatialDistribution.h:1766
static OccupancyArray createOccupancyArray(const Vector2 *imagePoints, const size_t number, const Scalar left, const Scalar top, const Scalar width, const Scalar height, const unsigned int horizontalBins, const unsigned int verticalBins)
Distributes the given 2D image points into a spatial array.
static DistanceElements sortAccordingDistance(const Vector2 *imagePoints, const size_t number, const unsigned int width, const unsigned int height, const unsigned int bins, const bool minimalDistanceFirst)
Sorts the given 2D image points according to their minimal distance to neighboring image points.
static void idealBinsNeighborhood9(const unsigned int width, const unsigned int height, const Scalar distance, unsigned int &horizontalBins, unsigned int &verticalBins, const unsigned int minimalHorizontalBins=2u, const unsigned int minimalVerticalBins=2u, const unsigned int maximalHorizontalBins=20u, const unsigned int maximalVerticalBins=20u)
Calculates the ideal number of horizontal and vertical bins for an array if bin elements within a cer...
static void determineMinimalSqrDistances(const Vector2 *imagePoints, const size_t numberImagePoints, const Vector2 *candidates, const size_t numberCandidates, const unsigned int width, const unsigned int height, const unsigned int bins, Scalar *sqrDistances)
Determines the minimal square distances for each given 2D image point to another given set of 2D imag...
static T identity(const T &value)
This function simply returns the given object (actually a copy of the object).
Definition SpatialDistribution.h:1920
static void filterCandidatePoint(const Vector2 *imagePoints, const size_t numberImagePoints, const Vector2 *candidatePoints, const size_t numberCandidatePoints, const unsigned int width, const unsigned int height, const Scalar filterDistance, const unsigned int filterSize, Indices32 *filteredIndices=nullptr, Vectors2 *filteredCandidates=nullptr)
Filters the given 2D candidate points according to the distance to the given image points.
This class provides basic numeric functionalities.
Definition Numeric.h:57
static T sqrt(const T value)
Returns the square root of a given value.
Definition Numeric.h:1537
static constexpr T eps()
Returns a small epsilon.
static T floor(const T value)
Returns the largest integer value that is not greater than the given value.
Definition Numeric.h:2035
static T ceil(const T value)
Returns the smallest integer value that is not less than the given value.
Definition Numeric.h:1997
const T & x() const noexcept
Returns the x value.
Definition Vector2.h:710
const T & y() const noexcept
Returns the y value.
Definition Vector2.h:722
std::vector< Index32 > Indices32
Definition of a vector holding 32 bit index values.
Definition Base.h:96
std::vector< Indices32 > IndexGroups32
Definition of a vector holding 32 bit indices, so we have groups of indices.
Definition Base.h:102
uint32_t Index32
Definition of a 32 bit index value.
Definition Base.h:84
unsigned int sqr(const char value)
Returns the square value of a given value.
Definition base/Utilities.h:1099
std::vector< Vector2 > Vectors2
Definition of a vector holding Vector2 objects.
Definition Vector2.h:64
float Scalar
Definition of a scalar type.
Definition Math.h:129
The namespace covering the entire Ocean framework.
Definition Accessor.h:15