Ocean
Loading...
Searching...
No Matches
NonMaximumSuppression.h
Go to the documentation of this file.
1/*
2 * Copyright (c) Meta Platforms, Inc. and affiliates.
3 *
4 * This source code is licensed under the MIT license found in the
5 * LICENSE file in the root directory of this source tree.
6 */
7
8#ifndef META_OCEAN_CV_NON_MAXIMUM_SUPPRESSION_H
9#define META_OCEAN_CV_NON_MAXIMUM_SUPPRESSION_H
10
11#include "ocean/cv/CV.h"
12
14#include "ocean/base/Worker.h"
15
16#include "ocean/math/Vector2.h"
17
18#include <functional>
19
20namespace Ocean
21{
22
23namespace CV
24{
25
26/**
27 * This class provides base functionality and type definitions for non-maximum-suppression operations.
28 * It defines common types like StrengthPosition and StrengthPositions used by the template class NonMaximumSuppressionT.
29 * @see NonMaximumSuppressionT
30 * @ingroup cv
31 */
33{
34 public:
35
36 /**
37 * This class extends a 2D position by a third parameter storing a strength value.
38 * @tparam TCoordinate The data type of a scalar coordinate
39 * @tparam TStrength The data type of the strength parameter
40 */
41 template <typename TCoordinate, typename TStrength>
42 class StrengthPosition : public VectorT2<TCoordinate>
43 {
44 public:
45
46 /**
47 * Creates a new object with default strength parameter.
48 */
49 StrengthPosition() = default;
50
51 /**
52 * Creates a new object with explicit position and strength parameter.
53 * @param x Horizontal position
54 * @param y Vertical position
55 * @param strength The strength parameter
56 */
57 inline StrengthPosition(const TCoordinate x, const TCoordinate y, const TStrength& strength);
58
59 /**
60 * Returns the strength parameter of this object.
61 * @return Strength parameter
62 */
63 inline const TStrength& strength() const;
64
65 /**
66 * Compares the strength value of two objects.
67 * @param left The left object to compare
68 * @param right The right object to compare
69 * @return True, if so
70 * @tparam tLeftLargerThanRight True, to return whether left's strength is larger than right's strength; False, to return whether right is larger than left
71 */
72 template <bool tLeftLargerThanRight = true>
74
75 private:
76
77 /// Strength parameter of this object.
78 TStrength strength_ = TStrength();
79 };
80
81 /**
82 * Definition of a vector holding strength pixel positions.
83 */
84 template <typename TCoordinate, typename TStrength>
85 using StrengthPositions = std::vector<StrengthPosition<TCoordinate, TStrength>>;
86};
87
88/**
89 * This class implements the possibility to find local maximum in a 2D array by applying a non-maximum-suppression search.
90 * The search is done within a 3x3 neighborhood (centered around the point of interest).<br>
91 * Use this class to determine e.g. reliable feature points.<br>
92 * The class supports bin accuracy (pixel accuracy) and sub-bin accuracy (sub-pixel accuracy).
93 *
94 * The non-maximum-suppression search is implemented by a vertical list holding maps of horizontal array elements.<br>
95 * The performance depends on the number of elements inserted into the individual maps.<br>
96 * Thus, do not add data elements with negligible value.
97 *
98 * It should be mentioned that the application of this class should be restricted to situations in which the entire filter response values do not exist already.<br>
99 * The performance boost comes with a simultaneous determination of filter responses and the insertion of possible candidates for maximum locations.
100 * @tparam T The data type of the individual elements that are applied for the non-maximum-suppression search.
101 * @ingroup cv
102 */
103template <typename T>
105{
106 public:
107
108 /**
109 * Definition of a callback function used to determine the precise sub-pixel position of a specific point.
110 * @param x The horizontal position of the point, with range [0, width - 1]
111 * @param y The vertical position of the point, with range [0, height - 1]
112 * @param strength The strength parameter already known for the position of the point
113 * @param preciseX The resulting precise horizontal position of the point, with range (x - 1, x + 1)
114 * @param preciseY The resulting precise vertical position of the point, with range (y - 1, y + 1)
115 * @param preciseStrength The resulting precise strength parameter of the precise point
116 * @return True, if the precise position could be determined
117 * @tparam TCoordinate The data type of a scalar coordinate
118 * @tparam TStrength The data type of the strength parameter
119 */
120 template <typename TCoordinate, typename TStrength>
121 using PositionCallback = std::function<bool(const unsigned int x, const unsigned int y, const TStrength strength, TCoordinate& preciseX, TCoordinate& preciseY, TStrength& preciseStrength)>;
122
123 protected:
124
125 /**
126 * This class holds the horizontal position and strength parameter of an interest pixel.
127 */
129 {
130 public:
131
132 /**
133 * Creates a new candidate object.
134 */
135 inline StrengthCandidate();
136
137 /**
138 * Creates a new candidate object with horizontal position and strength parameter.
139 * @param x Horizontal position in pixel
140 * @param strength The strength parameter
141 */
142 inline StrengthCandidate(const unsigned int x, const T& strength);
143
144 /**
145 * Returns the horizontal position of this candidate object.
146 * @return Horizontal position in pixel
147 */
148 inline unsigned int x() const;
149
150 /**
151 * Returns the strength parameter of this object.
152 * @return Strength parameter
153 */
154 inline const T& strength() const;
155
156 private:
157
158 /// Horizontal position of this object.
159 unsigned int positionX_ = (unsigned int)(-1);
160
161 /// Strength parameter of this object.
162 T strength_ = T();
163 };
164
165 /**
166 * Definition of a vector holding strength candidate objects.
167 */
168 using StrengthCandidateRow = std::vector<StrengthCandidate>;
169
170 /**
171 * Definition of a vector holding a vector of strength candidates.
172 */
174
175 public:
176
177 /**
178 * Move constructor.
179 * @param nonMaximumSuppression The object to be moved
180 */
181 NonMaximumSuppressionT(NonMaximumSuppressionT<T>&& nonMaximumSuppression) noexcept;
182
183 /**
184 * Copy constructor.
185 * @param nonMaximumSuppression The object to be moved
186 */
187 NonMaximumSuppressionT(const NonMaximumSuppressionT<T>& nonMaximumSuppression) noexcept;
188
189 /**
190 * Creates a new maximum suppression object with a predefined size.
191 * @param width The width of this object in pixel, with range [3, infinity)
192 * @param height The height of this object in pixel, with range [3, infinity)
193 * @param yOffset Optional offset in the vertical direction moving the suppression region by the specified number of rows, with range [0, infinity)
194 */
195 NonMaximumSuppressionT(const unsigned int width, const unsigned int height, const unsigned int yOffset = 0u) noexcept;
196
197 /**
198 * Returns the width of this object.
199 * @return Width in pixel
200 */
201 inline unsigned int width() const;
202
203 /**
204 * Returns the height of this object.
205 * @return Height in pixel
206 */
207 inline unsigned int height() const;
208
209 /**
210 * Returns the optional offset in the vertical direction.
211 * @return Optional vertical direction offset, 0 by default
212 */
213 inline unsigned int yOffset() const;
214
215 /**
216 * Adds a new candidate to this object.
217 * Beware: Due to performance issues do no add candidates with negligible strength parameter.
218 * @param x Horizontal position in pixel, with range [0, width() - 1]
219 * @param y Vertical position in pixel, with range [yOffset(), yOffset() + height() - 1]
220 * @param strength The strength parameter
221 * @see addCandidates(), removeCandidatesFromRight().
222 */
223 inline void addCandidate(const unsigned int x, const unsigned int y, const T& strength);
224
225 /**
226 * Adds new candidates to this object from a given buffer providing one value for each bin/pixel of this object.
227 * Beware: Due to performance reasons, you should use the addCandidate() function to add one single new candidate in the moment the filter response is larger than a specific threshold.<br>
228 * @param values The from which candidates will be added, must be width() * height() elements
229 * @param valuesPaddingElements The number of padding elements at the end of each values row, in elements, with range [0, infinity)
230 * @param firstColumn First column to be handled, with range [0, width() - 1]
231 * @param numberColumns Number of columns to be handled, with range [1, width() - firstColumn]
232 * @param firstRow First row to be handled, with range [yOffset(), height() - 1]
233 * @param numberRows Number of rows to be handled, with range [1, height() - firstRow]
234 * @param minimalThreshold The minimal threshold so that a value counts as candidate
235 * @param worker Optional worker object to distribute the computation
236 * @see addCandidate(), removeCandidatesFromRight().
237 */
238 void addCandidates(const T* values, const unsigned int valuesPaddingElements, const unsigned int firstColumn, const unsigned int numberColumns, const unsigned int firstRow, const unsigned int numberRows, const T& minimalThreshold, Worker* worker);
239
240 /**
241 * Removes all candidates from a specified row having a horizontal location equal or larger than a specified coordinate.
242 * @param x The horizontal coordinate specifying which candidates will be removed, all candidates with horizontal location >= x will be removed, with range [0, infinity)
243 * @param y The index of the row in which the candidates will be removed, with range [yOffset(), yOffset() + height() - 1]
244 */
245 inline void removeCandidatesRightFrom(const unsigned int x, const unsigned int y);
246
247 /**
248 * Applies a non-maximum-suppression search on a given 2D frame in a 3x3 neighborhood (eight neighbors).
249 * This function allows to determine the precise position of the individual maximum value positions by application of a callback function determining the individual positions.<br>
250 * @param firstColumn First column to be handled, with range [1, width() - 1)
251 * @param numberColumns Number of columns to be handled
252 * @param firstRow First row to be handled, with range [yOffset() + 1, height() - 1)
253 * @param numberRows Number of rows to be handled
254 * @param strengthPositions The resulting non maximum suppressed positions including the strength parameters, will be appended
255 * @param worker Optional worker object to distribute the computation
256 * @param positionCallback Optional callback function allowing to determine the precise position of the individual maximum value positions
257 * @return True, if succeeded
258 * @tparam TCoordinate The data type of a scalar coordinate
259 * @tparam TStrength The data type of the strength parameter
260 * @tparam tStrictMaximum True, to search for a strict maximum (larger than all eight neighbors); False, to allow equal values in the upper left neighborhood
261 */
262 template <typename TCoordinate, typename TStrength, bool tStrictMaximum = true>
263 bool suppressNonMaximum(const unsigned int firstColumn, const unsigned int numberColumns, const unsigned int firstRow, const unsigned int numberRows, StrengthPositions<TCoordinate, TStrength>& strengthPositions, Worker* worker = nullptr, const PositionCallback<TCoordinate, TStrength>* positionCallback = nullptr) const;
264
265 /**
266 * Returns all gathered candidates of this object.
267 * The resulting candidates are raw candidates without any suppression.
268 * @param firstColumn The first column from which candidates will be returned, with range [0, width() - 1]
269 * @param numberColumns The number of columns for which candidates will be returned, with range [1, width() - firstColumn]
270 * @param firstRow The first row from which candidates will be returned, with range [yOffset(), height() - 1]
271 * @param numberRows The number of rows for which candidates will be returned, with range [1, height() - firstRow]
272 * @param strengthPositions The resulting strength positions
273 */
274 void candidates(const unsigned int firstColumn, const unsigned int numberColumns, const unsigned int firstRow, const unsigned int numberRows, StrengthPositions<unsigned int, T>& strengthPositions);
275
276 /**
277 * Removes the gathered non-maximum suppression information so that this object can be reused again (for the same task with same resolution etc.).
278 * The allocated memory will remain so that reusing this object may improve performance.
279 */
280 void reset();
281
282 /**
283 * Move operator.
284 * @param nonMaximumSuppression Object to be moved
285 * @return Reference to this object
286 */
288
289 /**
290 * Copy operator.
291 * @param nonMaximumSuppression The object to be copied
292 * @return Reference to this object
293 */
295
296 /**
297 * Applies a non-maximum-suppression based on already existing strength positions (just with a custom suppression radius) e.g., as a post-processing step.
298 * @param width The width of the image/domain in which the strength positions are located, e.g., in pixel, with range [1, infinity)
299 * @param height The height of the image/domain in which the strength positions are located, e.g., in pixel, with range [1, infinity)
300 * @param strengthPositions The strength positions for which a custom suppression-radius will be applied
301 * @param radius The suppression radius to be applied, with range [1, infinity)
302 * @param validIndices Optional resulting indices of all strength positions which remain after suppression
303 * @return The resulting strength positions
304 * @tparam TCoordinate The data type of a scalar coordinate
305 * @tparam TStrength The data type of the strength parameter
306 * @tparam tStrictMaximum True, to search for a strict maximum (larger than all eight neighbors); False, to allow equal values in the upper left neighborhood
307 */
308 template <typename TCoordinate, typename TStrength, bool tStrictMaximum>
309 static StrengthPositions<TCoordinate, TStrength> suppressNonMaximum(const unsigned int width, const unsigned int height, const StrengthPositions<TCoordinate, TStrength>& strengthPositions, const TCoordinate radius, Indices32* validIndices = nullptr);
310
311 /**
312 * Determines the precise peak location in 1D space for three discrete neighboring measurements at location x == 0.
313 * The precise peak is determined based on the first and second derivatives of the measurement values.
314 * @param leftValue The left discrete value, e.g., at location x - 1, with range (-infinity, middleValue]
315 * @param middleValue The middle discrete value, e.g., at location x, with range (-infinity, infinity)
316 * @param rightValue The discrete value, e.g., at location x + 1, with range (-infinity, middleValue]
317 * @param location The location of the precise peak of all values, with range (-1, 1)
318 * @return True, if succeeded
319 * @tparam TFloat The floating point data type to be used for calculation, either 'float' or 'double'
320 */
321 template <typename TFloat>
322 static bool determinePrecisePeakLocation1(const T& leftValue, const T& middleValue, const T& rightValue, TFloat& location);
323
324 /**
325 * Determines the precise peak location in 2D space for nine discrete neighboring measurements at location x == 0, y == 0.
326 * The precise peak is determined based on the first and second derivatives of the measurement values.
327 * @param topValues The three discrete values in the top row, must be valid
328 * @param centerValues The three discrete values in the center row, must be valid
329 * @param bottomValues The three discrete values in the bottom row, must be valid
330 * @param location The location of the precise peak of all values, with range (-1, 1)
331 * @return True, if succeeded
332 * @tparam TFloat The floating point data type to be used for calculation, either 'float' or 'double'
333 */
334 template <typename TFloat>
335 static bool determinePrecisePeakLocation2(const T* const topValues, const T* const centerValues, const T* const bottomValues, VectorT2<TFloat>& location);
336
337 private:
338
339 /**
340 * Adds new candidates to this object from a subset of a given buffer providing one value for each bin/pixel of this object.
341 * @param values The from which candidates will be added, must be width() * height() elements
342 * @param valuesStrideElements The number of elements between two values rows, in elements, with range [0, infinity)
343 * @param minimalThreshold The minimal threshold so that a value counts as candidate
344 * @param firstColumn First column to be handled, with range [0, width() - 1]
345 * @param numberColumns Number of columns to be handled, with range [1, width() - firstColumn]
346 * @param firstRow The first row in the buffer from which the candidates will be added, with range [yOffset(), height())
347 * @param numberRows The number of rows to be handled, with range [1, height() - firstRow]
348 * @see addCandidates().
349 */
350 void addCandidatesSubset(const T* values, const unsigned int valuesStrideElements, const unsigned int firstColumn, const unsigned int numberColumns, const T* minimalThreshold, const unsigned int firstRow, const unsigned int numberRows);
351
352 /**
353 * Applies a non-maximum-suppression search on a subset of a given 2D frame in a 3x3 neighborhood (eight neighbors).
354 * This function allows to determine the precise position of the individual maximum value positions by application of a callback function determining the individual positions.<br>
355 * @param strengthPositions Resulting non maximum suppressed positions including the strength parameters
356 * @param firstColumn First column to be handled
357 * @param numberColumns Number of columns to be handled
358 * @param lock The lock object that must be defined if this function is executed in parallel on several threads
359 * @param positionCallback Optional callback function allowing to determine the precise position of the individual maximum value positions
360 * @param firstRow First row to be handled
361 * @param numberRows Number of rows to be handled
362 * @tparam tStrictMaximum True, to search for a strict maximum (larger than all eight neighbors); False, to allow equal values in the upper left neighborhood
363 */
364 template <typename TCoordinate, typename TStrength, bool tStrictMaximum>
365 void suppressNonMaximumSubset(StrengthPositions<TCoordinate, TStrength>* strengthPositions, const unsigned int firstColumn, const unsigned int firstRow, Lock* lock, const PositionCallback<TCoordinate, TStrength>* positionCallback, const unsigned int numberColumns, const unsigned int numberRows) const;
366
367 private:
368
369 /// Width of this object.
370 unsigned int width_ = 0u;
371
372 /// All candidate rows.
374};
375
376template <typename TCoordinate, typename TStrength>
378 VectorT2<TCoordinate>(x, y),
379 strength_(strength)
380{
381 // nothing to do here
382}
383
384template <typename TCoordinate, typename TStrength>
386{
387 return strength_;
388}
389
390template <typename TCoordinate, typename TStrength>
391template <bool tLeftLargerThanRight>
393{
394 if constexpr (tLeftLargerThanRight)
395 {
396 return left.strength() > right.strength();
397 }
398 else
399 {
400 return left.strength() < right.strength();
401 }
402}
403
404template <typename T>
406 positionX_(-1),
407 strength_(T())
408{
409 // nothing to do here
410}
411
412template <typename T>
413inline NonMaximumSuppressionT<T>::StrengthCandidate::StrengthCandidate(const unsigned int x, const T& strength) :
414 positionX_(x),
415 strength_(strength)
416{
417 // nothing to do here
418}
419
420template <typename T>
422{
423 return positionX_;
424}
425
426template <typename T>
428{
429 return strength_;
430}
431
432template <typename T>
434{
435 *this = std::move(nonMaximumSuppression);
436}
437
438template <typename T>
440 width_(nonMaximumSuppression.width_),
441 rows_(nonMaximumSuppression.rows_)
442{
443 // nothing to do here
444}
445
446template <typename T>
447NonMaximumSuppressionT<T>::NonMaximumSuppressionT(const unsigned int width, const unsigned int height, const unsigned int yOffset) noexcept :
448 width_(width),
450{
451 // nothing to do here
452}
453
454template <typename T>
455inline unsigned int NonMaximumSuppressionT<T>::width() const
456{
457 return width_;
458}
459
460template <typename T>
461inline unsigned int NonMaximumSuppressionT<T>::height() const
462{
463 return (unsigned int)rows_.size();
464}
465
466template <typename T>
467inline unsigned int NonMaximumSuppressionT<T>::yOffset() const
468{
469 ocean_assert(rows_.firstIndex() >= 0);
470
471 return (unsigned int)(rows_.firstIndex());
472}
473
474template <typename T>
475inline void NonMaximumSuppressionT<T>::addCandidate(const unsigned int x, const unsigned int y, const T& strength)
476{
477 ocean_assert(x < width_);
478
479 ocean_assert(rows_.isValidIndex(y) && y >= (unsigned int)(rows_.firstIndex()) && y <= (unsigned int)(rows_.endIndex()));
480
481 if (rows_[y].empty())
482 {
483 rows_[y].reserve(128);
484 }
485
486 rows_[y].emplace_back(x, strength);
487}
488
489template <typename T>
490void NonMaximumSuppressionT<T>::addCandidates(const T* values, const unsigned int valuesPaddingElements, const unsigned int firstColumn, const unsigned int numberColumns, const unsigned int firstRow, const unsigned int numberRows, const T& minimalThreshold, Worker* worker)
491{
492 ocean_assert(values != nullptr);
493
494 ocean_assert(firstColumn + numberColumns <= width_);
495 ocean_assert(typename StrengthCandidateRows::Index(firstRow) >= rows_.firstIndex());
496 ocean_assert(typename StrengthCandidateRows::Index(firstRow + numberRows) <= rows_.endIndex());
497
498 const unsigned int valuesStrideElements = width_ + valuesPaddingElements;
499
500 if (worker != nullptr)
501 {
502 worker->executeFunction(Worker::Function::create(*this, &NonMaximumSuppressionT<T>::addCandidatesSubset, values, valuesStrideElements, firstColumn, numberColumns, &minimalThreshold, 0u, 0u), firstRow, numberRows, 5u, 6u, 20u);
503 }
504 else
505 {
506 addCandidatesSubset(values, valuesStrideElements, firstColumn, numberColumns, &minimalThreshold, firstRow, numberRows);
507 }
508}
509
510template <typename T>
511inline void NonMaximumSuppressionT<T>::removeCandidatesRightFrom(const unsigned int x, const unsigned int y)
512{
513 ocean_assert(rows_.isValidIndex(y) && y >= (unsigned int)(rows_.firstIndex()) && y <= (unsigned int)(rows_.endIndex()));
514
515 StrengthCandidateRow& suppressionRow = rows_[y];
516
517 while (!suppressionRow.empty())
518 {
519 if (suppressionRow.back().x() >= x)
520 {
521 suppressionRow.pop_back();
522 }
523 else
524 {
525 break;
526 }
527 }
528}
529
530template <typename T>
531template <typename TCoordinate, typename TStrength, bool tStrictMaximum>
532bool NonMaximumSuppressionT<T>::suppressNonMaximum(const unsigned int firstColumn, const unsigned int numberColumns, const unsigned int firstRow, const unsigned int numberRows, StrengthPositions<TCoordinate, TStrength>& strengthPositions, Worker* worker, const PositionCallback<TCoordinate, TStrength>* positionCallback) const
533{
534 ocean_assert(firstColumn + numberColumns <= width_);
535 ocean_assert(firstRow >= (unsigned int)(rows_.firstIndex()) && firstRow + numberRows <= (unsigned int)(rows_.endIndex()));
536
537 if (firstColumn + numberColumns > width_)
538 {
539 return false;
540 }
541
542 if (firstRow >= (unsigned int)(rows_.endIndex()) || firstRow + numberRows <= (unsigned int)(rows_.firstIndex()))
543 {
544 return false;
545 }
546
547 strengthPositions.reserve(strengthPositions.size() + 128);
548
549 if (worker != nullptr)
550 {
551 Lock lock;
552 worker->executeFunction(Worker::Function::create(*this, &NonMaximumSuppressionT<T>::suppressNonMaximumSubset<TCoordinate, TStrength, tStrictMaximum>, &strengthPositions, firstColumn, numberColumns, &lock, positionCallback, 0u, 0u), firstRow, numberRows, 5u, 6u, 3u);
553 }
554 else
555 {
556 suppressNonMaximumSubset<TCoordinate, TStrength, tStrictMaximum>(&strengthPositions, firstColumn, numberColumns, nullptr, positionCallback, firstRow, numberRows);
557 }
558
559 return true;
560}
561
562template <typename T>
563void NonMaximumSuppressionT<T>::candidates(const unsigned int firstColumn, const unsigned int numberColumns, const unsigned int firstRow, const unsigned int numberRows, NonMaximumSuppressionT<T>::StrengthPositions<unsigned int, T>& strengthPositions)
564{
565 ocean_assert(firstColumn + numberColumns <= width_);
566 ocean_assert(firstRow + numberRows <= (unsigned int)(rows_.endIndex()));
567
568 const unsigned int endColumn = firstColumn + numberColumns;
569
570 for (unsigned int y = firstRow; y < firstRow + numberRows; ++y)
571 {
572 const StrengthCandidateRow& row = rows_[y];
573
574 for (const StrengthCandidate& candidate : row)
575 {
576 if (candidate.x() < firstColumn)
577 {
578 continue;
579 }
580
581 if (candidate.x() >= endColumn)
582 {
583 break;
584 }
585
586 strengthPositions.emplace_back(candidate.x(), y, candidate.strength());
587 }
588 }
589}
590
591template <typename T>
593{
594 for (ptrdiff_t n = rows_.firstIndex(); n < rows_.endIndex(); ++n)
595 {
596 rows_[n].clear();
597 }
598}
599
600template <typename T>
602{
603 if (this != &nonMaximumSuppression)
604 {
605 width_ = nonMaximumSuppression.width_;
606 nonMaximumSuppression.width_ = 0u;
607
608 rows_ = std::move(nonMaximumSuppression.rows_);
609 }
610
611 return *this;
612}
613
614template <typename T>
616{
617 if (this != &nonMaximumSuppression)
618 {
619 width_ = nonMaximumSuppression.width_;
620 rows_ = nonMaximumSuppression.rows_;
621 }
622
623 return *this;
624}
625
626template <typename T>
627template <typename TCoordinate, typename TStrength, bool tStrictMaximum>
629{
630 ocean_assert(width >= 1u && height >= 1u);
631 ocean_assert(radius >= TCoordinate(1));
632
633 const unsigned int binSize = std::max(10u, (unsigned int)(NumericT<TCoordinate>::ceil(radius)));
634
635 const unsigned int horizontalBins = std::max(1u, (width + binSize - 1u) / binSize);
636 const unsigned int verticalBins = std::max(1u, (height + binSize - 1u) / binSize);
637
638 ocean_assert(binSize * horizontalBins >= width);
639 ocean_assert(binSize * verticalBins >= height);
640
641 IndexGroups32 indexGroups(horizontalBins * verticalBins);
642
643 // distributing all strength positions into a regular grid to reduce search space later
644
645 for (size_t n = 0; n < strengthPositions.size(); ++n)
646 {
647 const VectorT2<TCoordinate>& position = strengthPositions[n];
648
649 ocean_assert((unsigned int)(position.x()) < width);
650 ocean_assert((unsigned int)(position.y()) < height);
651
652 const unsigned int xBin = (unsigned int)(position.x()) / binSize;
653 const unsigned int yBin = (unsigned int)(position.y()) / binSize;
654
655 ocean_assert(xBin <= horizontalBins);
656 ocean_assert(yBin <= verticalBins);
657
658 indexGroups[yBin * horizontalBins + xBin].emplace_back(Index32(n));
659 }
660
661 std::vector<uint8_t> validPositions(strengthPositions.size(), 1u);
662
663 const TCoordinate sqrRadius = radius * radius;
664
665 for (size_t nCandidate = 0; nCandidate < strengthPositions.size(); ++nCandidate)
666 {
667 if (validPositions[nCandidate] == 0u)
668 {
669 // the positions is already suppressed
670 continue;
671 }
672
673 const StrengthPosition<TCoordinate, TStrength>& candidatePosition = strengthPositions[nCandidate];
674
675 const unsigned int xCandidateBin = (unsigned int)(candidatePosition.x()) / binSize;
676 const unsigned int yCandidateBin = (unsigned int)(candidatePosition.y()) / binSize;
677
678 ocean_assert(xCandidateBin <= horizontalBins);
679 ocean_assert(yCandidateBin <= verticalBins);
680
681 bool checkNextCandidate = false;
682
683 for (unsigned int yBin = (unsigned int)(max(0, int(yCandidateBin) - 1)); !checkNextCandidate && yBin < min(yCandidateBin + 2u, verticalBins); ++yBin)
684 {
685 for (unsigned int xBin = (unsigned int)(max(0, int(xCandidateBin) - 1)); !checkNextCandidate && xBin < min(xCandidateBin + 2u, horizontalBins); ++xBin)
686 {
687 const Indices32& indices = indexGroups[yBin * horizontalBins + xBin];
688
689 for (const Index32& nTest : indices)
690 {
691 if (nTest == Index32(nCandidate))
692 {
693 continue;
694 }
695
696 const StrengthPosition<TCoordinate, TStrength>& testPosition = strengthPositions[nTest];
697
698 // we do not check whether test position is suppressed already (as the test position may still be the reason to suppress the candidate position)
699
700 if (candidatePosition.sqrDistance(testPosition) <= sqrRadius)
701 {
702 if (candidatePosition.strength() > testPosition.strength())
703 {
704 validPositions[nTest] = 0u;
705 }
706 else if (candidatePosition.strength() < testPosition.strength())
707 {
708 validPositions[nCandidate] = 0u;
709
710 checkNextCandidate = true;
711 break;
712 }
713 else
714 {
715 ocean_assert(candidatePosition.strength() == testPosition.strength());
716
717 if constexpr (tStrictMaximum)
718 {
719 // we suppress both elements, as we seek a strict maximum element
720
721 validPositions[nCandidate] = 0u;
722 validPositions[nTest] = 0u;
723
724 checkNextCandidate = true;
725 break;
726 }
727 else
728 {
729 // we will suppress one of both elements, as we accept a non-strict maximum element
730
731 if (candidatePosition.y() < testPosition.y() || (candidatePosition.y() == testPosition.y() && candidatePosition.x() < testPosition.x()))
732 {
733 // the candidate position will be suppressed as the test position is located to the bottom/right of the candidate position
734
735 validPositions[nCandidate] = 0u;
736
737 checkNextCandidate = true;
738 break;
739 }
740 else
741 {
742 ocean_assert(testPosition.y() < candidatePosition.y() || (testPosition.y() == candidatePosition.y() && testPosition.x() < candidatePosition.x()));
743
744 // the test position will be suppressed as the candidate position is located to the bottom/right of the test position
745
746 validPositions[nTest] = 0u;
747 }
748 }
749 }
750 }
751 }
752 }
753 }
754 }
755
757 remainingPositions.reserve(strengthPositions.size());
758
759 if (validIndices)
760 {
761 ocean_assert(validIndices->empty());
762
763 validIndices->clear();
764 validIndices->reserve(strengthPositions.size());
765
766 for (size_t n = 0; n < validPositions.size(); ++n)
767 {
768 if (validPositions[n])
769 {
770 remainingPositions.emplace_back(strengthPositions[n]);
771 validIndices->emplace_back(Index32(n));
772 }
773 }
774 }
775 else
776 {
777 for (size_t n = 0; n < validPositions.size(); ++n)
778 {
779 if (validPositions[n])
780 {
781 remainingPositions.emplace_back(strengthPositions[n]);
782 }
783 }
784 }
785
786 return remainingPositions;
787}
788
789template <typename T>
790template <typename TFloat>
791bool NonMaximumSuppressionT<T>::determinePrecisePeakLocation1(const T& leftValue, const T& middleValue, const T& rightValue, TFloat& location)
792{
793 static_assert(std::is_floating_point<TFloat>::value, "Invalid floating point data type!");
794
795 // f(x) = f(a) + f`(a) * (x - a)
796
797 // we expect our middle value to be located at a = 0:
798 // f(x) = f(0) + f`(0) * x
799
800 // 0 = f'(x)
801 // = f'(0) + f''(0) * x
802
803 // x = - f'(0) / f''(0)
804
805 // f`(x) = [-1 0 1] * 1/2
806 const TFloat df = (TFloat(rightValue) - TFloat(leftValue)) * TFloat(0.5);
807
808 // f``(x) = [1 -2 1] * 1/1
809 const TFloat dff = TFloat(leftValue) + TFloat(rightValue) - TFloat(middleValue) * TFloat(2);
810
812 {
813 location = TFloat(0);
814 return true;
815 }
816
817 const TFloat x = -df / dff;
818
819 if (x < TFloat(-1) || x > TFloat(1))
820 {
821 return false;
822 }
823
824 location = x;
825 return true;
826}
827
828template <typename T>
829template <typename TFloat>
830bool NonMaximumSuppressionT<T>::determinePrecisePeakLocation2(const T* const topValues, const T* const centerValues, const T* const bottomValues, VectorT2<TFloat>& location)
831{
832 static_assert(std::is_floating_point<TFloat>::value, "Invalid floating point data type!");
833
834 const T& value00 = topValues[0];
835 const T& value01 = topValues[1];
836 const T& value02 = topValues[2];
837
838 const T& value10 = centerValues[0];
839 const T& value11 = centerValues[1];
840 const T& value12 = centerValues[2];
841
842 const T& value20 = bottomValues[0];
843 const T& value21 = bottomValues[1];
844 const T& value22 = bottomValues[2];
845
846#if 0
847 // some response values may not perfectly follow the peak criteria so that we do not use the asserts by default
848 ocean_assert(value11 >= value00 && value11 >= value01 && value11 >= value02);
849 ocean_assert(value11 >= value10 && value11 >= value12);
850 ocean_assert(value11 >= value20 && value11 >= value21 && value11 >= value22);
851#endif
852
853 // [-1 0 1] * 1/2
854 const TFloat dx = TFloat(value12 - value10) * TFloat(0.5);
855 const TFloat dy = TFloat(value21 - value01) * TFloat(0.5);
856
857 // [1 -2 1] * 1/1
858 const TFloat dxx = TFloat(value12 + value10) - TFloat(value11) * TFloat(2);
859 const TFloat dyy = TFloat(value21 + value01) - TFloat(value11) * TFloat(2);
860
861 // [ 1 0 -1 ]
862 // [ 0 0 0 ] * 1/4
863 // [-1 0 1 ]
864
865 const TFloat dxy = TFloat(value22 + value00 - value20 - value02) * TFloat(0.25);
866
867 const TFloat denominator = dxx * dyy - dxy * dxy;
868
869 if (NumericT<TFloat>::isEqualEps(denominator))
870 {
871 location = VectorT2<TFloat>(0, 0);
872 return true;
873 }
874
875 const TFloat factor = TFloat(1) / denominator;
876
877 const TFloat offsetX = -(dyy * dx - dxy * dy) * factor;
878 const TFloat offsetY = -(dxx * dy - dxy * dx) * factor;
879
880 if (offsetX < TFloat(-1) || offsetX > TFloat(1) || offsetY < TFloat(-1) || offsetY > TFloat(1))
881 {
882 return false;
883 }
884
885 location = VectorT2<TFloat>(offsetX, offsetY);
886 return true;
887}
888
889template <typename T>
890void NonMaximumSuppressionT<T>::addCandidatesSubset(const T* values, const unsigned int valuesStrideElements, const unsigned int firstColumn, const unsigned int numberColumns, const T* minimalThreshold, const unsigned int firstRow, const unsigned int numberRows)
891{
892 ocean_assert(values != nullptr);
893 ocean_assert(valuesStrideElements >= width_);
894 ocean_assert(firstColumn + numberColumns <= width_);
895
896 ocean_assert(typename StrengthCandidateRows::Index(firstRow) >= rows_.firstIndex());
897 ocean_assert(typename StrengthCandidateRows::Index(firstRow + numberRows) <= rows_.endIndex());
898
899 const T localThreshold = *minimalThreshold;
900
901 values += firstRow * valuesStrideElements;
902
903 for (unsigned int y = firstRow; y < firstRow + numberRows; ++y)
904 {
905 for (unsigned int x = firstColumn; x < firstColumn + numberColumns; ++x)
906 {
907 if (values[x] >= localThreshold)
908 {
909 addCandidate(x, y, values[x]);
910 }
911 }
912
913 values += valuesStrideElements;
914 }
915}
916
917template <typename T>
918template <typename TCoordinate, typename TStrength, bool tStrictMaximum>
919void NonMaximumSuppressionT<T>::suppressNonMaximumSubset(StrengthPositions<TCoordinate, TStrength>* strengthPositions, const unsigned int firstColumn, const unsigned int numberColumns, Lock* lock, const PositionCallback<TCoordinate, TStrength>* positionCallback, const unsigned int firstRow, const unsigned int numberRows) const
920{
921 ocean_assert(strengthPositions);
922
923 ocean_assert(firstColumn + numberColumns <= width_);
924 ocean_assert(firstRow >= (unsigned int)(rows_.firstIndex()));
925 ocean_assert(firstRow + numberRows <= (unsigned int)rows_.endIndex());
926
927 if (numberColumns < 3u || numberRows < 3u)
928 {
929 return;
930 }
931
932 const unsigned int firstCenterColumn = max(1u, firstColumn);
933 const unsigned int endCenterColumn = min(firstColumn + numberColumns, width_ - 1u);
934
935 const unsigned int firstCenterRow = max((unsigned int)rows_.firstIndex() + 1u, firstRow);
936 const unsigned int endCenterRow = min(firstRow + numberRows, (unsigned int)rows_.lastIndex());
937
938 ocean_assert(firstCenterRow >= 1u);
939
940 StrengthPositions<TCoordinate, TStrength> localStrengthPositions;
941 localStrengthPositions.reserve(100);
942
943 for (unsigned int y = firstCenterRow; y < endCenterRow; ++y)
944 {
945 const StrengthCandidateRow& row0 = rows_[y - 1u];
946 const StrengthCandidateRow& row1 = rows_[y + 0u];
947 const StrengthCandidateRow& row2 = rows_[y + 1u];
948
949 typename StrengthCandidateRow::const_iterator iRow0 = row0.begin();
950 typename StrengthCandidateRow::const_iterator iRow2 = row2.begin();
951
952 typename StrengthCandidateRow::const_iterator iRow1Minus = row1.end();
953 typename StrengthCandidateRow::const_iterator iRow1Plus = row1.size() > 1 ? row1.begin() + 1 : row1.end();
954
955 for (typename StrengthCandidateRow::const_iterator iRow1 = row1.begin(); iRow1 != row1.end(); ++iRow1)
956 {
957 ocean_assert(iRow1->x() >= 0u && iRow1->x() + 1u <= width_);
958
959 // check left candidate (west)
960 if (iRow1->x() >= firstCenterColumn && iRow1->x() < endCenterColumn && (iRow1Minus == row1.end() || iRow1Minus->x() + 1u != iRow1->x() || (tStrictMaximum && iRow1Minus->strength() < iRow1->strength()) || (!tStrictMaximum && iRow1Minus->strength() <= iRow1->strength())))
961 {
962 // check right candidate (east)
963 if (iRow1Plus == row1.end() || iRow1Plus->x() != iRow1->x() + 1u || iRow1Plus->strength() < iRow1->strength())
964 {
965 // set the top row iterator to the right position
966 while (iRow0 != row0.end())
967 {
968 if (iRow0->x() + 1u < iRow1->x())
969 {
970 ++iRow0;
971 }
972 else
973 {
974 break;
975 }
976 }
977
978 // now iRow0 should point at least to the north west pixel position (or more far east)
979 ocean_assert(iRow0 == row0.end() || iRow0->x() + 1u >= iRow1->x());
980
981 if (iRow0 != row0.end() && iRow0->x() <= iRow1->x() + 1u)
982 {
983 ocean_assert(iRow0->x() + 1u == iRow1->x() || iRow0->x() == iRow1->x() || iRow0->x() - 1u == iRow1->x());
984
985 if ((tStrictMaximum && iRow0->strength() >= iRow1->strength()) || (!tStrictMaximum && iRow0->strength() > iRow1->strength()))
986 {
987 goto next;
988 }
989
990 // check if there is a further candidate in the north row
991
992 const typename StrengthCandidateRow::const_iterator iRow0Plus = iRow0 + 1;
993
994 if (iRow0Plus != row0.end() && iRow0Plus->x() <= iRow1->x() + 1u)
995 {
996 if ((tStrictMaximum && iRow0Plus->strength() >= iRow1->strength()) || (!tStrictMaximum && iRow0Plus->strength() > iRow1->strength()))
997 {
998 goto next;
999 }
1000
1001 // check if there is a further candidate in the north row
1002
1003 const typename StrengthCandidateRow::const_iterator iRow0PlusPlus = iRow0Plus + 1;
1004
1005 if (iRow0PlusPlus != row0.end() && iRow0PlusPlus->x() <= iRow1->x() + 1u)
1006 {
1007 ocean_assert(iRow0PlusPlus->x() == iRow1->x() + 1u);
1008
1009 if ((tStrictMaximum && iRow0PlusPlus->strength() >= iRow1->strength()) || (!tStrictMaximum && iRow0PlusPlus->strength() > iRow1->strength()))
1010 {
1011 goto next;
1012 }
1013 }
1014 }
1015 }
1016
1017
1018 // set the bottom row iterator to the right position
1019 while (iRow2 != row2.end())
1020 {
1021 if (iRow2->x() + 1u < iRow1->x())
1022 {
1023 ++iRow2;
1024 }
1025 else
1026 {
1027 break;
1028 }
1029 }
1030
1031 // now iRow2 should point at least to the south west pixel position (or more far east)
1032 ocean_assert(iRow2 == row2.end() || iRow2->x() + 1u >= iRow1->x());
1033
1034 if (iRow2 != row2.end() && iRow2->x() <= iRow1->x() + 1u)
1035 {
1036 ocean_assert(iRow2->x() + 1u == iRow1->x() || iRow2->x() == iRow1->x() || iRow2->x() - 1u == iRow1->x());
1037
1038 if (iRow2->x() + 1u == iRow1->x())
1039 {
1040 // iRow2 points to the south west pixel
1041
1042 if ((tStrictMaximum && iRow2->strength() >= iRow1->strength()) || (!tStrictMaximum && iRow2->strength() > iRow1->strength()))
1043 {
1044 goto next;
1045 }
1046 }
1047 else
1048 {
1049 if (iRow2->strength() >= iRow1->strength())
1050 {
1051 goto next;
1052 }
1053 }
1054
1055 // check if there is a further candidate in the south row
1056
1057 const typename StrengthCandidateRow::const_iterator iRow2Plus = iRow2 + 1;
1058
1059 if (iRow2Plus != row2.end() && iRow2Plus->x() <= iRow1->x() + 1u)
1060 {
1061 if (iRow2Plus->strength() >= iRow1->strength())
1062 {
1063 goto next;
1064 }
1065
1066 // check if there is a further candidate in the south row
1067
1068 const typename StrengthCandidateRow::const_iterator iRow2PlusPlus = iRow2Plus + 1;
1069
1070 if (iRow2PlusPlus != row2.end() && iRow2PlusPlus->x() <= iRow1->x() + 1u)
1071 {
1072 ocean_assert(iRow2PlusPlus->x() == iRow1->x() + 1u);
1073
1074 if (iRow2PlusPlus->strength() >= iRow1->strength())
1075 {
1076 goto next;
1077 }
1078 }
1079 }
1080 }
1081
1082 if (positionCallback != nullptr)
1083 {
1084 TCoordinate preciseX;
1085 TCoordinate preciseY;
1086 TStrength preciseStrength;
1087
1088 if ((*positionCallback)(iRow1->x(), y, iRow1->strength(), preciseX, preciseY, preciseStrength))
1089 {
1090 localStrengthPositions.emplace_back(preciseX, preciseY, preciseStrength);
1091 }
1092 }
1093 else
1094 {
1095 localStrengthPositions.emplace_back(TCoordinate(iRow1->x()), TCoordinate(y), iRow1->strength());
1096 }
1097 }
1098 }
1099
1100next:
1101
1102 iRow1Minus = iRow1;
1103
1104 if (iRow1Plus != row1.end())
1105 {
1106 ++iRow1Plus;
1107 }
1108 }
1109 }
1110
1111 const OptionalScopedLock scopedLock(lock);
1112
1113 strengthPositions->insert(strengthPositions->end(), localStrengthPositions.begin(), localStrengthPositions.end());
1114}
1115
1116}
1117
1118}
1119
1120#endif // META_OCEAN_CV_NON_MAXIMUM_SUPPRESSION_H
This class extends a 2D position by a third parameter storing a strength value.
Definition NonMaximumSuppression.h:43
const TStrength & strength() const
Returns the strength parameter of this object.
Definition NonMaximumSuppression.h:385
StrengthPosition()=default
Creates a new object with default strength parameter.
TStrength strength_
Strength parameter of this object.
Definition NonMaximumSuppression.h:78
static bool compareStrength(const StrengthPosition< TCoordinate, TStrength > &left, const StrengthPosition< TCoordinate, TStrength > &right)
Compares the strength value of two objects.
Definition NonMaximumSuppression.h:392
This class provides base functionality and type definitions for non-maximum-suppression operations.
Definition NonMaximumSuppression.h:33
std::vector< StrengthPosition< TCoordinate, TStrength > > StrengthPositions
Definition of a vector holding strength pixel positions.
Definition NonMaximumSuppression.h:85
This class holds the horizontal position and strength parameter of an interest pixel.
Definition NonMaximumSuppression.h:129
StrengthCandidate()
Creates a new candidate object.
Definition NonMaximumSuppression.h:405
unsigned int positionX_
Horizontal position of this object.
Definition NonMaximumSuppression.h:159
const T & strength() const
Returns the strength parameter of this object.
Definition NonMaximumSuppression.h:427
unsigned int x() const
Returns the horizontal position of this candidate object.
Definition NonMaximumSuppression.h:421
T strength_
Strength parameter of this object.
Definition NonMaximumSuppression.h:162
This class implements the possibility to find local maximum in a 2D array by applying a non-maximum-s...
Definition NonMaximumSuppression.h:105
unsigned int yOffset() const
Returns the optional offset in the vertical direction.
Definition NonMaximumSuppression.h:467
void suppressNonMaximumSubset(StrengthPositions< TCoordinate, TStrength > *strengthPositions, const unsigned int firstColumn, const unsigned int firstRow, Lock *lock, const PositionCallback< TCoordinate, TStrength > *positionCallback, const unsigned int numberColumns, const unsigned int numberRows) const
Applies a non-maximum-suppression search on a subset of a given 2D frame in a 3x3 neighborhood (eight...
Definition NonMaximumSuppression.h:919
void reset()
Removes the gathered non-maximum suppression information so that this object can be reused again (for...
Definition NonMaximumSuppression.h:592
static bool determinePrecisePeakLocation2(const T *const topValues, const T *const centerValues, const T *const bottomValues, VectorT2< TFloat > &location)
Determines the precise peak location in 2D space for nine discrete neighboring measurements at locati...
Definition NonMaximumSuppression.h:830
void addCandidate(const unsigned int x, const unsigned int y, const T &strength)
Adds a new candidate to this object.
Definition NonMaximumSuppression.h:475
static StrengthPositions< TCoordinate, TStrength > suppressNonMaximum(const unsigned int width, const unsigned int height, const StrengthPositions< TCoordinate, TStrength > &strengthPositions, const TCoordinate radius, Indices32 *validIndices=nullptr)
Applies a non-maximum-suppression based on already existing strength positions (just with a custom su...
void removeCandidatesRightFrom(const unsigned int x, const unsigned int y)
Removes all candidates from a specified row having a horizontal location equal or larger than a speci...
Definition NonMaximumSuppression.h:511
void candidates(const unsigned int firstColumn, const unsigned int numberColumns, const unsigned int firstRow, const unsigned int numberRows, StrengthPositions< unsigned int, T > &strengthPositions)
Returns all gathered candidates of this object.
Definition NonMaximumSuppression.h:563
unsigned int height() const
Returns the height of this object.
Definition NonMaximumSuppression.h:461
bool suppressNonMaximum(const unsigned int firstColumn, const unsigned int numberColumns, const unsigned int firstRow, const unsigned int numberRows, StrengthPositions< TCoordinate, TStrength > &strengthPositions, Worker *worker=nullptr, const PositionCallback< TCoordinate, TStrength > *positionCallback=nullptr) const
Applies a non-maximum-suppression search on a given 2D frame in a 3x3 neighborhood (eight neighbors).
Definition NonMaximumSuppression.h:532
static bool determinePrecisePeakLocation1(const T &leftValue, const T &middleValue, const T &rightValue, TFloat &location)
Determines the precise peak location in 1D space for three discrete neighboring measurements at locat...
Definition NonMaximumSuppression.h:791
NonMaximumSuppressionT< T > & operator=(NonMaximumSuppressionT< T > &&nonMaximumSuppression)
Move operator.
Definition NonMaximumSuppression.h:601
std::vector< StrengthCandidate > StrengthCandidateRow
Definition of a vector holding strength candidate objects.
Definition NonMaximumSuppression.h:168
std::function< bool(const unsigned int x, const unsigned int y, const TStrength strength, TCoordinate &preciseX, TCoordinate &preciseY, TStrength &preciseStrength)> PositionCallback
Definition of a callback function used to determine the precise sub-pixel position of a specific poin...
Definition NonMaximumSuppression.h:121
NonMaximumSuppressionT(NonMaximumSuppressionT< T > &&nonMaximumSuppression) noexcept
Move constructor.
Definition NonMaximumSuppression.h:433
void addCandidates(const T *values, const unsigned int valuesPaddingElements, const unsigned int firstColumn, const unsigned int numberColumns, const unsigned int firstRow, const unsigned int numberRows, const T &minimalThreshold, Worker *worker)
Adds new candidates to this object from a given buffer providing one value for each bin/pixel of this...
Definition NonMaximumSuppression.h:490
void addCandidatesSubset(const T *values, const unsigned int valuesStrideElements, const unsigned int firstColumn, const unsigned int numberColumns, const T *minimalThreshold, const unsigned int firstRow, const unsigned int numberRows)
Adds new candidates to this object from a subset of a given buffer providing one value for each bin/p...
Definition NonMaximumSuppression.h:890
StrengthCandidateRows rows_
All candidate rows.
Definition NonMaximumSuppression.h:373
unsigned int width_
Width of this object.
Definition NonMaximumSuppression.h:370
unsigned int width() const
Returns the width of this object.
Definition NonMaximumSuppression.h:455
static Caller< void > create(CT &object, typename MemberFunctionPointerMaker< CT, void, NullClass, NullClass, NullClass, NullClass, NullClass, NullClass, NullClass, NullClass, NullClass, NullClass, NullClass, NullClass, NullClass, NullClass, NullClass, NullClass, NullClass, NullClass, NullClass, NullClass >::Type function)
Creates a new caller container for a member function with no function parameter.
Definition Caller.h:3024
This class implements a recursive lock object.
Definition Lock.h:31
This class provides basic numeric functionalities.
Definition Numeric.h:57
This class implements an optional recursive scoped lock object locking the lock object only if it's d...
Definition Lock.h:387
bool isValidIndex(const Index index) const
Returns whether a specific index is valid for this vector and matches to the current offset layout.
Definition ShiftVector.h:646
size_t size() const
Returns the number of elements that are stored by this object.
Definition ShiftVector.h:490
Index endIndex() const
Returns the index of the element behind the last (excluding) element of this object.
Definition ShiftVector.h:435
std::ptrdiff_t Index
Definition of an element index.
Definition ShiftVector.h:38
void clear()
Clears this object, the specified index shift will be untouched.
Definition ShiftVector.h:658
Iterator begin()
Returns the iterator for the first data element.
Definition ShiftVector.h:670
Index lastIndex() const
Returns the index of the last (including) element of this object.
Definition ShiftVector.h:422
Index firstIndex() const
Returns the index of the first element of this object.
Definition ShiftVector.h:416
This class implements a vector with two elements.
Definition Vector2.h:96
const TCoordinate & x() const noexcept
Returns the x value.
Definition Vector2.h:710
const TCoordinate & y() const noexcept
Returns the y value.
Definition Vector2.h:722
T sqrDistance(const VectorT2< T > &right) const
Returns the square distance between this 2D position and a second 2D position.
Definition Vector2.h:645
This class implements a worker able to distribute function calls over different threads.
Definition Worker.h:33
bool executeFunction(const Function &function, const unsigned int first, const unsigned int size, const unsigned int firstIndex=(unsigned int)(-1), const unsigned int sizeIndex=(unsigned int)(-1), const unsigned int minimalIterations=1u, const unsigned int threadIndex=(unsigned int)(-1))
Executes a callback function separable by two function parameters.
std::vector< Index32 > Indices32
Definition of a vector holding 32 bit index values.
Definition Base.h:96
std::vector< 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
The namespace covering the entire Ocean framework.
Definition Accessor.h:15