ultralytics 8.3.142__py3-none-any.whl → 8.3.144__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/conftest.py +7 -24
- tests/test_cli.py +1 -1
- tests/test_cuda.py +7 -2
- tests/test_engine.py +7 -8
- tests/test_exports.py +16 -16
- tests/test_integrations.py +1 -1
- tests/test_solutions.py +12 -12
- ultralytics/__init__.py +1 -1
- ultralytics/cfg/__init__.py +16 -13
- ultralytics/data/annotator.py +6 -5
- ultralytics/data/augment.py +127 -126
- ultralytics/data/base.py +54 -51
- ultralytics/data/build.py +47 -23
- ultralytics/data/converter.py +47 -43
- ultralytics/data/dataset.py +51 -50
- ultralytics/data/loaders.py +77 -44
- ultralytics/data/split.py +22 -9
- ultralytics/data/split_dota.py +63 -39
- ultralytics/data/utils.py +59 -39
- ultralytics/engine/exporter.py +79 -27
- ultralytics/engine/model.py +39 -39
- ultralytics/engine/predictor.py +37 -28
- ultralytics/engine/results.py +187 -157
- ultralytics/engine/trainer.py +36 -19
- ultralytics/engine/tuner.py +12 -9
- ultralytics/engine/validator.py +7 -9
- ultralytics/hub/__init__.py +11 -13
- ultralytics/hub/auth.py +22 -2
- ultralytics/hub/google/__init__.py +19 -19
- ultralytics/hub/session.py +37 -51
- ultralytics/hub/utils.py +19 -5
- ultralytics/models/fastsam/model.py +30 -12
- ultralytics/models/fastsam/predict.py +5 -6
- ultralytics/models/fastsam/utils.py +3 -3
- ultralytics/models/fastsam/val.py +10 -6
- ultralytics/models/nas/model.py +9 -5
- ultralytics/models/nas/predict.py +6 -6
- ultralytics/models/nas/val.py +3 -3
- ultralytics/models/rtdetr/model.py +7 -6
- ultralytics/models/rtdetr/predict.py +14 -7
- ultralytics/models/rtdetr/train.py +10 -4
- ultralytics/models/rtdetr/val.py +36 -9
- ultralytics/models/sam/amg.py +30 -12
- ultralytics/models/sam/build.py +22 -22
- ultralytics/models/sam/model.py +10 -9
- ultralytics/models/sam/modules/blocks.py +76 -80
- ultralytics/models/sam/modules/decoders.py +6 -8
- ultralytics/models/sam/modules/encoders.py +23 -26
- ultralytics/models/sam/modules/memory_attention.py +13 -1
- ultralytics/models/sam/modules/sam.py +57 -26
- ultralytics/models/sam/modules/tiny_encoder.py +232 -237
- ultralytics/models/sam/modules/transformer.py +13 -13
- ultralytics/models/sam/modules/utils.py +11 -19
- ultralytics/models/sam/predict.py +114 -101
- ultralytics/models/utils/loss.py +98 -77
- ultralytics/models/utils/ops.py +116 -67
- ultralytics/models/yolo/classify/predict.py +5 -5
- ultralytics/models/yolo/classify/train.py +32 -28
- ultralytics/models/yolo/classify/val.py +7 -8
- ultralytics/models/yolo/detect/predict.py +1 -0
- ultralytics/models/yolo/detect/train.py +15 -14
- ultralytics/models/yolo/detect/val.py +37 -36
- ultralytics/models/yolo/model.py +106 -23
- ultralytics/models/yolo/obb/predict.py +3 -4
- ultralytics/models/yolo/obb/train.py +14 -6
- ultralytics/models/yolo/obb/val.py +29 -23
- ultralytics/models/yolo/pose/predict.py +9 -8
- ultralytics/models/yolo/pose/train.py +24 -16
- ultralytics/models/yolo/pose/val.py +44 -26
- ultralytics/models/yolo/segment/predict.py +5 -5
- ultralytics/models/yolo/segment/train.py +11 -7
- ultralytics/models/yolo/segment/val.py +2 -2
- ultralytics/models/yolo/world/train.py +33 -23
- ultralytics/models/yolo/world/train_world.py +11 -3
- ultralytics/models/yolo/yoloe/predict.py +11 -11
- ultralytics/models/yolo/yoloe/train.py +73 -21
- ultralytics/models/yolo/yoloe/train_seg.py +10 -7
- ultralytics/models/yolo/yoloe/val.py +42 -18
- ultralytics/nn/autobackend.py +59 -15
- ultralytics/nn/modules/__init__.py +4 -4
- ultralytics/nn/modules/activation.py +4 -1
- ultralytics/nn/modules/block.py +178 -111
- ultralytics/nn/modules/conv.py +6 -5
- ultralytics/nn/modules/head.py +469 -121
- ultralytics/nn/modules/transformer.py +147 -58
- ultralytics/nn/tasks.py +227 -20
- ultralytics/nn/text_model.py +30 -33
- ultralytics/solutions/ai_gym.py +1 -1
- ultralytics/solutions/analytics.py +7 -4
- ultralytics/solutions/config.py +10 -10
- ultralytics/solutions/distance_calculation.py +11 -10
- ultralytics/solutions/heatmap.py +1 -1
- ultralytics/solutions/instance_segmentation.py +6 -3
- ultralytics/solutions/object_blurrer.py +3 -3
- ultralytics/solutions/object_counter.py +16 -8
- ultralytics/solutions/object_cropper.py +12 -5
- ultralytics/solutions/parking_management.py +29 -28
- ultralytics/solutions/queue_management.py +6 -6
- ultralytics/solutions/region_counter.py +10 -3
- ultralytics/solutions/security_alarm.py +3 -3
- ultralytics/solutions/similarity_search.py +85 -24
- ultralytics/solutions/solutions.py +215 -85
- ultralytics/solutions/speed_estimation.py +28 -22
- ultralytics/solutions/streamlit_inference.py +17 -12
- ultralytics/solutions/trackzone.py +4 -4
- ultralytics/trackers/basetrack.py +16 -23
- ultralytics/trackers/bot_sort.py +30 -20
- ultralytics/trackers/byte_tracker.py +70 -64
- ultralytics/trackers/track.py +4 -8
- ultralytics/trackers/utils/gmc.py +31 -58
- ultralytics/trackers/utils/kalman_filter.py +37 -37
- ultralytics/trackers/utils/matching.py +1 -1
- ultralytics/utils/__init__.py +105 -89
- ultralytics/utils/autobatch.py +16 -3
- ultralytics/utils/autodevice.py +54 -24
- ultralytics/utils/benchmarks.py +42 -28
- ultralytics/utils/callbacks/base.py +3 -3
- ultralytics/utils/callbacks/clearml.py +9 -9
- ultralytics/utils/callbacks/comet.py +67 -25
- ultralytics/utils/callbacks/dvc.py +7 -10
- ultralytics/utils/callbacks/mlflow.py +2 -5
- ultralytics/utils/callbacks/neptune.py +7 -13
- ultralytics/utils/callbacks/raytune.py +1 -1
- ultralytics/utils/callbacks/tensorboard.py +5 -6
- ultralytics/utils/callbacks/wb.py +14 -14
- ultralytics/utils/checks.py +14 -13
- ultralytics/utils/dist.py +5 -5
- ultralytics/utils/downloads.py +94 -67
- ultralytics/utils/errors.py +5 -5
- ultralytics/utils/export.py +61 -47
- ultralytics/utils/files.py +23 -22
- ultralytics/utils/instance.py +48 -52
- ultralytics/utils/loss.py +78 -40
- ultralytics/utils/metrics.py +186 -130
- ultralytics/utils/ops.py +186 -190
- ultralytics/utils/patches.py +15 -17
- ultralytics/utils/plotting.py +71 -27
- ultralytics/utils/tal.py +21 -15
- ultralytics/utils/torch_utils.py +53 -50
- ultralytics/utils/triton.py +5 -4
- ultralytics/utils/tuner.py +5 -5
- {ultralytics-8.3.142.dist-info → ultralytics-8.3.144.dist-info}/METADATA +1 -1
- ultralytics-8.3.144.dist-info/RECORD +272 -0
- ultralytics-8.3.142.dist-info/RECORD +0 -272
- {ultralytics-8.3.142.dist-info → ultralytics-8.3.144.dist-info}/WHEEL +0 -0
- {ultralytics-8.3.142.dist-info → ultralytics-8.3.144.dist-info}/entry_points.txt +0 -0
- {ultralytics-8.3.142.dist-info → ultralytics-8.3.144.dist-info}/licenses/LICENSE +0 -0
- {ultralytics-8.3.142.dist-info → ultralytics-8.3.144.dist-info}/top_level.txt +0 -0
@@ -2,13 +2,14 @@
|
|
2
2
|
|
3
3
|
import math
|
4
4
|
from collections import defaultdict
|
5
|
+
from typing import Any, Dict, List, Optional, Tuple
|
5
6
|
|
6
7
|
import cv2
|
7
8
|
import numpy as np
|
8
9
|
|
9
10
|
from ultralytics import YOLO
|
10
11
|
from ultralytics.solutions.config import SolutionConfig
|
11
|
-
from ultralytics.utils import ASSETS_URL, LOGGER
|
12
|
+
from ultralytics.utils import ASSETS_URL, LOGGER, ops
|
12
13
|
from ultralytics.utils.checks import check_imshow, check_requirements
|
13
14
|
from ultralytics.utils.plotting import Annotator
|
14
15
|
|
@@ -18,25 +19,47 @@ class BaseSolution:
|
|
18
19
|
A base class for managing Ultralytics Solutions.
|
19
20
|
|
20
21
|
This class provides core functionality for various Ultralytics Solutions, including model loading, object tracking,
|
21
|
-
and region initialization.
|
22
|
+
and region initialization. It serves as the foundation for implementing specific computer vision solutions such as
|
23
|
+
object counting, pose estimation, and analytics.
|
22
24
|
|
23
25
|
Attributes:
|
24
|
-
LineString
|
25
|
-
Polygon
|
26
|
-
Point
|
27
|
-
|
28
|
-
|
26
|
+
LineString: Class for creating line string geometries from shapely.
|
27
|
+
Polygon: Class for creating polygon geometries from shapely.
|
28
|
+
Point: Class for creating point geometries from shapely.
|
29
|
+
prep: Prepared geometry function from shapely for optimized spatial operations.
|
30
|
+
CFG (Dict[str, Any]): Configuration dictionary loaded from YAML file and updated with kwargs.
|
31
|
+
LOGGER: Logger instance for solution-specific logging.
|
32
|
+
annotator: Annotator instance for drawing on images.
|
33
|
+
tracks: YOLO tracking results from the latest inference.
|
34
|
+
track_data: Extracted tracking data (boxes or OBB) from tracks.
|
35
|
+
boxes (List): Bounding box coordinates from tracking results.
|
36
|
+
clss (List[int]): Class indices from tracking results.
|
37
|
+
track_ids (List[int]): Track IDs from tracking results.
|
38
|
+
confs (List[float]): Confidence scores from tracking results.
|
39
|
+
track_line: Current track line for storing tracking history.
|
40
|
+
masks: Segmentation masks from tracking results.
|
41
|
+
r_s: Region or line geometry object for spatial operations.
|
42
|
+
frame_no (int): Current frame number for logging purposes.
|
43
|
+
region (List[Tuple[int, int]]): List of coordinate tuples defining region of interest.
|
29
44
|
line_width (int): Width of lines used in visualizations.
|
30
|
-
model (
|
45
|
+
model (YOLO): Loaded YOLO model instance.
|
31
46
|
names (Dict[int, str]): Dictionary mapping class indices to class names.
|
32
|
-
|
33
|
-
|
47
|
+
classes (List[int]): List of class indices to track.
|
48
|
+
show_conf (bool): Flag to show confidence scores in annotations.
|
49
|
+
show_labels (bool): Flag to show class labels in annotations.
|
50
|
+
device (str): Device for model inference.
|
51
|
+
track_add_args (Dict[str, Any]): Additional arguments for tracking configuration.
|
52
|
+
env_check (bool): Flag indicating whether environment supports image display.
|
53
|
+
track_history (defaultdict): Dictionary storing tracking history for each object.
|
54
|
+
profilers (Tuple): Profiler instances for performance monitoring.
|
34
55
|
|
35
56
|
Methods:
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
57
|
+
adjust_box_label: Generate formatted label for bounding box.
|
58
|
+
extract_tracks: Apply object tracking and extract tracks from input image.
|
59
|
+
store_tracking_history: Store object tracking history for given track ID and bounding box.
|
60
|
+
initialize_region: Initialize counting region and line segment based on configuration.
|
61
|
+
display_output: Display processing results including frames or saved results.
|
62
|
+
process: Process method to be implemented by each Solution subclass.
|
40
63
|
|
41
64
|
Examples:
|
42
65
|
>>> solution = BaseSolution(model="yolo11n.pt", region=[(0, 0), (100, 0), (100, 100), (0, 100)])
|
@@ -46,12 +69,12 @@ class BaseSolution:
|
|
46
69
|
>>> solution.display_output(image)
|
47
70
|
"""
|
48
71
|
|
49
|
-
def __init__(self, is_cli=False, **kwargs):
|
72
|
+
def __init__(self, is_cli: bool = False, **kwargs):
|
50
73
|
"""
|
51
|
-
|
74
|
+
Initialize the BaseSolution class with configuration settings and YOLO model.
|
52
75
|
|
53
76
|
Args:
|
54
|
-
is_cli (bool):
|
77
|
+
is_cli (bool): Enable CLI mode if set to True.
|
55
78
|
**kwargs (Any): Additional configuration parameters that override defaults.
|
56
79
|
"""
|
57
80
|
self.CFG = vars(SolutionConfig().update(**kwargs))
|
@@ -75,6 +98,7 @@ class BaseSolution:
|
|
75
98
|
self.track_line = None
|
76
99
|
self.masks = None
|
77
100
|
self.r_s = None
|
101
|
+
self.frame_no = -1 # Only for logging
|
78
102
|
|
79
103
|
self.LOGGER.info(f"Ultralytics Solutions: ✅ {self.CFG}")
|
80
104
|
self.region = self.CFG["region"] # Store region data for other classes usage
|
@@ -88,9 +112,10 @@ class BaseSolution:
|
|
88
112
|
self.classes = self.CFG["classes"]
|
89
113
|
self.show_conf = self.CFG["show_conf"]
|
90
114
|
self.show_labels = self.CFG["show_labels"]
|
115
|
+
self.device = self.CFG["device"]
|
91
116
|
|
92
117
|
self.track_add_args = { # Tracker additional arguments for advance configuration
|
93
|
-
k: self.CFG[k] for k in ["iou", "conf", "device", "max_det", "half", "tracker"
|
118
|
+
k: self.CFG[k] for k in ["iou", "conf", "device", "max_det", "half", "tracker"]
|
94
119
|
} # verbose must be passed to track method; setting it False in YOLO still logs the track information.
|
95
120
|
|
96
121
|
if is_cli and self.CFG["source"] is None:
|
@@ -105,9 +130,14 @@ class BaseSolution:
|
|
105
130
|
self.env_check = check_imshow(warn=True)
|
106
131
|
self.track_history = defaultdict(list)
|
107
132
|
|
108
|
-
|
133
|
+
self.profilers = (
|
134
|
+
ops.Profile(device=self.device), # track
|
135
|
+
ops.Profile(device=self.device), # solution
|
136
|
+
)
|
137
|
+
|
138
|
+
def adjust_box_label(self, cls: int, conf: float, track_id: Optional[int] = None) -> Optional[str]:
|
109
139
|
"""
|
110
|
-
|
140
|
+
Generate a formatted label for a bounding box.
|
111
141
|
|
112
142
|
This method constructs a label string for a bounding box using the class index and confidence score.
|
113
143
|
Optionally includes the track ID if provided. The label format adapts based on the display settings
|
@@ -116,17 +146,17 @@ class BaseSolution:
|
|
116
146
|
Args:
|
117
147
|
cls (int): The class index of the detected object.
|
118
148
|
conf (float): The confidence score of the detection.
|
119
|
-
track_id (int, optional): The unique identifier for the tracked object.
|
149
|
+
track_id (int, optional): The unique identifier for the tracked object.
|
120
150
|
|
121
151
|
Returns:
|
122
|
-
(str
|
152
|
+
(str | None): The formatted label string if `self.show_labels` is True; otherwise, None.
|
123
153
|
"""
|
124
154
|
name = ("" if track_id is None else f"{track_id} ") + self.names[cls]
|
125
155
|
return (f"{name} {conf:.2f}" if self.show_conf else name) if self.show_labels else None
|
126
156
|
|
127
|
-
def extract_tracks(self, im0):
|
157
|
+
def extract_tracks(self, im0: np.ndarray):
|
128
158
|
"""
|
129
|
-
|
159
|
+
Apply object tracking and extract tracks from an input image or frame.
|
130
160
|
|
131
161
|
Args:
|
132
162
|
im0 (np.ndarray): The input image or frame.
|
@@ -136,7 +166,10 @@ class BaseSolution:
|
|
136
166
|
>>> frame = cv2.imread("path/to/image.jpg")
|
137
167
|
>>> solution.extract_tracks(frame)
|
138
168
|
"""
|
139
|
-
|
169
|
+
with self.profilers[0]:
|
170
|
+
self.tracks = self.model.track(
|
171
|
+
source=im0, persist=True, classes=self.classes, verbose=False, **self.track_add_args
|
172
|
+
)
|
140
173
|
self.track_data = self.tracks[0].obb or self.tracks[0].boxes # Extract tracks for OBB or object detection
|
141
174
|
|
142
175
|
if self.track_data and self.track_data.id is not None:
|
@@ -148,9 +181,9 @@ class BaseSolution:
|
|
148
181
|
self.LOGGER.warning("no tracks found!")
|
149
182
|
self.boxes, self.clss, self.track_ids, self.confs = [], [], [], []
|
150
183
|
|
151
|
-
def store_tracking_history(self, track_id, box
|
184
|
+
def store_tracking_history(self, track_id: int, box):
|
152
185
|
"""
|
153
|
-
|
186
|
+
Store the tracking history of an object.
|
154
187
|
|
155
188
|
This method updates the tracking history for a given object by appending the center point of its
|
156
189
|
bounding box to the track line. It maintains a maximum of 30 points in the tracking history.
|
@@ -158,7 +191,6 @@ class BaseSolution:
|
|
158
191
|
Args:
|
159
192
|
track_id (int): The unique identifier for the tracked object.
|
160
193
|
box (List[float]): The bounding box coordinates of the object in the format [x1, y1, x2, y2].
|
161
|
-
is_obb (bool): True if OBB model is used (applies to object counting only).
|
162
194
|
|
163
195
|
Examples:
|
164
196
|
>>> solution = BaseSolution()
|
@@ -166,7 +198,7 @@ class BaseSolution:
|
|
166
198
|
"""
|
167
199
|
# Store tracking history
|
168
200
|
self.track_line = self.track_history[track_id]
|
169
|
-
self.track_line.append(tuple(box.mean(dim=0)) if
|
201
|
+
self.track_line.append(tuple(box.mean(dim=0)) if box.numel() > 4 else (box[:4:2].mean(), box[1:4:2].mean()))
|
170
202
|
if len(self.track_line) > 30:
|
171
203
|
self.track_line.pop(0)
|
172
204
|
|
@@ -178,7 +210,7 @@ class BaseSolution:
|
|
178
210
|
self.Polygon(self.region) if len(self.region) >= 3 else self.LineString(self.region)
|
179
211
|
) # region or line
|
180
212
|
|
181
|
-
def display_output(self, plot_im):
|
213
|
+
def display_output(self, plot_im: np.ndarray):
|
182
214
|
"""
|
183
215
|
Display the results of the processing, which could involve showing frames, printing counts, or saving results.
|
184
216
|
|
@@ -186,7 +218,7 @@ class BaseSolution:
|
|
186
218
|
the processed frame with annotations, and allows for user interaction to close the display.
|
187
219
|
|
188
220
|
Args:
|
189
|
-
plot_im (
|
221
|
+
plot_im (np.ndarray): The image or frame that has been processed and annotated.
|
190
222
|
|
191
223
|
Examples:
|
192
224
|
>>> solution = BaseSolution()
|
@@ -209,9 +241,20 @@ class BaseSolution:
|
|
209
241
|
|
210
242
|
def __call__(self, *args, **kwargs):
|
211
243
|
"""Allow instances to be called like a function with flexible arguments."""
|
212
|
-
|
213
|
-
|
214
|
-
|
244
|
+
with self.profilers[1]:
|
245
|
+
result = self.process(*args, **kwargs) # Call the subclass-specific process method
|
246
|
+
track_or_predict = "predict" if type(self).__name__ == "ObjectCropper" else "track"
|
247
|
+
track_or_predict_speed = self.profilers[0].dt * 1e3
|
248
|
+
solution_speed = (self.profilers[1].dt - self.profilers[0].dt) * 1e3 # solution time = process - track
|
249
|
+
result.speed = {track_or_predict: track_or_predict_speed, "solution": solution_speed}
|
250
|
+
if self.CFG["verbose"]:
|
251
|
+
self.frame_no += 1
|
252
|
+
LOGGER.info(
|
253
|
+
f"{self.frame_no}: {result.plot_im.shape[0]}x{result.plot_im.shape[1]} {solution_speed:.1f}ms\n"
|
254
|
+
f"Speed: {track_or_predict_speed:.1f}ms {track_or_predict}, "
|
255
|
+
f"{solution_speed:.1f}ms solution per image at shape "
|
256
|
+
f"(1, {getattr(self.model, 'ch', 3)}, {result.plot_im.shape[0]}, {result.plot_im.shape[1]})\n"
|
257
|
+
)
|
215
258
|
return result
|
216
259
|
|
217
260
|
|
@@ -220,8 +263,8 @@ class SolutionAnnotator(Annotator):
|
|
220
263
|
A specialized annotator class for visualizing and analyzing computer vision tasks.
|
221
264
|
|
222
265
|
This class extends the base Annotator class, providing additional methods for drawing regions, centroids, tracking
|
223
|
-
trails, and visual annotations for Ultralytics Solutions
|
224
|
-
and
|
266
|
+
trails, and visual annotations for Ultralytics Solutions. It offers comprehensive visualization capabilities for
|
267
|
+
various computer vision applications including object detection, tracking, pose estimation, and analytics.
|
225
268
|
|
226
269
|
Attributes:
|
227
270
|
im (np.ndarray): The image being annotated.
|
@@ -232,19 +275,19 @@ class SolutionAnnotator(Annotator):
|
|
232
275
|
example (str): An example attribute for demonstration purposes.
|
233
276
|
|
234
277
|
Methods:
|
235
|
-
draw_region:
|
236
|
-
queue_counts_display:
|
237
|
-
display_analytics:
|
238
|
-
estimate_pose_angle:
|
239
|
-
|
240
|
-
plot_workout_information:
|
241
|
-
plot_angle_and_count_and_stage:
|
242
|
-
plot_distance_and_line:
|
243
|
-
display_objects_labels:
|
244
|
-
sweep_annotator:
|
245
|
-
visioneye:
|
246
|
-
circle_label:
|
247
|
-
text_label:
|
278
|
+
draw_region: Draw a region using specified points, colors, and thickness.
|
279
|
+
queue_counts_display: Display queue counts in the specified region.
|
280
|
+
display_analytics: Display overall statistics for parking lot management.
|
281
|
+
estimate_pose_angle: Calculate the angle between three points in an object pose.
|
282
|
+
draw_specific_kpts: Draw specific keypoints on the image.
|
283
|
+
plot_workout_information: Draw a labeled text box on the image.
|
284
|
+
plot_angle_and_count_and_stage: Visualize angle, step count, and stage for workout monitoring.
|
285
|
+
plot_distance_and_line: Display the distance between centroids and connect them with a line.
|
286
|
+
display_objects_labels: Annotate bounding boxes with object class labels.
|
287
|
+
sweep_annotator: Visualize a vertical sweep line and optional label.
|
288
|
+
visioneye: Map and connect object centroids to a visual "eye" point.
|
289
|
+
circle_label: Draw a circular label within a bounding box.
|
290
|
+
text_label: Draw a rectangular label within a bounding box.
|
248
291
|
|
249
292
|
Examples:
|
250
293
|
>>> annotator = SolutionAnnotator(image)
|
@@ -254,26 +297,39 @@ class SolutionAnnotator(Annotator):
|
|
254
297
|
... )
|
255
298
|
"""
|
256
299
|
|
257
|
-
def __init__(
|
300
|
+
def __init__(
|
301
|
+
self,
|
302
|
+
im: np.ndarray,
|
303
|
+
line_width: Optional[int] = None,
|
304
|
+
font_size: Optional[int] = None,
|
305
|
+
font: str = "Arial.ttf",
|
306
|
+
pil: bool = False,
|
307
|
+
example: str = "abc",
|
308
|
+
):
|
258
309
|
"""
|
259
|
-
|
310
|
+
Initialize the SolutionAnnotator class with an image for annotation.
|
260
311
|
|
261
312
|
Args:
|
262
313
|
im (np.ndarray): The image to be annotated.
|
263
314
|
line_width (int, optional): Line thickness for drawing on the image.
|
264
315
|
font_size (int, optional): Font size for text annotations.
|
265
|
-
font (str
|
266
|
-
pil (bool
|
267
|
-
example (str
|
316
|
+
font (str): Path to the font file.
|
317
|
+
pil (bool): Indicates whether to use PIL for rendering text.
|
318
|
+
example (str): An example parameter for demonstration purposes.
|
268
319
|
"""
|
269
320
|
super().__init__(im, line_width, font_size, font, pil, example)
|
270
321
|
|
271
|
-
def draw_region(
|
322
|
+
def draw_region(
|
323
|
+
self,
|
324
|
+
reg_pts: Optional[List[Tuple[int, int]]] = None,
|
325
|
+
color: Tuple[int, int, int] = (0, 255, 0),
|
326
|
+
thickness: int = 5,
|
327
|
+
):
|
272
328
|
"""
|
273
329
|
Draw a region or line on the image.
|
274
330
|
|
275
331
|
Args:
|
276
|
-
reg_pts (List[Tuple[int, int]]): Region points (for line 2 points, for region 4+ points).
|
332
|
+
reg_pts (List[Tuple[int, int]], optional): Region points (for line 2 points, for region 4+ points).
|
277
333
|
color (Tuple[int, int, int]): RGB color value for the region.
|
278
334
|
thickness (int): Line thickness for drawing the region.
|
279
335
|
"""
|
@@ -283,13 +339,19 @@ class SolutionAnnotator(Annotator):
|
|
283
339
|
for point in reg_pts:
|
284
340
|
cv2.circle(self.im, (point[0], point[1]), thickness * 2, color, -1) # -1 fills the circle
|
285
341
|
|
286
|
-
def queue_counts_display(
|
342
|
+
def queue_counts_display(
|
343
|
+
self,
|
344
|
+
label: str,
|
345
|
+
points: Optional[List[Tuple[int, int]]] = None,
|
346
|
+
region_color: Tuple[int, int, int] = (255, 255, 255),
|
347
|
+
txt_color: Tuple[int, int, int] = (0, 0, 0),
|
348
|
+
):
|
287
349
|
"""
|
288
|
-
|
350
|
+
Display queue counts on an image centered at the points with customizable font size and colors.
|
289
351
|
|
290
352
|
Args:
|
291
353
|
label (str): Queue counts label.
|
292
|
-
points (List[Tuple[int, int]]): Region points for center point calculation to display text.
|
354
|
+
points (List[Tuple[int, int]], optional): Region points for center point calculation to display text.
|
293
355
|
region_color (Tuple[int, int, int]): RGB queue region color.
|
294
356
|
txt_color (Tuple[int, int, int]): RGB text display color.
|
295
357
|
"""
|
@@ -323,7 +385,14 @@ class SolutionAnnotator(Annotator):
|
|
323
385
|
lineType=cv2.LINE_AA,
|
324
386
|
)
|
325
387
|
|
326
|
-
def display_analytics(
|
388
|
+
def display_analytics(
|
389
|
+
self,
|
390
|
+
im0: np.ndarray,
|
391
|
+
text: Dict[str, Any],
|
392
|
+
txt_color: Tuple[int, int, int],
|
393
|
+
bg_color: Tuple[int, int, int],
|
394
|
+
margin: int,
|
395
|
+
):
|
327
396
|
"""
|
328
397
|
Display the overall statistics for parking lots, object counter etc.
|
329
398
|
|
@@ -353,7 +422,7 @@ class SolutionAnnotator(Annotator):
|
|
353
422
|
text_y_offset = rect_y2
|
354
423
|
|
355
424
|
@staticmethod
|
356
|
-
def estimate_pose_angle(a, b, c):
|
425
|
+
def estimate_pose_angle(a: List[float], b: List[float], c: List[float]) -> float:
|
357
426
|
"""
|
358
427
|
Calculate the angle between three points for workout monitoring.
|
359
428
|
|
@@ -369,20 +438,26 @@ class SolutionAnnotator(Annotator):
|
|
369
438
|
angle = abs(radians * 180.0 / math.pi)
|
370
439
|
return angle if angle <= 180.0 else (360 - angle)
|
371
440
|
|
372
|
-
def draw_specific_kpts(
|
441
|
+
def draw_specific_kpts(
|
442
|
+
self,
|
443
|
+
keypoints: List[List[float]],
|
444
|
+
indices: Optional[List[int]] = None,
|
445
|
+
radius: int = 2,
|
446
|
+
conf_thresh: float = 0.25,
|
447
|
+
) -> np.ndarray:
|
373
448
|
"""
|
374
449
|
Draw specific keypoints for gym steps counting.
|
375
450
|
|
376
451
|
Args:
|
377
452
|
keypoints (List[List[float]]): Keypoints data to be plotted, each in format [x, y, confidence].
|
378
453
|
indices (List[int], optional): Keypoint indices to be plotted.
|
379
|
-
radius (int
|
380
|
-
conf_thresh (float
|
454
|
+
radius (int): Keypoint radius.
|
455
|
+
conf_thresh (float): Confidence threshold for keypoints.
|
381
456
|
|
382
457
|
Returns:
|
383
458
|
(np.ndarray): Image with drawn keypoints.
|
384
459
|
|
385
|
-
|
460
|
+
Notes:
|
386
461
|
Keypoint format: [x, y] or [x, y, confidence].
|
387
462
|
Modifies self.im in-place.
|
388
463
|
"""
|
@@ -399,20 +474,26 @@ class SolutionAnnotator(Annotator):
|
|
399
474
|
|
400
475
|
return self.im
|
401
476
|
|
402
|
-
def plot_workout_information(
|
477
|
+
def plot_workout_information(
|
478
|
+
self,
|
479
|
+
display_text: str,
|
480
|
+
position: Tuple[int, int],
|
481
|
+
color: Tuple[int, int, int] = (104, 31, 17),
|
482
|
+
txt_color: Tuple[int, int, int] = (255, 255, 255),
|
483
|
+
) -> int:
|
403
484
|
"""
|
404
485
|
Draw workout text with a background on the image.
|
405
486
|
|
406
487
|
Args:
|
407
488
|
display_text (str): The text to be displayed.
|
408
489
|
position (Tuple[int, int]): Coordinates (x, y) on the image where the text will be placed.
|
409
|
-
color (Tuple[int, int, int]
|
410
|
-
txt_color (Tuple[int, int, int]
|
490
|
+
color (Tuple[int, int, int]): Text background color.
|
491
|
+
txt_color (Tuple[int, int, int]): Text foreground color.
|
411
492
|
|
412
493
|
Returns:
|
413
494
|
(int): The height of the text.
|
414
495
|
"""
|
415
|
-
(text_width, text_height), _ = cv2.getTextSize(display_text, 0, self.sf, self.tf)
|
496
|
+
(text_width, text_height), _ = cv2.getTextSize(display_text, 0, fontScale=self.sf, thickness=self.tf)
|
416
497
|
|
417
498
|
# Draw background rectangle
|
418
499
|
cv2.rectangle(
|
@@ -428,7 +509,13 @@ class SolutionAnnotator(Annotator):
|
|
428
509
|
return text_height
|
429
510
|
|
430
511
|
def plot_angle_and_count_and_stage(
|
431
|
-
self,
|
512
|
+
self,
|
513
|
+
angle_text: str,
|
514
|
+
count_text: str,
|
515
|
+
stage_text: str,
|
516
|
+
center_kpt: List[int],
|
517
|
+
color: Tuple[int, int, int] = (104, 31, 17),
|
518
|
+
txt_color: Tuple[int, int, int] = (255, 255, 255),
|
432
519
|
):
|
433
520
|
"""
|
434
521
|
Plot the pose angle, count value, and step stage for workout monitoring.
|
@@ -438,8 +525,8 @@ class SolutionAnnotator(Annotator):
|
|
438
525
|
count_text (str): Counts value for workout monitoring.
|
439
526
|
stage_text (str): Stage decision for workout monitoring.
|
440
527
|
center_kpt (List[int]): Centroid pose index for workout monitoring.
|
441
|
-
color (Tuple[int, int, int]
|
442
|
-
txt_color (Tuple[int, int, int]
|
528
|
+
color (Tuple[int, int, int]): Text background color.
|
529
|
+
txt_color (Tuple[int, int, int]): Text foreground color.
|
443
530
|
"""
|
444
531
|
# Format text
|
445
532
|
angle_text, count_text, stage_text = f" {angle_text:.2f}", f"Steps : {count_text}", f" {stage_text}"
|
@@ -456,7 +543,11 @@ class SolutionAnnotator(Annotator):
|
|
456
543
|
)
|
457
544
|
|
458
545
|
def plot_distance_and_line(
|
459
|
-
self,
|
546
|
+
self,
|
547
|
+
pixels_distance: float,
|
548
|
+
centroids: List[Tuple[int, int]],
|
549
|
+
line_color: Tuple[int, int, int] = (104, 31, 17),
|
550
|
+
centroid_color: Tuple[int, int, int] = (255, 0, 255),
|
460
551
|
):
|
461
552
|
"""
|
462
553
|
Plot the distance and line between two centroids on the frame.
|
@@ -464,8 +555,8 @@ class SolutionAnnotator(Annotator):
|
|
464
555
|
Args:
|
465
556
|
pixels_distance (float): Pixels distance between two bbox centroids.
|
466
557
|
centroids (List[Tuple[int, int]]): Bounding box centroids data.
|
467
|
-
line_color (Tuple[int, int, int]
|
468
|
-
centroid_color (Tuple[int, int, int]
|
558
|
+
line_color (Tuple[int, int, int]): Distance line color.
|
559
|
+
centroid_color (Tuple[int, int, int]): Bounding box centroid color.
|
469
560
|
"""
|
470
561
|
# Get the text size
|
471
562
|
text = f"Pixels Distance: {pixels_distance:.2f}"
|
@@ -491,7 +582,16 @@ class SolutionAnnotator(Annotator):
|
|
491
582
|
cv2.circle(self.im, centroids[0], 6, centroid_color, -1)
|
492
583
|
cv2.circle(self.im, centroids[1], 6, centroid_color, -1)
|
493
584
|
|
494
|
-
def display_objects_labels(
|
585
|
+
def display_objects_labels(
|
586
|
+
self,
|
587
|
+
im0: np.ndarray,
|
588
|
+
text: str,
|
589
|
+
txt_color: Tuple[int, int, int],
|
590
|
+
bg_color: Tuple[int, int, int],
|
591
|
+
x_center: float,
|
592
|
+
y_center: float,
|
593
|
+
margin: int,
|
594
|
+
):
|
495
595
|
"""
|
496
596
|
Display the bounding boxes labels in parking management app.
|
497
597
|
|
@@ -531,7 +631,14 @@ class SolutionAnnotator(Annotator):
|
|
531
631
|
lineType=cv2.LINE_AA,
|
532
632
|
)
|
533
633
|
|
534
|
-
def sweep_annotator(
|
634
|
+
def sweep_annotator(
|
635
|
+
self,
|
636
|
+
line_x: int = 0,
|
637
|
+
line_y: int = 0,
|
638
|
+
label: Optional[str] = None,
|
639
|
+
color: Tuple[int, int, int] = (221, 0, 186),
|
640
|
+
txt_color: Tuple[int, int, int] = (255, 255, 255),
|
641
|
+
):
|
535
642
|
"""
|
536
643
|
Draw a sweep annotation line and an optional label.
|
537
644
|
|
@@ -565,7 +672,13 @@ class SolutionAnnotator(Annotator):
|
|
565
672
|
self.tf,
|
566
673
|
)
|
567
674
|
|
568
|
-
def visioneye(
|
675
|
+
def visioneye(
|
676
|
+
self,
|
677
|
+
box: List[float],
|
678
|
+
center_point: Tuple[int, int],
|
679
|
+
color: Tuple[int, int, int] = (235, 219, 11),
|
680
|
+
pin_color: Tuple[int, int, int] = (255, 0, 255),
|
681
|
+
):
|
569
682
|
"""
|
570
683
|
Perform pinpoint human-vision eye mapping and plotting.
|
571
684
|
|
@@ -580,7 +693,14 @@ class SolutionAnnotator(Annotator):
|
|
580
693
|
cv2.circle(self.im, center_bbox, self.tf * 2, color, -1)
|
581
694
|
cv2.line(self.im, center_point, center_bbox, color, self.tf)
|
582
695
|
|
583
|
-
def circle_label(
|
696
|
+
def circle_label(
|
697
|
+
self,
|
698
|
+
box: Tuple[float, float, float, float],
|
699
|
+
label: str = "",
|
700
|
+
color: Tuple[int, int, int] = (128, 128, 128),
|
701
|
+
txt_color: Tuple[int, int, int] = (255, 255, 255),
|
702
|
+
margin: int = 2,
|
703
|
+
):
|
584
704
|
"""
|
585
705
|
Draw a label with a background circle centered within a given bounding box.
|
586
706
|
|
@@ -618,7 +738,14 @@ class SolutionAnnotator(Annotator):
|
|
618
738
|
lineType=cv2.LINE_AA,
|
619
739
|
)
|
620
740
|
|
621
|
-
def text_label(
|
741
|
+
def text_label(
|
742
|
+
self,
|
743
|
+
box: Tuple[float, float, float, float],
|
744
|
+
label: str = "",
|
745
|
+
color: Tuple[int, int, int] = (128, 128, 128),
|
746
|
+
txt_color: Tuple[int, int, int] = (255, 255, 255),
|
747
|
+
margin: int = 5,
|
748
|
+
):
|
622
749
|
"""
|
623
750
|
Draw a label with a background rectangle centered within a given bounding box.
|
624
751
|
|
@@ -661,7 +788,8 @@ class SolutionResults:
|
|
661
788
|
A class to encapsulate the results of Ultralytics Solutions.
|
662
789
|
|
663
790
|
This class is designed to store and manage various outputs generated by the solution pipeline, including counts,
|
664
|
-
angles, and
|
791
|
+
angles, workout stages, and other analytics data. It provides a structured way to access and manipulate results
|
792
|
+
from different computer vision solutions such as object counting, pose estimation, and tracking analytics.
|
665
793
|
|
666
794
|
Attributes:
|
667
795
|
plot_im (np.ndarray): Processed image with counts, blurred, or other effects from solutions.
|
@@ -677,9 +805,10 @@ class SolutionResults:
|
|
677
805
|
filled_slots (int): The number of filled slots in a monitored area.
|
678
806
|
email_sent (bool): A flag indicating whether an email notification was sent.
|
679
807
|
total_tracks (int): The total number of tracked objects.
|
680
|
-
region_counts (
|
808
|
+
region_counts (Dict): The count of objects within a specific region.
|
681
809
|
speed_dict (Dict[str, float]): A dictionary containing speed information for tracked objects.
|
682
810
|
total_crop_objects (int): Total number of cropped objects using ObjectCropper class.
|
811
|
+
speed (Dict): Performance timing information for tracking and solution processing.
|
683
812
|
"""
|
684
813
|
|
685
814
|
def __init__(self, **kwargs):
|
@@ -703,13 +832,14 @@ class SolutionResults:
|
|
703
832
|
self.email_sent = False
|
704
833
|
self.total_tracks = 0
|
705
834
|
self.region_counts = {}
|
706
|
-
self.speed_dict = {}
|
835
|
+
self.speed_dict = {} # for speed estimation
|
707
836
|
self.total_crop_objects = 0
|
837
|
+
self.speed = {}
|
708
838
|
|
709
839
|
# Override with user-defined values
|
710
840
|
self.__dict__.update(kwargs)
|
711
841
|
|
712
|
-
def __str__(self):
|
842
|
+
def __str__(self) -> str:
|
713
843
|
"""
|
714
844
|
Return a formatted string representation of the SolutionResults object.
|
715
845
|
|
@@ -721,4 +851,4 @@ class SolutionResults:
|
|
721
851
|
for k, v in self.__dict__.items()
|
722
852
|
if k != "plot_im" and v not in [None, {}, 0, 0.0, False] # Exclude `plot_im` explicitly
|
723
853
|
}
|
724
|
-
return
|
854
|
+
return ", ".join(f"{k}={v}" for k, v in attrs.items())
|