ultralytics 8.3.7__py3-none-any.whl → 8.3.9__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.

Files changed (34) hide show
  1. tests/test_solutions.py +4 -7
  2. ultralytics/__init__.py +4 -3
  3. ultralytics/cfg/__init__.py +3 -2
  4. ultralytics/cfg/solutions/default.yaml +9 -9
  5. ultralytics/data/converter.py +11 -8
  6. ultralytics/data/dataset.py +23 -23
  7. ultralytics/data/utils.py +3 -2
  8. ultralytics/engine/model.py +1 -3
  9. ultralytics/engine/trainer.py +7 -8
  10. ultralytics/models/yolo/detect/val.py +1 -1
  11. ultralytics/nn/autobackend.py +11 -6
  12. ultralytics/nn/tasks.py +18 -12
  13. ultralytics/solutions/object_counter.py +1 -1
  14. ultralytics/solutions/queue_management.py +43 -106
  15. ultralytics/solutions/solutions.py +5 -3
  16. ultralytics/solutions/speed_estimation.py +39 -79
  17. ultralytics/utils/__init__.py +22 -16
  18. ultralytics/utils/autobatch.py +3 -2
  19. ultralytics/utils/callbacks/clearml.py +2 -2
  20. ultralytics/utils/callbacks/comet.py +4 -4
  21. ultralytics/utils/callbacks/mlflow.py +1 -1
  22. ultralytics/utils/callbacks/neptune.py +5 -1
  23. ultralytics/utils/callbacks/tensorboard.py +16 -16
  24. ultralytics/utils/callbacks/wb.py +1 -1
  25. ultralytics/utils/checks.py +14 -8
  26. ultralytics/utils/downloads.py +3 -3
  27. ultralytics/utils/plotting.py +7 -10
  28. ultralytics/utils/torch_utils.py +3 -2
  29. {ultralytics-8.3.7.dist-info → ultralytics-8.3.9.dist-info}/METADATA +1 -1
  30. {ultralytics-8.3.7.dist-info → ultralytics-8.3.9.dist-info}/RECORD +34 -34
  31. {ultralytics-8.3.7.dist-info → ultralytics-8.3.9.dist-info}/LICENSE +0 -0
  32. {ultralytics-8.3.7.dist-info → ultralytics-8.3.9.dist-info}/WHEEL +0 -0
  33. {ultralytics-8.3.7.dist-info → ultralytics-8.3.9.dist-info}/entry_points.txt +0 -0
  34. {ultralytics-8.3.7.dist-info → ultralytics-8.3.9.dist-info}/top_level.txt +0 -0
@@ -1,116 +1,76 @@
1
1
  # Ultralytics YOLO 🚀, AGPL-3.0 license
2
2
 
3
- from collections import defaultdict
4
3
  from time import time
5
4
 
6
- import cv2
7
5
  import numpy as np
8
6
 
9
- from ultralytics.utils.checks import check_imshow
7
+ from ultralytics.solutions.solutions import BaseSolution, LineString
10
8
  from ultralytics.utils.plotting import Annotator, colors
11
9
 
12
10
 
13
- class SpeedEstimator:
11
+ class SpeedEstimator(BaseSolution):
14
12
  """A class to estimate the speed of objects in a real-time video stream based on their tracks."""
15
13
 
16
- def __init__(self, names, reg_pts=None, view_img=False, line_thickness=2, spdl_dist_thresh=10):
17
- """
18
- Initializes the SpeedEstimator with the given parameters.
19
-
20
- Args:
21
- names (dict): Dictionary of class names.
22
- reg_pts (list, optional): List of region points for speed estimation. Defaults to [(20, 400), (1260, 400)].
23
- view_img (bool, optional): Whether to display the image with annotations. Defaults to False.
24
- line_thickness (int, optional): Thickness of the lines for drawing boxes and tracks. Defaults to 2.
25
- spdl_dist_thresh (int, optional): Distance threshold for speed calculation. Defaults to 10.
26
- """
27
- # Region information
28
- self.reg_pts = reg_pts if reg_pts is not None else [(20, 400), (1260, 400)]
14
+ def __init__(self, **kwargs):
15
+ """Initializes the SpeedEstimator with the given parameters."""
16
+ super().__init__(**kwargs)
29
17
 
