ultralytics 8.1.29__py3-none-any.whl → 8.3.63__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.
- tests/__init__.py +22 -0
- tests/conftest.py +83 -0
- tests/test_cli.py +122 -0
- tests/test_cuda.py +155 -0
- tests/test_engine.py +131 -0
- tests/test_exports.py +216 -0
- tests/test_integrations.py +150 -0
- tests/test_python.py +615 -0
- tests/test_solutions.py +94 -0
- ultralytics/__init__.py +11 -8
- ultralytics/cfg/__init__.py +569 -131
- ultralytics/cfg/datasets/Argoverse.yaml +2 -1
- ultralytics/cfg/datasets/DOTAv1.5.yaml +3 -2
- ultralytics/cfg/datasets/DOTAv1.yaml +3 -2
- ultralytics/cfg/datasets/GlobalWheat2020.yaml +3 -2
- ultralytics/cfg/datasets/ImageNet.yaml +2 -1
- ultralytics/cfg/datasets/Objects365.yaml +5 -4
- ultralytics/cfg/datasets/SKU-110K.yaml +2 -1
- ultralytics/cfg/datasets/VOC.yaml +3 -2
- ultralytics/cfg/datasets/VisDrone.yaml +6 -5
- ultralytics/cfg/datasets/african-wildlife.yaml +25 -0
- ultralytics/cfg/datasets/brain-tumor.yaml +23 -0
- ultralytics/cfg/datasets/carparts-seg.yaml +3 -2
- ultralytics/cfg/datasets/coco-pose.yaml +7 -6
- ultralytics/cfg/datasets/coco.yaml +3 -2
- ultralytics/cfg/datasets/coco128-seg.yaml +4 -3
- ultralytics/cfg/datasets/coco128.yaml +4 -3
- ultralytics/cfg/datasets/coco8-pose.yaml +3 -2
- ultralytics/cfg/datasets/coco8-seg.yaml +3 -2
- ultralytics/cfg/datasets/coco8.yaml +3 -2
- ultralytics/cfg/datasets/crack-seg.yaml +3 -2
- ultralytics/cfg/datasets/dog-pose.yaml +24 -0
- ultralytics/cfg/datasets/dota8.yaml +3 -2
- ultralytics/cfg/datasets/hand-keypoints.yaml +26 -0
- ultralytics/cfg/datasets/lvis.yaml +1236 -0
- ultralytics/cfg/datasets/medical-pills.yaml +22 -0
- ultralytics/cfg/datasets/open-images-v7.yaml +2 -1
- ultralytics/cfg/datasets/package-seg.yaml +5 -4
- ultralytics/cfg/datasets/signature.yaml +21 -0
- ultralytics/cfg/datasets/tiger-pose.yaml +3 -2
- ultralytics/cfg/datasets/xView.yaml +2 -1
- ultralytics/cfg/default.yaml +14 -11
- ultralytics/cfg/models/11/yolo11-cls-resnet18.yaml +24 -0
- ultralytics/cfg/models/11/yolo11-cls.yaml +33 -0
- ultralytics/cfg/models/11/yolo11-obb.yaml +50 -0
- ultralytics/cfg/models/11/yolo11-pose.yaml +51 -0
- ultralytics/cfg/models/11/yolo11-seg.yaml +50 -0
- ultralytics/cfg/models/11/yolo11.yaml +50 -0
- ultralytics/cfg/models/rt-detr/rtdetr-l.yaml +5 -2
- ultralytics/cfg/models/rt-detr/rtdetr-resnet101.yaml +5 -2
- ultralytics/cfg/models/rt-detr/rtdetr-resnet50.yaml +5 -2
- ultralytics/cfg/models/rt-detr/rtdetr-x.yaml +5 -2
- ultralytics/cfg/models/v10/yolov10b.yaml +45 -0
- ultralytics/cfg/models/v10/yolov10l.yaml +45 -0
- ultralytics/cfg/models/v10/yolov10m.yaml +45 -0
- ultralytics/cfg/models/v10/yolov10n.yaml +45 -0
- ultralytics/cfg/models/v10/yolov10s.yaml +45 -0
- ultralytics/cfg/models/v10/yolov10x.yaml +45 -0
- ultralytics/cfg/models/v3/yolov3-spp.yaml +5 -2
- ultralytics/cfg/models/v3/yolov3-tiny.yaml +5 -2
- ultralytics/cfg/models/v3/yolov3.yaml +5 -2
- ultralytics/cfg/models/v5/yolov5-p6.yaml +5 -2
- ultralytics/cfg/models/v5/yolov5.yaml +5 -2
- ultralytics/cfg/models/v6/yolov6.yaml +5 -2
- ultralytics/cfg/models/v8/yolov8-cls-resnet101.yaml +5 -2
- ultralytics/cfg/models/v8/yolov8-cls-resnet50.yaml +5 -2
- ultralytics/cfg/models/v8/yolov8-cls.yaml +5 -2
- ultralytics/cfg/models/v8/yolov8-ghost-p2.yaml +6 -2
- ultralytics/cfg/models/v8/yolov8-ghost-p6.yaml +6 -2
- ultralytics/cfg/models/v8/yolov8-ghost.yaml +5 -2
- ultralytics/cfg/models/v8/yolov8-obb.yaml +5 -2
- ultralytics/cfg/models/v8/yolov8-p2.yaml +5 -2
- ultralytics/cfg/models/v8/yolov8-p6.yaml +10 -7
- ultralytics/cfg/models/v8/yolov8-pose-p6.yaml +5 -2
- ultralytics/cfg/models/v8/yolov8-pose.yaml +5 -2
- ultralytics/cfg/models/v8/yolov8-rtdetr.yaml +5 -2
- ultralytics/cfg/models/v8/yolov8-seg-p6.yaml +5 -2
- ultralytics/cfg/models/v8/yolov8-seg.yaml +5 -2
- ultralytics/cfg/models/v8/yolov8-world.yaml +5 -2
- ultralytics/cfg/models/v8/yolov8-worldv2.yaml +5 -2
- ultralytics/cfg/models/v8/yolov8.yaml +5 -2
- ultralytics/cfg/models/v9/yolov9c-seg.yaml +41 -0
- ultralytics/cfg/models/v9/yolov9c.yaml +30 -25
- ultralytics/cfg/models/v9/yolov9e-seg.yaml +64 -0
- ultralytics/cfg/models/v9/yolov9e.yaml +46 -42
- ultralytics/cfg/models/v9/yolov9m.yaml +41 -0
- ultralytics/cfg/models/v9/yolov9s.yaml +41 -0
- ultralytics/cfg/models/v9/yolov9t.yaml +41 -0
- ultralytics/cfg/solutions/default.yaml +24 -0
- ultralytics/cfg/trackers/botsort.yaml +8 -5
- ultralytics/cfg/trackers/bytetrack.yaml +8 -5
- ultralytics/data/__init__.py +14 -3
- ultralytics/data/annotator.py +37 -15
- ultralytics/data/augment.py +1783 -289
- ultralytics/data/base.py +62 -27
- ultralytics/data/build.py +37 -8
- ultralytics/data/converter.py +196 -36
- ultralytics/data/dataset.py +233 -94
- ultralytics/data/loaders.py +199 -96
- ultralytics/data/split_dota.py +39 -29
- ultralytics/data/utils.py +111 -41
- ultralytics/engine/__init__.py +1 -1
- ultralytics/engine/exporter.py +579 -244
- ultralytics/engine/model.py +604 -252
- ultralytics/engine/predictor.py +22 -11
- ultralytics/engine/results.py +1228 -218
- ultralytics/engine/trainer.py +191 -129
- ultralytics/engine/tuner.py +18 -18
- ultralytics/engine/validator.py +18 -15
- ultralytics/hub/__init__.py +31 -13
- ultralytics/hub/auth.py +11 -7
- ultralytics/hub/google/__init__.py +159 -0
- ultralytics/hub/session.py +128 -94
- ultralytics/hub/utils.py +20 -21
- ultralytics/models/__init__.py +4 -2
- ultralytics/models/fastsam/__init__.py +2 -3
- ultralytics/models/fastsam/model.py +26 -4
- ultralytics/models/fastsam/predict.py +127 -63
- ultralytics/models/fastsam/utils.py +1 -44
- ultralytics/models/fastsam/val.py +1 -1
- ultralytics/models/nas/__init__.py +1 -1
- ultralytics/models/nas/model.py +21 -10
- ultralytics/models/nas/predict.py +3 -6
- ultralytics/models/nas/val.py +4 -4
- ultralytics/models/rtdetr/__init__.py +1 -1
- ultralytics/models/rtdetr/model.py +1 -1
- ultralytics/models/rtdetr/predict.py +6 -8
- ultralytics/models/rtdetr/train.py +6 -2
- ultralytics/models/rtdetr/val.py +3 -3
- ultralytics/models/sam/__init__.py +3 -3
- ultralytics/models/sam/amg.py +29 -23
- ultralytics/models/sam/build.py +211 -13
- ultralytics/models/sam/model.py +91 -30
- ultralytics/models/sam/modules/__init__.py +1 -1
- ultralytics/models/sam/modules/blocks.py +1129 -0
- ultralytics/models/sam/modules/decoders.py +381 -53
- ultralytics/models/sam/modules/encoders.py +515 -324
- ultralytics/models/sam/modules/memory_attention.py +237 -0
- ultralytics/models/sam/modules/sam.py +969 -21
- ultralytics/models/sam/modules/tiny_encoder.py +425 -154
- ultralytics/models/sam/modules/transformer.py +159 -60
- ultralytics/models/sam/modules/utils.py +293 -0
- ultralytics/models/sam/predict.py +1263 -132
- ultralytics/models/utils/__init__.py +1 -1
- ultralytics/models/utils/loss.py +36 -24
- ultralytics/models/utils/ops.py +3 -7
- ultralytics/models/yolo/__init__.py +3 -3
- ultralytics/models/yolo/classify/__init__.py +1 -1
- ultralytics/models/yolo/classify/predict.py +7 -8
- ultralytics/models/yolo/classify/train.py +17 -22
- ultralytics/models/yolo/classify/val.py +8 -4
- ultralytics/models/yolo/detect/__init__.py +1 -1
- ultralytics/models/yolo/detect/predict.py +3 -5
- ultralytics/models/yolo/detect/train.py +11 -4
- ultralytics/models/yolo/detect/val.py +90 -52
- ultralytics/models/yolo/model.py +14 -9
- ultralytics/models/yolo/obb/__init__.py +1 -1
- ultralytics/models/yolo/obb/predict.py +2 -2
- ultralytics/models/yolo/obb/train.py +5 -3
- ultralytics/models/yolo/obb/val.py +41 -23
- ultralytics/models/yolo/pose/__init__.py +1 -1
- ultralytics/models/yolo/pose/predict.py +3 -5
- ultralytics/models/yolo/pose/train.py +2 -2
- ultralytics/models/yolo/pose/val.py +51 -17
- ultralytics/models/yolo/segment/__init__.py +1 -1
- ultralytics/models/yolo/segment/predict.py +3 -5
- ultralytics/models/yolo/segment/train.py +2 -2
- ultralytics/models/yolo/segment/val.py +60 -19
- ultralytics/models/yolo/world/__init__.py +5 -0
- ultralytics/models/yolo/world/train.py +92 -0
- ultralytics/models/yolo/world/train_world.py +109 -0
- ultralytics/nn/__init__.py +1 -1
- ultralytics/nn/autobackend.py +228 -93
- ultralytics/nn/modules/__init__.py +39 -14
- ultralytics/nn/modules/activation.py +21 -0
- ultralytics/nn/modules/block.py +526 -66
- ultralytics/nn/modules/conv.py +24 -7
- ultralytics/nn/modules/head.py +177 -34
- ultralytics/nn/modules/transformer.py +6 -5
- ultralytics/nn/modules/utils.py +1 -2
- ultralytics/nn/tasks.py +226 -82
- ultralytics/solutions/__init__.py +30 -1
- ultralytics/solutions/ai_gym.py +96 -143
- ultralytics/solutions/analytics.py +247 -0
- ultralytics/solutions/distance_calculation.py +78 -135
- ultralytics/solutions/heatmap.py +93 -247
- ultralytics/solutions/object_counter.py +184 -259
- ultralytics/solutions/parking_management.py +246 -0
- ultralytics/solutions/queue_management.py +112 -0
- ultralytics/solutions/region_counter.py +116 -0
- ultralytics/solutions/security_alarm.py +144 -0
- ultralytics/solutions/solutions.py +178 -0
- ultralytics/solutions/speed_estimation.py +86 -174
- ultralytics/solutions/streamlit_inference.py +190 -0
- ultralytics/solutions/trackzone.py +68 -0
- ultralytics/trackers/__init__.py +1 -1
- ultralytics/trackers/basetrack.py +32 -13
- ultralytics/trackers/bot_sort.py +61 -28
- ultralytics/trackers/byte_tracker.py +83 -51
- ultralytics/trackers/track.py +21 -6
- ultralytics/trackers/utils/__init__.py +1 -1
- ultralytics/trackers/utils/gmc.py +62 -48
- ultralytics/trackers/utils/kalman_filter.py +166 -35
- ultralytics/trackers/utils/matching.py +40 -21
- ultralytics/utils/__init__.py +511 -239
- ultralytics/utils/autobatch.py +40 -22
- ultralytics/utils/benchmarks.py +266 -85
- ultralytics/utils/callbacks/__init__.py +1 -1
- ultralytics/utils/callbacks/base.py +1 -3
- ultralytics/utils/callbacks/clearml.py +7 -6
- ultralytics/utils/callbacks/comet.py +39 -17
- ultralytics/utils/callbacks/dvc.py +1 -1
- ultralytics/utils/callbacks/hub.py +16 -16
- ultralytics/utils/callbacks/mlflow.py +28 -24
- ultralytics/utils/callbacks/neptune.py +6 -2
- ultralytics/utils/callbacks/raytune.py +3 -4
- ultralytics/utils/callbacks/tensorboard.py +18 -18
- ultralytics/utils/callbacks/wb.py +27 -20
- ultralytics/utils/checks.py +172 -100
- ultralytics/utils/dist.py +2 -1
- ultralytics/utils/downloads.py +40 -34
- ultralytics/utils/errors.py +1 -1
- ultralytics/utils/files.py +72 -38
- ultralytics/utils/instance.py +41 -19
- ultralytics/utils/loss.py +83 -55
- ultralytics/utils/metrics.py +61 -56
- ultralytics/utils/ops.py +94 -89
- ultralytics/utils/patches.py +30 -14
- ultralytics/utils/plotting.py +600 -269
- ultralytics/utils/tal.py +67 -26
- ultralytics/utils/torch_utils.py +305 -112
- ultralytics/utils/triton.py +2 -1
- ultralytics/utils/tuner.py +21 -12
- ultralytics-8.3.63.dist-info/METADATA +370 -0
- ultralytics-8.3.63.dist-info/RECORD +241 -0
- {ultralytics-8.1.29.dist-info → ultralytics-8.3.63.dist-info}/WHEEL +1 -1
- ultralytics/data/explorer/__init__.py +0 -5
- ultralytics/data/explorer/explorer.py +0 -472
- ultralytics/data/explorer/gui/__init__.py +0 -1
- ultralytics/data/explorer/gui/dash.py +0 -268
- ultralytics/data/explorer/utils.py +0 -166
- ultralytics/models/fastsam/prompt.py +0 -357
- ultralytics-8.1.29.dist-info/METADATA +0 -373
- ultralytics-8.1.29.dist-info/RECORD +0 -197
- {ultralytics-8.1.29.dist-info → ultralytics-8.3.63.dist-info}/LICENSE +0 -0
- {ultralytics-8.1.29.dist-info → ultralytics-8.3.63.dist-info}/entry_points.txt +0 -0
- {ultralytics-8.1.29.dist-info → ultralytics-8.3.63.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,68 @@
|
|
1
|
+
# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license
|
2
|
+
|
3
|
+
import cv2
|
4
|
+
import numpy as np
|
5
|
+
|
6
|
+
from ultralytics.solutions.solutions import BaseSolution
|
7
|
+
from ultralytics.utils.plotting import Annotator, colors
|
8
|
+
|
9
|
+
|
10
|
+
class TrackZone(BaseSolution):
|
11
|
+
"""
|
12
|
+
A class to manage region-based object tracking in a video stream.
|
13
|
+
|
14
|
+
This class extends the BaseSolution class and provides functionality for tracking objects within a specific region
|
15
|
+
defined by a polygonal area. Objects outside the region are excluded from tracking. It supports dynamic initialization
|
16
|
+
of the region, allowing either a default region or a user-specified polygon.
|
17
|
+
|
18
|
+
Attributes:
|
19
|
+
region (ndarray): The polygonal region for tracking, represented as a convex hull.
|
20
|
+
|
21
|
+
Methods:
|
22
|
+
trackzone: Processes each frame of the video, applying region-based tracking.
|
23
|
+
|
24
|
+
Examples:
|
25
|
+
>>> tracker = TrackZone()
|
26
|
+
>>> frame = cv2.imread("frame.jpg")
|
27
|
+
>>> processed_frame = tracker.trackzone(frame)
|
28
|
+
>>> cv2.imshow("Tracked Frame", processed_frame)
|
29
|
+
"""
|
30
|
+
|
31
|
+
def __init__(self, **kwargs):
|
32
|
+
"""Initializes the TrackZone class for tracking objects within a defined region in video streams."""
|
33
|
+
super().__init__(**kwargs)
|
34
|
+
default_region = [(150, 150), (1130, 150), (1130, 570), (150, 570)]
|
35
|
+
self.region = cv2.convexHull(np.array(self.region or default_region, dtype=np.int32))
|
36
|
+
|
37
|
+
def trackzone(self, im0):
|
38
|
+
"""
|
39
|
+
Processes the input frame to track objects within a defined region.
|
40
|
+
|
41
|
+
This method initializes the annotator, creates a mask for the specified region, extracts tracks
|
42
|
+
only from the masked area, and updates tracking information. Objects outside the region are ignored.
|
43
|
+
|
44
|
+
Args:
|
45
|
+
im0 (numpy.ndarray): The input image or frame to be processed.
|
46
|
+
|
47
|
+
Returns:
|
48
|
+
(numpy.ndarray): The processed image with tracking id and bounding boxes annotations.
|
49
|
+
|
50
|
+
Examples:
|
51
|
+
>>> tracker = TrackZone()
|
52
|
+
>>> frame = cv2.imread("path/to/image.jpg")
|
53
|
+
>>> tracker.trackzone(frame)
|
54
|
+
"""
|
55
|
+
self.annotator = Annotator(im0, line_width=self.line_width) # Initialize annotator
|
56
|
+
# Create a mask for the region and extract tracks from the masked image
|
57
|
+
masked_frame = cv2.bitwise_and(im0, im0, mask=cv2.fillPoly(np.zeros_like(im0[:, :, 0]), [self.region], 255))
|
58
|
+
self.extract_tracks(masked_frame)
|
59
|
+
|
60
|
+
cv2.polylines(im0, [self.region], isClosed=True, color=(255, 255, 255), thickness=self.line_width * 2)
|
61
|
+
|
62
|
+
# Iterate over boxes, track ids, classes indexes list and draw bounding boxes
|
63
|
+
for box, track_id, cls in zip(self.boxes, self.track_ids, self.clss):
|
64
|
+
self.annotator.box_label(box, label=f"{self.names[cls]}:{track_id}", color=colors(track_id, True))
|
65
|
+
|
66
|
+
self.display_output(im0) # display output with base class function
|
67
|
+
|
68
|
+
return im0 # return output image for more usage
|
ultralytics/trackers/__init__.py
CHANGED
@@ -1,5 +1,5 @@
|
|
1
|
-
# Ultralytics
|
2
|
-
"""
|
1
|
+
# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license
|
2
|
+
"""Module defines the base classes and structures for object tracking in YOLO."""
|
3
3
|
|
4
4
|
from collections import OrderedDict
|
5
5
|
|
@@ -15,6 +15,11 @@ class TrackState:
|
|
15
15
|
Tracked (int): State when the object is successfully tracked in subsequent frames.
|
16
16
|
Lost (int): State when the object is no longer tracked.
|
17
17
|
Removed (int): State when the object is removed from tracking.
|
18
|
+
|
19
|
+
Examples:
|
20
|
+
>>> state = TrackState.New
|
21
|
+
>>> if state == TrackState.New:
|
22
|
+
>>> print("Object is newly detected.")
|
18
23
|
"""
|
19
24
|
|
20
25
|
New = 0
|
@@ -33,8 +38,8 @@ class BaseTrack:
|
|
33
38
|
is_activated (bool): Flag indicating whether the track is currently active.
|
34
39
|
state (TrackState): Current state of the track.
|
35
40
|
history (OrderedDict): Ordered history of the track's states.
|
36
|
-
features (
|
37
|
-
curr_feature (
|
41
|
+
features (List): List of features extracted from the object for tracking.
|
42
|
+
curr_feature (Any): The current feature of the object being tracked.
|
38
43
|
score (float): The confidence score of the tracking.
|
39
44
|
start_frame (int): The frame number where tracking started.
|
40
45
|
frame_id (int): The most recent frame ID processed by the track.
|
@@ -50,12 +55,26 @@ class BaseTrack:
|
|
50
55
|
mark_lost: Marks the track as lost.
|
51
56
|
mark_removed: Marks the track as removed.
|
52
57
|
reset_id: Resets the global track ID counter.
|
58
|
+
|
59
|
+
Examples:
|
60
|
+
Initialize a new track and mark it as lost:
|
61
|
+
>>> track = BaseTrack()
|
62
|
+
>>> track.mark_lost()
|
63
|
+
>>> print(track.state) # Output: 2 (TrackState.Lost)
|
53
64
|
"""
|
54
65
|
|
55
66
|
_count = 0
|
56
67
|
|
57
68
|
def __init__(self):
|
58
|
-
"""
|
69
|
+
"""
|
70
|
+
Initializes a new track with a unique ID and foundational tracking attributes.
|
71
|
+
|
72
|
+
Examples:
|
73
|
+
Initialize a new track
|
74
|
+
>>> track = BaseTrack()
|
75
|
+
>>> print(track.track_id)
|
76
|
+
0
|
77
|
+
"""
|
59
78
|
self.track_id = 0
|
60
79
|
self.is_activated = False
|
61
80
|
self.state = TrackState.New
|
@@ -70,36 +89,36 @@ class BaseTrack:
|
|
70
89
|
|
71
90
|
@property
|
72
91
|
def end_frame(self):
|
73
|
-
"""
|
92
|
+
"""Returns the ID of the most recent frame where the object was tracked."""
|
74
93
|
return self.frame_id
|
75
94
|
|
76
95
|
@staticmethod
|
77
96
|
def next_id():
|
78
|
-
"""Increment and return the global track ID
|
97
|
+
"""Increment and return the next unique global track ID for object tracking."""
|
79
98
|
BaseTrack._count += 1
|
80
99
|
return BaseTrack._count
|
81
100
|
|
82
101
|
def activate(self, *args):
|
83
|
-
"""
|
102
|
+
"""Activates the track with provided arguments, initializing necessary attributes for tracking."""
|
84
103
|
raise NotImplementedError
|
85
104
|
|
86
105
|
def predict(self):
|
87
|
-
"""
|
106
|
+
"""Predicts the next state of the track based on the current state and tracking model."""
|
88
107
|
raise NotImplementedError
|
89
108
|
|
90
109
|
def update(self, *args, **kwargs):
|
91
|
-
"""
|
110
|
+
"""Updates the track with new observations and data, modifying its state and attributes accordingly."""
|
92
111
|
raise NotImplementedError
|
93
112
|
|
94
113
|
def mark_lost(self):
|
95
|
-
"""
|
114
|
+
"""Marks the track as lost by updating its state to TrackState.Lost."""
|
96
115
|
self.state = TrackState.Lost
|
97
116
|
|
98
117
|
def mark_removed(self):
|
99
|
-
"""
|
118
|
+
"""Marks the track as removed by setting its state to TrackState.Removed."""
|
100
119
|
self.state = TrackState.Removed
|
101
120
|
|
102
121
|
@staticmethod
|
103
122
|
def reset_id():
|
104
|
-
"""Reset the global track ID counter."""
|
123
|
+
"""Reset the global track ID counter to its initial value."""
|
105
124
|
BaseTrack._count = 0
|
ultralytics/trackers/bot_sort.py
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# Ultralytics
|
1
|
+
# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license
|
2
2
|
|
3
3
|
from collections import deque
|
4
4
|
|
@@ -15,6 +15,9 @@ class BOTrack(STrack):
|
|
15
15
|
"""
|
16
16
|
An extended version of the STrack class for YOLOv8, adding object tracking features.
|
17
17
|
|
18
|
+
This class extends the STrack class to include additional functionalities for object tracking, such as feature
|
19
|
+
smoothing, Kalman filter prediction, and reactivation of tracks.
|
20
|
+
|
18
21
|
Attributes:
|
19
22
|
shared_kalman (KalmanFilterXYWH): A shared Kalman filter for all instances of BOTrack.
|
20
23
|
smooth_feat (np.ndarray): Smoothed feature vector.
|
@@ -34,16 +37,35 @@ class BOTrack(STrack):
|
|
34
37
|
convert_coords(tlwh): Converts tlwh bounding box coordinates to xywh format.
|
35
38
|
tlwh_to_xywh(tlwh): Convert bounding box to xywh format `(center x, center y, width, height)`.
|
36
39
|
|
37
|
-
|
38
|
-
|
39
|
-
bo_track.
|
40
|
-
bo_track.
|
40
|
+
Examples:
|
41
|
+
Create a BOTrack instance and update its features
|
42
|
+
>>> bo_track = BOTrack(tlwh=[100, 50, 80, 40], score=0.9, cls=1, feat=np.random.rand(128))
|
43
|
+
>>> bo_track.predict()
|
44
|
+
>>> new_track = BOTrack(tlwh=[110, 60, 80, 40], score=0.85, cls=1, feat=np.random.rand(128))
|
45
|
+
>>> bo_track.update(new_track, frame_id=2)
|
41
46
|
"""
|
42
47
|
|
43
48
|
shared_kalman = KalmanFilterXYWH()
|
44
49
|
|
45
50
|
def __init__(self, tlwh, score, cls, feat=None, feat_history=50):
|
46
|
-
"""
|
51
|
+
"""
|
52
|
+
Initialize a BOTrack object with temporal parameters, such as feature history, alpha, and current features.
|
53
|
+
|
54
|
+
Args:
|
55
|
+
tlwh (np.ndarray): Bounding box coordinates in tlwh format (top left x, top left y, width, height).
|
56
|
+
score (float): Confidence score of the detection.
|
57
|
+
cls (int): Class ID of the detected object.
|
58
|
+
feat (np.ndarray | None): Feature vector associated with the detection.
|
59
|
+
feat_history (int): Maximum length of the feature history deque.
|
60
|
+
|
61
|
+
Examples:
|
62
|
+
Initialize a BOTrack object with bounding box, score, class ID, and feature vector
|
63
|
+
>>> tlwh = np.array([100, 50, 80, 120])
|
64
|
+
>>> score = 0.9
|
65
|
+
>>> cls = 1
|
66
|
+
>>> feat = np.random.rand(128)
|
67
|
+
>>> bo_track = BOTrack(tlwh, score, cls, feat)
|
68
|
+
"""
|
47
69
|
super().__init__(tlwh, score, cls)
|
48
70
|
|
49
71
|
self.smooth_feat = None
|
@@ -54,7 +76,7 @@ class BOTrack(STrack):
|
|
54
76
|
self.alpha = 0.9
|
55
77
|
|
56
78
|
def update_features(self, feat):
|
57
|
-
"""Update
|
79
|
+
"""Update the feature vector and apply exponential moving average smoothing."""
|
58
80
|
feat /= np.linalg.norm(feat)
|
59
81
|
self.curr_feat = feat
|
60
82
|
if self.smooth_feat is None:
|
@@ -65,7 +87,7 @@ class BOTrack(STrack):
|
|
65
87
|
self.smooth_feat /= np.linalg.norm(self.smooth_feat)
|
66
88
|
|
67
89
|
def predict(self):
|
68
|
-
"""Predicts the
|
90
|
+
"""Predicts the object's future state using the Kalman filter to update its mean and covariance."""
|
69
91
|
mean_state = self.mean.copy()
|
70
92
|
if self.state != TrackState.Tracked:
|
71
93
|
mean_state[6] = 0
|
@@ -80,14 +102,14 @@ class BOTrack(STrack):
|
|
80
102
|
super().re_activate(new_track, frame_id, new_id)
|
81
103
|
|
82
104
|
def update(self, new_track, frame_id):
|
83
|
-
"""
|
105
|
+
"""Updates the YOLOv8 instance with new track information and the current frame ID."""
|
84
106
|
if new_track.curr_feat is not None:
|
85
107
|
self.update_features(new_track.curr_feat)
|
86
108
|
super().update(new_track, frame_id)
|
87
109
|
|
88
110
|
@property
|
89
111
|
def tlwh(self):
|
90
|
-
"""
|
112
|
+
"""Returns the current bounding box position in `(top left x, top left y, width, height)` format."""
|
91
113
|
if self.mean is None:
|
92
114
|
return self._tlwh.copy()
|
93
115
|
ret = self.mean[:4].copy()
|
@@ -96,7 +118,7 @@ class BOTrack(STrack):
|
|
96
118
|
|
97
119
|
@staticmethod
|
98
120
|
def multi_predict(stracks):
|
99
|
-
"""Predicts the mean and covariance
|
121
|
+
"""Predicts the mean and covariance for multiple object tracks using a shared Kalman filter."""
|
100
122
|
if len(stracks) <= 0:
|
101
123
|
return
|
102
124
|
multi_mean = np.asarray([st.mean.copy() for st in stracks])
|
@@ -111,12 +133,12 @@ class BOTrack(STrack):
|
|
111
133
|
stracks[i].covariance = cov
|
112
134
|
|
113
135
|
def convert_coords(self, tlwh):
|
114
|
-
"""Converts
|
136
|
+
"""Converts tlwh bounding box coordinates to xywh format."""
|
115
137
|
return self.tlwh_to_xywh(tlwh)
|
116
138
|
|
117
139
|
@staticmethod
|
118
140
|
def tlwh_to_xywh(tlwh):
|
119
|
-
"""Convert bounding box to
|
141
|
+
"""Convert bounding box from tlwh (top-left-width-height) to xywh (center-x-center-y-width-height) format."""
|
120
142
|
ret = np.asarray(tlwh).copy()
|
121
143
|
ret[:2] += ret[2:] / 2
|
122
144
|
return ret
|
@@ -129,9 +151,9 @@ class BOTSORT(BYTETracker):
|
|
129
151
|
Attributes:
|
130
152
|
proximity_thresh (float): Threshold for spatial proximity (IoU) between tracks and detections.
|
131
153
|
appearance_thresh (float): Threshold for appearance similarity (ReID embeddings) between tracks and detections.
|
132
|
-
encoder (
|
154
|
+
encoder (Any): Object to handle ReID embeddings, set to None if ReID is not enabled.
|
133
155
|
gmc (GMC): An instance of the GMC algorithm for data association.
|
134
|
-
args (
|
156
|
+
args (Any): Parsed command-line arguments containing tracking parameters.
|
135
157
|
|
136
158
|
Methods:
|
137
159
|
get_kalmanfilter(): Returns an instance of KalmanFilterXYWH for object tracking.
|
@@ -139,17 +161,29 @@ class BOTSORT(BYTETracker):
|
|
139
161
|
get_dists(tracks, detections): Get distances between tracks and detections using IoU and (optionally) ReID.
|
140
162
|
multi_predict(tracks): Predict and track multiple objects with YOLOv8 model.
|
141
163
|
|
142
|
-
|
143
|
-
|
144
|
-
bot_sort
|
145
|
-
bot_sort.
|
164
|
+
Examples:
|
165
|
+
Initialize BOTSORT and process detections
|
166
|
+
>>> bot_sort = BOTSORT(args, frame_rate=30)
|
167
|
+
>>> bot_sort.init_track(dets, scores, cls, img)
|
168
|
+
>>> bot_sort.multi_predict(tracks)
|
146
169
|
|
147
170
|
Note:
|
148
171
|
The class is designed to work with the YOLOv8 object detection model and supports ReID only if enabled via args.
|
149
172
|
"""
|
150
173
|
|
151
174
|
def __init__(self, args, frame_rate=30):
|
152
|
-
"""
|
175
|
+
"""
|
176
|
+
Initialize YOLOv8 object with ReID module and GMC algorithm.
|
177
|
+
|
178
|
+
Args:
|
179
|
+
args (object): Parsed command-line arguments containing tracking parameters.
|
180
|
+
frame_rate (int): Frame rate of the video being processed.
|
181
|
+
|
182
|
+
Examples:
|
183
|
+
Initialize BOTSORT with command-line arguments and a specified frame rate:
|
184
|
+
>>> args = parse_args()
|
185
|
+
>>> bot_sort = BOTSORT(args, frame_rate=30)
|
186
|
+
"""
|
153
187
|
super().__init__(args, frame_rate)
|
154
188
|
# ReID module
|
155
189
|
self.proximity_thresh = args.proximity_thresh
|
@@ -161,11 +195,11 @@ class BOTSORT(BYTETracker):
|
|
161
195
|
self.gmc = GMC(method=args.gmc_method)
|
162
196
|
|
163
197
|
def get_kalmanfilter(self):
|
164
|
-
"""Returns an instance of KalmanFilterXYWH for object tracking."""
|
198
|
+
"""Returns an instance of KalmanFilterXYWH for predicting and updating object states in the tracking process."""
|
165
199
|
return KalmanFilterXYWH()
|
166
200
|
|
167
201
|
def init_track(self, dets, scores, cls, img=None):
|
168
|
-
"""Initialize
|
202
|
+
"""Initialize object tracks using detection bounding boxes, scores, class labels, and optional ReID features."""
|
169
203
|
if len(dets) == 0:
|
170
204
|
return []
|
171
205
|
if self.args.with_reid and self.encoder is not None:
|
@@ -175,13 +209,12 @@ class BOTSORT(BYTETracker):
|
|
175
209
|
return [BOTrack(xyxy, s, c) for (xyxy, s, c) in zip(dets, scores, cls)] # detections
|
176
210
|
|
177
211
|
def get_dists(self, tracks, detections):
|
178
|
-
"""
|
212
|
+
"""Calculates distances between tracks and detections using IoU and optionally ReID embeddings."""
|
179
213
|
dists = matching.iou_distance(tracks, detections)
|
180
214
|
dists_mask = dists > self.proximity_thresh
|
181
215
|
|
182
|
-
|
183
|
-
|
184
|
-
dists = matching.fuse_score(dists, detections)
|
216
|
+
if self.args.fuse_score:
|
217
|
+
dists = matching.fuse_score(dists, detections)
|
185
218
|
|
186
219
|
if self.args.with_reid and self.encoder is not None:
|
187
220
|
emb_dists = matching.embedding_distance(tracks, detections) / 2.0
|
@@ -191,10 +224,10 @@ class BOTSORT(BYTETracker):
|
|
191
224
|
return dists
|
192
225
|
|
193
226
|
def multi_predict(self, tracks):
|
194
|
-
"""
|
227
|
+
"""Predicts the mean and covariance of multiple object tracks using a shared Kalman filter."""
|
195
228
|
BOTrack.multi_predict(tracks)
|
196
229
|
|
197
230
|
def reset(self):
|
198
|
-
"""
|
231
|
+
"""Resets the BOTSORT tracker to its initial state, clearing all tracked objects and internal states."""
|
199
232
|
super().reset()
|
200
233
|
self.gmc.reset_params()
|