import tkinter as tk from tkinter import messagebox import os from ultralytics import YOLO # 停车场布局数据 left_side = list(range(119, 132)) right_side = list(range(99, 87, -1)) right_side = [str(number).zfill(3) for number in right_side] entry_left = [117, 115, 113] entry_right = [108, 106, 104, 102, 101, 100] p_row1 = [118, 116, 114, 112, 111, 110, None, 109, 107, 105, 103] middle_bottom_row1 = [292, 290, 288, 286, 284, 282, 280, 278, 276, 274, 272] middle_top_row2 = [293, 291, 289, 287, 285, 283, 281, 279, 277, 275, 273, 271] middle_bottom_row2 = list(range(259, 271)) middle_top_row3 = [None] * 10 + [0] + [None] middle_bottom_row3 = [258, 257, 256, None, None, None, None, None, None, 255, 254, None] # 样式参数 car_space_width = 50 car_space_height = 80 road_width = 40 canvas_width = 1200 canvas_height = 900 middle_area_offset_y = 100 status_color = { 'free': 'lightgreen', 'occupied': 'tomato', } default_color = 'white' selected_color = 'cyan' path_color = 'yellow' MODEL_PATH = r"D:\\car2\\runs\\citrus_auto_detection_20250428-104743\\citrus_model\\weights\\best.pt" PARKING_FOLDER = r"D:\\car2\\parking_folders" model = YOLO(MODEL_PATH) class ParkingLot(tk.Tk): def __init__(self): super().__init__() self.title("停车场平面图 🚗") self.geometry(f"{canvas_width}x{canvas_height}") self.canvas = tk.Canvas(self, width=canvas_width, height=canvas_height, bg='#CCCCCC') self.canvas.pack() self.search_entry = tk.Entry(self) self.search_entry.pack(pady=5) self.search_button = tk.Button(self, text="搜索车位", command=self.search_spot) self.search_button.pack(pady=5) self.nav_button = tk.Button(self, text="导航到车位", command=self.navigate_to_spot) self.nav_button.pack(pady=5) self.refresh_button = tk.Button(self, text="刷新车位状态", command=self.refresh_all_status) self.refresh_button.pack(pady=5) self.spots = {} self.draw_parking_lot() # 绑定空格键刷新 self.bind('', lambda event: self.refresh_all_status()) def draw_parking_lot(self): self.canvas.create_rectangle(400, 0, 800, road_width, fill='gray') self.canvas.create_text(750, 20, text="入口", fill="red", font=('Arial', 16)) for idx, number in enumerate(entry_left): x = 400 - (idx + 1) * (car_space_width + 5) y = 0 self.draw_parking_spot(x, y, number, direction='down') for idx, number in enumerate(entry_right): x = 800 + idx * (car_space_width + 5) y = 0 self.draw_parking_spot(x, y, number, direction='down') for idx, number in enumerate(left_side): x = 0 y = road_width + idx * (car_space_height + 5) self.draw_parking_spot(x, y, number, direction='right') for idx, number in enumerate(right_side): x = canvas_width - 50 y = road_width + idx * (car_space_height + 5) self.draw_parking_spot(x, y, number, direction='left') start_y = road_width + 20 + middle_area_offset_y self.draw_middle_row(start_y, p_row1, up=True) self.draw_middle_row(start_y + car_space_height + 5, middle_bottom_row1, up=False) start_y += (car_space_height + 5) * 2 + road_width self.draw_middle_row(start_y, middle_top_row2, up=True) self.draw_middle_row(start_y + car_space_height + 5, middle_bottom_row2, up=False) start_y += (car_space_height + 5) * 2 + road_width self.draw_middle_row(start_y, middle_top_row3, up=True) self.draw_middle_row(start_y + car_space_height + 5, middle_bottom_row3, up=False) def draw_middle_row(self, start_y, row_data, up=True): total_spots = len(row_data) row_width = total_spots * (car_space_width + 5) - 5 start_x = (canvas_width - row_width) / 2 current_x = start_x for number in row_data: rect = self.canvas.create_rectangle( current_x, start_y, current_x + car_space_width, start_y + car_space_height, fill=default_color, outline='black' ) if number is not None: self.spots[rect] = {'number': number, 'status': 'unknown'} self.draw_arrow(current_x, start_y, 'up' if up else 'down') self.canvas.create_text(current_x + car_space_width / 2, start_y + car_space_height / 2, text=str(number).zfill(3), font=('Arial', 8)) self.canvas.tag_bind(rect, '', self.toggle_spot) current_x += car_space_width + 5 def draw_arrow(self, x, y, direction): if direction == 'up': points = [x + car_space_width / 2, y + 10, x + 10, y + 30, x + car_space_width - 10, y + 30] elif direction == 'down': points = [x + car_space_width / 2, y + car_space_height - 10, x + 10, y + car_space_height - 30, x + car_space_width - 10, y + car_space_height - 30] elif direction == 'left': points = [x + 10, y + car_space_height / 2, x + 30, y + 10, x + 30, y + car_space_height - 10] else: points = [x + car_space_width - 10, y + car_space_height / 2, x + car_space_width - 30, y + 10, x + car_space_width - 30, y + car_space_height - 10] self.canvas.create_polygon(points, fill='black') def draw_parking_spot(self, x, y, number, direction='up'): rect = self.canvas.create_rectangle(x, y, x + car_space_width, y + car_space_height, fill=default_color, outline='black') self.spots[rect] = {'number': number, 'status': 'unknown'} self.draw_arrow(x, y, direction) self.canvas.create_text(x + car_space_width / 2, y + car_space_height / 2, text=str(number).zfill(3), font=('Arial', 8)) self.canvas.tag_bind(rect, '', self.toggle_spot) def refresh_all_status(self): for rect, spot in self.spots.items(): number = spot['number'] if number is None: continue new_status = self.detect_parking_status(number) spot['status'] = new_status self.canvas.itemconfig(rect, fill=status_color.get(new_status, default_color)) messagebox.showinfo("提示", "所有车位状态已刷新!") def detect_parking_status(self, number): folder_name = str(number).zfill(3) folder_path = os.path.join(PARKING_FOLDER, folder_name) if not os.path.isdir(folder_path): return 'free' images = [f for f in os.listdir(folder_path) if f.lower().endswith('.jpg')] if not images: return 'free' image_path = os.path.join(folder_path, sorted(images)[-1]) try: results = model(image_path) for result in results: if len(result.boxes) > 0: return 'occupied' except Exception as e: print(f"检测{number}出错: {e}") return 'free' def toggle_spot(self, event): clicked = event.widget.find_withtag('current')[0] spot = self.spots.get(clicked) if spot: messagebox.showinfo("车位信息", f"车位编号: {str(spot['number']).zfill(3)}\n状态: {spot['status']}") def search_spot(self): query = self.search_entry.get().zfill(3) found = False for rect, spot in self.spots.items(): spot_number = str(spot['number']).zfill(3) if spot_number == query: self.canvas.itemconfig(rect, fill=selected_color) found = True else: self.canvas.itemconfig(rect, fill=status_color.get(spot['status'], default_color)) if not found: messagebox.showwarning("提示", "未找到该车位编号!") def navigate_to_spot(self): query = self.search_entry.get().zfill(3) found = False for rect, spot in self.spots.items(): spot_number = str(spot['number']).zfill(3) if spot_number == query: self.canvas.itemconfig(rect, fill=selected_color) found = True else: if spot['number'] is not None and spot_number[0] == query[0]: self.canvas.itemconfig(rect, fill=path_color) else: self.canvas.itemconfig(rect, fill=status_color.get(spot['status'], default_color)) if not found: messagebox.showwarning("提示", "未找到该车位编号!") if __name__ == "__main__": app = ParkingLot() app.mainloop()