30
- self.names = names # Classes names
18
+ self.initialize_region() # Initialize speed region
31
19
 
32
- # Tracking information
33
- self.trk_history = defaultdict(list)
34
-
35
- self.view_img = view_img # bool for displaying inference
36
- self.tf = line_thickness # line thickness for annotator
37
20
  self.spd = {} # set for speed data
38
21
  self.trkd_ids = [] # list for already speed_estimated and tracked ID's
39
- self.spdl = spdl_dist_thresh # Speed line distance threshold
40
22
  self.trk_pt = {} # set for tracks previous time
41
23
  self.trk_pp = {} # set for tracks previous point
42
24
 
43
- # Check if the environment supports imshow
44
- self.env_check = check_imshow(warn=True)
45
-
46
- def estimate_speed(self, im0, tracks):
25
+ def estimate_speed(self, im0):
47
26
  """
48
27
  Estimates the speed of objects based on tracking data.
49
28
 
50
29
  Args:
51
- im0 (ndarray): Image.
52
- tracks (list): List of tracks obtained from the object tracking process.
53
-
54
- Returns:
55
- (ndarray): The image with annotated boxes and tracks.
30
+ im0 (ndarray): The input image that will be used for processing
31
+ Returns
32
+ im0 (ndarray): The processed image for more usage
56
33
  """
57
- if tracks[0].boxes.id is None:
58
- return im0
34
+ self.annotator = Annotator(im0, line_width=self.line_width) # Initialize annotator
35
+ self.extract_tracks(im0) # Extract tracks
59
36
 
60
- boxes = tracks[0].boxes.xyxy.cpu()
61
- clss = tracks[0].boxes.cls.cpu().tolist()
62
- t_ids = tracks[0].boxes.id.int().cpu().tolist()
63
- annotator = Annotator(im0, line_width=self.tf)
64
- annotator.draw_region(reg_pts=self.reg_pts, color=(255, 0, 255), thickness=self.tf * 2)
37
+ self.annotator.draw_region(
38
+ reg_pts=self.region, color=(104, 0, 123), thickness=self.line_width * 2
39
+ ) # Draw region
65
40
 
66
- for box, t_id, cls in zip(boxes, t_ids, clss):
67
- track = self.trk_history[t_id]
68
- bbox_center = (float((box[0] + box[2]) / 2), float((box[1] + box[3]) / 2))
69
- track.append(bbox_center)
41
+ for box, track_id, cls in zip(self.boxes, self.track_ids, self.clss):
42
+ self.store_tracking_history(track_id, box) # Store track history
70
43
 
71
- if len(track) > 30:
72
- track.pop(0)
44
+ # Check if track_id is already in self.trk_pp or trk_pt initialize if not
45
+ if track_id not in self.trk_pt:
46
+ self.trk_pt[track_id] = 0
47
+ if track_id not in self.trk_pp:
48
+ self.trk_pp[track_id] = self.track_line[-1]
73
49
 
74
- trk_pts = np.hstack(track).astype(np.int32).reshape((-1, 1, 2))
50
+ speed_label = f"{int(self.spd[track_id])} km/h" if track_id in self.spd else self.names[int(cls)]
51
+ self.annotator.box_label(box, label=speed_label, color=colors(track_id, True)) # Draw bounding box
75
52
 
76
- if t_id not in self.trk_pt:
77
- self.trk_pt[t_id] = 0
53
+ # Draw tracks of objects
54
+ self.annotator.draw_centroid_and_tracks(
55
+ self.track_line, color=colors(int(track_id), True), track_thickness=self.line_width
56
+ )
78
57
 
