39 using CandidateBox = std::pair<
int ,
float >;
40 using Box = std::tuple<float, float, float, float>;
42 inline float get_elem_by_coordinate(
const SimpleTensor<float> &
tensor, Coordinates coord)
44 return *
static_cast<const float *
>(
tensor(coord));
47 inline Box get_box(
const SimpleTensor<float> &boxes,
size_t id)
49 return std::make_tuple(
50 get_elem_by_coordinate(boxes, Coordinates(0,
id)),
51 get_elem_by_coordinate(boxes, Coordinates(1,
id)),
52 get_elem_by_coordinate(boxes, Coordinates(2,
id)),
53 get_elem_by_coordinate(boxes, Coordinates(3,
id)));
57 inline std::pair<float, float> get_min_yx(Box
b)
59 return std::make_pair(
60 std::min<float>(std::get<0>(
b), std::get<2>(
b)),
61 std::min<float>(std::get<1>(
b), std::get<3>(
b)));
64 inline std::pair<float, float> get_max_yx(Box
b)
66 return std::make_pair(
67 std::max<float>(std::get<0>(
b), std::get<2>(
b)),
68 std::max<float>(std::get<1>(
b), std::get<3>(
b)));
71 inline float compute_size(
const std::pair<float, float> &min,
const std::pair<float, float> &max)
73 return (max.first - min.first) * (max.second - min.second);
76 inline float compute_intersection(
const std::pair<float, float> &b0_min,
const std::pair<float, float> &b0_max,
77 const std::pair<float, float> &b1_min,
const std::pair<float, float> &b1_max,
float b0_size,
float b1_size)
79 const float inter = std::max<float>(std::min<float>(b0_max.first, b1_max.first) - std::max<float>(b0_min.first, b1_min.first), 0.0f) * std::max<float>(std::min<float>(b0_max.second,
81 - std::max<float>(b0_min.second, b1_min.second),
83 return inter / (b0_size + b1_size - inter);
86 inline bool reject_box(Box b0, Box b1,
float threshold)
88 const auto b0_min = get_min_yx(b0);
89 const auto b0_max = get_max_yx(b0);
90 const auto b1_min = get_min_yx(b1);
91 const auto b1_max = get_max_yx(b1);
92 const float b0_size = compute_size(b0_min, b0_max);
93 const float b1_size = compute_size(b1_min, b1_max);
94 if(b0_size <= 0.f || b1_size <= 0.f)
100 const float box_weight = compute_intersection(b0_min, b0_max, b1_min, b1_max, b0_size, b1_size);
101 return box_weight > threshold;
105 inline std::vector<CandidateBox> get_candidates(
const SimpleTensor<float> &scores,
float threshold)
107 std::vector<CandidateBox> candidates_vector;
108 for(
int i = 0; i < scores.num_elements(); ++i)
110 if(scores[i] >= threshold)
112 const auto cb = CandidateBox({ i, scores[i] });
113 candidates_vector.push_back(cb);
116 std::stable_sort(candidates_vector.begin(), candidates_vector.end(), [](
const CandidateBox bb0,
const CandidateBox bb1)
118 return bb0.second > bb1.second;
120 return candidates_vector;
123 inline bool is_box_selected(
const CandidateBox &cb,
const SimpleTensor<float> &bboxes, std::vector<int> &selected_boxes,
float threshold)
125 for(
int j = selected_boxes.size() - 1; j >= 0; --j)
127 const auto selected_box_jth = get_box(bboxes, selected_boxes[j]);
128 const auto candidate_box = get_box(bboxes, cb.first);
129 const bool candidate_rejected = reject_box(candidate_box, selected_box_jth, threshold);
130 if(candidate_rejected)
140 unsigned int max_output_size,
float score_threshold,
float nms_threshold)
142 const size_t num_boxes = bboxes.
shape().y();
143 const size_t output_size = std::min(
static_cast<size_t>(max_output_size), num_boxes);
144 const std::vector<CandidateBox> candidates_vector = get_candidates(scores, score_threshold);
145 std::vector<int> selected;
146 for(
const auto &c : candidates_vector)
152 if(is_box_selected(c, bboxes, selected, nms_threshold))
154 selected.push_back(c.first);
157 std::copy_n(selected.begin(), selected.size(), indices.
data());
159 for(
unsigned int i = selected.size(); i < max_output_size; ++i)