ultralytics 8.3.88__py3-none-any.whl → 8.3.90__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.
Files changed (155) hide show
  1. tests/conftest.py +2 -2
  2. tests/test_cli.py +13 -11
  3. tests/test_cuda.py +10 -1
  4. tests/test_integrations.py +1 -5
  5. tests/test_python.py +16 -16
  6. tests/test_solutions.py +9 -9
  7. ultralytics/__init__.py +1 -1
  8. ultralytics/cfg/__init__.py +3 -1
  9. ultralytics/cfg/models/11/yolo11-cls.yaml +5 -5
  10. ultralytics/cfg/models/11/yolo11-obb.yaml +5 -5
  11. ultralytics/cfg/models/11/yolo11-pose.yaml +5 -5
  12. ultralytics/cfg/models/11/yolo11-seg.yaml +5 -5
  13. ultralytics/cfg/models/11/yolo11.yaml +5 -5
  14. ultralytics/cfg/models/v8/yolov8-ghost-p2.yaml +5 -5
  15. ultralytics/cfg/models/v8/yolov8-ghost-p6.yaml +5 -5
  16. ultralytics/cfg/models/v8/yolov8-ghost.yaml +5 -5
  17. ultralytics/cfg/models/v8/yolov8-obb.yaml +5 -5
  18. ultralytics/cfg/models/v8/yolov8-p6.yaml +5 -5
  19. ultralytics/cfg/models/v8/yolov8-rtdetr.yaml +5 -5
  20. ultralytics/cfg/models/v8/yolov8-world.yaml +5 -5
  21. ultralytics/cfg/models/v8/yolov8-worldv2.yaml +5 -5
  22. ultralytics/cfg/models/v8/yolov8.yaml +5 -5
  23. ultralytics/cfg/models/v9/yolov9c-seg.yaml +1 -1
  24. ultralytics/cfg/models/v9/yolov9c.yaml +1 -1
  25. ultralytics/cfg/models/v9/yolov9e-seg.yaml +1 -1
  26. ultralytics/cfg/models/v9/yolov9e.yaml +1 -1
  27. ultralytics/cfg/models/v9/yolov9m.yaml +1 -1
  28. ultralytics/cfg/models/v9/yolov9s.yaml +1 -1
  29. ultralytics/cfg/models/v9/yolov9t.yaml +1 -1
  30. ultralytics/data/annotator.py +9 -14
  31. ultralytics/data/base.py +125 -39
  32. ultralytics/data/build.py +63 -24
  33. ultralytics/data/converter.py +34 -33
  34. ultralytics/data/dataset.py +207 -53
  35. ultralytics/data/loaders.py +1 -0
  36. ultralytics/data/split_dota.py +39 -12
  37. ultralytics/data/utils.py +33 -47
  38. ultralytics/engine/exporter.py +19 -17
  39. ultralytics/engine/model.py +69 -90
  40. ultralytics/engine/predictor.py +106 -21
  41. ultralytics/engine/trainer.py +32 -23
  42. ultralytics/engine/tuner.py +31 -38
  43. ultralytics/engine/validator.py +75 -41
  44. ultralytics/hub/__init__.py +21 -26
  45. ultralytics/hub/auth.py +9 -12
  46. ultralytics/hub/session.py +76 -21
  47. ultralytics/hub/utils.py +19 -17
  48. ultralytics/models/fastsam/model.py +23 -17
  49. ultralytics/models/fastsam/predict.py +36 -16
  50. ultralytics/models/fastsam/utils.py +5 -5
  51. ultralytics/models/fastsam/val.py +6 -6
  52. ultralytics/models/nas/model.py +29 -24
  53. ultralytics/models/nas/predict.py +14 -11
  54. ultralytics/models/nas/val.py +11 -13
  55. ultralytics/models/rtdetr/model.py +20 -11
  56. ultralytics/models/rtdetr/predict.py +21 -21
  57. ultralytics/models/rtdetr/train.py +25 -24
  58. ultralytics/models/rtdetr/val.py +47 -14
  59. ultralytics/models/sam/__init__.py +1 -1
  60. ultralytics/models/sam/amg.py +50 -4
  61. ultralytics/models/sam/model.py +8 -14
  62. ultralytics/models/sam/modules/decoders.py +18 -21
  63. ultralytics/models/sam/modules/encoders.py +25 -46
  64. ultralytics/models/sam/modules/memory_attention.py +19 -15
  65. ultralytics/models/sam/modules/sam.py +18 -25
  66. ultralytics/models/sam/modules/tiny_encoder.py +19 -29
  67. ultralytics/models/sam/modules/transformer.py +35 -57
  68. ultralytics/models/sam/modules/utils.py +15 -15
  69. ultralytics/models/sam/predict.py +0 -3
  70. ultralytics/models/utils/loss.py +87 -36
  71. ultralytics/models/utils/ops.py +26 -31
  72. ultralytics/models/yolo/classify/predict.py +30 -12
  73. ultralytics/models/yolo/classify/train.py +83 -19
  74. ultralytics/models/yolo/classify/val.py +45 -23
  75. ultralytics/models/yolo/detect/predict.py +29 -19
  76. ultralytics/models/yolo/detect/train.py +90 -23
  77. ultralytics/models/yolo/detect/val.py +150 -29
  78. ultralytics/models/yolo/model.py +1 -2
  79. ultralytics/models/yolo/obb/predict.py +18 -13
  80. ultralytics/models/yolo/obb/train.py +12 -8
  81. ultralytics/models/yolo/obb/val.py +35 -22
  82. ultralytics/models/yolo/pose/predict.py +28 -15
  83. ultralytics/models/yolo/pose/train.py +21 -8
  84. ultralytics/models/yolo/pose/val.py +51 -31
  85. ultralytics/models/yolo/segment/predict.py +27 -16
  86. ultralytics/models/yolo/segment/train.py +11 -8
  87. ultralytics/models/yolo/segment/val.py +110 -29
  88. ultralytics/models/yolo/world/train.py +43 -16
  89. ultralytics/models/yolo/world/train_world.py +61 -36
  90. ultralytics/nn/autobackend.py +28 -14
  91. ultralytics/nn/modules/__init__.py +12 -12
  92. ultralytics/nn/modules/activation.py +12 -3
  93. ultralytics/nn/modules/block.py +587 -84
  94. ultralytics/nn/modules/conv.py +418 -54
  95. ultralytics/nn/modules/head.py +3 -4
  96. ultralytics/nn/modules/transformer.py +320 -34
  97. ultralytics/nn/modules/utils.py +17 -3
  98. ultralytics/nn/tasks.py +226 -79
  99. ultralytics/solutions/ai_gym.py +2 -2
  100. ultralytics/solutions/analytics.py +4 -4
  101. ultralytics/solutions/heatmap.py +4 -4
  102. ultralytics/solutions/instance_segmentation.py +10 -4
  103. ultralytics/solutions/object_blurrer.py +2 -2
  104. ultralytics/solutions/object_counter.py +2 -2
  105. ultralytics/solutions/object_cropper.py +2 -2
  106. ultralytics/solutions/parking_management.py +9 -9
  107. ultralytics/solutions/queue_management.py +1 -1
  108. ultralytics/solutions/region_counter.py +2 -2
  109. ultralytics/solutions/security_alarm.py +7 -7
  110. ultralytics/solutions/solutions.py +7 -4
  111. ultralytics/solutions/speed_estimation.py +2 -2
  112. ultralytics/solutions/streamlit_inference.py +6 -6
  113. ultralytics/solutions/trackzone.py +9 -2
  114. ultralytics/solutions/vision_eye.py +4 -4
  115. ultralytics/trackers/basetrack.py +1 -1
  116. ultralytics/trackers/bot_sort.py +23 -22
  117. ultralytics/trackers/byte_tracker.py +4 -4
  118. ultralytics/trackers/track.py +2 -1
  119. ultralytics/trackers/utils/gmc.py +26 -27
  120. ultralytics/trackers/utils/kalman_filter.py +31 -29
  121. ultralytics/trackers/utils/matching.py +7 -7
  122. ultralytics/utils/__init__.py +37 -35
  123. ultralytics/utils/autobatch.py +5 -5
  124. ultralytics/utils/benchmarks.py +111 -18
  125. ultralytics/utils/callbacks/base.py +3 -3
  126. ultralytics/utils/callbacks/clearml.py +11 -11
  127. ultralytics/utils/callbacks/comet.py +35 -22
  128. ultralytics/utils/callbacks/dvc.py +11 -10
  129. ultralytics/utils/callbacks/hub.py +8 -8
  130. ultralytics/utils/callbacks/mlflow.py +1 -1
  131. ultralytics/utils/callbacks/neptune.py +12 -10
  132. ultralytics/utils/callbacks/raytune.py +1 -1
  133. ultralytics/utils/callbacks/tensorboard.py +6 -6
  134. ultralytics/utils/callbacks/wb.py +16 -16
  135. ultralytics/utils/checks.py +139 -68
  136. ultralytics/utils/dist.py +15 -2
  137. ultralytics/utils/downloads.py +37 -56
  138. ultralytics/utils/files.py +12 -13
  139. ultralytics/utils/instance.py +117 -52
  140. ultralytics/utils/loss.py +28 -33
  141. ultralytics/utils/metrics.py +246 -181
  142. ultralytics/utils/ops.py +65 -61
  143. ultralytics/utils/patches.py +8 -6
  144. ultralytics/utils/plotting.py +72 -59
  145. ultralytics/utils/tal.py +88 -57
  146. ultralytics/utils/torch_utils.py +202 -64
  147. ultralytics/utils/triton.py +13 -3
  148. ultralytics/utils/tuner.py +13 -25
  149. {ultralytics-8.3.88.dist-info → ultralytics-8.3.90.dist-info}/METADATA +2 -2
  150. ultralytics-8.3.90.dist-info/RECORD +250 -0
  151. ultralytics-8.3.88.dist-info/RECORD +0 -250
  152. {ultralytics-8.3.88.dist-info → ultralytics-8.3.90.dist-info}/LICENSE +0 -0
  153. {ultralytics-8.3.88.dist-info → ultralytics-8.3.90.dist-info}/WHEEL +0 -0
  154. {ultralytics-8.3.88.dist-info → ultralytics-8.3.90.dist-info}/entry_points.txt +0 -0
  155. {ultralytics-8.3.88.dist-info → ultralytics-8.3.90.dist-info}/top_level.txt +0 -0
