ultralytics 8.0.238__py3-none-any.whl → 8.0.239__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 (134) hide show
  1. ultralytics/__init__.py +2 -2
  2. ultralytics/cfg/__init__.py +241 -138
  3. ultralytics/data/__init__.py +9 -2
  4. ultralytics/data/annotator.py +4 -4
  5. ultralytics/data/augment.py +186 -169
  6. ultralytics/data/base.py +54 -48
  7. ultralytics/data/build.py +34 -23
  8. ultralytics/data/converter.py +242 -70
  9. ultralytics/data/dataset.py +117 -95
  10. ultralytics/data/explorer/__init__.py +3 -1
  11. ultralytics/data/explorer/explorer.py +120 -100
  12. ultralytics/data/explorer/gui/__init__.py +1 -0
  13. ultralytics/data/explorer/gui/dash.py +123 -89
  14. ultralytics/data/explorer/utils.py +37 -39
  15. ultralytics/data/loaders.py +75 -62
  16. ultralytics/data/split_dota.py +44 -36
  17. ultralytics/data/utils.py +160 -142
  18. ultralytics/engine/exporter.py +348 -292
  19. ultralytics/engine/model.py +102 -66
  20. ultralytics/engine/predictor.py +74 -55
  21. ultralytics/engine/results.py +61 -41
  22. ultralytics/engine/trainer.py +192 -144
  23. ultralytics/engine/tuner.py +66 -59
  24. ultralytics/engine/validator.py +31 -26
  25. ultralytics/hub/__init__.py +54 -31
  26. ultralytics/hub/auth.py +28 -25
  27. ultralytics/hub/session.py +282 -133
  28. ultralytics/hub/utils.py +64 -42
  29. ultralytics/models/__init__.py +1 -1
  30. ultralytics/models/fastsam/__init__.py +1 -1
  31. ultralytics/models/fastsam/model.py +6 -6
  32. ultralytics/models/fastsam/predict.py +3 -2
  33. ultralytics/models/fastsam/prompt.py +55 -48
  34. ultralytics/models/fastsam/val.py +1 -1
  35. ultralytics/models/nas/__init__.py +1 -1
  36. ultralytics/models/nas/model.py +9 -8
  37. ultralytics/models/nas/predict.py +8 -6
  38. ultralytics/models/nas/val.py +11 -9
  39. ultralytics/models/rtdetr/__init__.py +1 -1
  40. ultralytics/models/rtdetr/model.py +11 -9
  41. ultralytics/models/rtdetr/train.py +18 -16
  42. ultralytics/models/rtdetr/val.py +25 -19
  43. ultralytics/models/sam/__init__.py +1 -1
  44. ultralytics/models/sam/amg.py +13 -14
  45. ultralytics/models/sam/build.py +44 -42
  46. ultralytics/models/sam/model.py +6 -6
  47. ultralytics/models/sam/modules/decoders.py +6 -4
  48. ultralytics/models/sam/modules/encoders.py +37 -35
  49. ultralytics/models/sam/modules/sam.py +5 -4
  50. ultralytics/models/sam/modules/tiny_encoder.py +95 -73
  51. ultralytics/models/sam/modules/transformer.py +3 -2
  52. ultralytics/models/sam/predict.py +39 -27
  53. ultralytics/models/utils/loss.py +99 -95
  54. ultralytics/models/utils/ops.py +34 -31
  55. ultralytics/models/yolo/__init__.py +1 -1
  56. ultralytics/models/yolo/classify/__init__.py +1 -1
  57. ultralytics/models/yolo/classify/predict.py +8 -6
  58. ultralytics/models/yolo/classify/train.py +37 -31
  59. ultralytics/models/yolo/classify/val.py +26 -24
  60. ultralytics/models/yolo/detect/__init__.py +1 -1
  61. ultralytics/models/yolo/detect/predict.py +8 -6
  62. ultralytics/models/yolo/detect/train.py +47 -37
  63. ultralytics/models/yolo/detect/val.py +100 -82
  64. ultralytics/models/yolo/model.py +31 -25
  65. ultralytics/models/yolo/obb/__init__.py +1 -1
  66. ultralytics/models/yolo/obb/predict.py +13 -11
  67. ultralytics/models/yolo/obb/train.py +3 -3
  68. ultralytics/models/yolo/obb/val.py +70 -59
  69. ultralytics/models/yolo/pose/__init__.py +1 -1
  70. ultralytics/models/yolo/pose/predict.py +17 -12
  71. ultralytics/models/yolo/pose/train.py +28 -25
  72. ultralytics/models/yolo/pose/val.py +91 -64
  73. ultralytics/models/yolo/segment/__init__.py +1 -1
  74. ultralytics/models/yolo/segment/predict.py +10 -8
  75. ultralytics/models/yolo/segment/train.py +16 -15
  76. ultralytics/models/yolo/segment/val.py +90 -68
  77. ultralytics/nn/__init__.py +26 -6
  78. ultralytics/nn/autobackend.py +144 -112
  79. ultralytics/nn/modules/__init__.py +96 -13
  80. ultralytics/nn/modules/block.py +28 -7
  81. ultralytics/nn/modules/conv.py +41 -23
  82. ultralytics/nn/modules/head.py +60 -52
  83. ultralytics/nn/modules/transformer.py +49 -32
  84. ultralytics/nn/modules/utils.py +20 -15
  85. ultralytics/nn/tasks.py +215 -141
  86. ultralytics/solutions/ai_gym.py +59 -47
  87. ultralytics/solutions/distance_calculation.py +17 -14
  88. ultralytics/solutions/heatmap.py +57 -55
  89. ultralytics/solutions/object_counter.py +46 -39
  90. ultralytics/solutions/speed_estimation.py +13 -16
  91. ultralytics/trackers/__init__.py +1 -1
  92. ultralytics/trackers/basetrack.py +1 -0
  93. ultralytics/trackers/bot_sort.py +2 -1
  94. ultralytics/trackers/byte_tracker.py +10 -7
  95. ultralytics/trackers/track.py +7 -7
  96. ultralytics/trackers/utils/gmc.py +25 -25
  97. ultralytics/trackers/utils/kalman_filter.py +85 -42
  98. ultralytics/trackers/utils/matching.py +8 -7
  99. ultralytics/utils/__init__.py +173 -152
  100. ultralytics/utils/autobatch.py +10 -10
  101. ultralytics/utils/benchmarks.py +76 -86
  102. ultralytics/utils/callbacks/__init__.py +1 -1
  103. ultralytics/utils/callbacks/base.py +29 -29
  104. ultralytics/utils/callbacks/clearml.py +51 -43
  105. ultralytics/utils/callbacks/comet.py +81 -66
  106. ultralytics/utils/callbacks/dvc.py +33 -26
  107. ultralytics/utils/callbacks/hub.py +44 -26
  108. ultralytics/utils/callbacks/mlflow.py +31 -24
  109. ultralytics/utils/callbacks/neptune.py +35 -25
  110. ultralytics/utils/callbacks/raytune.py +9 -4
  111. ultralytics/utils/callbacks/tensorboard.py +16 -11
  112. ultralytics/utils/callbacks/wb.py +39 -33
  113. ultralytics/utils/checks.py +189 -141
  114. ultralytics/utils/dist.py +15 -12
  115. ultralytics/utils/downloads.py +112 -96
  116. ultralytics/utils/errors.py +1 -1
  117. ultralytics/utils/files.py +11 -11
  118. ultralytics/utils/instance.py +22 -22
  119. ultralytics/utils/loss.py +117 -67
  120. ultralytics/utils/metrics.py +224 -158
  121. ultralytics/utils/ops.py +38 -28
  122. ultralytics/utils/patches.py +3 -3
  123. ultralytics/utils/plotting.py +217 -120
  124. ultralytics/utils/tal.py +19 -13
  125. ultralytics/utils/torch_utils.py +138 -109
  126. ultralytics/utils/triton.py +12 -10
  127. ultralytics/utils/tuner.py +49 -47
  128. {ultralytics-8.0.238.dist-info → ultralytics-8.0.239.dist-info}/METADATA +2 -1
  129. ultralytics-8.0.239.dist-info/RECORD +188 -0
  130. ultralytics-8.0.238.dist-info/RECORD +0 -188
  131. {ultralytics-8.0.238.dist-info → ultralytics-8.0.239.dist-info}/LICENSE +0 -0
  132. {ultralytics-8.0.238.dist-info → ultralytics-8.0.239.dist-info}/WHEEL +0 -0
  133. {ultralytics-8.0.238.dist-info → ultralytics-8.0.239.dist-info}/entry_points.txt +0 -0
  134. {ultralytics-8.0.238.dist-info → ultralytics-8.0.239.dist-info}/top_level.txt +0 -0
