前言

前段时间,用PyQt5写了两篇文章,关于Python自制一款炫酷音乐播放器、自定义桌面动画挂件。有粉丝问我,为什么要用PyQt5?之前没接触过PyQt5,能不能多分享一些这方面的开发案例?

今天就继续给大家分享一个实战案例,带大家一起用Python的PyQt5开发一个车牌自动识别系统!

首先一起来看看最终实现的车牌识别系统效果图:
下面,我们就开始介绍如何实现这款自动车牌识别系统。

直接跳到文末获取粉丝专属福利。

一、核心功能设计

总体来说,我们首先要进行UI界面构建设计,根据车牌识别系统功能进行画面排版布局;其次我们的这款车牌识别系统的主要功能车辆图片读取识别显示、图片中车牌ROI区域获取、车牌识别结果输出显示。

对于结果输出显示,我们主要包含了读取图片名称、读取录入时间、识别车牌号码、识别车牌颜色、识别车牌所属地。最后我们还可以将车牌识别系统的数据信息导出本地存储。

拆解需求,大致可以整理出核心功能如下:

  • UI设计排版布局

    • 左侧区域进行识别信息显示,包含图片名称、读取录入时间、识别车牌号码、识别车牌颜色、识别车牌所属地信息
    • 右侧可以分成3个区域,顶部区域包含窗体最小化,最大化,关闭功能;中间区域显示读取车辆图片;底部区域包含车牌显示区域、图片读取、车牌信息存储功能
  • 车牌识别

    • 通过读取图片进行车牌区域提取输出
    • 车牌自动识别结果输出
  • 车牌信息显示存储

    • 根据自动识别结果对车牌各类信息显示
    • 对录入识别的车辆车牌识别信息存储

二、实现步骤

1. UI设计排版布局

根据车牌识别需要的功能,首先进行UI布局设计,我们这次还是使用的pyqt5。核心设计代码如下:

