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()