@@ -26,7 +26,7 @@ class AIGym:
26
26
  self.angle = None
27
27
  self.count = None
28
28
  self.stage = None
29
- self.pose_type = 'pushup'
29
+ self.pose_type = "pushup"
30
30
  self.kpts_to_check = None
31
31
 
32
32
  # Visual Information
@@ -36,13 +36,15 @@ class AIGym:
36
36
  # Check if environment support imshow
37
37
  self.env_check = check_imshow(warn=True)
38
38
 
39
- def set_args(self,
40
- kpts_to_check,
41
- line_thickness=2,
42
- view_img=False,
43
- pose_up_angle=145.0,
44
- pose_down_angle=90.0,
45
- pose_type='pullup'):
39
+ def set_args(
40
+ self,
41
+ kpts_to_check,
42
+ line_thickness=2,
43
+ view_img=False,
44
+ pose_up_angle=145.0,
45
+ pose_down_angle=90.0,
46
+ pose_type="pullup",
47
+ ):
46
48
  """
47
49
  Configures the AIGym line_thickness, save image and view image parameters
48
50
  Args:
@@ -72,65 +74,75 @@ class AIGym:
72
74
  if frame_count == 1:
73
75
  self.count = [0] * len(results[0])
74
76
  self.angle = [0] * len(results[0])
75
- self.stage = ['-' for _ in results[0]]
77
+ self.stage = ["-" for _ in results[0]]
76
78
  self.keypoints = results[0].keypoints.data
77
79
  self.annotator = Annotator(im0, line_width=2)
78
80
 
79
81
  for ind, k in enumerate(reversed(self.keypoints)):
80
- if self.pose_type == 'pushup' or self.pose_type == 'pullup':
81
- self.angle[ind] = self.annotator.estimate_pose_angle(k[int(self.kpts_to_check[0])].cpu(),
82
- k[int(self.kpts_to_check[1])].cpu(),
83
- k[int(self.kpts_to_check[2])].cpu())
82
+ if self.pose_type == "pushup" or self.pose_type == "pullup":
83
+ self.angle[ind] = self.annotator.estimate_pose_angle(
84
+ k[int(self.kpts_to_check[0])].cpu(),
85
+ k[int(self.kpts_to_check[1])].cpu(),
86
+ k[int(self.kpts_to_check[2])].cpu(),
87
+ )
84
88
  self.im0 = self.annotator.draw_specific_points(k, self.kpts_to_check, shape=(640, 640), radius=10)
85
89
 
86
- if self.pose_type == 'abworkout':
87
- self.angle[ind] = self.annotator.estimate_pose_angle(k[int(self.kpts_to_check[0])].cpu(),
88
- k[int(self.kpts_to_check[1])].cpu(),
89
- k[int(self.kpts_to_check[2])].cpu())
90
+ if self.pose_type == "abworkout":
91
+ self.angle[ind] = self.annotator.estimate_pose_angle(
92
+ k[int(self.kpts_to_check[0])].cpu(),
93
+ k[int(self.kpts_to_check[1])].cpu(),
94
+ k[int(self.kpts_to_check[2])].cpu(),
95
+ )
90
96
  self.im0 = self.annotator.draw_specific_points(k, self.kpts_to_check, shape=(640, 640), radius=10)
91
97
  if self.angle[ind] > self.poseup_angle:
92
- self.stage[ind] = 'down'
93
- if self.angle[ind] < self.posedown_angle and self.stage[ind] == 'down':
94
- self.stage[ind] = 'up'
98
+ self.stage[ind] = "down"
99
+ if self.angle[ind] < self.posedown_angle and self.stage[ind] == "down":
100
+ self.stage[ind] = "up"
95
101
  self.count[ind] += 1
96
- self.annotator.plot_angle_and_count_and_stage(angle_text=self.angle[ind],
97
- count_text=self.count[ind],
98
- stage_text=self.stage[ind],
99
- center_kpt=k[int(self.kpts_to_check[1])],
100
- line_thickness=self.tf)
101
-
102
- if self.pose_type == 'pushup':
102
+ self.annotator.plot_angle_and_count_and_stage(
103
+ angle_text=self.angle[ind],
104
+ count_text=self.count[ind],
105
+ stage_text=self.stage[ind],
106
+ center_kpt=k[int(self.kpts_to_check[1])],
107
+ line_thickness=self.tf,
108
+ )
109
+
110
+ if self.pose_type == "pushup":
103
111
  if self.angle[ind] > self.poseup_angle:
104
- self.stage[ind] = 'up'
105
- if self.angle[ind] < self.posedown_angle and self.stage[ind] == 'up':
106
- self.stage[ind] = 'down'
112
+ self.stage[ind] = "up"
113
+ if self.angle[ind] < self.posedown_angle and self.stage[ind] == "up":
114
+ self.stage[ind] = "down"
107
115
  self.count[ind] += 1
108
- self.annotator.plot_angle_and_count_and_stage(angle_text=self.angle[ind],
109
- count_text=self.count[ind],
110
- stage_text=self.stage[ind],
111
- center_kpt=k[int(self.kpts_to_check[1])],
112
- line_thickness=self.tf)
113
- if self.pose_type == 'pullup':
116
+ self.annotator.plot_angle_and_count_and_stage(
117
+ angle_text=self.angle[ind],
118
+ count_text=self.count[ind],
119
+ stage_text=self.stage[ind],
120
+ center_kpt=k[int(self.kpts_to_check[1])],
121
+ line_thickness=self.tf,
122
+ )
123
+ if self.pose_type == "pullup":
114
124
  if self.angle[ind] > self.poseup_angle:
115
- self.stage[ind] = 'down'
116
- if self.angle[ind] < self.posedown_angle and self.stage[ind] == 'down':
117
- self.stage[ind] = 'up'
125
+ self.stage[ind] = "down"
126
+ if self.angle[ind] < self.posedown_angle and self.stage[ind] == "down":
127
+ self.stage[ind] = "up"
118
128
  self.count[ind] += 1
119
- self.annotator.plot_angle_and_count_and_stage(angle_text=self.angle[ind],
120
- count_text=self.count[ind],
121
- stage_text=self.stage[ind],
122
- center_kpt=k[int(self.kpts_to_check[1])],
123
- line_thickness=self.tf)
129
+ self.annotator.plot_angle_and_count_and_stage(
130
+ angle_text=self.angle[ind],
131
+ count_text=self.count[ind],
132
+ stage_text=self.stage[ind],
133
+ center_kpt=k[int(self.kpts_to_check[1])],
134
+ line_thickness=self.tf,
135
+ )
124
136
 
125
137
  self.annotator.kpts(k, shape=(640, 640), radius=1, kpt_line=True)
126
138
 
127
139
  if self.env_check and self.view_img:
128
- cv2.imshow('Ultralytics YOLOv8 AI GYM', self.im0)
129
- if cv2.waitKey(1) & 0xFF == ord('q'):
140
+ cv2.imshow("Ultralytics YOLOv8 AI GYM", self.im0)
141
+ if cv2.waitKey(1) & 0xFF == ord("q"):
130
142
  return
131
143
 
132
144
  return self.im0
133
145
 
134
146
 
135
- if __name__ == '__main__':
147
+ if __name__ == "__main__":
136
148
  AIGym()
@@ -41,13 +41,15 @@ class DistanceCalculation:
41
41
  # Check if environment support imshow
42
42
  self.env_check = check_imshow(warn=True)
43
43
 
44
- def set_args(self,
45
- names,
46
- pixels_per_meter=10,
47
- view_img=False,
48
- line_thickness=2,
49
- line_color=(255, 255, 0),
50
- centroid_color=(255, 0, 255)):
44
+ def set_args(
45
+ self,
46
+ names,
47
+ pixels_per_meter=10,
48
+ view_img=False,
49
+ line_thickness=2,
50
+ line_color=(255, 255, 0),
51
+ centroid_color=(255, 0, 255),
52
+ ):
51
53
  """
