0


基于Python_opencv的车牌识别系统

基于python_opencv的车牌识别系统

一、说明

根据现有的车牌识别系统,本人对代码进行了优化,原有功能:

1、对图片中的车牌号进行识别,并对车牌所属地可视化
2、将识别出的车牌号、车牌所属地等信息导出Excel表格
3、根据QtDesinger设计GUI界面,将程序系统化

添加功能:调用摄像头实时识别捕捉到的车牌信息,并可视化

链接: 最新代码传送门

下图分别是调用摄像头和直接识别图像的画面:
在这里插入图片描述
在这里插入图片描述

二、具体实现流程

整个项目为模块化处理,按文件分为:

  1. Recognition.py(识别模块)
  2. UI_main(主函数及UI模块)
  3. SVM训练模块
  4. 路由配置模块

Recognition模块

此模块问本项目的核心,主要包含的功能有:
1、读取图像
使用

cv2.imdecode()

函数将图片文件转换成流数据,赋值到内存缓存中,便于后续图像操作。使用

cv2.resize()

函数对读取的图像进行缩放,以免图像过大导致识别耗时过长。

def__imreadex(self, filename):return cv2.imdecode(np.fromfile(filename, dtype=np.uint8), cv2.IMREAD_COLOR)def__point_limit(self, point):if point[0]<0:
            point[0]=0if point[1]<0:
            point[1]=0

2、图像预处理

def__preTreatment(self, car_pic):iftype(car_pic)==type("openc"):
            img = self.__imreadex(car_pic)else:
            img = car_pic
        pic_hight, pic_width = img.shape[:2]if pic_width > self.MAX_WIDTH:
            resize_rate = self.MAX_WIDTH / pic_width
            img = cv2.resize(img,(self.MAX_WIDTH,int(pic_hight * resize_rate)),
                             interpolation=cv2.INTER_AREA)# 图片分辨率调整# cv2.imshow('Image', img)

3、利用投影法,根据设定的阈值和图片直方图,找出波峰,用于分隔字符,得到逐个字符图片

def__find_waves(self, threshold, histogram):
        up_point =-1# 上升点
        is_peak =Falseif histogram[0]> threshold:
            up_point =0
            is_peak =True
        wave_peaks =[]for i, x inenumerate(histogram):if is_peak and x < threshold:if i - up_point >2:
                    is_peak =False
                    wave_peaks.append((up_point, i))elifnot is_peak and x >= threshold:
                is_peak =True
                up_point = i
        if is_peak and up_point !=-1and i - up_point > 
            wave_peaks.append((up_point, i))return wave_peaks

    def__seperate_card(self, img, waves):
        part_cards =[]for wave in waves:
            part_cards.append(img[:, wave[0]:wave[1]])return part_cards

4、高斯去噪
使用

cv2.GaussianBlur()

进行高斯去噪。使

cv2.morphologyEx()

函数进行开运算,再使用

cv2.addWeighted()

函数将运算结果与原图像做一次融合,从而去掉孤立的小点,毛刺等噪声。

if blur >0:
            img = cv2.GaussianBlur(img,(blur, blur),0)
        oldimg = img
        img = 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);# 与上一次开运算结果融合

5、排除不是车牌的矩形区域

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_width
            wh_ratio = area_width / area_height
            # print('宽高比:',wh_ratio)# 要求矩形区域长宽比在2到5.5之间,2到5.5是车牌的长宽比,其余的矩形排除if wh_ratio >2and wh_ratio <5.5:
                car_contours.append(rect)# box = cv2.boxPoints(rect)# box = np.int0(box)# 框出所有可能的矩形# oldimg = cv2.drawContours(img, [box], 0, (0, 0, 255), 2)# cv2.imshow("Test",oldimg )

6、分割字符并识别车牌文字
使用

cv2.threshold()

函数进行二值化处理,再使用

cv2.Canny()

函数找到各区域边缘,使用

cv2.morphologyEx()

cv2.morphologyEx()

两个函数分别进行一次开运算(先腐蚀运算,再膨胀运算)和一个闭运算(先膨胀运算,再腐蚀运算),去掉较小区域,同时填平小孔,弥合小裂缝。将车牌位置凸显出来

