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

ultralytics/__init__.py CHANGED
@@ -1,6 +1,6 @@
1
1
  # Ultralytics YOLO 🚀, AGPL-3.0 license
2
2
 
3
- __version__ = "8.2.17"
3
+ __version__ = "8.2.18"
4
4
 
5
5
  from ultralytics.data.explorer.explorer import Explorer
6
6
  from ultralytics.models import RTDETR, SAM, YOLO, YOLOWorld
@@ -1 +1,19 @@
1
1
  # Ultralytics YOLO 🚀, AGPL-3.0 license
2
+
3
+ from .ai_gym import AIGym
4
+ from .distance_calculation import DistanceCalculation
5
+ from .heatmap import Heatmap
6
+ from .object_counter import ObjectCounter
7
+ from .parking_management import ParkingManagement
8
+ from .queue_management import QueueManager
9
+ from .speed_estimation import SpeedEstimator
10
+
11
+ __all__ = (
12
+ "AIGym",
13
+ "DistanceCalculation",
14
+ "Heatmap",
15
+ "ObjectCounter",
16
+ "ParkingManagement",
17
+ "QueueManager",
18
+ "SpeedEstimator",
19
+ )
@@ -9,79 +9,75 @@ from ultralytics.utils.plotting import Annotator
9
9
  class AIGym:
10
10
  """A class to manage the gym steps of people in a real-time video stream based on their poses."""
11
11
 
12
- def __init__(self):
13
- """Initializes the AIGym with default values for Visual and Image parameters."""
12
+ def __init__(
13
+ self,
14
+ kpts_to_check,
15
+ line_thickness=2,
16
+ view_img=False,
17
+ pose_up_angle=145.0,
18
+ pose_down_angle=90.0,
19
+ pose_type="pullup",
20
+ ):
21
+ """
22
+ Initializes the AIGym class with the specified parameters.
23
+
24
+ Args:
25
+ kpts_to_check (list): Indices of keypoints to check.
26
+ line_thickness (int, optional): Thickness of the lines drawn. Defaults to 2.
27
+ view_img (bool, optional): Flag to display the image. Defaults to False.
28
+ pose_up_angle (float, optional): Angle threshold for the 'up' pose. Defaults to 145.0.
29
+ pose_down_angle (float, optional): Angle threshold for the 'down' pose. Defaults to 90.0.
30
+ pose_type (str, optional): Type of pose to detect ('pullup', 'pushup', 'abworkout'). Defaults to "pullup".
31
+ """
14
32
 
15
33
  # Image and line thickness
16
34
  self.im0 = None
17
- self.tf = None
35
+ self.tf = line_thickness
18
36
 
19
37
  # Keypoints and count information
20
38
  self.keypoints = None
21
- self.poseup_angle = None
22
- self.posedown_angle = None
39
+ self.poseup_angle = pose_up_angle
40
+ self.posedown_angle = pose_down_angle
23
41
  self.threshold = 0.001
24
42
 
25
43
  # Store stage, count and angle information
26
44
  self.angle = None
27
45
  self.count = None
28
46
  self.stage = None
29
- self.pose_type = "pushup"
30
- self.kpts_to_check = None
47
+ self.pose_type = pose_type
48
+ self.kpts_to_check = kpts_to_check
31
49
 
32
50
  # Visual Information
33
- self.view_img = False
51
+ self.view_img = view_img
34
52
  self.annotator = None
35
53
 
36
- # Check if environment support imshow
54
+ # Check if environment supports imshow
37
55
  self.env_check = check_imshow(warn=True)