52
54
  Configures the distance calculation and display parameters.
53
55
 
@@ -129,8 +131,9 @@ class DistanceCalculation:
129
131
  distance (float): Distance between two centroids
130
132
  """
131
133
  cv2.rectangle(self.im0, (15, 25), (280, 70), (255, 255, 255), -1)
132
- cv2.putText(self.im0, f'Distance : {distance:.2f}m', (20, 55), cv2.FONT_HERSHEY_SIMPLEX, 0.8, (0, 0, 0), 2,
133
- cv2.LINE_AA)
134
+ cv2.putText(
135
+ self.im0, f"Distance : {distance:.2f}m", (20, 55), cv2.FONT_HERSHEY_SIMPLEX, 0.8, (0, 0, 0), 2, cv2.LINE_AA
136
+ )
134
137
  cv2.line(self.im0, self.centroids[0], self.centroids[1], self.line_color, 3)
135
138
  cv2.circle(self.im0, self.centroids[0], 6, self.centroid_color, -1)
136
139
  cv2.circle(self.im0, self.centroids[1], 6, self.centroid_color, -1)
@@ -179,13 +182,13 @@ class DistanceCalculation:
179
182
 
180
183
  def display_frames(self):
181
184
  """Display frame."""
182
- cv2.namedWindow('Ultralytics Distance Estimation')
183
- cv2.setMouseCallback('Ultralytics Distance Estimation', self.mouse_event_for_distance)
184
- cv2.imshow('Ultralytics Distance Estimation', self.im0)
185
+ cv2.namedWindow("Ultralytics Distance Estimation")
186
+ cv2.setMouseCallback("Ultralytics Distance Estimation", self.mouse_event_for_distance)
187
+ cv2.imshow("Ultralytics Distance Estimation", self.im0)
185
188
 
186
- if cv2.waitKey(1) & 0xFF == ord('q'):
189
+ if cv2.waitKey(1) & 0xFF == ord("q"):
187
190
  return
188
191
 
189
192
 
190
- if __name__ == '__main__':
193
+ if __name__ == "__main__":
191
194
  DistanceCalculation()
@@ -8,7 +8,7 @@ import numpy as np
8
8
  from ultralytics.utils.checks import check_imshow, check_requirements
9
9
  from ultralytics.utils.plotting import Annotator
10
10
 
11
- check_requirements('shapely>=2.0.0')
11
+ check_requirements("shapely>=2.0.0")
12
12
 
13
13
  from shapely.geometry import LineString, Point, Polygon
14
14
 
@@ -22,7 +22,7 @@ class Heatmap:
22
22
  # Visual information
23
23
  self.annotator = None
24
24
  self.view_img = False
25
- self.shape = 'circle'
25
+ self.shape = "circle"
26
26
 
27
27
  # Image information
28
28
  self.imw = None
@@ -63,23 +63,25 @@ class Heatmap:
63
63
  # Check if environment support imshow
64
64
  self.env_check = check_imshow(warn=True)
65
65
 
66
- def set_args(self,
67
- imw,
68
- imh,
69
- colormap=cv2.COLORMAP_JET,
70
- heatmap_alpha=0.5,
71
- view_img=False,
72
- view_in_counts=True,
73
- view_out_counts=True,
74
- count_reg_pts=None,
75
- count_txt_thickness=2,
76
- count_txt_color=(0, 0, 0),
77
- count_color=(255, 255, 255),
78
- count_reg_color=(255, 0, 255),
79
- region_thickness=5,
80
- line_dist_thresh=15,
81
- decay_factor=0.99,
82
- shape='circle'):
66
+ def set_args(
67
+ self,
68
+ imw,
69
+ imh,
70
+ colormap=cv2.COLORMAP_JET,
71
+ heatmap_alpha=0.5,
72
+ view_img=False,
73
+ view_in_counts=True,
74
+ view_out_counts=True,
75
+ count_reg_pts=None,
76
+ count_txt_thickness=2,
77
+ count_txt_color=(0, 0, 0),
78
+ count_color=(255, 255, 255),
79
+ count_reg_color=(255, 0, 255),
80
+ region_thickness=5,
81
+ line_dist_thresh=15,
82
+ decay_factor=0.99,
83
+ shape="circle",
84
+ ):
83
85
  """