def__identification(self, card_imgs, colors,model,modelchinese):# 识别车牌中的字符
        result ={}
        predict_result =[]
        roi =None
        card_color =Nonefor i, color inenumerate(colors):if color in("blue","yellow","green"):
                card_img = card_imgs[i]# old_img = card_img# 做一次锐化处理
                kernel = np.array([[0,-1,0],[-1,5,-1],[0,-1,0]], np.float32)# 锐化
                card_img = cv2.filter2D(card_img,-1, kernel=kernel)# cv2.imshow("custom_blur", card_img)# RGB转GARY
                gray_img = cv2.cvtColor(card_img, cv2.COLOR_BGR2GRAY)# cv2.imshow('gray_img', gray_img)# 黄、绿车牌字符比背景暗、与蓝车牌刚好相反,所以黄、绿车牌需要反向if color =="green"or color =="yellow":
                    gray_img = cv2.bitwise_not(gray_img)# 二值化
                ret, gray_img = cv2.threshold(gray_img,0,255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)# cv2.imshow('gray_img', gray_img)# 查找水平直方图波峰
                x_histogram = np.sum(gray_img, axis=1)# 最小值
                x_min = np.min(x_histogram)# 均值
                x_average = np.sum(x_histogram)/ x_histogram.shape[0]
                x_threshold =(x_min + x_average)/2
                wave_peaks = self.__find_waves(x_threshold, x_histogram)iflen(wave_peaks)==0:continue# 认为水平方向,最大的波峰为车牌区域
                wave =max(wave_peaks, key=lambda x: x[1]- x[0])
                gray_img = gray_img[wave[0]:wave[1]]# cv2.imshow('gray_img', gray_img)# 查找垂直直方图波峰
                row_num, col_num = gray_img.shape[:2]# 去掉车牌上下边缘1个像素,避免白边影响阈值判断
                gray_img = gray_img[1:row_num -1]# cv2.imshow('gray_img', gray_img)
                y_histogram = np.sum(gray_img, axis=0)
                y_min = np.min(y_histogram)
                y_average = np.sum(y_histogram)/ y_histogram.shape[0]
                y_threshold =(y_min + y_average)/5# U和0要求阈值偏小,否则U和0会被分成两半

                wave_peaks = self.__find_waves(y_threshold, y_histogram)# print(wave_peaks)# for wave in wave_peaks:#    cv2.line(card_img, pt1=(wave[0], 5), pt2=(wave[1], 5), color=(0, 0, 255), thickness=2)# 车牌字符数应大于6iflen(wave_peaks)<=6:#   print(wave_peaks)continue

                wave =max(wave_peaks, key=lambda x: x[1]- x[0])
                max_wave_dis = wave[1]- wave[0]# 判断是否是左侧车牌边缘if wave_peaks[0][1]- wave_peaks[0][0]< max_wave_dis /3and wave_peaks[0][0]==0:
                    wave_peaks.pop(0)# 组合分离汉字
                cur_dis =0for i, wave inenumerate(wave_peaks):if wave[1]- wave[0]+ cur_dis > max_wave_dis *0.6:breakelse:
                        cur_dis += wave[1]- wave[0]if i >0:
                    wave =(wave_peaks[0][0], wave_peaks[i][1])
                    wave_peaks = wave_peaks[i +1:]
                    wave_peaks.insert(0, wave)# 去除车牌上的分隔点
                point = wave_peaks[2]if point[1]- point[0]< max_wave_dis /3:
                    point_img = gray_img[:, point[0]:point[1]]if np.mean(point_img)<255/5:
                        wave_peaks.pop(2)iflen(wave_peaks)<=6:# print("peak less 2:", wave_peaks)continue# print(wave_peaks)# 分割牌照字符
                part_cards = self.__seperate_card(gray_img, wave_peaks)# 分割输出#for i, part_card in enumerate(part_cards):#    cv2.imshow(str(i), part_card)# 识别for i, part_card inenumerate(part_cards):# 可能是固定车牌的铆钉if np.mean(part_card)<255/5:continue
                    part_card_old = part_card
                    w =abs(part_card.shape[1]- self.SZ)//2# 边缘填充
                    part_card = cv2.copyMakeBorder(part_card,0,0, w, w, cv2.BORDER_CONSTANT, value=[0,0,0])# cv2.imshow('part_card', part_card)# 图片缩放(缩小)
                    part_card = cv2.resize(part_card,(self.SZ, self.SZ), interpolation=cv2.INTER_AREA)# cv2.imshow('part_card', part_card)

                    part_card = SVM_Train.preprocess_hog([part_card])if i ==0:# 识别汉字
                        resp = self.modelchinese.predict(part_card)# 匹配样本
                        charactor = self.provinces[int(resp[0])- self.PROVINCE_START]# print(charactor)else:# 识别字母
                        resp = self.model.predict(part_card)# 匹配样本
                        charactor =chr(resp[0])# print(charactor)# 判断最后一个数是否是车牌边缘,假设车牌边缘被认为是1if charactor =="1"and i ==len(part_cards)-1:if color =='blue'andlen(part_cards)>7:if part_card_old.shape[0]/ part_card_old.shape[1]>=7:# 1太细,认为是边缘continueelif color =='blue'andlen(part_cards)>7:if part_card_old.shape[0]/ part_card_old.shape[1]>=7:# 1太细,认为是边缘continueelif color =='green'andlen(part_cards)>8:if part_card_old.shape[0]/ part_card_old.shape[1]>=7:# 1太细,认为是边缘continue
                    predict_result.append(charactor)
                roi = card_img  # old_img
                card_color = color
                breakreturn predict_result, roi, card_color  # 识别到的字符、定位的车牌图像、车牌颜色

