13 std::vector<ClassScore> classScores;
16 double box_diagonal(
const cv::Rect_<float>& box)
18 return std::sqrt(box.width * box.width + box.height * box.height);
21 double box_area(
const cv::Rect_<float>& box)
23 return std::max(0.0f, box.width) * std::max(0.0f, box.height);
26 double aspect_ratio(
const cv::Rect_<float>& box)
28 if (box.width <= 0.0f || box.height <= 0.0f)
30 return static_cast<double>(box.width) /
static_cast<double>(box.height);
33 bool box_shape_matches(
const cv::Rect_<float>& predicted_box,
const cv::Rect_<float>& detection_box,
double iou)
35 const double predicted_area = box_area(predicted_box);
36 const double detection_area = box_area(detection_box);
37 if (predicted_area <= 1.0 || detection_area <= 1.0)
40 const double area_ratio = detection_area / predicted_area;
41 const double predicted_aspect = aspect_ratio(predicted_box);
42 const double detection_aspect = aspect_ratio(detection_box);
43 const double aspect_ratio_delta = (predicted_aspect > 0.0 && detection_aspect > 0.0)
44 ? std::max(predicted_aspect / detection_aspect, detection_aspect / predicted_aspect)
48 return area_ratio >= 0.20 && area_ratio <= 5.00 && aspect_ratio_delta <= 4.00;
49 return area_ratio >= 0.35 && area_ratio <= 2.80 && aspect_ratio_delta <= 2.75;
52 bool detection_matches_track_gate(
54 const cv::Rect_<float>& predicted_box,
55 const DetectionBox& detection,
57 double centroid_distance)
59 if (!box_shape_matches(predicted_box, detection.box, iou))
62 const double scale = std::max(box_diagonal(predicted_box), box_diagonal(detection.box));
65 if (missed_previous_frame) {
66 const double reacquire_distance = std::max(12.0, scale * 0.25);
67 return iou >= 0.35 || centroid_distance <= reacquire_distance;
70 const double local_distance = std::max(12.0, scale * 0.22);
71 return iou >= 0.20 || centroid_distance <= local_distance;
80 _max_missed = max_missed;
82 _nms_iou_thresh = nms_iou_thresh;
91 float in = (bb_test & bb_gt).area();
92 float un = bb_test.area() + bb_gt.area() - in;
97 return (
double)(in / un);
102 cv::Rect_<float> bb_test,
103 cv::Rect_<float> bb_gt)
105 float bb_test_centroid_x = (bb_test.x + bb_test.width / 2);
106 float bb_test_centroid_y = (bb_test.y + bb_test.height / 2);
108 float bb_gt_centroid_x = (bb_gt.x + bb_gt.width / 2);
109 float bb_gt_centroid_y = (bb_gt.y + bb_gt.height / 2);
111 double distance = (double)sqrt(pow(bb_gt_centroid_x - bb_test_centroid_x, 2) + pow(bb_gt_centroid_y - bb_test_centroid_y, 2));
117 void apply_nms(vector<DetectionBox>& detections,
double nms_iou_thresh) {
118 if (detections.empty())
return;
121 std::sort(detections.begin(), detections.end(), [](
const DetectionBox& a,
const DetectionBox& b) {
122 return a.confidence > b.confidence;
125 vector<bool> suppressed(detections.size(),
false);
127 for (
size_t i = 0; i < detections.size(); ++i) {
128 if (suppressed[i])
continue;
130 for (
size_t j = i + 1; j < detections.size(); ++j) {
131 if (suppressed[j])
continue;
134 if ((detections[i].classId == detections[j].classId && iou > nms_iou_thresh) ||
136 suppressed[j] =
true;
142 vector<DetectionBox> filtered;
143 for (
size_t i = 0; i < detections.size(); ++i) {
144 if (!suppressed[i]) {
145 filtered.push_back(detections[i]);
148 detections = filtered;
151 void SortTracker::update(vector<cv::Rect> detections_cv,
int frame_count,
double image_diagonal, std::vector<float> confidences, std::vector<int> classIds, std::vector<std::vector<ClassScore>> classScores)
153 vector<DetectionBox> detections;
154 dead_trackers_id.clear();
155 if (classScores.size() != detections_cv.size())
156 classScores.resize(detections_cv.size());
157 if (trackers.size() == 0)
159 alive_tracker =
false;
161 for (
unsigned int i = 0; i < detections_cv.size(); i++)
163 if (confidences[i] < _min_conf)
continue;
167 tb.box = cv::Rect_<float>(detections_cv[i]);
168 tb.classId = classIds[i];
169 tb.confidence = confidences[i];
170 tb.classScores = classScores[i];
171 detections.push_back(tb);
176 for (
const auto& detection : detections)
179 trackers.push_back(trk);
185 for (
unsigned int i = 0; i < detections_cv.size(); i++)
187 if (confidences[i] < _min_conf)
continue;
190 tb.box = cv::Rect_<float>(detections_cv[i]);
191 tb.classId = classIds[i];
192 tb.confidence = confidences[i];
193 tb.classScores = classScores[i];
194 detections.push_back(tb);
203 predictedBoxes.clear();
204 for (
unsigned int i = 0; i < trackers.size();)
206 cv::Rect_<float> pBox = trackers[i].predict();
207 if (pBox.x >= 0 && pBox.y >= 0)
209 predictedBoxes.push_back(pBox);
213 trackers.erase(trackers.begin() + i);
216 trkNum = predictedBoxes.size();
217 detNum = detections.size();
220 cost_matrix.resize(trkNum, vector<double>(detNum, 0));
222 matchedPairs.clear();
223 unmatchedTrajectories.clear();
224 unmatchedDetections.clear();
226 matchedItems.clear();
230 for (
auto& detection : detections)
232 KalmanTracker tracker =
KalmanTracker(detection.box, detection.confidence, detection.classId, _next_id++, detection.classScores);
233 trackers.push_back(tracker);
236 else if (detNum == 0)
238 for (
unsigned int i = 0; i < trkNum; ++i)
239 unmatchedTrajectories.insert(i);
244 for (
unsigned int i = 0; i < trkNum; i++)
246 for (
unsigned int j = 0; j < detNum; j++)
248 double iou = GetIOU(predictedBoxes[i], detections[j].box);
249 double centroid_distance = GetCentroidsDistance(predictedBoxes[i], detections[j].box);
250 if (!detection_matches_track_gate(trackers[i], predictedBoxes[i], detections[j], iou, centroid_distance))
252 cost_matrix[i][j] = 1e9;
256 const double scale = std::max(1.0, std::max(box_diagonal(predictedBoxes[i]), box_diagonal(detections[j].box)));
257 const double distance_penalty = std::min(1.0, centroid_distance / scale) * 0.35;
258 cost_matrix[i][j] = 1 - iou + distance_penalty + (1 - detections[j].confidence) * 0.1;
264 HungAlgo.
Solve(cost_matrix, assignment);
269 for (
unsigned int n = 0; n < detNum; n++)
272 for (
unsigned int i = 0; i < trkNum; ++i)
273 matchedItems.insert(assignment[i]);
275 set_difference(allItems.begin(), allItems.end(),
276 matchedItems.begin(), matchedItems.end(),
277 insert_iterator<set<int>>(unmatchedDetections, unmatchedDetections.begin()));
279 else if (detNum < trkNum)
281 for (
unsigned int i = 0; i < trkNum; ++i)
282 if (assignment[i] == -1)
283 unmatchedTrajectories.insert(i);
289 for (
unsigned int i = 0; i < trkNum; ++i)
291 if (assignment[i] == -1)
293 if (cost_matrix[i][assignment[i]] >= 1e8)
295 unmatchedTrajectories.insert(i);
296 unmatchedDetections.insert(assignment[i]);
299 matchedPairs.push_back(cv::Point(i, assignment[i]));
303 for (
unsigned int i = 0; i < matchedPairs.size(); i++)
305 int trkIdx = matchedPairs[i].x;
306 int detIdx = matchedPairs[i].y;
307 trackers[trkIdx].update(detections[detIdx].box);
308 trackers[trkIdx].update_class_scores(detections[detIdx].classScores, detections[detIdx].classId, detections[detIdx].confidence);
309 trackers[trkIdx].confidence = detections[detIdx].confidence;
313 for (
auto umd : unmatchedDetections)
315 KalmanTracker tracker =
KalmanTracker(detections[umd].box, detections[umd].confidence, detections[umd].classId, _next_id++, detections[umd].classScores);
316 trackers.push_back(tracker);
320 frameTrackingResult.clear();
321 for (
unsigned int i = 0; i < trackers.size();)
323 if ((trackers[i].m_hits >= _min_hits && trackers[i].m_time_since_update <= _max_missed) ||
324 frame_count <= _min_hits)
326 alive_tracker =
true;
328 if (i < predictedBoxes.size() && trackers[i].m_time_since_update > 0)
329 res.
box = predictedBoxes[i];
331 res.
box = trackers[i].get_state();
332 res.
id = trackers[i].m_id;
333 res.
frame = frame_count;
334 res.
classId = trackers[i].classId;
336 frameTrackingResult.push_back(res);
340 if (trackers[i].m_time_since_update >= _max_age)
342 trackers.erase(trackers.begin() + i);