supervisely 6.73.418__py3-none-any.whl → 6.73.419__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. supervisely/api/entity_annotation/figure_api.py +89 -45
  2. supervisely/nn/inference/inference.py +61 -45
  3. supervisely/nn/inference/instance_segmentation/instance_segmentation.py +1 -0
  4. supervisely/nn/inference/object_detection/object_detection.py +1 -0
  5. supervisely/nn/inference/session.py +4 -4
  6. supervisely/nn/model/model_api.py +31 -20
  7. supervisely/nn/model/prediction.py +11 -0
  8. supervisely/nn/model/prediction_session.py +33 -6
  9. supervisely/nn/tracker/__init__.py +1 -2
  10. supervisely/nn/tracker/base_tracker.py +44 -0
  11. supervisely/nn/tracker/botsort/__init__.py +1 -0
  12. supervisely/nn/tracker/botsort/botsort_config.yaml +31 -0
  13. supervisely/nn/tracker/botsort/osnet_reid/osnet.py +566 -0
  14. supervisely/nn/tracker/botsort/osnet_reid/osnet_reid_interface.py +88 -0
  15. supervisely/nn/tracker/botsort/tracker/__init__.py +0 -0
  16. supervisely/nn/tracker/{bot_sort → botsort/tracker}/basetrack.py +1 -2
  17. supervisely/nn/tracker/{utils → botsort/tracker}/gmc.py +51 -59
  18. supervisely/nn/tracker/{deep_sort/deep_sort → botsort/tracker}/kalman_filter.py +71 -33
  19. supervisely/nn/tracker/botsort/tracker/matching.py +202 -0
  20. supervisely/nn/tracker/{bot_sort/bot_sort.py → botsort/tracker/mc_bot_sort.py} +68 -81
  21. supervisely/nn/tracker/botsort_tracker.py +259 -0
  22. supervisely/project/project.py +1 -1
  23. {supervisely-6.73.418.dist-info → supervisely-6.73.419.dist-info}/METADATA +3 -1
  24. {supervisely-6.73.418.dist-info → supervisely-6.73.419.dist-info}/RECORD +29 -42
  25. supervisely/nn/tracker/bot_sort/__init__.py +0 -21
  26. supervisely/nn/tracker/bot_sort/fast_reid_interface.py +0 -152
  27. supervisely/nn/tracker/bot_sort/matching.py +0 -127
  28. supervisely/nn/tracker/bot_sort/sly_tracker.py +0 -401
  29. supervisely/nn/tracker/deep_sort/__init__.py +0 -6
  30. supervisely/nn/tracker/deep_sort/deep_sort/__init__.py +0 -1
  31. supervisely/nn/tracker/deep_sort/deep_sort/detection.py +0 -49
  32. supervisely/nn/tracker/deep_sort/deep_sort/iou_matching.py +0 -81
  33. supervisely/nn/tracker/deep_sort/deep_sort/linear_assignment.py +0 -202
  34. supervisely/nn/tracker/deep_sort/deep_sort/nn_matching.py +0 -176
  35. supervisely/nn/tracker/deep_sort/deep_sort/track.py +0 -166
  36. supervisely/nn/tracker/deep_sort/deep_sort/tracker.py +0 -145
  37. supervisely/nn/tracker/deep_sort/deep_sort.py +0 -301
  38. supervisely/nn/tracker/deep_sort/generate_clip_detections.py +0 -90
  39. supervisely/nn/tracker/deep_sort/preprocessing.py +0 -70
  40. supervisely/nn/tracker/deep_sort/sly_tracker.py +0 -273
  41. supervisely/nn/tracker/tracker.py +0 -285
  42. supervisely/nn/tracker/utils/kalman_filter.py +0 -492
  43. supervisely/nn/tracking/__init__.py +0 -1
  44. supervisely/nn/tracking/boxmot.py +0 -114
  45. supervisely/nn/tracking/tracking.py +0 -24
  46. /supervisely/nn/tracker/{utils → botsort/osnet_reid}/__init__.py +0 -0
  47. {supervisely-6.73.418.dist-info → supervisely-6.73.419.dist-info}/LICENSE +0 -0
  48. {supervisely-6.73.418.dist-info → supervisely-6.73.419.dist-info}/WHEEL +0 -0
  49. {supervisely-6.73.418.dist-info → supervisely-6.73.419.dist-info}/entry_points.txt +0 -0
  50. {supervisely-6.73.418.dist-info → supervisely-6.73.419.dist-info}/top_level.txt +0 -0