UI_main模块

此模块主要包含UI界面的设计的控件,图片识别的入口函数,摄像头识别入口函数,Excel表格生成函数:

1、UI界面主类

classUi_MainWindow(object):def__init__(self):
        self.RowLength =0
        self.Data =[['文件名称','录入时间','车牌号码','车牌类型','识别耗时','车牌信息']]defsetupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(1213,680)
        MainWindow.setFixedSize(1213,680)# 设置窗体固定大小
        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,10,511,491))
        self.scrollArea.setWidgetResizable(False)
        self.scrollArea.setObjectName("scrollArea")
        self.scrollAreaWidgetContents = QtWidgets.QWidget()
        self.scrollAreaWidgetContents.setGeometry(QtCore.QRect(10,10,509,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,441))
        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(6)
        self.tableWidget.setColumnWidth(0,106)# 设置1列的宽度
        self.tableWidget.setColumnWidth(1,106)# 设置2列的宽度
        self.tableWidget.setColumnWidth(2,106)# 设置3列的宽度
        self.tableWidget.setColumnWidth(3,106)# 设置4列的宽度
        self.tableWidget.setColumnWidth(4,106)# 设置5列的宽度
        self.tableWidget.setColumnWidth(5,106)# 设置6列的宽度
        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(10,50,80,30))
        self.pushButton_2.setObjectName("pushButton_2")

        self.pushButton = QtWidgets.QPushButton(self.scrollAreaWidgetContents_4)
        self.pushButton.setGeometry(QtCore.QRect(10,90,80,30))
        self.pushButton.setObjectName("pushButton")

        self.pushButton_3 = QtWidgets.QPushButton(self.scrollAreaWidgetContents_4)
        self.pushButton_3.setGeometry(QtCore.QRect(100,50,50,70))
        self.pushButton_3.setObjectName("pushButton_3")

        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_2.clicked.connect(self.__writeFiles)# 设置点击事件
        self.pushButton_3.clicked.connect(self.__openVideo)#设置事件

        self.retranslateUi(MainWindow)
        QtCore.QMetaObject.connectSlotsByName(MainWindow)
        self.ProjectPath = os.getcwd()# 获取当前工程文件位置defretranslateUi(self, MainWindow):
        _translate = QtCore.QCoreApplication.translate
        MainWindow.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.pushButton_3.setText(_translate("MainWindow","摄像"))
        self.label_4.setText(_translate("MainWindow","控制面板:"))
        self.scrollAreaWidgetContents_1.show()

2、识别入口函数

def__vlpr(self, path):
        PR = PlateRecognition()
        result = PR.VLPR(path)return result

3、写入及导出Excel表格文件

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(str(result['UseTime'])+'秒'))
        self.tableWidget.setItem(self.RowLength -1,3, QTableWidgetItem(result['Number']))
        self.tableWidget.setItem(self.RowLength -1,4, QTableWidgetItem(result['Type']))if result['Type']=='蓝色牌照':
            self.tableWidget.item(self.RowLength -1,4).setBackground(QBrush(QColor(3,128,255)))elif result['Type']=='绿色牌照':
            self.tableWidget.item(self.RowLength -1,4).setBackground(QBrush(QColor(98,198,148)))elif result['Type']=='黄色牌照':
            self.tableWidget.item(self.RowLength -1,4).setBackground(QBrush(QColor(242,202,9)))
        self.tableWidget.setItem(self.RowLength -1,5, QTableWidgetItem(result['From']))# 显示识别到的车牌位置
        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))def__writexls(self, DATA, path):
        wb = xlwt.Workbook();
        ws = wb.add_sheet('Data');for i, Data inenumerate(DATA):for j, data inenumerate(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)+'\n')
        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)