38
56
 
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
- ):
48
- """
49
- Configures the AIGym line_thickness, save image and view image parameters.
50
-
51
- Args:
52
- kpts_to_check (list): 3 keypoints for counting
53
- line_thickness (int): Line thickness for bounding boxes.
54
- view_img (bool): display the im0
55
- pose_up_angle (float): Angle to set pose position up
56
- pose_down_angle (float): Angle to set pose position down
57
- pose_type (str): "pushup", "pullup" or "abworkout"
58
- """
59
- self.kpts_to_check = kpts_to_check
60
- self.tf = line_thickness
61
- self.view_img = view_img
62
- self.poseup_angle = pose_up_angle
63
- self.posedown_angle = pose_down_angle
64
- self.pose_type = pose_type
65
-
66
57
  def start_counting(self, im0, results, frame_count):
67
58
  """
68
59
  Function used to count the gym steps.
69
60
 
70
61
  Args:
71
62
  im0 (ndarray): Current frame from the video stream.
72
- results (list): Pose estimation data
73
- frame_count (int): store current frame count
63
+ results (list): Pose estimation data.
64
+ frame_count (int): Current frame count.
74
65
  """
66
+
75
67
  self.im0 = im0
68
+
69
+ # Initialize count, angle, and stage lists on the first frame
76
70
  if frame_count == 1:
77
71
  self.count = [0] * len(results[0])
78
72
  self.angle = [0] * len(results[0])
79
73
  self.stage = ["-" for _ in results[0]]
74
+
80
75
  self.keypoints = results[0].keypoints.data
81
76
  self.annotator = Annotator(im0, line_width=2)
82
77
 
83
78
  for ind, k in enumerate(reversed(self.keypoints)):
84
- if self.pose_type in {"pushup", "pullup"}:
79
+ # Estimate angle and draw specific points based on pose type
80
+ if self.pose_type in {"pushup", "pullup", "abworkout"}:
85
81
  self.angle[ind] = self.annotator.estimate_pose_angle(
86
82
  k[int(self.kpts_to_check[0])].cpu(),
87
83
  k[int(self.kpts_to_check[1])].cpu(),
@@ -89,55 +85,32 @@ class AIGym:
89
85
  )
90
86
  self.im0 = self.annotator.draw_specific_points(k, self.kpts_to_check, shape=(640, 640), radius=10)
91
87
 
92
- if self.pose_type == "abworkout":
93
- self.angle[ind] = self.annotator.estimate_pose_angle(
94
- k[int(self.kpts_to_check[0])].cpu(),
95
- k[int(self.kpts_to_check[1])].cpu(),
96
- k[int(self.kpts_to_check[2])].cpu(),
97
- )
98
- self.im0 = self.annotator.draw_specific_points(k, self.kpts_to_check, shape=(640, 640), radius=10)
99
- if self.angle[ind] > self.poseup_angle:
100
- self.stage[ind] = "down"
101
- if self.angle[ind] < self.posedown_angle and self.stage[ind] == "down":
102
- self.stage[ind] = "up"
103
- self.count[ind] += 1
104
- self.annotator.plot_angle_and_count_and_stage(
105
- angle_text=self.angle[ind],
106
- count_text=self.count[ind],
107
- stage_text=self.stage[ind],
108
- center_kpt=k[int(self.kpts_to_check[1])],
109
- line_thickness=self.tf,
110
- )
88
+ # Check and update pose stages and counts based on angle
89
+ if self.pose_type in {"abworkout", "pullup"}:
90
+ if self.angle[ind] > self.poseup_angle:
91
+ self.stage[ind] = "down"
92
+ if self.angle[ind] < self.posedown_angle and self.stage[ind] == "down":
93
+ self.stage[ind] = "up"
94
+ self.count[ind] += 1
95
+
96
+ elif self.pose_type == "pushup":
97
+ if self.angle[ind] > self.poseup_angle:
98
+ self.stage[ind] = "up"
99
+ if self.angle[ind] < self.posedown_angle and self.stage[ind] == "up":
100
+ self.stage[ind] = "down"
101
+ self.count[ind] += 1
111
102
 
