mustafa2ak commited on
Commit
6bdcad8
·
verified ·
1 Parent(s): 11e442b

Update tracking.py

Browse files
Files changed (1) hide show
  1. tracking.py +18 -123
tracking.py CHANGED
@@ -1,5 +1,5 @@
1
  """
2
- DeepSORT Tracker Implementation
3
  Uses Kalman filter for motion prediction + appearance features
4
  """
5
  import numpy as np
@@ -11,85 +11,53 @@ import uuid
11
  from detection import Detection
12
 
13
  class KalmanFilter:
14
- """
15
- Kalman Filter for tracking with constant velocity model
16
- State: [x, y, w, h, vx, vy, vw, vh]
17
- """
18
  def __init__(self):
19
- # State transition matrix (constant velocity model)
20
  self.F = np.eye(8)
21
  for i in range(4):
22
  self.F[i, i+4] = 1
23
 
24
- # Measurement matrix (we observe position and size)
25
  self.H = np.eye(4, 8)
26
-
27
- # Process noise
28
  self.Q = np.eye(8)
29
- self.Q[4:, 4:] *= 0.01 # Smaller noise for velocities
30
-
31
- # Measurement noise
32
  self.R = np.eye(4) * 10
33
-
34
- # State covariance
35
  self.P = np.eye(8) * 1000
36
-
37
- # State vector [x, y, w, h, vx, vy, vw, vh]
38
  self.x = np.zeros(8)
39
 
40
  def initiate(self, measurement: np.ndarray):
41
- """Initialize filter with first measurement [x, y, w, h]"""
42
  self.x[:4] = measurement
43
- self.x[4:] = 0 # Zero velocity
44
 
45
  def predict(self):
46
- """Predict next state"""
47
  self.x = self.F @ self.x
48
  self.P = self.F @ self.P @ self.F.T + self.Q
49
  return self.x[:4]
50
 
51
  def update(self, measurement: np.ndarray):
52
- """Update with new measurement"""
53
- # Innovation
54
  y = measurement - self.H @ self.x
55
-
56
- # Innovation covariance
57
  S = self.H @ self.P @ self.H.T + self.R
58
-
59
- # Kalman gain
60
  K = self.P @ self.H.T @ np.linalg.inv(S)
61
-
62
- # Update state
63
  self.x = self.x + K @ y
64
-
65
- # Update covariance
66
  self.P = (np.eye(8) - K @ self.H) @ self.P
67
-
68
  return self.x[:4]
69
 
70
  def get_state(self) -> np.ndarray:
71
- """Get current state [x, y, w, h]"""
72
  return self.x[:4]
73
 
74
  class DeepSORTTrack:
75
- """
76
- DeepSORT Track with Kalman filter and appearance features
77
- """
78
  def __init__(self, detection: Detection, track_id: Optional[int] = None):
79
  self.track_id = track_id if track_id else self._generate_id()
80
 
81
- # Convert bbox to center format [cx, cy, w, h]
82
  x1, y1, x2, y2 = detection.bbox
83
  cx = (x1 + x2) / 2
84
  cy = (y1 + y2) / 2
85
  w = x2 - x1
86
  h = y2 - y1
87
 
88
- # Initialize Kalman filter
89
  self.kf = KalmanFilter()
90
  self.kf.initiate(np.array([cx, cy, w, h]))
91
 
92
- # Track state
93
  self.detections = [detection]
94
  self.confidence = detection.confidence
95
  self.hits = 1
@@ -97,16 +65,13 @@ class DeepSORTTrack:
97
  self.time_since_update = 0
98
  self.state = 'tentative'
99
 
100
- # Appearance features for ReID
101
- self.features = deque(maxlen=100) # Store last 100 features
102
  if hasattr(detection, 'features') and detection.features is not None:
103
  self.features.append(detection.features)
104
 
105
- # Trajectory
106
  self.trajectory = deque(maxlen=30)
107
  self.trajectory.append((cx, cy))
108
 