84
86
  Configures the heatmap colormap, width, height and display parameters.
85
87
 
@@ -111,20 +113,19 @@ class Heatmap:
111
113
 
112
114
  # Region and line selection
113
115
  if count_reg_pts is not None:
114
-
115
116
  if len(count_reg_pts) == 2:
116
- print('Line Counter Initiated.')
117
+ print("Line Counter Initiated.")
117
118
  self.count_reg_pts = count_reg_pts
118
119
  self.counting_region = LineString(count_reg_pts)
119
120
 
120
121
  elif len(count_reg_pts) == 4:
121
- print('Region Counter Initiated.')
122
+ print("Region Counter Initiated.")
122
123
  self.count_reg_pts = count_reg_pts
123
124
  self.counting_region = Polygon(self.count_reg_pts)
124
125
 
125
126
  else:
126
- print('Region or line points Invalid, 2 or 4 points supported')
127
- print('Using Line Counter Now')
127
+ print("Region or line points Invalid, 2 or 4 points supported")
128
+ print("Using Line Counter Now")
128
129
  self.counting_region = Polygon([(20, 400), (1260, 400)]) # dummy points
129
130
 
130
131
  # Heatmap new frame
@@ -140,10 +141,10 @@ class Heatmap:
140
141
  self.shape = shape
