pcod-common v1.0.0
Shared preprocessing and postprocessing for point-cloud object detection
Loading...
Searching...
No Matches
test_nms.cpp
Go to the documentation of this file.
1// Copyright Institute for Automotive Engineering (ika), RWTH Aachen University
2// SPDX-License-Identifier: Apache-2.0
3
4#include "pcod_common/nms.hpp"
5
6#include <cassert>
7#include <cmath>
8#include <vector>
9
10namespace {
11
22pcod_common::BoundingBox MakeBox(std::size_t idx, float x, float y, float length, float width, float yaw, float score) {
24 box.center = {x, y};
25 box.z = static_cast<float>(idx);
26 box.length = length;
27 box.width = width;
28 box.height = 1.0f;
29 box.yaw = yaw;
30 box.existence_probability = score;
31 box.classification.push_back({0, 1.0f});
32 return box;
33}
34
41void RunNmsCase(std::vector<pcod_common::BoundingBox> boxes,
42 float iou_threshold,
43 int max_detections,
44 const std::vector<std::size_t>& expected_indices) {
46 config.score_thresholds = {0.1f};
47 config.iou_threshold = iou_threshold;
48 config.max_detections = max_detections;
49
50 pcod_common::ApplyRotatedNms(boxes, config);
51
52 assert(boxes.size() == expected_indices.size());
53 for (std::size_t i = 0; i < expected_indices.size(); ++i) {
54 assert(static_cast<std::size_t>(std::lround(boxes[i].z)) == expected_indices[i]);
55 }
56}
57
58} // namespace
59
61int main() {
62 {
64 box_a.center = {0.0f, 0.0f};
65 box_a.length = 4.0f;
66 box_a.width = 2.0f;
67 box_a.existence_probability = 0.9f;
68 box_a.classification.push_back({0, 1.0f});
69
70 pcod_common::BoundingBox box_b = box_a;
71 box_b.center = {0.5f, 0.0f};
72 box_b.existence_probability = 0.8f;
73
74 std::vector<pcod_common::BoundingBox> boxes{box_a, box_b};
75
77 config.score_thresholds = {0.1f};
78 config.iou_threshold = 0.1f;
79 config.max_detections = 10;
80
81 pcod_common::ApplyRotatedNms(boxes, config);
82 assert(boxes.size() == 1);
83 assert(std::abs(boxes[0].center[0]) < 1e-6f);
84 assert(std::abs(boxes[0].center[1]) < 1e-6f);
85 }
86
87 {
88 RunNmsCase(
89 {
90 MakeBox(0, 0.0f, 0.0f, 4.0f, 2.0f, 0.0f, 0.9f),
91 MakeBox(1, 0.0f, 0.0f, 4.0f, 2.0f, 0.0f, 0.8f),
92 },
93 0.1f, 10, {0});
94
95 RunNmsCase(
96 {
97 MakeBox(0, 0.0f, 0.0f, 4.0f, 2.0f, 0.0f, 0.9f),
98 MakeBox(1, 0.5f, 0.0f, 4.0f, 2.0f, 0.0f, 0.8f),
99 },
100 0.1f, 10, {0});
101
102 RunNmsCase(
103 {
104 MakeBox(0, 0.0f, 0.0f, 4.0f, 2.0f, 0.0f, 0.9f),
105 MakeBox(1, 3.5f, 0.0f, 4.0f, 2.0f, 0.0f, 0.8f),
106 },
107 0.1f, 10, {0, 1});
108
109 RunNmsCase(
110 {
111 MakeBox(0, 0.0f, 0.0f, 4.0f, 2.0f, 0.0f, 0.9f),
112 MakeBox(1, 4.0f, 0.0f, 4.0f, 2.0f, 0.0f, 0.8f),
113 },
114 0.0f, 10, {0, 1});
115
116 RunNmsCase(
117 {
118 MakeBox(0, 0.0f, 0.0f, 6.0f, 4.0f, 0.0f, 0.9f),
119 MakeBox(1, 0.0f, 0.0f, 2.0f, 1.0f, 0.0f, 0.8f),
120 },
121 0.05f, 10, {0});
122
123 RunNmsCase(
124 {
125 MakeBox(0, 0.0f, 0.0f, 4.0f, 2.0f, static_cast<float>(M_PI / 4.0), 0.9f),
126 MakeBox(1, 0.2f, 0.1f, 4.0f, 2.0f, static_cast<float>(M_PI / 4.0), 0.8f),
127 },
128 0.1f, 10, {0});
129
130 RunNmsCase(
131 {
132 MakeBox(0, 0.0f, 0.0f, 4.0f, 2.0f, static_cast<float>(M_PI / 4.0), 0.9f),
133 MakeBox(1, 0.0f, 0.0f, 4.0f, 2.0f, static_cast<float>(-M_PI / 4.0), 0.8f),
134 },
135 0.1f, 10, {0});
136
137 RunNmsCase(
138 {
139 MakeBox(0, 0.0f, 0.0f, 4.0f, 2.0f, static_cast<float>(M_PI / 4.0), 0.9f),
140 MakeBox(1, 4.0f, 4.0f, 4.0f, 2.0f, static_cast<float>(M_PI / 4.0), 0.8f),
141 },
142 0.1f, 10, {0, 1});
143
144 RunNmsCase(
145 {
146 MakeBox(0, 0.0f, 0.0f, 4.0f, 2.0f, 0.0f, 0.8f),
147 MakeBox(1, 0.5f, 0.0f, 4.0f, 2.0f, 0.0f, 0.95f),
148 MakeBox(2, 8.0f, 0.0f, 4.0f, 2.0f, 0.0f, 0.7f),
149 },
150 0.1f, 10, {1, 2});
151
152 RunNmsCase(
153 {
154 MakeBox(0, 0.0f, 0.0f, 4.0f, 2.0f, 0.0f, 0.9f),
155 MakeBox(1, 8.0f, 0.0f, 4.0f, 2.0f, 0.0f, 0.8f),
156 MakeBox(2, 16.0f, 0.0f, 4.0f, 2.0f, 0.0f, 0.7f),
157 },
158 0.1f, 2, {0, 1});
159 }
160
161 {
163 keep_box.center = {0.0f, 0.0f};
164 keep_box.length = 1.0f;
165 keep_box.width = 1.0f;
166 keep_box.existence_probability = 0.6f;
167 keep_box.classification.push_back({0, 0.9f});
168 keep_box.classification.push_back({1, 0.1f});
169
171 drop_box.center = {10.0f, 10.0f}; // ensure no IoU suppression interaction
172 drop_box.length = 1.0f;
173 drop_box.width = 1.0f;
174 drop_box.existence_probability = 0.4f;
175 drop_box.classification.push_back({0, 0.1f});
176 drop_box.classification.push_back({1, 0.9f});
177
178 std::vector<pcod_common::BoundingBox> boxes{keep_box, drop_box};
180 config.score_thresholds = {0.1f, 0.9f};
181 config.iou_threshold = 0.1f;
182 config.max_detections = 10;
183 config.internal_score_threshold = 0.5f;
184
185 pcod_common::ApplyRotatedNms(boxes, config);
186 assert(boxes.size() == 1);
187 assert(std::abs(boxes[0].center[0]) < 1e-6f);
188 assert(std::abs(boxes[0].center[1]) < 1e-6f);
189 }
190
191 return 0;
192}
void ApplyRotatedNms(std::vector< BoundingBox > &bboxes, const NmsConfig &config)
Definition nms.cpp:12
float length
Length along the local X axis.
std::array< float, 2 > center
XY center in metres.
float height
Height along the Z axis.
float z
Z center in metres.
float width
Width along the local Y axis.
std::vector< ClassificationEntry > classification
Ranked semantic predictions.
float existence_probability
Detection confidence.
float yaw
Heading in radians.
float iou_threshold
IoU above which a lower-scored box is suppressed.
Definition nms.hpp:15
std::vector< float > score_thresholds
Per-class thresholds, or one threshold shared by all classes.
Definition nms.hpp:14
int max_detections
Maximum number of boxes retained.
Definition nms.hpp:16
float internal_score_threshold
Score pivot used when rescaling class thresholds.
Definition nms.hpp:17
int main()
Definition test_nms.cpp:61