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.
- ultralytics/__init__.py +2 -2
- ultralytics/cfg/__init__.py +241 -138
- ultralytics/data/__init__.py +9 -2
- ultralytics/data/annotator.py +4 -4
- ultralytics/data/augment.py +186 -169
- ultralytics/data/base.py +54 -48
- ultralytics/data/build.py +34 -23
- ultralytics/data/converter.py +242 -70
- ultralytics/data/dataset.py +117 -95
- ultralytics/data/explorer/__init__.py +3 -1
- ultralytics/data/explorer/explorer.py +120 -100
- ultralytics/data/explorer/gui/__init__.py +1 -0
- ultralytics/data/explorer/gui/dash.py +123 -89
- ultralytics/data/explorer/utils.py +37 -39
- ultralytics/data/loaders.py +75 -62
- ultralytics/data/split_dota.py +44 -36
- ultralytics/data/utils.py +160 -142
- ultralytics/engine/exporter.py +348 -292
- ultralytics/engine/model.py +102 -66
- ultralytics/engine/predictor.py +74 -55
- ultralytics/engine/results.py +61 -41
- ultralytics/engine/trainer.py +192 -144
- ultralytics/engine/tuner.py +66 -59
- ultralytics/engine/validator.py +31 -26
- ultralytics/hub/__init__.py +54 -31
- ultralytics/hub/auth.py +28 -25
- ultralytics/hub/session.py +282 -133
- ultralytics/hub/utils.py +64 -42
- ultralytics/models/__init__.py +1 -1
- ultralytics/models/fastsam/__init__.py +1 -1
- ultralytics/models/fastsam/model.py +6 -6
- ultralytics/models/fastsam/predict.py +3 -2
- ultralytics/models/fastsam/prompt.py +55 -48
- ultralytics/models/fastsam/val.py +1 -1
- ultralytics/models/nas/__init__.py +1 -1
- ultralytics/models/nas/model.py +9 -8
- ultralytics/models/nas/predict.py +8 -6
- ultralytics/models/nas/val.py +11 -9
- ultralytics/models/rtdetr/__init__.py +1 -1
- ultralytics/models/rtdetr/model.py +11 -9
- ultralytics/models/rtdetr/train.py +18 -16
- ultralytics/models/rtdetr/val.py +25 -19
- ultralytics/models/sam/__init__.py +1 -1
- ultralytics/models/sam/amg.py +13 -14
- ultralytics/models/sam/build.py +44 -42
- ultralytics/models/sam/model.py +6 -6
- ultralytics/models/sam/modules/decoders.py +6 -4
- ultralytics/models/sam/modules/encoders.py +37 -35
- ultralytics/models/sam/modules/sam.py +5 -4
- ultralytics/models/sam/modules/tiny_encoder.py +95 -73
- ultralytics/models/sam/modules/transformer.py +3 -2
- ultralytics/models/sam/predict.py +39 -27
- ultralytics/models/utils/loss.py +99 -95
- ultralytics/models/utils/ops.py +34 -31
- ultralytics/models/yolo/__init__.py +1 -1
- ultralytics/models/yolo/classify/__init__.py +1 -1
- ultralytics/models/yolo/classify/predict.py +8 -6
- ultralytics/models/yolo/classify/train.py +37 -31
- ultralytics/models/yolo/classify/val.py +26 -24
- ultralytics/models/yolo/detect/__init__.py +1 -1
- ultralytics/models/yolo/detect/predict.py +8 -6
- ultralytics/models/yolo/detect/train.py +47 -37
- ultralytics/models/yolo/detect/val.py +100 -82
- ultralytics/models/yolo/model.py +31 -25
- ultralytics/models/yolo/obb/__init__.py +1 -1
- ultralytics/models/yolo/obb/predict.py +13 -11
- ultralytics/models/yolo/obb/train.py +3 -3
- ultralytics/models/yolo/obb/val.py +70 -59
- ultralytics/models/yolo/pose/__init__.py +1 -1
- ultralytics/models/yolo/pose/predict.py +17 -12
- ultralytics/models/yolo/pose/train.py +28 -25
- ultralytics/models/yolo/pose/val.py +91 -64
- ultralytics/models/yolo/segment/__init__.py +1 -1
- ultralytics/models/yolo/segment/predict.py +10 -8
- ultralytics/models/yolo/segment/train.py +16 -15
- ultralytics/models/yolo/segment/val.py +90 -68
- ultralytics/nn/__init__.py +26 -6
- ultralytics/nn/autobackend.py +144 -112
- ultralytics/nn/modules/__init__.py +96 -13
- ultralytics/nn/modules/block.py +28 -7
- ultralytics/nn/modules/conv.py +41 -23
- ultralytics/nn/modules/head.py +60 -52
- ultralytics/nn/modules/transformer.py +49 -32
- ultralytics/nn/modules/utils.py +20 -15
- ultralytics/nn/tasks.py +215 -141
- ultralytics/solutions/ai_gym.py +59 -47
- ultralytics/solutions/distance_calculation.py +17 -14
- ultralytics/solutions/heatmap.py +57 -55
- ultralytics/solutions/object_counter.py +46 -39
- ultralytics/solutions/speed_estimation.py +13 -16
- ultralytics/trackers/__init__.py +1 -1
- ultralytics/trackers/basetrack.py +1 -0
- ultralytics/trackers/bot_sort.py +2 -1
- ultralytics/trackers/byte_tracker.py +10 -7
- ultralytics/trackers/track.py +7 -7
- ultralytics/trackers/utils/gmc.py +25 -25
- ultralytics/trackers/utils/kalman_filter.py +85 -42
- ultralytics/trackers/utils/matching.py +8 -7
- ultralytics/utils/__init__.py +173 -152
- ultralytics/utils/autobatch.py +10 -10
- ultralytics/utils/benchmarks.py +76 -86
- ultralytics/utils/callbacks/__init__.py +1 -1
- ultralytics/utils/callbacks/base.py +29 -29
- ultralytics/utils/callbacks/clearml.py +51 -43
- ultralytics/utils/callbacks/comet.py +81 -66
- ultralytics/utils/callbacks/dvc.py +33 -26
- ultralytics/utils/callbacks/hub.py +44 -26
- ultralytics/utils/callbacks/mlflow.py +31 -24
- ultralytics/utils/callbacks/neptune.py +35 -25
- ultralytics/utils/callbacks/raytune.py +9 -4
- ultralytics/utils/callbacks/tensorboard.py +16 -11
- ultralytics/utils/callbacks/wb.py +39 -33
- ultralytics/utils/checks.py +189 -141
- ultralytics/utils/dist.py +15 -12
- ultralytics/utils/downloads.py +112 -96
- ultralytics/utils/errors.py +1 -1
- ultralytics/utils/files.py +11 -11
- ultralytics/utils/instance.py +22 -22
- ultralytics/utils/loss.py +117 -67
- ultralytics/utils/metrics.py +224 -158
- ultralytics/utils/ops.py +38 -28
- ultralytics/utils/patches.py +3 -3
- ultralytics/utils/plotting.py +217 -120
- ultralytics/utils/tal.py +19 -13
- ultralytics/utils/torch_utils.py +138 -109
- ultralytics/utils/triton.py +12 -10
- ultralytics/utils/tuner.py +49 -47
- {ultralytics-8.0.238.dist-info → ultralytics-8.0.239.dist-info}/METADATA +2 -1
- ultralytics-8.0.239.dist-info/RECORD +188 -0
- ultralytics-8.0.238.dist-info/RECORD +0 -188
- {ultralytics-8.0.238.dist-info → ultralytics-8.0.239.dist-info}/LICENSE +0 -0
- {ultralytics-8.0.238.dist-info → ultralytics-8.0.239.dist-info}/WHEEL +0 -0
- {ultralytics-8.0.238.dist-info → ultralytics-8.0.239.dist-info}/entry_points.txt +0 -0
- {ultralytics-8.0.238.dist-info → ultralytics-8.0.239.dist-info}/top_level.txt +0 -0
ultralytics/solutions/ai_gym.py
CHANGED
|
@@ -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 =
|
|
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(
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
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 = [
|
|
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 ==
|
|
81
|
-
self.angle[ind] = self.annotator.estimate_pose_angle(
|
|
82
|
-
|
|
83
|
-
|
|
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 ==
|
|
87
|
-
self.angle[ind] = self.annotator.estimate_pose_angle(
|
|
88
|
-
|
|
89
|
-
|
|
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] =
|
|
93
|
-
if self.angle[ind] < self.posedown_angle and self.stage[ind] ==
|
|
94
|
-
self.stage[ind] =
|
|
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(
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
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] =
|
|
105
|
-
if self.angle[ind] < self.posedown_angle and self.stage[ind] ==
|
|
106
|
-
self.stage[ind] =
|
|
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(
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
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] =
|
|
116
|
-
if self.angle[ind] < self.posedown_angle and self.stage[ind] ==
|
|
117
|
-
self.stage[ind] =
|
|
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(
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
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(
|
|
129
|
-
if cv2.waitKey(1) & 0xFF == ord(
|
|
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__ ==
|
|
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(
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
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(
|
|
133
|
-
|
|
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(
|
|
183
|
-
cv2.setMouseCallback(
|
|
184
|
-
cv2.imshow(
|
|
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(
|
|
189
|
+
if cv2.waitKey(1) & 0xFF == ord("q"):
|
|
187
190
|
return
|
|
188
191
|
|
|
189
192
|
|
|
190
|
-
if __name__ ==
|
|
193
|
+
if __name__ == "__main__":
|
|
191
194
|
DistanceCalculation()
|
ultralytics/solutions/heatmap.py
CHANGED
|
@@ -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(
|
|
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 =
|
|
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(
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
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(
|
|
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(
|
|
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(
|
|
127
|
-
print(
|
|
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 [
|
|
144
|
+
if self.shape not in ["circle", "rect"]:
|
|
144
145
|
print("Unknown shape value provided, 'circle' & 'rect' supported")
|
|
145
|
-
print(
|
|
146
|
-
self.shape =
|
|
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(
|
|
184
|
-
|
|
185
|
-
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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 =
|
|
248
|
-
outcount_label =
|
|
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 +
|
|
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(
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
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(
|
|
278
|
+
cv2.imshow("Ultralytics Heatmap", self.im0)
|
|
277
279
|
|
|
278
|
-
if cv2.waitKey(1) & 0xFF == ord(
|
|
280
|
+
if cv2.waitKey(1) & 0xFF == ord("q"):
|
|
279
281
|
return
|
|
280
282
|
|
|
281
283
|
|
|
282
|
-
if __name__ ==
|
|
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(
|
|
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(
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
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(
|
|
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(
|
|
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(
|
|
113
|
-
print(
|
|
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(
|
|
167
|
-
|
|
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(
|
|
178
|
-
|
|
179
|
-
|
|
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 =
|
|
202
|
-
outcount_label =
|
|
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 +
|
|
217
|
+
counts_label = incount_label + " " + outcount_label
|
|
214
218
|
|
|
215
219
|
if counts_label is not None:
|
|
216
|
-
self.annotator.count_labels(
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
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(
|
|
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(
|
|
227
|
-
|
|
228
|
-
|
|
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(
|
|
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__ ==
|
|
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(
|
|
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 =
|
|
118
|
-
self.dist_data[track_id])) +
|
|
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
|
-
|
|
137
|
-
direction =
|
|
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 =
|
|
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(
|
|
198
|
-
if cv2.waitKey(1) & 0xFF == ord(
|
|
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__ ==
|
|
199
|
+
if __name__ == "__main__":
|
|
203
200
|
SpeedEstimator()
|
ultralytics/trackers/__init__.py
CHANGED