From 7402dc775eec9c36d4e0b35807b343f3edafa2f7 Mon Sep 17 00:00:00 2001 From: aolong Date: Mon, 5 May 2025 16:55:41 +0800 Subject: [PATCH] =?UTF-8?q?=E5=8A=A0=E5=85=A5=E5=88=AB=E4=BA=BA=E7=9A=84?= =?UTF-8?q?=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 21 +++- cs.py | 38 +++++++ data.py | 52 ++++++++++ navigate.py | 12 ++- test.py | 289 ++++++++++++++++++++++++++++++++++++++++++++++++++++ test2.py | 223 ++++++++++++++++++++++++++++++++++++++++ 6 files changed, 628 insertions(+), 7 deletions(-) create mode 100644 cs.py create mode 100644 data.py create mode 100644 test.py create mode 100644 test2.py diff --git a/README.md b/README.md index f7fa4da..751e0f9 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,23 @@ -# graduation-project - +# graduation-project + 题目:基于计算机视觉的停车场车位检测和预约系统 具体实现:1.拍摄学校地下停车场车位情况照片 2.构建停车场车位和道路情况地图 3.通过自己拍摄的图片把车位情况识别出来 4.识别的是否有车信息传给地图,在地图上显示出来是否有车。 -5.让用户选择个空车位,最后在地图上把导航路径画出来。 \ No newline at end of file +5.让用户选择个空车位,最后在地图上把导航路径画出来。 + +## TODO + +- 看懂他的代码,把他的底图换成我们制定的数据结构。/ 或者自己重新写。 +- 随机生成停车站状态,嵌入路径规划算法,实现交互。 + +## 导航算法 + +数据结构: +- 0:路 +- 1:车位入口 +- 2: +- 3:车位入口,有车了 +- 4: +- -1:其他区域 diff --git a/cs.py b/cs.py new file mode 100644 index 0000000..7916f73 --- /dev/null +++ b/cs.py @@ -0,0 +1,38 @@ +import os + +# 车位编号列表 +left_side = list(range(119, 132)) +right_side = list(range(99, 87, -1)) +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] + +# 合并所有编号列表,去掉 None +all_spots = [ + left_side, right_side, entry_left, entry_right, p_row1, + middle_bottom_row1, middle_top_row2, middle_bottom_row2, + middle_top_row3, middle_bottom_row3 +] + +all_numbers = [number for row in all_spots for number in row if number is not None] + +# 指定存放文件夹的根目录 +root_directory = "D:/car2/parking_folders" + +# 创建根目录(如果不存在) +if not os.path.exists(root_directory): + os.makedirs(root_directory) + +# 创建文件夹,确保文件夹名是三位数 +for number in all_numbers: + folder_name = str(number).zfill(3) # 将编号转换为三位数 + folder_path = os.path.join(root_directory, folder_name) + if not os.path.exists(folder_path): + os.makedirs(folder_path) + +print(f"已成功创建 {len(all_numbers)} 个文件夹。") diff --git a/data.py b/data.py new file mode 100644 index 0000000..6f423d9 --- /dev/null +++ b/data.py @@ -0,0 +1,52 @@ +import os +import random +import shutil + +# 车位编号列表 +left_side = list(range(119, 132)) +right_side = list(range(99, 87, -1)) +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] + +# 合并所有编号列表,去掉 None +all_spots = [ + left_side, right_side, entry_left, entry_right, p_row1, + middle_bottom_row1, middle_top_row2, middle_bottom_row2, + middle_top_row3, middle_bottom_row3 +] + +all_numbers = [number for row in all_spots for number in row if number is not None] + +# 指定存放文件夹的根目录 +root_directory = "D:/car2/parking_folders" +source_directory = "D:/car2/cs" # 图片文件夹 + +# 遍历所有车位编号 +for number in all_numbers: + folder_name = str(number).zfill(3) # 将编号转换为三位数 + folder_path = os.path.join(root_directory, folder_name) + + # 检查车位编号文件夹是否存在 + if os.path.exists(folder_path): + # 获取所有图片文件 + image_files = [f for f in os.listdir(source_directory) if f.lower().endswith(('.png', '.jpg', '.jpeg'))] + + if image_files: + # 随机选择一张图片 + selected_image = random.choice(image_files) + image_path = os.path.join(source_directory, selected_image) + + # 目标路径是车位编号对应的文件夹 + destination_path = os.path.join(folder_path, selected_image) + + # 将图片复制到对应的文件夹中 + shutil.copy(image_path, destination_path) + print(f"已将图片 {selected_image} 复制到 {folder_path} 文件夹。") + +print("图片已成功随机分配到车位文件夹。") diff --git a/navigate.py b/navigate.py index 27e755f..40aa7a6 100644 --- a/navigate.py +++ b/navigate.py @@ -52,14 +52,18 @@ def a_star(start, goal): if __name__ == "__main__": # 停车场状态矩阵 parking_lot = [ - [1, 1, 1, 0, 1, 1, 1], - [1, 1, 1, 0, 1, 1, 1], - [0, 0, 0, 0, 0, 0, 0] + [1, 1, 1, 0, 3, 2, 1], + [1, 1, 1, 0, 3, 1, 1], + [0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0], + [0, 1, 1, 1, 1, 1, 0], + [0, 2, 2, 2, 2, 2, 0], + [0, 0, 0, 0, 0, 0, 0], ] # 起点和终点(行, 列) start = (0, 3) - goal = (1, 1) + goal = (3, 5) # 执行 A* 路径搜索 path = a_star(start, goal) diff --git a/test.py b/test.py new file mode 100644 index 0000000..5e0d588 --- /dev/null +++ b/test.py @@ -0,0 +1,289 @@ +import tkinter as tk +from tkinter import messagebox +import random +import heapq +import os +import cv2 +import numpy as np + +# 停车场布局数据 +left_side = list(range(119, 132)) +right_side = list(range(99, 87, -1)) + +# 将右侧车位编号转换为三位数格式(例如:099, 098, ...) +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 + [00] + [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' # 搜索高亮颜色 + +# 设置 YOLO 检测结果路径 +detection_folder = r"D:\car2\parking_folders" + + +# A*算法的启发式函数 +def heuristic(a, b): + return abs(a[0] - b[0]) + abs(a[1] - b[1]) # 曼哈顿距离 + + +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.spots = {} # 存储车位信息 + self.path = [] # 存储路径 + self.obstacles = [] # 存储障碍物坐标 + self.draw_parking_lot() + + 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: + # 初始随机给状态 + status = random.choice(['free', 'occupied']) + self.spots[rect] = {'number': number, 'status': status} + 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), font=('Arial', 8)) + self.canvas.tag_bind(rect, '', self.toggle_spot) + # 按状态上色 + fill_color = status_color.get(status, default_color) + self.canvas.itemconfig(rect, fill=fill_color) + + # 添加障碍物坐标 + self.obstacles.append((current_x, start_y)) + + 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') + + # 获取车位编号对应的YOLO检测结果图像路径 + detection_image_path = os.path.join(detection_folder, f"{number}.jpg") # 假设图像以车位编号命名 + + # 检查文件是否存在 + if os.path.exists(detection_image_path): + # 读取 YOLO 检测结果图像(假设是红绿图像,红色表示有车,绿色表示空位) + detection_image = cv2.imread(detection_image_path) + + # 检查图片是否为空 + if detection_image is not None: + # 假设检测图像中左上角是车位的检测状态,我们可以检查该区域的颜色 + # 获取车位区域的颜色 + region_color = detection_image[10, 10] # 假设检测图像左上角有车位状态信息 + + # 判断颜色,红色表示有车,绿色表示空位 + if np.array_equal(region_color, [0, 0, 255]): # 红色 + status = 'occupied' + elif np.array_equal(region_color, [0, 255, 0]): # 绿色 + status = 'free' + else: + status = 'free' # 默认状态为免费 + else: + status = 'free' # 默认状态为免费,如果读取失败 + else: + status = 'free' # 默认状态为免费,如果没有检测结果 + + self.spots[rect] = {'number': number, 'status': status} + + # 绘制箭头 + self.draw_arrow(x, y, direction) + + # 绘制车位编号 + self.canvas.create_text(x + car_space_width / 2, y + car_space_height / 2, text=str(number), font=('Arial', 8)) + + # 绑定点击事件 + self.canvas.tag_bind(rect, '', self.toggle_spot) + + # 按状态设置颜色 + fill_color = status_color.get(status, default_color) + self.canvas.itemconfig(rect, fill=fill_color) + + def toggle_spot(self, event): + clicked = event.widget.find_withtag('current')[0] + spot = self.spots.get(clicked) + if spot: + messagebox.showinfo("车位信息", f"车位编号: {spot['number']}\n状态: {spot['status']}") + + def search_spot(self): + query = self.search_entry.get() + found = False + for rect, spot in self.spots.items(): + if str(spot['number']) == query: + self.canvas.itemconfig(rect, fill=selected_color) + self.find_path(rect) + found = True + else: + # 恢复成状态颜色 + self.canvas.itemconfig(rect, fill=status_color.get(spot['status'], default_color)) + + if not found: + messagebox.showwarning("提示", "未找到该车位编号!") + + def find_path(self, target_rect): + target_coords = self.canvas.coords(target_rect) + start_coords = (canvas_width // 2, 0) # 入口位置 + + # A*路径规划的实现,避免车位区域 + path = self.a_star(start_coords, target_coords) + + # 绘制路径 + for i in range(len(path) - 1): + self.canvas.create_line(path[i][0], path[i][1], path[i + 1][0], path[i + 1][1], fill="blue", width=4, + arrow=tk.LAST) + + def a_star(self, start, end): + open_list = [] + closed_list = set() + came_from = {} + + start_node = (start[0], start[1]) + end_node = (end[0], end[1]) + + # 计算G、H、F值 + def g_cost(node): + return abs(node[0] - start[0]) + abs(node[1] - start[1]) + + def h_cost(node): + return heuristic(node, end_node) + + def f_cost(node): + return g_cost(node) + h_cost(node) + + heapq.heappush(open_list, (f_cost(start_node), start_node)) + came_from[start_node] = None + + while open_list: + current_f, current_node = heapq.heappop(open_list) + if current_node == end_node: + path = [] + while current_node: + path.append(current_node) + current_node = came_from[current_node] + return path[::-1] + + closed_list.add(current_node) + + for direction in [(0, -car_space_height - 5), (0, car_space_height + 5), (-car_space_width - 5, 0), + (car_space_width + 5, 0)]: + neighbor = (current_node[0] + direction[0], current_node[1] + direction[1]) + + # Check if the neighbor is within bounds and not an obstacle + if 0 <= neighbor[0] < canvas_width and 0 <= neighbor[1] < canvas_height: + if self.is_obstacle(neighbor) or neighbor in closed_list: + continue + + heapq.heappush(open_list, (f_cost(neighbor), neighbor)) + came_from[neighbor] = current_node + + return [] # No path found + + def is_obstacle(self, coords): + # 判断当前位置是否为车位(障碍物) + for (x, y) in self.obstacles: + if x <= coords[0] <= x + car_space_width and y <= coords[1] <= y + car_space_height: + return True + return False + + +if __name__ == "__main__": + app = ParkingLot() + app.mainloop() diff --git a/test2.py b/test2.py new file mode 100644 index 0000000..0ae7bad --- /dev/null +++ b/test2.py @@ -0,0 +1,223 @@ +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()