python利用百度文字识别功能,实现小区车辆进出识别,并显示进出信息和收费信息;可查看停车信息,也可查看历史数据;
开发环境:Windows+python.+pycharm..(开发工具);
目录机构:
最终效果:由于涉及隐私,不能上传动态效果;左边为摄像头的画面(这里是视频播放页面),右上角显示车位情况和最近十条车辆信息,右下角显示识别信息、收费信息或提示信息;
创建过程参考《微信小程序利用百度AI实现扫描身份证获取信息功能》(把“图像识别”换为“文字识别”)。
、文件“settings.py”用来设置该程序的基础信息;
class Settings(): def __init__(self): """ 初始化设置 """ # 屏幕设置(宽、高、背景色、线颜色) self.screen_width = self.screen_height = self.bg_color = (, , ) # 停车位 self.total = # 识别颜色、车牌号、进来时间、出入场信息 self.ocr_color = (, , ) self.carnumber = self.comeInTime = self.message =
、文件“timeutil.py”有两个函数:
函数time_cmp主要用来比较出场时间跟卡有效期,判断业主是否需要收费;
函数priceCalc用来计算停车时间,里面存在两种情况,一种是外来车,只需要比较出入场时间差;另一种是业主车,入场时,卡未到期,但出场时间已经到期,所以需要比较卡有效期和出场时间的差值;
Tips:由于读取Excel的卡有效期字段,会多“.xxxx”这部分,所以需要经过split(.)处理。
import datetimeimport math# 计算两个日期大小def time_cmp(first_time, second_time): # 由于有效期获取后会有小数数据 firstTime = datetime.datetime.strptime(str(first_time).split(.)[], "%Y-%m-%d %H:%M:%S") secondTime = datetime.datetime.strptime(str(second_time), "%Y-%m-%d %H:%M") number = if firstTime > secondTime else return number# 计算停车时间四舍五入def priceCalc(inDate, outDate): if . in str(inDate): inDate = str(inDate).split(.)[] inDate = datetime.datetime.strptime(inDate, "%Y-%m-%d %H:%M:%S") print(特殊处理) else: inDate = datetime.datetime.strptime(inDate, "%Y-%m-%d %H:%M") outDate = datetime.datetime.strptime(str(outDate), "%Y-%m-%d %H:%M") rtn = outDate - inDate # 计算停车多少小时(往上取整) y = math.ceil(rtn.total_seconds() / / ) return y
、文件“button.py”用来绘制按钮,这里用来绘制“识别”按钮;
import pygame.fontclass Button(): def __init__(self, screen, msg): """初始化按钮的属性""" self.screen = screen self.screen_rect = screen.get_rect() # 设置按钮的尺寸和其他属性 self.width, self.height = , self.button_color = (, , ) self.text_color = (, , ) self.font = pygame.font.SysFont(SimHei, ) # 创建按钮的rect对象,并使其居中 self.rect = pygame.Rect(, , self.width, self.height) # 创建按钮的rect对象,并设置按钮中心位置 self.rect.centerx = - self.width / + self.rect.centery = - self.height / + # 按钮的标签只需创建一次 self.prep_msg(msg) def prep_msg(self, msg): """将msg渲染为图像,并使其在按钮上居中""" self.msg_image = self.font.render(msg, True, self.text_color, self.button_color) self.msg_image_rect = self.msg_image.get_rect() self.msg_image_rect.center = self.rect.center def draw_button(self): # 绘制一个用颜色填充的按钮,再绘制文本 self.screen.fill(self.button_color, self.rect) self.screen.blit(self.msg_image, self.msg_image_rect)
、文件“textboard.py”用来绘制背景和文字;
import pygame.font# 线颜色line_color = (, , )# 显示文字信息时使用的字体设置text_color = (, , )def draw_bg(screen): # 背景文图案 bgfont = pygame.font.SysFont(SimHei, ) # 绘制横线 pygame.draw.aaline(screen, line_color, (, ), (, ), ) # 渲染为图片 text_image = bgfont.render(识别信息:, True, text_color) # 获取文字图像位置 text_rect = text_image.get_rect() # 设置文字图像中心点 text_rect.left = text_rect.top = # 绘制内容 screen.blit(text_image, text_rect)# 绘制文字(text-文字内容、xpos-x坐标、ypos-y坐标、fontSize-字体大小)def draw_text(screen, text, xpos, ypos, fontsize, tc=text_color): # 使用系统字体 xtfont = pygame.font.SysFont(SimHei, fontsize) text_image = xtfont.render(text, True, tc) # 获取文字图像位置 text_rect = text_image.get_rect() # 设置文字图像中心点 text_rect.left = xpos text_rect.top = ypos # 绘制内容 screen.blit(text_image, text_rect)
、文件“ocrutil.py”用来调用百度文字识别SDK,获取图片中的车牌信息;
Tips:文件“test.jpg”为从摄像头读取的图片,每次循环获取一次,这里为了测试方便使用视频;
from aip import AipOcrimport os# 百度识别车牌# 申请地址 https://login.bce.baidu.com/filename = file/key.txt # 记录申请的Key的文件位置if os.path.exists(filename): # 判断文件是否存在 with open(filename, "r") as file: # 打开文件 dictkey = eval(file.readlines()[]) # 读取全部内容转换为字典 # 以下获取的三个Key是进入百度AI开放平台的控制台的应用列表里创建应用得来的 APP_ID = dictkey[APP_ID] # 获取申请的APIID API_KEY = dictkey[API_KEY] # 获取申请的APIKEY SECRET_KEY = dictkey[SECRET_KEY] # 获取申请的SECRETKEYelse: print("请先在file目录下创建key.txt,并且写入申请的Key!格式如下:" " {APP_ID:申请的APIID, API_KEY:申请的APIKEY, SECRET_KEY:申请的SECRETKEY}")# 初始化AipOcr对象client = AipOcr(APP_ID, API_KEY, SECRET_KEY)# 读取文件def get_file_content(filePath): with open(filePath, rb) as fp: return fp.read()# 根据图片返回车牌号def getcn(): # 读取图片 image = get_file_content(images/test.jpg) # 调用车牌识别 results = client.licensePlate(image)[words_result][number] # 输出车牌号 return results
、文件“procedure_functions.py”存放跟程序相关的业务逻辑函数;
里面比较复杂的就是点击“识别”按钮后的逻辑处理(event.type == pygame.MOUSEBUTTONDOWN):
)当停车场没有停车时,只需要识别后,把车辆信息存入“停车场车辆表”并把相关信息显示到界面右下角;
)当停车场已有停车时,会出现两种情况,一种是入场,一种是出场:
入场需判断是否停车场已满,已满则不给进入并显示提示信息;未满则把车辆信息存入“停车场车辆表”并把相关信息显示到界面右下角;
出场分业主有效、业主过期、外来车三种情况收费,并删除车辆表相应的车辆信息,并把车辆信息和收费信息等存入“停车场历史表”(可用于后面数据的汇总统计);
import sysimport pygameimport timeimport pandas as pdimport ocrutilimport timeutil# 事件def check_events(settings, recognition_button, ownerInfo_table, carInfo_table, history_table, path): """ 响应按键和鼠标事件 """ for event in pygame.event.get(): if event.type == pygame.QUIT: sys.exit() elif event.type == pygame.MOUSEBUTTONDOWN: mouse_x, mouse_y = pygame.mouse.get_pos() button_clicked = recognition_button.rect.collidepoint(mouse_x, mouse_y) if button_clicked: try: # 获取车牌 carnumber = ocrutil.getcn() # 转换当前时间 -- : localtime = time.strftime(%Y-%m-%d %H:%M, time.localtime()) settings.carnumber = 车牌号码: + carnumber # 判断进入车辆是否业主车辆 # 获取业主车辆信息(只显示卡未过期) ownerInfo_table = ownerInfo_table[ownerInfo_table[validityDate] > localtime] owner_carnumbers = ownerInfo_table[[carnumber, validityDate]].values carnumbers = ownerInfo_table[carnumber].values # 获取车辆表信息 carInfo_carnumbers = carInfo_table[[carnumber, inDate, isOwner, validityDate]].values cars = carInfo_table[carnumber].values # 增加车辆信息 append_carInfo = { carnumber: carnumber } # 增加历史信息 append_history = { carnumber: carnumber } carInfo_length = len(carInfo_carnumbers) # 车辆表未有数据 if carInfo_length == : print(未有车辆数据入场) in_park(owner_carnumbers, carnumbers, carInfo_table, append_carInfo, carnumber, localtime, settings, path) # 车辆表有数据 else: if carnumber in cars: # 出停车场 i = for carInfo_carnumber in carInfo_carnumbers: if carnumber == carInfo_carnumber[]: if carInfo_carnumber[] == : if timeutil.time_cmp(carInfo_carnumber[], localtime): print(业主车,自动抬杠) msgMessage = 业主车,可出停车场 parkPrice = 业主卡 else: print(业主车,但卡已过期,收费抬杠) # 比较卡有效期时间 price = timeutil.priceCalc(carInfo_carnumber[], localtime) msgMessage = 停车费用: + str( * int(price)) + (提醒业主,卡已到期) parkPrice = * int(price) else: print(外来车,收费抬杠) # 比较入场时间 price = timeutil.priceCalc(carInfo_carnumber[], localtime) msgMessage = 停车费用: + str( * price) parkPrice = * int(price) print(i) carInfo_table = carInfo_table.drop([i]) # 增加数据到历史表 append_history[inDate] = carInfo_carnumber[] append_history[outData] = localtime append_history[price] = parkPrice append_history[isOwner] = carInfo_carnumber[] append_history[validityDate] = carInfo_carnumber[] history_table = history_table.append(append_history, ignore_index=True) settings.comeInTime = 出场时间: + localtime settings.message = msgMessage # 更新车辆表和历史表 pd.DataFrame(carInfo_table).to_excel(path + 停车场车辆表 + .xlsx, sheet_name=data, index=False, header=True) pd.DataFrame(history_table).to_excel(path + 停车场历史表 + .xlsx, sheet_name=data, index=False, header=True) break i += else: # 入停车场 print(有车辆表数据入场) if carInfo_length < settings.total: in_park(owner_carnumbers, carnumbers, carInfo_table, append_carInfo, carnumber, localtime, settings, path) else: print(停车场已满) settings.comeInTime = 进场时间: + localtime settings.message = 停车场已满,无法进入 except Exception as e: print("错误原因:", e) continue pass# 车辆入停车场def in_park(owner_carnumbers, carnumbers, carInfo_table, append_carInfo, carnumber, localtime, settings, path): if carnumber in carnumbers: for owner_carnumber in owner_carnumbers: if carnumber == owner_carnumber[]: print(业主车,自动抬杠) msgMessage = 提示信息:业主车,可入停车场 append_carInfo[isOwner] = append_carInfo[validityDate] = owner_carnumber[] # 退出循环 break else: print(外来车,识别抬杠) msgMessage = 提示信息:外来车,可入停车场 append_carInfo[isOwner] = append_carInfo[inDate] = localtime settings.comeInTime = 进场时间: + localtime settings.message = msgMessage # 添加信息到车辆表 carInfo_table = carInfo_table.append(append_carInfo, ignore_index=True) # 更新车辆表 pd.DataFrame(carInfo_table).to_excel(path + 停车场车辆表 + .xlsx, sheet_name=data, index=False, header=True)
、文件“main.py”为程序的主函数,用来初始化程序,并同步更新程序的信息。
import pygameimport cvimport osimport pandas as pd# 引入自定义模块from settings import Settingsfrom button import Buttonimport textboardimport procedure_functions as pfdef run_procedure(): # 获取文件的路径 cdir = os.getcwd() # 文件夹路径 path = cdir + /file/ # 读取路径 if not os.path.exists(path + 停车场车辆表 + .xlsx): # 车牌号 进入时间 离开时间 价格 是否业主 carnfile = pd.DataFrame(columns=[carnumber, inDate, outData, price, isOwner, validityDate]) # 生成xlsx文件 carnfile.to_excel(path + 停车场车辆表 + .xlsx, sheet_name=data) carnfile.to_excel(path + 停车场历史表 + .xlsx, sheet_name=data) settings = Settings() # 初始化并创建一个屏幕对象 pygame.init() pygame.display.set_caption(智能小区车牌识别系统) ic_launcher = pygame.image.load(images/icon_launcher.png) pygame.display.set_icon(ic_launcher) screen = pygame.display.set_mode((settings.screen_width, settings.screen_height)) try: # cam = cv.VideoCapture() # 开启摄像头 cam = cv.VideoCapture(file/test.mp) except: print(请连接摄像头) # 循环帧率设置 clock = pygame.time.Clock() running = True # 开始主循环 while running: screen.fill(settings.bg_color) # 从摄像头读取图片 sucess, img = cam.read() # 保存图片,并退出。 if sucess: cv.imwrite(images/test.jpg, img) else: # 识别不到图片或者设备停止,则退出系统 running = False # 加载图像 image = pygame.image.load(images/test.jpg) # 设置图片大小 image = pygame.transform.scale(image, (, )) # 绘制视频画面 screen.blit(image, (, )) # 创建识别按钮 recognition_button = Button(screen, 识别) recognition_button.draw_button() # 读取文件内容 ownerInfo_table = pd.read_excel(path + 住户车辆表.xlsx, sheet_name=data) carInfo_table = pd.read_excel(path + 停车场车辆表.xlsx, sheet_name=data) history_table = pd.read_excel(path + 停车场历史表.xlsx, sheet_name=data) inNumber = len(carInfo_table[carnumber].values) # 绘制背景 textboard.draw_bg(screen) # 绘制信息标题 textboard.draw_text(screen, 共有车位: + str(settings.total) + 剩余车位: + str(settings.total - inNumber), , , ) # 绘制信息表头 textboard.draw_text(screen, 车牌号 进入时间, , , ) # 绘制停车场车辆前十条信息 carInfos = carInfo_table.sort_values(by=inDate, ascending=False) i = for carInfo in carInfos.values: if i >= : break i += textboard.draw_text(screen, str(carInfo[])+ +str(carInfo[]), , + i * , ) # 绘制识别信息 textboard.draw_text(screen, settings.carnumber, , , , settings.ocr_color) textboard.draw_text(screen, settings.comeInTime, , , , settings.ocr_color) textboard.draw_text(screen, settings.message, , , , settings.ocr_color) """ 响应鼠标事件 """ pf.check_events(settings, recognition_button, ownerInfo_table, carInfo_table, history_table, path) pygame.display.flip() # 控制游戏最大帧率为 clock.tick() # 关闭摄像头 cam.release()run_procedure()