OpenShot Library | libopenshot 0.2.7
sort.cpp
Go to the documentation of this file.
1#include "sort.hpp"
2
3using namespace std;
4
5// Constructor
6SortTracker::SortTracker(int max_age, int min_hits)
7{
8 _min_hits = min_hits;
9 _max_age = max_age;
10 alive_tracker = true;
11}
12
13// Computes IOU between two bounding boxes
14double SortTracker::GetIOU(cv::Rect_<float> bb_test, cv::Rect_<float> bb_gt)
15{
16 float in = (bb_test & bb_gt).area();
17 float un = bb_test.area() + bb_gt.area() - in;
18
19 if (un < DBL_EPSILON)
20 return 0;
21
22 return (double)(in / un);
23}
24
25// Computes centroid distance between two bounding boxes
27 cv::Rect_<float> bb_test,
28 cv::Rect_<float> bb_gt)
29{
30 float bb_test_centroid_x = (bb_test.x + bb_test.width / 2);
31 float bb_test_centroid_y = (bb_test.y + bb_test.height / 2);
32
33 float bb_gt_centroid_x = (bb_gt.x + bb_gt.width / 2);
34 float bb_gt_centroid_y = (bb_gt.y + bb_gt.height / 2);
35
36 double distance = (double)sqrt(pow(bb_gt_centroid_x - bb_test_centroid_x, 2) + pow(bb_gt_centroid_y - bb_test_centroid_y, 2));
37
38 return distance;
39}
40
41void SortTracker::update(vector<cv::Rect> detections_cv, int frame_count, double image_diagonal, std::vector<float> confidences, std::vector<int> classIds)
42{
43 vector<TrackingBox> detections;
44 if (trackers.size() == 0) // the first frame met
45 {
46 alive_tracker = false;
47 // initialize kalman trackers using first detections.
48 for (unsigned int i = 0; i < detections_cv.size(); i++)
49 {
50 TrackingBox tb;
51
52 tb.box = cv::Rect_<float>(detections_cv[i]);
53 tb.classId = classIds[i];
54 tb.confidence = confidences[i];
55 detections.push_back(tb);
56
57 KalmanTracker trk = KalmanTracker(detections[i].box, detections[i].confidence, detections[i].classId, i);
58 trackers.push_back(trk);
59 }
60 return;
61 }
62 else
63 {
64 for (unsigned int i = 0; i < detections_cv.size(); i++)
65 {
66 TrackingBox tb;
67 tb.box = cv::Rect_<float>(detections_cv[i]);
68 tb.classId = classIds[i];
69 tb.confidence = confidences[i];
70 detections.push_back(tb);
71 }
72 for (auto it = frameTrackingResult.begin(); it != frameTrackingResult.end(); it++)
73 {
74 int frame_age = frame_count - it->frame;
75 if (frame_age >= _max_age || frame_age < 0)
76 {
77 dead_trackers_id.push_back(it->id);
78 }
79 }
80 }
81
82 ///////////////////////////////////////
83 // 3.1. get predicted locations from existing trackers.
84 predictedBoxes.clear();
85 for (unsigned int i = 0; i < trackers.size();)
86 {
87 cv::Rect_<float> pBox = trackers[i].predict();
88 if (pBox.x >= 0 && pBox.y >= 0)
89 {
90 predictedBoxes.push_back(pBox);
91 i++;
92 continue;
93 }
94 trackers.erase(trackers.begin() + i);
95 }
96
97 trkNum = predictedBoxes.size();
98 detNum = detections.size();
99
100 centroid_dist_matrix.clear();
101 centroid_dist_matrix.resize(trkNum, vector<double>(detNum, 0));
102
103 for (unsigned int i = 0; i < trkNum; i++) // compute iou matrix as a distance matrix
104 {
105 for (unsigned int j = 0; j < detNum; j++)
106 {
107 // use 1-iou because the hungarian algorithm computes a minimum-cost assignment.
108 double distance = SortTracker::GetCentroidsDistance(predictedBoxes[i], detections[j].box) / image_diagonal;
109 centroid_dist_matrix[i][j] = distance;
110 }
111 }
112
113 HungarianAlgorithm HungAlgo;
114 assignment.clear();
116 // find matches, unmatched_detections and unmatched_predictions
117 unmatchedTrajectories.clear();
118 unmatchedDetections.clear();
119 allItems.clear();
120 matchedItems.clear();
121
122 if (detNum > trkNum) // there are unmatched detections
123 {
124 for (unsigned int n = 0; n < detNum; n++)
125 allItems.insert(n);
126
127 for (unsigned int i = 0; i < trkNum; ++i)
128 matchedItems.insert(assignment[i]);
129
130 set_difference(allItems.begin(), allItems.end(),
131 matchedItems.begin(), matchedItems.end(),
132 insert_iterator<set<int>>(unmatchedDetections, unmatchedDetections.begin()));
133 }
134 else if (detNum < trkNum) // there are unmatched trajectory/predictions
135 {
136 for (unsigned int i = 0; i < trkNum; ++i)
137 if (assignment[i] == -1) // unassigned label will be set as -1 in the assignment algorithm
138 unmatchedTrajectories.insert(i);
139 }
140 else
141 ;
142
143 // filter out matched with low IOU
144 matchedPairs.clear();
145 for (unsigned int i = 0; i < trkNum; ++i)
146 {
147 if (assignment[i] == -1) // pass over invalid values
148 continue;
150 {
151 unmatchedTrajectories.insert(i);
153 }
154 else
155 matchedPairs.push_back(cv::Point(i, assignment[i]));
156 }
157
158 for (unsigned int i = 0; i < matchedPairs.size(); i++)
159 {
160 int trkIdx = matchedPairs[i].x;
161 int detIdx = matchedPairs[i].y;
162 trackers[trkIdx].update(detections[detIdx].box);
163 trackers[trkIdx].classId = detections[detIdx].classId;
164 trackers[trkIdx].confidence = detections[detIdx].confidence;
165 }
166
167 // create and initialise new trackers for unmatched detections
168 for (auto umd : unmatchedDetections)
169 {
170 KalmanTracker tracker = KalmanTracker(detections[umd].box, detections[umd].confidence, detections[umd].classId, umd);
171 trackers.push_back(tracker);
172 }
173
174 for (auto it2 = dead_trackers_id.begin(); it2 != dead_trackers_id.end(); it2++)
175 {
176 for (unsigned int i = 0; i < trackers.size();)
177 {
178 if (trackers[i].m_id == (*it2))
179 {
180 trackers.erase(trackers.begin() + i);
181 continue;
182 }
183 i++;
184 }
185 }
186
187 // get trackers' output
188 frameTrackingResult.clear();
189 for (unsigned int i = 0; i < trackers.size();)
190 {
191 if ((trackers[i].m_time_since_update < 1 && trackers[i].m_hit_streak >= _min_hits) || frame_count <= _min_hits)
192 {
193 alive_tracker = true;
194 TrackingBox res;
195 res.box = trackers[i].get_state();
196 res.id = trackers[i].m_id;
197 res.frame = frame_count;
198 res.classId = trackers[i].classId;
199 res.confidence = trackers[i].confidence;
200 frameTrackingResult.push_back(res);
201 }
202
203 // remove dead tracklet
204 if (trackers[i].m_time_since_update >= _max_age)
205 {
206 trackers.erase(trackers.begin() + i);
207 continue;
208 }
209 i++;
210 }
211}
double Solve(std::vector< std::vector< double > > &DistMatrix, std::vector< int > &Assignment)
Definition: Hungarian.cpp:22
This class represents the internel state of individual tracked objects observed as bounding box.
Definition: KalmanTracker.h:15
SortTracker(int max_age=7, int min_hits=2)
Definition: sort.cpp:6
unsigned int trkNum
Definition: sort.hpp:56
double max_centroid_dist_norm
Definition: sort.hpp:42
std::vector< int > dead_trackers_id
Definition: sort.hpp:54
std::vector< TrackingBox > frameTrackingResult
Definition: sort.hpp:53
std::set< int > unmatchedDetections
Definition: sort.hpp:47
std::vector< std::vector< double > > centroid_dist_matrix
Definition: sort.hpp:45
int _max_age
Definition: sort.hpp:59
std::vector< cv::Point > matchedPairs
Definition: sort.hpp:51
double GetCentroidsDistance(cv::Rect_< float > bb_test, cv::Rect_< float > bb_gt)
Definition: sort.cpp:26
std::vector< KalmanTracker > trackers
Definition: sort.hpp:40
std::vector< cv::Rect_< float > > predictedBoxes
Definition: sort.hpp:44
int _min_hits
Definition: sort.hpp:58
void update(std::vector< cv::Rect > detection, int frame_count, double image_diagonal, std::vector< float > confidences, std::vector< int > classIds)
Definition: sort.cpp:41
std::set< int > allItems
Definition: sort.hpp:49
unsigned int detNum
Definition: sort.hpp:57
bool alive_tracker
Definition: sort.hpp:60
std::vector< int > assignment
Definition: sort.hpp:46
std::set< int > matchedItems
Definition: sort.hpp:50
std::set< int > unmatchedTrajectories
Definition: sort.hpp:48
double GetIOU(cv::Rect_< float > bb_test, cv::Rect_< float > bb_gt)
Definition: sort.cpp:14
cv::Rect_< float > box
Definition: sort.hpp:24
int frame
Definition: sort.hpp:20
float confidence
Definition: sort.hpp:21
int classId
Definition: sort.hpp:22
int id
Definition: sort.hpp:23