|
| 1 | +# -*- coding:utf-8 -*- |
| 2 | +# author: DuanshengLiu |
| 3 | +import cv2 |
| 4 | +import numpy as np |
| 5 | +from tkinter import * |
| 6 | +from tkinter.filedialog import askopenfilename |
| 7 | +from PIL import Image, ImageTk |
| 8 | +from tensorflow import keras |
| 9 | +from core import locate_and_correct |
| 10 | +from Unet import unet_predict |
| 11 | +from CNN import cnn_predict |
| 12 | + |
| 13 | + |
| 14 | +class Window: |
| 15 | + def __init__(self, win, ww, wh): |
| 16 | + self.win = win |
| 17 | + self.ww = ww |
| 18 | + self.wh = wh |
| 19 | + self.win.geometry("%dx%d+%d+%d" % (ww, wh, 200, 50)) # 界面启动时的初始位置 |
| 20 | + self.win.title("车牌定位,矫正和识别软件---by DuanshengLiu") |
| 21 | + self.img_src_path = None |
| 22 | + |
| 23 | + self.label_src = Label(self.win, text='原图:', font=('微软雅黑', 13)).place(x=0, y=0) |
| 24 | + self.label_lic1 = Label(self.win, text='车牌区域1:', font=('微软雅黑', 13)).place(x=615, y=0) |
| 25 | + self.label_pred1 = Label(self.win, text='识别结果1:', font=('微软雅黑', 13)).place(x=615, y=85) |
| 26 | + self.label_lic2 = Label(self.win, text='车牌区域2:', font=('微软雅黑', 13)).place(x=615, y=180) |
| 27 | + self.label_pred2 = Label(self.win, text='识别结果2:', font=('微软雅黑', 13)).place(x=615, y=265) |
| 28 | + self.label_lic3 = Label(self.win, text='车牌区域3:', font=('微软雅黑', 13)).place(x=615, y=360) |
| 29 | + self.label_pred3 = Label(self.win, text='识别结果3:', font=('微软雅黑', 13)).place(x=615, y=445) |
| 30 | + |
| 31 | + self.can_src = Canvas(self.win, width=512, height=512, bg='white', relief='solid', borderwidth=1) # 原图画布 |
| 32 | + self.can_src.place(x=50, y=0) |
| 33 | + self.can_lic1 = Canvas(self.win, width=245, height=85, bg='white', relief='solid', borderwidth=1) # 车牌区域1画布 |
| 34 | + self.can_lic1.place(x=710, y=0) |
| 35 | + self.can_pred1 = Canvas(self.win, width=245, height=65, bg='white', relief='solid', borderwidth=1) # 车牌识别1画布 |
| 36 | + self.can_pred1.place(x=710, y=90) |
| 37 | + self.can_lic2 = Canvas(self.win, width=245, height=85, bg='white', relief='solid', borderwidth=1) # 车牌区域2画布 |
| 38 | + self.can_lic2.place(x=710, y=175) |
| 39 | + self.can_pred2 = Canvas(self.win, width=245, height=65, bg='white', relief='solid', borderwidth=1) # 车牌识别2画布 |
| 40 | + self.can_pred2.place(x=710, y=265) |
| 41 | + self.can_lic3 = Canvas(self.win, width=245, height=85, bg='white', relief='solid', borderwidth=1) # 车牌区域3画布 |
| 42 | + self.can_lic3.place(x=710, y=350) |
| 43 | + self.can_pred3 = Canvas(self.win, width=245, height=65, bg='white', relief='solid', borderwidth=1) # 车牌识别3画布 |
| 44 | + self.can_pred3.place(x=710, y=440) |
| 45 | + |
| 46 | + self.button1 = Button(self.win, text='选择文件', width=10, height=1, command=self.load_show_img) # 选择文件按钮 |
| 47 | + self.button1.place(x=680, y=wh - 30) |
| 48 | + self.button2 = Button(self.win, text='识别车牌', width=10, height=1, command=self.display) # 识别车牌按钮 |
| 49 | + self.button2.place(x=780, y=wh - 30) |
| 50 | + self.button3 = Button(self.win, text='清空所有', width=10, height=1, command=self.clear) # 清空所有按钮 |
| 51 | + self.button3.place(x=880, y=wh - 30) |
| 52 | + self.unet = keras.models.load_model('unet.h5') |
| 53 | + self.cnn = keras.models.load_model('cnn.h5') |
| 54 | + print('正在启动中,请稍等...') |
| 55 | + cnn_predict(self.cnn, [np.zeros((80, 240, 3))]) |
| 56 | + print("已启动,开始识别吧!") |
| 57 | + |
| 58 | + |
| 59 | + def load_show_img(self): |
| 60 | + self.clear() |
| 61 | + sv = StringVar() |
| 62 | + sv.set(askopenfilename()) |
| 63 | + self.img_src_path = Entry(self.win, state='readonly', text=sv).get() # 获取到所打开的图片 |
| 64 | + img_open = Image.open(self.img_src_path) |
| 65 | + if img_open.size[0] * img_open.size[1] > 240 * 80: |
| 66 | + img_open = img_open.resize((512, 512), Image.ANTIALIAS) |
| 67 | + self.img_Tk = ImageTk.PhotoImage(img_open) |
| 68 | + self.can_src.create_image(258, 258, image=self.img_Tk, anchor='center') |
| 69 | + |
| 70 | + def display(self): |
| 71 | + if self.img_src_path == None: # 还没选择图片就进行预测 |
| 72 | + self.can_pred1.create_text(32, 15, text='请选择图片', anchor='nw', font=('黑体', 28)) |
| 73 | + else: |
| 74 | + img_src = cv2.imdecode(np.fromfile(self.img_src_path, dtype=np.uint8), -1) # 从中文路径读取时用 |
| 75 | + h, w = img_src.shape[0], img_src.shape[1] |
| 76 | + if h * w <= 240 * 80 and 2 <= w / h <= 5: # 满足该条件说明可能整个图片就是一张车牌,无需定位,直接识别即可 |
| 77 | + lic = cv2.resize(img_src, dsize=(240, 80), interpolation=cv2.INTER_AREA)[:, :, :3] # 直接resize为(240,80) |
| 78 | + img_src_copy, Lic_img = img_src, [lic] |
| 79 | + else: # 否则就需通过unet对img_src原图预测,得到img_mask,实现车牌定位,然后进行识别 |
| 80 | + img_src, img_mask = unet_predict(self.unet, self.img_src_path) |
| 81 | + img_src_copy, Lic_img = locate_and_correct(img_src, img_mask) # 利用core.py中的locate_and_correct函数进行车牌定位和矫正 |
| 82 | + |
| 83 | + Lic_pred = cnn_predict(self.cnn, Lic_img) # 利用cnn进行车牌的识别预测,Lic_pred中存的是元祖(车牌图片,识别结果) |
| 84 | + if Lic_pred: |
| 85 | + img = Image.fromarray(img_src_copy[:, :, ::-1]) # img_src_copy[:, :, ::-1]将BGR转为RGB |
| 86 | + self.img_Tk = ImageTk.PhotoImage(img) |
| 87 | + self.can_src.delete('all') # 显示前,先清空画板 |
| 88 | + self.can_src.create_image(258, 258, image=self.img_Tk, |
| 89 | + anchor='center') # img_src_copy上绘制出了定位的车牌轮廓,将其显示在画板上 |
| 90 | + for i, lic_pred in enumerate(Lic_pred): |
| 91 | + if i == 0: |
| 92 | + self.lic_Tk1 = ImageTk.PhotoImage(Image.fromarray(lic_pred[0][:, :, ::-1])) |
| 93 | + self.can_lic1.create_image(5, 5, image=self.lic_Tk1, anchor='nw') |
| 94 | + self.can_pred1.create_text(35, 15, text=lic_pred[1], anchor='nw', font=('黑体', 28)) |
| 95 | + elif i == 1: |
| 96 | + self.lic_Tk2 = ImageTk.PhotoImage(Image.fromarray(lic_pred[0][:, :, ::-1])) |
| 97 | + self.can_lic2.create_image(5, 5, image=self.lic_Tk2, anchor='nw') |
| 98 | + self.can_pred2.create_text(40, 15, text=lic_pred[1], anchor='nw', font=('黑体', 28)) |
| 99 | + elif i == 2: |
| 100 | + self.lic_Tk3 = ImageTk.PhotoImage(Image.fromarray(lic_pred[0][:, :, ::-1])) |
| 101 | + self.can_lic3.create_image(5, 5, image=self.lic_Tk3, anchor='nw') |
| 102 | + self.can_pred3.create_text(40, 15, text=lic_pred[1], anchor='nw', font=('黑体', 28)) |
| 103 | + |
| 104 | + else: # Lic_pred为空说明未能识别 |
| 105 | + self.can_pred1.create_text(47, 15, text='未能识别', anchor='nw', font=('黑体', 27)) |
| 106 | + |
| 107 | + def clear(self): |
| 108 | + self.can_src.delete('all') |
| 109 | + self.can_lic1.delete('all') |
| 110 | + self.can_lic2.delete('all') |
| 111 | + self.can_lic3.delete('all') |
| 112 | + self.can_pred1.delete('all') |
| 113 | + self.can_pred2.delete('all') |
| 114 | + self.can_pred3.delete('all') |
| 115 | + self.img_src_path = None |
| 116 | + |
| 117 | + def closeEvent(): # 关闭前清除session(),防止'NoneType' object is not callable |
| 118 | + keras.backend.clear_session() |
| 119 | + sys.exit() |
| 120 | + |
| 121 | + |
| 122 | +if __name__ == '__main__': |
| 123 | + win = Tk() |
| 124 | + ww = 1000 # 窗口宽设定1000 |
| 125 | + wh = 600 # 窗口高设定600 |
| 126 | + Window(win, ww, wh) |
| 127 | + win.protocol("WM_DELETE_WINDOW", Window.closeEvent) |
| 128 | + win.mainloop() |
0 commit comments