# author:CSDN-
def setupUi(self, MainWindow):MainWindow.setObjectName("MainWindow")MainWindow.resize(1213, 670)MainWindow.setFixedSize(1213, 670)  # 设置窗体固定大小MainWindow.setToolButtonStyle(QtCore.Qt.ToolButtonIconOnly)self.centralwidget = QtWidgets.QWidget(MainWindow)self.centralwidget.setObjectName("centralwidget")self.scrollArea = QtWidgets.QScrollArea(self.centralwidget)self.scrollArea.setGeometry(QtCore.QRect(690, 40, 511, 460))self.scrollArea.setWidgetResizable(True)self.scrollArea.setObjectName("scrollArea")self.scrollAreaWidgetContents = QtWidgets.QWidget()self.scrollAreaWidgetContents.setGeometry(QtCore.QRect(0, 0, 500, 489))self.scrollAreaWidgetContents.setObjectName("scrollAreaWidgetContents")self.label_0 = QtWidgets.QLabel(self.scrollAreaWidgetContents)self.label_0.setGeometry(QtCore.QRect(10, 10, 111, 20))font = QtGui.QFont()font.setPointSize(11)self.label_0.setFont(font)self.label_0.setObjectName("label_0")self.label = QtWidgets.QLabel(self.scrollAreaWidgetContents)self.label.setGeometry(QtCore.QRect(10, 40, 481, 420))self.label.setObjectName("label")self.label.setAlignment(Qt.AlignCenter)self.scrollArea.setWidget(self.scrollAreaWidgetContents)self.scrollArea_2 = QtWidgets.QScrollArea(self.centralwidget)self.scrollArea_2.setGeometry(QtCore.QRect(10, 10, 671, 631))self.scrollArea_2.setWidgetResizable(True)self.scrollArea_2.setObjectName("scrollArea_2")self.scrollAreaWidgetContents_1 = QtWidgets.QWidget()self.scrollAreaWidgetContents_1.setGeometry(QtCore.QRect(0, 0, 669, 629))self.scrollAreaWidgetContents_1.setObjectName("scrollAreaWidgetContents_1")self.label_1 = QtWidgets.QLabel(self.scrollAreaWidgetContents_1)self.label_1.setGeometry(QtCore.QRect(10, 10, 111, 20))font = QtGui.QFont()font.setPointSize(11)self.label_1.setFont(font)self.label_1.setObjectName("label_1")self.tableWidget = QtWidgets.QTableWidget(self.scrollAreaWidgetContents_1)self.tableWidget.setGeometry(QtCore.QRect(10, 40, 651, 581))  # 581))self.tableWidget.setObjectName("tableWidget")self.tableWidget.setColumnCount(5)self.tableWidget.setColumnWidth(0, 140)  # 设置1列的宽度self.tableWidget.setColumnWidth(1, 130)  # 设置2列的宽度self.tableWidget.setColumnWidth(2, 110)  # 设置3列的宽度self.tableWidget.setColumnWidth(3, 90)  # 设置4列的宽度self.tableWidget.setColumnWidth(4, 181)  # 设置5列的宽度self.tableWidget.setHorizontalHeaderLabels(["图片名称", "录入时间", "车牌号码", "车牌类型", "车牌信息"])self.tableWidget.setRowCount(self.RowLength)self.tableWidget.verticalHeader().setVisible(False)  # 隐藏垂直表头)self.tableWidget.setEditTriggers(QAbstractItemView.NoEditTriggers)self.tableWidget.raise_()self.scrollArea_2.setWidget(self.scrollAreaWidgetContents_1)self.scrollArea_3 = QtWidgets.QScrollArea(self.centralwidget)self.scrollArea_3.setGeometry(QtCore.QRect(690, 510, 341, 131))self.scrollArea_3.setWidgetResizable(True)self.scrollArea_3.setObjectName("scrollArea_3")self.scrollAreaWidgetContents_3 = QtWidgets.QWidget()self.scrollAreaWidgetContents_3.setGeometry(QtCore.QRect(0, 0, 339, 129))self.scrollAreaWidgetContents_3.setObjectName("scrollAreaWidgetContents_3")self.label_2 = QtWidgets.QLabel(self.scrollAreaWidgetContents_3)self.label_2.setGeometry(QtCore.QRect(10, 10, 111, 20))font = QtGui.QFont()font.setPointSize(11)self.label_2.setFont(font)self.label_2.setObjectName("label_2")self.label_3 = QtWidgets.QLabel(self.scrollAreaWidgetContents_3)self.label_3.setGeometry(QtCore.QRect(10, 40, 321, 81))self.label_3.setObjectName("label_3")self.scrollArea_3.setWidget(self.scrollAreaWidgetContents_3)self.scrollArea_4 = QtWidgets.QScrollArea(self.centralwidget)self.scrollArea_4.setGeometry(QtCore.QRect(1040, 510, 161, 131))self.scrollArea_4.setWidgetResizable(True)self.scrollArea_4.setObjectName("scrollArea_4")self.scrollAreaWidgetContents_4 = QtWidgets.QWidget()self.scrollAreaWidgetContents_4.setGeometry(QtCore.QRect(0, 0, 159, 129))self.scrollAreaWidgetContents_4.setObjectName("scrollAreaWidgetContents_4")self.pushButton_2 = QtWidgets.QPushButton(self.scrollAreaWidgetContents_4)self.pushButton_2.setGeometry(QtCore.QRect(20, 50, 121, 31))self.pushButton_2.setObjectName("pushButton_2")self.pushButton = QtWidgets.QPushButton(self.scrollAreaWidgetContents_4)self.pushButton.setGeometry(QtCore.QRect(20, 90, 121, 31))self.pushButton.setObjectName("pushButton")self.label_4 = QtWidgets.QLabel(self.scrollAreaWidgetContents_4)self.label_4.setGeometry(QtCore.QRect(10, 10, 111, 20))font = QtGui.QFont()font.setPointSize(11)self.label_4.setFont(font)self.label_4.setObjectName("label_4")self.scrollArea_4.setWidget(self.scrollAreaWidgetContents_4)MainWindow.setCentralWidget(self.centralwidget)self.statusbar = QtWidgets.QStatusBar(MainWindow)self.statusbar.setObjectName("statusbar")MainWindow.setStatusBar(self.statusbar)self.retranslateUi(MainWindow)QtCore.QMetaObject.connectSlotsByName(MainWindow)self.retranslateUi(MainWindow)QtCore.QMetaObject.connectSlotsByName(MainWindow)self.pushButton.clicked.connect(self.__openimage)  # 设置点击事件self.pushButton.setStyleSheet('''QPushButton{background:#222225;border-radius:5px;}QPushButton:hover{background:#2B2B2B;}''')self.pushButton_2.clicked.connect(self.__writeFiles)  # 设置点击事件self.pushButton_2.setStyleSheet('''QPushButton{background:#222225;border-radius:5px;}QPushButton:hover{background:#2B2B2B;}''')self.retranslateUi(MainWindow)self.close_widget = QtWidgets.QWidget(self.centralwidget)self.close_widget.setGeometry(QtCore.QRect(1130, 0, 90, 50))self.close_widget.setObjectName("close_widget")self.close_layout = QGridLayout()  # 创建左侧部件的网格布局层self.close_widget.setLayout(self.close_layout)  # 设置左侧部件布局为网格self.left_close = QPushButton("")  # 关闭按钮self.left_close.clicked.connect(self.close)self.left_visit = QPushButton("")  # 空白按钮self.left_visit.clicked.connect(MainWindow.big)self.left_mini = QPushButton("")  # 最小化按钮self.left_mini.clicked.connect(MainWindow.mini)self.close_layout.addWidget(self.left_mini, 0, 0, 1, 1)self.close_layout.addWidget(self.left_close, 0, 2, 1, 1)self.close_layout.addWidget(self.left_visit, 0, 1, 1, 1)self.left_close.setFixedSize(15, 15)  # 设置关闭按钮的大小self.left_visit.setFixedSize(15, 15)  # 设置按钮大小self.left_mini.setFixedSize(15, 15)  # 设置最小化按钮大小self.left_close.setStyleSheet('''QPushButton{background:#F76677;border-radius:5px;}QPushButton:hover{background:red;}''')self.left_visit.setStyleSheet('''QPushButton{background:#F7D674;border-radius:5px;}QPushButton:hover{background:yellow;}''')self.left_mini.setStyleSheet('''QPushButton{background:#6DDF6D;border-radius:5px;}QPushButton:hover{background:green;}''')QtCore.QMetaObject.connectSlotsByName(MainWindow)self.ProjectPath = os.getcwd()  # 获取当前工程文件位置self.scrollAreaWidgetContents.setStyleSheet(sc)self.scrollAreaWidgetContents_3.setStyleSheet(sc)self.scrollAreaWidgetContents_4.setStyleSheet(sc)b =             '''color:white;background:#2B2B2B;'''self.label_0.setStyleSheet(b)self.label_1.setStyleSheet(b)self.label_2.setStyleSheet(b)self.label_3.setStyleSheet(b)MainWindow.setWindowOpacity(0.95)  # 设置窗口透明度MainWindow.setAttribute(Qt.WA_TranslucentBackground)MainWindow.setWindowFlag(Qt.FramelessWindowHint)  # 隐藏边框# author:CSDN-
def retranslateUi(self, MainWindow):_translate = QtCore.QCoreApplication.translateMainWindow.setWindowTitle(_translate("MainWindow", "车牌识别系统"))self.label_0.setText(_translate("MainWindow", "原始图片:"))self.label.setText(_translate("MainWindow", ""))self.label_1.setText(_translate("MainWindow", "识别结果:"))self.label_2.setText(_translate("MainWindow", "车牌区域:"))self.label_3.setText(_translate("MainWindow", ""))self.pushButton.setText(_translate("MainWindow", "打开文件"))self.pushButton_2.setText(_translate("MainWindow", "导出数据"))self.label_4.setText(_translate("MainWindow", "事件:"))self.scrollAreaWidgetContents_1.show()