109
- # Quality metrics
110
  self.avg_confidence = self.confidence
111
  self.consecutive_misses = 0
112
 
@@ -115,37 +80,24 @@ class DeepSORTTrack:
115
 
116
  @property
117
  def bbox(self) -> List[float]:
118
- """Get bbox in [x1, y1, x2, y2] format"""
119
  cx, cy, w, h = self.kf.get_state()
120
- return [
121
- cx - w/2,
122
- cy - h/2,
123
- cx + w/2,
124
- cy + h/2
125
- ]
126
 
127
  def predict(self):
128
- """Predict next state using Kalman filter"""
129
  self.age += 1
130
  self.time_since_update += 1
131
  self.consecutive_misses += 1
132
-
133
- # Predict with Kalman filter
134
  self.kf.predict()
135
 
136
  def update(self, detection: Detection):
137
- """Update track with new detection"""
138
- # Convert to center format
139
  x1, y1, x2, y2 = detection.bbox
140
  cx = (x1 + x2) / 2
141
  cy = (y1 + y2) / 2
142
  w = x2 - x1
143
  h = y2 - y1
144
 
145
- # Update Kalman filter
146
  self.kf.update(np.array([cx, cy, w, h]))
147
 
148
- # Update track state
149
  self.detections.append(detection)
150
  self.confidence = detection.confidence
151
  self.avg_confidence = 0.9 * self.avg_confidence + 0.1 * self.confidence
@@ -154,18 +106,14 @@ class DeepSORTTrack:
154
  self.time_since_update = 0
155
  self.consecutive_misses = 0
156
 
157
- # Update features
158
  if hasattr(detection, 'features') and detection.features is not None:
159
  self.features.append(detection.features)
160
 
161
- # Update trajectory
162
  self.trajectory.append((cx, cy))
163
 
164
- # Confirm track
165
  if self.state == 'tentative' and self.hits >= 3:
166
  self.state = 'confirmed'
167
 
168
- # Keep only recent detections
169
  if len(self.detections) > 5:
170
  for old_det in self.detections[:-5]:
171
  if hasattr(old_det, 'image_crop'):
@@ -173,7 +121,6 @@ class DeepSORTTrack:
173
  self.detections = self.detections[-5:]
174
 
175
  def mark_missed(self):
176
- """Mark track as missed"""
177
  if self.state == 'confirmed':
178
  if self.consecutive_misses > 30 or self.time_since_update > 60:
179
  self.state = 'deleted'
@@ -182,34 +129,21 @@ class DeepSORTTrack:
182
  self.state = 'deleted'
183
 
184
  def get_feature(self) -> Optional[np.ndarray]:
185
- """Get averaged appearance feature"""
186
  if not self.features:
187
  return None
188
- # Use exponential moving average for recent features
189
  features_array = np.array(list(self.features))
190
  weights = np.exp(np.linspace(-1, 0, len(features_array)))
191
  weights /= weights.sum()
192
  return np.average(features_array, axis=0, weights=weights)
193
 
194
  class DeepSORTTracker:
195
- """
196
- DeepSORT Tracker combining Kalman filter motion model
197
- with appearance feature matching
198
- """
199
  def __init__(self,
200
  max_iou_distance: float = 0.7,
201
  max_age: int = 30,
202
  n_init: int = 3,
203
  nn_budget: int = 100,
204
  use_appearance: bool = True):
205
- """
206
- Args:
207
- max_iou_distance: Maximum IoU distance for matching (0.7 = 30% IoU)
208
- max_age: Maximum frames to keep lost tracks
209
- n_init: Number of frames to confirm a track
210
- nn_budget: Maximum size of appearance feature gallery
211
- use_appearance: Whether to use appearance features
212
- """
213
  self.max_iou_distance = max_iou_distance
214
  self.max_age = max_age
215
  self.n_init = n_init
@@ -219,65 +153,46 @@ class DeepSORTTracker:
219
  self.tracks: List[DeepSORTTrack] = []
220
  self.track_id_count = 1
