tracktors 2.6.0.dev0__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.
- trackers/__init__.py +58 -0
- trackers/annotators/__init__.py +5 -0
- trackers/annotators/trace.py +219 -0
- trackers/core/__init__.py +5 -0
- trackers/core/base.py +683 -0
- trackers/core/botsort/__init__.py +8 -0
- trackers/core/botsort/cmc.py +47 -0
- trackers/core/botsort/tracker.py +503 -0
- trackers/core/botsort/tracklet.py +252 -0
- trackers/core/botsort/utils.py +92 -0
- trackers/core/bytetrack/__init__.py +5 -0
- trackers/core/bytetrack/tracker.py +427 -0
- trackers/core/bytetrack/tracklet.py +71 -0
- trackers/core/bytetrack/utils.py +65 -0
- trackers/core/cbiou/__init__.py +5 -0
- trackers/core/cbiou/tracker.py +335 -0
- trackers/core/ocsort/__init__.py +5 -0
- trackers/core/ocsort/tracker.py +416 -0
- trackers/core/ocsort/tracklet.py +371 -0
- trackers/core/ocsort/utils.py +113 -0
- trackers/core/sort/__init__.py +5 -0
- trackers/core/sort/tracker.py +294 -0
- trackers/core/sort/tracklet.py +84 -0
- trackers/core/sort/utils.py +153 -0
- trackers/datasets/__init__.py +7 -0
- trackers/datasets/download.py +167 -0
- trackers/datasets/manifest.py +144 -0
- trackers/eval/__init__.py +54 -0
- trackers/eval/box.py +194 -0
- trackers/eval/clear.py +365 -0
- trackers/eval/constants.py +17 -0
- trackers/eval/evaluate.py +421 -0
- trackers/eval/hota.py +350 -0
- trackers/eval/identity.py +235 -0
- trackers/eval/results.py +704 -0
- trackers/io/__init__.py +5 -0
- trackers/io/frames.py +67 -0
- trackers/io/mot.py +469 -0
- trackers/io/paths.py +40 -0
- trackers/io/video.py +164 -0
- trackers/motion/__init__.py +5 -0
- trackers/motion/estimator.py +225 -0
- trackers/motion/transformation.py +144 -0
- trackers/py.typed +0 -0
- trackers/scripts/__init__.py +5 -0
- trackers/scripts/__main__.py +70 -0
- trackers/scripts/download.py +109 -0
- trackers/scripts/eval.py +169 -0
- trackers/scripts/progress.py +232 -0
- trackers/scripts/track.py +738 -0
- trackers/scripts/tune.py +230 -0
- trackers/tune/__init__.py +11 -0
- trackers/tune/tuner.py +452 -0
- trackers/utils/__init__.py +5 -0
- trackers/utils/base_tracklet.py +113 -0
- trackers/utils/cmc.py +935 -0
- trackers/utils/converters.py +115 -0
- trackers/utils/detections.py +49 -0
- trackers/utils/device.py +30 -0
- trackers/utils/downloader.py +230 -0
- trackers/utils/general.py +73 -0
- trackers/utils/iou.py +202 -0
- trackers/utils/kalman_filter.py +155 -0
- trackers/utils/motion_models.py +204 -0
- trackers/utils/predict_timing.py +60 -0
- trackers/utils/state_representations.py +341 -0
- tracktors/__init__.py +20 -0
- tracktors/py.typed +1 -0
- tracktors-2.6.0.dev0.dist-info/METADATA +218 -0
- tracktors-2.6.0.dev0.dist-info/RECORD +74 -0
- tracktors-2.6.0.dev0.dist-info/WHEEL +5 -0
- tracktors-2.6.0.dev0.dist-info/entry_points.txt +3 -0
- tracktors-2.6.0.dev0.dist-info/licenses/LICENSE +201 -0
- tracktors-2.6.0.dev0.dist-info/top_level.txt +2 -0
trackers/__init__.py
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# ------------------------------------------------------------------------
|
|
2
|
+
# Trackers
|
|
3
|
+
# Copyright (c) 2026 Roboflow. All Rights Reserved.
|
|
4
|
+
# Licensed under the Apache License, Version 2.0 [see LICENSE for details]
|
|
5
|
+
# ------------------------------------------------------------------------
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
from trackers.annotators.trace import MotionAwareTraceAnnotator
|
|
10
|
+
from trackers.core.botsort.tracker import BoTSORTTracker
|
|
11
|
+
from trackers.core.bytetrack.tracker import ByteTrackTracker
|
|
12
|
+
from trackers.core.cbiou.tracker import CBIoUTracker
|
|
13
|
+
from trackers.core.ocsort.tracker import OCSORTTracker
|
|
14
|
+
from trackers.core.sort.tracker import SORTTracker
|
|
15
|
+
from trackers.datasets.download import download_dataset
|
|
16
|
+
from trackers.datasets.manifest import Dataset, DatasetAsset, DatasetSplit
|
|
17
|
+
from trackers.io.mot import load_mot_file
|
|
18
|
+
from trackers.io.video import frames_from_source
|
|
19
|
+
from trackers.motion.estimator import MotionEstimator
|
|
20
|
+
from trackers.motion.transformation import (
|
|
21
|
+
CoordinatesTransformation,
|
|
22
|
+
HomographyTransformation,
|
|
23
|
+
IdentityTransformation,
|
|
24
|
+
)
|
|
25
|
+
from trackers.utils.cmc import CMC, CMCConfig, CMCMethod, CMCTMethod
|
|
26
|
+
from trackers.utils.converters import xcycsr_to_xyxy, xyxy_to_xcycsr
|
|
27
|
+
from trackers.utils.iou import BaseIoU, BIoU, CIoU, DIoU, GIoU, IoU
|
|
28
|
+
|
|
29
|
+
__all__ = [
|
|
30
|
+
"CMC",
|
|
31
|
+
"BIoU",
|
|
32
|
+
"BaseIoU",
|
|
33
|
+
"BoTSORTTracker",
|
|
34
|
+
"ByteTrackTracker",
|
|
35
|
+
"CBIoUTracker",
|
|
36
|
+
"CIoU",
|
|
37
|
+
"CMCConfig",
|
|
38
|
+
"CMCMethod",
|
|
39
|
+
"CMCTMethod",
|
|
40
|
+
"CoordinatesTransformation",
|
|
41
|
+
"DIoU",
|
|
42
|
+
"Dataset",
|
|
43
|
+
"DatasetAsset",
|
|
44
|
+
"DatasetSplit",
|
|
45
|
+
"GIoU",
|
|
46
|
+
"HomographyTransformation",
|
|
47
|
+
"IdentityTransformation",
|
|
48
|
+
"IoU",
|
|
49
|
+
"MotionAwareTraceAnnotator",
|
|
50
|
+
"MotionEstimator",
|
|
51
|
+
"OCSORTTracker",
|
|
52
|
+
"SORTTracker",
|
|
53
|
+
"download_dataset",
|
|
54
|
+
"frames_from_source",
|
|
55
|
+
"load_mot_file",
|
|
56
|
+
"xcycsr_to_xyxy",
|
|
57
|
+
"xyxy_to_xcycsr",
|
|
58
|
+
]
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
# ------------------------------------------------------------------------
|
|
2
|
+
# Trackers
|
|
3
|
+
# Copyright (c) 2026 Roboflow. All Rights Reserved.
|
|
4
|
+
# Licensed under the Apache License, Version 2.0 [see LICENSE for details]
|
|
5
|
+
# ------------------------------------------------------------------------
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
# ------------------------------------------------------------------------
|
|
2
|
+
# Trackers
|
|
3
|
+
# Copyright (c) 2026 Roboflow. All Rights Reserved.
|
|
4
|
+
# Licensed under the Apache License, Version 2.0 [see LICENSE for details]
|
|
5
|
+
# ------------------------------------------------------------------------
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
from collections import defaultdict
|
|
10
|
+
|
|
11
|
+
import cv2
|
|
12
|
+
import numpy as np
|
|
13
|
+
import supervision as sv
|
|
14
|
+
from supervision.annotators.utils import ColorLookup, resolve_color
|
|
15
|
+
from supervision.draw.color import Color, ColorPalette
|
|
16
|
+
from supervision.geometry.core import Position
|
|
17
|
+
|
|
18
|
+
from trackers.motion.transformation import (
|
|
19
|
+
CoordinatesTransformation,
|
|
20
|
+
IdentityTransformation,
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class MotionAwareTraceAnnotator:
|
|
25
|
+
"""Draws object trajectories with camera motion compensation.
|
|
26
|
+
|
|
27
|
+
This annotator maintains a history of object positions in world coordinates
|
|
28
|
+
and draws them as trajectories (traces) on each frame. When used with camera
|
|
29
|
+
motion compensation, trajectories appear stable even when the camera moves.
|
|
30
|
+
|
|
31
|
+
The API is compatible with supervision annotators, using the same color
|
|
32
|
+
resolution strategy and position anchoring.
|
|
33
|
+
|
|
34
|
+
Args:
|
|
35
|
+
color: The color to draw the trace. Can be a single `Color` or a
|
|
36
|
+
`ColorPalette`. Defaults to `ColorPalette.DEFAULT`.
|
|
37
|
+
position: The anchor position on the bounding box for the trace point.
|
|
38
|
+
Defaults to `Position.CENTER`.
|
|
39
|
+
trace_length: Maximum number of points to store per trajectory.
|
|
40
|
+
Defaults to `30`.
|
|
41
|
+
thickness: Line thickness for drawing traces. Defaults to `2`.
|
|
42
|
+
color_lookup: Strategy for mapping colors to annotations.
|
|
43
|
+
Options are `INDEX`, `CLASS`, `TRACK`. Defaults to `ColorLookup.TRACK`.
|
|
44
|
+
|
|
45
|
+
Example:
|
|
46
|
+
```python
|
|
47
|
+
import cv2
|
|
48
|
+
import supervision as sv
|
|
49
|
+
from inference import get_model
|
|
50
|
+
|
|
51
|
+
from trackers import (
|
|
52
|
+
ByteTrackTracker,
|
|
53
|
+
MotionAwareTraceAnnotator,
|
|
54
|
+
MotionEstimator,
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
model = get_model("rfdetr-nano")
|
|
58
|
+
tracker = ByteTrackTracker()
|
|
59
|
+
motion_estimator = MotionEstimator()
|
|
60
|
+
trace_annotator = MotionAwareTraceAnnotator()
|
|
61
|
+
|
|
62
|
+
cap = cv2.VideoCapture("moving_camera.mp4")
|
|
63
|
+
while True:
|
|
64
|
+
ret, frame = cap.read()
|
|
65
|
+
if not ret:
|
|
66
|
+
break
|
|
67
|
+
|
|
68
|
+
coord_transform = motion_estimator.update(frame)
|
|
69
|
+
|
|
70
|
+
result = model.infer(frame)[0]
|
|
71
|
+
detections = sv.Detections.from_inference(result)
|
|
72
|
+
detections = tracker.update(detections)
|
|
73
|
+
|
|
74
|
+
frame = trace_annotator.annotate(
|
|
75
|
+
scene=frame,
|
|
76
|
+
detections=detections,
|
|
77
|
+
coord_transform=coord_transform,
|
|
78
|
+
)
|
|
79
|
+
```
|
|
80
|
+
"""
|
|
81
|
+
|
|
82
|
+
def __init__(
|
|
83
|
+
self,
|
|
84
|
+
color: Color | ColorPalette | None = None,
|
|
85
|
+
position: Position | None = None,
|
|
86
|
+
trace_length: int = 30,
|
|
87
|
+
thickness: int = 2,
|
|
88
|
+
color_lookup: ColorLookup | None = None,
|
|
89
|
+
) -> None:
|
|
90
|
+
self.color: Color | ColorPalette = color if color is not None else ColorPalette.DEFAULT
|
|
91
|
+
self.position: Position = position if position is not None else Position.CENTER
|
|
92
|
+
self.trace_length = trace_length
|
|
93
|
+
self.thickness = thickness
|
|
94
|
+
self.color_lookup: ColorLookup = color_lookup if color_lookup is not None else ColorLookup.TRACK
|
|
95
|
+
|
|
96
|
+
self._trajectories: dict[int, list[tuple[float, float]]] = defaultdict(list)
|
|
97
|
+
|
|
98
|
+
def _get_anchor_points(self, detections: sv.Detections) -> np.ndarray:
|
|
99
|
+
"""Extract anchor points from detections based on position setting.
|
|
100
|
+
|
|
101
|
+
Args:
|
|
102
|
+
detections: Detections object with xyxy boxes.
|
|
103
|
+
|
|
104
|
+
Returns:
|
|
105
|
+
Array of shape `(N, 2)` with `(x, y)` anchor points.
|
|
106
|
+
"""
|
|
107
|
+
return detections.get_anchors_coordinates(self.position)
|
|
108
|
+
|
|
109
|
+
def annotate(
|
|
110
|
+
self,
|
|
111
|
+
scene: np.ndarray,
|
|
112
|
+
detections: sv.Detections,
|
|
113
|
+
custom_color_lookup: np.ndarray | None = None,
|
|
114
|
+
coord_transform: CoordinatesTransformation | None = None,
|
|
115
|
+
) -> np.ndarray:
|
|
116
|
+
"""Draw motion-compensated trace paths on the scene.
|
|
117
|
+
|
|
118
|
+
Updates internal trajectory storage with new detection positions (converted
|
|
119
|
+
to world coordinates), then draws all trajectories transformed back to
|
|
120
|
+
frame coordinates.
|
|
121
|
+
|
|
122
|
+
Args:
|
|
123
|
+
scene: The image on which traces will be drawn. Modified in place.
|
|
124
|
+
detections: Detections with `tracker_id` field populated.
|
|
125
|
+
custom_color_lookup: Optional custom color lookup array to override
|
|
126
|
+
the default color mapping strategy.
|
|
127
|
+
coord_transform: Coordinate transformation for the current frame.
|
|
128
|
+
If None, uses identity transformation (no motion compensation).
|
|
129
|
+
|
|
130
|
+
Returns:
|
|
131
|
+
The annotated image.
|
|
132
|
+
|
|
133
|
+
Raises:
|
|
134
|
+
ValueError: If detections don't have tracker_id field.
|
|
135
|
+
"""
|
|
136
|
+
if detections.tracker_id is None:
|
|
137
|
+
raise ValueError(
|
|
138
|
+
"The `tracker_id` field is missing in the provided detections. "
|
|
139
|
+
"See: https://supervision.roboflow.com/latest/how_to/track_objects"
|
|
140
|
+
)
|
|
141
|
+
|
|
142
|
+
if coord_transform is None:
|
|
143
|
+
coord_transform = IdentityTransformation()
|
|
144
|
+
|
|
145
|
+
anchor_points = self._get_anchor_points(detections)
|
|
146
|
+
|
|
147
|
+
if len(anchor_points) > 0:
|
|
148
|
+
world_points = coord_transform.rel_to_abs(anchor_points)
|
|
149
|
+
|
|
150
|
+
for tracker_id, world_point in zip(detections.tracker_id, world_points):
|
|
151
|
+
if tracker_id is None or tracker_id < 0:
|
|
152
|
+
continue
|
|
153
|
+
tracker_id = int(tracker_id)
|
|
154
|
+
trajectory = self._trajectories[tracker_id]
|
|
155
|
+
trajectory.append((float(world_point[0]), float(world_point[1])))
|
|
156
|
+
|
|
157
|
+
if len(trajectory) > self.trace_length:
|
|
158
|
+
self._trajectories[tracker_id] = trajectory[-self.trace_length :]
|
|
159
|
+
|
|
160
|
+
for detection_idx in range(len(detections)):
|
|
161
|
+
tracker_id = detections.tracker_id[detection_idx]
|
|
162
|
+
if tracker_id is None or tracker_id < 0:
|
|
163
|
+
continue
|
|
164
|
+
tracker_id = int(tracker_id)
|
|
165
|
+
|
|
166
|
+
trajectory = self._trajectories.get(tracker_id, [])
|
|
167
|
+
if len(trajectory) < 2:
|
|
168
|
+
continue
|
|
169
|
+
|
|
170
|
+
color = resolve_color(
|
|
171
|
+
color=self.color,
|
|
172
|
+
detections=detections,
|
|
173
|
+
detection_idx=detection_idx,
|
|
174
|
+
color_lookup=(self.color_lookup if custom_color_lookup is None else custom_color_lookup),
|
|
175
|
+
)
|
|
176
|
+
|
|
177
|
+
world_points = np.array(trajectory, dtype=np.float32)
|
|
178
|
+
frame_points = coord_transform.abs_to_rel(world_points)
|
|
179
|
+
|
|
180
|
+
# Filter out points outside the frame bounds
|
|
181
|
+
height, width = scene.shape[:2]
|
|
182
|
+
valid_mask = (
|
|
183
|
+
(frame_points[:, 0] >= 0)
|
|
184
|
+
& (frame_points[:, 0] < width)
|
|
185
|
+
& (frame_points[:, 1] >= 0)
|
|
186
|
+
& (frame_points[:, 1] < height)
|
|
187
|
+
& np.isfinite(frame_points[:, 0])
|
|
188
|
+
& np.isfinite(frame_points[:, 1])
|
|
189
|
+
)
|
|
190
|
+
|
|
191
|
+
if np.sum(valid_mask) < 2:
|
|
192
|
+
continue
|
|
193
|
+
|
|
194
|
+
points: np.ndarray = frame_points[valid_mask].astype(np.int32)
|
|
195
|
+
|
|
196
|
+
scene = cv2.polylines(
|
|
197
|
+
scene,
|
|
198
|
+
[points],
|
|
199
|
+
isClosed=False,
|
|
200
|
+
color=color.as_bgr(),
|
|
201
|
+
thickness=self.thickness,
|
|
202
|
+
)
|
|
203
|
+
|
|
204
|
+
return scene
|
|
205
|
+
|
|
206
|
+
def reset(self) -> None:
|
|
207
|
+
"""Clear all stored trajectories.
|
|
208
|
+
|
|
209
|
+
Call this when switching videos or when you want to reset trajectory history.
|
|
210
|
+
"""
|
|
211
|
+
self._trajectories.clear()
|
|
212
|
+
|
|
213
|
+
def clear_tracker(self, tracker_id: int) -> None:
|
|
214
|
+
"""Clear the trajectory for a specific tracker ID.
|
|
215
|
+
|
|
216
|
+
Args:
|
|
217
|
+
tracker_id: The tracker ID to clear.
|
|
218
|
+
"""
|
|
219
|
+
self._trajectories.pop(tracker_id, None)
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
# ------------------------------------------------------------------------
|
|
2
|
+
# Trackers
|
|
3
|
+
# Copyright (c) 2026 Roboflow. All Rights Reserved.
|
|
4
|
+
# Licensed under the Apache License, Version 2.0 [see LICENSE for details]
|
|
5
|
+
# ------------------------------------------------------------------------
|