79
- speed_label = f"{int(self.spd[t_id])} km/h" if t_id in self.spd else self.names[int(cls)]
80
- bbox_color = colors(int(t_id), True)
81
-
82
- annotator.box_label(box, speed_label, bbox_color)
83
- cv2.polylines(im0, [trk_pts], isClosed=False, color=bbox_color, thickness=self.tf)
84
- cv2.circle(im0, (int(track[-1][0]), int(track[-1][1])), self.tf * 2, bbox_color, -1)
85
-
86
- # Calculation of object speed
87
- if not self.reg_pts[0][0] < track[-1][0] < self.reg_pts[1][0]:
88
- return
89
- if self.reg_pts[1][1] - self.spdl < track[-1][1] < self.reg_pts[1][1] + self.spdl:
90
- direction = "known"
91
- elif self.reg_pts[0][1] - self.spdl < track[-1][1] < self.reg_pts[0][1] + self.spdl:
58
+ # Calculate object speed and direction based on region intersection
59
+ if LineString([self.trk_pp[track_id], self.track_line[-1]]).intersects(self.l_s):
92
60
  direction = "known"
93
61
  else:
94
62
  direction = "unknown"
95
63
 
96
- if self.trk_pt.get(t_id) != 0 and direction != "unknown" and t_id not in self.trkd_ids:
97
- self.trkd_ids.append(t_id)
98
-
99
- time_difference = time() - self.trk_pt[t_id]
64
+ # Perform speed calculation and tracking updates if direction is valid
65
+ if direction == "known" and track_id not in self.trkd_ids:
66
+ self.trkd_ids.append(track_id)
67
+ time_difference = time() - self.trk_pt[track_id]
100
68
  if time_difference > 0:
101
- self.spd[t_id] = np.abs(track[-1][1] - self.trk_pp[t_id][1]) / time_difference
102
-
103
- self.trk_pt[t_id] = time()
104
- self.trk_pp[t_id] = track[-1]
105
-
106
- if self.view_img and self.env_check:
107
- cv2.imshow("Ultralytics Speed Estimation", im0)
108
- if cv2.waitKey(1) & 0xFF == ord("q"):
109
- return
69
+ self.spd[track_id] = np.abs(self.track_line[-1][1] - self.trk_pp[track_id][1]) / time_difference
110
70
 
111
- return im0
71
+ self.trk_pt[track_id] = time()
72
+ self.trk_pp[track_id] = self.track_line[-1]
112
73
 
74
+ self.display_output(im0) # display output with base class function
113
75
 
114
- if __name__ == "__main__":
115
- names = {0: "person", 1: "car"} # example class names
116
- speed_estimator = SpeedEstimator(names)
76
+ return im0 # return output image for more usage
@@ -523,10 +523,11 @@ def read_device_model() -> str:
523
523
  Returns:
524
524
  (str): Model file contents if read successfully or empty string otherwise.
525
525
  """
526
- with contextlib.suppress(Exception):
526
+ try:
527
527
  with open("/proc/device-tree/model") as f:
528
528
  return f.read()
529
- return ""
529
+ except: # noqa E722
530
+ return ""
530
531
 
531
532
 
532
533
  def is_ubuntu() -> bool:
@@ -536,10 +537,11 @@ def is_ubuntu() -> bool:
536
537
  Returns:
537
538
  (bool): True if OS is Ubuntu, False otherwise.
538
539
  """
539
- with contextlib.suppress(FileNotFoundError):
540
+ try:
540
541
  with open("/etc/os-release") as f:
541
542
  return "ID=ubuntu" in f.read()
542
- return False
543
+ except FileNotFoundError:
544
+ return False
543
545
 
544
546
 
545
547
  def is_colab():
@@ -569,11 +571,7 @@ def is_jupyter():
569
571
  Returns:
570
572
  (bool): True if running inside a Jupyter Notebook, False otherwise.
571
573
  """
572
- with contextlib.suppress(Exception):
573
- from IPython import get_ipython
574
-
575
- return get_ipython() is not None
576
- return False
574
+ return "get_ipython" in locals()
577
575
 
578
576
 
579
577
  def is_docker() -> bool:
@@ -583,10 +581,11 @@ def is_docker() -> bool:
583
581
  Returns:
584
582
  (bool): True if the script is running inside a Docker container, False otherwise.
585
583
  """