UI实现效果如下:

2. 车牌识别

接下来我们需要实现两个核心功能,包括获取车牌ROI区域车牌自动识别功能。

车牌ROI区域提取:

根据读取的车辆图片,预处理进行车牌ROI区域提取,主要通过Opencv的图像处理相关知识点来完成。主要包括对图像去噪、二值化、边缘轮廓提取、矩形区域矫正、蓝绿黄车牌颜色定位识别。核心代码如下:

# author:CSDN-
# 预处理
def pretreatment(self, car_pic):if type(car_pic) == type(""):img = self.__imreadex(car_pic)else:img = car_picpic_hight, pic_width = img.shape[:2]if pic_width > self.MAX_WIDTH:resize_rate = self.MAX_WIDTH / pic_widthimg = cv2.resize(img, (self.MAX_WIDTH, int(pic_hight * resize_rate)),interpolation=cv2.INTER_AREA)  # 图片分辨率调整blur = self.cfg["blur"]# 高斯去噪if blur > 0:img = cv2.GaussianBlur(img, (blur, blur), 0)oldimg = imgimg = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)kernel = np.ones((20, 20), np.uint8)img_opening = cv2.morphologyEx(img, cv2.MORPH_OPEN, kernel)  # 开运算img_opening = cv2.addWeighted(img, 1, img_opening, -1, 0);  # 与上一次开运算结果融合# cv2.imshow('img_opening', img_opening)# 找到图像边缘ret, img_thresh = cv2.threshold(img_opening, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)  # 二值化img_edge = cv2.Canny(img_thresh, 100, 200)# cv2.imshow('img_edge', img_edge)# 使用开运算和闭运算让图像边缘成为一个整体kernel = np.ones((self.cfg["morphologyr"], self.cfg["morphologyc"]), np.uint8)img_edge1 = cv2.morphologyEx(img_edge, cv2.MORPH_CLOSE, kernel)  # 闭运算img_edge2 = cv2.morphologyEx(img_edge1, cv2.MORPH_OPEN, kernel)  # 开运算# cv2.imshow('img_edge2', img_edge2)# cv2.imwrite('./edge2.png', img_edge2)# 查找图像边缘整体形成的矩形区域,可能有很多,车牌就在其中一个矩形区域中image, contours, hierarchy = cv2.findContours(img_edge2, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)contours = [cnt for cnt in contours if cv2.contourArea(cnt) > self.Min_Area]# 逐个排除不是车牌的矩形区域car_contours = []for cnt in contours:# 框选 生成最小外接矩形 返回值(中心(x,y), (宽,高), 旋转角度)rect = cv2.minAreaRect(cnt)# print('宽高:',rect[1])area_width, area_height = rect[1]# 选择宽大于高的区域if area_width < area_height:area_width, area_height = area_height, area_widthwh_ratio = area_width / area_height# print('宽高比:',wh_ratio)# 要求矩形区域长宽比在2到5.5之间,2到5.5是车牌的长宽比,其余的矩形排除if wh_ratio > 2 and wh_ratio < 5.5:car_contours.append(rect)box = cv2.boxPoints(rect)box = np.int0(box)# 矩形区域可能是倾斜的矩形,需要矫正,以便使用颜色定位card_imgs = []for rect in car_contours:if rect[2] > -1 and rect[2] < 1:  # 创造角度,使得左、高、右、低拿到正确的值angle = 1else:angle = rect[2]rect = (rect[0], (rect[1][0] + 5, rect[1][1] + 5), angle)  # 扩大范围,避免车牌边缘被排除box = cv2.boxPoints(rect)heigth_point = right_point = [0, 0]left_point = low_point = [pic_width, pic_hight]for point in box:if left_point[0] > point[0]:left_point = pointif low_point[1] > point[1]:low_point = pointif heigth_point[1] < point[1]:heigth_point = pointif right_point[0] < point[0]:right_point = pointif left_point[1] <= right_point[1]:  # 正角度new_right_point = [right_point[0], heigth_point[1]]pts2 = np.float32([left_point, heigth_point, new_right_point])  # 字符只是高度需要改变pts1 = np.float32([left_point, heigth_point, right_point])M = cv2.getAffineTransform(pts1, pts2)dst = cv2.warpAffine(oldimg, M, (pic_width, pic_hight))self.__point_limit(new_right_point)self.__point_limit(heigth_point)self.__point_limit(left_point)card_img = dst[int(left_point[1]):int(heigth_point[1]), int(left_point[0]):int(new_right_point[0])]card_imgs.append(card_img)elif left_point[1] > right_point[1]:  # 负角度new_left_point = [left_point[0], heigth_point[1]]pts2 = np.float32([new_left_point, heigth_point, right_point])  # 字符只是高度需要改变pts1 = np.float32([left_point, heigth_point, right_point])M = cv2.getAffineTransform(pts1, pts2)dst = cv2.warpAffine(oldimg, M, (pic_width, pic_hight))self.__point_limit(right_point)self.__point_limit(heigth_point)self.__point_limit(new_left_point)card_img = dst[int(right_point[1]):int(heigth_point[1]), int(new_left_point[0]):int(right_point[0])]card_imgs.append(card_img)#使用颜色定位,排除不是车牌的矩形,目前只识别蓝、绿、黄车牌colors = []for card_index, card_img in enumerate(card_imgs):green = yellow = blue = black = white = 0try:# 有转换失败的可能,原因来自于上面矫正矩形出错card_img_hsv = cv2.cvtColor(card_img, cv2.COLOR_BGR2HSV)except:print('BGR转HSV失败')card_imgs = colors = Nonereturn card_imgs, colorsif card_img_hsv is None:continuerow_num, col_num = card_img_hsv.shape[:2]card_img_count = row_num * col_num# 确定车牌颜色for i in range(row_num):for j in range(col_num):H = card_img_hsv.item(i, j, 0)S = card_img_hsv.item(i, j, 1)V = card_img_hsv.item(i, j, 2)if 11 < H <= 34 and S > 34:  # 图片分辨率调整yellow += 1elif 35 < H <= 99 and S > 34:  # 图片分辨率调整green += 1elif 99 < H <= 124 and S > 34:  # 图片分辨率调整blue += 1if 0 < H < 180 and 0 < S < 255 and 0 < V < 46:black += 1elif 0 < H < 180 and 0 < S < 43 and 221 < V < 225:white += 1color = "no"# print('黄:{:<6}绿:{:<6}蓝:{:<6}'.format(yellow,green,blue))limit1 = limit2 = 0if yellow * 2 >= card_img_count:color = "yellow"limit1 = 11limit2 = 34  # 有的图片有色偏偏绿elif green * 2 >= card_img_count:color = "green"limit1 = 35limit2 = 99elif blue * 2 >= card_img_count:color = "blue"limit1 = 100limit2 = 124  # 有的图片有色偏偏紫elif black + white >= card_img_count * 0.7:color = "bw"# print(color)colors.append(color)# print(blue, green, yellow, black, white, card_img_count)if limit1 == 0:continue# 根据车牌颜色再定位,缩小边缘非车牌边界xl, xr, yh, yl = self.accurate_place(card_img_hsv, limit1, limit2, color)if yl == yh and xl == xr:continueneed_accurate = Falseif yl >= yh:yl = 0yh = row_numneed_accurate = Trueif xl >= xr:xl = 0xr = col_numneed_accurate = Truecard_imgs[card_index] = card_img[yl:yh, xl:xr] if color != "green" or yl < (yh - yl) // 4 else card_img[yl - (yh - yl) // 4:yh, xl:xr]if need_accurate:  # 可能x或y方向未缩小,需要再试一次card_img = card_imgs[card_index]card_img_hsv = cv2.cvtColor(card_img, cv2.COLOR_BGR2HSV)xl, xr, yh, yl = self.accurate_place(card_img_hsv, limit1, limit2, color)if yl == yh and xl == xr:continueif yl >= yh:yl = 0yh = row_numif xl >= xr:xl = 0xr = col_numcard_imgs[card_index] = card_img[yl:yh, xl:xr] if color != "green" or yl < (yh - yl) // 4 else card_img[yl - (yh - yl) // 4:yh, xl:xr]# cv2.imshow("result", card_imgs[0])# cv2.imwrite('1.jpg', card_imgs[0])# print('颜色识别结果:' + colors[0])return card_imgs, colors