@@ -1,492 +0,0 @@
1
- import numpy as np
2
-
3
- """
4
- Table for the 0.95 quantile of the chi-square distribution with N degrees of
5
- freedom (contains values for N=1, ..., 9). Taken from MATLAB/Octave's chi2inv
6
- function and used as Mahalanobis gating threshold.
7
- """
8
- chi2inv95 = {
9
- 1: 3.8415,
10
- 2: 5.9915,
11
- 3: 7.8147,
12
- 4: 9.4877,
13
- 5: 11.070,
14
- 6: 12.592,
15
- 7: 14.067,
16
- 8: 15.507,
17
- 9: 16.919,
18
- }
19
-
20
-
21
- class KalmanFilterXYWH(object):
22
- """
23
- A simple Kalman filter for tracking bounding boxes in image space.
24
-
25
- The 8-dimensional state space
26
-
27
- x, y, w, h, vx, vy, vw, vh
28
-
29
- contains the bounding box center position (x, y), width w, height h,
30
- and their respective velocities.
31
-
32
- Object motion follows a constant velocity model. The bounding box location
33
- (x, y, w, h) is taken as direct observation of the state space (linear
34
- observation model).
35
-
36
- """
37
-
38
- def __init__(self):
39
- ndim, dt = 4, 1.0
40
-
41
- # Create Kalman filter model matrices.
42
- self._motion_mat = np.eye(2 * ndim, 2 * ndim)
43
- for i in range(ndim):
44
- self._motion_mat[i, ndim + i] = dt
45
- self._update_mat = np.eye(ndim, 2 * ndim)
46
-
47
- # Motion and observation uncertainty are chosen relative to the current
48
- # state estimate. These weights control the amount of uncertainty in
49
- # the model. This is a bit hacky.
50
- self._std_weight_position = 1.0 / 20
51
- self._std_weight_velocity = 1.0 / 160
52
-
53
- def initiate(self, measurement):
54
- """Create track from unassociated measurement.
55
-
56
- Parameters
57
- ----------
58
- measurement : ndarray
59
- Bounding box coordinates (x, y, w, h) with center position (x, y),
60
- width w, and height h.
61
-
62
- Returns
63
- -------
64
- (ndarray, ndarray)
65
- Returns the mean vector (8 dimensional) and covariance matrix (8x8
66
- dimensional) of the new track. Unobserved velocities are initialized
67
- to 0 mean.
68
-
69
- """
70
- mean_pos = measurement
71
- mean_vel = np.zeros_like(mean_pos)
72
- mean = np.r_[mean_pos, mean_vel]
73
-
74
- std = [
75
- 2 * self._std_weight_position * measurement[2],
76
- 2 * self._std_weight_position * measurement[3],
77
- 2 * self._std_weight_position * measurement[2],
78
- 2 * self._std_weight_position * measurement[3],
79
- 10 * self._std_weight_velocity * measurement[2],
80
- 10 * self._std_weight_velocity * measurement[3],
81
- 10 * self._std_weight_velocity * measurement[2],
82
- 10 * self._std_weight_velocity * measurement[3],
83
- ]
84
- covariance = np.diag(np.square(std))
85
- return mean, covariance
86
-
87
- def predict(self, mean, covariance):
88
- """Run Kalman filter prediction step.
89
-
90
- Parameters
91
- ----------
92
- mean : ndarray
93
- The 8 dimensional mean vector of the object state at the previous
94
- time step.
95
- covariance : ndarray
96
- The 8x8 dimensional covariance matrix of the object state at the
97
- previous time step.
98
-
99
- Returns
100
- -------
101
- (ndarray, ndarray)
102
- Returns the mean vector and covariance matrix of the predicted
103
- state. Unobserved velocities are initialized to 0 mean.
104
-
105
- """
106
- std_pos = [
107
- self._std_weight_position * mean[2],
108
- self._std_weight_position * mean[3],
109
- self._std_weight_position * mean[2],
110
- self._std_weight_position * mean[3],
111
- ]
112
- std_vel = [
113
- self._std_weight_velocity * mean[2],
114
- self._std_weight_velocity * mean[3],
115
- self._std_weight_velocity * mean[2],
116
- self._std_weight_velocity * mean[3],
117
- ]
118
- motion_cov = np.diag(np.square(np.r_[std_pos, std_vel]))
119
-
120
- mean = np.dot(mean, self._motion_mat.T)
121
- covariance = (
122
- np.linalg.multi_dot((self._motion_mat, covariance, self._motion_mat.T)) + motion_cov
123
- )
124
-
125
- return mean, covariance
126
-
127
- def project(self, mean, covariance):
128
- """Project state distribution to measurement space.
129
-
130
- Parameters
131
- ----------
132
- mean : ndarray
133
- The state's mean vector (8 dimensional array).
134
- covariance : ndarray
135
- The state's covariance matrix (8x8 dimensional).
136
-
137
- Returns
138
- -------
139
- (ndarray, ndarray)
140
- Returns the projected mean and covariance matrix of the given state
141
- estimate.
142
-
143
- """
144
- std = [
145
- self._std_weight_position * mean[2],
146
- self._std_weight_position * mean[3],
147
- self._std_weight_position * mean[2],
148
- self._std_weight_position * mean[3],
149
- ]
150
- innovation_cov = np.diag(np.square(std))
151
-
152
- mean = np.dot(self._update_mat, mean)
153
- covariance = np.linalg.multi_dot((self._update_mat, covariance, self._update_mat.T))
154
- return mean, covariance + innovation_cov
155
-
156
- def multi_predict(self, mean, covariance):
157
- """Run Kalman filter prediction step (Vectorized version).
158
- Parameters
159
- ----------
160
- mean : ndarray
161
- The Nx8 dimensional mean matrix of the object states at the previous
162
- time step.
163
- covariance : ndarray
164
- The Nx8x8 dimensional covariance matrics of the object states at the
165
- previous time step.
166
- Returns
167
- -------
168
- (ndarray, ndarray)
169
- Returns the mean vector and covariance matrix of the predicted
170
- state. Unobserved velocities are initialized to 0 mean.
171
- """
172
- std_pos = [
173
- self._std_weight_position * mean[:, 2],
174
- self._std_weight_position * mean[:, 3],
175
- self._std_weight_position * mean[:, 2],
176
- self._std_weight_position * mean[:, 3],
177
- ]
178
- std_vel = [
179
- self._std_weight_velocity * mean[:, 2],
180
- self._std_weight_velocity * mean[:, 3],
181
- self._std_weight_velocity * mean[:, 2],
182
- self._std_weight_velocity * mean[:, 3],
183
- ]
184
- sqr = np.square(np.r_[std_pos, std_vel]).T
185
-
186
- motion_cov = []
187
- for i in range(len(mean)):
188
- motion_cov.append(np.diag(sqr[i]))
189
- motion_cov = np.asarray(motion_cov)
190
-
191
- mean = np.dot(mean, self._motion_mat.T)
192
- left = np.dot(self._motion_mat, covariance).transpose((1, 0, 2))
193
- covariance = np.dot(left, self._motion_mat.T) + motion_cov
194
-
195
- return mean, covariance
196
-
197
- def update(self, mean, covariance, measurement):
198
- """Run Kalman filter correction step.
199
-
200
- Parameters
201
- ----------
202
- mean : ndarray
203
- The predicted state's mean vector (8 dimensional).
204
- covariance : ndarray
205
- The state's covariance matrix (8x8 dimensional).
206
- measurement : ndarray
207
- The 4 dimensional measurement vector (x, y, w, h), where (x, y)
208
- is the center position, w the width, and h the height of the
209
- bounding box.
210
-
211
- Returns
212
- -------
213
- (ndarray, ndarray)
214
- Returns the measurement-corrected state distribution.
215
-
216
- """
217
- import scipy.linalg # pylint: disable=import-error
218
-
219
- projected_mean, projected_cov = self.project(mean, covariance)
220
-
221
- chol_factor, lower = scipy.linalg.cho_factor(projected_cov, lower=True, check_finite=False)
222
- kalman_gain = scipy.linalg.cho_solve(
223
- (chol_factor, lower), np.dot(covariance, self._update_mat.T).T, check_finite=False
224
- ).T
225
- innovation = measurement - projected_mean
226
-
227
- new_mean = mean + np.dot(innovation, kalman_gain.T)
228
- new_covariance = covariance - np.linalg.multi_dot(
229
- (kalman_gain, projected_cov, kalman_gain.T)
230
- )
231
- return new_mean, new_covariance
232
-
233
- def gating_distance(self, mean, covariance, measurements, only_position=False, metric="maha"):
234
- """Compute gating distance between state distribution and measurements.
235
- A suitable distance threshold can be obtained from `chi2inv95`. If
236
- `only_position` is False, the chi-square distribution has 4 degrees of
237
- freedom, otherwise 2.
238
- Parameters
239
- ----------
240
- mean : ndarray
241
- Mean vector over the state distribution (8 dimensional).
242
- covariance : ndarray
243
- Covariance of the state distribution (8x8 dimensional).
244
- measurements : ndarray
245
- An Nx4 dimensional matrix of N measurements, each in
246
- format (x, y, a, h) where (x, y) is the bounding box center
247
- position, a the aspect ratio, and h the height.
248
- only_position : Optional[bool]
249
- If True, distance computation is done with respect to the bounding
250
- box center position only.
251
- Returns
252
- -------
253
- ndarray
254
- Returns an array of length N, where the i-th element contains the
255
- squared Mahalanobis distance between (mean, covariance) and
256
- `measurements[i]`.
257
- """
258
- import scipy.linalg # pylint: disable=import-error
259
-
260
- mean, covariance = self.project(mean, covariance)
261
- if only_position:
262
- mean, covariance = mean[:2], covariance[:2, :2]
263
- measurements = measurements[:, :2]
264
-
265
- d = measurements - mean
266
- if metric == "gaussian":
267
- return np.sum(d * d, axis=1)
268
- elif metric == "maha":
269
- cholesky_factor = np.linalg.cholesky(covariance)
270
- z = scipy.linalg.solve_triangular(
271
- cholesky_factor, d.T, lower=True, check_finite=False, overwrite_b=True
272
- )
273
- squared_maha = np.sum(z * z, axis=0)
274
- return squared_maha
275
- else:
276
- raise ValueError("invalid distance metric")
277
-
278
-
279
- class KalmanFilterXYAH(object):
280
- """
281
- A simple Kalman filter for tracking bounding boxes in image space.
282
-
283
- The 8-dimensional state space
284
-
285
- x, y, a, h, vx, vy, va, vh
286
-
287
- contains the bounding box center position (x, y), aspect ratio a, height h,
288
- and their respective velocities.
289
-
290
- Object motion follows a constant velocity model. The bounding box location
291
- (x, y, a, h) is taken as direct observation of the state space (linear
292
- observation model).
293
-
294
- """
295
-
296
- def __init__(self):
297
- ndim, dt = 4, 1.0
298
-
299
- # Create Kalman filter model matrices.
300
- self._motion_mat = np.eye(2 * ndim, 2 * ndim)
301
- for i in range(ndim):
302
- self._motion_mat[i, ndim + i] = dt
303
- self._update_mat = np.eye(ndim, 2 * ndim)
304
-
305
- # Motion and observation uncertainty are chosen relative to the current
306
- # state estimate. These weights control the amount of uncertainty in
307
- # the model. This is a bit hacky.
308
- self._std_weight_position = 1.0 / 20
309
- self._std_weight_velocity = 1.0 / 160
310
-
311
- def initiate(self, measurement):
312
- """Create track from unassociated measurement.
313
-
314
- Parameters
315
- ----------
316
- measurement : ndarray
317
- Bounding box coordinates (x, y, a, h) with center position (x, y),
318
- aspect ratio a, and height h.
319
-
320
- Returns
321
- -------
322
- (ndarray, ndarray)
323
- Returns the mean vector (8 dimensional) and covariance matrix (8x8
324
- dimensional) of the new track. Unobserved velocities are initialized
325
- to 0 mean.
326
-
327
- """
328
- mean_pos = measurement
329
- mean_vel = np.zeros_like(mean_pos)
330
- mean = np.r_[mean_pos, mean_vel]
331
-
332
- std = [
333
- 2 * self._std_weight_position * measurement[3],
334
- 2 * self._std_weight_position * measurement[3],
335
- 1e-2,
336
- 2 * self._std_weight_position * measurement[3],
337
- 10 * self._std_weight_velocity * measurement[3],
338
- 10 * self._std_weight_velocity * measurement[3],
339
- 1e-5,
340
- 10 * self._std_weight_velocity * measurement[3],
341
- ]
342
- covariance = np.diag(np.square(std))
343
- return mean, covariance
344
-
345
- def predict(self, mean, covariance):
346
- """Run Kalman filter prediction step.
347
-
348
- Parameters
349
- ----------
350
- mean : ndarray
351
- The 8 dimensional mean vector of the object state at the previous
352
- time step.
353
- covariance : ndarray
354
- The 8x8 dimensional covariance matrix of the object state at the
355
- previous time step.
356
-
357
- Returns
358
- -------
359
- (ndarray, ndarray)
360
- Returns the mean vector and covariance matrix of the predicted
361
- state. Unobserved velocities are initialized to 0 mean.
362
-
363
- """
364
- std_pos = [
365
- self._std_weight_position * mean[3],
366
- self._std_weight_position * mean[3],
367
- 1e-2,
368
- self._std_weight_position * mean[3],
369
- ]
370
- std_vel = [
371
- self._std_weight_velocity * mean[3],
372
- self._std_weight_velocity * mean[3],
373
- 1e-5,
374
- self._std_weight_velocity * mean[3],
375
- ]
376
- motion_cov = np.diag(np.square(np.r_[std_pos, std_vel]))
377
-
378
- mean = np.dot(self._motion_mat, mean)
379
- covariance = (
380
- np.linalg.multi_dot((self._motion_mat, covariance, self._motion_mat.T)) + motion_cov
381
- )
382
-
383
- return mean, covariance
384
-
385
- def project(self, mean, covariance):
386
- """Project state distribution to measurement space.
387
-
388
- Parameters
389
- ----------
390
- mean : ndarray
391
- The state's mean vector (8 dimensional array).
392
- covariance : ndarray
393
- The state's covariance matrix (8x8 dimensional).
394
-
395
- Returns
396
- -------
397
- (ndarray, ndarray)
398
- Returns the projected mean and covariance matrix of the given state
399
- estimate.
400
-
401
- """
402
- std = [
403
- self._std_weight_position * mean[3],
404
- self._std_weight_position * mean[3],
405
- 1e-1,
406
- self._std_weight_position * mean[3],
407
- ]
408
- innovation_cov = np.diag(np.square(std))
409
-
410
- mean = np.dot(self._update_mat, mean)
411
- covariance = np.linalg.multi_dot((self._update_mat, covariance, self._update_mat.T))
412
- return mean, covariance + innovation_cov
413
-
414
- def update(self, mean, covariance, measurement):
415
- """Run Kalman filter correction step.
416
-
417
- Parameters
418
- ----------
419
- mean : ndarray
420
- The predicted state's mean vector (8 dimensional).
421
- covariance : ndarray
422
- The state's covariance matrix (8x8 dimensional).
423
- measurement : ndarray
424
- The 4 dimensional measurement vector (x, y, a, h), where (x, y)
425
- is the center position, a the aspect ratio, and h the height of the
426
- bounding box.
427
-
428
- Returns
429
- -------
430
- (ndarray, ndarray)
431
- Returns the measurement-corrected state distribution.
432
-
433
- """
434
- import scipy.linalg # pylint: disable=import-error
435
-
436
- projected_mean, projected_cov = self.project(mean, covariance)
437
-
438
- chol_factor, lower = scipy.linalg.cho_factor(projected_cov, lower=True, check_finite=False)
439
- kalman_gain = scipy.linalg.cho_solve(
440
- (chol_factor, lower), np.dot(covariance, self._update_mat.T).T, check_finite=False
441
- ).T
442
- innovation = measurement - projected_mean
443
-
444
- new_mean = mean + np.dot(innovation, kalman_gain.T)
445
- new_covariance = covariance - np.linalg.multi_dot(
446
- (kalman_gain, projected_cov, kalman_gain.T)
447
- )
448
- return new_mean, new_covariance
449
-
450
- def gating_distance(self, mean, covariance, measurements, only_position=False):
451
- """Compute gating distance between state distribution and measurements.
452
-
453
- A suitable distance threshold can be obtained from `chi2inv95`. If
454
- `only_position` is False, the chi-square distribution has 4 degrees of
455
- freedom, otherwise 2.
456
-
457
- Parameters
458
- ----------
459
- mean : ndarray
460
- Mean vector over the state distribution (8 dimensional).
461
- covariance : ndarray
462
- Covariance of the state distribution (8x8 dimensional).
463
- measurements : ndarray
464
- An Nx4 dimensional matrix of N measurements, each in
465
- format (x, y, a, h) where (x, y) is the bounding box center
466
- position, a the aspect ratio, and h the height.
467
- only_position : Optional[bool]
468
- If True, distance computation is done with respect to the bounding
469
- box center position only.
470
-
471
- Returns
472
- -------
473
- ndarray
474
- Returns an array of length N, where the i-th element contains the
475
- squared Mahalanobis distance between (mean, covariance) and
476
- `measurements[i]`.
477
-
478
- """
479
- import scipy.linalg # pylint: disable=import-error
480
-
481
- mean, covariance = self.project(mean, covariance)
482
- if only_position:
483
- mean, covariance = mean[:2], covariance[:2, :2]
484
- measurements = measurements[:, :2]
485
-
486
- cholesky_factor = np.linalg.cholesky(covariance)
487
- d = measurements - mean
488
- z = scipy.linalg.solve_triangular(
489
- cholesky_factor, d.T, lower=True, check_finite=False, overwrite_b=True
490
- )
491
- squared_maha = np.sum(z * z, axis=0)
492
- return squared_maha
@@ -1 +0,0 @@
1
- from supervisely.nn.tracking.tracking import track
@@ -1,114 +0,0 @@
1
- from typing import Iterable, List, Optional, Union
2
-
3
- import numpy as np
4
-
5
- from supervisely.annotation.annotation import Annotation
6
- from supervisely.geometry.rectangle import Rectangle
7
- from supervisely.nn.model.model_api import Prediction
8
- from supervisely.video_annotation.frame import Frame
9
- from supervisely.video_annotation.frame_collection import FrameCollection
10
- from supervisely.video_annotation.video_annotation import VideoAnnotation
11
- from supervisely.video_annotation.video_figure import VideoFigure
12
- from supervisely.video_annotation.video_object import VideoObject
13
- from supervisely.video_annotation.video_object_collection import VideoObjectCollection
14
-
15
-
16
- def _none_generator():
17
- while True:
18
- yield None
19
-
20
-
21
- def apply_boxmot(
22
- tracker,
23
- predictions: Union[List[Prediction], List[Annotation]],
24
- class_names: List[str],
25
- frames: Optional[Iterable[np.ndarray]] = None,
26
- ) -> VideoAnnotation:
27
- if frames is None:
28
- frames = _none_generator()
29
- results = []
30
- annotations = []
31
- frames_count = 0
32
- for prediction, frame in zip(predictions, frames):
33
- frames_count += 1
34
- if isinstance(prediction, Prediction):
35
- annotation = prediction.annotation
36
- if frame is None:
37
- frame = prediction.load_image()
38
- else:
39
- annotation = prediction
40
- frame_shape = frame.shape[:2]
41
- annotations.append(annotation)
42
- detections = to_boxes(annotation, class_names) # N x (x, y, x, y, conf, label)
43
- tracks = tracker.update(
44
- detections, frame
45
- ) # M x (x, y, x, y, track_id, conf, label, det_id)
46
- results.append(tracks)
47
- return create_video_annotation(annotations, results, class_names, frame_shape, frames_count)
48
-
49
-
50
- def to_boxes(ann: Annotation, class_names: List[str]) -> np.ndarray:
51
- """
52
- Convert annotation to detections array in boxmot format.
53
- :param ann: Supervisely Annotation object
54
- :type ann: Annotation
55
- :param class_names: model class names
56
- :type class_names: List[str]
57
- :return: detections array N x (x, y, x, y, conf, label)
58
- :rtype: np.ndarray
59
- """
60
- # convert ann to N x (x, y, x, y, conf, cls) np.array
61
- cls2label = {class_name: i for i, class_name in enumerate(class_names)}
62
- detections = []
63
- for label in ann.labels:
64
- cat = cls2label[label.obj_class.name]
65
- bbox = label.geometry.to_bbox()
66
- conf = label.tags.get("confidence").value
67
- detections.append([bbox.left, bbox.top, bbox.right, bbox.bottom, conf, cat])
68
- detections = np.array(detections)
69
- return detections
70
-
71
-
72
- def create_video_annotation(
73
- annotations: List[Annotation],
74
- tracking_results: list,
75
- class_names: List[str],
76
- frame_shape: tuple,
77
- frames_count: int,
78
- ) -> VideoAnnotation:
79
- img_h, img_w = frame_shape
80
- video_objects = {} # track_id -> VideoObject
81
- frames = []
82
- cat2obj = {}
83
- name2cat = {class_name: i for i, class_name in enumerate(class_names)}
84
- obj_classes = {}
85
- for annotation in annotations:
86
- for label in annotation.labels:
87
- obj_classes.setdefault(label.obj_class.name, label.obj_class)
88
- for obj_name, cat in name2cat.items():
89
- obj_class = obj_classes.get(obj_name)
90
- if obj_class is None:
91
- raise ValueError(f"Object class {obj_name} not found in annotations.")
92
- cat2obj[cat] = obj_class
93
- for i, tracks in enumerate(tracking_results):
94
- frame_figures = []
95
- for track in tracks:
96
- # crop bbox to image size
97
- dims = np.array([img_w, img_h, img_w, img_h]) - 1
98
- track[:4] = np.clip(track[:4], 0, dims)
99
- x1, y1, x2, y2, track_id, conf, cat = track[:7]
100
- cat = int(cat)
101
- track_id = int(track_id)
102
- rect = Rectangle(y1, x1, y2, x2)
103
- video_object = video_objects.setdefault(track_id, VideoObject(cat2obj[cat]))
104
- frame_figures.append(VideoFigure(video_object, rect, i))
105
- frames.append(Frame(i, frame_figures))
106
-
107
- objects = list(video_objects.values())
108
- video_annotation = VideoAnnotation(
109
- img_size=frame_shape,
110
- frames_count=frames_count,
111
- objects=VideoObjectCollection(objects),
112
- frames=FrameCollection(frames),
113
- )
114
- return video_annotation
@@ -1,24 +0,0 @@
1
- from typing import Any, Callable
2
-
3
- from supervisely.nn.model.model_api import ModelAPI
4
- from supervisely.nn.tracking.boxmot import apply_boxmot
5
- from supervisely.video_annotation.video_annotation import VideoAnnotation
6
-
7
-
8
- def _get_apply_fn(tracker: Any) -> Callable:
9
- if tracker.__class__.__module__.startswith("boxmot"):
10
- return apply_boxmot
11
- else:
12
- raise ValueError(
13
- f"Tracker {tracker.__class__.__module__} is not supported. Please, use boxmot tracker."
14
- )
15
-
16
-
17
- def track(video_id: int, tracker, detector: ModelAPI, **kwargs) -> VideoAnnotation:
18
- apply_fn = _get_apply_fn(tracker)
19
- if "classes" in kwargs:
20
- classes = kwargs["classes"]
21
- else:
22
- classes = detector.get_classes()
23
- predictions = detector.predict_detached(video_id=video_id, **kwargs)
24
- return apply_fn(tracker, predictions, classes)