ultralytics 8.2.4__py3-none-any.whl → 8.2.5__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 +1 -1
- ultralytics/solutions/heatmap.py +13 -22
- ultralytics/solutions/object_counter.py +13 -22
- ultralytics/solutions/parking_management.py +235 -0
- ultralytics/utils/plotting.py +47 -35
- {ultralytics-8.2.4.dist-info → ultralytics-8.2.5.dist-info}/METADATA +1 -1
- {ultralytics-8.2.4.dist-info → ultralytics-8.2.5.dist-info}/RECORD +11 -10
- {ultralytics-8.2.4.dist-info → ultralytics-8.2.5.dist-info}/LICENSE +0 -0
- {ultralytics-8.2.4.dist-info → ultralytics-8.2.5.dist-info}/WHEEL +0 -0
- {ultralytics-8.2.4.dist-info → ultralytics-8.2.5.dist-info}/entry_points.txt +0 -0
- {ultralytics-8.2.4.dist-info → ultralytics-8.2.5.dist-info}/top_level.txt +0 -0
ultralytics/__init__.py
CHANGED
ultralytics/solutions/heatmap.py
CHANGED
|
@@ -190,9 +190,7 @@ class Heatmap:
|
|
|
190
190
|
for box, cls, track_id in zip(self.boxes, self.clss, self.track_ids):
|
|
191
191
|
# Store class info
|
|
192
192
|
if self.names[cls] not in self.class_wise_count:
|
|
193
|
-
|
|
194
|
-
self.names[cls] = self.names[cls][:5]
|
|
195
|
-
self.class_wise_count[self.names[cls]] = {"in": 0, "out": 0}
|
|
193
|
+
self.class_wise_count[self.names[cls]] = {"IN": 0, "OUT": 0}
|
|
196
194
|
|
|
197
195
|
if self.shape == "circle":
|
|
198
196
|
center = (int((box[0] + box[2]) // 2), int((box[1] + box[3]) // 2))
|
|
@@ -225,10 +223,10 @@ class Heatmap:
|
|
|
225
223
|
|
|
226
224
|
if (box[0] - prev_position[0]) * (self.counting_region.centroid.x - prev_position[0]) > 0:
|
|
227
225
|
self.in_counts += 1
|
|
228
|
-
self.class_wise_count[self.names[cls]]["
|
|
226
|
+
self.class_wise_count[self.names[cls]]["IN"] += 1
|
|
229
227
|
else:
|
|
230
228
|
self.out_counts += 1
|
|
231
|
-
self.class_wise_count[self.names[cls]]["
|
|
229
|
+
self.class_wise_count[self.names[cls]]["OUT"] += 1
|
|
232
230
|
|
|
233
231
|
# Count objects using line
|
|
234
232
|
elif len(self.count_reg_pts) == 2:
|
|
@@ -239,10 +237,10 @@ class Heatmap:
|
|
|
239
237
|
|
|
240
238
|
if (box[0] - prev_position[0]) * (self.counting_region.centroid.x - prev_position[0]) > 0:
|
|
241
239
|
self.in_counts += 1
|
|
242
|
-
self.class_wise_count[self.names[cls]]["
|
|
240
|
+
self.class_wise_count[self.names[cls]]["IN"] += 1
|
|
243
241
|
else:
|
|
244
242
|
self.out_counts += 1
|
|
245
|
-
self.class_wise_count[self.names[cls]]["
|
|
243
|
+
self.class_wise_count[self.names[cls]]["OUT"] += 1
|
|
246
244
|
|
|
247
245
|
else:
|
|
248
246
|
for box, cls in zip(self.boxes, self.clss):
|
|
@@ -264,28 +262,21 @@ class Heatmap:
|
|
|
264
262
|
heatmap_normalized = cv2.normalize(self.heatmap, None, 0, 255, cv2.NORM_MINMAX)
|
|
265
263
|
heatmap_colored = cv2.applyColorMap(heatmap_normalized.astype(np.uint8), self.colormap)
|
|
266
264
|
|
|
267
|
-
|
|
265
|
+
labels_dict = {}
|
|
268
266
|
|
|
269
267
|
for key, value in self.class_wise_count.items():
|
|
270
|
-
if value["
|
|
268
|
+
if value["IN"] != 0 or value["OUT"] != 0:
|
|
271
269
|
if not self.view_in_counts and not self.view_out_counts:
|
|
272
|
-
|
|
270
|
+
continue
|
|
273
271
|
elif not self.view_in_counts:
|
|
274
|
-
|
|
272
|
+
labels_dict[str.capitalize(key)] = f"OUT {value['OUT']}"
|
|
275
273
|
elif not self.view_out_counts:
|
|
276
|
-
|
|
274
|
+
labels_dict[str.capitalize(key)] = f"IN {value['IN']}"
|
|
277
275
|
else:
|
|
278
|
-
|
|
276
|
+
labels_dict[str.capitalize(key)] = f"IN {value['IN']} OUT {value['OUT']}"
|
|
279
277
|
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
if self.count_reg_pts is not None and label is not None:
|
|
284
|
-
self.annotator.display_counts(
|
|
285
|
-
counts=label,
|
|
286
|
-
count_txt_color=self.count_txt_color,
|
|
287
|
-
count_bg_color=self.count_bg_color,
|
|
288
|
-
)
|
|
278
|
+
if labels_dict is not None:
|
|
279
|
+
self.annotator.display_analytics(self.im0, labels_dict, self.count_txt_color, self.count_bg_color, 10)
|
|
289
280
|
|
|
290
281
|
self.im0 = cv2.addWeighted(self.im0, 1 - self.heatmap_alpha, heatmap_colored, self.heatmap_alpha, 0)
|
|
291
282
|
|
|
@@ -181,9 +181,7 @@ class ObjectCounter:
|
|
|
181
181
|
|
|
182
182
|
# Store class info
|
|
183
183
|
if self.names[cls] not in self.class_wise_count:
|
|
184
|
-
|
|
185
|
-
self.names[cls] = self.names[cls][:5]
|
|
186
|
-
self.class_wise_count[self.names[cls]] = {"in": 0, "out": 0}
|
|
184
|
+
self.class_wise_count[self.names[cls]] = {"IN": 0, "OUT": 0}
|
|
187
185
|
|
|
188
186
|
# Draw Tracks
|
|
189
187
|
track_line = self.track_history[track_id]
|
|
@@ -210,10 +208,10 @@ class ObjectCounter:
|
|
|
210
208
|
|
|
211
209
|
if (box[0] - prev_position[0]) * (self.counting_region.centroid.x - prev_position[0]) > 0:
|
|
212
210
|
self.in_counts += 1
|
|
213
|
-
self.class_wise_count[self.names[cls]]["
|
|
211
|
+
self.class_wise_count[self.names[cls]]["IN"] += 1
|
|
214
212
|
else:
|
|
215
213
|
self.out_counts += 1
|
|
216
|
-
self.class_wise_count[self.names[cls]]["
|
|
214
|
+
self.class_wise_count[self.names[cls]]["OUT"] += 1
|
|
217
215
|
|
|
218
216
|
# Count objects using line
|
|
219
217
|
elif len(self.reg_pts) == 2:
|
|
@@ -224,33 +222,26 @@ class ObjectCounter:
|
|
|
224
222
|
|
|
225
223
|
if (box[0] - prev_position[0]) * (self.counting_region.centroid.x - prev_position[0]) > 0:
|
|
226
224
|
self.in_counts += 1
|
|
227
|
-
self.class_wise_count[self.names[cls]]["
|
|
225
|
+
self.class_wise_count[self.names[cls]]["IN"] += 1
|
|
228
226
|
else:
|
|
229
227
|
self.out_counts += 1
|
|
230
|
-
self.class_wise_count[self.names[cls]]["
|
|
228
|
+
self.class_wise_count[self.names[cls]]["OUT"] += 1
|
|
231
229
|
|
|
232
|
-
|
|
230
|
+
labels_dict = {}
|
|
233
231
|
|
|
234
232
|
for key, value in self.class_wise_count.items():
|
|
235
|
-
if value["
|
|
233
|
+
if value["IN"] != 0 or value["OUT"] != 0:
|
|
236
234
|
if not self.view_in_counts and not self.view_out_counts:
|
|
237
|
-
|
|
235
|
+
continue
|
|
238
236
|
elif not self.view_in_counts:
|
|
239
|
-
|
|
237
|
+
labels_dict[str.capitalize(key)] = f"OUT {value['OUT']}"
|
|
240
238
|
elif not self.view_out_counts:
|
|
241
|
-
|
|
239
|
+
labels_dict[str.capitalize(key)] = f"IN {value['IN']}"
|
|
242
240
|
else:
|
|
243
|
-
|
|
241
|
+
labels_dict[str.capitalize(key)] = f"IN {value['IN']} OUT {value['OUT']}"
|
|
244
242
|
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
if label is not None:
|
|
249
|
-
self.annotator.display_counts(
|
|
250
|
-
counts=label,
|
|
251
|
-
count_txt_color=self.count_txt_color,
|
|
252
|
-
count_bg_color=self.count_bg_color,
|
|
253
|
-
)
|
|
243
|
+
if labels_dict is not None:
|
|
244
|
+
self.annotator.display_analytics(self.im0, labels_dict, self.count_txt_color, self.count_bg_color, 10)
|
|
254
245
|
|
|
255
246
|
def display_frames(self):
|
|
256
247
|
"""Display frame."""
|
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
import json
|
|
2
|
+
from tkinter import filedialog, messagebox
|
|
3
|
+
|
|
4
|
+
import cv2
|
|
5
|
+
import numpy as np
|
|
6
|
+
from PIL import Image, ImageTk
|
|
7
|
+
|
|
8
|
+
from ultralytics.utils.checks import check_imshow, check_requirements
|
|
9
|
+
from ultralytics.utils.plotting import Annotator
|
|
10
|
+
|
|
11
|
+
check_requirements("tkinter")
|
|
12
|
+
import tkinter as tk
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class ParkingPtsSelection:
|
|
16
|
+
def __init__(self, master):
|
|
17
|
+
# Initialize window and widgets.
|
|
18
|
+
self.master = master
|
|
19
|
+
master.title("Ultralytics Parking Zones Points Selector")
|
|
20
|
+
self.initialize_ui()
|
|
21
|
+
|
|
22
|
+
# Initialize properties
|
|
23
|
+
self.image_path = None
|
|
24
|
+
self.image = None
|
|
25
|
+
self.canvas_image = None
|
|
26
|
+
self.canvas = None
|
|
27
|
+
self.bounding_boxes = []
|
|
28
|
+
self.current_box = []
|
|
29
|
+
self.img_width = 0
|
|
30
|
+
self.img_height = 0
|
|
31
|
+
|
|
32
|
+
# Constants
|
|
33
|
+
self.canvas_max_width = 1280
|
|
34
|
+
self.canvas_max_height = 720
|
|
35
|
+
|
|
36
|
+
def initialize_ui(self):
|
|
37
|
+
"""Setup UI components."""
|
|
38
|
+
# Setup buttons
|
|
39
|
+
button_frame = tk.Frame(self.master)
|
|
40
|
+
button_frame.pack(side=tk.TOP)
|
|
41
|
+
|
|
42
|
+
tk.Button(button_frame, text="Upload Image", command=self.upload_image).grid(row=0, column=0)
|
|
43
|
+
tk.Button(button_frame, text="Remove Last BBox", command=self.remove_last_bounding_box).grid(row=0, column=1)
|
|
44
|
+
tk.Button(button_frame, text="Save", command=self.save_to_json).grid(row=0, column=2)
|
|
45
|
+
|
|
46
|
+
# Setup canvas for image display
|
|
47
|
+
self.canvas = tk.Canvas(self.master, bg="white")
|
|
48
|
+
self.canvas.pack(side=tk.BOTTOM)
|
|
49
|
+
self.canvas.bind("<Button-1>", self.on_canvas_click)
|
|
50
|
+
|
|
51
|
+
def upload_image(self):
|
|
52
|
+
"""Upload an image and resize it to fit canvas."""
|
|
53
|
+
self.image_path = filedialog.askopenfilename(filetypes=[("Image Files", "*.png;*.jpg;*.jpeg")])
|
|
54
|
+
if not self.image_path:
|
|
55
|
+
return
|
|
56
|
+
|
|
57
|
+
self.image = Image.open(self.image_path)
|
|
58
|
+
self.img_width, self.img_height = self.image.size
|
|
59
|
+
|
|
60
|
+
# Calculate the aspect ratio and resize image
|
|
61
|
+
aspect_ratio = self.img_width / self.img_height
|
|
62
|
+
if aspect_ratio > 1:
|
|
63
|
+
# Landscape orientation
|
|
64
|
+
canvas_width = min(self.canvas_max_width, self.img_width)
|
|
65
|
+
canvas_height = int(canvas_width / aspect_ratio)
|
|
66
|
+
else:
|
|
67
|
+
# Portrait orientation
|
|
68
|
+
canvas_height = min(self.canvas_max_height, self.img_height)
|
|
69
|
+
canvas_width = int(canvas_height * aspect_ratio)
|
|
70
|
+
|
|
71
|
+
self.canvas.config(width=canvas_width, height=canvas_height)
|
|
72
|
+
resized_image = self.image.resize((canvas_width, canvas_height), Image.LANCZOS)
|
|
73
|
+
self.canvas_image = ImageTk.PhotoImage(resized_image)
|
|
74
|
+
self.canvas.create_image(0, 0, anchor=tk.NW, image=self.canvas_image)
|
|
75
|
+
|
|
76
|
+
# Reset bounding boxes and current box
|
|
77
|
+
self.bounding_boxes = []
|
|
78
|
+
self.current_box = []
|
|
79
|
+
|
|
80
|
+
def on_canvas_click(self, event):
|
|
81
|
+
"""Handle mouse clicks on canvas to create points for bounding boxes."""
|
|
82
|
+
self.current_box.append((event.x, event.y))
|
|
83
|
+
|
|
84
|
+
if len(self.current_box) == 4:
|
|
85
|
+
self.bounding_boxes.append(self.current_box)
|
|
86
|
+
self.draw_bounding_box(self.current_box)
|
|
87
|
+
self.current_box = []
|
|
88
|
+
|
|
89
|
+
def draw_bounding_box(self, box):
|
|
90
|
+
"""Draw bounding box on canvas."""
|
|
91
|
+
for i in range(4):
|
|
92
|
+
x1, y1 = box[i]
|
|
93
|
+
x2, y2 = box[(i + 1) % 4]
|
|
94
|
+
self.canvas.create_line(x1, y1, x2, y2, fill="blue", width=2)
|
|
95
|
+
|
|
96
|
+
def remove_last_bounding_box(self):
|
|
97
|
+
"""Remove the last drawn bounding box from canvas."""
|
|
98
|
+
if self.bounding_boxes:
|
|
99
|
+
self.bounding_boxes.pop() # Remove the last bounding box
|
|
100
|
+
self.canvas.delete("all") # Clear the canvas
|
|
101
|
+
self.canvas.create_image(0, 0, anchor=tk.NW, image=self.canvas_image) # Redraw the image
|
|
102
|
+
|
|
103
|
+
# Redraw all bounding boxes
|
|
104
|
+
for box in self.bounding_boxes:
|
|
105
|
+
self.draw_bounding_box(box)
|
|
106
|
+
|
|
107
|
+
messagebox.showinfo("Success", "Last bounding box removed.")
|
|
108
|
+
else:
|
|
109
|
+
messagebox.showwarning("Warning", "No bounding boxes to remove.")
|
|
110
|
+
|
|
111
|
+
def save_to_json(self):
|
|
112
|
+
canvas_width, canvas_height = self.canvas.winfo_width(), self.canvas.winfo_height()
|
|
113
|
+
width_scaling_factor = self.img_width / canvas_width
|
|
114
|
+
height_scaling_factor = self.img_height / canvas_height
|
|
115
|
+
bounding_boxes_data = []
|
|
116
|
+
for box in self.bounding_boxes:
|
|
117
|
+
print("Bounding Box ", bounding_boxes_data)
|
|
118
|
+
rescaled_box = []
|
|
119
|
+
for x, y in box:
|
|
120
|
+
rescaled_x = int(x * width_scaling_factor)
|
|
121
|
+
rescaled_y = int(y * height_scaling_factor)
|
|
122
|
+
rescaled_box.append((rescaled_x, rescaled_y))
|
|
123
|
+
bounding_boxes_data.append({"points": rescaled_box})
|
|
124
|
+
with open("bounding_boxes.json", "w") as json_file:
|
|
125
|
+
json.dump(bounding_boxes_data, json_file, indent=4)
|
|
126
|
+
|
|
127
|
+
messagebox.showinfo("Success", "Bounding boxes saved to bounding_boxes.json")
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
class ParkingManagement:
|
|
131
|
+
def __init__(
|
|
132
|
+
self,
|
|
133
|
+
model_path,
|
|
134
|
+
txt_color=(0, 0, 0),
|
|
135
|
+
bg_color=(255, 255, 255),
|
|
136
|
+
occupied_region_color=(0, 255, 0),
|
|
137
|
+
available_region_color=(0, 0, 255),
|
|
138
|
+
margin=10,
|
|
139
|
+
):
|
|
140
|
+
# Model path and initialization
|
|
141
|
+
self.model_path = model_path
|
|
142
|
+
self.model = self.load_model()
|
|
143
|
+
|
|
144
|
+
# Labels dictionary
|
|
145
|
+
self.labels_dict = {"Occupancy": 0, "Available": 0}
|
|
146
|
+
|
|
147
|
+
# Visualization details
|
|
148
|
+
self.margin = margin
|
|
149
|
+
self.bg_color = bg_color
|
|
150
|
+
self.txt_color = txt_color
|
|
151
|
+
self.occupied_region_color = occupied_region_color
|
|
152
|
+
self.available_region_color = available_region_color
|
|
153
|
+
|
|
154
|
+
self.window_name = "Ultralytics YOLOv8 Parking Management System"
|
|
155
|
+
# Check if environment support imshow
|
|
156
|
+
self.env_check = check_imshow(warn=True)
|
|
157
|
+
|
|
158
|
+
def load_model(self):
|
|
159
|
+
"""Load the Ultralytics YOLOv8 model for inference and analytics."""
|
|
160
|
+
from ultralytics import YOLO
|
|
161
|
+
|
|
162
|
+
self.model = YOLO(self.model_path)
|
|
163
|
+
return self.model
|
|
164
|
+
|
|
165
|
+
def parking_regions_extraction(self, json_file):
|
|
166
|
+
"""
|
|
167
|
+
Extract parking regions from json file.
|
|
168
|
+
|
|
169
|
+
Args:
|
|
170
|
+
json_file (str): file that have all parking slot points
|
|
171
|
+
"""
|
|
172
|
+
|
|
173
|
+
with open(json_file, "r") as json_file:
|
|
174
|
+
json_data = json.load(json_file)
|
|
175
|
+
return json_data
|
|
176
|
+
|
|
177
|
+
def process_data(self, json_data, im0, boxes, clss):
|
|
178
|
+
"""
|
|
179
|
+
Process the model data for parking lot management.
|
|
180
|
+
|
|
181
|
+
Args:
|
|
182
|
+
json_data (str): json data for parking lot management
|
|
183
|
+
im0 (ndarray): inference image
|
|
184
|
+
boxes (list): bounding boxes data
|
|
185
|
+
clss (list): bounding boxes classes list
|
|
186
|
+
Returns:
|
|
187
|
+
filled_slots (int): total slots that are filled in parking lot
|
|
188
|
+
empty_slots (int): total slots that are available in parking lot
|
|
189
|
+
"""
|
|
190
|
+
annotator = Annotator(im0)
|
|
191
|
+
total_slots, filled_slots = len(json_data), 0
|
|
192
|
+
empty_slots = total_slots
|
|
193
|
+
|
|
194
|
+
for region in json_data:
|
|
195
|
+
points = region["points"]
|
|
196
|
+
points_array = np.array(points, dtype=np.int32).reshape((-1, 1, 2))
|
|
197
|
+
region_occupied = False
|
|
198
|
+
|
|
199
|
+
for box, cls in zip(boxes, clss):
|
|
200
|
+
x_center = int((box[0] + box[2]) / 2)
|
|
201
|
+
y_center = int((box[1] + box[3]) / 2)
|
|
202
|
+
text = f"{self.model.names[int(cls)]}"
|
|
203
|
+
|
|
204
|
+
annotator.display_objects_labels(
|
|
205
|
+
im0, text, self.txt_color, self.bg_color, x_center, y_center, self.margin
|
|
206
|
+
)
|
|
207
|
+
dist = cv2.pointPolygonTest(points_array, (x_center, y_center), False)
|
|
208
|
+
if dist >= 0:
|
|
209
|
+
region_occupied = True
|
|
210
|
+
break
|
|
211
|
+
|
|
212
|
+
color = self.occupied_region_color if region_occupied else self.available_region_color
|
|
213
|
+
cv2.polylines(im0, [points_array], isClosed=True, color=color, thickness=2)
|
|
214
|
+
if region_occupied:
|
|
215
|
+
filled_slots += 1
|
|
216
|
+
empty_slots -= 1
|
|
217
|
+
|
|
218
|
+
self.labels_dict["Occupancy"] = filled_slots
|
|
219
|
+
self.labels_dict["Available"] = empty_slots
|
|
220
|
+
|
|
221
|
+
annotator.display_analytics(im0, self.labels_dict, self.txt_color, self.bg_color, self.margin)
|
|
222
|
+
|
|
223
|
+
def display_frames(self, im0):
|
|
224
|
+
"""
|
|
225
|
+
Display frame.
|
|
226
|
+
|
|
227
|
+
Args:
|
|
228
|
+
im0 (ndarray): inference image
|
|
229
|
+
"""
|
|
230
|
+
if self.env_check:
|
|
231
|
+
cv2.namedWindow(self.window_name)
|
|
232
|
+
cv2.imshow(self.window_name, im0)
|
|
233
|
+
# Break Window
|
|
234
|
+
if cv2.waitKey(1) & 0xFF == ord("q"):
|
|
235
|
+
return
|
ultralytics/utils/plotting.py
CHANGED
|
@@ -419,51 +419,63 @@ class Annotator:
|
|
|
419
419
|
lineType=cv2.LINE_AA,
|
|
420
420
|
)
|
|
421
421
|
|
|
422
|
-
|
|
422
|
+
### Parking management utils
|
|
423
|
+
def display_objects_labels(self, im0, text, txt_color, bg_color, x_center, y_center, margin):
|
|
423
424
|
"""
|
|
424
|
-
Display
|
|
425
|
+
Display the bounding boxes labels in parking management app.
|
|
425
426
|
|
|
426
427
|
Args:
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
428
|
+
im0 (ndarray): inference image
|
|
429
|
+
text (str): object/class name
|
|
430
|
+
txt_color (bgr color): display color for text foreground
|
|
431
|
+
bg_color (bgr color): display color for text background
|
|
432
|
+
x_center (float): x position center point for bounding box
|
|
433
|
+
y_center (float): y position center point for bounding box
|
|
434
|
+
margin (int): gap between text and rectangle for better display
|
|
430
435
|
"""
|
|
431
436
|
|
|
432
|
-
|
|
433
|
-
|
|
437
|
+
text_size = cv2.getTextSize(text, 0, fontScale=self.sf, thickness=self.tf)[0]
|
|
438
|
+
text_x = x_center - text_size[0] // 2
|
|
439
|
+
text_y = y_center + text_size[1] // 2
|
|
434
440
|
|
|
435
|
-
|
|
441
|
+
rect_x1 = text_x - margin
|
|
442
|
+
rect_y1 = text_y - text_size[1] - margin
|
|
443
|
+
rect_x2 = text_x + text_size[0] + margin
|
|
444
|
+
rect_y2 = text_y + margin
|
|
445
|
+
cv2.rectangle(im0, (rect_x1, rect_y1), (rect_x2, rect_y2), bg_color, -1)
|
|
446
|
+
cv2.putText(im0, text, (text_x, text_y), 0, self.sf, txt_color, self.tf, lineType=cv2.LINE_AA)
|
|
436
447
|
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
cv2.rectangle(
|
|
449
|
-
self.im,
|
|
450
|
-
(text_x_pos - (10 * tf), text_y_pos - (10 * tf)),
|
|
451
|
-
(text_x_pos + max_text_width + (10 * tf), text_y_pos + max_text_height + (10 * tf)),
|
|
452
|
-
count_bg_color,
|
|
453
|
-
-1,
|
|
454
|
-
)
|
|
448
|
+
# Parking lot and object counting app
|
|
449
|
+
def display_analytics(self, im0, text, txt_color, bg_color, margin):
|
|
450
|
+
"""
|
|
451
|
+
Display the overall statistics for parking lots
|
|
452
|
+
Args:
|
|
453
|
+
im0 (ndarray): inference image
|
|
454
|
+
text (dict): labels dictionary
|
|
455
|
+
txt_color (bgr color): display color for text foreground
|
|
456
|
+
bg_color (bgr color): display color for text background
|
|
457
|
+
margin (int): gap between text and rectangle for better display
|
|
458
|
+
"""
|
|
455
459
|
|
|
456
|
-
|
|
460
|
+
horizontal_gap = int(im0.shape[1] * 0.02)
|
|
461
|
+
vertical_gap = int(im0.shape[0] * 0.01)
|
|
462
|
+
|
|
463
|
+
text_y_offset = 0
|
|
464
|
+
|
|
465
|
+
for label, value in text.items():
|
|
466
|
+
txt = f"{label}: {value}"
|
|
467
|
+
text_size = cv2.getTextSize(txt, 0, int(self.sf * 1.5), int(self.tf * 1.5))[0]
|
|
468
|
+
text_x = im0.shape[1] - text_size[0] - margin * 2 - horizontal_gap
|
|
469
|
+
text_y = text_y_offset + text_size[1] + margin * 2 + vertical_gap
|
|
470
|
+
rect_x1 = text_x - margin * 2
|
|
471
|
+
rect_y1 = text_y - text_size[1] - margin * 2
|
|
472
|
+
rect_x2 = text_x + text_size[0] + margin * 2
|
|
473
|
+
rect_y2 = text_y + margin * 2
|
|
474
|
+
cv2.rectangle(im0, (rect_x1, rect_y1), (rect_x2, rect_y2), bg_color, -1)
|
|
457
475
|
cv2.putText(
|
|
458
|
-
self.
|
|
459
|
-
str(count),
|
|
460
|
-
(text_x_pos, text_y_pos + max_text_height),
|
|
461
|
-
0,
|
|
462
|
-
fontScale=self.sf,
|
|
463
|
-
color=count_txt_color,
|
|
464
|
-
thickness=self.tf,
|
|
465
|
-
lineType=cv2.LINE_AA,
|
|
476
|
+
im0, txt, (text_x, text_y), 0, int(self.sf * 1.5), txt_color, int(self.tf * 1.5), lineType=cv2.LINE_AA
|
|
466
477
|
)
|
|
478
|
+
text_y_offset = rect_y2
|
|
467
479
|
|
|
468
480
|
@staticmethod
|
|
469
481
|
def estimate_pose_angle(a, b, c):
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: ultralytics
|
|
3
|
-
Version: 8.2.
|
|
3
|
+
Version: 8.2.5
|
|
4
4
|
Summary: Ultralytics YOLOv8 for SOTA object detection, multi-object tracking, instance segmentation, pose estimation and image classification.
|
|
5
5
|
Author: Glenn Jocher, Ayush Chaurasia, Jing Qiu
|
|
6
6
|
Maintainer: Glenn Jocher, Ayush Chaurasia, Jing Qiu
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
ultralytics/__init__.py,sha256=
|
|
1
|
+
ultralytics/__init__.py,sha256=8L2PFYKp8nFhzx3h971QWLvL3FdQrbfPqRAE4lYrB7Y,632
|
|
2
2
|
ultralytics/assets/bus.jpg,sha256=wCAZxJecGR63Od3ZRERe9Aja1Weayrb9Ug751DS_vGM,137419
|
|
3
3
|
ultralytics/assets/zidane.jpg,sha256=Ftc4aeMmen1O0A3o6GCDO9FlfBslLpTAw0gnetx7bts,50427
|
|
4
4
|
ultralytics/cfg/__init__.py,sha256=4ZnvY2ULMGofFhjaRIzKQlGC5YVkvWkEAYAhnsKC1Po,21312
|
|
@@ -156,8 +156,9 @@ ultralytics/nn/modules/utils.py,sha256=779QnnKp9v8jv251ESduTXJ0ol8HkIOLbGQWwEGQj
|
|
|
156
156
|
ultralytics/solutions/__init__.py,sha256=mHtJuK4hwF8cuV-VHDc7tp6u6D1gHz2Z7JI8grmQDTs,42
|
|
157
157
|
ultralytics/solutions/ai_gym.py,sha256=IZHpvmNyEQT_aqMTrA5sIjCsl3_5Zl2WG31HxGT6KV4,5696
|
|
158
158
|
ultralytics/solutions/distance_calculation.py,sha256=N1QB5uDG_6sp8jD5uSwp_NTPmyP4UCqJm9G2lNrgpr8,6334
|
|
159
|
-
ultralytics/solutions/heatmap.py,sha256=
|
|
160
|
-
ultralytics/solutions/object_counter.py,sha256=
|
|
159
|
+
ultralytics/solutions/heatmap.py,sha256=LDY8cpmsenkaWgDmaKuOPMyQcPCH4jQeMvgbZlTx2fc,11970
|
|
160
|
+
ultralytics/solutions/object_counter.py,sha256=nYwUN_9M5azW9zET_hnV7wIY8gDNR4LtUoWo4C2cbXw,11287
|
|
161
|
+
ultralytics/solutions/parking_management.py,sha256=7M85ThMtQodv-zIfqCIkJccK-_gpOHz4VYiHHx43NwA,8656
|
|
161
162
|
ultralytics/solutions/queue_management.py,sha256=TBQ2dIKYtymBjhdw0Enxa22KHyH3IdXf2C-1Se21siA,6684
|
|
162
163
|
ultralytics/solutions/speed_estimation.py,sha256=lvaU-F8f3V4KFVKFaNS7isIdYtMSFjh_zF9gl0Mals8,6714
|
|
163
164
|
ultralytics/trackers/__init__.py,sha256=j72IgH2dZHQArMPK4YwcV5ieIw94fYvlGdQjB9cOQKw,227
|
|
@@ -182,7 +183,7 @@ ultralytics/utils/loss.py,sha256=ejXnPEIAzNEoNz2UjW0_fcdeUs9Hy-jPzUrJ3FiIIwE,327
|
|
|
182
183
|
ultralytics/utils/metrics.py,sha256=XPD-xP0fchR8KgCuTcihV2-n0EK1cWi3-53BWN_pLuA,53518
|
|
183
184
|
ultralytics/utils/ops.py,sha256=wZCWx7dm5GJNIJHyZaFJRetGcQ7prdv-anplqq9figQ,33309
|
|
184
185
|
ultralytics/utils/patches.py,sha256=SgMqeMsq2K6JoBJP1NplXMl9C6rK0JeJUChjBrJOneo,2750
|
|
185
|
-
ultralytics/utils/plotting.py,sha256=
|
|
186
|
+
ultralytics/utils/plotting.py,sha256=8Bts0M758PxAdOywsn8xv4ULBG7DuCGMhYWBVH5BrOM,48315
|
|
186
187
|
ultralytics/utils/tal.py,sha256=xuIyryUjaaYHkHPG9GvBwh1xxN2Hq4y3hXOtuERehwY,16017
|
|
187
188
|
ultralytics/utils/torch_utils.py,sha256=y1qJniyii0sJFg8dpP-yjYh8AMOoFok9NEZcRi669Jo,25916
|
|
188
189
|
ultralytics/utils/triton.py,sha256=gg1finxno_tY2Ge9PMhmu7PI9wvoFZoiicdT4Bhqv3w,3936
|
|
@@ -198,9 +199,9 @@ ultralytics/utils/callbacks/neptune.py,sha256=5Z3ua5YBTUS56FH8VQKQG1aaIo9fH8GEyz
|
|
|
198
199
|
ultralytics/utils/callbacks/raytune.py,sha256=ODVYzy-CoM4Uge0zjkh3Hnh9nF2M0vhDrSenXnvcizw,705
|
|
199
200
|
ultralytics/utils/callbacks/tensorboard.py,sha256=Z1veCVcn9THPhdplWuIzwlsW2yF7y-On9IZIk3khM0Y,4135
|
|
200
201
|
ultralytics/utils/callbacks/wb.py,sha256=woCQVuZzqtM5KnwxIibcfM3sFBYojeMPnv11jrRaIQA,6674
|
|
201
|
-
ultralytics-8.2.
|
|
202
|
-
ultralytics-8.2.
|
|
203
|
-
ultralytics-8.2.
|
|
204
|
-
ultralytics-8.2.
|
|
205
|
-
ultralytics-8.2.
|
|
206
|
-
ultralytics-8.2.
|
|
202
|
+
ultralytics-8.2.5.dist-info/LICENSE,sha256=DZak_2itbUtvHzD3E7GNUYSRK6jdOJ-GqncQ2weavLA,34523
|
|
203
|
+
ultralytics-8.2.5.dist-info/METADATA,sha256=ZTi7THAVk9TWzifCEVyFz4CfJuAQWyw7-frp1q4S_NY,40595
|
|
204
|
+
ultralytics-8.2.5.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
|
|
205
|
+
ultralytics-8.2.5.dist-info/entry_points.txt,sha256=YM_wiKyTe9yRrsEfqvYolNO5ngwfoL4-NwgKzc8_7sI,93
|
|
206
|
+
ultralytics-8.2.5.dist-info/top_level.txt,sha256=XP49TwiMw4QGsvTLSYiJhz1xF_k7ev5mQ8jJXaXi45Q,12
|
|
207
|
+
ultralytics-8.2.5.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|