221
 
222
- # Gating thresholds
223
- self.gating_threshold_iou = 0.3 # Minimum IoU for association
224
- self.gating_threshold_appearance = 0.5 # Maximum cosine distance
225
 
226
  def update(self, detections: List[Detection]) -> List[DeepSORTTrack]:
227
- """Update tracks with new detections"""
228
- # Predict existing tracks
229
  for track in self.tracks:
230
  track.predict()
231
 
232
- # Match detections to tracks
233
  matches, unmatched_tracks, unmatched_detections = self._match(
234
  detections, self.tracks
235
  )
236
 
237
- # Update matched tracks
238
  for track_idx, det_idx in matches:
239
  self.tracks[track_idx].update(detections[det_idx])
240
 
241
- # Mark unmatched tracks as missed
242
  for track_idx in unmatched_tracks:
243
  self.tracks[track_idx].mark_missed()
244
 
245
- # Create new tracks for unmatched detections
246
  for det_idx in unmatched_detections:
247
  self._initiate_track(detections[det_idx])
248
 
249
- # Remove deleted tracks
250
  self.tracks = [t for t in self.tracks if t.state != 'deleted']
251
 
252
- # Return confirmed tracks
253
  return [t for t in self.tracks if t.state == 'confirmed']
254
 
255
  def _match(self, detections: List[Detection], tracks: List[DeepSORTTrack]) -> Tuple:
256
- """
257
- Match detections to tracks using cascade matching
258
- Returns: (matches, unmatched_tracks, unmatched_detections)
259
- """
260
  if not tracks or not detections:
261
  return [], list(range(len(tracks))), list(range(len(detections)))
262
 
263
- # Split tracks by state
264
  confirmed_tracks = [i for i, t in enumerate(tracks) if t.state == 'confirmed']
265
  unconfirmed_tracks = [i for i, t in enumerate(tracks) if t.state == 'tentative']
266
 
267
- # Stage 1: Match confirmed tracks
268
  matches_a, unmatched_tracks_a, unmatched_detections = \
269
  self._matching_cascade(detections, tracks, confirmed_tracks)
270
 
271
- # Stage 2: Match unconfirmed tracks
272
  iou_track_candidates = unconfirmed_tracks + unmatched_tracks_a
273
-
274
- # Filter detections used in stage 1
275
  remaining_detections = [detections[i] for i in unmatched_detections]
276
 
277
  matches_b, unmatched_tracks_b, unmatched_detections_b = \
278
  self._match_iou(remaining_detections, tracks, iou_track_candidates)
279
 
280
- # Remap indices for stage 2
281
  matches_b = [(t, unmatched_detections[d]) for t, d in matches_b]
282
  unmatched_detections = [unmatched_detections[i] for i in unmatched_detections_b]
283
 
@@ -289,11 +204,9 @@ class DeepSORTTracker:
289
  def _matching_cascade(self, detections: List[Detection],
290
  tracks: List[DeepSORTTrack],
291
  track_indices: List[int]) -> Tuple:
292
- """Cascade matching by time since update"""
293
  matches = []
294
  unmatched_detections = list(range(len(detections)))
295
 
296
- # Group tracks by time since update
297
  for level in range(self.max_age):
298
  if len(unmatched_detections) == 0:
299
  break
@@ -306,22 +219,18 @@ class DeepSORTTracker:
306
  if len(track_indices_l) == 0:
307
  continue
308
 
309
- # Match at this level
310
- matches_l, _, unmatched_detections = self._match_features_and_iou(
311
- [detections[i] for i in unmatched_detections],
 
312
  tracks,
313
  track_indices_l
314
  )
315
 
316
- # Remap detection indices
317
- matches_l = [(t, unmatched_detections[d]) for t, d in matches_l]
318
- matches.extend(matches_l)
319
 
320
- # Update unmatched detections
321
- unmatched_detections = [
322
- unmatched_detections[i] for i in range(len(unmatched_detections))
323
- if i not in [d for _, d in matches_l]
324
- ]
325
 