112
- if self.pose_type == "pushup":
113
- if self.angle[ind] > self.poseup_angle:
114
- self.stage[ind] = "up"
115
- if self.angle[ind] < self.posedown_angle and self.stage[ind] == "up":
116
- self.stage[ind] = "down"
117
- self.count[ind] += 1
118
- self.annotator.plot_angle_and_count_and_stage(
119
- 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,
124
- )
125
- if self.pose_type == "pullup":
126
- if self.angle[ind] > self.poseup_angle:
127
- self.stage[ind] = "down"
128
- if self.angle[ind] < self.posedown_angle and self.stage[ind] == "down":
129
- self.stage[ind] = "up"
130
- self.count[ind] += 1
131
103
  self.annotator.plot_angle_and_count_and_stage(
132
104
  angle_text=self.angle[ind],
133
105
  count_text=self.count[ind],
134
106
  stage_text=self.stage[ind],
135
107
  center_kpt=k[int(self.kpts_to_check[1])],
136
- line_thickness=self.tf,
137
108
  )
138
109
 
110
+ # Draw keypoints
139
111
  self.annotator.kpts(k, shape=(640, 640), radius=1, kpt_line=True)
140
112
 
113
+ # Display the image if environment supports it and view_img is True
141
114
  if self.env_check and self.view_img:
142
115
  cv2.imshow("Ultralytics YOLOv8 AI GYM", self.im0)
143
116
  if cv2.waitKey(1) & 0xFF == ord("q"):
@@ -147,4 +120,5 @@ class AIGym:
147
120
 
148
121
 
149
122
  if __name__ == "__main__":
150
- AIGym()
123
+ kpts_to_check = [0, 1, 2] # example keypoints
124
+ aigym = AIGym(kpts_to_check)
@@ -9,94 +9,78 @@ from ultralytics.utils.plotting import Annotator, colors
9
9
 
10
10
 
11
11
  class DistanceCalculation:
12
- """A class to calculate distance between two objects in real-time video stream based on their tracks."""
12
+ """A class to calculate distance between two objects in a real-time video stream based on their tracks."""
13
13
 
14
- def __init__(self):
15
- """Initializes the distance calculation class with default values for Visual, Image, track and distance
16
- parameters.
14
+ def __init__(
15
+ self,
16
+ names,
17
+ pixels_per_meter=10,
18
+ view_img=False,
19
+ line_thickness=2,
20
+ line_color=(255, 255, 0),
21
+ centroid_color=(255, 0, 255),
22
+ ):
17
23
  """
24
+ Initializes the DistanceCalculation class with the given parameters.
18
25
 
19
- # Visual & im0 information
26
+ Args:
27
+ names (dict): Dictionary mapping class indices to class names.
28
+ pixels_per_meter (int, optional): Conversion factor from pixels to meters. Defaults to 10.
29
+ view_img (bool, optional): Flag to indicate if the video stream should be displayed. Defaults to False.
30
+ line_thickness (int, optional): Thickness of the lines drawn on the image. Defaults to 2.
31
+ line_color (tuple, optional): Color of the lines drawn on the image (BGR format). Defaults to (255, 255, 0).
32
+ centroid_color (tuple, optional): Color of the centroids drawn (BGR format). Defaults to (255, 0, 255).
33
+ """
34
+ # Visual & image information
20
35
  self.im0 = None
21
36
  self.annotator = None
22
- self.view_img = False
23
- self.line_color = (255, 255, 0)
24
- self.centroid_color = (255, 0, 255)
37
+ self.view_img = view_img
38
+ self.line_color = line_color
39
+ self.centroid_color = centroid_color
25
40
 
26
- # Predict/track information
41
+ # Prediction & tracking information
27
42
  self.clss = None
28
- self.names = None
43
+ self.names = names
29
44
  self.boxes = None
30
- self.line_thickness = 2
45
+ self.line_thickness = line_thickness
31
46
  self.trk_ids = None
32
47
 
33
48
  # Distance calculation information
34
49
  self.centroids = []
35
- self.pixel_per_meter = 10
50
+ self.pixel_per_meter = pixels_per_meter
36
51
 
37
- # Mouse event
52
+ # Mouse event information
38
53
  self.left_mouse_count = 0
39
54
  self.selected_boxes = {}
40
55
 
41
- # Check if environment support imshow
56
+ # Check if environment supports imshow
42
57
  self.env_check = check_imshow(warn=True)
43
58
 
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
- ):
53
- """
54
- Configures the distance calculation and display parameters.
55
-
56
- Args:
57
- names (dict): object detection classes names
58
- pixels_per_meter (int): Number of pixels in meter
59
- view_img (bool): Flag indicating frame display
60
- line_thickness (int): Line thickness for bounding boxes.
61
- line_color (RGB): color of centroids line
62
- centroid_color (RGB): colors of bbox centroids
63
- """
64
- self.names = names
65
- self.pixel_per_meter = pixels_per_meter
66
- self.view_img = view_img
67
- self.line_thickness = line_thickness
68
- self.line_color = line_color
69
- self.centroid_color = centroid_color
70
-
71
59
  def mouse_event_for_distance(self, event, x, y, flags, param):
72
60
  """
