dgenerate-ultralytics-headless 8.3.253__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.
- dgenerate_ultralytics_headless-8.3.253.dist-info/METADATA +405 -0
- dgenerate_ultralytics_headless-8.3.253.dist-info/RECORD +299 -0
- dgenerate_ultralytics_headless-8.3.253.dist-info/WHEEL +5 -0
- dgenerate_ultralytics_headless-8.3.253.dist-info/entry_points.txt +3 -0
- dgenerate_ultralytics_headless-8.3.253.dist-info/licenses/LICENSE +661 -0
- dgenerate_ultralytics_headless-8.3.253.dist-info/top_level.txt +1 -0
- tests/__init__.py +23 -0
- tests/conftest.py +59 -0
- tests/test_cli.py +131 -0
- tests/test_cuda.py +216 -0
- tests/test_engine.py +157 -0
- tests/test_exports.py +309 -0
- tests/test_integrations.py +151 -0
- tests/test_python.py +777 -0
- tests/test_solutions.py +371 -0
- ultralytics/__init__.py +48 -0
- ultralytics/assets/bus.jpg +0 -0
- ultralytics/assets/zidane.jpg +0 -0
- ultralytics/cfg/__init__.py +1028 -0
- ultralytics/cfg/datasets/Argoverse.yaml +78 -0
- ultralytics/cfg/datasets/DOTAv1.5.yaml +37 -0
- ultralytics/cfg/datasets/DOTAv1.yaml +36 -0
- ultralytics/cfg/datasets/GlobalWheat2020.yaml +68 -0
- ultralytics/cfg/datasets/HomeObjects-3K.yaml +32 -0
- ultralytics/cfg/datasets/ImageNet.yaml +2025 -0
- ultralytics/cfg/datasets/Objects365.yaml +447 -0
- ultralytics/cfg/datasets/SKU-110K.yaml +58 -0
- ultralytics/cfg/datasets/TT100K.yaml +346 -0
- ultralytics/cfg/datasets/VOC.yaml +102 -0
- ultralytics/cfg/datasets/VisDrone.yaml +87 -0
- ultralytics/cfg/datasets/african-wildlife.yaml +25 -0
- ultralytics/cfg/datasets/brain-tumor.yaml +22 -0
- ultralytics/cfg/datasets/carparts-seg.yaml +44 -0
- ultralytics/cfg/datasets/coco-pose.yaml +64 -0
- ultralytics/cfg/datasets/coco.yaml +118 -0
- ultralytics/cfg/datasets/coco128-seg.yaml +101 -0
- ultralytics/cfg/datasets/coco128.yaml +101 -0
- ultralytics/cfg/datasets/coco8-grayscale.yaml +103 -0
- ultralytics/cfg/datasets/coco8-multispectral.yaml +104 -0
- ultralytics/cfg/datasets/coco8-pose.yaml +47 -0
- ultralytics/cfg/datasets/coco8-seg.yaml +101 -0
- ultralytics/cfg/datasets/coco8.yaml +101 -0
- ultralytics/cfg/datasets/construction-ppe.yaml +32 -0
- ultralytics/cfg/datasets/crack-seg.yaml +22 -0
- ultralytics/cfg/datasets/dog-pose.yaml +52 -0
- ultralytics/cfg/datasets/dota8-multispectral.yaml +38 -0
- ultralytics/cfg/datasets/dota8.yaml +35 -0
- ultralytics/cfg/datasets/hand-keypoints.yaml +50 -0
- ultralytics/cfg/datasets/kitti.yaml +27 -0
- ultralytics/cfg/datasets/lvis.yaml +1240 -0
- ultralytics/cfg/datasets/medical-pills.yaml +21 -0
- ultralytics/cfg/datasets/open-images-v7.yaml +663 -0
- ultralytics/cfg/datasets/package-seg.yaml +22 -0
- ultralytics/cfg/datasets/signature.yaml +21 -0
- ultralytics/cfg/datasets/tiger-pose.yaml +41 -0
- ultralytics/cfg/datasets/xView.yaml +155 -0
- ultralytics/cfg/default.yaml +130 -0
- ultralytics/cfg/models/11/yolo11-cls-resnet18.yaml +17 -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/11/yoloe-11-seg.yaml +48 -0
- ultralytics/cfg/models/11/yoloe-11.yaml +48 -0
- ultralytics/cfg/models/12/yolo12-cls.yaml +32 -0
- ultralytics/cfg/models/12/yolo12-obb.yaml +48 -0
- ultralytics/cfg/models/12/yolo12-pose.yaml +49 -0
- ultralytics/cfg/models/12/yolo12-seg.yaml +48 -0
- ultralytics/cfg/models/12/yolo12.yaml +48 -0
- ultralytics/cfg/models/rt-detr/rtdetr-l.yaml +53 -0
- ultralytics/cfg/models/rt-detr/rtdetr-resnet101.yaml +45 -0
- ultralytics/cfg/models/rt-detr/rtdetr-resnet50.yaml +45 -0
- ultralytics/cfg/models/rt-detr/rtdetr-x.yaml +57 -0
- 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 +49 -0
- ultralytics/cfg/models/v3/yolov3-tiny.yaml +40 -0
- ultralytics/cfg/models/v3/yolov3.yaml +49 -0
- ultralytics/cfg/models/v5/yolov5-p6.yaml +62 -0
- ultralytics/cfg/models/v5/yolov5.yaml +51 -0
- ultralytics/cfg/models/v6/yolov6.yaml +56 -0
- ultralytics/cfg/models/v8/yoloe-v8-seg.yaml +48 -0
- ultralytics/cfg/models/v8/yoloe-v8.yaml +48 -0
- ultralytics/cfg/models/v8/yolov8-cls-resnet101.yaml +28 -0
- ultralytics/cfg/models/v8/yolov8-cls-resnet50.yaml +28 -0
- ultralytics/cfg/models/v8/yolov8-cls.yaml +32 -0
- ultralytics/cfg/models/v8/yolov8-ghost-p2.yaml +58 -0
- ultralytics/cfg/models/v8/yolov8-ghost-p6.yaml +60 -0
- ultralytics/cfg/models/v8/yolov8-ghost.yaml +50 -0
- ultralytics/cfg/models/v8/yolov8-obb.yaml +49 -0
- ultralytics/cfg/models/v8/yolov8-p2.yaml +57 -0
- ultralytics/cfg/models/v8/yolov8-p6.yaml +59 -0
- ultralytics/cfg/models/v8/yolov8-pose-p6.yaml +60 -0
- ultralytics/cfg/models/v8/yolov8-pose.yaml +50 -0
- ultralytics/cfg/models/v8/yolov8-rtdetr.yaml +49 -0
- ultralytics/cfg/models/v8/yolov8-seg-p6.yaml +59 -0
- ultralytics/cfg/models/v8/yolov8-seg.yaml +49 -0
- ultralytics/cfg/models/v8/yolov8-world.yaml +51 -0
- ultralytics/cfg/models/v8/yolov8-worldv2.yaml +49 -0
- ultralytics/cfg/models/v8/yolov8.yaml +49 -0
- ultralytics/cfg/models/v9/yolov9c-seg.yaml +41 -0
- ultralytics/cfg/models/v9/yolov9c.yaml +41 -0
- ultralytics/cfg/models/v9/yolov9e-seg.yaml +64 -0
- ultralytics/cfg/models/v9/yolov9e.yaml +64 -0
- 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/trackers/botsort.yaml +21 -0
- ultralytics/cfg/trackers/bytetrack.yaml +12 -0
- ultralytics/data/__init__.py +26 -0
- ultralytics/data/annotator.py +66 -0
- ultralytics/data/augment.py +2801 -0
- ultralytics/data/base.py +435 -0
- ultralytics/data/build.py +437 -0
- ultralytics/data/converter.py +855 -0
- ultralytics/data/dataset.py +834 -0
- ultralytics/data/loaders.py +704 -0
- ultralytics/data/scripts/download_weights.sh +18 -0
- ultralytics/data/scripts/get_coco.sh +61 -0
- ultralytics/data/scripts/get_coco128.sh +18 -0
- ultralytics/data/scripts/get_imagenet.sh +52 -0
- ultralytics/data/split.py +138 -0
- ultralytics/data/split_dota.py +344 -0
- ultralytics/data/utils.py +798 -0
- ultralytics/engine/__init__.py +1 -0
- ultralytics/engine/exporter.py +1580 -0
- ultralytics/engine/model.py +1125 -0
- ultralytics/engine/predictor.py +508 -0
- ultralytics/engine/results.py +1522 -0
- ultralytics/engine/trainer.py +977 -0
- ultralytics/engine/tuner.py +449 -0
- ultralytics/engine/validator.py +387 -0
- ultralytics/hub/__init__.py +166 -0
- ultralytics/hub/auth.py +151 -0
- ultralytics/hub/google/__init__.py +174 -0
- ultralytics/hub/session.py +422 -0
- ultralytics/hub/utils.py +162 -0
- ultralytics/models/__init__.py +9 -0
- ultralytics/models/fastsam/__init__.py +7 -0
- ultralytics/models/fastsam/model.py +79 -0
- ultralytics/models/fastsam/predict.py +169 -0
- ultralytics/models/fastsam/utils.py +23 -0
- ultralytics/models/fastsam/val.py +38 -0
- ultralytics/models/nas/__init__.py +7 -0
- ultralytics/models/nas/model.py +98 -0
- ultralytics/models/nas/predict.py +56 -0
- ultralytics/models/nas/val.py +38 -0
- ultralytics/models/rtdetr/__init__.py +7 -0
- ultralytics/models/rtdetr/model.py +63 -0
- ultralytics/models/rtdetr/predict.py +88 -0
- ultralytics/models/rtdetr/train.py +89 -0
- ultralytics/models/rtdetr/val.py +216 -0
- ultralytics/models/sam/__init__.py +25 -0
- ultralytics/models/sam/amg.py +275 -0
- ultralytics/models/sam/build.py +365 -0
- ultralytics/models/sam/build_sam3.py +377 -0
- ultralytics/models/sam/model.py +169 -0
- ultralytics/models/sam/modules/__init__.py +1 -0
- ultralytics/models/sam/modules/blocks.py +1067 -0
- ultralytics/models/sam/modules/decoders.py +495 -0
- ultralytics/models/sam/modules/encoders.py +794 -0
- ultralytics/models/sam/modules/memory_attention.py +298 -0
- ultralytics/models/sam/modules/sam.py +1160 -0
- ultralytics/models/sam/modules/tiny_encoder.py +979 -0
- ultralytics/models/sam/modules/transformer.py +344 -0
- ultralytics/models/sam/modules/utils.py +512 -0
- ultralytics/models/sam/predict.py +3940 -0
- ultralytics/models/sam/sam3/__init__.py +3 -0
- ultralytics/models/sam/sam3/decoder.py +546 -0
- ultralytics/models/sam/sam3/encoder.py +529 -0
- ultralytics/models/sam/sam3/geometry_encoders.py +415 -0
- ultralytics/models/sam/sam3/maskformer_segmentation.py +286 -0
- ultralytics/models/sam/sam3/model_misc.py +199 -0
- ultralytics/models/sam/sam3/necks.py +129 -0
- ultralytics/models/sam/sam3/sam3_image.py +339 -0
- ultralytics/models/sam/sam3/text_encoder_ve.py +307 -0
- ultralytics/models/sam/sam3/vitdet.py +547 -0
- ultralytics/models/sam/sam3/vl_combiner.py +160 -0
- ultralytics/models/utils/__init__.py +1 -0
- ultralytics/models/utils/loss.py +466 -0
- ultralytics/models/utils/ops.py +315 -0
- ultralytics/models/yolo/__init__.py +7 -0
- ultralytics/models/yolo/classify/__init__.py +7 -0
- ultralytics/models/yolo/classify/predict.py +90 -0
- ultralytics/models/yolo/classify/train.py +202 -0
- ultralytics/models/yolo/classify/val.py +216 -0
- ultralytics/models/yolo/detect/__init__.py +7 -0
- ultralytics/models/yolo/detect/predict.py +122 -0
- ultralytics/models/yolo/detect/train.py +227 -0
- ultralytics/models/yolo/detect/val.py +507 -0
- ultralytics/models/yolo/model.py +430 -0
- ultralytics/models/yolo/obb/__init__.py +7 -0
- ultralytics/models/yolo/obb/predict.py +56 -0
- ultralytics/models/yolo/obb/train.py +79 -0
- ultralytics/models/yolo/obb/val.py +302 -0
- ultralytics/models/yolo/pose/__init__.py +7 -0
- ultralytics/models/yolo/pose/predict.py +65 -0
- ultralytics/models/yolo/pose/train.py +110 -0
- ultralytics/models/yolo/pose/val.py +248 -0
- ultralytics/models/yolo/segment/__init__.py +7 -0
- ultralytics/models/yolo/segment/predict.py +109 -0
- ultralytics/models/yolo/segment/train.py +69 -0
- ultralytics/models/yolo/segment/val.py +307 -0
- ultralytics/models/yolo/world/__init__.py +5 -0
- ultralytics/models/yolo/world/train.py +173 -0
- ultralytics/models/yolo/world/train_world.py +178 -0
- ultralytics/models/yolo/yoloe/__init__.py +22 -0
- ultralytics/models/yolo/yoloe/predict.py +162 -0
- ultralytics/models/yolo/yoloe/train.py +287 -0
- ultralytics/models/yolo/yoloe/train_seg.py +122 -0
- ultralytics/models/yolo/yoloe/val.py +206 -0
- ultralytics/nn/__init__.py +27 -0
- ultralytics/nn/autobackend.py +964 -0
- ultralytics/nn/modules/__init__.py +182 -0
- ultralytics/nn/modules/activation.py +54 -0
- ultralytics/nn/modules/block.py +1947 -0
- ultralytics/nn/modules/conv.py +669 -0
- ultralytics/nn/modules/head.py +1183 -0
- ultralytics/nn/modules/transformer.py +793 -0
- ultralytics/nn/modules/utils.py +159 -0
- ultralytics/nn/tasks.py +1768 -0
- ultralytics/nn/text_model.py +356 -0
- ultralytics/py.typed +1 -0
- ultralytics/solutions/__init__.py +41 -0
- ultralytics/solutions/ai_gym.py +108 -0
- ultralytics/solutions/analytics.py +264 -0
- ultralytics/solutions/config.py +107 -0
- ultralytics/solutions/distance_calculation.py +123 -0
- ultralytics/solutions/heatmap.py +125 -0
- ultralytics/solutions/instance_segmentation.py +86 -0
- ultralytics/solutions/object_blurrer.py +89 -0
- ultralytics/solutions/object_counter.py +190 -0
- ultralytics/solutions/object_cropper.py +87 -0
- ultralytics/solutions/parking_management.py +280 -0
- ultralytics/solutions/queue_management.py +93 -0
- ultralytics/solutions/region_counter.py +133 -0
- ultralytics/solutions/security_alarm.py +151 -0
- ultralytics/solutions/similarity_search.py +219 -0
- ultralytics/solutions/solutions.py +828 -0
- ultralytics/solutions/speed_estimation.py +114 -0
- ultralytics/solutions/streamlit_inference.py +260 -0
- ultralytics/solutions/templates/similarity-search.html +156 -0
- ultralytics/solutions/trackzone.py +88 -0
- ultralytics/solutions/vision_eye.py +67 -0
- ultralytics/trackers/__init__.py +7 -0
- ultralytics/trackers/basetrack.py +115 -0
- ultralytics/trackers/bot_sort.py +257 -0
- ultralytics/trackers/byte_tracker.py +469 -0
- ultralytics/trackers/track.py +116 -0
- ultralytics/trackers/utils/__init__.py +1 -0
- ultralytics/trackers/utils/gmc.py +339 -0
- ultralytics/trackers/utils/kalman_filter.py +482 -0
- ultralytics/trackers/utils/matching.py +154 -0
- ultralytics/utils/__init__.py +1450 -0
- ultralytics/utils/autobatch.py +118 -0
- ultralytics/utils/autodevice.py +205 -0
- ultralytics/utils/benchmarks.py +728 -0
- ultralytics/utils/callbacks/__init__.py +5 -0
- ultralytics/utils/callbacks/base.py +233 -0
- ultralytics/utils/callbacks/clearml.py +146 -0
- ultralytics/utils/callbacks/comet.py +625 -0
- ultralytics/utils/callbacks/dvc.py +197 -0
- ultralytics/utils/callbacks/hub.py +110 -0
- ultralytics/utils/callbacks/mlflow.py +134 -0
- ultralytics/utils/callbacks/neptune.py +126 -0
- ultralytics/utils/callbacks/platform.py +453 -0
- ultralytics/utils/callbacks/raytune.py +42 -0
- ultralytics/utils/callbacks/tensorboard.py +123 -0
- ultralytics/utils/callbacks/wb.py +188 -0
- ultralytics/utils/checks.py +1020 -0
- ultralytics/utils/cpu.py +85 -0
- ultralytics/utils/dist.py +123 -0
- ultralytics/utils/downloads.py +529 -0
- ultralytics/utils/errors.py +35 -0
- ultralytics/utils/events.py +113 -0
- ultralytics/utils/export/__init__.py +7 -0
- ultralytics/utils/export/engine.py +237 -0
- ultralytics/utils/export/imx.py +325 -0
- ultralytics/utils/export/tensorflow.py +231 -0
- ultralytics/utils/files.py +219 -0
- ultralytics/utils/git.py +137 -0
- ultralytics/utils/instance.py +484 -0
- ultralytics/utils/logger.py +506 -0
- ultralytics/utils/loss.py +849 -0
- ultralytics/utils/metrics.py +1563 -0
- ultralytics/utils/nms.py +337 -0
- ultralytics/utils/ops.py +664 -0
- ultralytics/utils/patches.py +201 -0
- ultralytics/utils/plotting.py +1047 -0
- ultralytics/utils/tal.py +404 -0
- ultralytics/utils/torch_utils.py +984 -0
- ultralytics/utils/tqdm.py +443 -0
- ultralytics/utils/triton.py +112 -0
- ultralytics/utils/tuner.py +168 -0
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license
|
|
2
|
+
|
|
3
|
+
from typing import Any
|
|
4
|
+
|
|
5
|
+
from ultralytics.solutions.solutions import BaseSolution, SolutionAnnotator, SolutionResults
|
|
6
|
+
from ultralytics.utils.plotting import colors
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class VisionEye(BaseSolution):
|
|
10
|
+
"""A class to manage object detection and vision mapping in images or video streams.
|
|
11
|
+
|
|
12
|
+
This class extends the BaseSolution class and provides functionality for detecting objects, mapping vision points,
|
|
13
|
+
and annotating results with bounding boxes and labels.
|
|
14
|
+
|
|
15
|
+
Attributes:
|
|
16
|
+
vision_point (tuple[int, int]): Coordinates (x, y) where vision will view objects and draw tracks.
|
|
17
|
+
|
|
18
|
+
Methods:
|
|
19
|
+
process: Process the input image to detect objects, annotate them, and apply vision mapping.
|
|
20
|
+
|
|
21
|
+
Examples:
|
|
22
|
+
>>> vision_eye = VisionEye()
|
|
23
|
+
>>> frame = cv2.imread("frame.jpg")
|
|
24
|
+
>>> results = vision_eye.process(frame)
|
|
25
|
+
>>> print(f"Total detected instances: {results.total_tracks}")
|
|
26
|
+
"""
|
|
27
|
+
|
|
28
|
+
def __init__(self, **kwargs: Any) -> None:
|
|
29
|
+
"""Initialize the VisionEye class for detecting objects and applying vision mapping.
|
|
30
|
+
|
|
31
|
+
Args:
|
|
32
|
+
**kwargs (Any): Keyword arguments passed to the parent class and for configuring vision_point.
|
|
33
|
+
"""
|
|
34
|
+
super().__init__(**kwargs)
|
|
35
|
+
# Set the vision point where the system will view objects and draw tracks
|
|
36
|
+
self.vision_point = self.CFG["vision_point"]
|
|
37
|
+
|
|
38
|
+
def process(self, im0) -> SolutionResults:
|
|
39
|
+
"""Perform object detection, vision mapping, and annotation on the input image.
|
|
40
|
+
|
|
41
|
+
Args:
|
|
42
|
+
im0 (np.ndarray): The input image for detection and annotation.
|
|
43
|
+
|
|
44
|
+
Returns:
|
|
45
|
+
(SolutionResults): Object containing the annotated image and tracking statistics.
|
|
46
|
+
- plot_im: Annotated output image with bounding boxes and vision mapping
|
|
47
|
+
- total_tracks: Number of tracked objects in the frame
|
|
48
|
+
|
|
49
|
+
Examples:
|
|
50
|
+
>>> vision_eye = VisionEye()
|
|
51
|
+
>>> frame = cv2.imread("image.jpg")
|
|
52
|
+
>>> results = vision_eye.process(frame)
|
|
53
|
+
>>> print(f"Detected {results.total_tracks} objects")
|
|
54
|
+
"""
|
|
55
|
+
self.extract_tracks(im0) # Extract tracks (bounding boxes, classes, and masks)
|
|
56
|
+
annotator = SolutionAnnotator(im0, self.line_width)
|
|
57
|
+
|
|
58
|
+
for cls, t_id, box, conf in zip(self.clss, self.track_ids, self.boxes, self.confs):
|
|
59
|
+
# Annotate the image with bounding boxes, labels, and vision mapping
|
|
60
|
+
annotator.box_label(box, label=self.adjust_box_label(cls, conf, t_id), color=colors(int(t_id), True))
|
|
61
|
+
annotator.visioneye(box, self.vision_point)
|
|
62
|
+
|
|
63
|
+
plot_im = annotator.result()
|
|
64
|
+
self.display_output(plot_im) # Display the annotated output using the base class function
|
|
65
|
+
|
|
66
|
+
# Return a SolutionResults object with the annotated image and tracking statistics
|
|
67
|
+
return SolutionResults(plot_im=plot_im, total_tracks=len(self.track_ids))
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license
|
|
2
|
+
"""Module defines the base classes and structures for object tracking in YOLO."""
|
|
3
|
+
|
|
4
|
+
from collections import OrderedDict
|
|
5
|
+
from typing import Any
|
|
6
|
+
|
|
7
|
+
import numpy as np
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class TrackState:
|
|
11
|
+
"""Enumeration class representing the possible states of an object being tracked.
|
|
12
|
+
|
|
13
|
+
Attributes:
|
|
14
|
+
New (int): State when the object is newly detected.
|
|
15
|
+
Tracked (int): State when the object is successfully tracked in subsequent frames.
|
|
16
|
+
Lost (int): State when the object is no longer tracked.
|
|
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.")
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
New = 0
|
|
26
|
+
Tracked = 1
|
|
27
|
+
Lost = 2
|
|
28
|
+
Removed = 3
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class BaseTrack:
|
|
32
|
+
"""Base class for object tracking, providing foundational attributes and methods.
|
|
33
|
+
|
|
34
|
+
Attributes:
|
|
35
|
+
_count (int): Class-level counter for unique track IDs.
|
|
36
|
+
track_id (int): Unique identifier for the track.
|
|
37
|
+
is_activated (bool): Flag indicating whether the track is currently active.
|
|
38
|
+
state (TrackState): Current state of the track.
|
|
39
|
+
history (OrderedDict): Ordered history of the track's states.
|
|
40
|
+
features (list): List of features extracted from the object for tracking.
|
|
41
|
+
curr_feature (Any): The current feature of the object being tracked.
|
|
42
|
+
score (float): The confidence score of the tracking.
|
|
43
|
+
start_frame (int): The frame number where tracking started.
|
|
44
|
+
frame_id (int): The most recent frame ID processed by the track.
|
|
45
|
+
time_since_update (int): Frames passed since the last update.
|
|
46
|
+
location (tuple): The location of the object in the context of multi-camera tracking.
|
|
47
|
+
|
|
48
|
+
Methods:
|
|
49
|
+
end_frame: Returns the ID of the last frame where the object was tracked.
|
|
50
|
+
next_id: Increments and returns the next global track ID.
|
|
51
|
+
activate: Abstract method to activate the track.
|
|
52
|
+
predict: Abstract method to predict the next state of the track.
|
|
53
|
+
update: Abstract method to update the track with new data.
|
|
54
|
+
mark_lost: Marks the track as lost.
|
|
55
|
+
mark_removed: Marks the track as removed.
|
|
56
|
+
reset_id: Resets the global track ID counter.
|
|
57
|
+
|
|
58
|
+
Examples:
|
|
59
|
+
Initialize a new track and mark it as lost:
|
|
60
|
+
>>> track = BaseTrack()
|
|
61
|
+
>>> track.mark_lost()
|
|
62
|
+
>>> print(track.state) # Output: 2 (TrackState.Lost)
|
|
63
|
+
"""
|
|
64
|
+
|
|
65
|
+
_count = 0
|
|
66
|
+
|
|
67
|
+
def __init__(self):
|
|
68
|
+
"""Initialize a new track with a unique ID and foundational tracking attributes."""
|
|
69
|
+
self.track_id = 0
|
|
70
|
+
self.is_activated = False
|
|
71
|
+
self.state = TrackState.New
|
|
72
|
+
self.history = OrderedDict()
|
|
73
|
+
self.features = []
|
|
74
|
+
self.curr_feature = None
|
|
75
|
+
self.score = 0
|
|
76
|
+
self.start_frame = 0
|
|
77
|
+
self.frame_id = 0
|
|
78
|
+
self.time_since_update = 0
|
|
79
|
+
self.location = (np.inf, np.inf)
|
|
80
|
+
|
|
81
|
+
@property
|
|
82
|
+
def end_frame(self) -> int:
|
|
83
|
+
"""Return the ID of the most recent frame where the object was tracked."""
|
|
84
|
+
return self.frame_id
|
|
85
|
+
|
|
86
|
+
@staticmethod
|
|
87
|
+
def next_id() -> int:
|
|
88
|
+
"""Increment and return the next unique global track ID for object tracking."""
|
|
89
|
+
BaseTrack._count += 1
|
|
90
|
+
return BaseTrack._count
|
|
91
|
+
|
|
92
|
+
def activate(self, *args: Any) -> None:
|
|
93
|
+
"""Activate the track with provided arguments, initializing necessary attributes for tracking."""
|
|
94
|
+
raise NotImplementedError
|
|
95
|
+
|
|
96
|
+
def predict(self) -> None:
|
|
97
|
+
"""Predict the next state of the track based on the current state and tracking model."""
|
|
98
|
+
raise NotImplementedError
|
|
99
|
+
|
|
100
|
+
def update(self, *args: Any, **kwargs: Any) -> None:
|
|
101
|
+
"""Update the track with new observations and data, modifying its state and attributes accordingly."""
|
|
102
|
+
raise NotImplementedError
|
|
103
|
+
|
|
104
|
+
def mark_lost(self) -> None:
|
|
105
|
+
"""Mark the track as lost by updating its state to TrackState.Lost."""
|
|
106
|
+
self.state = TrackState.Lost
|
|
107
|
+
|
|
108
|
+
def mark_removed(self) -> None:
|
|
109
|
+
"""Mark the track as removed by setting its state to TrackState.Removed."""
|
|
110
|
+
self.state = TrackState.Removed
|
|
111
|
+
|
|
112
|
+
@staticmethod
|
|
113
|
+
def reset_id() -> None:
|
|
114
|
+
"""Reset the global track ID counter to its initial value."""
|
|
115
|
+
BaseTrack._count = 0
|
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from collections import deque
|
|
6
|
+
from typing import Any
|
|
7
|
+
|
|
8
|
+
import numpy as np
|
|
9
|
+
import torch
|
|
10
|
+
|
|
11
|
+
from ultralytics.utils.ops import xywh2xyxy
|
|
12
|
+
from ultralytics.utils.plotting import save_one_box
|
|
13
|
+
|
|
14
|
+
from .basetrack import TrackState
|
|
15
|
+
from .byte_tracker import BYTETracker, STrack
|
|
16
|
+
from .utils import matching
|
|
17
|
+
from .utils.gmc import GMC
|
|
18
|
+
from .utils.kalman_filter import KalmanFilterXYWH
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class BOTrack(STrack):
|
|
22
|
+
"""An extended version of the STrack class for YOLO, adding object tracking features.
|
|
23
|
+
|
|
24
|
+
This class extends the STrack class to include additional functionalities for object tracking, such as feature
|
|
25
|
+
smoothing, Kalman filter prediction, and reactivation of tracks.
|
|
26
|
+
|
|
27
|
+
Attributes:
|
|
28
|
+
shared_kalman (KalmanFilterXYWH): A shared Kalman filter for all instances of BOTrack.
|
|
29
|
+
smooth_feat (np.ndarray): Smoothed feature vector.
|
|
30
|
+
curr_feat (np.ndarray): Current feature vector.
|
|
31
|
+
features (deque): A deque to store feature vectors with a maximum length defined by `feat_history`.
|
|
32
|
+
alpha (float): Smoothing factor for the exponential moving average of features.
|
|
33
|
+
mean (np.ndarray): The mean state of the Kalman filter.
|
|
34
|
+
covariance (np.ndarray): The covariance matrix of the Kalman filter.
|
|
35
|
+
|
|
36
|
+
Methods:
|
|
37
|
+
update_features: Update features vector and smooth it using exponential moving average.
|
|
38
|
+
predict: Predict the mean and covariance using Kalman filter.
|
|
39
|
+
re_activate: Reactivate a track with updated features and optionally new ID.
|
|
40
|
+
update: Update the track with new detection and frame ID.
|
|
41
|
+
tlwh: Property that gets the current position in tlwh format `(top left x, top left y, width, height)`.
|
|
42
|
+
multi_predict: Predict the mean and covariance of multiple object tracks using shared Kalman filter.
|
|
43
|
+
convert_coords: Convert tlwh bounding box coordinates to xywh format.
|
|
44
|
+
tlwh_to_xywh: Convert bounding box to xywh format `(center x, center y, width, height)`.
|
|
45
|
+
|
|
46
|
+
Examples:
|
|
47
|
+
Create a BOTrack instance and update its features
|
|
48
|
+
>>> bo_track = BOTrack(xywh=np.array([100, 50, 80, 40, 0]), score=0.9, cls=1, feat=np.random.rand(128))
|
|
49
|
+
>>> bo_track.predict()
|
|
50
|
+
>>> new_track = BOTrack(xywh=np.array([110, 60, 80, 40, 0]), score=0.85, cls=1, feat=np.random.rand(128))
|
|
51
|
+
>>> bo_track.update(new_track, frame_id=2)
|
|
52
|
+
"""
|
|
53
|
+
|
|
54
|
+
shared_kalman = KalmanFilterXYWH()
|
|
55
|
+
|
|
56
|
+
def __init__(
|
|
57
|
+
self, xywh: np.ndarray, score: float, cls: int, feat: np.ndarray | None = None, feat_history: int = 50
|
|
58
|
+
):
|
|
59
|
+
"""Initialize a BOTrack object with temporal parameters, such as feature history, alpha, and current features.
|
|
60
|
+
|
|
61
|
+
Args:
|
|
62
|
+
xywh (np.ndarray): Bounding box in `(x, y, w, h, idx)` or `(x, y, w, h, angle, idx)` format, where (x, y) is
|
|
63
|
+
the center, (w, h) are width and height, and `idx` is the detection index.
|
|
64
|
+
score (float): Confidence score of the detection.
|
|
65
|
+
cls (int): Class ID of the detected object.
|
|
66
|
+
feat (np.ndarray, optional): Feature vector associated with the detection.
|
|
67
|
+
feat_history (int): Maximum length of the feature history deque.
|
|
68
|
+
"""
|
|
69
|
+
super().__init__(xywh, score, cls)
|
|
70
|
+
|
|
71
|
+
self.smooth_feat = None
|
|
72
|
+
self.curr_feat = None
|
|
73
|
+
if feat is not None:
|
|
74
|
+
self.update_features(feat)
|
|
75
|
+
self.features = deque([], maxlen=feat_history)
|
|
76
|
+
self.alpha = 0.9
|
|
77
|
+
|
|
78
|
+
def update_features(self, feat: np.ndarray) -> None:
|
|
79
|
+
"""Update the feature vector and apply exponential moving average smoothing."""
|
|
80
|
+
feat /= np.linalg.norm(feat)
|
|
81
|
+
self.curr_feat = feat
|
|
82
|
+
if self.smooth_feat is None:
|
|
83
|
+
self.smooth_feat = feat
|
|
84
|
+
else:
|
|
85
|
+
self.smooth_feat = self.alpha * self.smooth_feat + (1 - self.alpha) * feat
|
|
86
|
+
self.features.append(feat)
|
|
87
|
+
self.smooth_feat /= np.linalg.norm(self.smooth_feat)
|
|
88
|
+
|
|
89
|
+
def predict(self) -> None:
|
|
90
|
+
"""Predict the object's future state using the Kalman filter to update its mean and covariance."""
|
|
91
|
+
mean_state = self.mean.copy()
|
|
92
|
+
if self.state != TrackState.Tracked:
|
|
93
|
+
mean_state[6] = 0
|
|
94
|
+
mean_state[7] = 0
|
|
95
|
+
|
|
96
|
+
self.mean, self.covariance = self.kalman_filter.predict(mean_state, self.covariance)
|
|
97
|
+
|
|
98
|
+
def re_activate(self, new_track: BOTrack, frame_id: int, new_id: bool = False) -> None:
|
|
99
|
+
"""Reactivate a track with updated features and optionally assign a new ID."""
|
|
100
|
+
if new_track.curr_feat is not None:
|
|
101
|
+
self.update_features(new_track.curr_feat)
|
|
102
|
+
super().re_activate(new_track, frame_id, new_id)
|
|
103
|
+
|
|
104
|
+
def update(self, new_track: BOTrack, frame_id: int) -> None:
|
|
105
|
+
"""Update the track with new detection information and the current frame ID."""
|
|
106
|
+
if new_track.curr_feat is not None:
|
|
107
|
+
self.update_features(new_track.curr_feat)
|
|
108
|
+
super().update(new_track, frame_id)
|
|
109
|
+
|
|
110
|
+
@property
|
|
111
|
+
def tlwh(self) -> np.ndarray:
|
|
112
|
+
"""Return the current bounding box position in `(top left x, top left y, width, height)` format."""
|
|
113
|
+
if self.mean is None:
|
|
114
|
+
return self._tlwh.copy()
|
|
115
|
+
ret = self.mean[:4].copy()
|
|
116
|
+
ret[:2] -= ret[2:] / 2
|
|
117
|
+
return ret
|
|
118
|
+
|
|
119
|
+
@staticmethod
|
|
120
|
+
def multi_predict(stracks: list[BOTrack]) -> None:
|
|
121
|
+
"""Predict the mean and covariance for multiple object tracks using a shared Kalman filter."""
|
|
122
|
+
if len(stracks) <= 0:
|
|
123
|
+
return
|
|
124
|
+
multi_mean = np.asarray([st.mean.copy() for st in stracks])
|
|
125
|
+
multi_covariance = np.asarray([st.covariance for st in stracks])
|
|
126
|
+
for i, st in enumerate(stracks):
|
|
127
|
+
if st.state != TrackState.Tracked:
|
|
128
|
+
multi_mean[i][6] = 0
|
|
129
|
+
multi_mean[i][7] = 0
|
|
130
|
+
multi_mean, multi_covariance = BOTrack.shared_kalman.multi_predict(multi_mean, multi_covariance)
|
|
131
|
+
for i, (mean, cov) in enumerate(zip(multi_mean, multi_covariance)):
|
|
132
|
+
stracks[i].mean = mean
|
|
133
|
+
stracks[i].covariance = cov
|
|
134
|
+
|
|
135
|
+
def convert_coords(self, tlwh: np.ndarray) -> np.ndarray:
|
|
136
|
+
"""Convert tlwh bounding box coordinates to xywh format."""
|
|
137
|
+
return self.tlwh_to_xywh(tlwh)
|
|
138
|
+
|
|
139
|
+
@staticmethod
|
|
140
|
+
def tlwh_to_xywh(tlwh: np.ndarray) -> np.ndarray:
|
|
141
|
+
"""Convert bounding box from tlwh (top-left-width-height) to xywh (center-x-center-y-width-height) format."""
|
|
142
|
+
ret = np.asarray(tlwh).copy()
|
|
143
|
+
ret[:2] += ret[2:] / 2
|
|
144
|
+
return ret
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
class BOTSORT(BYTETracker):
|
|
148
|
+
"""An extended version of the BYTETracker class for YOLO, designed for object tracking with ReID and GMC algorithm.
|
|
149
|
+
|
|
150
|
+
Attributes:
|
|
151
|
+
proximity_thresh (float): Threshold for spatial proximity (IoU) between tracks and detections.
|
|
152
|
+
appearance_thresh (float): Threshold for appearance similarity (ReID embeddings) between tracks and detections.
|
|
153
|
+
encoder (Any): Object to handle ReID embeddings, set to None if ReID is not enabled.
|
|
154
|
+
gmc (GMC): An instance of the GMC algorithm for data association.
|
|
155
|
+
args (Any): Parsed command-line arguments containing tracking parameters.
|
|
156
|
+
|
|
157
|
+
Methods:
|
|
158
|
+
get_kalmanfilter: Return an instance of KalmanFilterXYWH for object tracking.
|
|
159
|
+
init_track: Initialize track with detections, scores, and classes.
|
|
160
|
+
get_dists: Get distances between tracks and detections using IoU and (optionally) ReID.
|
|
161
|
+
multi_predict: Predict and track multiple objects with a YOLO model.
|
|
162
|
+
reset: Reset the BOTSORT tracker to its initial state.
|
|
163
|
+
|
|
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)
|
|
169
|
+
|
|
170
|
+
Notes:
|
|
171
|
+
The class is designed to work with a YOLO object detection model and supports ReID only if enabled via args.
|
|
172
|
+
"""
|
|
173
|
+
|
|
174
|
+
def __init__(self, args: Any, frame_rate: int = 30):
|
|
175
|
+
"""Initialize BOTSORT object with ReID module and GMC algorithm.
|
|
176
|
+
|
|
177
|
+
Args:
|
|
178
|
+
args (Any): Parsed command-line arguments containing tracking parameters.
|
|
179
|
+
frame_rate (int): Frame rate of the video being processed.
|
|
180
|
+
"""
|
|
181
|
+
super().__init__(args, frame_rate)
|
|
182
|
+
self.gmc = GMC(method=args.gmc_method)
|
|
183
|
+
|
|
184
|
+
# ReID module
|
|
185
|
+
self.proximity_thresh = args.proximity_thresh
|
|
186
|
+
self.appearance_thresh = args.appearance_thresh
|
|
187
|
+
self.encoder = (
|
|
188
|
+
(lambda feats, s: [f.cpu().numpy() for f in feats]) # native features do not require any model
|
|
189
|
+
if args.with_reid and self.args.model == "auto"
|
|
190
|
+
else ReID(args.model)
|
|
191
|
+
if args.with_reid
|
|
192
|
+
else None
|
|
193
|
+
)
|
|
194
|
+
|
|
195
|
+
def get_kalmanfilter(self) -> KalmanFilterXYWH:
|
|
196
|
+
"""Return an instance of KalmanFilterXYWH for predicting and updating object states in the tracking process."""
|
|
197
|
+
return KalmanFilterXYWH()
|
|
198
|
+
|
|
199
|
+
def init_track(self, results, img: np.ndarray | None = None) -> list[BOTrack]:
|
|
200
|
+
"""Initialize object tracks using detection bounding boxes, scores, class labels, and optional ReID features."""
|
|
201
|
+
if len(results) == 0:
|
|
202
|
+
return []
|
|
203
|
+
bboxes = results.xywhr if hasattr(results, "xywhr") else results.xywh
|
|
204
|
+
bboxes = np.concatenate([bboxes, np.arange(len(bboxes)).reshape(-1, 1)], axis=-1)
|
|
205
|
+
if self.args.with_reid and self.encoder is not None:
|
|
206
|
+
features_keep = self.encoder(img, bboxes)
|
|
207
|
+
return [BOTrack(xywh, s, c, f) for (xywh, s, c, f) in zip(bboxes, results.conf, results.cls, features_keep)]
|
|
208
|
+
else:
|
|
209
|
+
return [BOTrack(xywh, s, c) for (xywh, s, c) in zip(bboxes, results.conf, results.cls)]
|
|
210
|
+
|
|
211
|
+
def get_dists(self, tracks: list[BOTrack], detections: list[BOTrack]) -> np.ndarray:
|
|
212
|
+
"""Calculate distances between tracks and detections using IoU and optionally ReID embeddings."""
|
|
213
|
+
dists = matching.iou_distance(tracks, detections)
|
|
214
|
+
dists_mask = dists > (1 - self.proximity_thresh)
|
|
215
|
+
|
|
216
|
+
if self.args.fuse_score:
|
|
217
|
+
dists = matching.fuse_score(dists, detections)
|
|
218
|
+
|
|
219
|
+
if self.args.with_reid and self.encoder is not None:
|
|
220
|
+
emb_dists = matching.embedding_distance(tracks, detections) / 2.0
|
|
221
|
+
emb_dists[emb_dists > (1 - self.appearance_thresh)] = 1.0
|
|
222
|
+
emb_dists[dists_mask] = 1.0
|
|
223
|
+
dists = np.minimum(dists, emb_dists)
|
|
224
|
+
return dists
|
|
225
|
+
|
|
226
|
+
def multi_predict(self, tracks: list[BOTrack]) -> None:
|
|
227
|
+
"""Predict the mean and covariance of multiple object tracks using a shared Kalman filter."""
|
|
228
|
+
BOTrack.multi_predict(tracks)
|
|
229
|
+
|
|
230
|
+
def reset(self) -> None:
|
|
231
|
+
"""Reset the BOTSORT tracker to its initial state, clearing all tracked objects and internal states."""
|
|
232
|
+
super().reset()
|
|
233
|
+
self.gmc.reset_params()
|
|
234
|
+
|
|
235
|
+
|
|
236
|
+
class ReID:
|
|
237
|
+
"""YOLO model as encoder for re-identification."""
|
|
238
|
+
|
|
239
|
+
def __init__(self, model: str):
|
|
240
|
+
"""Initialize encoder for re-identification.
|
|
241
|
+
|
|
242
|
+
Args:
|
|
243
|
+
model (str): Path to the YOLO model for re-identification.
|
|
244
|
+
"""
|
|
245
|
+
from ultralytics import YOLO
|
|
246
|
+
|
|
247
|
+
self.model = YOLO(model)
|
|
248
|
+
self.model(embed=[len(self.model.model.model) - 2 if ".pt" in model else -1], verbose=False, save=False) # init
|
|
249
|
+
|
|
250
|
+
def __call__(self, img: np.ndarray, dets: np.ndarray) -> list[np.ndarray]:
|
|
251
|
+
"""Extract embeddings for detected objects."""
|
|
252
|
+
feats = self.model.predictor(
|
|
253
|
+
[save_one_box(det, img, save=False) for det in xywh2xyxy(torch.from_numpy(dets[:, :4]))]
|
|
254
|
+
)
|
|
255
|
+
if len(feats) != dets.shape[0] and feats[0].shape[0] == dets.shape[0]:
|
|
256
|
+
feats = feats[0] # batched prediction with non-PyTorch backend
|
|
257
|
+
return [f.cpu().numpy() for f in feats]
|