@@ -48,10 +48,8 @@ def is_url(url, check=False):
48
48
  (bool): Returns True for a valid URL. If 'check' is True, also returns True if the URL exists online.
49
49
  Returns False otherwise.
50
50
 
51
- Example:
52
- ```python
53
- valid = is_url("https://www.example.com")
54
- ```
51
+ Examples:
52
+ >>> valid = is_url("https://www.example.com")
55
53
  """
56
54
  try:
57
55
  url = str(url)
@@ -67,20 +65,17 @@ def is_url(url, check=False):
67
65
 
68
66
  def delete_dsstore(path, files_to_delete=(".DS_Store", "__MACOSX")):
69
67
  """
70
- Deletes all ".DS_store" files under a specified directory.
68
+ Delete all ".DS_store" files in a specified directory.
71
69
 
72
70
  Args:
73
71
  path (str, optional): The directory path where the ".DS_store" files should be deleted.
74
72
  files_to_delete (tuple): The files to be deleted.
75
73
 
76
- Example:
77
- ```python
78
- from ultralytics.utils.downloads import delete_dsstore
74
+ Examples:
75
+ >>> from ultralytics.utils.downloads import delete_dsstore
76
+ >>> delete_dsstore("path/to/dir")
79
77
 
80
- delete_dsstore("path/to/dir")
81
- ```
82
-
83
- Note:
78
+ Notes:
84
79
  ".DS_store" files are created by the Apple operating system and contain metadata about folders and files. They
