ultralytics 8.3.10__py3-none-any.whl → 8.3.12__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.
Potentially problematic release.
This version of ultralytics might be problematic. Click here for more details.
- tests/test_cli.py +4 -1
- tests/test_cuda.py +13 -1
- ultralytics/__init__.py +1 -3
- ultralytics/cfg/__init__.py +2 -35
- ultralytics/cfg/solutions/default.yaml +1 -0
- ultralytics/data/annotator.py +1 -1
- ultralytics/engine/exporter.py +56 -51
- ultralytics/engine/model.py +33 -33
- ultralytics/engine/results.py +1 -1
- ultralytics/engine/tuner.py +3 -3
- ultralytics/models/sam/predict.py +12 -5
- ultralytics/models/yolo/detect/predict.py +1 -1
- ultralytics/models/yolo/detect/train.py +1 -1
- ultralytics/models/yolo/detect/val.py +1 -1
- ultralytics/models/yolo/model.py +1 -1
- ultralytics/nn/autobackend.py +1 -1
- ultralytics/solutions/analytics.py +151 -264
- ultralytics/utils/benchmarks.py +2 -2
- ultralytics/utils/checks.py +1 -1
- ultralytics/utils/downloads.py +1 -1
- ultralytics/utils/files.py +2 -2
- ultralytics/utils/tuner.py +1 -1
- {ultralytics-8.3.10.dist-info → ultralytics-8.3.12.dist-info}/METADATA +4 -5
- {ultralytics-8.3.10.dist-info → ultralytics-8.3.12.dist-info}/RECORD +28 -33
- ultralytics/data/explorer/__init__.py +0 -5
- ultralytics/data/explorer/explorer.py +0 -460
- ultralytics/data/explorer/gui/__init__.py +0 -1
- ultralytics/data/explorer/gui/dash.py +0 -269
- ultralytics/data/explorer/utils.py +0 -167
- {ultralytics-8.3.10.dist-info → ultralytics-8.3.12.dist-info}/LICENSE +0 -0
- {ultralytics-8.3.10.dist-info → ultralytics-8.3.12.dist-info}/WHEEL +0 -0
- {ultralytics-8.3.10.dist-info → ultralytics-8.3.12.dist-info}/entry_points.txt +0 -0
- {ultralytics-8.3.10.dist-info → ultralytics-8.3.12.dist-info}/top_level.txt +0 -0
ultralytics/engine/results.py
CHANGED
|
@@ -676,7 +676,7 @@ class Results(SimpleClass):
|
|
|
676
676
|
|
|
677
677
|
Examples:
|
|
678
678
|
>>> from ultralytics import YOLO
|
|
679
|
-
>>> model = YOLO("
|
|
679
|
+
>>> model = YOLO("yolo11n.pt")
|
|
680
680
|
>>> results = model("path/to/image.jpg")
|
|
681
681
|
>>> for result in results:
|
|
682
682
|
... result.save_txt("output.txt")
|
ultralytics/engine/tuner.py
CHANGED
|
@@ -12,7 +12,7 @@ Example:
|
|
|
12
12
|
```python
|
|
13
13
|
from ultralytics import YOLO
|
|
14
14
|
|
|
15
|
-
model = YOLO("
|
|
15
|
+
model = YOLO("yolo11n.pt")
|
|
16
16
|
model.tune(data="coco8.yaml", epochs=10, iterations=300, optimizer="AdamW", plots=False, save=False, val=False)
|
|
17
17
|
```
|
|
18
18
|
"""
|
|
@@ -54,7 +54,7 @@ class Tuner:
|
|
|
54
54
|
```python
|
|
55
55
|
from ultralytics import YOLO
|
|
56
56
|
|
|
57
|
-
model = YOLO("
|
|
57
|
+
model = YOLO("yolo11n.pt")
|
|
58
58
|
model.tune(data="coco8.yaml", epochs=10, iterations=300, optimizer="AdamW", plots=False, save=False, val=False)
|
|
59
59
|
```
|
|
60
60
|
|
|
@@ -62,7 +62,7 @@ class Tuner:
|
|
|
62
62
|
```python
|
|
63
63
|
from ultralytics import YOLO
|
|
64
64
|
|
|
65
|
-
model = YOLO("
|
|
65
|
+
model = YOLO("yolo11n.pt")
|
|
66
66
|
model.tune(space={key1: val1, key2: val2}) # custom search space dictionary
|
|
67
67
|
```
|
|
68
68
|
"""
|
|
@@ -213,11 +213,14 @@ class Predictor(BasePredictor):
|
|
|
213
213
|
Args:
|
|
214
214
|
im (torch.Tensor): Preprocessed input image tensor with shape (N, C, H, W).
|
|
215
215
|
bboxes (np.ndarray | List | None): Bounding boxes in XYXY format with shape (N, 4).
|
|
216
|
-
points (np.ndarray | List | None): Points indicating object locations with shape (N, 2), in pixels.
|
|
217
|
-
labels (np.ndarray | List | None): Point prompt labels with shape (N,). 1 for foreground, 0 for background.
|
|
216
|
+
points (np.ndarray | List | None): Points indicating object locations with shape (N, 2) or (N, num_points, 2), in pixels.
|
|
217
|
+
labels (np.ndarray | List | None): Point prompt labels with shape (N,) or (N, num_points). 1 for foreground, 0 for background.
|
|
218
218
|
masks (np.ndarray | None): Low-res masks from previous predictions with shape (N, H, W). For SAM, H=W=256.
|
|
219
219
|
multimask_output (bool): Flag to return multiple masks for ambiguous prompts.
|
|
220
220
|
|
|
221
|
+
Raises:
|
|
222
|
+
AssertionError: If the number of points don't match the number of labels, in case labels were passed.
|
|
223
|
+
|
|
221
224
|
Returns:
|
|
222
225
|
(tuple): Tuple containing:
|
|
223
226
|
- np.ndarray: Output masks with shape (C, H, W), where C is the number of generated masks.
|
|
@@ -240,11 +243,15 @@ class Predictor(BasePredictor):
|
|
|
240
243
|
points = points[None] if points.ndim == 1 else points
|
|
241
244
|
# Assuming labels are all positive if users don't pass labels.
|
|
242
245
|
if labels is None:
|
|
243
|
-
labels = np.ones(points.shape[
|
|
246
|
+
labels = np.ones(points.shape[:-1])
|
|
244
247
|
labels = torch.as_tensor(labels, dtype=torch.int32, device=self.device)
|
|
248
|
+
assert (
|
|
249
|
+
points.shape[-2] == labels.shape[-1]
|
|
250
|
+
), f"Number of points {points.shape[-2]} should match number of labels {labels.shape[-1]}."
|
|
245
251
|
points *= r
|
|
246
|
-
|
|
247
|
-
|
|
252
|
+
if points.ndim == 2:
|
|
253
|
+
# (N, 2) --> (N, 1, 2), (N, ) --> (N, 1)
|
|
254
|
+
points, labels = points[:, None, :], labels[:, None]
|
|
248
255
|
if bboxes is not None:
|
|
249
256
|
bboxes = torch.as_tensor(bboxes, dtype=torch.float32, device=self.device)
|
|
250
257
|
bboxes = bboxes[None] if bboxes.ndim == 1 else bboxes
|
|
@@ -14,7 +14,7 @@ class DetectionPredictor(BasePredictor):
|
|
|
14
14
|
from ultralytics.utils import ASSETS
|
|
15
15
|
from ultralytics.models.yolo.detect import DetectionPredictor
|
|
16
16
|
|
|
17
|
-
args = dict(model="
|
|
17
|
+
args = dict(model="yolo11n.pt", source=ASSETS)
|
|
18
18
|
predictor = DetectionPredictor(overrides=args)
|
|
19
19
|
predictor.predict_cli()
|
|
20
20
|
```
|
|
@@ -24,7 +24,7 @@ class DetectionTrainer(BaseTrainer):
|
|
|
24
24
|
```python
|
|
25
25
|
from ultralytics.models.yolo.detect import DetectionTrainer
|
|
26
26
|
|
|
27
|
-
args = dict(model="
|
|
27
|
+
args = dict(model="yolo11n.pt", data="coco8.yaml", epochs=3)
|
|
28
28
|
trainer = DetectionTrainer(overrides=args)
|
|
29
29
|
trainer.train()
|
|
30
30
|
```
|
|
@@ -22,7 +22,7 @@ class DetectionValidator(BaseValidator):
|
|
|
22
22
|
```python
|
|
23
23
|
from ultralytics.models.yolo.detect import DetectionValidator
|
|
24
24
|
|
|
25
|
-
args = dict(model="
|
|
25
|
+
args = dict(model="yolo11n.pt", data="coco8.yaml")
|
|
26
26
|
validator = DetectionValidator(args=args)
|
|
27
27
|
validator()
|
|
28
28
|
```
|
ultralytics/models/yolo/model.py
CHANGED
|
@@ -11,7 +11,7 @@ from ultralytics.utils import ROOT, yaml_load
|
|
|
11
11
|
class YOLO(Model):
|
|
12
12
|
"""YOLO (You Only Look Once) object detection model."""
|
|
13
13
|
|
|
14
|
-
def __init__(self, model="
|
|
14
|
+
def __init__(self, model="yolo11n.pt", task=None, verbose=False):
|
|
15
15
|
"""Initialize YOLO model, switching to YOLOWorld if model filename contains '-world'."""
|
|
16
16
|
path = Path(model)
|
|
17
17
|
if "-world" in path.stem and path.suffix in {".pt", ".yaml", ".yml"}: # if YOLOWorld PyTorch model
|
ultralytics/nn/autobackend.py
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
# Ultralytics YOLO 🚀, AGPL-3.0 license
|
|
2
2
|
|
|
3
|
-
import warnings
|
|
4
3
|
from itertools import cycle
|
|
5
4
|
|
|
6
5
|
import cv2
|
|
@@ -9,299 +8,187 @@ import numpy as np
|
|
|
9
8
|
from matplotlib.backends.backend_agg import FigureCanvasAgg as FigureCanvas
|
|
10
9
|
from matplotlib.figure import Figure
|
|
11
10
|
|
|
11
|
+
from ultralytics.solutions.solutions import BaseSolution # Import a parent class
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
|
|
14
|
+
class Analytics(BaseSolution):
|
|
14
15
|
"""A class to create and update various types of charts (line, bar, pie, area) for visual analytics."""
|
|
15
16
|
|
|
16
|
-
def __init__(
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
writer,
|
|
20
|
-
im0_shape,
|
|
21
|
-
title="ultralytics",
|
|
22
|
-
x_label="x",
|
|
23
|
-
y_label="y",
|
|
24
|
-
bg_color="white",
|
|
25
|
-
fg_color="black",
|
|
26
|
-
line_color="yellow",
|
|
27
|
-
line_width=2,
|
|
28
|
-
points_width=10,
|
|
29
|
-
fontsize=13,
|
|
30
|
-
view_img=False,
|
|
31
|
-
save_img=True,
|
|
32
|
-
max_points=50,
|
|
33
|
-
):
|
|
34
|
-
"""
|
|
35
|
-
Initialize the Analytics class with various chart types.
|
|
17
|
+
def __init__(self, **kwargs):
|
|
18
|
+
"""Initialize the Analytics class with various chart types."""
|
|
19
|
+
super().__init__(**kwargs)
|
|
36
20
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
fontsize (int): Font size for chart text.
|
|
50
|
-
view_img (bool): Whether to display the image.
|
|
51
|
-
save_img (bool): Whether to save the image.
|
|
52
|
-
max_points (int): Specifies when to remove the oldest points in a graph for multiple lines.
|
|
53
|
-
"""
|
|
54
|
-
self.bg_color = bg_color
|
|
55
|
-
self.fg_color = fg_color
|
|
56
|
-
self.view_img = view_img
|
|
57
|
-
self.save_img = save_img
|
|
58
|
-
self.title = title
|
|
59
|
-
self.writer = writer
|
|
60
|
-
self.max_points = max_points
|
|
61
|
-
self.line_color = line_color
|
|
62
|
-
self.x_label = x_label
|
|
63
|
-
self.y_label = y_label
|
|
64
|
-
self.points_width = points_width
|
|
65
|
-
self.line_width = line_width
|
|
66
|
-
self.fontsize = fontsize
|
|
21
|
+
self.type = self.CFG["analytics_type"] # extract type of analytics
|
|
22
|
+
self.x_label = "Classes" if self.type in {"bar", "pie"} else "Frame#"
|
|
23
|
+
self.y_label = "Total Counts"
|
|
24
|
+
|
|
25
|
+
# Predefined data
|
|
26
|
+
self.bg_color = "#00F344" # background color of frame
|
|
27
|
+
self.fg_color = "#111E68" # foreground color of frame
|
|
28
|
+
self.title = "Ultralytics Solutions" # window name
|
|
29
|
+
self.max_points = 45 # maximum points to be drawn on window
|
|
30
|
+
self.fontsize = 25 # text font size for display
|
|
31
|
+
figsize = (19.2, 10.8) # Set output image size 1920 * 1080
|
|
32
|
+
self.color_cycle = cycle(["#DD00BA", "#042AFF", "#FF4447", "#7D24FF", "#BD00FF"])
|
|
67
33
|
|
|
68
|
-
#
|
|
69
|
-
|
|
34
|
+
self.total_counts = 0 # count variable for storing total counts i.e for line
|
|
35
|
+
self.clswise_count = {} # dictionary for classwise counts
|
|
70
36
|
|
|
71
|
-
|
|
72
|
-
|
|
37
|
+
# Ensure line and area chart
|
|
38
|
+
if self.type in {"line", "area"}:
|
|
73
39
|
self.lines = {}
|
|
74
40
|
self.fig = Figure(facecolor=self.bg_color, figsize=figsize)
|
|
75
|
-
self.canvas = FigureCanvas(self.fig)
|
|
41
|
+
self.canvas = FigureCanvas(self.fig) # Set common axis properties
|
|
76
42
|
self.ax = self.fig.add_subplot(111, facecolor=self.bg_color)
|
|
77
|
-
if type == "line":
|
|
78
|
-
(self.line,) = self.ax.plot([], [], color=
|
|
79
|
-
|
|
80
|
-
elif type in {"bar", "pie"}:
|
|
43
|
+
if self.type == "line":
|
|
44
|
+
(self.line,) = self.ax.plot([], [], color="cyan", linewidth=self.line_width)
|
|
45
|
+
elif self.type in {"bar", "pie"}:
|
|
81
46
|
# Initialize bar or pie plot
|
|
82
47
|
self.fig, self.ax = plt.subplots(figsize=figsize, facecolor=self.bg_color)
|
|
48
|
+
self.canvas = FigureCanvas(self.fig) # Set common axis properties
|
|
83
49
|
self.ax.set_facecolor(self.bg_color)
|
|
84
|
-
color_palette = [
|
|
85
|
-
(31, 119, 180),
|
|
86
|
-
(255, 127, 14),
|
|
87
|
-
(44, 160, 44),
|
|
88
|
-
(214, 39, 40),
|
|
89
|
-
(148, 103, 189),
|
|
90
|
-
(140, 86, 75),
|
|
91
|
-
(227, 119, 194),
|
|
92
|
-
(127, 127, 127),
|
|
93
|
-
(188, 189, 34),
|
|
94
|
-
(23, 190, 207),
|
|
95
|
-
]
|
|
96
|
-
self.color_palette = [(r / 255, g / 255, b / 255, 1) for r, g, b in color_palette]
|
|
97
|
-
self.color_cycle = cycle(self.color_palette)
|
|
98
50
|
self.color_mapping = {}
|
|
51
|
+
self.ax.axis("equal") if type == "pie" else None # Ensure pie chart is circular
|
|
99
52
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
# Set common axis properties
|
|
104
|
-
self.ax.set_title(self.title, color=self.fg_color, fontsize=self.fontsize)
|
|
105
|
-
self.ax.set_xlabel(x_label, color=self.fg_color, fontsize=self.fontsize - 3)
|
|
106
|
-
self.ax.set_ylabel(y_label, color=self.fg_color, fontsize=self.fontsize - 3)
|
|
107
|
-
self.ax.tick_params(axis="both", colors=self.fg_color)
|
|
53
|
+
def process_data(self, im0, frame_number):
|
|
54
|
+
"""
|
|
55
|
+
Process the image data, run object tracking.
|
|
108
56
|
|
|
109
|
-
|
|
57
|
+
Args:
|
|
58
|
+
im0 (ndarray): Input image for processing.
|
|
59
|
+
frame_number (int): Video frame # for plotting the data.
|
|
60
|
+
"""
|
|
61
|
+
self.extract_tracks(im0) # Extract tracks
|
|
62
|
+
|
|
63
|
+
if self.type == "line":
|
|
64
|
+
for box in self.boxes:
|
|
65
|
+
self.total_counts += 1
|
|
66
|
+
im0 = self.update_graph(frame_number=frame_number)
|
|
67
|
+
self.total_counts = 0
|
|
68
|
+
elif self.type == "pie" or self.type == "bar" or self.type == "area":
|
|
69
|
+
self.clswise_count = {}
|
|
70
|
+
for box, cls in zip(self.boxes, self.clss):
|
|
71
|
+
if self.names[int(cls)] in self.clswise_count:
|
|
72
|
+
self.clswise_count[self.names[int(cls)]] += 1
|
|
73
|
+
else:
|
|
74
|
+
self.clswise_count[self.names[int(cls)]] = 1
|
|
75
|
+
im0 = self.update_graph(frame_number=frame_number, count_dict=self.clswise_count, plot=self.type)
|
|
76
|
+
else:
|
|
77
|
+
raise ModuleNotFoundError(f"{self.type} chart is not supported ❌")
|
|
78
|
+
return im0
|
|
79
|
+
|
|
80
|
+
def update_graph(self, frame_number, count_dict=None, plot="line"):
|
|
110
81
|
"""
|
|
111
|
-
Update the area
|
|
82
|
+
Update the graph (line or area) with new data for single or multiple classes.
|
|
112
83
|
|
|
113
84
|
Args:
|
|
114
85
|
frame_number (int): The current frame number.
|
|
115
|
-
|
|
86
|
+
count_dict (dict, optional): Dictionary with class names as keys and counts as values for multiple classes.
|
|
87
|
+
If None, updates a single line graph.
|
|
88
|
+
plot (str): Type of the plot i.e. line, bar or area.
|
|
116
89
|
"""
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
y_data_dict
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
x_data
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
90
|
+
if count_dict is None:
|
|
91
|
+
# Single line update
|
|
92
|
+
x_data = np.append(self.line.get_xdata(), float(frame_number))
|
|
93
|
+
y_data = np.append(self.line.get_ydata(), float(self.total_counts))
|
|
94
|
+
|
|
95
|
+
if len(x_data) > self.max_points:
|
|
96
|
+
x_data, y_data = x_data[-self.max_points :], y_data[-self.max_points :]
|
|
97
|
+
|
|
98
|
+
self.line.set_data(x_data, y_data)
|
|
99
|
+
self.line.set_label("Counts")
|
|
100
|
+
self.line.set_color("#7b0068") # Pink color
|
|
101
|
+
self.line.set_marker("*")
|
|
102
|
+
self.line.set_markersize(self.line_width * 5)
|
|
103
|
+
else:
|
|
104
|
+
labels = list(count_dict.keys())
|
|
105
|
+
counts = list(count_dict.values())
|
|
106
|
+
if plot == "area":
|
|
107
|
+
color_cycle = cycle(["#DD00BA", "#042AFF", "#FF4447", "#7D24FF", "#BD00FF"])
|
|
108
|
+
# Multiple lines or area update
|
|
109
|
+
x_data = self.ax.lines[0].get_xdata() if self.ax.lines else np.array([])
|
|
110
|
+
y_data_dict = {key: np.array([]) for key in count_dict.keys()}
|
|
111
|
+
if self.ax.lines:
|
|
112
|
+
for line, key in zip(self.ax.lines, count_dict.keys()):
|
|
113
|
+
y_data_dict[key] = line.get_ydata()
|
|
114
|
+
|
|
115
|
+
x_data = np.append(x_data, float(frame_number))
|
|
116
|
+
max_length = len(x_data)
|
|
117
|
+
for key in count_dict.keys():
|
|
118
|
+
y_data_dict[key] = np.append(y_data_dict[key], float(count_dict[key]))
|
|
119
|
+
if len(y_data_dict[key]) < max_length:
|
|
120
|
+
y_data_dict[key] = np.pad(y_data_dict[key], (0, max_length - len(y_data_dict[key])), "constant")
|
|
121
|
+
if len(x_data) > self.max_points:
|
|
122
|
+
x_data = x_data[1:]
|
|
123
|
+
for key in count_dict.keys():
|
|
124
|
+
y_data_dict[key] = y_data_dict[key][1:]
|
|
125
|
+
|
|
126
|
+
self.ax.clear()
|
|
127
|
+
for key, y_data in y_data_dict.items():
|
|
128
|
+
color = next(color_cycle)
|
|
129
|
+
self.ax.fill_between(x_data, y_data, color=color, alpha=0.7)
|
|
130
|
+
self.ax.plot(
|
|
131
|
+
x_data,
|
|
132
|
+
y_data,
|
|
133
|
+
color=color,
|
|
134
|
+
linewidth=self.line_width,
|
|
135
|
+
marker="o",
|
|
136
|
+
markersize=self.line_width * 5,
|
|
137
|
+
label=f"{key} Data Points",
|
|
138
|
+
)
|
|
139
|
+
if plot == "bar":
|
|
140
|
+
self.ax.clear() # clear bar data
|
|
141
|
+
for label in labels: # Map labels to colors
|
|
142
|
+
if label not in self.color_mapping:
|
|
143
|
+
self.color_mapping[label] = next(self.color_cycle)
|
|
144
|
+
colors = [self.color_mapping[label] for label in labels]
|
|
145
|
+
bars = self.ax.bar(labels, counts, color=colors)
|
|
146
|
+
for bar, count in zip(bars, counts):
|
|
147
|
+
self.ax.text(
|
|
148
|
+
bar.get_x() + bar.get_width() / 2,
|
|
149
|
+
bar.get_height(),
|
|
150
|
+
str(count),
|
|
151
|
+
ha="center",
|
|
152
|
+
va="bottom",
|
|
153
|
+
color=self.fg_color,
|
|
154
|
+
)
|
|
155
|
+
# Create the legend using labels from the bars
|
|
156
|
+
for bar, label in zip(bars, labels):
|
|
157
|
+
bar.set_label(label) # Assign label to each bar
|
|
158
|
+
self.ax.legend(loc="upper left", fontsize=13, facecolor=self.fg_color, edgecolor=self.fg_color)
|
|
159
|
+
if plot == "pie":
|
|
160
|
+
total = sum(counts)
|
|
161
|
+
percentages = [size / total * 100 for size in counts]
|
|
162
|
+
start_angle = 90
|
|
163
|
+
self.ax.clear()
|
|
164
|
+
|
|
165
|
+
# Create pie chart and create legend labels with percentages
|
|
166
|
+
wedges, autotexts = self.ax.pie(
|
|
167
|
+
counts, labels=labels, startangle=start_angle, textprops={"color": self.fg_color}, autopct=None
|
|
168
|
+
)
|
|
169
|
+
legend_labels = [f"{label} ({percentage:.1f}%)" for label, percentage in zip(labels, percentages)]
|
|
170
|
+
|
|
171
|
+
# Assign the legend using the wedges and manually created labels
|
|
172
|
+
self.ax.legend(wedges, legend_labels, title="Classes", loc="center left", bbox_to_anchor=(1, 0, 0.5, 1))
|
|
173
|
+
self.fig.subplots_adjust(left=0.1, right=0.75) # Adjust layout to fit the legend
|
|
174
|
+
|
|
175
|
+
# Common plot settings
|
|
176
|
+
self.ax.set_facecolor("#f0f0f0") # Set to light gray or any other color you like
|
|
157
177
|
self.ax.set_title(self.title, color=self.fg_color, fontsize=self.fontsize)
|
|
158
178
|
self.ax.set_xlabel(self.x_label, color=self.fg_color, fontsize=self.fontsize - 3)
|
|
159
179
|
self.ax.set_ylabel(self.y_label, color=self.fg_color, fontsize=self.fontsize - 3)
|
|
160
|
-
legend = self.ax.legend(loc="upper left", fontsize=13, facecolor=self.bg_color, edgecolor=self.fg_color)
|
|
161
180
|
|
|
162
|
-
#
|
|
181
|
+
# Add and format legend
|
|
182
|
+
legend = self.ax.legend(loc="upper left", fontsize=13, facecolor=self.bg_color, edgecolor=self.bg_color)
|
|
163
183
|
for text in legend.get_texts():
|
|
164
184
|
text.set_color(self.fg_color)
|
|
165
185
|
|
|
166
|
-
|
|
167
|
-
im0 = np.array(self.canvas.renderer.buffer_rgba())
|
|
168
|
-
self.write_and_display(im0)
|
|
169
|
-
|
|
170
|
-
def update_line(self, frame_number, total_counts):
|
|
171
|
-
"""
|
|
172
|
-
Update the line graph with new data.
|
|
173
|
-
|
|
174
|
-
Args:
|
|
175
|
-
frame_number (int): The current frame number.
|
|
176
|
-
total_counts (int): The total counts to plot.
|
|
177
|
-
"""
|
|
178
|
-
# Update line graph data
|
|
179
|
-
x_data = self.line.get_xdata()
|
|
180
|
-
y_data = self.line.get_ydata()
|
|
181
|
-
x_data = np.append(x_data, float(frame_number))
|
|
182
|
-
y_data = np.append(y_data, float(total_counts))
|
|
183
|
-
self.line.set_data(x_data, y_data)
|
|
186
|
+
# Redraw graph, update view, capture, and display the updated plot
|
|
184
187
|
self.ax.relim()
|
|
185
188
|
self.ax.autoscale_view()
|
|
186
189
|
self.canvas.draw()
|
|
187
190
|
im0 = np.array(self.canvas.renderer.buffer_rgba())
|
|
188
|
-
self.write_and_display(im0)
|
|
189
|
-
|
|
190
|
-
def update_multiple_lines(self, counts_dict, labels_list, frame_number):
|
|
191
|
-
"""
|
|
192
|
-
Update the line graph with multiple classes.
|
|
193
|
-
|
|
194
|
-
Args:
|
|
195
|
-
counts_dict (int): Dictionary include each class counts.
|
|
196
|
-
labels_list (int): list include each classes names.
|
|
197
|
-
frame_number (int): The current frame number.
|
|
198
|
-
"""
|
|
199
|
-
warnings.warn("Display is not supported for multiple lines, output will be stored normally!")
|
|
200
|
-
for obj in labels_list:
|
|
201
|
-
if obj not in self.lines:
|
|
202
|
-
(line,) = self.ax.plot([], [], label=obj, marker="o", markersize=self.points_width)
|
|
203
|
-
self.lines[obj] = line
|
|
204
|
-
|
|
205
|
-
x_data = self.lines[obj].get_xdata()
|
|
206
|
-
y_data = self.lines[obj].get_ydata()
|
|
207
|
-
|
|
208
|
-
# Remove the initial point if the number of points exceeds max_points
|
|
209
|
-
if len(x_data) >= self.max_points:
|
|
210
|
-
x_data = np.delete(x_data, 0)
|
|
211
|
-
y_data = np.delete(y_data, 0)
|
|
212
|
-
|
|
213
|
-
x_data = np.append(x_data, float(frame_number)) # Ensure frame_number is converted to float
|
|
214
|
-
y_data = np.append(y_data, float(counts_dict.get(obj, 0))) # Ensure total_count is converted to float
|
|
215
|
-
self.lines[obj].set_data(x_data, y_data)
|
|
216
|
-
|
|
217
|
-
self.ax.relim()
|
|
218
|
-
self.ax.autoscale_view()
|
|
219
|
-
self.ax.legend()
|
|
220
|
-
self.canvas.draw()
|
|
221
|
-
|
|
222
|
-
im0 = np.array(self.canvas.renderer.buffer_rgba())
|
|
223
|
-
self.view_img = False # for multiple line view_img not supported yet, coming soon!
|
|
224
|
-
self.write_and_display(im0)
|
|
225
|
-
|
|
226
|
-
def write_and_display(self, im0):
|
|
227
|
-
"""
|
|
228
|
-
Write and display the line graph
|
|
229
|
-
Args:
|
|
230
|
-
im0 (ndarray): Image for processing.
|
|
231
|
-
"""
|
|
232
191
|
im0 = cv2.cvtColor(im0[:, :, :3], cv2.COLOR_RGBA2BGR)
|
|
233
|
-
|
|
234
|
-
self.writer.write(im0) if self.save_img else None
|
|
235
|
-
|
|
236
|
-
def update_bar(self, count_dict):
|
|
237
|
-
"""
|
|
238
|
-
Update the bar graph with new data.
|
|
239
|
-
|
|
240
|
-
Args:
|
|
241
|
-
count_dict (dict): Dictionary containing the count data to plot.
|
|
242
|
-
"""
|
|
243
|
-
# Update bar graph data
|
|
244
|
-
self.ax.clear()
|
|
245
|
-
self.ax.set_facecolor(self.bg_color)
|
|
246
|
-
labels = list(count_dict.keys())
|
|
247
|
-
counts = list(count_dict.values())
|
|
248
|
-
|
|
249
|
-
# Map labels to colors
|
|
250
|
-
for label in labels:
|
|
251
|
-
if label not in self.color_mapping:
|
|
252
|
-
self.color_mapping[label] = next(self.color_cycle)
|
|
253
|
-
|
|
254
|
-
colors = [self.color_mapping[label] for label in labels]
|
|
255
|
-
|
|
256
|
-
bars = self.ax.bar(labels, counts, color=colors)
|
|
257
|
-
for bar, count in zip(bars, counts):
|
|
258
|
-
self.ax.text(
|
|
259
|
-
bar.get_x() + bar.get_width() / 2,
|
|
260
|
-
bar.get_height(),
|
|
261
|
-
str(count),
|
|
262
|
-
ha="center",
|
|
263
|
-
va="bottom",
|
|
264
|
-
color=self.fg_color,
|
|
265
|
-
)
|
|
266
|
-
|
|
267
|
-
# Display and save the updated graph
|
|
268
|
-
canvas = FigureCanvas(self.fig)
|
|
269
|
-
canvas.draw()
|
|
270
|
-
buf = canvas.buffer_rgba()
|
|
271
|
-
im0 = np.asarray(buf)
|
|
272
|
-
self.write_and_display(im0)
|
|
273
|
-
|
|
274
|
-
def update_pie(self, classes_dict):
|
|
275
|
-
"""
|
|
276
|
-
Update the pie chart with new data.
|
|
277
|
-
|
|
278
|
-
Args:
|
|
279
|
-
classes_dict (dict): Dictionary containing the class data to plot.
|
|
280
|
-
"""
|
|
281
|
-
# Update pie chart data
|
|
282
|
-
labels = list(classes_dict.keys())
|
|
283
|
-
sizes = list(classes_dict.values())
|
|
284
|
-
total = sum(sizes)
|
|
285
|
-
percentages = [size / total * 100 for size in sizes]
|
|
286
|
-
start_angle = 90
|
|
287
|
-
self.ax.clear()
|
|
288
|
-
|
|
289
|
-
# Create pie chart without labels inside the slices
|
|
290
|
-
wedges, autotexts = self.ax.pie(sizes, autopct=None, startangle=start_angle, textprops={"color": self.fg_color})
|
|
291
|
-
|
|
292
|
-
# Construct legend labels with percentages
|
|
293
|
-
legend_labels = [f"{label} ({percentage:.1f}%)" for label, percentage in zip(labels, percentages)]
|
|
294
|
-
self.ax.legend(wedges, legend_labels, title="Classes", loc="center left", bbox_to_anchor=(1, 0, 0.5, 1))
|
|
295
|
-
|
|
296
|
-
# Adjust layout to fit the legend
|
|
297
|
-
self.fig.tight_layout()
|
|
298
|
-
self.fig.subplots_adjust(left=0.1, right=0.75)
|
|
299
|
-
|
|
300
|
-
# Display and save the updated chart
|
|
301
|
-
im0 = self.fig.canvas.draw()
|
|
302
|
-
im0 = np.array(self.fig.canvas.renderer.buffer_rgba())
|
|
303
|
-
self.write_and_display(im0)
|
|
304
|
-
|
|
192
|
+
self.display_output(im0)
|
|
305
193
|
|
|
306
|
-
|
|
307
|
-
Analytics("line", writer=None, im0_shape=None)
|
|
194
|
+
return im0 # Return the image
|
ultralytics/utils/benchmarks.py
CHANGED
|
@@ -47,7 +47,7 @@ from ultralytics.utils.torch_utils import get_cpu_info, select_device
|
|
|
47
47
|
|
|
48
48
|
|
|
49
49
|
def benchmark(
|
|
50
|
-
model=WEIGHTS_DIR / "
|
|
50
|
+
model=WEIGHTS_DIR / "yolo11n.pt",
|
|
51
51
|
data=None,
|
|
52
52
|
imgsz=160,
|
|
53
53
|
half=False,
|
|
@@ -76,7 +76,7 @@ def benchmark(
|
|
|
76
76
|
Examples:
|
|
77
77
|
Benchmark a YOLO model with default settings:
|
|
78
78
|
>>> from ultralytics.utils.benchmarks import benchmark
|
|
79
|
-
>>> benchmark(model="
|
|
79
|
+
>>> benchmark(model="yolo11n.pt", imgsz=640)
|
|
80
80
|
"""
|
|
81
81
|
import pandas as pd # scope for faster 'import ultralytics'
|
|
82
82
|
|
ultralytics/utils/checks.py
CHANGED
|
@@ -458,7 +458,7 @@ def check_torchvision():
|
|
|
458
458
|
)
|
|
459
459
|
|
|
460
460
|
|
|
461
|
-
def check_suffix(file="
|
|
461
|
+
def check_suffix(file="yolo11n.pt", suffix=".pt", msg=""):
|
|
462
462
|
"""Check file(s) for acceptable suffix."""
|
|
463
463
|
if file and suffix:
|
|
464
464
|
if isinstance(suffix, str):
|
ultralytics/utils/downloads.py
CHANGED
|
@@ -425,7 +425,7 @@ def attempt_download_asset(file, repo="ultralytics/assets", release="v8.3.0", **
|
|
|
425
425
|
|
|
426
426
|
Example:
|
|
427
427
|
```python
|
|
428
|
-
file_path = attempt_download_asset("
|
|
428
|
+
file_path = attempt_download_asset("yolo11n.pt", repo="ultralytics/assets", release="latest")
|
|
429
429
|
```
|
|
430
430
|
"""
|
|
431
431
|
from ultralytics.utils import SETTINGS # scoped for circular import
|
ultralytics/utils/files.py
CHANGED
|
@@ -183,7 +183,7 @@ def get_latest_run(search_dir="."):
|
|
|
183
183
|
return max(last_list, key=os.path.getctime) if last_list else ""
|
|
184
184
|
|
|
185
185
|
|
|
186
|
-
def update_models(model_names=("
|
|
186
|
+
def update_models(model_names=("yolo11n.pt",), source_dir=Path("."), update_names=False):
|
|
187
187
|
"""
|
|
188
188
|
Updates and re-saves specified YOLO models in an 'updated_models' subdirectory.
|
|
189
189
|
|
|
@@ -195,7 +195,7 @@ def update_models(model_names=("yolov8n.pt",), source_dir=Path("."), update_name
|
|
|
195
195
|
Examples:
|
|
196
196
|
Update specified YOLO models and save them in 'updated_models' subdirectory:
|
|
197
197
|
>>> from ultralytics.utils.files import update_models
|
|
198
|
-
>>> model_names = ("
|
|
198
|
+
>>> model_names = ("yolo11n.pt", "yolov8s.pt")
|
|
199
199
|
>>> update_models(model_names, source_dir=Path("/models"), update_names=True)
|
|
200
200
|
"""
|
|
201
201
|
from ultralytics import YOLO
|
ultralytics/utils/tuner.py
CHANGED
|
@@ -28,7 +28,7 @@ def run_ray_tune(
|
|
|
28
28
|
from ultralytics import YOLO
|
|
29
29
|
|
|
30
30
|
# Load a YOLOv8n model
|
|
31
|
-
model = YOLO("
|
|
31
|
+
model = YOLO("yolo11n.pt")
|
|
32
32
|
|
|
33
33
|
# Start tuning hyperparameters for YOLOv8n training on the COCO8 dataset
|
|
34
34
|
result_grid = model.tune(data="coco8.yaml", use_ray=True)
|