OpenShot Library | libopenshot  0.2.7
sort.cpp
Go to the documentation of this file.
1 #include "sort.hpp"
2 
3 using namespace std;
4 
5 // Constructor
6 SortTracker::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
14 double 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 
41 void 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();
115  HungAlgo.Solve(centroid_dist_matrix, assignment);
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;
149  if (centroid_dist_matrix[i][assignment[i]] > max_centroid_dist_norm)
150  {
151  unmatchedTrajectories.insert(i);
152  unmatchedDetections.insert(assignment[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
double GetCentroidsDistance(cv::Rect_< float > bb_test, cv::Rect_< float > bb_gt)
Definition: sort.cpp:26
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
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