141
142
 
142
143
  # shape of heatmap, if not selected
143
- if self.shape not in ['circle', 'rect']:
144
+ if self.shape not in ["circle", "rect"]:
144
145
  print("Unknown shape value provided, 'circle' & 'rect' supported")
145
- print('Using Circular shape now')
146
- self.shape = 'circle'
146
+ print("Using Circular shape now")
147
+ self.shape = "circle"
147
148
 
148
149
  def extract_results(self, tracks):
149
150
  """
@@ -177,27 +178,26 @@ class Heatmap:
177
178
  self.annotator = Annotator(self.im0, self.count_txt_thickness, None)
178
179
 
179
180
  if self.count_reg_pts is not None:
180
-
181
181
  # Draw counting region
182
182
  if self.view_in_counts or self.view_out_counts:
183
- self.annotator.draw_region(reg_pts=self.count_reg_pts,
184
- color=self.region_color,
185
- thickness=self.region_thickness)
183
+ self.annotator.draw_region(
184
+ reg_pts=self.count_reg_pts, color=self.region_color, thickness=self.region_thickness
185
+ )
186
186
 
187
187
  for box, cls, track_id in zip(self.boxes, self.clss, self.track_ids):
188
-
189
- if self.shape == 'circle':
188
+ if self.shape == "circle":
190
189
  center = (int((box[0] + box[2]) // 2), int((box[1] + box[3]) // 2))
191
190
  radius = min(int(box[2]) - int(box[0]), int(box[3]) - int(box[1])) // 2
192
191
 
193
- y, x = np.ogrid[0:self.heatmap.shape[0], 0:self.heatmap.shape[1]]
194
- mask = (x - center[0]) ** 2 + (y - center[1]) ** 2 <= radius ** 2
192
+ y, x = np.ogrid[0 : self.heatmap.shape[0], 0 : self.heatmap.shape[1]]
193
+ mask = (x - center[0]) ** 2 + (y - center[1]) ** 2 <= radius**2
195
194
 
196
- self.heatmap[int(box[1]):int(box[3]), int(box[0]):int(box[2])] += \
197
- (2 * mask[int(box[1]):int(box[3]), int(box[0]):int(box[2])])
195
+ self.heatmap[int(box[1]) : int(box[3]), int(box[0]) : int(box[2])] += (
196
+ 2 * mask[int(box[1]) : int(box[3]), int(box[0]) : int(box[2])]
197
+ )
198
198
 
199
199
  else:
200
- self.heatmap[int(box[1]):int(box[3]), int(box[0]):int(box[2])] += 2
200
+ self.heatmap[int(box[1]) : int(box[3]), int(box[0]) : int(box[2])] += 2
201
201
 
202
202
  # Store tracking hist
203
203
  track_line = self.track_history[track_id]
@@ -226,26 +226,26 @@ class Heatmap:
226
226
  self.in_counts += 1
227
227
  else:
228
228
  for box, cls in zip(self.boxes, self.clss):
229
-
230
- if self.shape == 'circle':
229
+ if self.shape == "circle":
231
230
  center = (int((box[0] + box[2]) // 2), int((box[1] + box[3]) // 2))
232
231
  radius = min(int(box[2]) - int(box[0]), int(box[3]) - int(box[1])) // 2
233
232
 
234
- y, x = np.ogrid[0:self.heatmap.shape[0], 0:self.heatmap.shape[1]]
235
- mask = (x - center[0]) ** 2 + (y - center[1]) ** 2 <= radius ** 2
233
+ y, x = np.ogrid[0 : self.heatmap.shape[0], 0 : self.heatmap.shape[1]]
234
+ mask = (x - center[0]) ** 2 + (y - center[1]) ** 2 <= radius**2
236
235
 
237
- self.heatmap[int(box[1]):int(box[3]), int(box[0]):int(box[2])] += \
238
- (2 * mask[int(box[1]):int(box[3]), int(box[0]):int(box[2])])
236
+ self.heatmap[int(box[1]) : int(box[3]), int(box[0]) : int(box[2])] += (
237
+ 2 * mask[int(box[1]) : int(box[3]), int(box[0]) : int(box[2])]
238
+ )
239
239
 
240
240
  else:
241
- self.heatmap[int(box[1]):int(box[3]), int(box[0]):int(box[2])] += 2
241
+ self.heatmap[int(box[1]) : int(box[3]), int(box[0]) : int(box[2])] += 2
242
242
 
243
243
  # Normalize, apply colormap to heatmap and combine with original image
244
244
  heatmap_normalized = cv2.normalize(self.heatmap, None, 0, 255, cv2.NORM_MINMAX)
245
245
  heatmap_colored = cv2.applyColorMap(heatmap_normalized.astype(np.uint8), self.colormap)
246
246
 
247
- incount_label = 'In Count : ' + f'{self.in_counts}'
248
- outcount_label = 'OutCount : ' + f'{self.out_counts}'
247
+ incount_label = "In Count : " + f"{self.in_counts}"
248
+ outcount_label = "OutCount : " + f"{self.out_counts}"
249
249
 
250
250
  # Display counts based on user choice
251
251
  counts_label = None
@@ -256,13 +256,15 @@ class Heatmap:
256
256
  elif not self.view_out_counts:
257
257
  counts_label = incount_label
258
258
  else:
259
- counts_label = incount_label + ' ' + outcount_label
259
+ counts_label = incount_label + " " + outcount_label
260
260
 
261
261
  if self.count_reg_pts is not None and counts_label is not None:
262
- self.annotator.count_labels(counts=counts_label,
263
- count_txt_size=self.count_txt_thickness,
264
- txt_color=self.count_txt_color,
265
- color=self.count_color)
262
+ self.annotator.count_labels(
263
+ counts=counts_label,
264
+ count_txt_size=self.count_txt_thickness,
265
+ txt_color=self.count_txt_color,
266
+ color=self.count_color,
267
+ )
266
268
 
267
269
  self.im0 = cv2.addWeighted(self.im0, 1 - self.heatmap_alpha, heatmap_colored, self.heatmap_alpha, 0)
268
270
 
@@ -273,11 +275,11 @@ class Heatmap:
273
275
 
274
276
  def display_frames(self):
275
277
  """Display frame."""
276
- cv2.imshow('Ultralytics Heatmap', self.im0)
278
+ cv2.imshow("Ultralytics Heatmap", self.im0)
277
279
 
278
- if cv2.waitKey(1) & 0xFF == ord('q'):
280
+ if cv2.waitKey(1) & 0xFF == ord("q"):
279
281
  return
280
282
 
281
283
 
282
- if __name__ == '__main__':
284
+ if __name__ == "__main__":
283
285
  Heatmap()
@@ -7,7 +7,7 @@ import cv2
7
7
  from ultralytics.utils.checks import check_imshow, check_requirements
8
8
  from ultralytics.utils.plotting import Annotator, colors
9
9
 
10
- check_requirements('shapely>=2.0.0')
10
+ check_requirements("shapely>=2.0.0")
11
11
 
12
12
  from shapely.geometry import LineString, Point, Polygon
13
13
 
@@ -56,22 +56,24 @@ class ObjectCounter:
56
56
  # Check if environment support imshow
57
57
  self.env_check = check_imshow(warn=True)
58
58
 
59
- def set_args(self,
60
- classes_names,
61
- reg_pts,
62
- count_reg_color=(255, 0, 255),
63
- line_thickness=2,
64
- track_thickness=2,
65
- view_img=False,
66
- view_in_counts=True,
67
- view_out_counts=True,
68
- draw_tracks=False,
69
- count_txt_thickness=2,
70
- count_txt_color=(0, 0, 0),
71
- count_color=(255, 255, 255),
72
- track_color=(0, 255, 0),
73
- region_thickness=5,
74
- line_dist_thresh=15):
59
+ def set_args(
60
+ self,
61
+ classes_names,
62
+ reg_pts,
63
+ count_reg_color=(255, 0, 255),
64
+ line_thickness=2,
65
+ track_thickness=2,
66
+ view_img=False,
67
+ view_in_counts=True,
68
+ view_out_counts=True,
69
+ draw_tracks=False,
70
+ count_txt_thickness=2,
71
+ count_txt_color=(0, 0, 0),
72
+ count_color=(255, 255, 255),
73
+ track_color=(0, 255, 0),
74
+ region_thickness=5,
75
+ line_dist_thresh=15,
76
+ ):
75
77
  """