85
80
  are hidden system files and can cause issues when transferring files between different operating systems.
86
81
  """
@@ -105,12 +100,9 @@ def zip_directory(directory, compress=True, exclude=(".DS_Store", "__MACOSX"), p
105
100
  Returns:
106
101
  (Path): The path to the resulting zip file.
107
102
 
108
- Example:
109
- ```python
110
- from ultralytics.utils.downloads import zip_directory
111
-
112
- file = zip_directory("path/to/dir")
113
- ```
103
+ Examples:
104
+ >>> from ultralytics.utils.downloads import zip_directory
105
+ >>> file = zip_directory("path/to/dir")
114
106
  """
115
107
  from zipfile import ZIP_DEFLATED, ZIP_STORED, ZipFile
116
108
 
@@ -140,7 +132,7 @@ def unzip_file(file, path=None, exclude=(".DS_Store", "__MACOSX"), exist_ok=Fals
140
132
 
141
133
  Args:
142
134
  file (str | Path): The path to the zipfile to be extracted.
143
- path (str, optional): The path to extract the zipfile to. Defaults to None.
135
+ path (str | Path, optional): The path to extract the zipfile to. Defaults to None.
144
136
  exclude (tuple, optional): A tuple of filename strings to be excluded. Defaults to ('.DS_Store', '__MACOSX').
145
137
  exist_ok (bool, optional): Whether to overwrite existing contents if they exist. Defaults to False.
146
138
  progress (bool, optional): Whether to display a progress bar. Defaults to True.
@@ -151,12 +143,9 @@ def unzip_file(file, path=None, exclude=(".DS_Store", "__MACOSX"), exist_ok=Fals
151
143
  Returns:
152
144
  (Path): The path to the directory where the zipfile was extracted.
153
145
 
154
- Example:
155
- ```python
156
- from ultralytics.utils.downloads import unzip_file
157
-
158
- dir = unzip_file("path/to/file.zip")
159
- ```
146
+ Examples:
147
+ >>> from ultralytics.utils.downloads import unzip_file
148
+ >>> directory = unzip_file("path/to/file.zip")
160
149
  """
161
150
  from zipfile import BadZipFile, ZipFile, is_zipfile
162
151
 
@@ -245,13 +234,10 @@ def get_google_drive_file_info(link):
245
234
  (str): Direct download URL for the Google Drive file.
246
235
  (str): Original filename of the Google Drive file. If filename extraction fails, returns None.
247
236
 
248
- Example:
249
- ```python
250
- from ultralytics.utils.downloads import get_google_drive_file_info
251
-
252
- link = "https://drive.google.com/file/d/1cqT-cJgANNrhIHCrEufUYhQ4RqiWG_lJ/view?usp=drive_link"
253
- url, filename = get_google_drive_file_info(link)
254
- ```
237
+ Examples:
238
+ >>> from ultralytics.utils.downloads import get_google_drive_file_info
239
+ >>> link = "https://drive.google.com/file/d/1cqT-cJgANNrhIHCrEufUYhQ4RqiWG_lJ/view?usp=drive_link"
240
+ >>> url, filename = get_google_drive_file_info(link)
255
241
  """
256
242
  file_id = link.split("/d/")[1].split("/view")[0]
257
243
  drive_url = f"https://drive.google.com/uc?export=download&id={file_id}"
@@ -294,7 +280,7 @@ def safe_download(
294
280
  url (str): The URL of the file to be downloaded.
295
281
  file (str, optional): The filename of the downloaded file.
296
282
  If not provided, the file will be saved with the same name as the URL.
297
- dir (str, optional): The directory to save the downloaded file.
283
+ dir (str | Path, optional): The directory to save the downloaded file.
298
284
  If not provided, the file will be saved in the current working directory.
299
285
  unzip (bool, optional): Whether to unzip the downloaded file. Default: True.
300
286
  delete (bool, optional): Whether to delete the downloaded file after unzipping. Default: False.
@@ -305,13 +291,13 @@ def safe_download(
305
291
  exist_ok (bool, optional): Whether to overwrite existing contents during unzipping. Defaults to False.
306
292
  progress (bool, optional): Whether to display a progress bar during the download. Default: True.
307
293
 
308
- Example:
309
- ```python
310
- from ultralytics.utils.downloads import safe_download
294
+ Returns:
295
+ (Path | str): The path to the downloaded file or extracted directory.
311
296
 
312
- link = "https://ultralytics.com/assets/bus.jpg"
313
- path = safe_download(link)
314
- ```
297
+ Examples:
298
+ >>> from ultralytics.utils.downloads import safe_download
299
+ >>> link = "https://ultralytics.com/assets/bus.jpg"
300
+ >>> path = safe_download(link)
315
301
  """
316
302
  gdrive = url.startswith("https://drive.google.com/") # check if the URL is a Google Drive link
317
303
  if gdrive:
@@ -376,6 +362,7 @@ def safe_download(
376
362
  if delete:
377
363
  f.unlink() # remove zip
378
364
  return unzip_dir
365
+ return f
379
366
 
380
367
 
381
368
  def get_github_assets(repo="ultralytics/assets", version="latest", retry=False):
@@ -389,12 +376,11 @@ def get_github_assets(repo="ultralytics/assets", version="latest", retry=False):
389
376
  retry (bool, optional): Flag to retry the request in case of a failure. Defaults to False.
390
377
 
391
378
  Returns:
392
- (tuple): A tuple containing the release tag and a list of asset names.
379
+ (str): The release tag.
380
+ (List[str]): A list of asset names.
393
381
 
394
- Example:
395
- ```python
396
- tag, assets = get_github_assets(repo="ultralytics/assets", version="latest")
397
- ```
382
+ Examples:
383
+ >>> tag, assets = get_github_assets(repo="ultralytics/assets", version="latest")
398
384
  """
399
385
  if version != "latest":
400
386
  version = f"tags/{version}" # i.e. tags/v6.2
@@ -411,22 +397,19 @@ def get_github_assets(repo="ultralytics/assets", version="latest", retry=False):
411
397
 
412
398
  def attempt_download_asset(file, repo="ultralytics/assets", release="v8.3.0", **kwargs):
413
399
  """
414
- Attempt to download a file from GitHub release assets if it is not found locally. The function checks for the file
415
- locally first, then tries to download it from the specified GitHub repository release.
400
+ Attempt to download a file from GitHub release assets if it is not found locally.
416
401
 
417
402
  Args:
418
403
  file (str | Path): The filename or file path to be downloaded.
419
404
  repo (str, optional): The GitHub repository in the format 'owner/repo'. Defaults to 'ultralytics/assets'.
420
405
  release (str, optional): The specific release version to be downloaded. Defaults to 'v8.3.0'.
421
- **kwargs (any): Additional keyword arguments for the download process.
406
+ **kwargs (Any): Additional keyword arguments for the download process.
422
407
 
423
408
  Returns:
424
409
  (str): The path to the downloaded file.
425
410
 
426
- Example:
427
- ```python
428
- file_path = attempt_download_asset("yolo11n.pt", repo="ultralytics/assets", release="latest")
429
- ```
411
+ Examples:
412
+ >>> file_path = attempt_download_asset("yolo11n.pt", repo="ultralytics/assets", release="latest")
430
413
  """
431
414
  from ultralytics.utils import SETTINGS # scoped for circular import
432
415
 
@@ -469,7 +452,7 @@ def download(url, dir=Path.cwd(), unzip=True, delete=False, curl=False, threads=
469
452
  specified.
470
453
 
471
454
  Args:
472
- url (str | list): The URL or list of URLs of the files to be downloaded.
455
+ url (str | List[str]): The URL or list of URLs of the files to be downloaded.
473
456
  dir (Path, optional): The directory where the files will be saved. Defaults to the current working directory.
474
457
  unzip (bool, optional): Flag to unzip the files after downloading. Defaults to True.
475
458
  delete (bool, optional): Flag to delete the zip files after extraction. Defaults to False.
@@ -478,10 +461,8 @@ def download(url, dir=Path.cwd(), unzip=True, delete=False, curl=False, threads=
478
461
  retry (int, optional): Number of retries in case of download failure. Defaults to 3.
479
462
  exist_ok (bool, optional): Whether to overwrite existing contents during unzipping. Defaults to False.
480
463
 
481
- Example:
482
- ```python
483
- download("https://ultralytics.com/assets/example.zip", dir="path/to/dir", unzip=True)
484
- ```
464
+ Examples:
465
+ >>> download("https://ultralytics.com/assets/example.zip", dir="path/to/dir", unzip=True)
485
466
  """
486
467
  dir = Path(dir)
487
468
  dir.mkdir(parents=True, exist_ok=True) # make directory
@@ -18,7 +18,7 @@ class WorkingDirectory(contextlib.ContextDecorator):
18
18
  It ensures that the original working directory is restored after the context or decorated function completes.
19
19
 
20
20
  Attributes:
21
- dir (Path): The new directory to switch to.
21
+ dir (Path | str): The new directory to switch to.
22
22
  cwd (Path): The original current working directory before the switch.
23
23
 
24
24
  Methods:
@@ -55,21 +55,21 @@ class WorkingDirectory(contextlib.ContextDecorator):
55
55
  @contextmanager
56
56
  def spaces_in_path(path):
57
57
  """
58
- Context manager to handle paths with spaces in their names. If a path contains spaces, it replaces them with
59
- underscores, copies the file/directory to the new path, executes the context code block, then copies the
60
- file/directory back to its original location.
58
+ Context manager to handle paths with spaces in their names.
59
+
60
+ If a path contains spaces, it replaces them with underscores, copies the file/directory to the new path, executes
61
+ the context code block, then copies the file/directory back to its original location.
61
62
 
62
63
  Args:
63
64
  path (str | Path): The original path that may contain spaces.
64
65
 
65
66
  Yields:
66
- (Path): Temporary path with spaces replaced by underscores if spaces were present, otherwise the original path.
67
+ (Path | str): Temporary path with spaces replaced by underscores if spaces were present, otherwise the original path.
67
68
 
68
69
  Examples:
69
- Use the context manager to handle paths with spaces:
70
- >>> from ultralytics.utils.files import spaces_in_path
71
70
  >>> with spaces_in_path('/path/with spaces') as new_path:
72
71
  >>> # Your code here
72
+ >>> pass
73
73
  """
74
74
  # If path has spaces, replace them with underscores
75
75
  if " " in str(path):
@@ -106,21 +106,20 @@ def spaces_in_path(path):
106
106
 
107
107
  def increment_path(path, exist_ok=False, sep="", mkdir=False):
108
108
  """
109
- Increments a file or directory path, i.e., runs/exp --> runs/exp{sep}2, runs/exp{sep}3, ... etc.
109
+ Increment a file or directory path, i.e., runs/exp --> runs/exp{sep}2, runs/exp{sep}3, ... etc.
110
110
 
111
111
  If the path exists and `exist_ok` is not True, the path will be incremented by appending a number and `sep` to
112
112
  the end of the path. If the path is a file, the file extension will be preserved. If the path is a directory, the
113
- number will be appended directly to the end of the path. If `mkdir` is set to True, the path will be created as a
114
- directory if it does not already exist.
113
+ number will be appended directly to the end of the path.
115
114
 
116
115
  Args:
117
- path (str | pathlib.Path): Path to increment.
116
+ path (str | Path): Path to increment.
118
117
  exist_ok (bool): If True, the path will not be incremented and returned as-is.
119
118
  sep (str): Separator to use between the path and the incrementation number.
120
119
  mkdir (bool): Create a directory if it does not exist.
121
120
 
122
121
  Returns:
123
- (pathlib.Path): Incremented path.
122
+ (Path): Incremented path.
124
123
 
125
124
  Examples:
126
125
  Increment a directory path:
@@ -185,7 +184,7 @@ def get_latest_run(search_dir="."):
185
184
 
186
185
  def update_models(model_names=("yolo11n.pt",), source_dir=Path("."), update_names=False):
187
186
  """
188
- Updates and re-saves specified YOLO models in an 'updated_models' subdirectory.
187
+ Update and re-save specified YOLO models in an 'updated_models' subdirectory.
189
188
 
190
189
  Args:
191
190
  model_names (Tuple[str, ...]): Model filenames to update.
@@ -14,7 +14,7 @@ def _ntuple(n):
14
14
  """From PyTorch internals."""
15
15
 
16
16
  def parse(x):
17
- """Parse bounding boxes format between XYWH and LTWH."""
17
+ """Parse input to return n-tuple by repeating singleton values n times."""
18
18
  return x if isinstance(x, abc.Iterable) else tuple(repeat(x, n))
19
19
 
20
20
  return parse
@@ -39,7 +39,7 @@ class Bboxes:
39
39
  Bounding box data should be provided in numpy arrays.
40
40
 
41
41
  Attributes:
42
- bboxes (numpy.ndarray): The bounding boxes stored in a 2D numpy array.
42
+ bboxes (np.ndarray): The bounding boxes stored in a 2D numpy array with shape (N, 4).
43
43
  format (str): The format of the bounding boxes ('xyxy', 'xywh', or 'ltwh').
44
44
 
45
45
  Note:
@@ -47,7 +47,13 @@ class Bboxes:
47
47
  """
48
48
 
49
49
  def __init__(self, bboxes, format="xyxy") -> None:
50
- """Initializes the Bboxes class with bounding box data in a specified format."""
50
+ """
51
+ Initialize the Bboxes class with bounding box data in a specified format.
52
+
53
+ Args:
54
+ bboxes (np.ndarray): Array of bounding boxes with shape (N, 4) or (4,).
55
+ format (str): Format of the bounding boxes, one of 'xyxy', 'xywh', or 'ltwh'.
56
+ """
51
57
  assert format in _formats, f"Invalid bounding box format: {format}, format must be one of {_formats}"
52
58
  bboxes = bboxes[None, :] if bboxes.ndim == 1 else bboxes
53
59
  assert bboxes.ndim == 2
@@ -57,7 +63,12 @@ class Bboxes:
57
63
  # self.normalized = normalized
58
64
 
59
65
  def convert(self, format):
60
- """Converts bounding box format from one type to another."""
66
+ """
67
+ Convert bounding box format from one type to another.
68
+
69
+ Args:
70
+ format (str): Target format for conversion, one of 'xyxy', 'xywh', or 'ltwh'.
71
+ """
61
72
  assert format in _formats, f"Invalid bounding box format: {format}, format must be one of {_formats}"
62
73
  if self.format == format:
63
74
  return
@@ -140,10 +151,9 @@ class Bboxes:
140
151
  Args:
141
152
  boxes_list (List[Bboxes]): A list of Bboxes objects to concatenate.
142
153
  axis (int, optional): The axis along which to concatenate the bounding boxes.
143
- Defaults to 0.
144
154
 
145
155
  Returns:
146
- Bboxes: A new Bboxes object containing the concatenated bounding boxes.
156
+ (Bboxes): A new Bboxes object containing the concatenated bounding boxes.
147
157
 
148
158
  Note:
149
159
  The input should be a list or tuple of Bboxes objects.
@@ -162,11 +172,11 @@ class Bboxes:
162
172
  Retrieve a specific bounding box or a set of bounding boxes using indexing.
163
173
 
164
174
  Args:
165
- index (int, slice, or np.ndarray): The index, slice, or boolean array to select
166
- the desired bounding boxes.
175
+ index (int | slice | np.ndarray): The index, slice, or boolean array to select
176
+ the desired bounding boxes.
167
177
 
168
178
  Returns:
169
- Bboxes: A new Bboxes object containing the selected bounding boxes.
179
+ (Bboxes): A new Bboxes object containing the selected bounding boxes.
170
180
 
171
181
  Raises:
172
182
  AssertionError: If the indexed bounding boxes do not form a 2-dimensional matrix.
@@ -188,30 +198,29 @@ class Instances:
188
198
 
189
199
  Attributes:
190
200
  _bboxes (Bboxes): Internal object for handling bounding box operations.
191
- keypoints (np.ndarray): keypoints(x, y, visible) with shape [N, 17, 3]. Default is None.
201
+ keypoints (np.ndarray): Keypoints with shape (N, 17, 3) in format (x, y, visible).
192
202
  normalized (bool): Flag indicating whether the bounding box coordinates are normalized.
193
- segments (np.ndarray): Segments array with shape [N, 1000, 2] after resampling.
194
-
195
- Args:
196
- bboxes (np.ndarray): An array of bounding boxes with shape [N, 4].
197
- segments (list | ndarray, optional): A list or array of object segments. Default is None.
198
- keypoints (ndarray, optional): An array of keypoints with shape [N, 17, 3]. Default is None.
199
- bbox_format (str, optional): The format of bounding boxes ('xywh' or 'xyxy'). Default is 'xywh'.
200
- normalized (bool, optional): Whether the bounding box coordinates are normalized. Default is True.
203
+ segments (np.ndarray): Segments array with shape (N, M, 2) after resampling.
204
+
205
+ Methods:
206
+ convert_bbox: Convert bounding box format.
207
+ scale: Scale coordinates by given factors.
208
+ denormalize: Convert normalized coordinates to absolute coordinates.
209
+ normalize: Convert absolute coordinates to normalized coordinates.
210
+ add_padding: Add padding to coordinates.
211
+ flipud: Flip coordinates vertically.
212
+ fliplr: Flip coordinates horizontally.
213
+ clip: Clip coordinates to stay within image boundaries.
214
+ remove_zero_area_boxes: Remove boxes with zero area.
215
+ update: Update instance variables.
216
+ concatenate: Concatenate multiple Instances objects.
201
217
 
202
218
  Examples:
203
- ```python
204
- # Create an Instances object
205
- instances = Instances(
206
- bboxes=np.array([[10, 10, 30, 30], [20, 20, 40, 40]]),
207
- segments=[np.array([[5, 5], [10, 10]]), np.array([[15, 15], [20, 20]])],
208
- keypoints=np.array([[[5, 5, 1], [10, 10, 1]], [[15, 15, 1], [20, 20, 1]]]),
209
- )
210
- ```
211
-
212
- Note:
213
- The bounding box format is either 'xywh' or 'xyxy', and is determined by the `bbox_format` argument.
214
- This class does not perform input validation, and it assumes the inputs are well-formed.
219
+ >>> instances = Instances(
220
+ ... bboxes=np.array([[10, 10, 30, 30], [20, 20, 40, 40]]),
221
+ ... segments=[np.array([[5, 5], [10, 10]]), np.array([[15, 15], [20, 20]])],
222
+ ... keypoints=np.array([[[5, 5, 1], [10, 10, 1]], [[15, 15, 1], [20, 20, 1]]]),
223
+ ... )
215
224
  """
216
225
 
217
226
  def __init__(self, bboxes, segments=None, keypoints=None, bbox_format="xywh", normalized=True) -> None:
@@ -219,11 +228,11 @@ class Instances:
219
228
  Initialize the object with bounding boxes, segments, and keypoints.
220
229
 
221
230
  Args:
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.
231
+ bboxes (np.ndarray): Bounding boxes, shape (N, 4).
232
+ segments (List | np.ndarray, optional): Segmentation masks.
233
+ keypoints (np.ndarray, optional): Keypoints, shape (N, 17, 3) in format (x, y, visible).
234
+ bbox_format (str, optional): Format of bboxes.
235
+ normalized (bool, optional): Whether the coordinates are normalized.
227
236
  """
228
237
  self._bboxes = Bboxes(bboxes=bboxes, format=bbox_format)
229
238
  self.keypoints = keypoints
@@ -231,7 +240,12 @@ class Instances:
231
240
  self.segments = segments
232
241
 
233
242
  def convert_bbox(self, format):
234
- """Convert bounding box format."""
243
+ """
244
+ Convert bounding box format.
245
+
246
+ Args:
247
+ format (str): Target format for conversion, one of 'xyxy', 'xywh', or 'ltwh'.
248
+ """
235
249
  self._bboxes.convert(format=format)
236
250
 
237
251
  @property
@@ -240,7 +254,14 @@ class Instances:
240
254
  return self._bboxes.areas()
241
255
 
242
256
  def scale(self, scale_w, scale_h, bbox_only=False):
243
- """Similar to denormalize func but without normalized sign."""
257
+ """
258
+ Scale coordinates by given factors.
259
+
260
+ Args:
261
+ scale_w (float): Scale factor for width.
262
+ scale_h (float): Scale factor for height.
263
+ bbox_only (bool, optional): Whether to scale only bounding boxes.
264
+ """
244
265
  self._bboxes.mul(scale=(scale_w, scale_h, scale_w, scale_h))
245
266
  if bbox_only:
246
267
  return
@@ -251,7 +272,13 @@ class Instances:
251
272
  self.keypoints[..., 1] *= scale_h
252
273
 
253
274
  def denormalize(self, w, h):
254
- """Denormalizes boxes, segments, and keypoints from normalized coordinates."""
275
+ """
276
+ Convert normalized coordinates to absolute coordinates.
277
+
278
+ Args:
279
+ w (int): Image width.
280
+ h (int): Image height.
281
+ """
255
282
  if not self.normalized:
256
283
  return
257
284
  self._bboxes.mul(scale=(w, h, w, h))
@@ -263,7 +290,13 @@ class Instances:
263
290
  self.normalized = False
264
291
 
265
292
  def normalize(self, w, h):
266
- """Normalize bounding boxes, segments, and keypoints to image dimensions."""
293
+ """
294
+ Convert absolute coordinates to normalized coordinates.
295
+
296
+ Args:
297
+ w (int): Image width.
298
+ h (int): Image height.
299
+ """
267
300
  if self.normalized:
268
301
  return
269
302
  self._bboxes.mul(scale=(1 / w, 1 / h, 1 / w, 1 / h))
@@ -275,7 +308,13 @@ class Instances:
275
308
  self.normalized = True
276
309
 
277
310
  def add_padding(self, padw, padh):
278
- """Handle rect and mosaic situation."""
311
+ """
312
+ Add padding to coordinates.
313
+
314
+ Args:
315
+ padw (int): Padding width.
316
+ padh (int): Padding height.
317
+ """
279
318
  assert not self.normalized, "you should add padding with absolute coordinates."
280
319
  self._bboxes.add(offset=(padw, padh, padw, padh))
281
320
  self.segments[..., 0] += padw
@@ -289,12 +328,10 @@ class Instances:
289
328
  Retrieve a specific instance or a set of instances using indexing.
290
329
 
291
330
  Args:
292
- index (int, slice, or np.ndarray): The index, slice, or boolean array to select
293
- the desired instances.
331
+ index (int | slice | np.ndarray): The index, slice, or boolean array to select the desired instances.
294
332
 
295
333
  Returns:
296
- Instances: A new Instances object containing the selected bounding boxes,
297
- segments, and keypoints if present.
334
+ (Instances): A new Instances object containing the selected boxes, segments, and keypoints if present.
298
335
 
299
336
  Note:
300
337
  When using boolean indexing, make sure to provide a boolean array with the same
@@ -313,7 +350,12 @@ class Instances:
313
350
  )
314
351
 
315
352
  def flipud(self, h):
316
- """Flips the coordinates of bounding boxes, segments, and keypoints vertically."""
353
+ """
354
+ Flip coordinates vertically.
355
+
356
+ Args:
357
+ h (int): Image height.
358
+ """
317
359
  if self._bboxes.format == "xyxy":
318
360
  y1 = self.bboxes[:, 1].copy()
319
361
  y2 = self.bboxes[:, 3].copy()
@@ -326,7 +368,12 @@ class Instances:
326
368
  self.keypoints[..., 1] = h - self.keypoints[..., 1]
327
369
 
328
370
  def fliplr(self, w):
329
- """Reverses the order of the bounding boxes and segments horizontally."""
371
+ """
372
+ Flip coordinates horizontally.
373
+
374
+ Args:
375
+ w (int): Image width.
376
+ """
330
377
  if self._bboxes.format == "xyxy":
331
378
  x1 = self.bboxes[:, 0].copy()
332
379
  x2 = self.bboxes[:, 2].copy()
@@ -339,7 +386,13 @@ class Instances:
339
386
  self.keypoints[..., 0] = w - self.keypoints[..., 0]
340
387
 
341
388
  def clip(self, w, h):
342
- """Clips bounding boxes, segments, and keypoints values to stay within image boundaries."""
389
+ """
390
+ Clip coordinates to stay within image boundaries.
391
+
392
+ Args:
393
+ w (int): Image width.
394
+ h (int): Image height.
395
+ """
343
396
  ori_format = self._bboxes.format
344
397
  self.convert_bbox(format="xyxy")
345
398
  self.bboxes[:, [0, 2]] = self.bboxes[:, [0, 2]].clip(0, w)
@@ -353,7 +406,12 @@ class Instances:
353
406
  self.keypoints[..., 1] = self.keypoints[..., 1].clip(0, h)
354
407
 
355
408
  def remove_zero_area_boxes(self):
356
- """Remove zero-area boxes, i.e. after clipping some boxes may have zero width or height."""
409
+ """
410
+ Remove zero-area boxes, i.e. after clipping some boxes may have zero width or height.
411
+
412
+ Returns:
413
+ (np.ndarray): Boolean array indicating which boxes were kept.
414
+ """
357
415
  good = self.bbox_areas > 0
358
416
  if not all(good):
359
417
  self._bboxes = self._bboxes[good]
@@ -364,7 +422,14 @@ class Instances:
364
422
  return good
365
423
 
366
424
  def update(self, bboxes, segments=None, keypoints=None):
367
- """Updates instance variables."""
425
+ """
426
+ Update instance variables.
427
+
428
+ Args:
429
+ bboxes (np.ndarray): New bounding boxes.
430
+ segments (np.ndarray, optional): New segments.
431
+ keypoints (np.ndarray, optional): New keypoints.
432
+ """
368
433
  self._bboxes = Bboxes(bboxes, format=self._bboxes.format)
369
434
  if segments is not None:
370
435
  self.segments = segments
@@ -378,14 +443,14 @@ class Instances:
378
443
  @classmethod
379
444
  def concatenate(cls, instances_list: List["Instances"], axis=0) -> "Instances":
380
445
  """
381
- Concatenates a list of Instances objects into a single Instances object.
446
+ Concatenate a list of Instances objects into a single Instances object.
382
447
 
383
448
  Args:
384
449
  instances_list (List[Instances]): A list of Instances objects to concatenate.
385
- axis (int, optional): The axis along which the arrays will be concatenated. Defaults to 0.
450
+ axis (int, optional): The axis along which the arrays will be concatenated.
386
451
 
387
452
  Returns:
388
- Instances: A new Instances object containing the concatenated bounding boxes,
453
+ (Instances): A new Instances object containing the concatenated bounding boxes,
389
454
  segments, and keypoints if present.
390
455
 
391
456
  Note: