diff --git a/main(final).py b/main(final).py new file mode 100644 index 0000000..82acdfd --- /dev/null +++ b/main(final).py @@ -0,0 +1,331 @@ +import numpy as np +import cv2 +import matplotlib.pyplot as plt +from matplotlib import font_manager +import ddddocr +import threadsafe_tkinter as tk +from tkinter import filedialog +font_path = "C:/Users/Lenovo/Downloads/OPPOSans3.0/OPPOSans-Regular.ttf" + +# 动态添加字体到 matplotlib 的字体列表 +font = font_manager.FontProperties(fname=font_path) + + + + +class Get_license(): + + #图像拉伸函数 + def stretch(self, img): + + maxi = float(img.max()) + mini = float(img.min()) + + for i in range(img.shape[0]): + for j in range(img.shape[1]): + img[i, j] = (255 / (maxi - mini) * img[i, j] - (255 * mini) / (maxi - mini)) + + return img + + #二值化处理函数 + def dobinaryzation(self, img): + # 使用OpenCV的自动阈值方法 + ret, thresh = cv2.threshold(img, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU) + return thresh + + #寻找矩形的轮廓 + def find_rectangle(self, contour): + + y, x = [],[] + + for p in contour: + y.append(p[0][0]) + x.append(p[0][1]) + + return [min(y), min(x), max(y), max(x)] + + #定位车牌号 + def locate_license(self, img, afterimg): + + contours, hierarchy = cv2.findContours(img, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) + + #找出最大的三个区域 + block = [] + for c in contours: + #找出轮廓的左上点和右下点 + #由此计算它的面积和长度比 + r = self.find_rectangle(c) + a = (r[2] - r[0]) * (r[3] - r[1]) #面积 + s = (r[2] - r[0]) * (r[3] - r[1]) #长度比 + + block.append([r, a, s]) + + #选出面积最大的3个区域 + block = sorted(block, key=lambda b: b[1])[-3:] + + #使用颜色识别判断找出最像车牌的区域 + maxweight, maxindex = 0, -1 + for i in range(len(block)): + b = afterimg[block[i][0][1]:block[i][0][3], block[i][0][0]:block[i][0][2]] + hsv = cv2.cvtColor(b, cv2.COLOR_BGR2HSV) + lower = np.array([100, 50, 50]) + upper = np.array([140, 255, 255]) + mask = cv2.inRange(hsv, lower, upper) + + # 计算mask中白色像素(即HSV范围内的像素)的数量 + weight = np.sum(mask == 255) # 或者简单地使用 np.count_nonzero(mask) + + # 选出最大权值的区域 + if weight > maxweight: + maxindex = i + maxweight = weight + + return block[maxindex][0] + + #预处理函数 + def find_license(self, img): + + m = 400 * img.shape[0] / img.shape[1] + + #压缩图像 + img = cv2.resize(img, (400, int(m)), interpolation=cv2.INTER_CUBIC) + + #BGR转换为灰度图像 + gray_img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) + + #灰度拉伸 + stretchedimg = self.stretch(gray_img) + + '''进行开运算,用来去除噪声''' + r = 16 + h = w = r * 2 + 1 + kernel = np.zeros((h, w), np.uint8) + cv2.circle(kernel, (r, r), r, 1, -1) + + openingimg = cv2.morphologyEx(stretchedimg, cv2.MORPH_OPEN, kernel) + + strtimg = cv2.absdiff(stretchedimg, openingimg) + + #图像二值化 + binaryimg = self.dobinaryzation(strtimg) + + #canny边缘检测 + canny = cv2.Canny(binaryimg, binaryimg.shape[0], binaryimg.shape[1]) + + '''消除小的区域,保留大块的区域,从而定位车牌''' + #进行闭运算 + kernel = np.ones((5, 17), np.uint8) + closingimg = cv2.morphologyEx(canny, cv2.MORPH_CLOSE, kernel) + + #进行开运算 + openingimg = cv2.morphologyEx(closingimg, cv2.MORPH_OPEN, kernel) + + + + #消除小区域,定位车牌位置 + rect = self.locate_license(openingimg, img) + + return rect, img + #图像分割函数 + def cut_license(self, afterimg, rect): + + #转换为宽度和高度 + rect[2] = rect[2] - rect[0] + rect[3] = rect[3] - rect[1] + rect_copy = tuple(rect.copy()) + #创建掩膜 + mask = np.zeros(afterimg.shape[:2], np.uint8) + #创建背景模型 大小只能为13*5,行数只能为1,单通道浮点型 + bgdModel = np.zeros((1, 65), np.float64) + #创建前景模型 + fgdModel = np.zeros((1, 65), np.float64) + #分割图像 + cv2.grabCut(afterimg, mask, rect_copy, bgdModel, fgdModel, 5, cv2.GC_INIT_WITH_RECT) + mask2 = np.where((mask == 2) | (mask == 0), 0, 1).astype('uint8') + img_show = afterimg * mask2[:, :, np.newaxis] + + return img_show + + +class Segmentation(): + def __init__(self, cutimg): + + #1、读取图像,并把图像转换为灰度图像并显示 + + img_gray = cv2.cvtColor(cutimg, cv2.COLOR_BGR2GRAY) #转换了灰度化 + + #2、将灰度图像二值化,设定阈值是150 + self.img_thre = img_gray + cv2.threshold(img_gray, 150 + , 255, cv2.THRESH_BINARY_INV, self.img_thre) + + + + #3、保存黑白图片 + cv2.imwrite('thre_res.jpg', self.img_thre) + + #4、分割字符 + self.white = [] #记录每一列的白色像素总和 + self.black = [] #黑色 + self.height = self.img_thre.shape[0] + self.width = self.img_thre.shape[1] + self.white_max = 0 + self.black_max = 0 + #计算每一列的黑白色像素总和 + for i in range(self.width): + white_count = 0 #这一列白色总数 + black_count = 0 #这一列黑色总数 + for j in range(self.height): + if self.img_thre[j][i] == 255: + white_count += 1 + if self.img_thre[j][i] == 0: + black_count += 1 + self.white_max = max(self.white_max, white_count) + self.black_max = max(self.black_max, black_count) + self.white.append(white_count) + self.black.append(black_count) + + self.arg = False #False表示白底黑字;True表示黑底白字 + if self.black_max > self.white_max: + self.arg = True + + def heibai(self): + return self.img_thre + + + def find_end(self, start_): + end_ = start_ + 1 + for m in range(start_ + 1, self.width - 1): + if (self.black[m] if self.arg else self.white[m]) > ( + 0.85 * self.black_max if self.arg else 0.85 * self.white_max): + end_ = m + break + return end_ + + def display(self): + #img_list = [] + n = 1 + plt.figure() + img_num = 0 + while n < self.width - 2: + n += 1 + if (self.white[n] if self.arg else self.black[n]) > ( + 0.15 * self.white_max if self.arg else 0.15 * self.black_max): + #上面这些判断用来辨别是白底黑字还是黑底白字 + + start = n + end = self.find_end(start) + n = end + + if end - start > 5: + cj = self.img_thre[1:self.height, start:end] + img_num += 1 + cj = cv2.cvtColor(cj, cv2.COLOR_RGB2BGR) + + plt.figure(2) + plt.subplot(2, 4, img_num) + plt.title('{}'.format(img_num)) + plt.imshow(cj) + plt.show() + return self.img_thre + + +if __name__ == '__main__': + + def select_image(): + # 弹出文件选择对话框,限制文件类型为图片 + file_path = filedialog.askopenfilename() + if file_path: + # 将文件路径显示在标签上 + img = cv2.imread(file_path) + img1 = cv2.cvtColor(img, cv2.COLOR_RGB2BGR) + # 绘图 + plt.figure(1) + plt.suptitle('车牌识别', fontproperties=font) + plt.subplot(2, 3, 1) + plt.title('原始图像', fontproperties=font) + plt.imshow(img1) + + # 预处理图像 + license = Get_license() + rect, afterimg = license.find_license(img) + afterimg = cv2.cvtColor(afterimg, cv2.COLOR_RGB2BGR) + + plt.subplot(2, 3, 2) + plt.title('预处理后图像', fontproperties=font) + plt.imshow(afterimg) + + # 车牌号打框 + cv2.rectangle(afterimg, (rect[0], rect[1]), (rect[2], rect[3]), (0, 255, 0), 1) + x1, y1, x2, y2 = int(rect[0]), int(rect[1]), int(rect[2]), int(rect[3]) + + plt.subplot(2, 3, 3) + plt.title('车牌框出', fontproperties=font) + plt.imshow(afterimg) + + # 背景去除 + cutimg = license.cut_license(afterimg, rect) + plt.subplot(2, 3, 4) + plt.title('车牌背景去除', fontproperties=font) + plt.imshow(cutimg) + # print(int(_rect[0]), int(_rect[3]), int(_rect[2]), int(_rect[1])) + + # 开始分割车牌 + # cutimg = cutimg[140:165, 151:240] + cutimg = cutimg[y1 + 3:y2 - 3, x1 - 1:x2 - 3] + # cutimg = cutimg[int(_rect[0]):int(_rect[3]),int(_rect[2]):int(_rect[1])] + + height, width = cutimg.shape[:2] + cutimg1 = cv2.resize(cutimg, (2 * width, 2 * height), interpolation=cv2.INTER_CUBIC) + plt.subplot(2, 3, 5) + plt.title('分割车牌与背景', fontproperties=font) + plt.imshow(cutimg) + + # 字符切割 + seg = Segmentation(cutimg) + plt.subplot(2, 3, 6) + img_hei = seg.heibai() + img_hei = cv2.cvtColor(img_hei, cv2.COLOR_RGB2BGR) + plt.title('车牌二值化处理', fontproperties=font) + plt.imshow(img_hei) + seg.display() + plt.show() + + # 打印车牌 + ocr = ddddocr.DdddOcr() + with open('thre_res.jpg', 'rb') as f: + image = f.read() + res = ocr.classification(image) + print(res) + + + + + # 创建根窗口 + root = tk.Tk() + root.title('车牌识别程序') + root.geometry('600x450') + # 创建一个标签用于显示图片路径 + label = tk.Label(root, text='未选择图片') + label.pack(pady=20) # 使用pack布局管理器,并添加一些垂直填充 + + + def exit_app(): + # 退出应用程序的函数 + root.destroy() + # 创建一个按钮,点击时会调用select_image函数 + button = tk.Button(root, text='选择图片', command=select_image) + button.pack() + button_exit = tk.Button(root, text='退出', command=exit_app) + button_exit.pack(pady=30) + # 启动事件循环 + root.mainloop() + + + + + + + + +