ultralytics 8.3.5__py3-none-any.whl → 8.3.6__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of ultralytics might be problematic. Click here for more details.
- tests/test_solutions.py +6 -8
- ultralytics/__init__.py +1 -1
- ultralytics/cfg/solutions/default.yaml +4 -0
- ultralytics/engine/exporter.py +3 -4
- ultralytics/engine/trainer.py +4 -4
- ultralytics/solutions/ai_gym.py +62 -110
- ultralytics/solutions/heatmap.py +63 -219
- ultralytics/solutions/object_counter.py +19 -17
- ultralytics/solutions/solutions.py +9 -4
- ultralytics/utils/__init__.py +47 -46
- ultralytics/utils/checks.py +36 -20
- ultralytics/utils/plotting.py +50 -70
- ultralytics/utils/torch_utils.py +7 -2
- {ultralytics-8.3.5.dist-info → ultralytics-8.3.6.dist-info}/METADATA +8 -9
- {ultralytics-8.3.5.dist-info → ultralytics-8.3.6.dist-info}/RECORD +19 -19
- {ultralytics-8.3.5.dist-info → ultralytics-8.3.6.dist-info}/LICENSE +0 -0
- {ultralytics-8.3.5.dist-info → ultralytics-8.3.6.dist-info}/WHEEL +0 -0
- {ultralytics-8.3.5.dist-info → ultralytics-8.3.6.dist-info}/entry_points.txt +0 -0
- {ultralytics-8.3.5.dist-info → ultralytics-8.3.6.dist-info}/top_level.txt +0 -0
tests/test_solutions.py
CHANGED
|
@@ -19,8 +19,8 @@ def test_major_solutions():
|
|
|
19
19
|
cap = cv2.VideoCapture("solutions_ci_demo.mp4")
|
|
20
20
|
assert cap.isOpened(), "Error reading video file"
|
|
21
21
|
region_points = [(20, 400), (1080, 404), (1080, 360), (20, 360)]
|
|
22
|
-
|
|
23
|
-
heatmap = solutions.Heatmap(colormap=cv2.COLORMAP_PARULA,
|
|
22
|
+
counter = solutions.ObjectCounter(region=region_points, model="yolo11n.pt", show=False)
|
|
23
|
+
heatmap = solutions.Heatmap(colormap=cv2.COLORMAP_PARULA, model="yolo11n.pt", show=False)
|
|
24
24
|
speed = solutions.SpeedEstimator(reg_pts=region_points, names=names, view_img=False)
|
|
25
25
|
queue = solutions.QueueManager(names=names, reg_pts=region_points, view_img=False)
|
|
26
26
|
while cap.isOpened():
|
|
@@ -29,8 +29,8 @@ def test_major_solutions():
|
|
|
29
29
|
break
|
|
30
30
|
original_im0 = im0.copy()
|
|
31
31
|
tracks = model.track(im0, persist=True, show=False)
|
|
32
|
-
|
|
33
|
-
_ = heatmap.generate_heatmap(original_im0.copy()
|
|
32
|
+
_ = counter.count(original_im0.copy())
|
|
33
|
+
_ = heatmap.generate_heatmap(original_im0.copy())
|
|
34
34
|
_ = speed.estimate_speed(original_im0.copy(), tracks)
|
|
35
35
|
_ = queue.process_queue(original_im0.copy(), tracks)
|
|
36
36
|
cap.release()
|
|
@@ -41,16 +41,14 @@ def test_major_solutions():
|
|
|
41
41
|
def test_aigym():
|
|
42
42
|
"""Test the workouts monitoring solution."""
|
|
43
43
|
safe_download(url=WORKOUTS_SOLUTION_DEMO)
|
|
44
|
-
model = YOLO("yolo11n-pose.pt")
|
|
45
44
|
cap = cv2.VideoCapture("solution_ci_pose_demo.mp4")
|
|
46
45
|
assert cap.isOpened(), "Error reading video file"
|
|
47
|
-
|
|
46
|
+
gym = solutions.AIGym(line_width=2, kpts=[5, 11, 13])
|
|
48
47
|
while cap.isOpened():
|
|
49
48
|
success, im0 = cap.read()
|
|
50
49
|
if not success:
|
|
51
50
|
break
|
|
52
|
-
|
|
53
|
-
_ = gym_object.start_counting(im0, results)
|
|
51
|
+
_ = gym.monitor(im0)
|
|
54
52
|
cap.release()
|
|
55
53
|
cv2.destroyAllWindows()
|
|
56
54
|
|
ultralytics/__init__.py
CHANGED
|
@@ -10,3 +10,7 @@ show: True # Flag to control whether to display output image or not
|
|
|
10
10
|
show_in: True # Flag to display objects moving *into* the defined region
|
|
11
11
|
show_out: True # Flag to display objects moving *out of* the defined region
|
|
12
12
|
classes: # To count specific classes
|
|
13
|
+
up_angle: 145.0 # Workouts up_angle for counts, 145.0 is default value
|
|
14
|
+
down_angle: 90 # Workouts down_angle for counts, 90 is default value
|
|
15
|
+
kpts: [6, 8, 10] # Keypoints for workouts monitoring
|
|
16
|
+
colormap: # Colormap for heatmap
|
ultralytics/engine/exporter.py
CHANGED
|
@@ -183,11 +183,10 @@ class Exporter:
|
|
|
183
183
|
|
|
184
184
|
# Get the closest match if format is invalid
|
|
185
185
|
matches = difflib.get_close_matches(fmt, fmts, n=1, cutoff=0.6) # 60% similarity required to match
|
|
186
|
-
if matches:
|
|
187
|
-
LOGGER.warning(f"WARNING ⚠️ Invalid export format='{fmt}', updating to format='{matches[0]}'")
|
|
188
|
-
fmt = matches[0]
|
|
189
|
-
else:
|
|
186
|
+
if not matches:
|
|
190
187
|
raise ValueError(f"Invalid export format='{fmt}'. Valid formats are {fmts}")
|
|
188
|
+
LOGGER.warning(f"WARNING ⚠️ Invalid export format='{fmt}', updating to format='{matches[0]}'")
|
|
189
|
+
fmt = matches[0]
|
|
191
190
|
flags = [x == fmt for x in fmts]
|
|
192
191
|
if sum(flags) != 1:
|
|
193
192
|
raise ValueError(f"Invalid export format='{fmt}'. Valid formats are {fmts}")
|
ultralytics/engine/trainer.py
CHANGED
|
@@ -469,11 +469,11 @@ class BaseTrainer:
|
|
|
469
469
|
|
|
470
470
|
if RANK in {-1, 0}:
|
|
471
471
|
# Do final val with best.pt
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
)
|
|
472
|
+
epochs = epoch - self.start_epoch + 1 # total training epochs
|
|
473
|
+
seconds = time.time() - self.train_time_start # total training seconds
|
|
474
|
+
LOGGER.info(f"\n{epochs} epochs completed in {seconds / 3600:.3f} hours.")
|
|
476
475
|
self.final_eval()
|
|
476
|
+
self.validator.metrics.training = {"epochs": epochs, "seconds": seconds} # add training speed
|
|
477
477
|
if self.args.plots:
|
|
478
478
|
self.plot_metrics()
|
|
479
479
|
self.run_callbacks("on_train_end")
|
ultralytics/solutions/ai_gym.py
CHANGED
|
@@ -1,127 +1,79 @@
|
|
|
1
1
|
# Ultralytics YOLO 🚀, AGPL-3.0 license
|
|
2
2
|
|
|
3
|
-
import
|
|
4
|
-
|
|
5
|
-
from ultralytics.utils.checks import check_imshow
|
|
3
|
+
from ultralytics.solutions.solutions import BaseSolution # Import a parent class
|
|
6
4
|
from ultralytics.utils.plotting import Annotator
|
|
7
5
|
|
|
8
6
|
|
|
9
|
-
class AIGym:
|
|
7
|
+
class AIGym(BaseSolution):
|
|
10
8
|
"""A class to manage the gym steps of people in a real-time video stream based on their poses."""
|
|
11
9
|
|
|
12
|
-
def __init__(
|
|
13
|
-
|
|
14
|
-
|
|
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
|
-
):
|
|
10
|
+
def __init__(self, **kwargs):
|
|
11
|
+
"""Initialization function for AiGYM class, a child class of BaseSolution class, can be used for workouts
|
|
12
|
+
monitoring.
|
|
21
13
|
"""
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
14
|
+
# Check if the model name ends with '-pose'
|
|
15
|
+
if "model" in kwargs and "-pose" not in kwargs["model"]:
|
|
16
|
+
kwargs["model"] = "yolo11n-pose.pt"
|
|
17
|
+
elif "model" not in kwargs:
|
|
18
|
+
kwargs["model"] = "yolo11n-pose.pt"
|
|
19
|
+
|
|
20
|
+
super().__init__(**kwargs)
|
|
21
|
+
self.count = [] # List for counts, necessary where there are multiple objects in frame
|
|
22
|
+
self.angle = [] # List for angle, necessary where there are multiple objects in frame
|
|
23
|
+
self.stage = [] # List for stage, necessary where there are multiple objects in frame
|
|
24
|
+
|
|
25
|
+
# Extract details from CFG single time for usage later
|
|
26
|
+
self.initial_stage = None
|
|
27
|
+
self.up_angle = float(self.CFG["up_angle"]) # Pose up predefined angle to consider up pose
|
|
28
|
+
self.down_angle = float(self.CFG["down_angle"]) # Pose down predefined angle to consider down pose
|
|
29
|
+
self.kpts = self.CFG["kpts"] # User selected kpts of workouts storage for further usage
|
|
30
|
+
self.lw = self.CFG["line_width"] # Store line_width for usage
|
|
31
|
+
|
|
32
|
+
def monitor(self, im0):
|
|
31
33
|
"""
|
|
32
|
-
|
|
33
|
-
self.im0 = None
|
|
34
|
-
self.tf = line_thickness
|
|
35
|
-
|
|
36
|
-
# Keypoints and count information
|
|
37
|
-
self.keypoints = None
|
|
38
|
-
self.poseup_angle = pose_up_angle
|
|
39
|
-
self.posedown_angle = pose_down_angle
|
|
40
|
-
self.threshold = 0.001
|
|
41
|
-
|
|
42
|
-
# Store stage, count and angle information
|
|
43
|
-
self.angle = None
|
|
44
|
-
self.count = None
|
|
45
|
-
self.stage = None
|
|
46
|
-
self.pose_type = pose_type
|
|
47
|
-
self.kpts_to_check = kpts_to_check
|
|
48
|
-
|
|
49
|
-
# Visual Information
|
|
50
|
-
self.view_img = view_img
|
|
51
|
-
self.annotator = None
|
|
52
|
-
|
|
53
|
-
# Check if environment supports imshow
|
|
54
|
-
self.env_check = check_imshow(warn=True)
|
|
55
|
-
self.count = []
|
|
56
|
-
self.angle = []
|
|
57
|
-
self.stage = []
|
|
58
|
-
|
|
59
|
-
def start_counting(self, im0, results):
|
|
60
|
-
"""
|
|
61
|
-
Function used to count the gym steps.
|
|
34
|
+
Monitor the workouts using Ultralytics YOLOv8 Pose Model: https://docs.ultralytics.com/tasks/pose/.
|
|
62
35
|
|
|
63
36
|
Args:
|
|
64
|
-
im0 (ndarray):
|
|
65
|
-
|
|
37
|
+
im0 (ndarray): The input image that will be used for processing
|
|
38
|
+
Returns
|
|
39
|
+
im0 (ndarray): The processed image for more usage
|
|
66
40
|
"""
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
self.
|
|
90
|
-
|
|
91
|
-
# Check and update pose stages and counts based on angle
|
|
92
|
-
if self.pose_type in {"abworkout", "pullup"}:
|
|
93
|
-
if self.angle[ind] > self.poseup_angle:
|
|
94
|
-
self.stage[ind] = "down"
|
|
95
|
-
if self.angle[ind] < self.posedown_angle and self.stage[ind] == "down":
|
|
96
|
-
self.stage[ind] = "up"
|
|
97
|
-
self.count[ind] += 1
|
|
98
|
-
|
|
99
|
-
elif self.pose_type in {"pushup", "squat"}:
|
|
100
|
-
if self.angle[ind] > self.poseup_angle:
|
|
101
|
-
self.stage[ind] = "up"
|
|
102
|
-
if self.angle[ind] < self.posedown_angle and self.stage[ind] == "up":
|
|
103
|
-
self.stage[ind] = "down"
|
|
41
|
+
# Extract tracks
|
|
42
|
+
tracks = self.model.track(source=im0, persist=True, classes=self.CFG["classes"])[0]
|
|
43
|
+
|
|
44
|
+
if tracks.boxes.id is not None:
|
|
45
|
+
# Extract and check keypoints
|
|
46
|
+
if len(tracks) > len(self.count):
|
|
47
|
+
new_human = len(tracks) - len(self.count)
|
|
48
|
+
self.angle += [0] * new_human
|
|
49
|
+
self.count += [0] * new_human
|
|
50
|
+
self.stage += ["-"] * new_human
|
|
51
|
+
|
|
52
|
+
# Initialize annotator
|
|
53
|
+
self.annotator = Annotator(im0, line_width=self.lw)
|
|
54
|
+
|
|
55
|
+
# Enumerate over keypoints
|
|
56
|
+
for ind, k in enumerate(reversed(tracks.keypoints.data)):
|
|
57
|
+
# Get keypoints and estimate the angle
|
|
58
|
+
kpts = [k[int(self.kpts[i])].cpu() for i in range(3)]
|
|
59
|
+
self.angle[ind] = self.annotator.estimate_pose_angle(*kpts)
|
|
60
|
+
im0 = self.annotator.draw_specific_points(k, self.kpts, radius=self.lw * 3)
|
|
61
|
+
|
|
62
|
+
# Determine stage and count logic based on angle thresholds
|
|
63
|
+
if self.angle[ind] < self.down_angle:
|
|
64
|
+
if self.stage[ind] == "up":
|
|
104
65
|
self.count[ind] += 1
|
|
66
|
+
self.stage[ind] = "down"
|
|
67
|
+
elif self.angle[ind] > self.up_angle:
|
|
68
|
+
self.stage[ind] = "up"
|
|
105
69
|
|
|
70
|
+
# Display angle, count, and stage text
|
|
106
71
|
self.annotator.plot_angle_and_count_and_stage(
|
|
107
|
-
angle_text=self.angle[ind],
|
|
108
|
-
count_text=self.count[ind],
|
|
109
|
-
stage_text=self.stage[ind],
|
|
110
|
-
center_kpt=k[int(self.
|
|
72
|
+
angle_text=self.angle[ind], # angle text for display
|
|
73
|
+
count_text=self.count[ind], # count text for workouts
|
|
74
|
+
stage_text=self.stage[ind], # stage position text
|
|
75
|
+
center_kpt=k[int(self.kpts[1])], # center keypoint for display
|
|
111
76
|
)
|
|
112
77
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
# Display the image if environment supports it and view_img is True
|
|
117
|
-
if self.env_check and self.view_img:
|
|
118
|
-
cv2.imshow("Ultralytics YOLOv8 AI GYM", self.im0)
|
|
119
|
-
if cv2.waitKey(1) & 0xFF == ord("q"):
|
|
120
|
-
return
|
|
121
|
-
|
|
122
|
-
return self.im0
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
if __name__ == "__main__":
|
|
126
|
-
kpts_to_check = [0, 1, 2] # example keypoints
|
|
127
|
-
aigym = AIGym(kpts_to_check)
|
|
78
|
+
self.display_output(im0) # Display output image, if environment support display
|
|
79
|
+
return im0 # return an image for writing or further usage
|
ultralytics/solutions/heatmap.py
CHANGED
|
@@ -1,249 +1,93 @@
|
|
|
1
1
|
# Ultralytics YOLO 🚀, AGPL-3.0 license
|
|
2
2
|
|
|
3
|
-
from collections import defaultdict
|
|
4
|
-
|
|
5
3
|
import cv2
|
|
6
4
|
import numpy as np
|
|
7
5
|
|
|
8
|
-
from ultralytics.
|
|
6
|
+
from ultralytics.solutions.object_counter import ObjectCounter # Import object counter class
|
|
9
7
|
from ultralytics.utils.plotting import Annotator
|
|
10
8
|
|
|
11
|
-
check_requirements("shapely>=2.0.0")
|
|
12
|
-
|
|
13
|
-
from shapely.geometry import LineString, Point, Polygon
|
|
14
|
-
|
|
15
9
|
|
|
16
|
-
class Heatmap:
|
|
10
|
+
class Heatmap(ObjectCounter):
|
|
17
11
|
"""A class to draw heatmaps in real-time video stream based on their tracks."""
|
|
18
12
|
|
|
19
|
-
def __init__(
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
colormap=cv2.COLORMAP_JET,
|
|
23
|
-
view_img=False,
|
|
24
|
-
view_in_counts=True,
|
|
25
|
-
view_out_counts=True,
|
|
26
|
-
count_reg_pts=None,
|
|
27
|
-
count_txt_color=(0, 0, 0),
|
|
28
|
-
count_bg_color=(255, 255, 255),
|
|
29
|
-
count_reg_color=(255, 0, 255),
|
|
30
|
-
region_thickness=5,
|
|
31
|
-
line_dist_thresh=15,
|
|
32
|
-
line_thickness=2,
|
|
33
|
-
shape="circle",
|
|
34
|
-
):
|
|
35
|
-
"""Initializes the heatmap class with default values for Visual, Image, track, count and heatmap parameters."""
|
|
36
|
-
# Visual information
|
|
37
|
-
self.annotator = None
|
|
38
|
-
self.view_img = view_img
|
|
39
|
-
self.shape = shape
|
|
40
|
-
|
|
41
|
-
self.initialized = False
|
|
42
|
-
self.names = names # Classes names
|
|
43
|
-
|
|
44
|
-
# Image information
|
|
45
|
-
self.im0 = None
|
|
46
|
-
self.tf = line_thickness
|
|
47
|
-
self.view_in_counts = view_in_counts
|
|
48
|
-
self.view_out_counts = view_out_counts
|
|
49
|
-
|
|
50
|
-
# Heatmap colormap and heatmap np array
|
|
51
|
-
self.colormap = colormap
|
|
52
|
-
self.heatmap = None
|
|
53
|
-
|
|
54
|
-
# Predict/track information
|
|
55
|
-
self.boxes = []
|
|
56
|
-
self.track_ids = []
|
|
57
|
-
self.clss = []
|
|
58
|
-
self.track_history = defaultdict(list)
|
|
59
|
-
|
|
60
|
-
# Region & Line Information
|
|
61
|
-
self.counting_region = None
|
|
62
|
-
self.line_dist_thresh = line_dist_thresh
|
|
63
|
-
self.region_thickness = region_thickness
|
|
64
|
-
self.region_color = count_reg_color
|
|
65
|
-
|
|
66
|
-
# Object Counting Information
|
|
67
|
-
self.in_counts = 0
|
|
68
|
-
self.out_counts = 0
|
|
69
|
-
self.count_ids = []
|
|
70
|
-
self.class_wise_count = {}
|
|
71
|
-
self.count_txt_color = count_txt_color
|
|
72
|
-
self.count_bg_color = count_bg_color
|
|
73
|
-
self.cls_txtdisplay_gap = 50
|
|
74
|
-
|
|
75
|
-
# Check if environment supports imshow
|
|
76
|
-
self.env_check = check_imshow(warn=True)
|
|
77
|
-
|
|
78
|
-
# Region and line selection
|
|
79
|
-
self.count_reg_pts = count_reg_pts
|
|
80
|
-
print(self.count_reg_pts)
|
|
81
|
-
if self.count_reg_pts is not None:
|
|
82
|
-
if len(self.count_reg_pts) == 2:
|
|
83
|
-
print("Line Counter Initiated.")
|
|
84
|
-
self.counting_region = LineString(self.count_reg_pts)
|
|
85
|
-
elif len(self.count_reg_pts) >= 3:
|
|
86
|
-
print("Polygon Counter Initiated.")
|
|
87
|
-
self.counting_region = Polygon(self.count_reg_pts)
|
|
88
|
-
else:
|
|
89
|
-
print("Invalid Region points provided, region_points must be 2 for lines or >= 3 for polygons.")
|
|
90
|
-
print("Using Line Counter Now")
|
|
91
|
-
self.counting_region = LineString(self.count_reg_pts)
|
|
92
|
-
|
|
93
|
-
# Shape of heatmap, if not selected
|
|
94
|
-
if self.shape not in {"circle", "rect"}:
|
|
95
|
-
print("Unknown shape value provided, 'circle' & 'rect' supported")
|
|
96
|
-
print("Using Circular shape now")
|
|
97
|
-
self.shape = "circle"
|
|
98
|
-
|
|
99
|
-
def extract_results(self, tracks):
|
|
100
|
-
"""
|
|
101
|
-
Extracts results from the provided data.
|
|
13
|
+
def __init__(self, **kwargs):
|
|
14
|
+
"""Initializes function for heatmap class with default values."""
|
|
15
|
+
super().__init__(**kwargs)
|
|
102
16
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
self.track_ids = tracks[0].boxes.id.int().tolist()
|
|
17
|
+
self.initialized = False # bool variable for heatmap initialization
|
|
18
|
+
if self.region is not None: # check if user provided the region coordinates
|
|
19
|
+
self.initialize_region()
|
|
20
|
+
|
|
21
|
+
# store colormap
|
|
22
|
+
self.colormap = cv2.COLORMAP_PARULA if self.CFG["colormap"] is None else self.CFG["colormap"]
|
|
110
23
|
|
|
111
|
-
def
|
|
24
|
+
def heatmap_effect(self, box):
|
|
112
25
|
"""
|
|
113
|
-
|
|
26
|
+
Efficient calculation of heatmap area and effect location for applying colormap.
|
|
114
27
|
|
|
115
28
|
Args:
|
|
116
|
-
|
|
117
|
-
tracks (list): List of tracks obtained from the object tracking process.
|
|
29
|
+
box (list): Bounding Box coordinates data [x0, y0, x1, y1]
|
|
118
30
|
"""
|
|
119
|
-
|
|
31
|
+
x0, y0, x1, y1 = map(int, box)
|
|
32
|
+
radius_squared = (min(x1 - x0, y1 - y0) // 2) ** 2
|
|
120
33
|
|
|
121
|
-
#
|
|
122
|
-
|
|
123
|
-
self.heatmap = np.zeros((int(self.im0.shape[0]), int(self.im0.shape[1])), dtype=np.float32)
|
|
124
|
-
self.initialized = True
|
|
34
|
+
# Create a meshgrid with region of interest (ROI) for vectorized distance calculations
|
|
35
|
+
xv, yv = np.meshgrid(np.arange(x0, x1), np.arange(y0, y1))
|
|
125
36
|
|
|
126
|
-
|
|
37
|
+
# Calculate squared distances from the center
|
|
38
|
+
dist_squared = (xv - ((x0 + x1) // 2)) ** 2 + (yv - ((y0 + y1) // 2)) ** 2
|
|
127
39
|
|
|
128
|
-
|
|
129
|
-
|
|
40
|
+
# Create a mask of points within the radius
|
|
41
|
+
within_radius = dist_squared <= radius_squared
|
|
130
42
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
if self.count_reg_pts is not None:
|
|
134
|
-
self.annotator.draw_region(
|
|
135
|
-
reg_pts=self.count_reg_pts, color=self.region_color, thickness=self.region_thickness
|
|
136
|
-
)
|
|
43
|
+
# Update only the values within the bounding box in a single vectorized operation
|
|
44
|
+
self.heatmap[y0:y1, x0:x1][within_radius] += 2
|
|
137
45
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
self.class_wise_count[self.names[cls]] = {"IN": 0, "OUT": 0}
|
|
142
|
-
|
|
143
|
-
if self.shape == "circle":
|
|
144
|
-
center = (int((box[0] + box[2]) // 2), int((box[1] + box[3]) // 2))
|
|
145
|
-
radius = min(int(box[2]) - int(box[0]), int(box[3]) - int(box[1])) // 2
|
|
46
|
+
def generate_heatmap(self, im0):
|
|
47
|
+
"""
|
|
48
|
+
Generate heatmap for each frame using Ultralytics.
|
|
146
49
|
|
|
147
|
-
|
|
148
|
-
|
|
50
|
+
Args:
|
|
51
|
+
im0 (ndarray): Input image array for processing
|
|
52
|
+
Returns:
|
|
53
|
+
im0 (ndarray): Processed image for further usage
|
|
54
|
+
"""
|
|
55
|
+
self.heatmap = np.zeros_like(im0, dtype=np.float32) * 0.99 if not self.initialized else self.heatmap
|
|
56
|
+
self.initialized = True # Initialize heatmap only once
|
|
149
57
|
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
)
|
|
58
|
+
self.annotator = Annotator(im0, line_width=self.line_width) # Initialize annotator
|
|
59
|
+
self.extract_tracks(im0) # Extract tracks
|
|
153
60
|
|
|
154
|
-
|
|
155
|
-
|
|
61
|
+
# Iterate over bounding boxes, track ids and classes index
|
|
62
|
+
for box, track_id, cls in zip(self.boxes, self.track_ids, self.clss):
|
|
63
|
+
# Draw bounding box and counting region
|
|
64
|
+
self.heatmap_effect(box)
|
|
156
65
|
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
track_line.pop(0)
|
|
66
|
+
if self.region is not None:
|
|
67
|
+
self.annotator.draw_region(reg_pts=self.region, color=(104, 0, 123), thickness=self.line_width * 2)
|
|
68
|
+
self.store_tracking_history(track_id, box) # Store track history
|
|
69
|
+
self.store_classwise_counts(cls) # store classwise counts in dict
|
|
162
70
|
|
|
71
|
+
# Store tracking previous position and perform object counting
|
|
163
72
|
prev_position = self.track_history[track_id][-2] if len(self.track_history[track_id]) > 1 else None
|
|
73
|
+
self.count_objects(self.track_line, box, track_id, prev_position, cls) # Perform object counting
|
|
164
74
|
|
|
165
|
-
|
|
166
|
-
# Count objects in any polygon
|
|
167
|
-
if len(self.count_reg_pts) >= 3:
|
|
168
|
-
is_inside = self.counting_region.contains(Point(track_line[-1]))
|
|
169
|
-
|
|
170
|
-
if prev_position is not None and is_inside and track_id not in self.count_ids:
|
|
171
|
-
self.count_ids.append(track_id)
|
|
172
|
-
|
|
173
|
-
if (box[0] - prev_position[0]) * (self.counting_region.centroid.x - prev_position[0]) > 0:
|
|
174
|
-
self.in_counts += 1
|
|
175
|
-
self.class_wise_count[self.names[cls]]["IN"] += 1
|
|
176
|
-
else:
|
|
177
|
-
self.out_counts += 1
|
|
178
|
-
self.class_wise_count[self.names[cls]]["OUT"] += 1
|
|
179
|
-
|
|
180
|
-
# Count objects using line
|
|
181
|
-
elif len(self.count_reg_pts) == 2:
|
|
182
|
-
if prev_position is not None and track_id not in self.count_ids:
|
|
183
|
-
distance = Point(track_line[-1]).distance(self.counting_region)
|
|
184
|
-
if distance < self.line_dist_thresh and track_id not in self.count_ids:
|
|
185
|
-
self.count_ids.append(track_id)
|
|
186
|
-
|
|
187
|
-
if (box[0] - prev_position[0]) * (
|
|
188
|
-
self.counting_region.centroid.x - prev_position[0]
|
|
189
|
-
) > 0:
|
|
190
|
-
self.in_counts += 1
|
|
191
|
-
self.class_wise_count[self.names[cls]]["IN"] += 1
|
|
192
|
-
else:
|
|
193
|
-
self.out_counts += 1
|
|
194
|
-
self.class_wise_count[self.names[cls]]["OUT"] += 1
|
|
195
|
-
|
|
196
|
-
else:
|
|
197
|
-
for box, cls in zip(self.boxes, self.clss):
|
|
198
|
-
if self.shape == "circle":
|
|
199
|
-
center = (int((box[0] + box[2]) // 2), int((box[1] + box[3]) // 2))
|
|
200
|
-
radius = min(int(box[2]) - int(box[0]), int(box[3]) - int(box[1])) // 2
|
|
201
|
-
|
|
202
|
-
y, x = np.ogrid[0 : self.heatmap.shape[0], 0 : self.heatmap.shape[1]]
|
|
203
|
-
mask = (x - center[0]) ** 2 + (y - center[1]) ** 2 <= radius**2
|
|
204
|
-
|
|
205
|
-
self.heatmap[int(box[1]) : int(box[3]), int(box[0]) : int(box[2])] += (
|
|
206
|
-
2 * mask[int(box[1]) : int(box[3]), int(box[0]) : int(box[2])]
|
|
207
|
-
)
|
|
208
|
-
|
|
209
|
-
else:
|
|
210
|
-
self.heatmap[int(box[1]) : int(box[3]), int(box[0]) : int(box[2])] += 2
|
|
211
|
-
|
|
212
|
-
if self.count_reg_pts is not None:
|
|
213
|
-
labels_dict = {}
|
|
214
|
-
|
|
215
|
-
for key, value in self.class_wise_count.items():
|
|
216
|
-
if value["IN"] != 0 or value["OUT"] != 0:
|
|
217
|
-
if not self.view_in_counts and not self.view_out_counts:
|
|
218
|
-
continue
|
|
219
|
-
elif not self.view_in_counts:
|
|
220
|
-
labels_dict[str.capitalize(key)] = f"OUT {value['OUT']}"
|
|
221
|
-
elif not self.view_out_counts:
|
|
222
|
-
labels_dict[str.capitalize(key)] = f"IN {value['IN']}"
|
|
223
|
-
else:
|
|
224
|
-
labels_dict[str.capitalize(key)] = f"IN {value['IN']} OUT {value['OUT']}"
|
|
225
|
-
|
|
226
|
-
if labels_dict is not None:
|
|
227
|
-
self.annotator.display_analytics(self.im0, labels_dict, self.count_txt_color, self.count_bg_color, 10)
|
|
75
|
+
self.display_counts(im0) if self.region is not None else None # Display the counts on the frame
|
|
228
76
|
|
|
229
77
|
# Normalize, apply colormap to heatmap and combine with original image
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
if __name__ == "__main__":
|
|
248
|
-
classes_names = {0: "person", 1: "car"} # example class names
|
|
249
|
-
heatmap = Heatmap(classes_names)
|
|
78
|
+
im0 = (
|
|
79
|
+
im0
|
|
80
|
+
if self.track_data.id is None
|
|
81
|
+
else cv2.addWeighted(
|
|
82
|
+
im0,
|
|
83
|
+
0.5,
|
|
84
|
+
cv2.applyColorMap(
|
|
85
|
+
cv2.normalize(self.heatmap, None, 0, 255, cv2.NORM_MINMAX).astype(np.uint8), self.colormap
|
|
86
|
+
),
|
|
87
|
+
0.5,
|
|
88
|
+
0,
|
|
89
|
+
)
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
self.display_output(im0) # display output with base class function
|
|
93
|
+
return im0 # return output image for more usage
|
|
@@ -19,8 +19,7 @@ class ObjectCounter(BaseSolution):
|
|
|
19
19
|
self.out_count = 0 # Counter for objects moving outward
|
|
20
20
|
self.counted_ids = [] # List of IDs of objects that have been counted
|
|
21
21
|
self.classwise_counts = {} # Dictionary for counts, categorized by object class
|
|
22
|
-
|
|
23
|
-
self.initialize_region() # Setup region and counting areas
|
|
22
|
+
self.region_initialized = False # Bool variable for region initialization
|
|
24
23
|
|
|
25
24
|
self.show_in = self.CFG["show_in"]
|
|
26
25
|
self.show_out = self.CFG["show_out"]
|
|
@@ -99,6 +98,10 @@ class ObjectCounter(BaseSolution):
|
|
|
99
98
|
Returns
|
|
100
99
|
im0 (ndarray): The processed image for more usage
|
|
101
100
|
"""
|
|
101
|
+
if not self.region_initialized:
|
|
102
|
+
self.initialize_region()
|
|
103
|
+
self.region_initialized = True
|
|
104
|
+
|
|
102
105
|
self.annotator = Annotator(im0, line_width=self.line_width) # Initialize annotator
|
|
103
106
|
self.extract_tracks(im0) # Extract tracks
|
|
104
107
|
|
|
@@ -107,21 +110,20 @@ class ObjectCounter(BaseSolution):
|
|
|
107
110
|
) # Draw region
|
|
108
111
|
|
|
109
112
|
# Iterate over bounding boxes, track ids and classes index
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
self.
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
self.count_objects(self.track_line, box, track_id, prev_position, cls) # Perform object counting
|
|
113
|
+
for box, track_id, cls in zip(self.boxes, self.track_ids, self.clss):
|
|
114
|
+
# Draw bounding box and counting region
|
|
115
|
+
self.annotator.box_label(box, label=self.names[cls], color=colors(track_id, True))
|
|
116
|
+
self.store_tracking_history(track_id, box) # Store track history
|
|
117
|
+
self.store_classwise_counts(cls) # store classwise counts in dict
|
|
118
|
+
|
|
119
|
+
# Draw centroid of objects
|
|
120
|
+
self.annotator.draw_centroid_and_tracks(
|
|
121
|
+
self.track_line, color=colors(int(track_id), True), track_thickness=self.line_width
|
|
122
|
+
)
|
|
123
|
+
|
|
124
|
+
# store previous position of track for object counting
|
|
125
|
+
prev_position = self.track_history[track_id][-2] if len(self.track_history[track_id]) > 1 else None
|
|
126
|
+
self.count_objects(self.track_line, box, track_id, prev_position, cls) # Perform object counting
|
|
125
127
|
|
|
126
128
|
self.display_counts(im0) # Display the counts on the frame
|
|
127
129
|
self.display_output(im0) # display output with base class function
|
|
@@ -4,11 +4,13 @@ from collections import defaultdict
|
|
|
4
4
|
from pathlib import Path
|
|
5
5
|
|
|
6
6
|
import cv2
|
|
7
|
-
from shapely.geometry import LineString, Polygon
|
|
8
7
|
|
|
9
8
|
from ultralytics import YOLO
|
|
10
|
-
from ultralytics.utils import yaml_load
|
|
11
|
-
from ultralytics.utils.checks import check_imshow
|
|
9
|
+
from ultralytics.utils import LOGGER, yaml_load
|
|
10
|
+
from ultralytics.utils.checks import check_imshow, check_requirements
|
|
11
|
+
|
|
12
|
+
check_requirements("shapely>=2.0.0")
|
|
13
|
+
from shapely.geometry import LineString, Polygon
|
|
12
14
|
|
|
13
15
|
DEFAULT_SOL_CFG_PATH = Path(__file__).resolve().parents[1] / "cfg/solutions/default.yaml"
|
|
14
16
|
|
|
@@ -25,7 +27,7 @@ class BaseSolution:
|
|
|
25
27
|
# Load config and update with args
|
|
26
28
|
self.CFG = yaml_load(DEFAULT_SOL_CFG_PATH)
|
|
27
29
|
self.CFG.update(kwargs)
|
|
28
|
-
|
|
30
|
+
LOGGER.info(f"Ultralytics Solutions: ✅ {self.CFG}")
|
|
29
31
|
|
|
30
32
|
self.region = self.CFG["region"] # Store region data for other classes usage
|
|
31
33
|
self.line_width = self.CFG["line_width"] # Store line_width for usage
|
|
@@ -54,6 +56,9 @@ class BaseSolution:
|
|
|
54
56
|
self.boxes = self.track_data.xyxy.cpu()
|
|
55
57
|
self.clss = self.track_data.cls.cpu().tolist()
|
|
56
58
|
self.track_ids = self.track_data.id.int().cpu().tolist()
|
|
59
|
+
else:
|
|
60
|
+
LOGGER.warning("WARNING ⚠️ no tracks found!")
|
|
61
|
+
self.boxes, self.clss, self.track_ids = [], [], []
|
|
57
62
|
|
|
58
63
|
def store_tracking_history(self, track_id, box):
|
|
59
64
|
"""
|
ultralytics/utils/__init__.py
CHANGED
|
@@ -989,55 +989,56 @@ def set_sentry():
|
|
|
989
989
|
Additionally, the function sets custom tags and user information for Sentry events.
|
|
990
990
|
"""
|
|
991
991
|
if (
|
|
992
|
-
SETTINGS["sync"]
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
992
|
+
not SETTINGS["sync"]
|
|
993
|
+
or RANK not in {-1, 0}
|
|
994
|
+
or Path(ARGV[0]).name != "yolo"
|
|
995
|
+
or TESTS_RUNNING
|
|
996
|
+
or not ONLINE
|
|
997
|
+
or not IS_PIP_PACKAGE
|
|
998
|
+
or IS_GIT_DIR
|
|
999
999
|
):
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1000
|
+
return
|
|
1001
|
+
# If sentry_sdk package is not installed then return and do not use Sentry
|
|
1002
|
+
try:
|
|
1003
|
+
import sentry_sdk # noqa
|
|
1004
|
+
except ImportError:
|
|
1005
|
+
return
|
|
1006
|
+
|
|
1007
|
+
def before_send(event, hint):
|
|
1008
|
+
"""
|
|
1009
|
+
Modify the event before sending it to Sentry based on specific exception types and messages.
|
|
1009
1010
|
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1011
|
+
Args:
|
|
1012
|
+
event (dict): The event dictionary containing information about the error.
|
|
1013
|
+
hint (dict): A dictionary containing additional information about the error.
|
|
1013
1014
|
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1015
|
+
Returns:
|
|
1016
|
+
dict: The modified event or None if the event should not be sent to Sentry.
|
|
1017
|
+
"""
|
|
1018
|
+
if "exc_info" in hint:
|
|
1019
|
+
exc_type, exc_value, _ = hint["exc_info"]
|
|
1020
|
+
if exc_type in {KeyboardInterrupt, FileNotFoundError} or "out of memory" in str(exc_value):
|
|
1021
|
+
return None # do not send event
|
|
1022
|
+
|
|
1023
|
+
event["tags"] = {
|
|
1024
|
+
"sys_argv": ARGV[0],
|
|
1025
|
+
"sys_argv_name": Path(ARGV[0]).name,
|
|
1026
|
+
"install": "git" if IS_GIT_DIR else "pip" if IS_PIP_PACKAGE else "other",
|
|
1027
|
+
"os": ENVIRONMENT,
|
|
1028
|
+
}
|
|
1029
|
+
return event
|
|
1030
|
+
|
|
1031
|
+
sentry_sdk.init(
|
|
1032
|
+
dsn="https://888e5a0778212e1d0314c37d4b9aae5d@o4504521589325824.ingest.us.sentry.io/4504521592406016",
|
|
1033
|
+
debug=False,
|
|
1034
|
+
auto_enabling_integrations=False,
|
|
1035
|
+
traces_sample_rate=1.0,
|
|
1036
|
+
release=__version__,
|
|
1037
|
+
environment="production", # 'dev' or 'production'
|
|
1038
|
+
before_send=before_send,
|
|
1039
|
+
ignore_errors=[KeyboardInterrupt, FileNotFoundError],
|
|
1040
|
+
)
|
|
1041
|
+
sentry_sdk.set_user({"id": SETTINGS["uuid"]}) # SHA-256 anonymized UUID hash
|
|
1041
1042
|
|
|
1042
1043
|
|
|
1043
1044
|
class JSONDict(dict):
|
ultralytics/utils/checks.py
CHANGED
|
@@ -593,20 +593,29 @@ def collect_system_info():
|
|
|
593
593
|
import psutil
|
|
594
594
|
|
|
595
595
|
from ultralytics.utils import ENVIRONMENT # scope to avoid circular import
|
|
596
|
-
from ultralytics.utils.torch_utils import get_cpu_info
|
|
596
|
+
from ultralytics.utils.torch_utils import get_cpu_info, get_gpu_info
|
|
597
597
|
|
|
598
|
-
|
|
598
|
+
gib = 1 << 30 # bytes per GiB
|
|
599
|
+
cuda = torch and torch.cuda.is_available()
|
|
599
600
|
check_yolo()
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
f"{
|
|
608
|
-
|
|
601
|
+
total, used, free = shutil.disk_usage("/")
|
|
602
|
+
|
|
603
|
+
info_dict = {
|
|
604
|
+
"OS": platform.platform(),
|
|
605
|
+
"Environment": ENVIRONMENT,
|
|
606
|
+
"Python": PYTHON_VERSION,
|
|
607
|
+
"Install": "git" if IS_GIT_DIR else "pip" if IS_PIP_PACKAGE else "other",
|
|
608
|
+
"RAM": f"{psutil.virtual_memory().total / gib:.2f} GB",
|
|
609
|
+
"Disk": f"{(total - free) / gib:.1f}/{total / gib:.1f} GB",
|
|
610
|
+
"CPU": get_cpu_info(),
|
|
611
|
+
"CPU count": os.cpu_count(),
|
|
612
|
+
"GPU": get_gpu_info(index=0) if cuda else None,
|
|
613
|
+
"GPU count": torch.cuda.device_count() if cuda else None,
|
|
614
|
+
"CUDA": torch.version.cuda if cuda else None,
|
|
615
|
+
}
|
|
616
|
+
LOGGER.info("\n" + "\n".join(f"{k:<20}{v}" for k, v in info_dict.items()) + "\n")
|
|
609
617
|
|
|
618
|
+
package_info = {}
|
|
610
619
|
for r in parse_requirements(package="ultralytics"):
|
|
611
620
|
try:
|
|
612
621
|
current = metadata.version(r.name)
|
|
@@ -614,17 +623,24 @@ def collect_system_info():
|
|
|
614
623
|
except metadata.PackageNotFoundError:
|
|
615
624
|
current = "(not installed)"
|
|
616
625
|
is_met = "❌ "
|
|
617
|
-
|
|
626
|
+
package_info[r.name] = f"{is_met}{current}{r.specifier}"
|
|
627
|
+
LOGGER.info(f"{r.name:<20}{package_info[r.name]}")
|
|
628
|
+
|
|
629
|
+
info_dict["Package Info"] = package_info
|
|
618
630
|
|
|
619
631
|
if is_github_action_running():
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
632
|
+
github_info = {
|
|
633
|
+
"RUNNER_OS": os.getenv("RUNNER_OS"),
|
|
634
|
+
"GITHUB_EVENT_NAME": os.getenv("GITHUB_EVENT_NAME"),
|
|
635
|
+
"GITHUB_WORKFLOW": os.getenv("GITHUB_WORKFLOW"),
|
|
636
|
+
"GITHUB_ACTOR": os.getenv("GITHUB_ACTOR"),
|
|
637
|
+
"GITHUB_REPOSITORY": os.getenv("GITHUB_REPOSITORY"),
|
|
638
|
+
"GITHUB_REPOSITORY_OWNER": os.getenv("GITHUB_REPOSITORY_OWNER"),
|
|
639
|
+
}
|
|
640
|
+
LOGGER.info("\n" + "\n".join(f"{k}: {v}" for k, v in github_info.items()))
|
|
641
|
+
info_dict["GitHub Info"] = github_info
|
|
642
|
+
|
|
643
|
+
return info_dict
|
|
628
644
|
|
|
629
645
|
|
|
630
646
|
def check_amp(model):
|
ultralytics/utils/plotting.py
CHANGED
|
@@ -697,14 +697,13 @@ class Annotator:
|
|
|
697
697
|
angle = 360 - angle
|
|
698
698
|
return angle
|
|
699
699
|
|
|
700
|
-
def draw_specific_points(self, keypoints, indices=None,
|
|
700
|
+
def draw_specific_points(self, keypoints, indices=None, radius=2, conf_thres=0.25):
|
|
701
701
|
"""
|
|
702
702
|
Draw specific keypoints for gym steps counting.
|
|
703
703
|
|
|
704
704
|
Args:
|
|
705
705
|
keypoints (list): Keypoints data to be plotted.
|
|
706
706
|
indices (list, optional): Keypoint indices to be plotted. Defaults to [2, 5, 7].
|
|
707
|
-
shape (tuple, optional): Image size for model inference. Defaults to (640, 640).
|
|
708
707
|
radius (int, optional): Keypoint radius. Defaults to 2.
|
|
709
708
|
conf_thres (float, optional): Confidence threshold for keypoints. Defaults to 0.25.
|
|
710
709
|
|
|
@@ -715,90 +714,71 @@ class Annotator:
|
|
|
715
714
|
Keypoint format: [x, y] or [x, y, confidence].
|
|
716
715
|
Modifies self.im in-place.
|
|
717
716
|
"""
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
717
|
+
indices = indices or [2, 5, 7]
|
|
718
|
+
points = [(int(k[0]), int(k[1])) for i, k in enumerate(keypoints) if i in indices and k[2] >= conf_thres]
|
|
719
|
+
|
|
720
|
+
# Draw lines between consecutive points
|
|
721
|
+
for start, end in zip(points[:-1], points[1:]):
|
|
722
|
+
cv2.line(self.im, start, end, (0, 255, 0), 2, lineType=cv2.LINE_AA)
|
|
723
|
+
|
|
724
|
+
# Draw circles for keypoints
|
|
725
|
+
for pt in points:
|
|
726
|
+
cv2.circle(self.im, pt, radius, (0, 0, 255), -1, lineType=cv2.LINE_AA)
|
|
727
|
+
|
|
729
728
|
return self.im
|
|
730
729
|
|
|
731
|
-
def
|
|
732
|
-
self, angle_text, count_text, stage_text, center_kpt, color=(104, 31, 17), txt_color=(255, 255, 255)
|
|
733
|
-
):
|
|
730
|
+
def plot_workout_information(self, display_text, position, color=(104, 31, 17), txt_color=(255, 255, 255)):
|
|
734
731
|
"""
|
|
735
|
-
|
|
732
|
+
Draw text with a background on the image.
|
|
736
733
|
|
|
737
734
|
Args:
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
color (tuple): text background color for workout monitoring
|
|
743
|
-
txt_color (tuple): text foreground color for workout monitoring
|
|
735
|
+
display_text (str): The text to be displayed.
|
|
736
|
+
position (tuple): Coordinates (x, y) on the image where the text will be placed.
|
|
737
|
+
color (tuple, optional): Text background color
|
|
738
|
+
txt_color (tuple, optional): Text foreground color
|
|
744
739
|
"""
|
|
745
|
-
|
|
740
|
+
(text_width, text_height), _ = cv2.getTextSize(display_text, 0, self.sf, self.tf)
|
|
746
741
|
|
|
747
|
-
# Draw
|
|
748
|
-
(angle_text_width, angle_text_height), _ = cv2.getTextSize(angle_text, 0, self.sf, self.tf)
|
|
749
|
-
angle_text_position = (int(center_kpt[0]), int(center_kpt[1]))
|
|
750
|
-
angle_background_position = (angle_text_position[0], angle_text_position[1] - angle_text_height - 5)
|
|
751
|
-
angle_background_size = (angle_text_width + 2 * 5, angle_text_height + 2 * 5 + (self.tf * 2))
|
|
742
|
+
# Draw background rectangle
|
|
752
743
|
cv2.rectangle(
|
|
753
744
|
self.im,
|
|
754
|
-
|
|
755
|
-
(
|
|
756
|
-
angle_background_position[0] + angle_background_size[0],
|
|
757
|
-
angle_background_position[1] + angle_background_size[1],
|
|
758
|
-
),
|
|
745
|
+
(position[0], position[1] - text_height - 5),
|
|
746
|
+
(position[0] + text_width + 10, position[1] - text_height - 5 + text_height + 10 + self.tf),
|
|
759
747
|
color,
|
|
760
748
|
-1,
|
|
761
749
|
)
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
# Draw Counts
|
|
765
|
-
(count_text_width, count_text_height), _ = cv2.getTextSize(count_text, 0, self.sf, self.tf)
|
|
766
|
-
count_text_position = (angle_text_position[0], angle_text_position[1] + angle_text_height + 20)
|
|
767
|
-
count_background_position = (
|
|
768
|
-
angle_background_position[0],
|
|
769
|
-
angle_background_position[1] + angle_background_size[1] + 5,
|
|
770
|
-
)
|
|
771
|
-
count_background_size = (count_text_width + 10, count_text_height + 10 + self.tf)
|
|
750
|
+
# Draw text
|
|
751
|
+
cv2.putText(self.im, display_text, position, 0, self.sf, txt_color, self.tf)
|
|
772
752
|
|
|
773
|
-
|
|
774
|
-
self.im,
|
|
775
|
-
count_background_position,
|
|
776
|
-
(
|
|
777
|
-
count_background_position[0] + count_background_size[0],
|
|
778
|
-
count_background_position[1] + count_background_size[1],
|
|
779
|
-
),
|
|
780
|
-
color,
|
|
781
|
-
-1,
|
|
782
|
-
)
|
|
783
|
-
cv2.putText(self.im, count_text, count_text_position, 0, self.sf, txt_color, self.tf)
|
|
753
|
+
return text_height
|
|
784
754
|
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
755
|
+
def plot_angle_and_count_and_stage(
|
|
756
|
+
self, angle_text, count_text, stage_text, center_kpt, color=(104, 31, 17), txt_color=(255, 255, 255)
|
|
757
|
+
):
|
|
758
|
+
"""
|
|
759
|
+
Plot the pose angle, count value, and step stage.
|
|
790
760
|
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
(
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
)
|
|
798
|
-
|
|
799
|
-
|
|
761
|
+
Args:
|
|
762
|
+
angle_text (str): Angle value for workout monitoring
|
|
763
|
+
count_text (str): Counts value for workout monitoring
|
|
764
|
+
stage_text (str): Stage decision for workout monitoring
|
|
765
|
+
center_kpt (list): Centroid pose index for workout monitoring
|
|
766
|
+
color (tuple, optional): Text background color
|
|
767
|
+
txt_color (tuple, optional): Text foreground color
|
|
768
|
+
"""
|
|
769
|
+
# Format text
|
|
770
|
+
angle_text, count_text, stage_text = f" {angle_text:.2f}", f"Steps : {count_text}", f" {stage_text}"
|
|
771
|
+
|
|
772
|
+
# Draw angle, count and stage text
|
|
773
|
+
angle_height = self.plot_workout_information(
|
|
774
|
+
angle_text, (int(center_kpt[0]), int(center_kpt[1])), color, txt_color
|
|
775
|
+
)
|
|
776
|
+
count_height = self.plot_workout_information(
|
|
777
|
+
count_text, (int(center_kpt[0]), int(center_kpt[1]) + angle_height + 20), color, txt_color
|
|
778
|
+
)
|
|
779
|
+
self.plot_workout_information(
|
|
780
|
+
stage_text, (int(center_kpt[0]), int(center_kpt[1]) + angle_height + count_height + 40), color, txt_color
|
|
800
781
|
)
|
|
801
|
-
cv2.putText(self.im, stage_text, stage_text_position, 0, self.sf, txt_color, self.tf)
|
|
802
782
|
|
|
803
783
|
def seg_bbox(self, mask, mask_color=(255, 0, 255), label=None, txt_color=(255, 255, 255)):
|
|
804
784
|
"""
|
ultralytics/utils/torch_utils.py
CHANGED
|
@@ -123,6 +123,12 @@ def get_cpu_info():
|
|
|
123
123
|
return PERSISTENT_CACHE.get("cpu_info", "unknown")
|
|
124
124
|
|
|
125
125
|
|
|
126
|
+
def get_gpu_info(index):
|
|
127
|
+
"""Return a string with system GPU information, i.e. 'Tesla T4, 15102MiB'."""
|
|
128
|
+
properties = torch.cuda.get_device_properties(index)
|
|
129
|
+
return f"{properties.name}, {properties.total_memory / (1 << 20):.0f}MiB"
|
|
130
|
+
|
|
131
|
+
|
|
126
132
|
def select_device(device="", batch=0, newline=False, verbose=True):
|
|
127
133
|
"""
|
|
128
134
|
Selects the appropriate PyTorch device based on the provided arguments.
|
|
@@ -208,8 +214,7 @@ def select_device(device="", batch=0, newline=False, verbose=True):
|
|
|
208
214
|
)
|
|
209
215
|
space = " " * (len(s) + 1)
|
|
210
216
|
for i, d in enumerate(devices):
|
|
211
|
-
|
|
212
|
-
s += f"{'' if i == 0 else space}CUDA:{d} ({p.name}, {p.total_memory / (1 << 20):.0f}MiB)\n" # bytes to MB
|
|
217
|
+
s += f"{'' if i == 0 else space}CUDA:{d} ({get_gpu_info(i)})\n" # bytes to MB
|
|
213
218
|
arg = "cuda:0"
|
|
214
219
|
elif mps and TORCH_2_0 and torch.backends.mps.is_available():
|
|
215
220
|
# Prefer MPS if available
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: ultralytics
|
|
3
|
-
Version: 8.3.
|
|
3
|
+
Version: 8.3.6
|
|
4
4
|
Summary: Ultralytics YOLO for SOTA object detection, multi-object tracking, instance segmentation, pose estimation and image classification.
|
|
5
|
-
Author: Ayush Chaurasia
|
|
6
5
|
Author-email: Glenn Jocher <glenn.jocher@ultralytics.com>, Jing Qiu <jing.qiu@ultralytics.com>
|
|
7
6
|
Maintainer-email: Ultralytics <hello@ultralytics.com>
|
|
8
7
|
License: AGPL-3.0
|
|
@@ -99,8 +98,8 @@ Requires-Dist: dvclive>=2.12.0; extra == "logging"
|
|
|
99
98
|
<a href="https://github.com/ultralytics/ultralytics/actions/workflows/ci.yaml"><img src="https://github.com/ultralytics/ultralytics/actions/workflows/ci.yaml/badge.svg" alt="Ultralytics CI"></a>
|
|
100
99
|
<a href="https://zenodo.org/badge/latestdoi/264818686"><img src="https://zenodo.org/badge/264818686.svg" alt="Ultralytics YOLO Citation"></a>
|
|
101
100
|
<a href="https://hub.docker.com/r/ultralytics/ultralytics"><img src="https://img.shields.io/docker/pulls/ultralytics/ultralytics?logo=docker" alt="Ultralytics Docker Pulls"></a>
|
|
102
|
-
<a href="https://
|
|
103
|
-
<a href="https://community.ultralytics.com"><img alt="Ultralytics Forums" src="https://img.shields.io/discourse/users?server=https%3A%2F%2Fcommunity.ultralytics.com&logo=discourse&label=Forums&color=blue"></a>
|
|
101
|
+
<a href="https://discord.com/invite/ultralytics"><img alt="Ultralytics Discord" src="https://img.shields.io/discord/1089800235347353640?logo=discord&logoColor=white&label=Discord&color=blue"></a>
|
|
102
|
+
<a href="https://community.ultralytics.com/"><img alt="Ultralytics Forums" src="https://img.shields.io/discourse/users?server=https%3A%2F%2Fcommunity.ultralytics.com&logo=discourse&label=Forums&color=blue"></a>
|
|
104
103
|
<a href="https://reddit.com/r/ultralytics"><img alt="Ultralytics Reddit" src="https://img.shields.io/reddit/subreddit-subscribers/ultralytics?style=flat&logo=reddit&logoColor=white&label=Reddit&color=blue"></a>
|
|
105
104
|
<br>
|
|
106
105
|
<a href="https://console.paperspace.com/github/ultralytics/ultralytics"><img src="https://assets.paperspace.io/img/gradient-badge.svg" alt="Run Ultralytics on Gradient"></a>
|
|
@@ -111,7 +110,7 @@ Requires-Dist: dvclive>=2.12.0; extra == "logging"
|
|
|
111
110
|
|
|
112
111
|
[Ultralytics](https://www.ultralytics.com/) [YOLO11](https://github.com/ultralytics/ultralytics) is a cutting-edge, state-of-the-art (SOTA) model that builds upon the success of previous YOLO versions and introduces new features and improvements to further boost performance and flexibility. YOLO11 is designed to be fast, accurate, and easy to use, making it an excellent choice for a wide range of object detection and tracking, instance segmentation, image classification and pose estimation tasks.
|
|
113
112
|
|
|
114
|
-
We hope that the resources here will help you get the most out of YOLO. Please browse the Ultralytics <a href="https://docs.ultralytics.com/">Docs</a> for details, raise an issue on <a href="https://github.com/ultralytics/ultralytics/issues/new/choose">GitHub</a> for support, questions, or discussions, become a member of the Ultralytics <a href="https://
|
|
113
|
+
We hope that the resources here will help you get the most out of YOLO. Please browse the Ultralytics <a href="https://docs.ultralytics.com/">Docs</a> for details, raise an issue on <a href="https://github.com/ultralytics/ultralytics/issues/new/choose">GitHub</a> for support, questions, or discussions, become a member of the Ultralytics <a href="https://discord.com/invite/ultralytics">Discord</a>, <a href="https://reddit.com/r/ultralytics">Reddit</a> and <a href="https://community.ultralytics.com/">Forums</a>!
|
|
115
114
|
|
|
116
115
|
To request an Enterprise License please complete the form at [Ultralytics Licensing](https://www.ultralytics.com/license).
|
|
117
116
|
|
|
@@ -130,7 +129,7 @@ To request an Enterprise License please complete the form at [Ultralytics Licens
|
|
|
130
129
|
<img src="https://github.com/ultralytics/assets/raw/main/social/logo-transparent.png" width="2%" alt="space">
|
|
131
130
|
<a href="https://ultralytics.com/bilibili"><img src="https://github.com/ultralytics/assets/raw/main/social/logo-social-bilibili.png" width="2%" alt="Ultralytics BiliBili"></a>
|
|
132
131
|
<img src="https://github.com/ultralytics/assets/raw/main/social/logo-transparent.png" width="2%" alt="space">
|
|
133
|
-
<a href="https://
|
|
132
|
+
<a href="https://discord.com/invite/ultralytics"><img src="https://github.com/ultralytics/assets/raw/main/social/logo-social-discord.png" width="2%" alt="Ultralytics Discord"></a>
|
|
134
133
|
</div>
|
|
135
134
|
</div>
|
|
136
135
|
|
|
@@ -299,7 +298,7 @@ See [OBB Docs](https://docs.ultralytics.com/tasks/obb/) for usage examples with
|
|
|
299
298
|
Our key integrations with leading AI platforms extend the functionality of Ultralytics' offerings, enhancing tasks like dataset labeling, training, visualization, and model management. Discover how Ultralytics, in collaboration with [Roboflow](https://roboflow.com/?ref=ultralytics), ClearML, [Comet](https://bit.ly/yolov8-readme-comet), Neural Magic and [OpenVINO](https://docs.ultralytics.com/integrations/openvino/), can optimize your AI workflow.
|
|
300
299
|
|
|
301
300
|
<br>
|
|
302
|
-
<a href="https://ultralytics.com/hub" target="_blank">
|
|
301
|
+
<a href="https://www.ultralytics.com/hub" target="_blank">
|
|
303
302
|
<img width="100%" src="https://github.com/ultralytics/assets/raw/main/yolov8/banner-integrations.png" alt="Ultralytics active learning integrations"></a>
|
|
304
303
|
<br>
|
|
305
304
|
<br>
|
|
@@ -326,7 +325,7 @@ Our key integrations with leading AI platforms extend the functionality of Ultra
|
|
|
326
325
|
|
|
327
326
|
Experience seamless AI with [Ultralytics HUB](https://www.ultralytics.com/hub) ⭐, the all-in-one solution for data visualization, YOLO11 🚀 model training and deployment, without any coding. Transform images into actionable insights and bring your AI visions to life with ease using our cutting-edge platform and user-friendly [Ultralytics App](https://www.ultralytics.com/app-install). Start your journey for **Free** now!
|
|
328
327
|
|
|
329
|
-
<a href="https://ultralytics.com/hub" target="_blank">
|
|
328
|
+
<a href="https://www.ultralytics.com/hub" target="_blank">
|
|
330
329
|
<img width="100%" src="https://github.com/ultralytics/assets/raw/main/im/ultralytics-hub.png" alt="Ultralytics HUB preview image"></a>
|
|
331
330
|
|
|
332
331
|
## <div align="center">Contribute</div>
|
|
@@ -363,5 +362,5 @@ For Ultralytics bug reports and feature requests please visit [GitHub Issues](ht
|
|
|
363
362
|
<img src="https://github.com/ultralytics/assets/raw/main/social/logo-transparent.png" width="3%" alt="space">
|
|
364
363
|
<a href="https://ultralytics.com/bilibili"><img src="https://github.com/ultralytics/assets/raw/main/social/logo-social-bilibili.png" width="3%" alt="Ultralytics BiliBili"></a>
|
|
365
364
|
<img src="https://github.com/ultralytics/assets/raw/main/social/logo-transparent.png" width="3%" alt="space">
|
|
366
|
-
<a href="https://
|
|
365
|
+
<a href="https://discord.com/invite/ultralytics"><img src="https://github.com/ultralytics/assets/raw/main/social/logo-social-discord.png" width="3%" alt="Ultralytics Discord"></a>
|
|
367
366
|
</div>
|
|
@@ -7,8 +7,8 @@ tests/test_explorer.py,sha256=9EeMtt4-K3-MeGnAc7NemTg3uTo-Xr6AYJlTJZJJeF8,2572
|
|
|
7
7
|
tests/test_exports.py,sha256=fpTKEVBUGLF3WiZPNKRs-IEcIY4cfxgvgKjUNfodjww,8042
|
|
8
8
|
tests/test_integrations.py,sha256=f5-QCUk1SU_-qn4mBCZwS3GN3tXEBIIXo4z2EhExbHw,6126
|
|
9
9
|
tests/test_python.py,sha256=I1RRdCwLdrc3jX06huVxct8HX8ccQOmQgVpuEflRl0U,23560
|
|
10
|
-
tests/test_solutions.py,sha256=
|
|
11
|
-
ultralytics/__init__.py,sha256=
|
|
10
|
+
tests/test_solutions.py,sha256=GYOjUXor2pHGPFwvZrmqrxNjs9wYz4r3_XWt8DMAVaM,3132
|
|
11
|
+
ultralytics/__init__.py,sha256=WlkyTS3L-3ozTAF5fT2vLMSf4tQNvOaCxGsICIQf7mA,693
|
|
12
12
|
ultralytics/assets/bus.jpg,sha256=wCAZxJecGR63Od3ZRERe9Aja1Weayrb9Ug751DS_vGM,137419
|
|
13
13
|
ultralytics/assets/zidane.jpg,sha256=Ftc4aeMmen1O0A3o6GCDO9FlfBslLpTAw0gnetx7bts,50427
|
|
14
14
|
ultralytics/cfg/__init__.py,sha256=62PSSAa0W4-gAEcRNKoKbcxUWBeFNs0ss2O4XJQhOPY,33145
|
|
@@ -86,7 +86,7 @@ ultralytics/cfg/models/v9/yolov9e.yaml,sha256=dhaR47WxuLOrZWDCceS4bQG00sQdrMc8FQ
|
|
|
86
86
|
ultralytics/cfg/models/v9/yolov9m.yaml,sha256=l6CmivzNu44sRVmkQXk4-tXflbV1nWnk5MSc8su2vhs,1311
|
|
87
87
|
ultralytics/cfg/models/v9/yolov9s.yaml,sha256=lPWcu-6ub1kCBD6zIDFwthYZ3RvdJfODWKy3vEQWRjo,1291
|
|
88
88
|
ultralytics/cfg/models/v9/yolov9t.yaml,sha256=qL__kr6GoefpQWP4jV0jdzwTp46bdFUcqtPRnfDbkY8,1275
|
|
89
|
-
ultralytics/cfg/solutions/default.yaml,sha256=
|
|
89
|
+
ultralytics/cfg/solutions/default.yaml,sha256=H4pXUoA-IafiHL6NNNTyWXrlHAjMRqaItGK1U5amNE4,825
|
|
90
90
|
ultralytics/cfg/trackers/botsort.yaml,sha256=8B0xNbnG_E-9DCUpap72PWkUgBb1AjuApEn7gHiVngE,916
|
|
91
91
|
ultralytics/cfg/trackers/bytetrack.yaml,sha256=8vpTZ2x9mhRXJymoJvs1G8kTXo_HxbSwHup2FQALT3A,721
|
|
92
92
|
ultralytics/data/__init__.py,sha256=VGe-ATG7j35F4A4r8Jmzffjlhve4JAJPgRa5ahKTU18,616
|
|
@@ -105,11 +105,11 @@ ultralytics/data/explorer/utils.py,sha256=EvvukQiQUTBrsZznmMnyEX2EqTuwZo_Geyc8yf
|
|
|
105
105
|
ultralytics/data/explorer/gui/__init__.py,sha256=mHtJuK4hwF8cuV-VHDc7tp6u6D1gHz2Z7JI8grmQDTs,42
|
|
106
106
|
ultralytics/data/explorer/gui/dash.py,sha256=vZ476NaUH4FKU08rAJ1K9WNyKtg0soMyJJxqg176yWc,10498
|
|
107
107
|
ultralytics/engine/__init__.py,sha256=mHtJuK4hwF8cuV-VHDc7tp6u6D1gHz2Z7JI8grmQDTs,42
|
|
108
|
-
ultralytics/engine/exporter.py,sha256=
|
|
108
|
+
ultralytics/engine/exporter.py,sha256=DeHW_T_Zd3A21BLQYV1-FnS5EcmepMOy9nrussYNieU,57505
|
|
109
109
|
ultralytics/engine/model.py,sha256=TDuy9JzzyvOaq5aKVljL_MFRKBDMCFwaLo3JD_d45CU,51462
|
|
110
110
|
ultralytics/engine/predictor.py,sha256=MgMWHUJdRcVCaVmOyvdy2Gjk_EyRHv-ar0SSGxQe8F4,17471
|
|
111
111
|
ultralytics/engine/results.py,sha256=8RJlN8J-_9w-mrDZm9wC-DZJTPBS7v1c_r_R173QyRM,75043
|
|
112
|
-
ultralytics/engine/trainer.py,sha256=
|
|
112
|
+
ultralytics/engine/trainer.py,sha256=ZCEXUPbJG_8Hzn2mLergk3WV-41ei0LT84Tspk0le30,37147
|
|
113
113
|
ultralytics/engine/tuner.py,sha256=gPqDTHH7vRB2O3YyH26m1BjVKbXxuA2XAlPRzTKFZsc,11838
|
|
114
114
|
ultralytics/engine/validator.py,sha256=2C_qXI36Z9rLOpmS0YR8Qe3ka4p23YiH2w5ai7-XBwE,14811
|
|
115
115
|
ultralytics/hub/__init__.py,sha256=3SKvZ5aRina3h94xMPQIB3D4maF62qFcyIqPPHRHNAc,5644
|
|
@@ -185,14 +185,14 @@ ultralytics/nn/modules/head.py,sha256=x0Y8lTKFqYC4oAN1JTJ-yQ43sIXEIp35dmC14vdtQn
|
|
|
185
185
|
ultralytics/nn/modules/transformer.py,sha256=tGiK8NmPfswwW1rbF21r5ILUkkZQ6Nk4s8j16vFBmps,18069
|
|
186
186
|
ultralytics/nn/modules/utils.py,sha256=a88cKl2wz1nMVSEBiajtvaCbDBQIkESWOKTZ_WAJy90,3195
|
|
187
187
|
ultralytics/solutions/__init__.py,sha256=6RDeXWO1QSaMgCq8YrWXaj2xvPw2sJwJL_a0dgjCvz0,648
|
|
188
|
-
ultralytics/solutions/ai_gym.py,sha256=
|
|
188
|
+
ultralytics/solutions/ai_gym.py,sha256=lBAkWV8vrEdKAXcBFVbugPeZZ08MOjGYTdnFlG22vKM,3772
|
|
189
189
|
ultralytics/solutions/analytics.py,sha256=bGuZes11D7DNiTsHdwu6PJ0QA0vCiqMMAtZ7NyEkshY,11568
|
|
190
190
|
ultralytics/solutions/distance_calculation.py,sha256=o_DAHk4JX8n2Vt7E68MX67mREOBZuy5skbXtVZ6iu_4,5228
|
|
191
|
-
ultralytics/solutions/heatmap.py,sha256=
|
|
192
|
-
ultralytics/solutions/object_counter.py,sha256=
|
|
191
|
+
ultralytics/solutions/heatmap.py,sha256=2C4s_rVFcOc5oSWxb0pNxNoCawe4lxajpTDNFd4tVL8,3850
|
|
192
|
+
ultralytics/solutions/object_counter.py,sha256=uuA7B-v9u-ElyEg1xCuNRgcnxpRpEfBWCdLs2ppjzzk,5497
|
|
193
193
|
ultralytics/solutions/parking_management.py,sha256=VgYyhoSEo7fnPegIhNUqnFL0jlMEevALx0QQbzJ3vGI,9049
|
|
194
194
|
ultralytics/solutions/queue_management.py,sha256=yKPGc2-fN-lMpNddkxjN7xYGIJwMdoU-VIDRxQ1KPow,4869
|
|
195
|
-
ultralytics/solutions/solutions.py,sha256=
|
|
195
|
+
ultralytics/solutions/solutions.py,sha256=y6A2ZelsUj9RgN0GZNFBc_01UakoByT_jLG8-FiiLyI,3461
|
|
196
196
|
ultralytics/solutions/speed_estimation.py,sha256=c9OPGpDU9x6Dj4SobNc-sO90EZTPTGeKkW5u6C6Zj7g,4623
|
|
197
197
|
ultralytics/solutions/streamlit_inference.py,sha256=qA2EtwUC7ADOQ8P-zs3VPyrIoRArhcZz9CxkFbH63bw,5699
|
|
198
198
|
ultralytics/trackers/__init__.py,sha256=j72IgH2dZHQArMPK4YwcV5ieIw94fYvlGdQjB9cOQKw,227
|
|
@@ -204,10 +204,10 @@ ultralytics/trackers/utils/__init__.py,sha256=mHtJuK4hwF8cuV-VHDc7tp6u6D1gHz2Z7J
|
|
|
204
204
|
ultralytics/trackers/utils/gmc.py,sha256=VcURuY041qGCeWUGMxHZBr10T16LtcMqyv7AmTfE1MY,14557
|
|
205
205
|
ultralytics/trackers/utils/kalman_filter.py,sha256=cH9zD3fwkuezP97H9mw8cSBN7a8hHKx_Sx1j7t3oYGs,21349
|
|
206
206
|
ultralytics/trackers/utils/matching.py,sha256=3Ie1WNNRZ4_q3365F03XD7Nr9juZB_08mw4yUKC3w74,7162
|
|
207
|
-
ultralytics/utils/__init__.py,sha256=
|
|
207
|
+
ultralytics/utils/__init__.py,sha256=XAfItx7avPCi7fpT7rRyQQqgjh2OwoSEkvkp01BbtYc,48760
|
|
208
208
|
ultralytics/utils/autobatch.py,sha256=AXboYfNSnTGsYj5FmgGYPQd0crfkeleyms6QXQfZGQ4,4194
|
|
209
209
|
ultralytics/utils/benchmarks.py,sha256=8FYp5WPzcxcDaeg8ol2sgzRBHVGYatEO7f3MrmPF6nI,25097
|
|
210
|
-
ultralytics/utils/checks.py,sha256=
|
|
210
|
+
ultralytics/utils/checks.py,sha256=7peQ6Ra7mgcu5Xt1XbYiMEJkO-8aYPHco7CBVRQ_oR4,29559
|
|
211
211
|
ultralytics/utils/dist.py,sha256=NDFga-uKxkBX2zLxFHSene_cCiGQJoyOeCXcN9JIOIk,2358
|
|
212
212
|
ultralytics/utils/downloads.py,sha256=97JitihZqvIMS6_TX5rJAG7BI8eYHlu5g8YXlI0RkR4,21998
|
|
213
213
|
ultralytics/utils/errors.py,sha256=GqP_Jgj_n0paxn8OMhn3DTCgoNkB2WjUcUaqs-M6SQk,816
|
|
@@ -217,9 +217,9 @@ ultralytics/utils/loss.py,sha256=SW3FVFFp8Ki_LCT8wIdFbm6KmyPcQn3RmKNcvVAhMQI,341
|
|
|
217
217
|
ultralytics/utils/metrics.py,sha256=UgLGudWp57uXDMlMUJy4gsz6cfVjcq7tYmHeto3TqvM,53927
|
|
218
218
|
ultralytics/utils/ops.py,sha256=dsXNdyrYx_p6io6zezig9p84dxS7U-10vceHNVu2IL0,32888
|
|
219
219
|
ultralytics/utils/patches.py,sha256=J-iOwIRbfUs-inBZerhnXby5tUKjYcOIyvhLTS352JE,3270
|
|
220
|
-
ultralytics/utils/plotting.py,sha256=
|
|
220
|
+
ultralytics/utils/plotting.py,sha256=UQMgubdCKkIcKLLIXkE6uM9dhL7NlFRka6xXgfCMFn8,61153
|
|
221
221
|
ultralytics/utils/tal.py,sha256=ECsu95xEqOItmxMDN4YTD3FsUiIsQNWy0pZC3TfvFfk,16877
|
|
222
|
-
ultralytics/utils/torch_utils.py,sha256=
|
|
222
|
+
ultralytics/utils/torch_utils.py,sha256=Dji6ELzywm4yq1D4AbUhOsanmoo9-pwxx5GBlYdIgqU,29956
|
|
223
223
|
ultralytics/utils/triton.py,sha256=gg1finxno_tY2Ge9PMhmu7PI9wvoFZoiicdT4Bhqv3w,3936
|
|
224
224
|
ultralytics/utils/tuner.py,sha256=AtEtK6pOt9xVTyx864OpNRVxNdAxz5aKHzveiXwkD1A,6250
|
|
225
225
|
ultralytics/utils/callbacks/__init__.py,sha256=YrWqC3BVVaTLob4iCPR6I36mUxIUOpPJW7B_LjT78Qw,214
|
|
@@ -233,9 +233,9 @@ ultralytics/utils/callbacks/neptune.py,sha256=5Z3ua5YBTUS56FH8VQKQG1aaIo9fH8GEyz
|
|
|
233
233
|
ultralytics/utils/callbacks/raytune.py,sha256=ODVYzy-CoM4Uge0zjkh3Hnh9nF2M0vhDrSenXnvcizw,705
|
|
234
234
|
ultralytics/utils/callbacks/tensorboard.py,sha256=0kn4IR10no99UCIheojWRujgybmUHSx5fPI6Vsq6l_g,4135
|
|
235
235
|
ultralytics/utils/callbacks/wb.py,sha256=9-fjQIdLjr3b73DTE3rHO171KvbH1VweJ-bmbv-rqTw,6747
|
|
236
|
-
ultralytics-8.3.
|
|
237
|
-
ultralytics-8.3.
|
|
238
|
-
ultralytics-8.3.
|
|
239
|
-
ultralytics-8.3.
|
|
240
|
-
ultralytics-8.3.
|
|
241
|
-
ultralytics-8.3.
|
|
236
|
+
ultralytics-8.3.6.dist-info/LICENSE,sha256=DZak_2itbUtvHzD3E7GNUYSRK6jdOJ-GqncQ2weavLA,34523
|
|
237
|
+
ultralytics-8.3.6.dist-info/METADATA,sha256=8c1KpR7WhT8HlvpimiFOS4G3vd8KtQ8YxBUHYnQ_dDc,34699
|
|
238
|
+
ultralytics-8.3.6.dist-info/WHEEL,sha256=GV9aMThwP_4oNCtvEC2ec3qUYutgWeAzklro_0m4WJQ,91
|
|
239
|
+
ultralytics-8.3.6.dist-info/entry_points.txt,sha256=YM_wiKyTe9yRrsEfqvYolNO5ngwfoL4-NwgKzc8_7sI,93
|
|
240
|
+
ultralytics-8.3.6.dist-info/top_level.txt,sha256=XP49TwiMw4QGsvTLSYiJhz1xF_k7ev5mQ8jJXaXi45Q,12
|
|
241
|
+
ultralytics-8.3.6.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|