至此我们就可以输出车牌ROI区域和车牌颜色了,效果如下:

车牌自动识别:

车牌识别博主自己写了一个基于Opencv和SVM的识别系统,由于代码篇幅较长,本篇不进行展示(感兴趣的可以私信博主获取源码)。本篇介绍调用百度AI提供的车牌识别接口 – 百度AI开放平台链接,识别效果也非常不错。

这里面我们可以创建一个车牌识别的应用,其中的API Key及Secret Key后面我们调用车牌识别检测接口时会用到。

我们可以看到官方提供的帮助文档,介绍了如何调用请求URL数据格式,向API服务地址使用POST发送请求,必须在URL中带上参数access_token,可通过后台的API Key和Secret Key生成。这里面的API Key和Secret Key就是我们上面提到的。

接下来我们看看调用车牌识别接口代码示例。

那我们如何获取识别的车牌号码呢?API文档可以看到里面有个words_result字典 ,其中的color代表车牌颜色number代表车牌号码 。这样我就可以知道识别的车牌颜色和车牌号了。


车牌识别的接口调用流程基本已经清楚了,下面就可以进行代码实现了。

# author:CSDN-
def get_token(self):host = 'https://aip.baidubce.com/oauth/2.0/token?grant_type=client_credentials&client_id=' + self.client_id + '&client_secret=' + self.client_secretresponse = requests.get(host)if response:token_info = response.json()token_key = token_info['access_token']return token_key# author:CSDN-
def get_license_plate(self, car_pic):result = {}card_imgs, colors = self.pretreatment(car_pic)request_url = "https://aip.baidubce.com/rest/2.0/ocr/v1/license_plate"# 二进制方式打开图片文件f = open(car_pic, 'rb')img = base64.b64encode(f.read())params = {"image": img}access_token = self.get_token()request_url = request_url + "?access_token=" + access_tokenheaders = {'content-type': 'application/x-www-form-urlencoded'}response = requests.post(request_url, data=params, headers=headers)if response:print(response.json())license_result = response.json()['words_result']['number']card_color = response.json()['words_result']['color']if license_result != []:result['InputTime'] = time.strftime("%Y-%m-%d %H:%M:%S")result['Type'] = self.cardtype[card_color]result['Picture'] = card_imgs[0]result['Number'] = ''.join(license_result[:2]) + '·' + ''.join(license_result[2:])try:result['From'] = ''.join(self.Prefecture[license_result[0]][license_result[1]])except:result['From'] = '未知'return resultelse:return None

