graduation-project/test.py
2025-05-05 16:55:41 +08:00

290 lines
11 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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, '<Button-1>', 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, '<Button-1>', 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()