4、图片识别入口

def__openimage(self):
        path, filetype = QFileDialog.getOpenFileName(None,"选择文件", self.ProjectPath,"JPEG Image (*.jpg);;PNG Image (*.png);;JFIF Image (*.jfif)")# ;;All Files (*)if path =="":# 未选择文件return
        filename = path.split('/')[-1]# 尺寸适配
        size = cv2.imdecode(np.fromfile(path, dtype=np.uint8), cv2.IMREAD_COLOR).shape
        if size[0]/ size[1]>1.0907:
            w = size[1]* self.label.height()/ size[0]
            h = self.label.height()
            jpg = QtGui.QPixmap(path).scaled(w, h)elif size[0]/ size[1]<1.0907:
            w = self.label.width()
            h = size[0]* self.label.width()/ size[1]
            jpg = QtGui.QPixmap(path).scaled(w, h)else:
            jpg = QtGui.QPixmap(path).scaled(self.label.width(), self.label.height())

        self.label.setPixmap(jpg)#保存jpg
        result = self.__vlpr(path)#识别if result isnotNone:
            self.Data.append([filename, result['InputTime'], result['Number'], result['Type'],str(result['UseTime'])+'秒',
                 result['From']])
            self.__show(result, filename)else:
            QMessageBox.warning(None,"Error","无法识别此图像!", QMessageBox.Yes)

5、摄像头识别入口

def__openVideo(self):
        cap = cv2.VideoCapture(0)whileTrue:
            success, img = cap.read()
            img1 = cv2.flip(img,1)
            cv2.imshow("VideoData", img1)

            k = cv2.waitKey(1)if cv2.getWindowProperty('VideoData', cv2.WND_PROP_VISIBLE)<1:breakelif k ==ord("s"):
                cv2.imwrite("index2.jpg", img1)#读取摄像头
                cv2.destroyAllWindows()
        cap.release()

6、重写MainWindow窗口

classMainWindow(QtWidgets.QMainWindow):defcloseEvent(self, event):
        reply = QtWidgets.QMessageBox.question(self,'提示',"是否要退出程序?\n提示:退出后将丢失所有识别数据",
                                               QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No,
                                               QtWidgets.QMessageBox.No)if reply == QtWidgets.QMessageBox.Yes:
            event.accept()else:
            event.ignore()

SVM训练模块

此模块主要用于对模型的准确性进行训练,包含字符中英文、数字的识别、图片尺寸的训练,最后将模型保存在svmchinese.dat中:

import cv2
import os
import numpy as np
from numpy.linalg import norm
from args import args

classStatModel(object):defload(self, fn):
        self.model = self.model.load(fn)defsave(self, fn):
        self.model.save(fn)classSVM(StatModel):def__init__(self, C=1, gamma=0.5):
        self.model = cv2.ml.SVM_create()
        self.model.setGamma(gamma)
        self.model.setC(C)
        self.model.setKernel(cv2.ml.SVM_RBF)
        self.model.setType(cv2.ml.SVM_C_SVC)# 不能保证包括所有省份# 训练svmdeftrain(self, samples, responses):
        self.model.train(samples, cv2.ml.ROW_SAMPLE, responses)# 字符识别defpredict(self, samples):
        r = self.model.predict(samples)return r[1].ravel()# 定义参数
SZ = args.Size  # 训练图片长宽
MAX_WIDTH = args.MAX_WIDTH  # 原始图片最大宽度
Min_Area = args.Min_Area  # 车牌区域允许最大面积
PROVINCE_START = args.PROVINCE_START
provinces = args.provinces

# 来自opencv的sample,用于svm训练defdeskew(img):
    m = cv2.moments(img)ifabs(m['mu02'])<1e-2:return img.copy()
    skew = m['mu11']/ m['mu02']
    M = np.float32([[1, skew,-0.5* SZ * skew],[0,1,0]])
    img = cv2.warpAffine(img, M,(SZ, SZ), flags=cv2.WARP_INVERSE_MAP | cv2.INTER_LINEAR)return img