这样我们就可以拿到车牌颜色和车牌号码了,效果如下:

3. 车牌信息显示存储

3.1 车牌信息显示:
# author:CSDN-
def __show(self, result, FileName):# 显示表格self.RowLength = self.RowLength + 1if self.RowLength > 18:self.tableWidget.setColumnWidth(5, 157)self.tableWidget.setRowCount(self.RowLength)self.tableWidget.setItem(self.RowLength - 1, 0, QTableWidgetItem(FileName))self.tableWidget.setItem(self.RowLength - 1, 1, QTableWidgetItem(result['InputTime']))self.tableWidget.setItem(self.RowLength - 1, 2, QTableWidgetItem(result['Number']))self.tableWidget.setItem(self.RowLength - 1, 3, QTableWidgetItem(result['Type']))if result['Type'] == '蓝色牌照':self.tableWidget.item(self.RowLength - 1, 3).setBackground(QBrush(QColor(3, 128, 255)))elif result['Type'] == '绿色牌照':self.tableWidget.item(self.RowLength - 1, 3).setBackground(QBrush(QColor(98, 198, 148)))elif result['Type'] == '黄色牌照':self.tableWidget.item(self.RowLength - 1, 3).setBackground(QBrush(QColor(242, 202, 9)))self.tableWidget.setItem(self.RowLength - 1, 4, QTableWidgetItem(result['From']))self.tableWidget.item(self.RowLength - 1, 4).setBackground(QBrush(QColor(255, 255, 255)))# 显示识别到的车牌位置size = (int(self.label_3.width()), int(self.label_3.height()))shrink = cv2.resize(result['Picture'], size, interpolation=cv2.INTER_AREA)shrink = cv2.cvtColor(shrink, cv2.COLOR_BGR2RGB)self.QtImg = QtGui.QImage(shrink[:], shrink.shape[1], shrink.shape[0], shrink.shape[1] * 3,QtGui.QImage.Format_RGB888)self.label_3.setPixmap(QtGui.QPixmap.fromImage(self.QtImg))