76
78
  Configures the Counter's image, bounding box line thickness, and counting region points.
77
79
 
@@ -101,16 +103,16 @@ class ObjectCounter:
101
103
 
102
104
  # Region and line selection
103
105
  if len(reg_pts) == 2:
104
- print('Line Counter Initiated.')
106
+ print("Line Counter Initiated.")
105
107
  self.reg_pts = reg_pts
106
108
  self.counting_region = LineString(self.reg_pts)
107
109
  elif len(reg_pts) == 4:
108
- print('Region Counter Initiated.')
110
+ print("Region Counter Initiated.")
109
111
  self.reg_pts = reg_pts
110
112
  self.counting_region = Polygon(self.reg_pts)
111
113
  else:
112
- print('Invalid Region points provided, region_points can be 2 or 4')
113
- print('Using Line Counter Now')
114
+ print("Invalid Region points provided, region_points can be 2 or 4")
115
+ print("Using Line Counter Now")
114
116
  self.counting_region = LineString(self.reg_pts)
115
117
 
116
118
  self.names = classes_names
@@ -153,6 +155,7 @@ class ObjectCounter:
153
155
  self.selected_point = None
154
156
 
155
157
  def extract_and_process_tracks(self, tracks):
158
+ """Extracts and processes tracks for object counting in a video stream."""
156
159
  boxes = tracks[0].boxes.xyxy.cpu()