# 来自opencv的sample,用于svm训练defpreprocess_hog(digits):
    samples =[]for img in digits:
        gx = cv2.Sobel(img, cv2.CV_32F,1,0)
        gy = cv2.Sobel(img, cv2.CV_32F,0,1)
        mag, ang = cv2.cartToPolar(gx, gy)
        bin_n =16bin= np.int32(bin_n * ang /(2* np.pi))
        bin_cells =bin[:10,:10],bin[10:,:10],bin[:10,10:],bin[10:,10:]
        mag_cells = mag[:10,:10], mag[10:,:10], mag[:10,10:], mag[10:,10:]
        hists =[np.bincount(b.ravel(), m.ravel(), bin_n)for b, m inzip(bin_cells, mag_cells)]
        hist = np.hstack(hists)# transform to Hellinger kernel
        eps =1e-7
        hist /= hist.sum()+ eps
        hist = np.sqrt(hist)
        hist /= norm(hist)+ eps

        samples.append(hist)return np.float32(samples)deftrain_svm(path):# 识别英文字母和数字
    Model = SVM(C=1, gamma=0.5)# 识别中文
    Modelchinese = SVM(C=1, gamma=0.5)# 英文字母和数字部分训练
    chars_train =[]
    chars_label =[]for root, dirs, files in os.walk(os.path.join(path,'chars')):iflen(os.path.basename(root))>1:continue
        root_int =ord(os.path.basename(root))for filename in files:print('input:{}'.format(filename))
            filepath = os.path.join(root, filename)
            digit_img = cv2.imread(filepath)
            digit_img = cv2.cvtColor(digit_img, cv2.COLOR_BGR2GRAY)
            chars_train.append(digit_img)
            chars_label.append(root_int)

    chars_train =list(map(deskew, chars_train))
    chars_train = preprocess_hog(chars_train)
    chars_label = np.array(chars_label)
    Model.train(chars_train, chars_label)ifnot os.path.exists("svm.dat"):# 保存模型
        Model.save("svm.dat")else:# 更新模型
        os.remove("svm.dat")
        Model.save("svm.dat")# 中文部分训练
    chars_train =[]
    chars_label =[]for root, dirs, files in os.walk(os.path.join(path,'charsChinese')):ifnot os.path.basename(root).startswith("zh_"):continue
        pinyin = os.path.basename(root)
        index = provinces.index(pinyin)+ PROVINCE_START +1# 1是拼音对应的汉字for filename in files:print('input:{}'.format(filename))
            filepath = os.path.join(root, filename)
            digit_img = cv2.imread(filepath)
            digit_img = cv2.cvtColor(digit_img, cv2.COLOR_BGR2GRAY)
            chars_train.append(digit_img)
            chars_label.append(index)
    chars_train =list(map(deskew, chars_train))
    chars_train = preprocess_hog(chars_train)
    chars_label = np.array(chars_label)
    Modelchinese.train(chars_train, chars_label)ifnot os.path.exists("svmchinese.dat"):# 保存模型
        Modelchinese.save("svmchinese.dat")else:# 更新模型
        os.remove("svmchinese.dat")
        Modelchinese.save("svmchinese.dat")if __name__ =='__main__':
    train_svm('train')print('完成')

路由配置模块

from _collections import OrderedDict
# 导入Flask类from flask import Flask, request, jsonify
from json_utils import jsonify
import numpy as np
import cv2
import time
from collections import OrderedDict
from Recognition import PlateRecognition

# 实例化
app = Flask(__name__)
PR = PlateRecognition()# 设置编码-否则返回数据中文时候-乱码
app.config['JSON_AS_ASCII']=False# route()方法用于设定路由;类似spring路由配置@app.route('/', methods=['POST'])# 在线识别defforecast():# 获取输入数据
    stat = time.time()file= request.files['image']
    img_bytes =file.read()
    image = np.asarray(bytearray(img_bytes), dtype="uint8")
    image = cv2.imdecode(image, cv2.IMREAD_COLOR)
    RES = PR.VLPR(image)if RES isnotNone:
        result = OrderedDict(
            Error=0,
            Errmsg='success',
            InputTime=RES['InputTime'],
            UseTime='{:.2f}'.format(time.time()- stat),# RES['UseTime'],
            Number=RES['Number'],
            From=RES['From'],
            Type=RES['Type'],
            List=RES['List'])else:
        result = OrderedDict(
            Error=1,
            Errmsg='unsuccess')return jsonify(result)if __name__ =='__main__':# app.run(host, port, debug, options)# 默认值:host=127.0.0.1(localhost), port=5000, debug=false
    app.run()# 本地路由地址,局域网下的主机均可通过该地址完成POST请求# app.run(host='192.168.1.100' )# 部署到服务器# from waitress import serve# serve(app, host=' IP  ', port=5000)

本文转载自: https://blog.csdn.net/weixin_51141489/article/details/128565063
版权归原作者 Svan. 所有, 如有侵权,请联系我们删除。

“基于Python_opencv的车牌识别系统”的评论:

还没有评论