效果如下:

3.2 信息导出存储:
# author:CSDN-
def __writexls(self, DATA, path):wb = xlwt.Workbook();ws = wb.add_sheet('Data');# DATA.insert(0, ['文件名称','录入时间', '车牌号码', '车牌类型', '车牌信息'])for i, Data in enumerate(DATA):for j, data in enumerate(Data):ws.write(i, j, data)wb.save(path)QMessageBox.information(None, "成功", "数据已保存!", QMessageBox.Yes)
def __writecsv(self, DATA, path):f = open(path, 'w')# DATA.insert(0, ['文件名称','录入时间', '车牌号码', '车牌类型', '车牌信息'])for data in DATA:f.write((',').join(data) + '
')f.close()QMessageBox.information(None, "成功", "数据已保存!", QMessageBox.Yes)def __writeFiles(self):path, filetype = QFileDialog.getSaveFileName(None, "另存为", self.ProjectPath,"Excel 工作簿(*.xls);;CSV (逗号分隔)(*.csv)")if path == "":  # 未选择returnif filetype == 'Excel 工作簿(*.xls)':self.__writexls(self.Data, path)elif filetype == 'CSV (逗号分隔)(*.csv)':self.__writecsv(self.Data, path)

效果如下:

导出车牌信息数据如下:

