Test_model1 / ultralytics /solutions /parking_management.py
akswelh's picture
Upload 663 files
f6228f9 verified
# Ultralytics YOLO 🚀, AGPL-3.0 license
import json
import cv2
import numpy as np
from ultralytics.utils.checks import check_imshow, check_requirements
from ultralytics.utils.plotting import Annotator
class ParkingPtsSelection:
"""Class for selecting and managing parking zone points on images using a Tkinter-based UI."""
def __init__(self):
"""Initializes the UI for selecting parking zone points in a tkinter window."""
check_requirements("tkinter")
import tkinter as tk # scope for multi-environment compatibility
self.tk = tk
self.master = tk.Tk()
self.master.title("Ultralytics Parking Zones Points Selector")
# Disable window resizing
self.master.resizable(False, False)
# Setup canvas for image display
self.canvas = self.tk.Canvas(self.master, bg="white")
# Setup buttons
button_frame = self.tk.Frame(self.master)
button_frame.pack(side=self.tk.TOP)
self.tk.Button(button_frame, text="Upload Image", command=self.upload_image).grid(row=0, column=0)
self.tk.Button(button_frame, text="Remove Last BBox", command=self.remove_last_bounding_box).grid(
row=0, column=1
)
self.tk.Button(button_frame, text="Save", command=self.save_to_json).grid(row=0, column=2)
# Initialize properties
self.image_path = None
self.image = None
self.canvas_image = None
self.rg_data = [] # region coordinates
self.current_box = []
self.imgw = 0 # image width
self.imgh = 0 # image height
# Constants
self.canvas_max_width = 1280
self.canvas_max_height = 720
self.master.mainloop()
def upload_image(self):
"""Upload an image and resize it to fit canvas."""
from tkinter import filedialog
from PIL import Image, ImageTk # scope because ImageTk requires tkinter package
self.image_path = filedialog.askopenfilename(filetypes=[("Image Files", "*.png;*.jpg;*.jpeg")])
if not self.image_path:
return
self.image = Image.open(self.image_path)
self.imgw, self.imgh = self.image.size
# Calculate the aspect ratio and resize image
aspect_ratio = self.imgw / self.imgh
if aspect_ratio > 1:
# Landscape orientation
canvas_width = min(self.canvas_max_width, self.imgw)
canvas_height = int(canvas_width / aspect_ratio)
else:
# Portrait orientation
canvas_height = min(self.canvas_max_height, self.imgh)
canvas_width = int(canvas_height * aspect_ratio)
# Check if canvas is already initialized
if self.canvas:
self.canvas.destroy() # Destroy previous canvas
self.canvas = self.tk.Canvas(self.master, bg="white", width=canvas_width, height=canvas_height)
resized_image = self.image.resize((canvas_width, canvas_height), Image.LANCZOS)
self.canvas_image = ImageTk.PhotoImage(resized_image)
self.canvas.create_image(0, 0, anchor=self.tk.NW, image=self.canvas_image)
self.canvas.pack(side=self.tk.BOTTOM)
self.canvas.bind("<Button-1>", self.on_canvas_click)
# Reset bounding boxes and current box
self.rg_data = []
self.current_box = []
def on_canvas_click(self, event):
"""Handle mouse clicks on canvas to create points for bounding boxes."""
self.current_box.append((event.x, event.y))
self.canvas.create_oval(event.x - 3, event.y - 3, event.x + 3, event.y + 3, fill="red")
if len(self.current_box) == 4:
self.rg_data.append(self.current_box)
[
self.canvas.create_line(self.current_box[i], self.current_box[(i + 1) % 4], fill="blue", width=2)
for i in range(4)
]
self.current_box = []
def remove_last_bounding_box(self):
"""Remove the last drawn bounding box from canvas."""
from tkinter import messagebox # scope for multi-environment compatibility
if self.rg_data:
self.rg_data.pop() # Remove the last bounding box
self.canvas.delete("all") # Clear the canvas
self.canvas.create_image(0, 0, anchor=self.tk.NW, image=self.canvas_image) # Redraw the image
# Redraw all bounding boxes
for box in self.rg_data:
[self.canvas.create_line(box[i], box[(i + 1) % 4], fill="blue", width=2) for i in range(4)]
messagebox.showinfo("Success", "Last bounding box removed.")
else:
messagebox.showwarning("Warning", "No bounding boxes to remove.")
def save_to_json(self):
"""Saves rescaled bounding boxes to 'bounding_boxes.json' based on image-to-canvas size ratio."""
from tkinter import messagebox # scope for multi-environment compatibility
rg_data = [] # regions data
for box in self.rg_data:
rs_box = [
(
int(x * self.imgw / self.canvas.winfo_width()), # width scaling
int(y * self.imgh / self.canvas.winfo_height()), # height scaling
)
for x, y in box
]
rg_data.append({"points": rs_box})
with open("bounding_boxes.json", "w") as f:
json.dump(rg_data, f, indent=4)
messagebox.showinfo("Success", "Bounding boxes saved to bounding_boxes.json")
class ParkingManagement:
"""Manages parking occupancy and availability using YOLOv8 for real-time monitoring and visualization."""
def __init__(
self,
model, # Ultralytics YOLO model file path
json_file, # Parking management annotation file created from Parking Annotator
occupied_region_color=(0, 0, 255), # occupied region color
available_region_color=(0, 255, 0), # available region color
):
"""
Initializes the parking management system with a YOLOv8 model and visualization settings.
Args:
model (str): Path to the YOLOv8 model.
json_file (str): file that have all parking slot points data
occupied_region_color (tuple): RGB color tuple for occupied regions.
available_region_color (tuple): RGB color tuple for available regions.
"""
# Model initialization
from ultralytics import YOLO
self.model = YOLO(model)
# Load JSON data
with open(json_file) as f:
self.json_data = json.load(f)
self.pr_info = {"Occupancy": 0, "Available": 0} # dictionary for parking information
self.occ = occupied_region_color
self.arc = available_region_color
self.env_check = check_imshow(warn=True) # check if environment supports imshow
def process_data(self, im0):
"""
Process the model data for parking lot management.
Args:
im0 (ndarray): inference image
"""
results = self.model.track(im0, persist=True, show=False) # object tracking
es, fs = len(self.json_data), 0 # empty slots, filled slots
annotator = Annotator(im0) # init annotator
# extract tracks data
if results[0].boxes.id is None:
self.display_frames(im0)
return im0
boxes = results[0].boxes.xyxy.cpu().tolist()
clss = results[0].boxes.cls.cpu().tolist()
for region in self.json_data:
# Convert points to a NumPy array with the correct dtype and reshape properly
pts_array = np.array(region["points"], dtype=np.int32).reshape((-1, 1, 2))
rg_occupied = False # occupied region initialization
for box, cls in zip(boxes, clss):
xc = int((box[0] + box[2]) / 2)
yc = int((box[1] + box[3]) / 2)
annotator.display_objects_labels(
im0, self.model.names[int(cls)], (104, 31, 17), (255, 255, 255), xc, yc, 10
)
dist = cv2.pointPolygonTest(pts_array, (xc, yc), False)
if dist >= 0:
rg_occupied = True
break
if rg_occupied:
fs += 1
es -= 1
# Plotting regions
color = self.occ if rg_occupied else self.arc
cv2.polylines(im0, [pts_array], isClosed=True, color=color, thickness=2)
self.pr_info["Occupancy"] = fs
self.pr_info["Available"] = es
annotator.display_analytics(im0, self.pr_info, (104, 31, 17), (255, 255, 255), 10)
self.display_frames(im0)
return im0
def display_frames(self, im0):
"""
Display frame.
Args:
im0 (ndarray): inference image
"""
if self.env_check:
cv2.imshow("Ultralytics Parking Manager", im0)
# Break Window
if cv2.waitKey(1) & 0xFF == ord("q"):
return