8#ifndef META_OCEAN_CV_NON_MAXIMUM_SUPPRESSION_H
9#define META_OCEAN_CV_NON_MAXIMUM_SUPPRESSION_H
74 template <
typename TCoordinate,
typename TStrength>
96 inline const TStrength&
strength()
const;
105 template <
bool tLeftLargerThanRight = true>
117 template <
typename TCoordinate,
typename TStrength>
153 template <
typename TCoordinate,
typename TStrength>
181 inline unsigned int x()
const;
234 inline unsigned int width()
const;
240 inline unsigned int height()
const;
246 inline unsigned int yOffset()
const;
256 inline void addCandidate(
const unsigned int x,
const unsigned int y,
const T& strength);
271 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);
288 bool candidate(
const unsigned int x,
const unsigned int y, T& strength)
const;
317 template <
typename TCoordinate,
typename TStrength,
bool tStrictMaximum = true, NonMaximumSuppression::SuppressionMode tSuppressionMode = NonMaximumSuppression::SM_MAXIMUM>
352 template <
typename TCoordinate,
typename TStrength,
bool tStrictMaximum>
365 template <
typename TFloat>
378 template <
typename TFloat>
395 template <
typename TFloat,
unsigned int tSize,
bool tFindMaximum = true>
419 template <
typename TFloat,
unsigned int tSize,
bool tFindMaximum = true, PixelCenter tPixelCenter = PC_TOP_LEFT>
420 static NonMaximumSuppression::RefinementStatus determinePrecisePeakLocationIterativeNxN(
const uint8_t* frame,
const unsigned int width,
const unsigned int height,
const unsigned int framePaddingElements,
const TFloat x,
const TFloat y, TFloat& preciseX, TFloat& preciseY,
const unsigned int maxIterations = 5u,
const TFloat stepSize = TFloat(0.75),
const TFloat convergenceThreshold = TFloat(0.01));
435 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);
452 template <
typename TCoordinate,
typename TStrength,
bool tStrictMaximum,
bool tOnlyPositive = false>
470 template <
typename TCoordinate,
typename TStrength,
bool tStrictMaximum,
bool tOnlyNegative = false>
482template <
typename TCoordinate,
typename TStrength>
490template <
typename TCoordinate,
typename TStrength>
496template <
typename TCoordinate,
typename TStrength>
497template <
bool tLeftLargerThanRight>
500 if constexpr (tLeftLargerThanRight)
541 *
this = std::move(nonMaximumSuppression);
546 width_(nonMaximumSuppression.width_),
547 rows_(nonMaximumSuppression.rows_)
587 if (
rows_[y].empty())
589 rows_[y].reserve(128);
592 rows_[y].emplace_back(x, strength);
596void 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)
598 ocean_assert(values !=
nullptr);
600 ocean_assert(firstColumn + numberColumns <=
width_);
604 const unsigned int valuesStrideElements =
width_ + valuesPaddingElements;
606 if (worker !=
nullptr)
608 worker->
executeFunction(
Worker::Function::create(*
this, &
NonMaximumSuppressionT<T>::addCandidatesSubset, values, valuesStrideElements, firstColumn, numberColumns, &minimalThreshold, 0u, 0u), firstRow, numberRows, 5u, 6u, 20u);
612 addCandidatesSubset(values, valuesStrideElements, firstColumn, numberColumns, &minimalThreshold, firstRow, numberRows);
623 while (!suppressionRow.empty())
625 if (suppressionRow.back().x() >= x)
627 suppressionRow.pop_back();
644 if (suppressionRow.empty())
650 size_t right = suppressionRow.
size() - 1;
652 while (left <= right)
654 const size_t mid = left + (right - left) / 2;
656 const unsigned int midX = suppressionRow[mid].x();
660 strength = suppressionRow[mid].strength();
684 ocean_assert(firstColumn + numberColumns <=
width_);
685 ocean_assert(firstRow + numberRows <= (
unsigned int)(
rows_.
endIndex()));
687 const unsigned int endColumn = firstColumn + numberColumns;
689 for (
unsigned int y = firstRow; y < firstRow + numberRows; ++y)
711template <
typename TCoordinate,
typename TStrength,
bool tStrictMaximum, NonMaximumSuppression::SuppressionMode tSuppressionMode>
714 ocean_assert(firstColumn + numberColumns <=
width_);
717 if (firstColumn + numberColumns >
width_)
727 strengthPositions.reserve(strengthPositions.size() + 128);
733 if (worker !=
nullptr)
736 worker->
executeFunction(
Worker::Function::create(*
this, &
NonMaximumSuppressionT<T>::suppressNonMaximumSubset<TCoordinate, TStrength, tStrictMaximum, tOnlyPositive>, &strengthPositions, firstColumn, numberColumns, &lock, positionCallback, 0u, 0u), firstRow, numberRows, 5u, 6u, 3u);
740 suppressNonMaximumSubset<TCoordinate, TStrength, tStrictMaximum, tOnlyPositive>(&strengthPositions, firstColumn, numberColumns,
nullptr, positionCallback, firstRow, numberRows);
749 if (worker !=
nullptr)
752 worker->
executeFunction(
Worker::Function::create(*
this, &
NonMaximumSuppressionT<T>::suppressNonMinimumSubset<TCoordinate, TStrength, tStrictMaximum, tOnlyNegative>, &strengthPositions, firstColumn, numberColumns, &lock, positionCallback, 0u, 0u), firstRow, numberRows, 5u, 6u, 3u);
756 suppressNonMinimumSubset<TCoordinate, TStrength, tStrictMaximum, tOnlyNegative>(&strengthPositions, firstColumn, numberColumns,
nullptr, positionCallback, firstRow, numberRows);
775 if (
this != &nonMaximumSuppression)
778 nonMaximumSuppression.width_ = 0u;
780 rows_ = std::move(nonMaximumSuppression.rows_);
789 if (
this != &nonMaximumSuppression)
799template <
typename TCoordinate,
typename TStrength,
bool tStrictMaximum>
807 const unsigned int horizontalBins = std::max(1u, (
width + binSize - 1u) / binSize);
808 const unsigned int verticalBins = std::max(1u, (
height + binSize - 1u) / binSize);
810 ocean_assert(binSize * horizontalBins >=
width);
811 ocean_assert(binSize * verticalBins >=
height);
817 for (
size_t n = 0; n < strengthPositions.size(); ++n)
821 ocean_assert((
unsigned int)(position.
x()) <
width);
822 ocean_assert((
unsigned int)(position.
y()) <
height);
824 const unsigned int xBin = (
unsigned int)(position.
x()) / binSize;
825 const unsigned int yBin = (
unsigned int)(position.
y()) / binSize;
827 ocean_assert(xBin <= horizontalBins);
828 ocean_assert(yBin <= verticalBins);
830 indexGroups[yBin * horizontalBins + xBin].emplace_back(
Index32(n));
833 std::vector<uint8_t> validPositions(strengthPositions.size(), 1u);
837 for (
size_t nCandidate = 0; nCandidate < strengthPositions.size(); ++nCandidate)
839 if (validPositions[nCandidate] == 0u)
847 const unsigned int xCandidateBin = (
unsigned int)(candidatePosition.
x()) / binSize;
848 const unsigned int yCandidateBin = (
unsigned int)(candidatePosition.
y()) / binSize;
850 ocean_assert(xCandidateBin <= horizontalBins);
851 ocean_assert(yCandidateBin <= verticalBins);
853 bool checkNextCandidate =
false;
855 for (
unsigned int yBin = (
unsigned int)(max(0,
int(yCandidateBin) - 1)); !checkNextCandidate && yBin < min(yCandidateBin + 2u, verticalBins); ++yBin)
857 for (
unsigned int xBin = (
unsigned int)(max(0,
int(xCandidateBin) - 1)); !checkNextCandidate && xBin < min(xCandidateBin + 2u, horizontalBins); ++xBin)
859 const Indices32& indices = indexGroups[yBin * horizontalBins + xBin];
861 for (
const Index32& nTest : indices)
863 if (nTest ==
Index32(nCandidate))
872 if (candidatePosition.
sqrDistance(testPosition) <= sqrRadius)
876 validPositions[nTest] = 0u;
880 validPositions[nCandidate] = 0u;
882 checkNextCandidate =
true;
889 if constexpr (tStrictMaximum)
893 validPositions[nCandidate] = 0u;
894 validPositions[nTest] = 0u;
896 checkNextCandidate =
true;
903 if (candidatePosition.
y() < testPosition.
y() || (candidatePosition.
y() == testPosition.
y() && candidatePosition.
x() < testPosition.
x()))
907 validPositions[nCandidate] = 0u;
909 checkNextCandidate =
true;
914 ocean_assert(testPosition.
y() < candidatePosition.
y() || (testPosition.
y() == candidatePosition.
y() && testPosition.
x() < candidatePosition.
x()));
918 validPositions[nTest] = 0u;
929 remainingPositions.reserve(strengthPositions.size());
933 ocean_assert(validIndices->empty());
935 validIndices->clear();
936 validIndices->reserve(strengthPositions.size());
938 for (
size_t n = 0; n < validPositions.size(); ++n)
940 if (validPositions[n])
942 remainingPositions.emplace_back(strengthPositions[n]);
943 validIndices->emplace_back(
Index32(n));
949 for (
size_t n = 0; n < validPositions.size(); ++n)
951 if (validPositions[n])
953 remainingPositions.emplace_back(strengthPositions[n]);
958 return remainingPositions;
962template <
typename TFloat>
965 static_assert(std::is_floating_point<TFloat>::value,
"Invalid floating point data type!");
978 const TFloat df = (TFloat(rightValue) - TFloat(leftValue)) * TFloat(0.5);
981 const TFloat dff = TFloat(leftValue) + TFloat(rightValue) - TFloat(middleValue) * TFloat(2);
985 location = TFloat(0);
989 const TFloat x = -df / dff;
991 if (x < TFloat(-1) || x > TFloat(1))
1000template <
typename T>
1001template <
typename TFloat>
1004 static_assert(std::is_floating_point<TFloat>::value,
"Invalid floating point data type!");
1006 const T& value00 = topValues[0];
1007 const T& value01 = topValues[1];
1008 const T& value02 = topValues[2];
1010 const T& value10 = centerValues[0];
1011 const T& value11 = centerValues[1];
1012 const T& value12 = centerValues[2];
1014 const T& value20 = bottomValues[0];
1015 const T& value21 = bottomValues[1];
1016 const T& value22 = bottomValues[2];
1020 ocean_assert(value11 >= value00 && value11 >= value01 && value11 >= value02);
1021 ocean_assert(value11 >= value10 && value11 >= value12);
1022 ocean_assert(value11 >= value20 && value11 >= value21 && value11 >= value22);
1026 const TFloat dx = TFloat(value12 - value10) * TFloat(0.5);
1027 const TFloat dy = TFloat(value21 - value01) * TFloat(0.5);
1030 const TFloat dxx = TFloat(value12 + value10) - TFloat(value11) * TFloat(2);
1031 const TFloat dyy = TFloat(value21 + value01) - TFloat(value11) * TFloat(2);
1037 const TFloat dxy = TFloat(value22 + value00 - value20 - value02) * TFloat(0.25);
1039 const TFloat denominator = dxx * dyy - dxy * dxy;
1047 const TFloat factor = TFloat(1) / denominator;
1049 const TFloat offsetX = -(dyy * dx - dxy * dy) * factor;
1050 const TFloat offsetY = -(dxx * dy - dxy * dx) * factor;
1052 if (offsetX < TFloat(-1) || offsetX > TFloat(1) || offsetY < TFloat(-1) || offsetY > TFloat(1))
1062template <
typename T>
1063template <
typename TFloat,
unsigned int tSize,
bool tFindMaximum>
1066 static_assert(std::is_floating_point<TFloat>::value,
"Invalid floating point data type!");
1067 static_assert(tSize >= 3u && tSize % 2u == 1u,
"Grid size must be odd and >= 3");
1069 ocean_assert(valuesStrideElements >= tSize);
1083 constexpr int tSize_2 = int(tSize / 2u);
1084 constexpr unsigned int n = tSize;
1090 const TFloat sumOfSquaredCoordinates = TFloat(tSize_2 * (tSize_2 + 1) * (2 * tSize_2 + 1)) / TFloat(3);
1091 const TFloat sumOfFourthPowerCoordinates = TFloat(tSize_2 * (tSize_2 + 1) * (2 * tSize_2 + 1) * (3 * tSize_2 * tSize_2 + 3 * tSize_2 - 1)) / TFloat(15);
1093 const TFloat normalEquationGradientDenominator = TFloat(n) * sumOfSquaredCoordinates;
1094 const TFloat squaredSumOfSquaredCoordinates = sumOfSquaredCoordinates * sumOfSquaredCoordinates;
1095 const TFloat normalEquationHessianDenominator = TFloat(n) * sumOfFourthPowerCoordinates - squaredSumOfSquaredCoordinates;
1099 offsetX = TFloat(0);
1100 offsetY = TFloat(0);
1107 TFloat sumValues = TFloat(0);
1108 TFloat sumXValues = TFloat(0);
1109 TFloat sumYValues = TFloat(0);
1110 TFloat sumXXValues = TFloat(0);
1111 TFloat sumYYValues = TFloat(0);
1112 TFloat sumXYValues = TFloat(0);
1114 for (
unsigned int yy = 0u; yy < tSize; ++yy)
1116 const TFloat yj = TFloat(
int(yy) - tSize_2);
1118 for (
unsigned int xx = 0u; xx < tSize; ++xx)
1120 const TFloat xi = TFloat(
int(xx) - tSize_2);
1121 const TFloat z = values[yy * valuesStrideElements + xx];
1124 sumXValues += xi * z;
1125 sumYValues += yj * z;
1126 sumXXValues += xi * xi * z;
1127 sumYYValues += yj * yj * z;
1128 sumXYValues += xi * yj * z;
1134 const TFloat dx = sumXValues / normalEquationGradientDenominator;
1135 const TFloat dy = sumYValues / normalEquationGradientDenominator;
1136 const TFloat dxy = sumXYValues / squaredSumOfSquaredCoordinates;
1138 const TFloat meanValue = sumValues / TFloat(n);
1139 const TFloat dxx = TFloat(2) * (sumXXValues - sumOfSquaredCoordinates * meanValue) / normalEquationHessianDenominator;
1140 const TFloat dyy = TFloat(2) * (sumYYValues - sumOfSquaredCoordinates * meanValue) / normalEquationHessianDenominator;
1142 const TFloat hessianDeterminant = dxx * dyy - dxy * dxy;
1146 offsetX = TFloat(0);
1147 offsetY = TFloat(0);
1154 if constexpr (tFindMaximum)
1156 if (dxx >= TFloat(0) || hessianDeterminant <= TFloat(0))
1158 offsetX = TFloat(0);
1159 offsetY = TFloat(0);
1166 if (dxx <= TFloat(0) || hessianDeterminant <= TFloat(0))
1168 offsetX = TFloat(0);
1169 offsetY = TFloat(0);
1175 const TFloat inverseHessianDeterminant = TFloat(1) / hessianDeterminant;
1177 offsetX = -(dyy * dx - dxy * dy) * inverseHessianDeterminant;
1178 offsetY = -(dxx * dy - dxy * dx) * inverseHessianDeterminant;
1180 if (offsetX < TFloat(-1) || offsetX > TFloat(1) || offsetY < TFloat(-1) || offsetY > TFloat(1))
1188template <
typename T>
1189template <
typename TFloat,
unsigned int tSize,
bool tFindMaximum, PixelCenter tPixelCenter>
1190NonMaximumSuppression::RefinementStatus NonMaximumSuppressionT<T>::determinePrecisePeakLocationIterativeNxN(
const uint8_t* frame,
const unsigned int width,
const unsigned int height,
const unsigned int framePaddingElements,
const TFloat x,
const TFloat y, TFloat& preciseX, TFloat& preciseY,
const unsigned int maxIterations,
const TFloat stepSize,
const TFloat convergenceThreshold)
1192 static_assert(std::is_floating_point<TFloat>::value,
"Invalid floating point data type!");
1193 static_assert(tSize >= 3u && tSize % 2u == 1u,
"Grid size must be odd and >= 3");
1195 ocean_assert(frame !=
nullptr);
1197 ocean_assert(maxIterations >= 1u);
1198 ocean_assert(stepSize > TFloat(0) && stepSize <= TFloat(1));
1199 ocean_assert(convergenceThreshold > TFloat(0));
1201 constexpr unsigned int tSize_2 = tSize / 2u;
1206 ocean_assert(x >= TFloat(0) && x <= maxSampleX);
1207 ocean_assert(y >= TFloat(0) && y <= maxSampleY);
1209 if (x < TFloat(0) || x > maxSampleX || y < TFloat(0) || y > maxSampleY)
1214 TFloat iterationX = x;
1215 TFloat iterationY = y;
1216 TFloat stepFactor = stepSize;
1218 const TFloat sqrConvergenceThreshold = convergenceThreshold * convergenceThreshold;
1220 for (
unsigned int iteration = 0u; iteration < maxIterations; ++iteration)
1222 if (iterationX - TFloat(tSize_2) < TFloat(0) || iterationX + TFloat(tSize_2) > maxSampleX || iterationY - TFloat(tSize_2) < TFloat(0) || iterationY + TFloat(tSize_2) > maxSampleY)
1224 preciseX = iterationX;
1225 preciseY = iterationY;
1230 TFloat interpolatedValues[tSize * tSize];
1232 for (
unsigned int yy = 0u; yy < tSize; ++yy)
1234 for (
unsigned int xx = 0u; xx < tSize; ++xx)
1236 const TFloat sampleX = iterationX + TFloat(
int(xx) -
int(tSize_2));
1237 const TFloat sampleY = iterationY + TFloat(
int(yy) -
int(tSize_2));
1239 ocean_assert(sampleX >= TFloat(0) && sampleX <= maxSampleX);
1240 ocean_assert(sampleY >= TFloat(0) && sampleY <= maxSampleY);
1244 FrameInterpolatorBilinear::interpolatePixel<uint8_t, TFloat, 1u, tPixelCenter, TFloat>(frame,
width,
height, framePaddingElements, samplePos, &interpolatedValues[yy * tSize + xx]);
1251 if (!determinePrecisePeakLocationNxN<TFloat, tSize, tFindMaximum>(interpolatedValues, tSize, fitOffsetX, fitOffsetY))
1253 preciseX = iterationX;
1254 preciseY = iterationY;
1259 if (fitOffsetX == TFloat(0) && fitOffsetY == TFloat(0))
1261 preciseX = iterationX;
1262 preciseY = iterationY;
1267 const TFloat pixelOffsetX = fitOffsetX * stepFactor;
1268 const TFloat pixelOffsetY = fitOffsetY * stepFactor;
1272 preciseX = iterationX;
1273 preciseY = iterationY;
1278 iterationX += pixelOffsetX;
1279 iterationY += pixelOffsetY;
1281 stepFactor *= stepSize;
1283 if (pixelOffsetX * pixelOffsetX + pixelOffsetY * pixelOffsetY < sqrConvergenceThreshold)
1285 preciseX = iterationX;
1286 preciseY = iterationY;
1292 preciseX = iterationX;
1293 preciseY = iterationY;
1298template <
typename T>
1299void 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)
1301 ocean_assert(values !=
nullptr);
1302 ocean_assert(valuesStrideElements >=
width_);
1303 ocean_assert(firstColumn + numberColumns <=
width_);
1308 const T localThreshold = *minimalThreshold;
1310 values += firstRow * valuesStrideElements;
1312 for (
unsigned int y = firstRow; y < firstRow + numberRows; ++y)
1314 for (
unsigned int x = firstColumn; x < firstColumn + numberColumns; ++x)
1316 if (values[x] >= localThreshold)
1322 values += valuesStrideElements;
1326template <
typename T>
1327template <
typename TCoordinate,
typename TStrength,
bool tStrictMaximum,
bool tOnlyPositive>
1330 ocean_assert(strengthPositions);
1332 ocean_assert(firstColumn + numberColumns <=
width_);
1334 ocean_assert(firstRow + numberRows <= (
unsigned int)
rows_.
endIndex());
1336 if (numberColumns < 3u || numberRows < 3u)
1341 const unsigned int firstCenterColumn = max(1u, firstColumn);
1342 const unsigned int endCenterColumn = min(firstColumn + numberColumns,
width_ - 1u);
1344 const unsigned int firstCenterRow = max((
unsigned int)
rows_.
firstIndex() + 1u, firstRow);
1345 const unsigned int endCenterRow = min(firstRow + numberRows, (
unsigned int)
rows_.
lastIndex());
1347 ocean_assert(firstCenterRow >= 1u);
1350 localStrengthPositions.reserve(100);
1352 for (
unsigned int y = firstCenterRow; y < endCenterRow; ++y)
1358 typename StrengthCandidateRow::const_iterator iRow0 = row0.
begin();
1359 typename StrengthCandidateRow::const_iterator iRow2 = row2.begin();
1361 typename StrengthCandidateRow::const_iterator iRow1Minus = row1.end();
1362 typename StrengthCandidateRow::const_iterator iRow1Plus = row1.size() > 1 ? row1.begin() + 1 : row1.end();
1364 for (
typename StrengthCandidateRow::const_iterator iRow1 = row1.begin(); iRow1 != row1.end(); ++iRow1)
1366 ocean_assert(iRow1->x() >= 0u && iRow1->x() + 1u <=
width_);
1369 if constexpr (tOnlyPositive)
1371 if (iRow1->strength() <= T(0))
1378 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())))
1381 if (iRow1Plus == row1.end() || iRow1Plus->x() != iRow1->x() + 1u || iRow1Plus->strength() < iRow1->strength())
1384 while (iRow0 != row0.end())
1386 if (iRow0->x() + 1u < iRow1->x())
1397 ocean_assert(iRow0 == row0.end() || iRow0->x() + 1u >= iRow1->x());
1399 if (iRow0 != row0.end() && iRow0->x() <= iRow1->x() + 1u)
1401 ocean_assert(iRow0->x() + 1u == iRow1->x() || iRow0->x() == iRow1->x() || iRow0->x() - 1u == iRow1->x());
1403 if ((tStrictMaximum && iRow0->strength() >= iRow1->strength()) || (!tStrictMaximum && iRow0->strength() > iRow1->strength()))
1410 const typename StrengthCandidateRow::const_iterator iRow0Plus = iRow0 + 1;
1412 if (iRow0Plus != row0.end() && iRow0Plus->x() <= iRow1->x() + 1u)
1414 if ((tStrictMaximum && iRow0Plus->strength() >= iRow1->strength()) || (!tStrictMaximum && iRow0Plus->strength() > iRow1->strength()))
1421 const typename StrengthCandidateRow::const_iterator iRow0PlusPlus = iRow0Plus + 1;
1423 if (iRow0PlusPlus != row0.end() && iRow0PlusPlus->x() <= iRow1->x() + 1u)
1425 ocean_assert(iRow0PlusPlus->x() == iRow1->x() + 1u);
1427 if ((tStrictMaximum && iRow0PlusPlus->strength() >= iRow1->strength()) || (!tStrictMaximum && iRow0PlusPlus->strength() > iRow1->strength()))
1437 while (iRow2 != row2.end())
1439 if (iRow2->x() + 1u < iRow1->x())
1450 ocean_assert(iRow2 == row2.end() || iRow2->x() + 1u >= iRow1->x());
1452 if (iRow2 != row2.end() && iRow2->x() <= iRow1->x() + 1u)
1454 ocean_assert(iRow2->x() + 1u == iRow1->x() || iRow2->x() == iRow1->x() || iRow2->x() - 1u == iRow1->x());
1456 if (iRow2->x() + 1u == iRow1->x())
1460 if ((tStrictMaximum && iRow2->strength() >= iRow1->strength()) || (!tStrictMaximum && iRow2->strength() > iRow1->strength()))
1467 if (iRow2->strength() >= iRow1->strength())
1475 const typename StrengthCandidateRow::const_iterator iRow2Plus = iRow2 + 1;
1477 if (iRow2Plus != row2.end() && iRow2Plus->x() <= iRow1->x() + 1u)
1479 if (iRow2Plus->strength() >= iRow1->strength())
1486 const typename StrengthCandidateRow::const_iterator iRow2PlusPlus = iRow2Plus + 1;
1488 if (iRow2PlusPlus != row2.end() && iRow2PlusPlus->x() <= iRow1->x() + 1u)
1490 ocean_assert(iRow2PlusPlus->x() == iRow1->x() + 1u);
1492 if (iRow2PlusPlus->strength() >= iRow1->strength())
1500 if (positionCallback !=
nullptr)
1504 TStrength preciseStrength;
1506 if ((*positionCallback)(iRow1->x(), y, iRow1->strength(), preciseX, preciseY, preciseStrength))
1508 localStrengthPositions.emplace_back(preciseX, preciseY, preciseStrength);
1522 if (iRow1Plus != row1.end())
1531 strengthPositions->insert(strengthPositions->end(), localStrengthPositions.begin(), localStrengthPositions.end());
1534template <
typename T>
1535template <
typename TCoordinate,
typename TStrength,
bool tStrictMaximum,
bool tOnlyNegative>
1538 ocean_assert(strengthPositions);
1540 ocean_assert(firstColumn + numberColumns <=
width_);
1542 ocean_assert(firstRow + numberRows <= (
unsigned int)
rows_.
endIndex());
1544 if (numberColumns < 3u || numberRows < 3u)
1549 const unsigned int firstCenterColumn = max(1u, firstColumn);
1550 const unsigned int endCenterColumn = min(firstColumn + numberColumns,
width_ - 1u);
1552 const unsigned int firstCenterRow = max((
unsigned int)
rows_.
firstIndex() + 1u, firstRow);
1553 const unsigned int endCenterRow = min(firstRow + numberRows, (
unsigned int)
rows_.
lastIndex());
1555 ocean_assert(firstCenterRow >= 1u);
1558 localStrengthPositions.reserve(100);
1560 for (
unsigned int y = firstCenterRow; y < endCenterRow; ++y)
1566 typename StrengthCandidateRow::const_iterator iRow0 = row0.
begin();
1567 typename StrengthCandidateRow::const_iterator iRow2 = row2.begin();
1569 typename StrengthCandidateRow::const_iterator iRow1Minus = row1.end();
1570 typename StrengthCandidateRow::const_iterator iRow1Plus = row1.size() > 1 ? row1.begin() + 1 : row1.end();
1572 for (
typename StrengthCandidateRow::const_iterator iRow1 = row1.begin(); iRow1 != row1.end(); ++iRow1)
1574 ocean_assert(iRow1->x() >= 0u && iRow1->x() + 1u <=
width_);
1577 if constexpr (tOnlyNegative)
1579 if (iRow1->strength() >= T(0))
1586 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())))
1589 if (iRow1Plus == row1.end() || iRow1Plus->x() != iRow1->x() + 1u || iRow1Plus->strength() > iRow1->strength())
1592 while (iRow0 != row0.end())
1594 if (iRow0->x() + 1u < iRow1->x())
1605 ocean_assert(iRow0 == row0.end() || iRow0->x() + 1u >= iRow1->x());
1607 if (iRow0 != row0.end() && iRow0->x() <= iRow1->x() + 1u)
1609 ocean_assert(iRow0->x() + 1u == iRow1->x() || iRow0->x() == iRow1->x() || iRow0->x() - 1u == iRow1->x());
1611 if ((tStrictMaximum && iRow0->strength() <= iRow1->strength()) || (!tStrictMaximum && iRow0->strength() < iRow1->strength()))
1618 const typename StrengthCandidateRow::const_iterator iRow0Plus = iRow0 + 1;
1620 if (iRow0Plus != row0.end() && iRow0Plus->x() <= iRow1->x() + 1u)
1622 if ((tStrictMaximum && iRow0Plus->strength() <= iRow1->strength()) || (!tStrictMaximum && iRow0Plus->strength() < iRow1->strength()))
1629 const typename StrengthCandidateRow::const_iterator iRow0PlusPlus = iRow0Plus + 1;
1631 if (iRow0PlusPlus != row0.end() && iRow0PlusPlus->x() <= iRow1->x() + 1u)
1633 ocean_assert(iRow0PlusPlus->x() == iRow1->x() + 1u);
1635 if ((tStrictMaximum && iRow0PlusPlus->strength() <= iRow1->strength()) || (!tStrictMaximum && iRow0PlusPlus->strength() < iRow1->strength()))
1645 while (iRow2 != row2.end())
1647 if (iRow2->x() + 1u < iRow1->x())
1658 ocean_assert(iRow2 == row2.end() || iRow2->x() + 1u >= iRow1->x());
1660 if (iRow2 != row2.end() && iRow2->x() <= iRow1->x() + 1u)
1662 ocean_assert(iRow2->x() + 1u == iRow1->x() || iRow2->x() == iRow1->x() || iRow2->x() - 1u == iRow1->x());
1664 if (iRow2->x() + 1u == iRow1->x())
1668 if ((tStrictMaximum && iRow2->strength() <= iRow1->strength()) || (!tStrictMaximum && iRow2->strength() < iRow1->strength()))
1675 if (iRow2->strength() <= iRow1->strength())
1683 const typename StrengthCandidateRow::const_iterator iRow2Plus = iRow2 + 1;
1685 if (iRow2Plus != row2.end() && iRow2Plus->x() <= iRow1->x() + 1u)
1687 if (iRow2Plus->strength() <= iRow1->strength())
1694 const typename StrengthCandidateRow::const_iterator iRow2PlusPlus = iRow2Plus + 1;
1696 if (iRow2PlusPlus != row2.end() && iRow2PlusPlus->x() <= iRow1->x() + 1u)
1698 ocean_assert(iRow2PlusPlus->x() == iRow1->x() + 1u);
1700 if (iRow2PlusPlus->strength() <= iRow1->strength())
1708 if (positionCallback !=
nullptr)
1712 TStrength preciseStrength;
1714 if ((*positionCallback)(iRow1->x(), y, iRow1->strength(), preciseX, preciseY, preciseStrength))
1716 localStrengthPositions.emplace_back(preciseX, preciseY, preciseStrength);
1730 if (iRow1Plus != row1.end())
1739 strengthPositions->insert(strengthPositions->end(), localStrengthPositions.begin(), localStrengthPositions.end());
This class extends a 2D position by a third parameter storing a strength value.
Definition NonMaximumSuppression.h:76
const TStrength & strength() const
Returns the strength parameter of this object.
Definition NonMaximumSuppression.h:491
StrengthPosition()=default
Creates a new object with default strength parameter.
TStrength strength_
Strength parameter of this object.
Definition NonMaximumSuppression.h:111
static bool compareStrength(const StrengthPosition< TCoordinate, TStrength > &left, const StrengthPosition< TCoordinate, TStrength > &right)
Compares the strength value of two objects.
Definition NonMaximumSuppression.h:498
This class provides base functionality and type definitions for non-maximum-suppression operations.
Definition NonMaximumSuppression.h:34
SuppressionMode
Definition of individual suppression modes for extremum search.
Definition NonMaximumSuppression.h:41
@ SM_MAXIMUM
Finds the maximum values, any value is allowed.
Definition NonMaximumSuppression.h:43
@ SM_MINIMUM
Finds the minimum values, any value is allowed.
Definition NonMaximumSuppression.h:45
@ SM_MAXIMUM_POSITIVE_ONLY
Finds the maximum values, only positive values are allowed (> 0).
Definition NonMaximumSuppression.h:47
@ SM_MINIMUM_NEGATIVE_ONLY
Finds the minimum values, only negative values are allowed (< 0).
Definition NonMaximumSuppression.h:49
RefinementStatus
Definition of individual refinement status values for iterative sub-pixel peak refinement.
Definition NonMaximumSuppression.h:56
@ RS_CONVERGED
The refinement converged, the offset is below the convergence threshold.
Definition NonMaximumSuppression.h:66
@ RS_BORDER
The sample position fell outside the frame bounds.
Definition NonMaximumSuppression.h:62
@ RS_MAX_ITERATIONS
The refinement did not converge within the maximum number of iterations.
Definition NonMaximumSuppression.h:64
@ RS_INVALID
Invalid status, no refinement was applied.
Definition NonMaximumSuppression.h:58
@ RS_DIVERGED
The fitted offset exceeded the step size, indicating divergence.
Definition NonMaximumSuppression.h:60
std::vector< StrengthPosition< TCoordinate, TStrength > > StrengthPositions
Definition of a vector holding strength pixel positions.
Definition NonMaximumSuppression.h:118
This class holds the horizontal position and strength parameter of an interest pixel.
Definition NonMaximumSuppression.h:162
StrengthCandidate()
Creates a new candidate object.
Definition NonMaximumSuppression.h:511
unsigned int positionX_
Horizontal position of this object.
Definition NonMaximumSuppression.h:192
const T & strength() const
Returns the strength parameter of this object.
Definition NonMaximumSuppression.h:533
unsigned int x() const
Returns the horizontal position of this candidate object.
Definition NonMaximumSuppression.h:527
T strength_
Strength parameter of this object.
Definition NonMaximumSuppression.h:195
This class implements the possibility to find local maximum in a 2D array by applying a non-maximum-s...
Definition NonMaximumSuppression.h:138
void 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
Applies a non-maximum-suppression search on a subset of a given 2D frame in a 3x3 neighborhood (eight...
Definition NonMaximumSuppression.h:1328
unsigned int yOffset() const
Returns the optional offset in the vertical direction.
Definition NonMaximumSuppression.h:573
static bool determinePrecisePeakLocationNxN(const TFloat *values, const size_t valuesStrideElements, TFloat &offsetX, TFloat &offsetY)
Determines the precise peak location in 2D space by fitting a quadratic surface via least-squares to ...
Definition NonMaximumSuppression.h:1064
void reset()
Removes the gathered non-maximum suppression information so that this object can be reused again (for...
Definition NonMaximumSuppression.h:764
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:1002
void addCandidate(const unsigned int x, const unsigned int y, const T &strength)
Adds a new candidate to this object.
Definition NonMaximumSuppression.h:581
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:617
unsigned int height() const
Returns the height of this object.
Definition NonMaximumSuppression.h:567
bool candidate(const unsigned int x, const unsigned int y, T &strength) const
Returns the strength value of a candidate at a specified position.
Definition NonMaximumSuppression.h:637
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:963
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:712
NonMaximumSuppressionT< T > & operator=(NonMaximumSuppressionT< T > &&nonMaximumSuppression)
Move operator.
Definition NonMaximumSuppression.h:773
std::vector< StrengthCandidate > StrengthCandidateRow
Definition of a vector holding strength candidate objects.
Definition NonMaximumSuppression.h:201
static NonMaximumSuppression::RefinementStatus determinePrecisePeakLocationIterativeNxN(const uint8_t *frame, const unsigned int width, const unsigned int height, const unsigned int framePaddingElements, const TFloat x, const TFloat y, TFloat &preciseX, TFloat &preciseY, const unsigned int maxIterations=5u, const TFloat stepSize=TFloat(0.75), const TFloat convergenceThreshold=TFloat(0.01))
Determines the precise sub-pixel peak location by iteratively sampling image intensity values at sub-...
Definition NonMaximumSuppression.h:1190
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:154
void suppressNonMinimumSubset(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
Applies a non-minimum-suppression search on a subset of a given 2D frame in a 3x3 neighborhood (eight...
Definition NonMaximumSuppression.h:1536
NonMaximumSuppressionT(NonMaximumSuppressionT< T > &&nonMaximumSuppression) noexcept
Move constructor.
Definition NonMaximumSuppression.h:539
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:596
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:1299
StrengthCandidateRows rows_
All candidate rows.
Definition NonMaximumSuppression.h:479
unsigned int width_
Width of this object.
Definition NonMaximumSuppression.h:476
unsigned int width() const
Returns the width of this object.
Definition NonMaximumSuppression.h:561
void candidates(const unsigned int firstColumn, const unsigned int numberColumns, const unsigned int firstRow, const unsigned int numberRows, StrengthPositions< unsigned int, T > &strengthPositions) const
Returns all gathered candidates of this object.
Definition NonMaximumSuppression.h:682
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
@ PC_TOP_LEFT
The center of a pixel is in the upper-left corner of each pixel's square.
Definition CV.h:133
The namespace covering the entire Ocean framework.
Definition Accessor.h:15