9 #include <boost/assert.hpp> 10 #include <boost/numeric/conversion/cast.hpp> 20 std::vector<unsigned int> range(k);
21 std::iota(range.begin(), range.end(), 0);
25 void TopKSort(
unsigned int k,
unsigned int* indices,
const float* values,
unsigned int numElement)
27 std::partial_sort(indices, indices + k, indices + numElement,
28 [&values](
unsigned int i,
unsigned int j) {
return values[i] > values[j]; });
38 float areaI = (boxI[yMax] - boxI[yMin]) * (boxI[xMax] - boxI[xMin]);
39 float areaJ = (boxJ[yMax] - boxJ[yMin]) * (boxJ[xMax] - boxJ[xMin]);
40 float yMinIntersection = std::max(boxI[yMin], boxJ[yMin]);
41 float xMinIntersection = std::max(boxI[xMin], boxJ[xMin]);
42 float yMaxIntersection = std::min(boxI[yMax], boxJ[yMax]);
43 float xMaxIntersection = std::min(boxI[xMax], boxJ[xMax]);
44 float areaIntersection = std::max(yMaxIntersection - yMinIntersection, 0.0f) *
45 std::max(xMaxIntersection - xMinIntersection, 0.0f);
46 float areaUnion = areaI + areaJ - areaIntersection;
47 return areaIntersection / areaUnion;
51 const std::vector<float>& boxCorners,
52 const std::vector<float>&
scores,
53 float nmsScoreThreshold,
54 unsigned int maxDetection,
55 float nmsIouThreshold)
58 std::vector<float> scoresAboveThreshold;
59 std::vector<unsigned int> indicesAboveThreshold;
60 for (
unsigned int i = 0; i < numBoxes; ++i)
62 if (scores[i] >= nmsScoreThreshold)
64 scoresAboveThreshold.push_back(scores[i]);
65 indicesAboveThreshold.push_back(i);
70 unsigned int numAboveThreshold = boost::numeric_cast<
unsigned int>(scoresAboveThreshold.size());
71 std::vector<unsigned int> sortedIndices =
GenerateRangeK(numAboveThreshold);
72 TopKSort(numAboveThreshold, sortedIndices.data(), scoresAboveThreshold.data(), numAboveThreshold);
75 unsigned int numOutput = std::min(maxDetection, numAboveThreshold);
76 std::vector<unsigned int> outputIndices;
77 std::vector<bool> visited(numAboveThreshold,
false);
80 for (
unsigned int i = 0; i < numAboveThreshold; ++i)
82 if (outputIndices.size() >= numOutput)
86 if (!visited[sortedIndices[i]])
88 outputIndices.push_back(indicesAboveThreshold[sortedIndices[i]]);
90 for (
unsigned int j = i + 1; j < numAboveThreshold; ++j)
92 unsigned int iIndex = indicesAboveThreshold[sortedIndices[i]] * 4;
93 unsigned int jIndex = indicesAboveThreshold[sortedIndices[j]] * 4;
96 visited[sortedIndices[j]] =
true;
100 return outputIndices;
104 unsigned int numSelected,
105 const std::vector<float>& boxCorners,
106 const std::vector<unsigned int>& outputIndices,
107 const std::vector<unsigned int>& selectedBoxes,
108 const std::vector<unsigned int>& selectedClasses,
109 const std::vector<float>& selectedScores,
110 float* detectionBoxes,
111 float* detectionScores,
112 float* detectionClasses,
113 float* numDetections)
115 for (
unsigned int i = 0; i < numOutput; ++i)
117 unsigned int boxIndex = i * 4;
120 unsigned int boxCornorIndex = selectedBoxes[outputIndices[i]] * 4;
121 detectionScores[i] = selectedScores[outputIndices[i]];
122 detectionClasses[i] = boost::numeric_cast<
float>(selectedClasses[outputIndices[i]]);
123 detectionBoxes[boxIndex] = boxCorners[boxCornorIndex];
124 detectionBoxes[boxIndex + 1] = boxCorners[boxCornorIndex + 1];
125 detectionBoxes[boxIndex + 2] = boxCorners[boxCornorIndex + 2];
126 detectionBoxes[boxIndex + 3] = boxCorners[boxCornorIndex + 3];
130 detectionScores[i] = 0.0f;
131 detectionClasses[i] = 0.0f;
132 detectionBoxes[boxIndex] = 0.0f;
133 detectionBoxes[boxIndex + 1] = 0.0f;
134 detectionBoxes[boxIndex + 2] = 0.0f;
135 detectionBoxes[boxIndex + 3] = 0.0f;
138 numDetections[0] = boost::numeric_cast<
float>(numSelected);
152 float* detectionBoxes,
153 float* detectionClasses,
154 float* detectionScores,
155 float* numDetections)
157 boost::ignore_unused(anchorsInfo, detectionClassesInfo, detectionScoresInfo, numDetectionsInfo);
163 const unsigned int numBoxes = boxEncodingsInfo.
GetShape()[1];
166 for (
unsigned int i = 0; i < numBoxes; ++i)
169 float boxEncodingY = boxEncodings.
Get();
170 float anchorY = anchors.
Get();
176 float boxEncodingX = boxEncodings.
Get();
177 float anchorX = anchors.
Get();
183 float boxEncodingH = boxEncodings.
Get();
184 float anchorH = anchors.
Get();
190 float boxEncodingW = boxEncodings.
Get();
191 float anchorW = anchors.
Get();
196 float yCentre = boxEncodingY / desc.
m_ScaleY * anchorH + anchorY;
197 float xCentre = boxEncodingX / desc.
m_ScaleX * anchorW + anchorX;
199 float halfH = 0.5f * expf(boxEncodingH / desc.
m_ScaleH) * anchorH;
200 float halfW = 0.5f * expf(boxEncodingW / desc.
m_ScaleW) * anchorW;
202 unsigned int indexY = i * 4;
203 unsigned int indexX = indexY + 1;
204 unsigned int indexH = indexX + 1;
205 unsigned int indexW = indexH + 1;
208 boxCorners[indexY] = yCentre - halfH;
210 boxCorners[indexX] = xCentre - halfW;
212 boxCorners[indexH] = yCentre + halfH;
214 boxCorners[indexW] = xCentre + halfW;
216 BOOST_ASSERT(boxCorners[indexY] < boxCorners[indexH]);
217 BOOST_ASSERT(boxCorners[indexX] < boxCorners[indexW]);
223 std::vector<float> decodedScores;
224 decodedScores.reserve(numScores);
226 for (
unsigned int i = 0u; i < numScores; ++i)
228 decodedScores.emplace_back(scores.
Get());
237 std::vector<float> classScores(numBoxes);
239 std::vector<unsigned int> selectedBoxesAfterNms;
240 selectedBoxesAfterNms.reserve(numBoxes);
242 std::vector<float> selectedScoresAfterNms;
243 selectedBoxesAfterNms.reserve(numScores);
245 std::vector<unsigned int> selectedClasses;
250 for (
unsigned int i = 0; i < numBoxes; ++i)
252 classScores[i] = decodedScores[i * numClassesWithBg + c + 1];
261 for (
unsigned int i = 0; i < selectedIndices.size(); ++i)
263 selectedBoxesAfterNms.push_back(selectedIndices[i]);
264 selectedScoresAfterNms.push_back(classScores[selectedIndices[i]]);
265 selectedClasses.push_back(c);
270 unsigned int numSelected = boost::numeric_cast<
unsigned int>(selectedBoxesAfterNms.size());
274 std::vector<unsigned int> outputIndices =
GenerateRangeK(numSelected);
275 TopKSort(numOutput, outputIndices.data(), selectedScoresAfterNms.data(), numSelected);
278 selectedBoxesAfterNms, selectedClasses, selectedScoresAfterNms,
279 detectionBoxes, detectionScores, detectionClasses, numDetections);
287 std::vector<float> maxScores;
288 std::vector<unsigned int>boxIndices;
289 std::vector<unsigned int>maxScoreClasses;
291 for (
unsigned int box = 0; box < numBoxes; ++box)
293 unsigned int scoreIndex = box * numClassesWithBg + 1;
297 TopKSort(numClassesPerBox, maxScoreIndices.data(),
300 for (
unsigned int i = 0; i < numClassesPerBox; ++i)
302 maxScores.push_back(decodedScores[scoreIndex + maxScoreIndices[i]]);
303 maxScoreClasses.push_back(maxScoreIndices[i]);
304 boxIndices.push_back(box);
309 std::vector<unsigned int> selectedIndices =
NonMaxSuppression(numBoxes, boxCorners, maxScores,
314 unsigned int numSelected = boost::numeric_cast<
unsigned int>(selectedIndices.size());
318 boxIndices, maxScoreClasses, maxScores,
319 detectionBoxes, detectionScores, detectionClasses, numDetections);
float m_ScaleX
Center size encoding scale x.
uint32_t m_MaxClassesPerDetection
Maximum numbers of classes per detection, used in Fast NMS.
uint32_t m_NumClasses
Number of classes.
float m_ScaleW
Center size encoding scale weight.
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)
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::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.
bool m_UseRegularNms
Use Regular NMS.
armnn::TensorInfo scoresInfo({ 1, 6, 3 }, armnn::DataType::Float32)
std::vector< float > scores({ 0.0f, 0.9f, 0.8f, 0.0f, 0.75f, 0.72f, 0.0f, 0.6f, 0.5f, 0.0f, 0.93f, 0.95f, 0.0f, 0.5f, 0.4f, 0.0f, 0.3f, 0.2f })
float m_NmsIouThreshold
Intersection over union threshold.
uint32_t m_DetectionsPerClass
Detections per classes, used in Regular NMS.
float m_NmsScoreThreshold
NMS score threshold.
std::vector< float > boxEncodings({ 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f })
void TopKSort(unsigned int k, unsigned int *indices, const float *values, unsigned int numElement)
std::vector< float > anchors({ 0.5f, 0.5f, 1.0f, 1.0f, 0.5f, 0.5f, 1.0f, 1.0f, 0.5f, 0.5f, 1.0f, 1.0f, 0.5f, 10.5f, 1.0f, 1.0f, 0.5f, 10.5f, 1.0f, 1.0f, 0.5f, 100.5f, 1.0f, 1.0f })
unsigned int GetNumElements() const
std::vector< unsigned int > GenerateRangeK(unsigned int k)
virtual IType Get() const =0
armnn::TensorInfo anchorsInfo({ 6, 4 }, armnn::DataType::Float32)
float IntersectionOverUnion(const float *boxI, const float *boxJ)
const TensorShape & GetShape() const
float m_ScaleH
Center size encoding scale height.
uint32_t m_MaxDetections
Maximum numbers of detections.