586
- with contextlib.suppress(Exception):
584
+ try:
587
585
  with open("/proc/self/cgroup") as f:
588
586
  return "docker" in f.read()
589
- return False
587
+ except: # noqa E722
588
+ return False
590
589
 
591
590
 
592
591
  def is_raspberrypi() -> bool:
@@ -617,14 +616,15 @@ def is_online() -> bool:
617
616
  Returns:
618
617
  (bool): True if connection is successful, False otherwise.
619
618
  """
620
- with contextlib.suppress(Exception):
619
+ try:
621
620
  assert str(os.getenv("YOLO_OFFLINE", "")).lower() != "true" # check if ENV var YOLO_OFFLINE="True"
622
621
  import socket
623
622
 
624
623
  for dns in ("1.1.1.1", "8.8.8.8"): # check Cloudflare and Google DNS
625
624
  socket.create_connection(address=(dns, 80), timeout=2.0).close()
626
625
  return True
627
- return False
626
+ except: # noqa E722
627
+ return False
628
628
 
629
629
 
630
630
  def is_pip_package(filepath: str = __name__) -> bool:
@@ -711,9 +711,11 @@ def get_git_origin_url():
711
711
  (str | None): The origin URL of the git repository or None if not git directory.
712
712
  """
713
713
  if IS_GIT_DIR:
714
- with contextlib.suppress(subprocess.CalledProcessError):
714
+ try:
715
715
  origin = subprocess.check_output(["git", "config", "--get", "remote.origin.url"])
716
716
  return origin.decode().strip()
717
+ except subprocess.CalledProcessError:
718
+ return None
717
719
 
718
720
 
719
721
  def get_git_branch():
@@ -724,9 +726,11 @@ def get_git_branch():
724
726
  (str | None): The current git branch name or None if not a git directory.
725
727
  """
726
728
  if IS_GIT_DIR:
727
- with contextlib.suppress(subprocess.CalledProcessError):
729
+ try:
728
730
  origin = subprocess.check_output(["git", "rev-parse", "--abbrev-ref", "HEAD"])
729
731
  return origin.decode().strip()
732
+ except subprocess.CalledProcessError:
733
+ return None
730
734
 
731
735
 
732
736
  def get_default_args(func):
@@ -751,9 +755,11 @@ def get_ubuntu_version():
751
755
  (str): Ubuntu version or None if not an Ubuntu OS.
752
756
  """
753
757
  if is_ubuntu():
754
- with contextlib.suppress(FileNotFoundError, AttributeError):
758
+ try:
755
759
  with open("/etc/os-release") as f:
756
760
  return re.search(r'VERSION_ID="(\d+\.\d+)"', f.read())[1]
761
+ except (FileNotFoundError, AttributeError):
762
+ return None
757
763
 
758
764
 
759
765
  def get_user_config_dir(sub_dir="Ultralytics"):
@@ -1,6 +1,7 @@
1
1
  # Ultralytics YOLO 🚀, AGPL-3.0 license
2
2
  """Functions for estimating the best YOLO batch size to use a fraction of the available CUDA memory in PyTorch."""
3
3
 
4
+ import os
4
5
  from copy import deepcopy
5
6
 
6
7
  import numpy as np
@@ -57,7 +58,7 @@ def autobatch(model, imgsz=640, fraction=0.60, batch_size=DEFAULT_CFG.batch):
57
58
 
58
59
  # Inspect CUDA memory
59
60
  gb = 1 << 30 # bytes to GiB (1024 ** 3)
60
- d = str(device).upper() # 'CUDA:0'
61
+ d = f"CUDA:{os.getenv('CUDA_VISIBLE_DEVICES', '0').strip()[0]}" # 'CUDA:0'
61
62
  properties = torch.cuda.get_device_properties(device) # device properties
62
63
  t = properties.total_memory / gb # GiB total
63
64
  r = torch.cuda.memory_reserved(device) / gb # GiB reserved