157
160
  clss = tracks[0].boxes.cls.cpu().tolist()
158
161
  track_ids = tracks[0].boxes.id.int().cpu().tolist()
@@ -163,8 +166,9 @@ class ObjectCounter:
163
166
 
164
167
  # Extract tracks
165
168
  for box, track_id, cls in zip(boxes, track_ids, clss):
166
- self.annotator.box_label(box, label=str(track_id) + ':' + self.names[cls],
167
- color=colors(int(cls), True)) # Draw bounding box
169
+ self.annotator.box_label(
170
+ box, label=str(track_id) + ":" + self.names[cls], color=colors(int(cls), True)
171
+ ) # Draw bounding box
168
172
 
169
173
  # Draw Tracks
170
174
  track_line = self.track_history[track_id]
@@ -174,9 +178,9 @@ class ObjectCounter:
174
178
 
175
179
  # Draw track trails
176
180
  if self.draw_tracks:
177
- self.annotator.draw_centroid_and_tracks(track_line,
178
- color=self.track_color,
179
- track_thickness=self.track_thickness)
181
+ self.annotator.draw_centroid_and_tracks(
182
+ track_line, color=self.track_color, track_thickness=self.track_thickness
183
+ )
180
184
 
181
185
  # Count objects
182
186
  if len(self.reg_pts) == 4:
@@ -198,8 +202,8 @@ class ObjectCounter:
198
202
  else:
199
203
  self.in_counts += 1
200
204
 
201
- incount_label = 'In Count : ' + f'{self.in_counts}'
202
- outcount_label = 'OutCount : ' + f'{self.out_counts}'
205
+ incount_label = "In Count : " + f"{self.in_counts}"
206
+ outcount_label = "OutCount : " + f"{self.out_counts}"
203
207
 
204
208
  # Display counts based on user choice
205
209
  counts_label = None
@@ -210,24 +214,27 @@ class ObjectCounter:
210
214
  elif not self.view_out_counts:
211
215
  counts_label = incount_label
212
216
  else:
213
- counts_label = incount_label + ' ' + outcount_label
217
+ counts_label = incount_label + " " + outcount_label
214
218
 
215
219
  if counts_label is not None:
216
- self.annotator.count_labels(counts=counts_label,
217
- count_txt_size=self.count_txt_thickness,
218
- txt_color=self.count_txt_color,
219
- color=self.count_color)
220
+ self.annotator.count_labels(
221
+ counts=counts_label,
222
+ count_txt_size=self.count_txt_thickness,
223
+ txt_color=self.count_txt_color,
224
+ color=self.count_color,
225
+ )
220
226
 
221
227
  def display_frames(self):
222
228
  """Display frame."""
223
229
  if self.env_check:
224
- cv2.namedWindow('Ultralytics YOLOv8 Object Counter')
230
+ cv2.namedWindow("Ultralytics YOLOv8 Object Counter")
225
231
  if len(self.reg_pts) == 4: # only add mouse event If user drawn region
