ultralytics 8.2.80__py3-none-any.whl → 8.2.82__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_solutions.py +0 -4
- ultralytics/__init__.py +1 -1
- ultralytics/cfg/__init__.py +14 -16
- ultralytics/data/annotator.py +1 -1
- ultralytics/data/augment.py +58 -58
- ultralytics/data/base.py +3 -3
- ultralytics/data/converter.py +7 -8
- ultralytics/data/explorer/explorer.py +7 -23
- ultralytics/data/loaders.py +1 -1
- ultralytics/data/split_dota.py +11 -3
- ultralytics/data/utils.py +6 -10
- ultralytics/engine/exporter.py +2 -4
- ultralytics/engine/model.py +47 -47
- ultralytics/engine/predictor.py +1 -1
- ultralytics/engine/results.py +30 -30
- ultralytics/engine/trainer.py +11 -8
- ultralytics/engine/tuner.py +7 -8
- ultralytics/engine/validator.py +3 -5
- ultralytics/hub/__init__.py +5 -5
- ultralytics/hub/auth.py +6 -2
- ultralytics/hub/session.py +30 -20
- ultralytics/models/fastsam/model.py +13 -10
- ultralytics/models/fastsam/predict.py +2 -2
- ultralytics/models/fastsam/utils.py +0 -1
- ultralytics/models/nas/model.py +4 -4
- ultralytics/models/nas/predict.py +1 -2
- ultralytics/models/nas/val.py +1 -1
- ultralytics/models/rtdetr/predict.py +1 -1
- ultralytics/models/rtdetr/train.py +1 -1
- ultralytics/models/rtdetr/val.py +1 -1
- ultralytics/models/sam/model.py +11 -11
- ultralytics/models/sam/modules/decoders.py +7 -4
- ultralytics/models/sam/modules/sam.py +9 -1
- ultralytics/models/sam/modules/tiny_encoder.py +1 -1
- ultralytics/models/sam/modules/transformer.py +0 -2
- ultralytics/models/sam/modules/utils.py +1 -1
- ultralytics/models/sam/predict.py +10 -10
- ultralytics/models/utils/loss.py +29 -17
- ultralytics/models/utils/ops.py +1 -5
- ultralytics/models/yolo/classify/predict.py +1 -1
- ultralytics/models/yolo/classify/train.py +1 -1
- ultralytics/models/yolo/classify/val.py +1 -1
- 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 +6 -2
- ultralytics/models/yolo/obb/predict.py +1 -1
- ultralytics/models/yolo/obb/train.py +1 -1
- ultralytics/models/yolo/obb/val.py +2 -2
- ultralytics/models/yolo/pose/predict.py +1 -1
- ultralytics/models/yolo/pose/train.py +1 -1
- ultralytics/models/yolo/pose/val.py +1 -1
- ultralytics/models/yolo/segment/predict.py +1 -1
- ultralytics/models/yolo/segment/train.py +1 -1
- ultralytics/models/yolo/segment/val.py +1 -1
- ultralytics/models/yolo/world/train.py +1 -1
- ultralytics/nn/autobackend.py +2 -2
- ultralytics/nn/modules/__init__.py +2 -2
- ultralytics/nn/modules/block.py +8 -20
- ultralytics/nn/modules/conv.py +1 -3
- ultralytics/nn/modules/head.py +16 -31
- ultralytics/nn/modules/transformer.py +0 -1
- ultralytics/nn/modules/utils.py +0 -1
- ultralytics/nn/tasks.py +11 -9
- ultralytics/solutions/__init__.py +1 -0
- ultralytics/solutions/ai_gym.py +0 -2
- ultralytics/solutions/analytics.py +1 -6
- ultralytics/solutions/heatmap.py +0 -1
- ultralytics/solutions/object_counter.py +0 -2
- ultralytics/solutions/queue_management.py +0 -2
- ultralytics/trackers/basetrack.py +1 -1
- ultralytics/trackers/byte_tracker.py +2 -2
- ultralytics/trackers/utils/gmc.py +5 -5
- ultralytics/trackers/utils/kalman_filter.py +1 -1
- ultralytics/trackers/utils/matching.py +1 -5
- ultralytics/utils/__init__.py +132 -30
- ultralytics/utils/autobatch.py +7 -4
- ultralytics/utils/benchmarks.py +6 -14
- ultralytics/utils/callbacks/base.py +0 -1
- ultralytics/utils/callbacks/comet.py +0 -1
- ultralytics/utils/callbacks/tensorboard.py +0 -1
- ultralytics/utils/checks.py +15 -18
- ultralytics/utils/downloads.py +6 -7
- ultralytics/utils/files.py +3 -4
- ultralytics/utils/instance.py +17 -7
- ultralytics/utils/metrics.py +15 -15
- ultralytics/utils/ops.py +8 -8
- ultralytics/utils/plotting.py +25 -35
- ultralytics/utils/tal.py +27 -18
- ultralytics/utils/torch_utils.py +12 -13
- ultralytics/utils/tuner.py +2 -3
- {ultralytics-8.2.80.dist-info → ultralytics-8.2.82.dist-info}/METADATA +1 -1
- {ultralytics-8.2.80.dist-info → ultralytics-8.2.82.dist-info}/RECORD +97 -97
- {ultralytics-8.2.80.dist-info → ultralytics-8.2.82.dist-info}/LICENSE +0 -0
- {ultralytics-8.2.80.dist-info → ultralytics-8.2.82.dist-info}/WHEEL +0 -0
- {ultralytics-8.2.80.dist-info → ultralytics-8.2.82.dist-info}/entry_points.txt +0 -0
- {ultralytics-8.2.80.dist-info → ultralytics-8.2.82.dist-info}/top_level.txt +0 -0
ultralytics/utils/checks.py
CHANGED
|
@@ -23,6 +23,7 @@ from ultralytics.utils import (
|
|
|
23
23
|
ASSETS,
|
|
24
24
|
AUTOINSTALL,
|
|
25
25
|
IS_COLAB,
|
|
26
|
+
IS_GIT_DIR,
|
|
26
27
|
IS_JUPYTER,
|
|
27
28
|
IS_KAGGLE,
|
|
28
29
|
IS_PIP_PACKAGE,
|
|
@@ -61,10 +62,9 @@ def parse_requirements(file_path=ROOT.parent / "requirements.txt", package=""):
|
|
|
61
62
|
```python
|
|
62
63
|
from ultralytics.utils.checks import parse_requirements
|
|
63
64
|
|
|
64
|
-
parse_requirements(package=
|
|
65
|
+
parse_requirements(package="ultralytics")
|
|
65
66
|
```
|
|
66
67
|
"""
|
|
67
|
-
|
|
68
68
|
if package:
|
|
69
69
|
requires = [x for x in metadata.distribution(package).requires if "extra == " not in x]
|
|
70
70
|
else:
|
|
@@ -196,16 +196,16 @@ def check_version(
|
|
|
196
196
|
Example:
|
|
197
197
|
```python
|
|
198
198
|
# Check if current version is exactly 22.04
|
|
199
|
-
check_version(current=
|
|
199
|
+
check_version(current="22.04", required="==22.04")
|
|
200
200
|
|
|
201
201
|
# Check if current version is greater than or equal to 22.04
|
|
202
|
-
check_version(current=
|
|
202
|
+
check_version(current="22.10", required="22.04") # assumes '>=' inequality if none passed
|
|
203
203
|
|
|
204
204
|
# Check if current version is less than or equal to 22.04
|
|
205
|
-
check_version(current=
|
|
205
|
+
check_version(current="22.04", required="<=22.04")
|
|
206
206
|
|
|
207
207
|
# Check if current version is between 20.04 (inclusive) and 22.04 (exclusive)
|
|
208
|
-
check_version(current=
|
|
208
|
+
check_version(current="21.10", required=">20.04,<22.04")
|
|
209
209
|
```
|
|
210
210
|
"""
|
|
211
211
|
if not current: # if current is '' or None
|
|
@@ -256,7 +256,7 @@ def check_latest_pypi_version(package_name="ultralytics"):
|
|
|
256
256
|
"""
|
|
257
257
|
Returns the latest version of a PyPI package without downloading or installing it.
|
|
258
258
|
|
|
259
|
-
|
|
259
|
+
Args:
|
|
260
260
|
package_name (str): The name of the package to find the latest version for.
|
|
261
261
|
|
|
262
262
|
Returns:
|
|
@@ -352,16 +352,15 @@ def check_requirements(requirements=ROOT.parent / "requirements.txt", exclude=()
|
|
|
352
352
|
from ultralytics.utils.checks import check_requirements
|
|
353
353
|
|
|
354
354
|
# Check a requirements.txt file
|
|
355
|
-
check_requirements(
|
|
355
|
+
check_requirements("path/to/requirements.txt")
|
|
356
356
|
|
|
357
357
|
# Check a single package
|
|
358
|
-
check_requirements(
|
|
358
|
+
check_requirements("ultralytics>=8.0.0")
|
|
359
359
|
|
|
360
360
|
# Check multiple packages
|
|
361
|
-
check_requirements([
|
|
361
|
+
check_requirements(["numpy", "ultralytics>=8.0.0"])
|
|
362
362
|
```
|
|
363
363
|
"""
|
|
364
|
-
|
|
365
364
|
prefix = colorstr("red", "bold", "requirements:")
|
|
366
365
|
check_python() # check python version
|
|
367
366
|
check_torchvision() # check torch-torchvision compatibility
|
|
@@ -421,7 +420,6 @@ def check_torchvision():
|
|
|
421
420
|
The compatibility table is a dictionary where the keys are PyTorch versions and the values are lists of compatible
|
|
422
421
|
Torchvision versions.
|
|
423
422
|
"""
|
|
424
|
-
|
|
425
423
|
# Compatibility table
|
|
426
424
|
compatibility_table = {
|
|
427
425
|
"2.3": ["0.18"],
|
|
@@ -582,10 +580,9 @@ def check_yolo(verbose=True, device=""):
|
|
|
582
580
|
|
|
583
581
|
def collect_system_info():
|
|
584
582
|
"""Collect and print relevant system information including OS, Python, RAM, CPU, and CUDA."""
|
|
585
|
-
|
|
586
583
|
import psutil
|
|
587
584
|
|
|
588
|
-
from ultralytics.utils import ENVIRONMENT
|
|
585
|
+
from ultralytics.utils import ENVIRONMENT # scope to avoid circular import
|
|
589
586
|
from ultralytics.utils.torch_utils import get_cpu_info
|
|
590
587
|
|
|
591
588
|
ram_info = psutil.virtual_memory().total / (1024**3) # Convert bytes to GB
|
|
@@ -622,9 +619,9 @@ def collect_system_info():
|
|
|
622
619
|
|
|
623
620
|
def check_amp(model):
|
|
624
621
|
"""
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
622
|
+
Checks the PyTorch Automatic Mixed Precision (AMP) functionality of a YOLOv8 model. If the checks fail, it means
|
|
623
|
+
there are anomalies with AMP on the system that may cause NaN losses or zero-mAP results, so AMP will be disabled
|
|
624
|
+
during training.
|
|
628
625
|
|
|
629
626
|
Args:
|
|
630
627
|
model (nn.Module): A YOLOv8 model instance.
|
|
@@ -634,7 +631,7 @@ def check_amp(model):
|
|
|
634
631
|
from ultralytics import YOLO
|
|
635
632
|
from ultralytics.utils.checks import check_amp
|
|
636
633
|
|
|
637
|
-
model = YOLO(
|
|
634
|
+
model = YOLO("yolov8n.pt").model.cuda()
|
|
638
635
|
check_amp(model)
|
|
639
636
|
```
|
|
640
637
|
|
ultralytics/utils/downloads.py
CHANGED
|
@@ -75,7 +75,7 @@ def delete_dsstore(path, files_to_delete=(".DS_Store", "__MACOSX")):
|
|
|
75
75
|
```python
|
|
76
76
|
from ultralytics.utils.downloads import delete_dsstore
|
|
77
77
|
|
|
78
|
-
delete_dsstore(
|
|
78
|
+
delete_dsstore("path/to/dir")
|
|
79
79
|
```
|
|
80
80
|
|
|
81
81
|
Note:
|
|
@@ -107,7 +107,7 @@ def zip_directory(directory, compress=True, exclude=(".DS_Store", "__MACOSX"), p
|
|
|
107
107
|
```python
|
|
108
108
|
from ultralytics.utils.downloads import zip_directory
|
|
109
109
|
|
|
110
|
-
file = zip_directory(
|
|
110
|
+
file = zip_directory("path/to/dir")
|
|
111
111
|
```
|
|
112
112
|
"""
|
|
113
113
|
from zipfile import ZIP_DEFLATED, ZIP_STORED, ZipFile
|
|
@@ -153,7 +153,7 @@ def unzip_file(file, path=None, exclude=(".DS_Store", "__MACOSX"), exist_ok=Fals
|
|
|
153
153
|
```python
|
|
154
154
|
from ultralytics.utils.downloads import unzip_file
|
|
155
155
|
|
|
156
|
-
dir = unzip_file(
|
|
156
|
+
dir = unzip_file("path/to/file.zip")
|
|
157
157
|
```
|
|
158
158
|
"""
|
|
159
159
|
from zipfile import BadZipFile, ZipFile, is_zipfile
|
|
@@ -392,10 +392,9 @@ def get_github_assets(repo="ultralytics/assets", version="latest", retry=False):
|
|
|
392
392
|
|
|
393
393
|
Example:
|
|
394
394
|
```python
|
|
395
|
-
tag, assets = get_github_assets(repo=
|
|
395
|
+
tag, assets = get_github_assets(repo="ultralytics/assets", version="latest")
|
|
396
396
|
```
|
|
397
397
|
"""
|
|
398
|
-
|
|
399
398
|
if version != "latest":
|
|
400
399
|
version = f"tags/{version}" # i.e. tags/v6.2
|
|
401
400
|
url = f"https://api.github.com/repos/{repo}/releases/{version}"
|
|
@@ -425,7 +424,7 @@ def attempt_download_asset(file, repo="ultralytics/assets", release="v8.2.0", **
|
|
|
425
424
|
|
|
426
425
|
Example:
|
|
427
426
|
```python
|
|
428
|
-
file_path = attempt_download_asset(
|
|
427
|
+
file_path = attempt_download_asset("yolov8n.pt", repo="ultralytics/assets", release="latest")
|
|
429
428
|
```
|
|
430
429
|
"""
|
|
431
430
|
from ultralytics.utils import SETTINGS # scoped for circular import
|
|
@@ -480,7 +479,7 @@ def download(url, dir=Path.cwd(), unzip=True, delete=False, curl=False, threads=
|
|
|
480
479
|
|
|
481
480
|
Example:
|
|
482
481
|
```python
|
|
483
|
-
download(
|
|
482
|
+
download("https://ultralytics.com/assets/example.zip", dir="path/to/dir", unzip=True)
|
|
484
483
|
```
|
|
485
484
|
"""
|
|
486
485
|
dir = Path(dir)
|
ultralytics/utils/files.py
CHANGED
|
@@ -28,13 +28,13 @@ class WorkingDirectory(contextlib.ContextDecorator):
|
|
|
28
28
|
Examples:
|
|
29
29
|
Using as a context manager:
|
|
30
30
|
>>> with WorkingDirectory('/path/to/new/dir'):
|
|
31
|
-
>>>
|
|
31
|
+
>>> # Perform operations in the new directory
|
|
32
32
|
>>> pass
|
|
33
33
|
|
|
34
34
|
Using as a decorator:
|
|
35
35
|
>>> @WorkingDirectory('/path/to/new/dir')
|
|
36
36
|
>>> def some_function():
|
|
37
|
-
>>>
|
|
37
|
+
>>> # Perform operations in the new directory
|
|
38
38
|
>>> pass
|
|
39
39
|
"""
|
|
40
40
|
|
|
@@ -69,9 +69,8 @@ def spaces_in_path(path):
|
|
|
69
69
|
Use the context manager to handle paths with spaces:
|
|
70
70
|
>>> from ultralytics.utils.files import spaces_in_path
|
|
71
71
|
>>> with spaces_in_path('/path/with spaces') as new_path:
|
|
72
|
-
>>>
|
|
72
|
+
>>> # Your code here
|
|
73
73
|
"""
|
|
74
|
-
|
|
75
74
|
# If path has spaces, replace them with underscores
|
|
76
75
|
if " " in str(path):
|
|
77
76
|
string = isinstance(path, str) # input type
|
ultralytics/utils/instance.py
CHANGED
|
@@ -96,8 +96,11 @@ class Bboxes:
|
|
|
96
96
|
|
|
97
97
|
def mul(self, scale):
|
|
98
98
|
"""
|
|
99
|
+
Multiply bounding box coordinates by scale factor(s).
|
|
100
|
+
|
|
99
101
|
Args:
|
|
100
|
-
scale (
|
|
102
|
+
scale (int | tuple | list): Scale factor(s) for four coordinates.
|
|
103
|
+
If int, the same scale is applied to all coordinates.
|
|
101
104
|
"""
|
|
102
105
|
if isinstance(scale, Number):
|
|
103
106
|
scale = to_4tuple(scale)
|
|
@@ -110,8 +113,11 @@ class Bboxes:
|
|
|
110
113
|
|
|
111
114
|
def add(self, offset):
|
|
112
115
|
"""
|
|
116
|
+
Add offset to bounding box coordinates.
|
|
117
|
+
|
|
113
118
|
Args:
|
|
114
|
-
offset (
|
|
119
|
+
offset (int | tuple | list): Offset(s) for four coordinates.
|
|
120
|
+
If int, the same offset is applied to all coordinates.
|
|
115
121
|
"""
|
|
116
122
|
if isinstance(offset, Number):
|
|
117
123
|
offset = to_4tuple(offset)
|
|
@@ -199,7 +205,7 @@ class Instances:
|
|
|
199
205
|
instances = Instances(
|
|
200
206
|
bboxes=np.array([[10, 10, 30, 30], [20, 20, 40, 40]]),
|
|
201
207
|
segments=[np.array([[5, 5], [10, 10]]), np.array([[15, 15], [20, 20]])],
|
|
202
|
-
keypoints=np.array([[[5, 5, 1], [10, 10, 1]], [[15, 15, 1], [20, 20, 1]]])
|
|
208
|
+
keypoints=np.array([[[5, 5, 1], [10, 10, 1]], [[15, 15, 1], [20, 20, 1]]]),
|
|
203
209
|
)
|
|
204
210
|
```
|
|
205
211
|
|
|
@@ -210,10 +216,14 @@ class Instances:
|
|
|
210
216
|
|
|
211
217
|
def __init__(self, bboxes, segments=None, keypoints=None, bbox_format="xywh", normalized=True) -> None:
|
|
212
218
|
"""
|
|
219
|
+
Initialize the object with bounding boxes, segments, and keypoints.
|
|
220
|
+
|
|
213
221
|
Args:
|
|
214
|
-
bboxes (ndarray):
|
|
215
|
-
segments (list | ndarray):
|
|
216
|
-
keypoints (ndarray):
|
|
222
|
+
bboxes (np.ndarray): Bounding boxes, shape [N, 4].
|
|
223
|
+
segments (list | np.ndarray, optional): Segmentation masks. Defaults to None.
|
|
224
|
+
keypoints (np.ndarray, optional): Keypoints, shape [N, 17, 3] and format (x, y, visible). Defaults to None.
|
|
225
|
+
bbox_format (str, optional): Format of bboxes. Defaults to "xywh".
|
|
226
|
+
normalized (bool, optional): Whether the coordinates are normalized. Defaults to True.
|
|
217
227
|
"""
|
|
218
228
|
self._bboxes = Bboxes(bboxes=bboxes, format=bbox_format)
|
|
219
229
|
self.keypoints = keypoints
|
|
@@ -230,7 +240,7 @@ class Instances:
|
|
|
230
240
|
return self._bboxes.areas()
|
|
231
241
|
|
|
232
242
|
def scale(self, scale_w, scale_h, bbox_only=False):
|
|
233
|
-
"""
|
|
243
|
+
"""Similar to denormalize func but without normalized sign."""
|
|
234
244
|
self._bboxes.mul(scale=(scale_w, scale_h, scale_w, scale_h))
|
|
235
245
|
if bbox_only:
|
|
236
246
|
return
|
ultralytics/utils/metrics.py
CHANGED
|
@@ -30,7 +30,6 @@ def bbox_ioa(box1, box2, iou=False, eps=1e-7):
|
|
|
30
30
|
Returns:
|
|
31
31
|
(np.ndarray): A numpy array of shape (n, m) representing the intersection over box2 area.
|
|
32
32
|
"""
|
|
33
|
-
|
|
34
33
|
# Get the coordinates of bounding boxes
|
|
35
34
|
b1_x1, b1_y1, b1_x2, b1_y2 = box1.T
|
|
36
35
|
b2_x1, b2_y1, b2_x2, b2_y2 = box2.T
|
|
@@ -53,7 +52,7 @@ def bbox_ioa(box1, box2, iou=False, eps=1e-7):
|
|
|
53
52
|
def box_iou(box1, box2, eps=1e-7):
|
|
54
53
|
"""
|
|
55
54
|
Calculate intersection-over-union (IoU) of boxes. Both sets of boxes are expected to be in (x1, y1, x2, y2) format.
|
|
56
|
-
Based on https://github.com/pytorch/vision/blob/master/torchvision/ops/boxes.py
|
|
55
|
+
Based on https://github.com/pytorch/vision/blob/master/torchvision/ops/boxes.py.
|
|
57
56
|
|
|
58
57
|
Args:
|
|
59
58
|
box1 (torch.Tensor): A tensor of shape (N, 4) representing N bounding boxes.
|
|
@@ -63,7 +62,6 @@ def box_iou(box1, box2, eps=1e-7):
|
|
|
63
62
|
Returns:
|
|
64
63
|
(torch.Tensor): An NxM tensor containing the pairwise IoU values for every element in box1 and box2.
|
|
65
64
|
"""
|
|
66
|
-
|
|
67
65
|
# NOTE: Need .float() to get accurate iou values
|
|
68
66
|
# inter(N,M) = (rb(N,M,2) - lt(N,M,2)).clamp(0).prod(2)
|
|
69
67
|
(a1, a2), (b1, b2) = box1.float().unsqueeze(1).chunk(2, 2), box2.float().unsqueeze(0).chunk(2, 2)
|
|
@@ -90,7 +88,6 @@ def bbox_iou(box1, box2, xywh=True, GIoU=False, DIoU=False, CIoU=False, eps=1e-7
|
|
|
90
88
|
Returns:
|
|
91
89
|
(torch.Tensor): IoU, GIoU, DIoU, or CIoU values depending on the specified flags.
|
|
92
90
|
"""
|
|
93
|
-
|
|
94
91
|
# Get the coordinates of bounding boxes
|
|
95
92
|
if xywh: # transform from xywh to xyxy
|
|
96
93
|
(x1, y1, w1, h1), (x2, y2, w2, h2) = box1.chunk(4, -1), box2.chunk(4, -1)
|
|
@@ -195,15 +192,22 @@ def _get_covariance_matrix(boxes):
|
|
|
195
192
|
|
|
196
193
|
def probiou(obb1, obb2, CIoU=False, eps=1e-7):
|
|
197
194
|
"""
|
|
198
|
-
Calculate
|
|
195
|
+
Calculate probabilistic IoU between oriented bounding boxes.
|
|
196
|
+
|
|
197
|
+
Implements the algorithm from https://arxiv.org/pdf/2106.06072v1.pdf.
|
|
199
198
|
|
|
200
199
|
Args:
|
|
201
|
-
obb1 (torch.Tensor):
|
|
202
|
-
obb2 (torch.Tensor):
|
|
203
|
-
|
|
200
|
+
obb1 (torch.Tensor): Ground truth OBBs, shape (N, 5), format xywhr.
|
|
201
|
+
obb2 (torch.Tensor): Predicted OBBs, shape (N, 5), format xywhr.
|
|
202
|
+
CIoU (bool, optional): If True, calculate CIoU. Defaults to False.
|
|
203
|
+
eps (float, optional): Small value to avoid division by zero. Defaults to 1e-7.
|
|
204
204
|
|
|
205
205
|
Returns:
|
|
206
|
-
(torch.Tensor):
|
|
206
|
+
(torch.Tensor): OBB similarities, shape (N,).
|
|
207
|
+
|
|
208
|
+
Note:
|
|
209
|
+
OBB format: [center_x, center_y, width, height, rotation_angle].
|
|
210
|
+
If CIoU is True, returns CIoU instead of IoU.
|
|
207
211
|
"""
|
|
208
212
|
x1, y1 = obb1[..., :2].split(1, dim=-1)
|
|
209
213
|
x2, y2 = obb2[..., :2].split(1, dim=-1)
|
|
@@ -507,7 +511,6 @@ def compute_ap(recall, precision):
|
|
|
507
511
|
(np.ndarray): Precision envelope curve.
|
|
508
512
|
(np.ndarray): Modified recall curve with sentinel values added at the beginning and end.
|
|
509
513
|
"""
|
|
510
|
-
|
|
511
514
|
# Append sentinel values to beginning and end
|
|
512
515
|
mrec = np.concatenate(([0.0], recall, [1.0]))
|
|
513
516
|
mpre = np.concatenate(([1.0], precision, [0.0]))
|
|
@@ -560,7 +563,6 @@ def ap_per_class(
|
|
|
560
563
|
x (np.ndarray): X-axis values for the curves. Shape: (1000,).
|
|
561
564
|
prec_values: Precision values at mAP@0.5 for each class. Shape: (nc, 1000).
|
|
562
565
|
"""
|
|
563
|
-
|
|
564
566
|
# Sort by objectness
|
|
565
567
|
i = np.argsort(-conf)
|
|
566
568
|
tp, conf, pred_cls = tp[i], conf[i], pred_cls[i]
|
|
@@ -792,8 +794,8 @@ class Metric(SimpleClass):
|
|
|
792
794
|
|
|
793
795
|
class DetMetrics(SimpleClass):
|
|
794
796
|
"""
|
|
795
|
-
|
|
796
|
-
|
|
797
|
+
Utility class for computing detection metrics such as precision, recall, and mean average precision (mAP) of an
|
|
798
|
+
object detection model.
|
|
797
799
|
|
|
798
800
|
Args:
|
|
799
801
|
save_dir (Path): A path to the directory where the output plots will be saved. Defaults to current directory.
|
|
@@ -942,7 +944,6 @@ class SegmentMetrics(SimpleClass):
|
|
|
942
944
|
pred_cls (list): List of predicted classes.
|
|
943
945
|
target_cls (list): List of target classes.
|
|
944
946
|
"""
|
|
945
|
-
|
|
946
947
|
results_mask = ap_per_class(
|
|
947
948
|
tp_m,
|
|
948
949
|
conf,
|
|
@@ -1084,7 +1085,6 @@ class PoseMetrics(SegmentMetrics):
|
|
|
1084
1085
|
pred_cls (list): List of predicted classes.
|
|
1085
1086
|
target_cls (list): List of target classes.
|
|
1086
1087
|
"""
|
|
1087
|
-
|
|
1088
1088
|
results_pose = ap_per_class(
|
|
1089
1089
|
tp_p,
|
|
1090
1090
|
conf,
|
ultralytics/utils/ops.py
CHANGED
|
@@ -141,14 +141,15 @@ def make_divisible(x, divisor):
|
|
|
141
141
|
|
|
142
142
|
def nms_rotated(boxes, scores, threshold=0.45):
|
|
143
143
|
"""
|
|
144
|
-
NMS for
|
|
144
|
+
NMS for oriented bounding boxes using probiou and fast-nms.
|
|
145
145
|
|
|
146
146
|
Args:
|
|
147
|
-
boxes (torch.Tensor): (N, 5), xywhr.
|
|
148
|
-
scores (torch.Tensor): (N,
|
|
149
|
-
threshold (float): IoU threshold.
|
|
147
|
+
boxes (torch.Tensor): Rotated bounding boxes, shape (N, 5), format xywhr.
|
|
148
|
+
scores (torch.Tensor): Confidence scores, shape (N,).
|
|
149
|
+
threshold (float, optional): IoU threshold. Defaults to 0.45.
|
|
150
150
|
|
|
151
151
|
Returns:
|
|
152
|
+
(torch.Tensor): Indices of boxes to keep after NMS.
|
|
152
153
|
"""
|
|
153
154
|
if len(boxes) == 0:
|
|
154
155
|
return np.empty((0,), dtype=np.int8)
|
|
@@ -597,7 +598,7 @@ def ltwh2xyxy(x):
|
|
|
597
598
|
|
|
598
599
|
def segments2boxes(segments):
|
|
599
600
|
"""
|
|
600
|
-
It converts segment labels to box labels, i.e. (cls, xy1, xy2, ...) to (cls, xywh)
|
|
601
|
+
It converts segment labels to box labels, i.e. (cls, xy1, xy2, ...) to (cls, xywh).
|
|
601
602
|
|
|
602
603
|
Args:
|
|
603
604
|
segments (list): list of segments, each segment is a list of points, each point is a list of x, y coordinates
|
|
@@ -667,7 +668,6 @@ def process_mask(protos, masks_in, bboxes, shape, upsample=False):
|
|
|
667
668
|
(torch.Tensor): A binary mask tensor of shape [n, h, w], where n is the number of masks after NMS, and h and w
|
|
668
669
|
are the height and width of the input image. The mask is applied to the bounding boxes.
|
|
669
670
|
"""
|
|
670
|
-
|
|
671
671
|
c, mh, mw = protos.shape # CHW
|
|
672
672
|
ih, iw = shape
|
|
673
673
|
masks = (masks_in @ protos.float().view(c, -1)).view(-1, mh, mw) # CHW
|
|
@@ -785,7 +785,7 @@ def regularize_rboxes(rboxes):
|
|
|
785
785
|
|
|
786
786
|
def masks2segments(masks, strategy="largest"):
|
|
787
787
|
"""
|
|
788
|
-
It takes a list of masks(n,h,w) and returns a list of segments(n,xy)
|
|
788
|
+
It takes a list of masks(n,h,w) and returns a list of segments(n,xy).
|
|
789
789
|
|
|
790
790
|
Args:
|
|
791
791
|
masks (torch.Tensor): the output of the model, which is a tensor of shape (batch_size, 160, 160)
|
|
@@ -823,7 +823,7 @@ def convert_torch2numpy_batch(batch: torch.Tensor) -> np.ndarray:
|
|
|
823
823
|
|
|
824
824
|
def clean_str(s):
|
|
825
825
|
"""
|
|
826
|
-
Cleans a string by replacing special characters with
|
|
826
|
+
Cleans a string by replacing special characters with '_' character.
|
|
827
827
|
|
|
828
828
|
Args:
|
|
829
829
|
s (str): a string needing special characters replaced
|
ultralytics/utils/plotting.py
CHANGED
|
@@ -204,7 +204,6 @@ class Annotator:
|
|
|
204
204
|
txt_color (tuple, optional): The color of the text (R, G, B).
|
|
205
205
|
margin (int, optional): The margin between the text and the rectangle border.
|
|
206
206
|
"""
|
|
207
|
-
|
|
208
207
|
# If label have more than 3 characters, skip other characters, due to circle size
|
|
209
208
|
if len(label) > 3:
|
|
210
209
|
print(
|
|
@@ -246,7 +245,6 @@ class Annotator:
|
|
|
246
245
|
txt_color (tuple, optional): The color of the text (R, G, B).
|
|
247
246
|
margin (int, optional): The margin between the text and the rectangle border.
|
|
248
247
|
"""
|
|
249
|
-
|
|
250
248
|
# Calculate the center of the bounding box
|
|
251
249
|
x_center, y_center = int((box[0] + box[2]) / 2), int((box[1] + box[3]) / 2)
|
|
252
250
|
# Get the size of the text
|
|
@@ -284,7 +282,6 @@ class Annotator:
|
|
|
284
282
|
txt_color (tuple, optional): The color of the text (R, G, B).
|
|
285
283
|
rotated (bool, optional): Variable used to check if task is OBB
|
|
286
284
|
"""
|
|
287
|
-
|
|
288
285
|
txt_color = self.get_txt_color(color, txt_color)
|
|
289
286
|
if isinstance(box, torch.Tensor):
|
|
290
287
|
box = box.tolist()
|
|
@@ -343,7 +340,6 @@ class Annotator:
|
|
|
343
340
|
alpha (float): Mask transparency: 0.0 fully transparent, 1.0 opaque
|
|
344
341
|
retina_masks (bool): Whether to use high resolution masks or not. Defaults to False.
|
|
345
342
|
"""
|
|
346
|
-
|
|
347
343
|
if self.pil:
|
|
348
344
|
# Convert to numpy first
|
|
349
345
|
self.im = np.asarray(self.im).copy()
|
|
@@ -374,17 +370,18 @@ class Annotator:
|
|
|
374
370
|
Plot keypoints on the image.
|
|
375
371
|
|
|
376
372
|
Args:
|
|
377
|
-
kpts (
|
|
378
|
-
shape (tuple): Image shape
|
|
379
|
-
radius (int, optional):
|
|
380
|
-
kpt_line (bool, optional):
|
|
381
|
-
|
|
382
|
-
kpt_color (tuple, optional):
|
|
373
|
+
kpts (torch.Tensor): Keypoints, shape [17, 3] (x, y, confidence).
|
|
374
|
+
shape (tuple, optional): Image shape (h, w). Defaults to (640, 640).
|
|
375
|
+
radius (int, optional): Keypoint radius. Defaults to 5.
|
|
376
|
+
kpt_line (bool, optional): Draw lines between keypoints. Defaults to True.
|
|
377
|
+
conf_thres (float, optional): Confidence threshold. Defaults to 0.25.
|
|
378
|
+
kpt_color (tuple, optional): Keypoint color (B, G, R). Defaults to None.
|
|
383
379
|
|
|
384
380
|
Note:
|
|
385
|
-
`kpt_line=True` currently only supports human pose plotting.
|
|
381
|
+
- `kpt_line=True` currently only supports human pose plotting.
|
|
382
|
+
- Modifies self.im in-place.
|
|
383
|
+
- If self.pil is True, converts image to numpy array and back to PIL.
|
|
386
384
|
"""
|
|
387
|
-
|
|
388
385
|
if self.pil:
|
|
389
386
|
# Convert to numpy first
|
|
390
387
|
self.im = np.asarray(self.im).copy()
|
|
@@ -488,7 +485,6 @@ class Annotator:
|
|
|
488
485
|
Returns:
|
|
489
486
|
angle (degree): Degree value of angle between three points
|
|
490
487
|
"""
|
|
491
|
-
|
|
492
488
|
x_min, y_min, x_max, y_max = bbox
|
|
493
489
|
width = x_max - x_min
|
|
494
490
|
height = y_max - y_min
|
|
@@ -503,7 +499,6 @@ class Annotator:
|
|
|
503
499
|
color (tuple): Region Color value
|
|
504
500
|
thickness (int): Region area thickness value
|
|
505
501
|
"""
|
|
506
|
-
|
|
507
502
|
cv2.polylines(self.im, [np.array(reg_pts, dtype=np.int32)], isClosed=True, color=color, thickness=thickness)
|
|
508
503
|
|
|
509
504
|
def draw_centroid_and_tracks(self, track, color=(255, 0, 255), track_thickness=2):
|
|
@@ -515,7 +510,6 @@ class Annotator:
|
|
|
515
510
|
color (tuple): tracks line color
|
|
516
511
|
track_thickness (int): track line thickness value
|
|
517
512
|
"""
|
|
518
|
-
|
|
519
513
|
points = np.hstack(track).astype(np.int32).reshape((-1, 1, 2))
|
|
520
514
|
cv2.polylines(self.im, [points], isClosed=False, color=color, thickness=track_thickness)
|
|
521
515
|
cv2.circle(self.im, (int(track[-1][0]), int(track[-1][1])), track_thickness * 2, color, -1)
|
|
@@ -530,7 +524,6 @@ class Annotator:
|
|
|
530
524
|
region_color (RGB): queue region color
|
|
531
525
|
txt_color (RGB): text display color
|
|
532
526
|
"""
|
|
533
|
-
|
|
534
527
|
x_values = [point[0] for point in points]
|
|
535
528
|
y_values = [point[1] for point in points]
|
|
536
529
|
center_x = sum(x_values) // len(points)
|
|
@@ -574,7 +567,6 @@ class Annotator:
|
|
|
574
567
|
y_center (float): y position center point for bounding box
|
|
575
568
|
margin (int): gap between text and rectangle for better display
|
|
576
569
|
"""
|
|
577
|
-
|
|
578
570
|
text_size = cv2.getTextSize(text, 0, fontScale=self.sf, thickness=self.tf)[0]
|
|
579
571
|
text_x = x_center - text_size[0] // 2
|
|
580
572
|
text_y = y_center + text_size[1] // 2
|
|
@@ -597,7 +589,6 @@ class Annotator:
|
|
|
597
589
|
bg_color (bgr color): display color for text background
|
|
598
590
|
margin (int): gap between text and rectangle for better display
|
|
599
591
|
"""
|
|
600
|
-
|
|
601
592
|
horizontal_gap = int(im0.shape[1] * 0.02)
|
|
602
593
|
vertical_gap = int(im0.shape[0] * 0.01)
|
|
603
594
|
text_y_offset = 0
|
|
@@ -629,7 +620,6 @@ class Annotator:
|
|
|
629
620
|
Returns:
|
|
630
621
|
angle (degree): Degree value of angle between three points
|
|
631
622
|
"""
|
|
632
|
-
|
|
633
623
|
a, b, c = np.array(a), np.array(b), np.array(c)
|
|
634
624
|
radians = np.arctan2(c[1] - b[1], c[0] - b[0]) - np.arctan2(a[1] - b[1], a[0] - b[0])
|
|
635
625
|
angle = np.abs(radians * 180.0 / np.pi)
|
|
@@ -642,12 +632,19 @@ class Annotator:
|
|
|
642
632
|
Draw specific keypoints for gym steps counting.
|
|
643
633
|
|
|
644
634
|
Args:
|
|
645
|
-
keypoints (list):
|
|
646
|
-
indices (list):
|
|
647
|
-
shape (tuple):
|
|
648
|
-
radius (int): Keypoint radius
|
|
649
|
-
|
|
635
|
+
keypoints (list): Keypoints data to be plotted.
|
|
636
|
+
indices (list, optional): Keypoint indices to be plotted. Defaults to [2, 5, 7].
|
|
637
|
+
shape (tuple, optional): Image size for model inference. Defaults to (640, 640).
|
|
638
|
+
radius (int, optional): Keypoint radius. Defaults to 2.
|
|
639
|
+
conf_thres (float, optional): Confidence threshold for keypoints. Defaults to 0.25.
|
|
640
|
+
|
|
641
|
+
Returns:
|
|
642
|
+
(numpy.ndarray): Image with drawn keypoints.
|
|
650
643
|
|
|
644
|
+
Note:
|
|
645
|
+
Keypoint format: [x, y] or [x, y, confidence].
|
|
646
|
+
Modifies self.im in-place.
|
|
647
|
+
"""
|
|
651
648
|
if indices is None:
|
|
652
649
|
indices = [2, 5, 7]
|
|
653
650
|
for i, k in enumerate(keypoints):
|
|
@@ -675,7 +672,6 @@ class Annotator:
|
|
|
675
672
|
color (tuple): text background color for workout monitoring
|
|
676
673
|
txt_color (tuple): text foreground color for workout monitoring
|
|
677
674
|
"""
|
|
678
|
-
|
|
679
675
|
angle_text, count_text, stage_text = (f" {angle_text:.2f}", f"Steps : {count_text}", f" {stage_text}")
|
|
680
676
|
|
|
681
677
|
# Draw angle
|
|
@@ -744,7 +740,6 @@ class Annotator:
|
|
|
744
740
|
label (str): Detection label text
|
|
745
741
|
txt_color (RGB): text color
|
|
746
742
|
"""
|
|
747
|
-
|
|
748
743
|
cv2.polylines(self.im, [np.int32([mask])], isClosed=True, color=mask_color, thickness=2)
|
|
749
744
|
text_size, _ = cv2.getTextSize(label, 0, self.sf, self.tf)
|
|
750
745
|
|
|
@@ -772,7 +767,6 @@ class Annotator:
|
|
|
772
767
|
line_color (RGB): Distance line color.
|
|
773
768
|
centroid_color (RGB): Bounding box centroid color.
|
|
774
769
|
"""
|
|
775
|
-
|
|
776
770
|
(text_width_m, text_height_m), _ = cv2.getTextSize(f"Distance M: {distance_m:.2f}m", 0, self.sf, self.tf)
|
|
777
771
|
cv2.rectangle(self.im, (15, 25), (15 + text_width_m + 10, 25 + text_height_m + 20), line_color, -1)
|
|
778
772
|
cv2.putText(
|
|
@@ -813,7 +807,6 @@ class Annotator:
|
|
|
813
807
|
color (tuple): object centroid and line color value
|
|
814
808
|
pin_color (tuple): visioneye point color value
|
|
815
809
|
"""
|
|
816
|
-
|
|
817
810
|
center_bbox = int((box[0] + box[2]) / 2), int((box[1] + box[3]) / 2)
|
|
818
811
|
cv2.circle(self.im, center_point, self.tf * 2, pin_color, -1)
|
|
819
812
|
cv2.circle(self.im, center_bbox, self.tf * 2, color, -1)
|
|
@@ -902,11 +895,10 @@ def save_one_box(xyxy, im, file=Path("im.jpg"), gain=1.02, pad=10, square=False,
|
|
|
902
895
|
from ultralytics.utils.plotting import save_one_box
|
|
903
896
|
|
|
904
897
|
xyxy = [50, 50, 150, 150]
|
|
905
|
-
im = cv2.imread(
|
|
906
|
-
cropped_im = save_one_box(xyxy, im, file=
|
|
898
|
+
im = cv2.imread("image.jpg")
|
|
899
|
+
cropped_im = save_one_box(xyxy, im, file="cropped.jpg", square=True)
|
|
907
900
|
```
|
|
908
901
|
"""
|
|
909
|
-
|
|
910
902
|
if not isinstance(xyxy, torch.Tensor): # may be list
|
|
911
903
|
xyxy = torch.stack(xyxy)
|
|
912
904
|
b = ops.xyxy2xywh(xyxy.view(-1, 4)) # boxes
|
|
@@ -1109,7 +1101,7 @@ def plot_results(file="path/to/results.csv", dir="", segment=False, pose=False,
|
|
|
1109
1101
|
```python
|
|
1110
1102
|
from ultralytics.utils.plotting import plot_results
|
|
1111
1103
|
|
|
1112
|
-
plot_results(
|
|
1104
|
+
plot_results("path/to/results.csv", segment=True)
|
|
1113
1105
|
```
|
|
1114
1106
|
"""
|
|
1115
1107
|
import pandas as pd # scope for faster 'import ultralytics'
|
|
@@ -1171,7 +1163,6 @@ def plt_color_scatter(v, f, bins=20, cmap="viridis", alpha=0.8, edgecolors="none
|
|
|
1171
1163
|
>>> f = np.random.rand(100)
|
|
1172
1164
|
>>> plt_color_scatter(v, f)
|
|
1173
1165
|
"""
|
|
1174
|
-
|
|
1175
1166
|
# Calculate 2D histogram and corresponding colors
|
|
1176
1167
|
hist, xedges, yedges = np.histogram2d(v, f, bins=bins)
|
|
1177
1168
|
colors = [
|
|
@@ -1195,9 +1186,8 @@ def plot_tune_results(csv_file="tune_results.csv"):
|
|
|
1195
1186
|
csv_file (str, optional): Path to the CSV file containing the tuning results. Defaults to 'tune_results.csv'.
|
|
1196
1187
|
|
|
1197
1188
|
Examples:
|
|
1198
|
-
>>> plot_tune_results(
|
|
1189
|
+
>>> plot_tune_results("path/to/tune_results.csv")
|
|
1199
1190
|
"""
|
|
1200
|
-
|
|
1201
1191
|
import pandas as pd # scope for faster 'import ultralytics'
|
|
1202
1192
|
from scipy.ndimage import gaussian_filter1d
|
|
1203
1193
|
|