19 std::vector<unsigned int> range(k);
20 std::iota(range.begin(), range.end(), 0);
24 void TopKSort(
unsigned int k,
unsigned int* indices,
const float* values,
unsigned int numElement)
26 std::partial_sort(indices, indices + k, indices + numElement,
27 [&values](
unsigned int i,
unsigned int j) {
return values[i] > values[j]; });
37 float areaI = (boxI[yMax] - boxI[yMin]) * (boxI[xMax] - boxI[xMin]);
38 float areaJ = (boxJ[yMax] - boxJ[yMin]) * (boxJ[xMax] - boxJ[xMin]);
39 float yMinIntersection = std::max(boxI[yMin], boxJ[yMin]);
40 float xMinIntersection = std::max(boxI[xMin], boxJ[xMin]);
41 float yMaxIntersection = std::min(boxI[yMax], boxJ[yMax]);
42 float xMaxIntersection = std::min(boxI[xMax], boxJ[xMax]);
43 float areaIntersection = std::max(yMaxIntersection - yMinIntersection, 0.0f) *
44 std::max(xMaxIntersection - xMinIntersection, 0.0f);
45 float areaUnion = areaI + areaJ - areaIntersection;
46 return areaIntersection / areaUnion;
50 const std::vector<float>& boxCorners,
51 const std::vector<float>& scores,
52 float nmsScoreThreshold,
53 unsigned int maxDetection,
54 float nmsIouThreshold)
57 std::vector<float> scoresAboveThreshold;
58 std::vector<unsigned int> indicesAboveThreshold;
59 for (
unsigned int i = 0; i < numBoxes; ++i)
61 if (scores[i] >= nmsScoreThreshold)
63 scoresAboveThreshold.push_back(scores[i]);
64 indicesAboveThreshold.push_back(i);
69 unsigned int numAboveThreshold =
armnn::numeric_cast<
unsigned int>(scoresAboveThreshold.size());
70 std::vector<unsigned int> sortedIndices =
GenerateRangeK(numAboveThreshold);
71 TopKSort(numAboveThreshold, sortedIndices.data(), scoresAboveThreshold.data(), numAboveThreshold);
74 unsigned int numOutput = std::min(maxDetection, numAboveThreshold);
75 std::vector<unsigned int> outputIndices;
76 std::vector<bool> visited(numAboveThreshold,
false);
79 for (
unsigned int i = 0; i < numAboveThreshold; ++i)
81 if (outputIndices.size() >= numOutput)
85 if (!visited[sortedIndices[i]])
87 outputIndices.push_back(indicesAboveThreshold[sortedIndices[i]]);
88 for (
unsigned int j = i + 1; j < numAboveThreshold; ++j)
90 unsigned int iIndex = indicesAboveThreshold[sortedIndices[i]] * 4;
91 unsigned int jIndex = indicesAboveThreshold[sortedIndices[j]] * 4;
94 visited[sortedIndices[j]] =
true;
103 unsigned int numSelected,
104 const std::vector<float>& boxCorners,
105 const std::vector<unsigned int>& outputIndices,
106 const std::vector<unsigned int>& selectedBoxes,
107 const std::vector<unsigned int>& selectedClasses,
108 const std::vector<float>& selectedScores,
109 float* detectionBoxes,
110 float* detectionScores,
111 float* detectionClasses,
112 float* numDetections)
114 for (
unsigned int i = 0; i < numOutput; ++i)
116 unsigned int boxIndex = i * 4;
119 unsigned int boxCornorIndex = selectedBoxes[outputIndices[i]] * 4;
120 detectionScores[i] = selectedScores[outputIndices[i]];
122 detectionBoxes[boxIndex] = boxCorners[boxCornorIndex];
123 detectionBoxes[boxIndex + 1] = boxCorners[boxCornorIndex + 1];
124 detectionBoxes[boxIndex + 2] = boxCorners[boxCornorIndex + 2];
125 detectionBoxes[boxIndex + 3] = boxCorners[boxCornorIndex + 3];
129 detectionScores[i] = 0.0f;
130 detectionClasses[i] = 0.0f;
131 detectionBoxes[boxIndex] = 0.0f;
132 detectionBoxes[boxIndex + 1] = 0.0f;
133 detectionBoxes[boxIndex + 2] = 0.0f;
134 detectionBoxes[boxIndex + 3] = 0.0f;
151 float* detectionBoxes,
152 float* detectionClasses,
153 float* detectionScores,
154 float* numDetections)
156 IgnoreUnused(anchorsInfo, detectionClassesInfo, detectionScoresInfo, numDetectionsInfo);
162 const unsigned int numBoxes = boxEncodingsInfo.
GetShape()[1];
165 for (
unsigned int i = 0; i < numBoxes; ++i)
168 float boxEncodingY = boxEncodings.
Get();
169 float anchorY = anchors.
Get();
175 float boxEncodingX = boxEncodings.
Get();
176 float anchorX = anchors.
Get();
182 float boxEncodingH = boxEncodings.
Get();
183 float anchorH = anchors.
Get();
189 float boxEncodingW = boxEncodings.
Get();
190 float anchorW = anchors.
Get();
195 float yCentre = boxEncodingY / desc.
m_ScaleY * anchorH + anchorY;
196 float xCentre = boxEncodingX / desc.
m_ScaleX * anchorW + anchorX;
198 float halfH = 0.5f * expf(boxEncodingH / desc.
m_ScaleH) * anchorH;
199 float halfW = 0.5f * expf(boxEncodingW / desc.
m_ScaleW) * anchorW;
201 unsigned int indexY = i * 4;
202 unsigned int indexX = indexY + 1;
203 unsigned int indexH = indexX + 1;
204 unsigned int indexW = indexH + 1;
207 boxCorners[indexY] = yCentre - halfH;
209 boxCorners[indexX] = xCentre - halfW;
211 boxCorners[indexH] = yCentre + halfH;
213 boxCorners[indexW] = xCentre + halfW;
222 std::vector<float> decodedScores;
223 decodedScores.reserve(numScores);
225 for (
unsigned int i = 0u; i < numScores; ++i)
227 decodedScores.emplace_back(scores.
Get());
236 std::vector<float> classScores(numBoxes);
238 std::vector<unsigned int> selectedBoxesAfterNms;
239 selectedBoxesAfterNms.reserve(numBoxes);
241 std::vector<float> selectedScoresAfterNms;
242 selectedBoxesAfterNms.reserve(numScores);
244 std::vector<unsigned int> selectedClasses;
249 for (
unsigned int i = 0; i < numBoxes; ++i)
251 classScores[i] = decodedScores[i * numClassesWithBg + c + 1];
260 for (
unsigned int i = 0; i < selectedIndices.size(); ++i)
262 selectedBoxesAfterNms.push_back(selectedIndices[i]);
263 selectedScoresAfterNms.push_back(classScores[selectedIndices[i]]);
264 selectedClasses.push_back(c);
269 unsigned int numSelected =
armnn::numeric_cast<
unsigned int>(selectedBoxesAfterNms.size());
273 std::vector<unsigned int> outputIndices =
GenerateRangeK(numSelected);
274 TopKSort(numOutput, outputIndices.data(), selectedScoresAfterNms.data(), numSelected);
277 selectedBoxesAfterNms, selectedClasses, selectedScoresAfterNms,
278 detectionBoxes, detectionScores, detectionClasses, numDetections);
286 std::vector<float> maxScores;
287 std::vector<unsigned int>boxIndices;
288 std::vector<unsigned int>maxScoreClasses;
290 for (
unsigned int box = 0; box < numBoxes; ++box)
292 unsigned int scoreIndex = box * numClassesWithBg + 1;
296 TopKSort(numClassesPerBox, maxScoreIndices.data(),
299 for (
unsigned int i = 0; i < numClassesPerBox; ++i)
301 maxScores.push_back(decodedScores[scoreIndex + maxScoreIndices[i]]);
302 maxScoreClasses.push_back(maxScoreIndices[i]);
303 boxIndices.push_back(box);
308 std::vector<unsigned int> selectedIndices =
NonMaxSuppression(numBoxes, boxCorners, maxScores,
317 boxIndices, maxScoreClasses, maxScores,
318 detectionBoxes, detectionScores, detectionClasses, numDetections);
float m_ScaleW
Center size encoding scale weight.
float IntersectionOverUnion(const float *boxI, const float *boxJ)
const TensorShape & GetShape() const
float m_ScaleX
Center size encoding scale x.
uint32_t m_DetectionsPerClass
Detections per classes, used in Regular NMS.
std::vector< unsigned int > GenerateRangeK(unsigned int k)
Copyright (c) 2021 ARM Limited and Contributors.
void IgnoreUnused(Ts &&...)
uint32_t m_MaxClassesPerDetection
Maximum numbers of classes per detection, used in Fast NMS.
virtual IType Get() const =0
uint32_t m_MaxDetections
Maximum numbers of detections.
void DetectionPostProcess(const TensorInfo &boxEncodingsInfo, const TensorInfo &scoresInfo, const TensorInfo &anchorsInfo, const TensorInfo &detectionBoxesInfo, const TensorInfo &detectionClassesInfo, const TensorInfo &detectionScoresInfo, const TensorInfo &numDetectionsInfo, const DetectionPostProcessDescriptor &desc, Decoder< float > &boxEncodings, Decoder< float > &scores, Decoder< float > &anchors, float *detectionBoxes, float *detectionClasses, float *detectionScores, float *numDetections)
float m_NmsIouThreshold
Intersection over union threshold.
void TopKSort(unsigned int k, unsigned int *indices, const float *values, unsigned int numElement)
uint32_t m_NumClasses
Number of classes.
#define ARMNN_ASSERT(COND)
bool m_UseRegularNms
Use Regular NMS.
float m_ScaleH
Center size encoding scale height.
void AllocateOutputData(unsigned int numOutput, unsigned int numSelected, const std::vector< float > &boxCorners, const std::vector< unsigned int > &outputIndices, const std::vector< unsigned int > &selectedBoxes, const std::vector< unsigned int > &selectedClasses, const std::vector< float > &selectedScores, float *detectionBoxes, float *detectionScores, float *detectionClasses, float *numDetections)
std::enable_if_t< std::is_unsigned< Source >::value &&std::is_unsigned< Dest >::value, Dest > numeric_cast(Source source)
std::vector< unsigned int > NonMaxSuppression(unsigned int numBoxes, const std::vector< float > &boxCorners, const std::vector< float > &scores, float nmsScoreThreshold, unsigned int maxDetection, float nmsIouThreshold)
float m_ScaleY
Center size encoding scale y.
float m_NmsScoreThreshold
NMS score threshold.
unsigned int GetNumElements() const