73
- This function is designed to move region with mouse events in a real-time video stream.
61
+ Handles mouse events to select regions in a real-time video stream.
74
62
 
75
63
  Args:
76
- event (int): The type of mouse event (e.g., cv2.EVENT_MOUSEMOVE, cv2.EVENT_LBUTTONDOWN, etc.).
77
- x (int): The x-coordinate of the mouse pointer.
78
- y (int): The y-coordinate of the mouse pointer.
79
- flags (int): Any flags associated with the event (e.g., cv2.EVENT_FLAG_CTRLKEY,
80
- cv2.EVENT_FLAG_SHIFTKEY, etc.).
81
- param (dict): Additional parameters you may want to pass to the function.
64
+ event (int): Type of mouse event (e.g., cv2.EVENT_MOUSEMOVE, cv2.EVENT_LBUTTONDOWN, etc.).
65
+ x (int): X-coordinate of the mouse pointer.
66
+ y (int): Y-coordinate of the mouse pointer.
67
+ flags (int): Flags associated with the event (e.g., cv2.EVENT_FLAG_CTRLKEY, cv2.EVENT_FLAG_SHIFTKEY, etc.).
68
+ param (dict): Additional parameters passed to the function.
82
69
  """
83
- global selected_boxes
84
- global left_mouse_count
85
70
  if event == cv2.EVENT_LBUTTONDOWN:
86
71
  self.left_mouse_count += 1
87
72
  if self.left_mouse_count <= 2:
88
73
  for box, track_id in zip(self.boxes, self.trk_ids):
89
74
  if box[0] < x < box[2] and box[1] < y < box[3] and track_id not in self.selected_boxes:
90
- self.selected_boxes[track_id] = []
91
75
  self.selected_boxes[track_id] = box
92
76
 
93
- if event == cv2.EVENT_RBUTTONDOWN:
77
+ elif event == cv2.EVENT_RBUTTONDOWN:
94
78
  self.selected_boxes = {}
95
79
  self.left_mouse_count = 0
96
80
 
97
81
  def extract_tracks(self, tracks):
98
82
  """
99
- Extracts results from the provided data.
83
+ Extracts tracking results from the provided data.
100
84
 
101
85
  Args:
102
86
  tracks (list): List of tracks obtained from the object tracking process.
@@ -105,55 +89,65 @@ class DistanceCalculation:
105
89
  self.clss = tracks[0].boxes.cls.cpu().tolist()
106
90
  self.trk_ids = tracks[0].boxes.id.int().cpu().tolist()
107
91
 
108
- def calculate_centroid(self, box):
92
+ @staticmethod
93
+ def calculate_centroid(box):
109
94
  """
110
- Calculate the centroid of bounding box.
95
+ Calculates the centroid of a bounding box.
111
96
 
112
97
  Args:
113
- box (list): Bounding box data
98
+ box (list): Bounding box coordinates [x1, y1, x2, y2].
99
+
100
+ Returns:
101
+ (tuple): Centroid coordinates (x, y).
114
102
  """