@@ -66,7 +67,7 @@ def autobatch(model, imgsz=640, fraction=0.60, batch_size=DEFAULT_CFG.batch):
66
67
  LOGGER.info(f"{prefix}{d} ({properties.name}) {t:.2f}G total, {r:.2f}G reserved, {a:.2f}G allocated, {f:.2f}G free")
67
68
 
68
69
  # Profile batch sizes
69
- batch_sizes = [1, 2, 4, 8, 16]
70
+ batch_sizes = [1, 2, 4, 8, 16] if t < 16 else [1, 2, 4, 8, 16, 32, 64]
70
71
  try:
71
72
  img = [torch.empty(b, 3, imgsz, imgsz) for b in batch_sizes]
72
73
  results = profile(img, model, n=1, device=device)
@@ -68,9 +68,9 @@ def on_pretrain_routine_start(trainer):
68
68
  PatchedMatplotlib.update_current_task(None)
69
69
  else:
70
70
  task = Task.init(
71
- project_name=trainer.args.project or "YOLOv8",
71
+ project_name=trainer.args.project or "Ultralytics",
72
72
  task_name=trainer.args.name,
73
- tags=["YOLOv8"],
73
+ tags=["Ultralytics"],
74
74
  output_uri=True,
75
75
  reuse_last_task_id=False,
76
76
  auto_connect_frameworks={"pytorch": False, "matplotlib": False},
@@ -15,7 +15,7 @@ try:
15
15
  # Ensures certain logging functions only run for supported tasks
16
16
  COMET_SUPPORTED_TASKS = ["detect"]
17
17
 
18
- # Names of plots created by YOLOv8 that are logged to Comet
18
+ # Names of plots created by Ultralytics that are logged to Comet
19
19
  EVALUATION_PLOT_NAMES = "F1_curve", "P_curve", "R_curve", "PR_curve", "confusion_matrix"
20
20
  LABEL_PLOT_NAMES = "labels", "labels_correlogram"
21
21
 
@@ -31,8 +31,8 @@ def _get_comet_mode():
31
31
 
32
32
 
33
33
  def _get_comet_model_name():
34
- """Returns the model name for Comet from the environment variable 'COMET_MODEL_NAME' or defaults to 'YOLOv8'."""
35
- return os.getenv("COMET_MODEL_NAME", "YOLOv8")
34
+ """Returns the model name for Comet from the environment variable COMET_MODEL_NAME or defaults to 'Ultralytics'."""
35
+ return os.getenv("COMET_MODEL_NAME", "Ultralytics")
36
36
 
37
37
 
38
38
  def _get_eval_batch_logging_interval():
@@ -110,7 +110,7 @@ def _fetch_trainer_metadata(trainer):
110
110
 
111
111
  def _scale_bounding_box_to_original_image_shape(box, resized_image_shape, original_image_shape, ratio_pad):
112
112
  """
113
- YOLOv8 resizes images during training and the label values are normalized based on this resized shape.
113
+ YOLO resizes images during training and the label values are normalized based on this resized shape.
114
114
 
115
115
  This function rescales the bounding box labels to the original image shape.
116
116
  """
@@ -71,7 +71,7 @@ def on_pretrain_routine_end(trainer):
71
71
  mlflow.set_tracking_uri(uri)
72
72
 
73
73
  # Set experiment and run names
74
- experiment_name = os.environ.get("MLFLOW_EXPERIMENT_NAME") or trainer.args.project or "/Shared/YOLOv8"
74
+ experiment_name = os.environ.get("MLFLOW_EXPERIMENT_NAME") or trainer.args.project or "/Shared/Ultralytics"
75
75
  run_name = os.environ.get("MLFLOW_RUN") or trainer.args.name
76
76
  mlflow.set_experiment(experiment_name)
77
77
 
@@ -52,7 +52,11 @@ def on_pretrain_routine_start(trainer):
52
52
  """Callback function called before the training routine starts."""
53
53
  try:
54
54
  global run
55
- run = neptune.init_run(project=trainer.args.project or "YOLOv8", name=trainer.args.name, tags=["YOLOv8"])
55
+ run = neptune.init_run(
56
+ project=trainer.args.project or "Ultralytics",
57
+ name=trainer.args.name,
58
+ tags=["Ultralytics"],
59
+ )
56
60
  run["Configuration/Hyperparameters"] = {k: "" if v is None else v for k, v in vars(trainer.args).items()}
57
61
  except Exception as e:
58
62
  LOGGER.warning(f"WARNING ⚠️ NeptuneAI installed but not initialized correctly, not logging this run. {e}")
@@ -1,6 +1,5 @@
1
1
  # Ultralytics YOLO 🚀, AGPL-3.0 license
2
2
 
3
- import contextlib
4
3
 
5
4
  from ultralytics.utils import LOGGER, SETTINGS, TESTS_RUNNING, colorstr
6
5
 
@@ -45,26 +44,27 @@ def _log_tensorboard_graph(trainer):
45
44
  warnings.simplefilter("ignore", category=torch.jit.TracerWarning) # suppress jit trace warning
46
45
 
47
46
  # Try simple method first (YOLO)
48
- with contextlib.suppress(Exception):
47
+ try:
49
48
  trainer.model.eval() # place in .eval() mode to avoid BatchNorm statistics changes
50
49
  WRITER.add_graph(torch.jit.trace(de_parallel(trainer.model), im, strict=False), [])
51
50
  LOGGER.info(f"{PREFIX}model graph visualization added ✅")
52
51
  return
53
52
 
54
- # Fallback to TorchScript export steps (RTDETR)
55
- try:
56
- model = deepcopy(de_parallel(trainer.model))
57
- model.eval()
58
- model = model.fuse(verbose=False)
59
- for m in model.modules():
60
- if hasattr(m, "export"): # Detect, RTDETRDecoder (Segment and Pose use Detect base class)
61
- m.export = True
62
- m.format = "torchscript"
63
- model(im) # dry run
64
- WRITER.add_graph(torch.jit.trace(model, im, strict=False), [])
65
- LOGGER.info(f"{PREFIX}model graph visualization added ✅")
66
- except Exception as e:
67
- LOGGER.warning(f"{PREFIX}WARNING ⚠️ TensorBoard graph visualization failure {e}")
53
+ except: # noqa E722
54
+ # Fallback to TorchScript export steps (RTDETR)
55
+ try:
56
+ model = deepcopy(de_parallel(trainer.model))
57
+ model.eval()
58
+ model = model.fuse(verbose=False)
59
+ for m in model.modules():
60
+ if hasattr(m, "export"): # Detect, RTDETRDecoder (Segment and Pose use Detect base class)
61
+ m.export = True
62
+ m.format = "torchscript"
63
+ model(im) # dry run
64
+ WRITER.add_graph(torch.jit.trace(model, im, strict=False), [])
65
+ LOGGER.info(f"{PREFIX}model graph visualization added ✅")
66
+ except Exception as e:
67
+ LOGGER.warning(f"{PREFIX}WARNING ⚠️ TensorBoard graph visualization failure {e}")
68
68
 
69
69
 
70
70
  def on_pretrain_routine_start(trainer):
@@ -109,7 +109,7 @@ def _log_plots(plots, step):
109
109
 
110
110
  def on_pretrain_routine_start(trainer):
111
111
  """Initiate and start project if module is present."""
112
- wb.run or wb.init(project=trainer.args.project or "YOLOv8", name=trainer.args.name, config=vars(trainer.args))
112
+ wb.run or wb.init(project=trainer.args.project or "Ultralytics", name=trainer.args.name, config=vars(trainer.args))
113
113
 
114
114
 
115
115
  def on_fit_epoch_end(trainer):
@@ -1,6 +1,5 @@
1
1
  # Ultralytics YOLO 🚀, AGPL-3.0 license
2
2
 
3
- import contextlib
4
3
  import glob
5
4
  import inspect
6
5
  import math
@@ -271,11 +270,13 @@ def check_latest_pypi_version(package_name="ultralytics"):
271
270
  Returns:
272
271
  (str): The latest version of the package.
273
272
  """
274
- with contextlib.suppress(Exception):
273
+ try:
275
274
  requests.packages.urllib3.disable_warnings() # Disable the InsecureRequestWarning
276
275
  response = requests.get(f"https://pypi.org/pypi/{package_name}/json", timeout=3)
277
276
  if response.status_code == 200:
278
277
  return response.json()["info"]["version"]
278
+ except: # noqa E722
279
+ return None
279
280
 
280
281
 
281
282
  def check_pip_update_available():
@@ -286,7 +287,7 @@ def check_pip_update_available():
286
287
  (bool): True if an update is available, False otherwise.
287
288
  """
288
289
  if ONLINE and IS_PIP_PACKAGE:
289
- with contextlib.suppress(Exception):
290
+ try:
290
291
  from ultralytics import __version__
291
292
 
292
293
  latest = check_latest_pypi_version()
@@ -296,6 +297,8 @@ def check_pip_update_available():
296
297
  f"Update with 'pip install -U ultralytics'"
297
298
  )