至此,整个车牌自动识别系统就完成了~今天我们就到这里,明天继续努力!
源码及数据已上传,关注文末公众号回复【源码】即可获取完整源码

Python往期精彩:

  • 见过仙女蹦迪吗?一起用python做个小仙女代码蹦迪视频

  • python自制一款炫酷音乐播放器,想听啥随便搜!

  • 斗地主老是输?一起用Python做个AI出牌器,豆子蹭蹭涨!

  • 桌面太单调?一起用Python做个自定义动画挂件,好玩又有趣!

  • 一起用Python做个车牌自动识别系统,好玩又实用!

  • 桌面太单调?一起用Python做个自定义动态壁纸,竟然还可以放视频!

  • 一起用Python做个自动化弹钢琴脚本,我竟然弹出了《天空之城》!
    往期精彩源码均可通过下方公众号获取

一起用Python做个车牌自动识别系统,好玩又实用!相关推荐

  1. 我给小区物业写了个车牌自动识别系统,非常实用。物业给你免费停车一年!

    前言 今天出门,出小区的时候发现停车杆没有反应,然后我就打电话让人来给我开杆!后来通过和物业人员聊天过程中,原来是车牌识别不了了.好像是坏了!这不是小事吗,我和物业说了一声,晚上我给你弄好!物业小姐姐 ...

  2. 一起用Python做个上课点名器,好玩又实用!

    前言 前段时间,用PyQt5写了几篇文章,关于Python自制一款炫酷音乐播放器.自定义动态壁纸.车牌自动识别系统.今天就继续给大家分享一个读者粉丝投稿的,关于上课点名的实战案例,一起来看看是如何实现 ...

  3. 一起用Python做个自动化短视频生成脚本,实现热门视频流水线生产!

    前言 前几天有粉丝和我说,最近在网上看到一些视频营销号一天能发布几百条短视频, 感觉都是批量生成的,能不能用Python做个自动化短视频生成脚本呢? 今天就带大家一起用Python做个自动化视频生成脚 ...

  4. 一起用python做个炫酷音乐播放器【V3.0含源码及打包exe】

    前言 熟悉的小伙伴都知道,前段时间写了一篇关于音乐播放器的文章–Python自制一款炫酷音乐播放器.不少小伙伴私信我,对播放器提了一些改进建议,对播放器的一些逻辑bug优化完善.今天音乐播放器3.0版 ...

  5. 桌面太单调?一起用Python做个自定义动画挂件,好玩又有趣!

    前言 前段时间,写了篇博客关于Python自制一款炫酷音乐播放器.有粉丝问我,音乐播放器为什么要用PyQt5,效果是不是比Tkinter赞?PyQt5真的可以实现这些炫酷的UI画面吗?之前没接触过Py ...

  6. yolov3 python含新能源车牌识别系统有pyqt5界面

    yolov3 python含新能源车牌识别系统有pyqt5界面 # First download Darknet project $ git clone https://github.com/pjre ...

  7. 广元停车场系统推荐_广元车牌自动识别停车系统设计方案,车牌自动识别系统停车场哪家有名...

    广元车牌自动识别停车系统设计方案 成都臻致三才科技有限公司自2014年成立以来"云"车牌识别系统.IC卡车辆管理系统.远距读卡系统.视频车位引导系统.人行通道闸.智能道闸.特种防恐 ...

  8. 基于MATLAB的机动车车牌自动识别系统

    随着智慧交通的发展,对机动车监管的需要,车牌识别技术成为现代智慧交通系统中不可或缺的一部分,在日常生活中应用十分 广泛.本文章研究分析了该技术实现各个部分所使用的相关算法,选取了识别准确率高并且效率较 ...

  9. 用python做一个车牌识别_如何用 Python 识别车牌

    车牌识别在高速公路中有着广泛的应用,比如我们常见的电子收费(ETC)系统和交通违章车辆的检测,除此之外像小区或地下车库门禁也会用到,基本上凡是需要对车辆进行身份检测的地方都会用到. 简介 车牌识别系统 ...

  10. 用python做一个舆情分析系统_如何用Python做舆情时间序列可视化?

    如何批量处理评论信息情感分析,并且在时间轴上可视化呈现?舆情分析并不难,让我们用Python来实现它吧. 痛点 你是一家连锁火锅店的区域经理,很注重顾客对餐厅的评价.从前,你苦恼的是顾客不爱写评价.最 ...