115
103
  return int((box[0] + box[2]) // 2), int((box[1] + box[3]) // 2)
116
104
 
117
105
  def calculate_distance(self, centroid1, centroid2):
118
106
  """
119
- Calculate distance between two centroids.
107
+ Calculates the distance between two centroids.
120
108
 
121
109
  Args:
122
- centroid1 (point): First bounding box data
123
- centroid2 (point): Second bounding box data
110
+ centroid1 (tuple): Coordinates of the first centroid (x, y).
111
+ centroid2 (tuple): Coordinates of the second centroid (x, y).
112
+
113
+ Returns:
114
+ (tuple): Distance in meters and millimeters.
124
115
  """
125
116
  pixel_distance = math.sqrt((centroid1[0] - centroid2[0]) ** 2 + (centroid1[1] - centroid2[1]) ** 2)
126
- return pixel_distance / self.pixel_per_meter, (pixel_distance / self.pixel_per_meter) * 1000
117
+ distance_m = pixel_distance / self.pixel_per_meter
118
+ distance_mm = distance_m * 1000
119
+ return distance_m, distance_mm
127
120
 
128
121
  def start_process(self, im0, tracks):
129
122
  """
130
- Calculate distance between two bounding boxes based on tracking data.
123
+ Processes the video frame and calculates the distance between two bounding boxes.
131
124
 
132
125
  Args:
133
- im0 (nd array): Image
126
+ im0 (ndarray): The image frame.
134
127
  tracks (list): List of tracks obtained from the object tracking process.
128
+
129
+ Returns:
130
+ (ndarray): The processed image frame.
135
131
  """
136
132
  self.im0 = im0
137
133
  if tracks[0].boxes.id is None:
138
134
  if self.view_img:
139
135
  self.display_frames()
140
- return
141
- self.extract_tracks(tracks)
136
+ return im0
142
137
 
143
- self.annotator = Annotator(self.im0, line_width=2)
138
+ self.extract_tracks(tracks)
139
+ self.annotator = Annotator(self.im0, line_width=self.line_thickness)
144
140
 
145
141
  for box, cls, track_id in zip(self.boxes, self.clss, self.trk_ids):
146
142
  self.annotator.box_label(box, color=colors(int(cls), True), label=self.names[int(cls)])
147
143
 
148
144
  if len(self.selected_boxes) == 2:
149
- for trk_id, _ in self.selected_boxes.items():
145
+ for trk_id in self.selected_boxes.keys():
150
146
  if trk_id == track_id:
151
147
  self.selected_boxes[track_id] = box
152
148
 
153
149
  if len(self.selected_boxes) == 2:
154
- for trk_id, box in self.selected_boxes.items():
155
- centroid = self.calculate_centroid(self.selected_boxes[trk_id])
156
- self.centroids.append(centroid)
150
+ self.centroids = [self.calculate_centroid(self.selected_boxes[trk_id]) for trk_id in self.selected_boxes]
157
151
 
158
152
  distance_m, distance_mm = self.calculate_distance(self.centroids[0], self.centroids[1])
159
153
  self.annotator.plot_distance_and_line(
@@ -168,7 +162,7 @@ class DistanceCalculation:
168
162
  return im0
169
163
 
170
164
  def display_frames(self):
171
- """Display frame."""
165
+ """Displays the current frame with annotations."""
172
166
  cv2.namedWindow("Ultralytics Distance Estimation")
173
167
  cv2.setMouseCallback("Ultralytics Distance Estimation", self.mouse_event_for_distance)
174
168
  cv2.imshow("Ultralytics Distance Estimation", self.im0)
@@ -178,4 +172,5 @@ class DistanceCalculation:
178
172
 
179
173
 
180
174
  if __name__ == "__main__":
181
- DistanceCalculation()
175
+ names = {0: "person", 1: "car"} # example class names
176
+ distance_calculation = DistanceCalculation(names)