dgenerate-ultralytics-headless 8.3.141__py3-none-any.whl → 8.3.143__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.141.dist-info → dgenerate_ultralytics_headless-8.3.143.dist-info}/METADATA +1 -1
- {dgenerate_ultralytics_headless-8.3.141.dist-info → dgenerate_ultralytics_headless-8.3.143.dist-info}/RECORD +15 -15
- tests/test_solutions.py +1 -1
- ultralytics/__init__.py +1 -1
- ultralytics/cfg/__init__.py +6 -6
- ultralytics/engine/results.py +0 -1
- ultralytics/solutions/distance_calculation.py +2 -1
- ultralytics/solutions/object_counter.py +3 -5
- ultralytics/solutions/object_cropper.py +9 -3
- ultralytics/solutions/solutions.py +32 -11
- ultralytics/utils/plotting.py +14 -16
- {dgenerate_ultralytics_headless-8.3.141.dist-info → dgenerate_ultralytics_headless-8.3.143.dist-info}/WHEEL +0 -0
- {dgenerate_ultralytics_headless-8.3.141.dist-info → dgenerate_ultralytics_headless-8.3.143.dist-info}/entry_points.txt +0 -0
- {dgenerate_ultralytics_headless-8.3.141.dist-info → dgenerate_ultralytics_headless-8.3.143.dist-info}/licenses/LICENSE +0 -0
- {dgenerate_ultralytics_headless-8.3.141.dist-info → dgenerate_ultralytics_headless-8.3.143.dist-info}/top_level.txt +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: dgenerate-ultralytics-headless
|
3
|
-
Version: 8.3.
|
3
|
+
Version: 8.3.143
|
4
4
|
Summary: Automatically built Ultralytics package with python-opencv-headless dependency instead of python-opencv
|
5
5
|
Author-email: Glenn Jocher <glenn.jocher@ultralytics.com>, Jing Qiu <jing.qiu@ultralytics.com>
|
6
6
|
Maintainer-email: Ultralytics <hello@ultralytics.com>
|
@@ -1,4 +1,4 @@
|
|
1
|
-
dgenerate_ultralytics_headless-8.3.
|
1
|
+
dgenerate_ultralytics_headless-8.3.143.dist-info/licenses/LICENSE,sha256=DZak_2itbUtvHzD3E7GNUYSRK6jdOJ-GqncQ2weavLA,34523
|
2
2
|
tests/__init__.py,sha256=xnMhv3O_DF1YrW4zk__ZywQzAaoTDjPKPoiI1Ktss1w,670
|
3
3
|
tests/conftest.py,sha256=rsIAipRKfrVNoTaJ1LdpYue8AbcJ_fr3d3WIlM_6uXY,2982
|
4
4
|
tests/test_cli.py,sha256=vXUC_EK0fa87JRhHsCOZf7AJQ5_Jm1sL8u-yhmsaQh0,5851
|
@@ -7,11 +7,11 @@ tests/test_engine.py,sha256=aGqZ8P7QO5C_nOa1b4FOyk92Ysdk5WiP-ST310Vyxys,4962
|
|
7
7
|
tests/test_exports.py,sha256=dhZn86LdbapW15RthQF870LGxDjC1MUZhlGdBgPmgIQ,9716
|
8
8
|
tests/test_integrations.py,sha256=dQteeRsRVuT_p5-T88-7jqT65Zm9iAXkyKg-KQ1_TQ8,6341
|
9
9
|
tests/test_python.py,sha256=Zx9OlPN11_D1WSLpi9nPFqORNHNz0lEn6mxVNL2ZHjE,25852
|
10
|
-
tests/test_solutions.py,sha256=
|
11
|
-
ultralytics/__init__.py,sha256=
|
10
|
+
tests/test_solutions.py,sha256=4TryDaWOeY3HF33RZuYe9ofUZhgQrp4_nFI8tPUdiOc,13080
|
11
|
+
ultralytics/__init__.py,sha256=XEt2XO7rEliN-Fgis0qJ7S8kTmeX8cMWBWgI0jROIRY,730
|
12
12
|
ultralytics/assets/bus.jpg,sha256=wCAZxJecGR63Od3ZRERe9Aja1Weayrb9Ug751DS_vGM,137419
|
13
13
|
ultralytics/assets/zidane.jpg,sha256=Ftc4aeMmen1O0A3o6GCDO9FlfBslLpTAw0gnetx7bts,50427
|
14
|
-
ultralytics/cfg/__init__.py,sha256=
|
14
|
+
ultralytics/cfg/__init__.py,sha256=nDPCpYipxJ5XLjwwaoB5DNbovbOH-GM26_e2G5jDQ28,39580
|
15
15
|
ultralytics/cfg/default.yaml,sha256=oFG6llJO-Py5H-cR9qs-7FieJamroDLwpbrkhmfROOM,8307
|
16
16
|
ultralytics/cfg/datasets/Argoverse.yaml,sha256=_xlEDIJ9XkUo0v_iNL7FW079BoSeZtKSuLteKTtGbA8,3275
|
17
17
|
ultralytics/cfg/datasets/DOTAv1.5.yaml,sha256=SHND_CFkojxw5iQD5Mcgju2kCZIl0gW2ajuzv1cqoL0,1224
|
@@ -122,7 +122,7 @@ ultralytics/engine/__init__.py,sha256=lm6MckFYCPTbqIoX7w0s_daxdjNeBeKW6DXppv1-QU
|
|
122
122
|
ultralytics/engine/exporter.py,sha256=BZWa7Mnl1BPvbPiD-RJs6M5Bca4sm3_MQgjoHesvXEs,70949
|
123
123
|
ultralytics/engine/model.py,sha256=6AhrrcuLOQk_JuOAPQt3uNktAhEBWcBBh_AP2DGEbAs,53147
|
124
124
|
ultralytics/engine/predictor.py,sha256=rZ5mIPeejkxUerpTfUf_1rSAklOR3THqoejlil4C04w,21651
|
125
|
-
ultralytics/engine/results.py,sha256=
|
125
|
+
ultralytics/engine/results.py,sha256=BOpn7RihPt8OUpdklWs1iL3LCxVXOiynPGpaR_MPToQ,70036
|
126
126
|
ultralytics/engine/trainer.py,sha256=xdgNAgq6umJ6915tiCK3U22NeY7w1HnvmAhXlwS_hYI,38955
|
127
127
|
ultralytics/engine/tuner.py,sha256=zEW1UpLlZ6N4xbvS7MxICkshRlaFgLNfuADA0VfRpao,12629
|
128
128
|
ultralytics/engine/validator.py,sha256=f9UUv3QqQStLrO1nojrHkdS58qYQxKXaoIQQria6WyA,17054
|
@@ -208,18 +208,18 @@ ultralytics/solutions/__init__.py,sha256=ZoeAQavTLp8aClnhZ9tbl6lxy86GxofyGvZWTx2
|
|
208
208
|
ultralytics/solutions/ai_gym.py,sha256=QRTFwuD0g9KJgAjqdww4OeitXm-hsyXL1pJlrAhTyqA,5347
|
209
209
|
ultralytics/solutions/analytics.py,sha256=u-khRAViGupjq9mkuAFCl9G3yE8hXfXASfKZd_SQZ-8,12111
|
210
210
|
ultralytics/solutions/config.py,sha256=TLxQuZjqW-vhbS2OFmTT188-31ukHg1XP7l-BeOmqbU,5427
|
211
|
-
ultralytics/solutions/distance_calculation.py,sha256=
|
211
|
+
ultralytics/solutions/distance_calculation.py,sha256=JyB1KC1WihwGLFX2R2kk4QEvo8Qm0f3CD8fYqchzmfU,5807
|
212
212
|
ultralytics/solutions/heatmap.py,sha256=0Hw2Vhg4heglpnbNkM-RiGrQOkvgYbPRf4x8x4-zTjg,5418
|
213
213
|
ultralytics/solutions/instance_segmentation.py,sha256=IuAxxEkKrbTPHmD0jV3VEjNWpBc78o8exg00nE0ldeQ,3558
|
214
214
|
ultralytics/solutions/object_blurrer.py,sha256=-wXOdqqZisVhxLutZz7JvZmdgVGmsN7Ymary0JHc2qo,3946
|
215
|
-
ultralytics/solutions/object_counter.py,sha256=
|
216
|
-
ultralytics/solutions/object_cropper.py,sha256=
|
215
|
+
ultralytics/solutions/object_counter.py,sha256=49ixmy1OPv5D3CZmsZWQCigJstQvYIdK5aHypNBsZg8,9519
|
216
|
+
ultralytics/solutions/object_cropper.py,sha256=s56XQMpgCgeQg9KEZs2_7_cP_V-eH6315cY1bxt2oGs,3456
|
217
217
|
ultralytics/solutions/parking_management.py,sha256=BV-2lpSfgmK7fib3DnPSZ5rtLdy11c8pBQm-72iTetc,13289
|
218
218
|
ultralytics/solutions/queue_management.py,sha256=p1-cuI_rs4ygtlBryXjE65NYG2bnZXhp3ylggFnWcRs,4344
|
219
219
|
ultralytics/solutions/region_counter.py,sha256=Zn35YRXNzhBk27D9MLOHBYe2L1o6H2ey3mEwCXofB_E,5418
|
220
220
|
ultralytics/solutions/security_alarm.py,sha256=JdkQUjqJl3iCd2MLVYkh1L7askvhi3_gp0RLXG6s390,6247
|
221
221
|
ultralytics/solutions/similarity_search.py,sha256=NVjrlxWStXPhSaE_tGW0g1_j8vD0evaT9IjGOHYERFg,7323
|
222
|
-
ultralytics/solutions/solutions.py,sha256=
|
222
|
+
ultralytics/solutions/solutions.py,sha256=zJ7CZh2U2VEUWe5LfC3XhVuc_HGOAQeHPM8ls3cmiZU,33681
|
223
223
|
ultralytics/solutions/speed_estimation.py,sha256=r7S5nGIx8PTV-zC4zCI36lQD2DVy5cen5cTXItfQIHo,5318
|
224
224
|
ultralytics/solutions/streamlit_inference.py,sha256=p1bBKTtmvB6zStXdOzS0CGYurm4zu82WKii5rJriizA,9849
|
225
225
|
ultralytics/solutions/trackzone.py,sha256=mfklnZcVRqI3bbhPiHF2iSoV6INcd10wwwGP4tlK7L0,3854
|
@@ -249,7 +249,7 @@ ultralytics/utils/loss.py,sha256=KMug5vHESghC3B3V5Vi-fhGVDdTjG9nGkGJmgO_WnPI,375
|
|
249
249
|
ultralytics/utils/metrics.py,sha256=8x4S7y-rBKRkM47f_o7jfMHA1Bz8SDq3t-R1FXlQNEM,59267
|
250
250
|
ultralytics/utils/ops.py,sha256=YFwPrKlPcgEmgAWqnJVR0Ccx5NQgp5e3P-YYHwVSP0k,34779
|
251
251
|
ultralytics/utils/patches.py,sha256=_dhIU_eDklQE-aWIjpyjPHl_wOwZoGuIUQnXgdSwk_A,5020
|
252
|
-
ultralytics/utils/plotting.py,sha256=
|
252
|
+
ultralytics/utils/plotting.py,sha256=WAWTGQAsM-cWy08QmcYOXrzFMHd24i8deYTed_u4kbg,47027
|
253
253
|
ultralytics/utils/tal.py,sha256=fkOdogPqPBUN07ThixpI8X7hea-oEfTIaaBLc26_O2s,20610
|
254
254
|
ultralytics/utils/torch_utils.py,sha256=WGNxGocstHD6ljhvujSCWjsYd4xWjNIXk_pq53zcKCc,39675
|
255
255
|
ultralytics/utils/triton.py,sha256=9P2rlQcGCTMFVKLA5S5mTYzU9cKbR5HF9ruVkPpVBE8,5307
|
@@ -265,8 +265,8 @@ ultralytics/utils/callbacks/neptune.py,sha256=yYUgEgSv6L39sSev6vjwhAWU3DlPDsbSDV
|
|
265
265
|
ultralytics/utils/callbacks/raytune.py,sha256=A8amUGpux7dYES-L1iSeMoMXBySGWCD1aUqT7vcG-pU,1284
|
266
266
|
ultralytics/utils/callbacks/tensorboard.py,sha256=jgYnym3cUQFAgN1GzTyO7l3jINtfAh8zhrllDvnLuVQ,5339
|
267
267
|
ultralytics/utils/callbacks/wb.py,sha256=iDRFXI4IIDm8R5OI89DMTmjs8aHLo1HRCLkOFKdaMG4,7507
|
268
|
-
dgenerate_ultralytics_headless-8.3.
|
269
|
-
dgenerate_ultralytics_headless-8.3.
|
270
|
-
dgenerate_ultralytics_headless-8.3.
|
271
|
-
dgenerate_ultralytics_headless-8.3.
|
272
|
-
dgenerate_ultralytics_headless-8.3.
|
268
|
+
dgenerate_ultralytics_headless-8.3.143.dist-info/METADATA,sha256=wqUmvH5KB1dRscjqNnjTtPutbgrLN7uYxR4GhovGWfw,38296
|
269
|
+
dgenerate_ultralytics_headless-8.3.143.dist-info/WHEEL,sha256=zaaOINJESkSfm_4HQVc5ssNzHCPXhJm0kEUakpsEHaU,91
|
270
|
+
dgenerate_ultralytics_headless-8.3.143.dist-info/entry_points.txt,sha256=YM_wiKyTe9yRrsEfqvYolNO5ngwfoL4-NwgKzc8_7sI,93
|
271
|
+
dgenerate_ultralytics_headless-8.3.143.dist-info/top_level.txt,sha256=XP49TwiMw4QGsvTLSYiJhz1xF_k7ev5mQ8jJXaXi45Q,12
|
272
|
+
dgenerate_ultralytics_headless-8.3.143.dist-info/RECORD,,
|
tests/test_solutions.py
CHANGED
@@ -245,7 +245,7 @@ def test_analytics_graph_not_supported():
|
|
245
245
|
"""Test that unsupported analytics type raises ModuleNotFoundError."""
|
246
246
|
try:
|
247
247
|
analytics = solutions.Analytics(analytics_type="test") # 'test' is unsupported
|
248
|
-
analytics.process(im0=
|
248
|
+
analytics.process(im0=np.zeros((640, 480, 3), dtype=np.uint8), frame_number=0)
|
249
249
|
assert False, "Expected ModuleNotFoundError for unsupported chart type"
|
250
250
|
except ModuleNotFoundError as e:
|
251
251
|
assert "test chart is not supported" in str(e)
|
ultralytics/__init__.py
CHANGED
ultralytics/cfg/__init__.py
CHANGED
@@ -108,8 +108,8 @@ CLI_HELP_MSG = f"""
|
|
108
108
|
|
109
109
|
yolo TASK MODE ARGS
|
110
110
|
|
111
|
-
Where TASK (optional) is one of {TASKS}
|
112
|
-
MODE (required) is one of {MODES}
|
111
|
+
Where TASK (optional) is one of {list(TASKS)}
|
112
|
+
MODE (required) is one of {list(MODES)}
|
113
113
|
ARGS (optional) are any number of custom 'arg=value' pairs like 'imgsz=320' that override defaults.
|
114
114
|
See all ARGS at https://docs.ultralytics.com/usage/cfg or with 'yolo cfg'
|
115
115
|
|
@@ -909,9 +909,9 @@ def entrypoint(debug: str = "") -> None:
|
|
909
909
|
mode = overrides.get("mode")
|
910
910
|
if mode is None:
|
911
911
|
mode = DEFAULT_CFG.mode or "predict"
|
912
|
-
LOGGER.warning(f"'mode' argument is missing. Valid modes are {MODES}. Using default 'mode={mode}'.")
|
912
|
+
LOGGER.warning(f"'mode' argument is missing. Valid modes are {list(MODES)}. Using default 'mode={mode}'.")
|
913
913
|
elif mode not in MODES:
|
914
|
-
raise ValueError(f"Invalid 'mode={mode}'. Valid modes are {MODES}.\n{CLI_HELP_MSG}")
|
914
|
+
raise ValueError(f"Invalid 'mode={mode}'. Valid modes are {list(MODES)}.\n{CLI_HELP_MSG}")
|
915
915
|
|
916
916
|
# Task
|
917
917
|
task = overrides.pop("task", None)
|
@@ -919,11 +919,11 @@ def entrypoint(debug: str = "") -> None:
|
|
919
919
|
if task not in TASKS:
|
920
920
|
if task == "track":
|
921
921
|
LOGGER.warning(
|
922
|
-
f"invalid 'task=track', setting 'task=detect' and 'mode=track'. Valid tasks are {TASKS}.\n{CLI_HELP_MSG}."
|
922
|
+
f"invalid 'task=track', setting 'task=detect' and 'mode=track'. Valid tasks are {list(TASKS)}.\n{CLI_HELP_MSG}."
|
923
923
|
)
|
924
924
|
task, mode = "detect", "track"
|
925
925
|
else:
|
926
|
-
raise ValueError(f"Invalid 'task={task}'. Valid tasks are {TASKS}.\n{CLI_HELP_MSG}")
|
926
|
+
raise ValueError(f"Invalid 'task={task}'. Valid tasks are {list(TASKS)}.\n{CLI_HELP_MSG}")
|
927
927
|
if "model" not in overrides:
|
928
928
|
overrides["model"] = TASK2MODEL[task]
|
929
929
|
|
ultralytics/engine/results.py
CHANGED
@@ -118,7 +118,8 @@ class DistanceCalculation(BaseSolution):
|
|
118
118
|
self.centroids = [] # Reset centroids for next frame
|
119
119
|
plot_im = annotator.result()
|
120
120
|
self.display_output(plot_im) # Display output with base class function
|
121
|
-
|
121
|
+
if self.CFG.get("show") and self.env_check:
|
122
|
+
cv2.setMouseCallback("Ultralytics Solutions", self.mouse_event_for_distance)
|
122
123
|
|
123
124
|
# Return SolutionResults with processed image and calculated metrics
|
124
125
|
return SolutionResults(plot_im=plot_im, pixels_distance=pixels_distance, total_tracks=len(self.track_ids))
|
@@ -160,7 +160,7 @@ class ObjectCounter(BaseSolution):
|
|
160
160
|
self.annotator = SolutionAnnotator(im0, line_width=self.line_width) # Initialize annotator
|
161
161
|
|
162
162
|
is_obb = getattr(self.tracks[0], "obb", None) is not None # True if OBB results exist
|
163
|
-
if is_obb:
|
163
|
+
if is_obb and self.track_data and self.track_data.id is not None:
|
164
164
|
self.boxes = self.track_data.xyxyxyxy.reshape(-1, 4, 2).cpu()
|
165
165
|
|
166
166
|
self.annotator.draw_region(
|
@@ -170,10 +170,8 @@ class ObjectCounter(BaseSolution):
|
|
170
170
|
# Iterate over bounding boxes, track ids and classes index
|
171
171
|
for box, track_id, cls, conf in zip(self.boxes, self.track_ids, self.clss, self.confs):
|
172
172
|
# Draw bounding box and counting region
|
173
|
-
self.annotator.box_label(
|
174
|
-
|
175
|
-
)
|
176
|
-
self.store_tracking_history(track_id, box, is_obb=is_obb) # Store track history
|
173
|
+
self.annotator.box_label(box, label=self.adjust_box_label(cls, conf, track_id), color=colors(cls, True))
|
174
|
+
self.store_tracking_history(track_id, box) # Store track history
|
177
175
|
|
178
176
|
# Store previous position of track for object counting
|
179
177
|
prev_position = None
|
@@ -67,9 +67,15 @@ class ObjectCropper(BaseSolution):
|
|
67
67
|
>>> results = cropper.process(frame)
|
68
68
|
>>> print(f"Total cropped objects: {results.total_crop_objects}")
|
69
69
|
"""
|
70
|
-
|
71
|
-
|
72
|
-
|
70
|
+
with self.profilers[0]:
|
71
|
+
results = self.model.predict(
|
72
|
+
im0,
|
73
|
+
classes=self.classes,
|
74
|
+
conf=self.conf,
|
75
|
+
iou=self.iou,
|
76
|
+
device=self.CFG["device"],
|
77
|
+
verbose=False,
|
78
|
+
)[0]
|
73
79
|
|
74
80
|
for box in results.boxes:
|
75
81
|
self.crop_idx += 1
|
@@ -8,7 +8,7 @@ import numpy as np
|
|
8
8
|
|
9
9
|
from ultralytics import YOLO
|
10
10
|
from ultralytics.solutions.config import SolutionConfig
|
11
|
-
from ultralytics.utils import ASSETS_URL, LOGGER
|
11
|
+
from ultralytics.utils import ASSETS_URL, LOGGER, ops
|
12
12
|
from ultralytics.utils.checks import check_imshow, check_requirements
|
13
13
|
from ultralytics.utils.plotting import Annotator
|
14
14
|
|
@@ -75,6 +75,7 @@ class BaseSolution:
|
|
75
75
|
self.track_line = None
|
76
76
|
self.masks = None
|
77
77
|
self.r_s = None
|
78
|
+
self.frame_no = -1 # Only for logging
|
78
79
|
|
79
80
|
self.LOGGER.info(f"Ultralytics Solutions: ✅ {self.CFG}")
|
80
81
|
self.region = self.CFG["region"] # Store region data for other classes usage
|
@@ -88,9 +89,10 @@ class BaseSolution:
|
|
88
89
|
self.classes = self.CFG["classes"]
|
89
90
|
self.show_conf = self.CFG["show_conf"]
|
90
91
|
self.show_labels = self.CFG["show_labels"]
|
92
|
+
self.device = self.CFG["device"]
|
91
93
|
|
92
94
|
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"
|
95
|
+
k: self.CFG[k] for k in ["iou", "conf", "device", "max_det", "half", "tracker"]
|
94
96
|
} # verbose must be passed to track method; setting it False in YOLO still logs the track information.
|
95
97
|
|
96
98
|
if is_cli and self.CFG["source"] is None:
|
@@ -105,6 +107,11 @@ class BaseSolution:
|
|
105
107
|
self.env_check = check_imshow(warn=True)
|
106
108
|
self.track_history = defaultdict(list)
|
107
109
|
|
110
|
+
self.profilers = (
|
111
|
+
ops.Profile(device=self.device), # track
|
112
|
+
ops.Profile(device=self.device), # solution
|
113
|
+
)
|
114
|
+
|
108
115
|
def adjust_box_label(self, cls, conf, track_id=None):
|
109
116
|
"""
|
110
117
|
Generates a formatted label for a bounding box.
|
@@ -136,7 +143,10 @@ class BaseSolution:
|
|
136
143
|
>>> frame = cv2.imread("path/to/image.jpg")
|
137
144
|
>>> solution.extract_tracks(frame)
|
138
145
|
"""
|
139
|
-
|
146
|
+
with self.profilers[0]:
|
147
|
+
self.tracks = self.model.track(
|
148
|
+
source=im0, persist=True, classes=self.classes, verbose=False, **self.track_add_args
|
149
|
+
)
|
140
150
|
self.track_data = self.tracks[0].obb or self.tracks[0].boxes # Extract tracks for OBB or object detection
|
141
151
|
|
142
152
|
if self.track_data and self.track_data.id is not None:
|
@@ -148,7 +158,7 @@ class BaseSolution:
|
|
148
158
|
self.LOGGER.warning("no tracks found!")
|
149
159
|
self.boxes, self.clss, self.track_ids, self.confs = [], [], [], []
|
150
160
|
|
151
|
-
def store_tracking_history(self, track_id, box
|
161
|
+
def store_tracking_history(self, track_id, box):
|
152
162
|
"""
|
153
163
|
Stores the tracking history of an object.
|
154
164
|
|
@@ -158,7 +168,6 @@ class BaseSolution:
|
|
158
168
|
Args:
|
159
169
|
track_id (int): The unique identifier for the tracked object.
|
160
170
|
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
171
|
|
163
172
|
Examples:
|
164
173
|
>>> solution = BaseSolution()
|
@@ -166,7 +175,7 @@ class BaseSolution:
|
|
166
175
|
"""
|
167
176
|
# Store tracking history
|
168
177
|
self.track_line = self.track_history[track_id]
|
169
|
-
self.track_line.append(tuple(box.mean(dim=0)) if
|
178
|
+
self.track_line.append(tuple(box.mean(dim=0)) if box.numel() > 4 else (box[:4:2].mean(), box[1:4:2].mean()))
|
170
179
|
if len(self.track_line) > 30:
|
171
180
|
self.track_line.pop(0)
|
172
181
|
|
@@ -209,9 +218,20 @@ class BaseSolution:
|
|
209
218
|
|
210
219
|
def __call__(self, *args, **kwargs):
|
211
220
|
"""Allow instances to be called like a function with flexible arguments."""
|
212
|
-
|
213
|
-
|
214
|
-
|
221
|
+
with self.profilers[1]:
|
222
|
+
result = self.process(*args, **kwargs) # Call the subclass-specific process method
|
223
|
+
track_or_predict = "predict" if type(self).__name__ == "ObjectCropper" else "track"
|
224
|
+
track_or_predict_speed = self.profilers[0].dt * 1e3
|
225
|
+
solution_speed = (self.profilers[1].dt - self.profilers[0].dt) * 1e3 # solution time = process - track
|
226
|
+
result.speed = {track_or_predict: track_or_predict_speed, "solution": solution_speed}
|
227
|
+
if self.CFG["verbose"]:
|
228
|
+
self.frame_no += 1
|
229
|
+
LOGGER.info(
|
230
|
+
f"{self.frame_no}: {result.plot_im.shape[0]}x{result.plot_im.shape[1]} {solution_speed:.1f}ms\n"
|
231
|
+
f"Speed: {track_or_predict_speed:.1f}ms {track_or_predict}, "
|
232
|
+
f"{solution_speed:.1f}ms solution per image at shape "
|
233
|
+
f"(1, {getattr(self.model, 'ch', 3)}, {result.plot_im.shape[0]}, {result.plot_im.shape[1]})\n"
|
234
|
+
)
|
215
235
|
return result
|
216
236
|
|
217
237
|
|
@@ -703,8 +723,9 @@ class SolutionResults:
|
|
703
723
|
self.email_sent = False
|
704
724
|
self.total_tracks = 0
|
705
725
|
self.region_counts = {}
|
706
|
-
self.speed_dict = {}
|
726
|
+
self.speed_dict = {} # for speed estimation
|
707
727
|
self.total_crop_objects = 0
|
728
|
+
self.speed = {}
|
708
729
|
|
709
730
|
# Override with user-defined values
|
710
731
|
self.__dict__.update(kwargs)
|
@@ -721,4 +742,4 @@ class SolutionResults:
|
|
721
742
|
for k, v in self.__dict__.items()
|
722
743
|
if k != "plot_im" and v not in [None, {}, 0, 0.0, False] # Exclude `plot_im` explicitly
|
723
744
|
}
|
724
|
-
return
|
745
|
+
return ", ".join(f"{k}={v}" for k, v in attrs.items())
|
ultralytics/utils/plotting.py
CHANGED
@@ -278,7 +278,7 @@ class Annotator:
|
|
278
278
|
else:
|
279
279
|
return txt_color
|
280
280
|
|
281
|
-
def box_label(self, box, label="", color=(128, 128, 128), txt_color=(255, 255, 255)
|
281
|
+
def box_label(self, box, label="", color=(128, 128, 128), txt_color=(255, 255, 255)):
|
282
282
|
"""
|
283
283
|
Draw a bounding box on an image with a given label.
|
284
284
|
|
@@ -287,7 +287,6 @@ class Annotator:
|
|
287
287
|
label (str, optional): The text label to be displayed.
|
288
288
|
color (tuple, optional): The background color of the rectangle (B, G, R).
|
289
289
|
txt_color (tuple, optional): The color of the text (R, G, B).
|
290
|
-
rotated (bool, optional): Whether the task is oriented bounding box detection.
|
291
290
|
|
292
291
|
Examples:
|
293
292
|
>>> from ultralytics.utils.plotting import Annotator
|
@@ -298,13 +297,13 @@ class Annotator:
|
|
298
297
|
txt_color = self.get_txt_color(color, txt_color)
|
299
298
|
if isinstance(box, torch.Tensor):
|
300
299
|
box = box.tolist()
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
300
|
+
|
301
|
+
multi_points = isinstance(box[0], list) # multiple points with shape (n, 2)
|
302
|
+
p1 = [int(b) for b in box[0]] if multi_points else (int(box[0]), int(box[1]))
|
303
|
+
if self.pil:
|
304
|
+
self.draw.polygon(
|
305
|
+
[tuple(b) for b in box], width=self.lw, outline=color
|
306
|
+
) if multi_points else self.draw.rectangle(box, width=self.lw, outline=color)
|
308
307
|
if label:
|
309
308
|
w, h = self.font.getsize(label) # text width, height
|
310
309
|
outside = p1[1] >= h # label fits outside box
|
@@ -317,12 +316,11 @@ class Annotator:
|
|
317
316
|
# self.draw.text([box[0], box[1]], label, fill=txt_color, font=self.font, anchor='ls') # for PIL>8.0
|
318
317
|
self.draw.text((p1[0], p1[1] - h if outside else p1[1]), label, fill=txt_color, font=self.font)
|
319
318
|
else: # cv2
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
cv2.rectangle(self.im, p1, p2, color, thickness=self.lw, lineType=cv2.LINE_AA)
|
319
|
+
cv2.polylines(
|
320
|
+
self.im, [np.asarray(box, dtype=int)], True, color, self.lw
|
321
|
+
) if multi_points else cv2.rectangle(
|
322
|
+
self.im, p1, (int(box[2]), int(box[3])), color, thickness=self.lw, lineType=cv2.LINE_AA
|
323
|
+
)
|
326
324
|
if label:
|
327
325
|
w, h = cv2.getTextSize(label, 0, fontScale=self.sf, thickness=self.tf)[0] # text width, height
|
328
326
|
h += 3 # add pixels to pad text
|
@@ -750,7 +748,7 @@ def plot_images(
|
|
750
748
|
c = names.get(c, c) if names else c
|
751
749
|
if labels or conf[j] > conf_thres:
|
752
750
|
label = f"{c}" if labels else f"{c} {conf[j]:.1f}"
|
753
|
-
annotator.box_label(box, label, color=color
|
751
|
+
annotator.box_label(box, label, color=color)
|
754
752
|
|
755
753
|
elif len(classes):
|
756
754
|
for c in classes:
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|