最新文章

  1. 微软官方office2010使用技巧宝典视频免费下载
  2. 决定项目生死的关键:是商业模式,而不是成本
  3. [0].Net开发者社区--您好大的官威啊!
  4. asp.net 调用SmtpClient发送邮件(转)
  5. java面向对象测试题二_JAVA面向对象-测试题
  6. python记录_day33 线程
  7. JavaScript静态页面值传递之URL篇
  8. Grafana 8重磅发布:统一警报、实时流、继续炫酷到底!
  9. 番茄工作法(番茄钟时间管理)
  10. 开源是什么以及如何做
  11. 【Kubernetes】Kubeadm安装的K8s集群的版本升级过程测试(二)
  12. 换个姿势做运维!GOPS 2022 · 深圳站精彩内容抢先看
  13. 【控制】鲁棒性 H2 H无穷
  14. 网络存储技术Windows server 2012 (项目二十二 远程异地灾备中心的部署)
  15. python3字典的应用方法及技巧
  16. 网易相册助手--批量上传下载好帮手
  17. 服务器RAID5 18T 磁盘挂载
  18. Android Socket连接(模拟心跳包,断线重连,发送数据等)
  19. libVLC 添加图片和文本水印
  20. 仿百度搜索热点列表的实现

热门文章

  1. Nmap——端口扫描
  2. 我的第一个项目(员工绩效管理系统 步骤超级详细---未完待更...)
  3. java企业绩效_员工绩效管理系统,基于SSM框架下的JAVA系统
  4. 基于javaweb+jsp的员工绩效考核管理系统(JavaWeb JSP MySQL Servlet SSM SpringBoot Bootstrap Ajax)
  5. Google Play 应用迁移
  6. 网页唤起QQ临时会话
  7. 建议阅读的投资经典55本
  8. com.android.phone lg g3,详细的lg g3 root教程与方法
  9. 番茄花园GhostXP sp3快速装机版2012.03
  10. uploadify php demo,uploadify HTML5 版本,多图上传