226
- cv2.setMouseCallback('Ultralytics YOLOv8 Object Counter', self.mouse_event_for_region,
227
- {'region_points': self.reg_pts})
228
- cv2.imshow('Ultralytics YOLOv8 Object Counter', self.im0)
232
+ cv2.setMouseCallback(
233
+ "Ultralytics YOLOv8 Object Counter", self.mouse_event_for_region, {"region_points": self.reg_pts}
234
+ )
235
+ cv2.imshow("Ultralytics YOLOv8 Object Counter", self.im0)
229
236
  # Break Window
230
- if cv2.waitKey(1) & 0xFF == ord('q'):
237
+ if cv2.waitKey(1) & 0xFF == ord("q"):
231
238
  return
232
239
 
233
240
  def start_counting(self, im0, tracks):
@@ -253,5 +260,5 @@ class ObjectCounter:
253
260
  return self.im0
254
261
 
255
262
 
256
- if __name__ == '__main__':
263
+ if __name__ == "__main__":
257
264
  ObjectCounter()
@@ -66,7 +66,7 @@ class SpeedEstimator:
66
66
  spdl_dist_thresh (int): Euclidean distance threshold for speed line
67
67
  """
68
68
  if reg_pts is None:
69
- print('Region points not provided, using default values')
69
+ print("Region points not provided, using default values")
70
70
  else:
71
71
  self.reg_pts = reg_pts
72
72
  self.names = names
@@ -114,8 +114,9 @@ class SpeedEstimator:
114
114
  cls (str): object class name
115
115
  track (list): tracking history for tracks path drawing
116
116
  """
117
- speed_label = str(int(
118
- self.dist_data[track_id])) + 'km/ph' if track_id in self.dist_data else self.names[int(cls)]
117
+ speed_label = (
118
+ str(int(self.dist_data[track_id])) + "km/ph" if track_id in self.dist_data else self.names[int(cls)]
119
+ )
119
120
  bbox_color = colors(int(track_id)) if track_id in self.dist_data else (255, 0, 255)
120
121
 
121
122
  self.annotator.box_label(box, speed_label, bbox_color)
@@ -132,19 +133,16 @@ class SpeedEstimator:
132
133
  """
133
134
 
134
135
  if self.reg_pts[0][0] < track[-1][0] < self.reg_pts[1][0]:
136
+ if self.reg_pts[1][1] - self.spdl_dist_thresh < track[-1][1] < self.reg_pts[1][1] + self.spdl_dist_thresh:
137
+ direction = "known"
135
138
 
136
- if (self.reg_pts[1][1] - self.spdl_dist_thresh < track[-1][1] < self.reg_pts[1][1] + self.spdl_dist_thresh):
137
- direction = 'known'
138
-
139
- elif (self.reg_pts[0][1] - self.spdl_dist_thresh < track[-1][1] <
140
- self.reg_pts[0][1] + self.spdl_dist_thresh):
141
- direction = 'known'
139
+ elif self.reg_pts[0][1] - self.spdl_dist_thresh < track[-1][1] < self.reg_pts[0][1] + self.spdl_dist_thresh:
140
+ direction = "known"
142
141
 
143
142
  else:
144
- direction = 'unknown'
145
-
146
- if self.trk_previous_times[trk_id] != 0 and direction != 'unknown':
143
+ direction = "unknown"
147
144
 
145
+ if self.trk_previous_times[trk_id] != 0 and direction != "unknown":
148
146
  if trk_id not in self.trk_idslist:
149
147
  self.trk_idslist.append(trk_id)
150
148
 
@@ -178,7 +176,6 @@ class SpeedEstimator:
178
176
  self.annotator.draw_region(reg_pts=self.reg_pts, color=(255, 0, 0), thickness=self.region_thickness)
179
177
 
180
178
  for box, trk_id, cls in zip(self.boxes, self.trk_ids, self.clss):
181
-
182
179
  track = self.store_track_info(trk_id, box)
183
180
 
184
181
  if trk_id not in self.trk_previous_times:
@@ -194,10 +191,10 @@ class SpeedEstimator:
194
191
 
195
192
  def display_frames(self):
196
193
  """Display frame."""
197
- cv2.imshow('Ultralytics Speed Estimation', self.im0)
198
- if cv2.waitKey(1) & 0xFF == ord('q'):
194
+ cv2.imshow("Ultralytics Speed Estimation", self.im0)
195
+ if cv2.waitKey(1) & 0xFF == ord("q"):
199
196
  return
200
197
 
201
198
 
202
- if __name__ == '__main__':
199
+ if __name__ == "__main__":
203
200
  SpeedEstimator()
@@ -4,4 +4,4 @@ from .bot_sort import BOTSORT
4
4
  from .byte_tracker import BYTETracker
5
5
  from .track import register_tracker
6
6
 
7
- __all__ = 'register_tracker', 'BOTSORT', 'BYTETracker' # allow simpler import
7
+ __all__ = "register_tracker", "BOTSORT", "BYTETracker" # allow simpler import
@@ -55,6 +55,7 @@ class BaseTrack:
55
55
  _count = 0
56
56
 
57
57
  def __init__(self):
58
+ """Initializes a new track with unique ID and foundational tracking attributes."""
58
59
  self.track_id = 0
59
60
  self.is_activated = False
60
61
  self.state = TrackState.New