326
  unmatched_tracks = [
327
  k for k in track_indices
@@ -333,11 +242,9 @@ class DeepSORTTracker:
333
  def _match_features_and_iou(self, detections: List[Detection],
334
  tracks: List[DeepSORTTrack],
335
  track_indices: List[int]) -> Tuple:
336
- """Match using both appearance features and IoU"""
337
  if not track_indices or not detections:
338
  return [], track_indices, list(range(len(detections)))
339
 
340
- # Calculate cost matrix
341
  cost_matrix = np.zeros((len(track_indices), len(detections)))
342
 
343
  for i, track_idx in enumerate(track_indices):
@@ -348,27 +255,23 @@ class DeepSORTTracker:
348
  for j, detection in enumerate(detections):
349
  det_bbox = detection.bbox
350
 
351
- # IoU cost
352
  iou = self._iou(track_bbox, det_bbox)
353
  iou_cost = 1 - iou
354
 
355
- # Appearance cost
356
  if self.use_appearance and track_feature is not None:
357
  if hasattr(detection, 'features') and detection.features is not None:
358
  cosine_dist = cosine(track_feature, detection.features)
359
  appearance_cost = cosine_dist
360
  else:
361
- appearance_cost = 0.5 # Neutral if no features
362
  else:
363
  appearance_cost = 0.0
364
 
365
- # Combined cost (weighted)
366
  if self.use_appearance and track_feature is not None:
367
  cost = 0.5 * iou_cost + 0.5 * appearance_cost
368
  else:
369
  cost = iou_cost
370
 
371
- # Gating: set to infinity if outside thresholds
372
  if iou < self.gating_threshold_iou:
373
  cost = 1e6
374
  if self.use_appearance and appearance_cost > self.gating_threshold_appearance:
@@ -376,7 +279,6 @@ class DeepSORTTracker:
376
 
377
  cost_matrix[i, j] = cost
378
 
379
- # Hungarian algorithm
380
  row_indices, col_indices = linear_sum_assignment(cost_matrix)
381
 
382
  matches = []
@@ -396,11 +298,9 @@ class DeepSORTTracker:
396
  def _match_iou(self, detections: List[Detection],
397
  tracks: List[DeepSORTTrack],
398
  track_indices: List[int]) -> Tuple:
399
- """Simple IoU matching for unconfirmed tracks"""
400
  if not track_indices or not detections:
401
  return [], track_indices, list(range(len(detections)))
402
 
403
- # IoU distance matrix
404
  iou_matrix = np.zeros((len(track_indices), len(detections)))
405
 
406
  for i, track_idx in enumerate(track_indices):
@@ -409,7 +309,6 @@ class DeepSORTTracker:
409
  iou = self._iou(track.bbox, detection.bbox)
410
  iou_matrix[i, j] = 1 - iou
411
 
412
- # Hungarian matching
413
  row_indices, col_indices = linear_sum_assignment(iou_matrix)
414
 
415
  matches = []
@@ -427,13 +326,11 @@ class DeepSORTTracker:
427
  return matches, unmatched_tracks, unmatched_detections
428
 
429
  def _initiate_track(self, detection: Detection):
430
- """Create new track"""
431
  new_track = DeepSORTTrack(detection, self.track_id_count)
432
  self.track_id_count += 1
433
  self.tracks.append(new_track)
434
 
435
  def _iou(self, bbox1: List[float], bbox2: List[float]) -> float:
436
- """Calculate IoU between two bboxes"""
437
  try:
438
  x1 = max(bbox1[0], bbox2[0])
439
  y1 = max(bbox1[1], bbox2[1])
@@ -453,11 +350,9 @@ class DeepSORTTracker:
453
  return 0.0
454
 
455
  def reset(self):
456
- """Reset tracker"""
457
  self.tracks.clear()
458
  self.track_id_count = 1
459
  print("DeepSORT tracker reset")
460
 
461
- # Compatibility alias
462
  SimpleTracker = DeepSORTTracker
463
  RobustTracker = DeepSORTTracker
 
1
  """
2
+ DeepSORT Tracker Implementation - Complete Fixed Version
3
  Uses Kalman filter for motion prediction + appearance features
4
  """
5
  import numpy as np
 
11
  from detection import Detection
12
 
13
  class KalmanFilter:
14
+ """Kalman Filter for tracking with constant velocity model"""
 
 
 
15
  def __init__(self):
 
16
  self.F = np.eye(8)
17
  for i in range(4):
18
  self.F[i, i+4] = 1
19
 
 
20
  self.H = np.eye(4, 8)
 
 
21
  self.Q = np.eye(8)
22
+ self.Q[4:, 4:] *= 0.01
 
 
23
  self.R = np.eye(4) * 10
 
 
24
  self.P = np.eye(8) * 1000
 
 
25
  self.x = np.zeros(8)
26
 
27
  def initiate(self, measurement: np.ndarray):
 
28
  self.x[:4] = measurement
29
+ self.x[4:] = 0
30
 
31
  def predict(self):
 
32
  self.x = self.F @ self.x
33
  self.P = self.F @ self.P @ self.F.T + self.Q
34
  return self.x[:4]
35
 
36
  def update(self, measurement: np.ndarray):
 
 
37
  y = measurement - self.H @ self.x
 
 
38
  S = self.H @ self.P @ self.H.T + self.R
 
 
39
  K = self.P @ self.H.T @ np.linalg.inv(S)
 
 
40
  self.x = self.x + K @ y
 
 
41
  self.P = (np.eye(8) - K @ self.H) @ self.P
 
42
  return self.x[:4]
43
 
44
  def get_state(self) -> np.ndarray:
 
45
  return self.x[:4]
46
 
47
  class DeepSORTTrack:
48
+ """DeepSORT Track with Kalman filter and appearance features"""
 
 
49
  def __init__(self, detection: Detection, track_id: Optional[int] = None):
50
  self.track_id = track_id if track_id else self._generate_id()
51
 
 
52
  x1, y1, x2, y2 = detection.bbox
53
  cx = (x1 + x2) / 2
54
  cy = (y1 + y2) / 2
55
  w = x2 - x1
56
  h = y2 - y1
57
 
 
58
  self.kf = KalmanFilter()
59
  self.kf.initiate(np.array([cx, cy, w, h]))
60
 
 
61
  self.detections = [detection]
62
  self.confidence = detection.confidence
63
  self.hits = 1
 
65
  self.time_since_update = 0
66
  self.state = 'tentative'
67
 
68
+ self.features = deque(maxlen=100)
 
69
  if hasattr(detection, 'features') and detection.features is not None:
70
  self.features.append(detection.features)
71
 
 
72
  self.trajectory = deque(maxlen=30)
73
  self.trajectory.append((cx, cy))
74
 
 
75
  self.avg_confidence = self.confidence
76
  self.consecutive_misses = 0
77
 
 
80
 
81
  @property
82
  def bbox(self) -> List[float]:
 
83
  cx, cy, w, h = self.kf.get_state()
84
+ return [cx - w/2, cy - h/2, cx + w/2, cy + h/2]
 
 
 
 
 
85
 
86
  def predict(self):
 
87
  self.age += 1
88
  self.time_since_update += 1
89
  self.consecutive_misses += 1
 
 
90
  self.kf.predict()
91
 
92
  def update(self, detection: Detection):
 
 
93
  x1, y1, x2, y2 = detection.bbox
94
  cx = (x1 + x2) / 2
95
  cy = (y1 + y2) / 2
96
  w = x2 - x1
97
  h = y2 - y1
98
 
 
99
  self.kf.update(np.array([cx, cy, w, h]))
100
 
 
101
  self.detections.append(detection)
102
  self.confidence = detection.confidence
103
  self.avg_confidence = 0.9 * self.avg_confidence + 0.1 * self.confidence
 
106
  self.time_since_update = 0
107
  self.consecutive_misses = 0
108
 
 
109
  if hasattr(detection, 'features') and detection.features is not None:
110
  self.features.append(detection.features)
111
 
 
112
  self.trajectory.append((cx, cy))
113
 
 
114
  if self.state == 'tentative' and self.hits >= 3:
115
  self.state = 'confirmed'
116
 
 
117
  if len(self.detections) > 5:
118
  for old_det in self.detections[:-5]:
119
  if hasattr(old_det, 'image_crop'):
 
121
  self.detections = self.detections[-5:]
122
 
123
  def mark_missed(self):
 
124
  if self.state == 'confirmed':
125
  if self.consecutive_misses > 30 or self.time_since_update > 60:
126
  self.state = 'deleted'
 
129
  self.state = 'deleted'
130
 
131
  def get_feature(self) -> Optional[np.ndarray]:
 
132
  if not self.features:
133
  return None
 
134
  features_array = np.array(list(self.features))
135
  weights = np.exp(np.linspace(-1, 0, len(features_array)))
136
  weights /= weights.sum()
137
  return np.average(features_array, axis=0, weights=weights)
138
 
139
  class DeepSORTTracker:
140
+ """DeepSORT Tracker combining Kalman filter with appearance features"""
 
 
 
141
  def __init__(self,
142
  max_iou_distance: float = 0.7,
143
  max_age: int = 30,
144
  n_init: int = 3,
145
  nn_budget: int = 100,
146
  use_appearance: bool = True):
 
 
 
 
 
 
 
 
147
  self.max_iou_distance = max_iou_distance
148
  self.max_age = max_age
149
  self.n_init = n_init
 
153
  self.tracks: List[DeepSORTTrack] = []
154
  self.track_id_count = 1
155
 
156
+ self.gating_threshold_iou = 0.3
157
+ self.gating_threshold_appearance = 0.5
 
158
 
159
  def update(self, detections: List[Detection]) -> List[DeepSORTTrack]:
 
 
160
  for track in self.tracks:
161
  track.predict()
162
 
 
163
  matches, unmatched_tracks, unmatched_detections = self._match(
164
  detections, self.tracks
165
  )
166
 
 
167
  for track_idx, det_idx in matches:
168
  self.tracks[track_idx].update(detections[det_idx])
169
 
 
170
  for track_idx in unmatched_tracks:
171
  self.tracks[track_idx].mark_missed()
172
 
 
173
  for det_idx in unmatched_detections:
174
  self._initiate_track(detections[det_idx])
175
 
 
176
  self.tracks = [t for t in self.tracks if t.state != 'deleted']
177
 
 
178
  return [t for t in self.tracks if t.state == 'confirmed']
179
 
180
  def _match(self, detections: List[Detection], tracks: List[DeepSORTTrack]) -> Tuple:
 
 
 
 
181
  if not tracks or not detections:
182
  return [], list(range(len(tracks))), list(range(len(detections)))
183
 
 
184
  confirmed_tracks = [i for i, t in enumerate(tracks) if t.state == 'confirmed']
185
  unconfirmed_tracks = [i for i, t in enumerate(tracks) if t.state == 'tentative']
186
 
 
187
  matches_a, unmatched_tracks_a, unmatched_detections = \
188
  self._matching_cascade(detections, tracks, confirmed_tracks)
189
 
 
190
  iou_track_candidates = unconfirmed_tracks + unmatched_tracks_a
 
 
191
  remaining_detections = [detections[i] for i in unmatched_detections]
192
 
193
  matches_b, unmatched_tracks_b, unmatched_detections_b = \
194
  self._match_iou(remaining_detections, tracks, iou_track_candidates)
195
 
 
196
  matches_b = [(t, unmatched_detections[d]) for t, d in matches_b]
197
  unmatched_detections = [unmatched_detections[i] for i in unmatched_detections_b]
198
 
 
204
  def _matching_cascade(self, detections: List[Detection],
205
  tracks: List[DeepSORTTrack],
206
  track_indices: List[int]) -> Tuple:
 
207
  matches = []
208
  unmatched_detections = list(range(len(detections)))
209
 
 
210
  for level in range(self.max_age):
211
  if len(unmatched_detections) == 0:
212
  break
 
219
  if len(track_indices_l) == 0:
220
  continue
221
 
222
+ detection_subset = [detections[i] for i in unmatched_detections]
223
+
224
+ matches_l, _, unmatched_subset_indices = self._match_features_and_iou(
225
+ detection_subset,
226
  tracks,
227
  track_indices_l
228
  )
229
 
230
+ matches_l_remapped = [(t, unmatched_detections[d]) for t, d in matches_l]
231
+ matches.extend(matches_l_remapped)
 
232
 
233
+ unmatched_detections = [unmatched_detections[i] for i in unmatched_subset_indices]
 
 
 
 
234
 
235
  unmatched_tracks = [
236
  k for k in track_indices
 
242
  def _match_features_and_iou(self, detections: List[Detection],
243
  tracks: List[DeepSORTTrack],
244
  track_indices: List[int]) -> Tuple:
 
245
  if not track_indices or not detections:
246
  return [], track_indices, list(range(len(detections)))
247
 
 
248
  cost_matrix = np.zeros((len(track_indices), len(detections)))
249
 
250
  for i, track_idx in enumerate(track_indices):
 
255
  for j, detection in enumerate(detections):
256
  det_bbox = detection.bbox
257
 
 
258
  iou = self._iou(track_bbox, det_bbox)
259
  iou_cost = 1 - iou
260
 
 
261
  if self.use_appearance and track_feature is not None:
262
  if hasattr(detection, 'features') and detection.features is not None:
263
  cosine_dist = cosine(track_feature, detection.features)
264
  appearance_cost = cosine_dist
265
  else:
266
+ appearance_cost = 0.5
267
  else:
268
  appearance_cost = 0.0
269
 
 
270
  if self.use_appearance and track_feature is not None:
271
  cost = 0.5 * iou_cost + 0.5 * appearance_cost
272
  else:
273
  cost = iou_cost
274
 
 
275
  if iou < self.gating_threshold_iou:
276
  cost = 1e6
277
  if self.use_appearance and appearance_cost > self.gating_threshold_appearance:
 
279
 
280
  cost_matrix[i, j] = cost
281
 
 
282
  row_indices, col_indices = linear_sum_assignment(cost_matrix)
283
 
284
  matches = []
 
298
  def _match_iou(self, detections: List[Detection],
299
  tracks: List[DeepSORTTrack],
300
  track_indices: List[int]) -> Tuple:
 
301
  if not track_indices or not detections:
302
  return [], track_indices, list(range(len(detections)))
303
 
 
304
  iou_matrix = np.zeros((len(track_indices), len(detections)))
305
 
306
  for i, track_idx in enumerate(track_indices):
 
309
  iou = self._iou(track.bbox, detection.bbox)
310
  iou_matrix[i, j] = 1 - iou
311
 
 
312
  row_indices, col_indices = linear_sum_assignment(iou_matrix)
313
 
314
  matches = []
 
326
  return matches, unmatched_tracks, unmatched_detections
327
 
328
  def _initiate_track(self, detection: Detection):
 
329
  new_track = DeepSORTTrack(detection, self.track_id_count)
330
  self.track_id_count += 1
331
  self.tracks.append(new_track)
332
 
333
  def _iou(self, bbox1: List[float], bbox2: List[float]) -> float:
 
334
  try:
335
  x1 = max(bbox1[0], bbox2[0])
336
  y1 = max(bbox1[1], bbox2[1])
 
350
  return 0.0
351
 
352
  def reset(self):
 
353
  self.tracks.clear()
354
  self.track_id_count = 1
355
  print("DeepSORT tracker reset")
356
 
 
357
  SimpleTracker = DeepSORTTracker
358
  RobustTracker = DeepSORTTracker