298
299
  return True
300
+ except: # noqa E722
301
+ pass
299
302
  return False
300
303
 
301
304
 
@@ -577,10 +580,12 @@ def check_yolo(verbose=True, device=""):
577
580
  ram = psutil.virtual_memory().total
578
581
  total, used, free = shutil.disk_usage("/")
579
582
  s = f"({os.cpu_count()} CPUs, {ram / gib:.1f} GB RAM, {(total - free) / gib:.1f}/{total / gib:.1f} GB disk)"
580
- with contextlib.suppress(Exception): # clear display if ipython is installed
583
+ try:
581
584
  from IPython import display
582
585
 
583
- display.clear_output()
586
+ display.clear_output() # clear display if notebook
587
+ except ImportError:
588
+ pass
584
589
  else:
585
590
  s = ""
586
591
 
@@ -619,7 +624,7 @@ def collect_system_info():
619
624
  for r in parse_requirements(package="ultralytics"):
620
625
  try:
621
626
  current = metadata.version(r.name)
622
- is_met = "✅ " if check_version(current, str(r.specifier), hard=True) else "❌ "
627
+ is_met = "✅ " if check_version(current, str(r.specifier), name=r.name, hard=True) else "❌ "
623
628
  except metadata.PackageNotFoundError:
624
629
  current = "(not installed)"
625
630
  is_met = "❌ "
@@ -707,9 +712,10 @@ def check_amp(model):
707
712
 
708
713
  def git_describe(path=ROOT): # path must be a directory
709
714
  """Return human-readable git description, i.e. v5.0-5-g3e25f1e https://git-scm.com/docs/git-describe."""
710
- with contextlib.suppress(Exception):
715
+ try:
711
716
  return subprocess.check_output(f"git -C {path} describe --tags --long --always", shell=True).decode()[:-1]
712
- return ""
717
+ except: # noqa E722
718
+ return ""
713
719
 
714
720
 
715
721
  def print_args(args: Optional[dict] = None, show_file=True, show_func=False):
@@ -1,6 +1,5 @@
1
1
  # Ultralytics YOLO 🚀, AGPL-3.0 license
2
2
 
3
- import contextlib
4
3
  import re
5
4
  import shutil
6
5
  import subprocess
@@ -53,7 +52,7 @@ def is_url(url, check=False):
53
52
  valid = is_url("https://www.example.com")
54
53
  ```
55
54
  """
56
- with contextlib.suppress(Exception):
55
+ try:
57
56
  url = str(url)
58
57
  result = parse.urlparse(url)
59
58
  assert all([result.scheme, result.netloc]) # check if is url
@@ -61,7 +60,8 @@ def is_url(url, check=False):
61
60
  with request.urlopen(url) as response:
62
61
  return response.getcode() == 200 # check if exists online
63
62
  return True
64
- return False
63
+ except: # noqa E722
64
+ return False
65
65
 
66
66
 
67
67
  def delete_dsstore(path, files_to_delete=(".DS_Store", "__MACOSX")):
@@ -1,6 +1,5 @@
1
1
  # Ultralytics YOLO 🚀, AGPL-3.0 license
2
2
 
3
- import contextlib
4
3
  import math
5
4
  import warnings
6
5
  from pathlib import Path
@@ -13,8 +12,8 @@ import torch
13
12
  from PIL import Image, ImageDraw, ImageFont
14
13
  from PIL import __version__ as pil_version
15
14
 
16
- from ultralytics.utils import IS_JUPYTER, LOGGER, TryExcept, ops, plt_settings, threaded
17
- from ultralytics.utils.checks import check_font, check_requirements, check_version, is_ascii
15
+ from ultralytics.utils import IS_COLAB, IS_KAGGLE, LOGGER, TryExcept, ops, plt_settings, threaded
16
+ from ultralytics.utils.checks import check_font, check_version, is_ascii
18
17
  from ultralytics.utils.files import increment_path
19
18
 
20
19
 
@@ -525,16 +524,12 @@ class Annotator:
525
524
  def show(self, title=None):
526
525
  """Show the annotated image."""
527
526
  im = Image.fromarray(np.asarray(self.im)[..., ::-1]) # Convert numpy array to PIL Image with RGB to BGR
528
- if IS_JUPYTER:
529
- check_requirements("ipython")
527
+ if IS_COLAB or IS_KAGGLE: # can not use IS_JUPYTER as will run for all ipython environments
530
528
  try:
531
- from IPython.display import display
532
-
533
- display(im)
529
+ display(im) # noqa - display() function only available in ipython environments
534
530
  except ImportError as e:
535
531
  LOGGER.warning(f"Unable to display image in Jupyter notebooks: {e}")
536
532
  else:
537
- # Convert numpy array to PIL Image and show
538
533
  im.show(title=title)
539
534
 
540
535
  def save(self, filename="image.jpg"):
@@ -1119,10 +1114,12 @@ def plot_images(
1119
1114
  mask = mask.astype(bool)
1120
1115
  else:
1121
1116
  mask = image_masks[j].astype(bool)
1122
- with contextlib.suppress(Exception):
1117
+ try:
1123
1118
  im[y : y + h, x : x + w, :][mask] = (
1124
1119
  im[y : y + h, x : x + w, :][mask] * 0.4 + np.array(color) * 0.6
1125
1120
  )
1121
+ except: # noqa E722
1122
+ pass
1126
1123
  annotator.fromarray(im)
1127
1124
  if not save:
1128
1125
  return np.asarray(annotator.im)
@@ -1,6 +1,5 @@
1
1
  # Ultralytics YOLO 🚀, AGPL-3.0 license
2
2
 
3
- import contextlib
4
3
  import gc
5
4
  import math
6
5
  import os
@@ -113,13 +112,15 @@ def get_cpu_info():
113
112
  from ultralytics.utils import PERSISTENT_CACHE # avoid circular import error
114
113
 
115
114
  if "cpu_info" not in PERSISTENT_CACHE:
116
- with contextlib.suppress(Exception):
115
+ try:
117
116
  import cpuinfo # pip install py-cpuinfo
118
117
 
119
118
  k = "brand_raw", "hardware_raw", "arch_string_raw" # keys sorted by preference
120
119
  info = cpuinfo.get_cpu_info() # info dict
121
120
  string = info.get(k[0] if k[0] in info else k[1] if k[1] in info else k[2], "unknown")
122
121
  PERSISTENT_CACHE["cpu_info"] = string.replace("(R)", "").replace("CPU ", "").replace("@ ", "")
122
+ except: # noqa E722
123
+ pass
123
124
  return PERSISTENT_CACHE.get("cpu_info", "unknown")
124
125
 
125
126
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: ultralytics
3
- Version: 8.3.7
3
+ Version: 8.3.9
4
4
  Summary: Ultralytics YOLO for SOTA object detection, multi-object tracking, instance segmentation, pose estimation and image classification.
5
5
  Author-email: Glenn Jocher <glenn.jocher@ultralytics.com>, Jing Qiu <jing.qiu@ultralytics.com>
6
6
  Maintainer-email: Ultralytics <hello@ultralytics.com>