车牌识别

介绍

opencv数字图像处理,pca+svm车牌识别

说明

该小工程是我为了学习支持向量机算法作为练习的,但继SVM的理论后,更多的困难体在数字图像处理上,比如车牌检测,字符分割,不过在坚持下都已被解决,希望大家能加入一起体验机器学习与数字图像处理
车牌识别的流程:
1检测到车牌
2将车牌的字符分割出来
3字符逐个使用SVM模型识别
具体的原理(包括SVM超平面推导公式)位于文件夹“theory”,格式为word

安装教程

python3
安装需要的库即可:
numpy
pandas
opencv
scikit-learn

eg:pip install scikit-learn -i https://pypi.tuna.tsinghua.edu.cn/simple

使用说明

首先可以直接运行demo.py,直接查看车牌识别的结果
作为学习,大家可以一步一步参与:
1.SVM:pixeltocsv将训练图片写入csv
svmtrain训练svm模型,其中用pca进行降维,模型保存为.m格式
loadsvm作为使用模型的接口
2.locate,车牌定位:高斯滤波,中值滤波;
Sobel算子边缘检测,二值化;
膨胀一次,腐蚀一次;
根据车牌长高比范围查找轮廓,将轮廓裁剪出来
3.spli,字符分割:反复滤波获得不含杂质(垂直投影不连续)的二值图像,
根据字符像素的脉冲信号起止分割字符
4.字符逐个使用SVM识别

注意如果是opencv版本差异带来的问题:
image_process,contours, hierarchy = cv2.findContours(img, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
改为
contours, hierarchy = cv2.findContours(img, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)即可
由于训练集只有数字和英文,所以不能识别车牌的中文字符

demo结果

输入图片

字符分割后


输出结果,数据集只有英文与数字,所以不识别中文

SVM原理:
首先,识别的方法是很多的,比如对于提取出来的一个个数字,用一个softmax网络就可以达到目的,CNN的正确率会更高,这个小小project选择svm进行分类主要是为了体验一下深度学习之前的最受好评的机器学习算法。
以下直接贴我写的文档内容,打字太累了:
做这个小项目的初衷是为了体验在深度学习出现前最流行的SVM,但是数字图像处理真的让我够头疼的,目前车牌字符分割上还存在一定问题,后续版本有待改进

车牌定位:

import cv2
import numpy as npdef preprocess(gray):# # 直方图均衡化# equ = cv2.equalizeHist(gray)# 高斯平滑gaussian = cv2.GaussianBlur(gray, (3, 3), 0, 0, cv2.BORDER_DEFAULT)# 中值滤波median = cv2.medianBlur(gaussian, 5)#cv2.imshow('gaussian&media', median)#cv2.waitKey(0)# Sobel算子,X方向求梯度sobel = cv2.Sobel(median, cv2.CV_8U, 1, 0, ksize=3)# 二值化ret, binary = cv2.threshold(sobel, 170, 255, cv2.THRESH_BINARY)#print("阈值:",ret)#cv2.imshow('binary', binary)#cv2.waitKey(0)# 膨胀和腐蚀操作的核函数element1 = cv2.getStructuringElement(cv2.MORPH_RECT, (9, 1))element2 = cv2.getStructuringElement(cv2.MORPH_RECT, (9, 7))# 膨胀一次,让轮廓突出dilation = cv2.dilate(binary, element2, iterations=1)# 腐蚀一次,去掉细节erosion = cv2.erode(dilation, element1, iterations=1)#cv2.imshow('erosion', erosion)#cv2.waitKey(0)# 再次膨胀,让轮廓明显一些dilation2 = cv2.dilate(erosion, element2, iterations=3)#cv2.imshow('dilation2', dilation2)#cv2.waitKey(0)return dilation2def findPlateNumberRegion(img,ImageArea):region = []# 查找轮廓,contours记录了每一个闭合的轮廓索引#image_process,contours, hierarchy = cv2.findContours(img, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)contours, hierarchy = cv2.findContours(img, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)#print("轮廓数:",len(contours))#print("原图面积",ImageArea)edge=ImageArea*0.016#print("阈值:",edge)# 筛选面积小的for i in range(len(contours)):cnt = contours[i]# 计算该轮廓的面积area = cv2.contourArea(cnt)#print("面积:",area)# 面积小的都筛选掉if (area < edge):continue# 轮廓近似,作用很小epsilon = 0.001 * cv2.arcLength(cnt, True)approx = cv2.approxPolyDP(cnt, epsilon, True)# 找到最小的矩形包围轮廓,该矩形可能有方向#返回矩形的中心点坐标,长宽,旋转角度[-90,0)rect = cv2.minAreaRect(cnt)#print("rect is: ",rect)# box是四个点的坐标box = cv2.boxPoints(rect)#取整box = np.int0(box)# 计算高和长height = abs(box[0][1] - box[2][1])width = abs(box[0][0] - box[2][0])# 车牌正常情况下长高比在2.7-5之间ratio = float(width) / float(height)#print("ratio: ",ratio)if (ratio > 5 or ratio < 2):continueregion.append(box)print("车牌区域:",region)print("车牌个数:",len(region))return regiondef detect(img):"""截取车牌"""# 转化成灰度图gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)#输入图像面积height, width = img.shape[:2]ImageArea=height*width# 形态学变换的预处理dilation = preprocess(gray)# 查找车牌区域region = findPlateNumberRegion(dilation,ImageArea)# 用绿线画出这些找到的轮廓for boxf in region:cv2.drawContours(img, [boxf], 0, (0, 0, 0), 2)ys = [boxf[0, 1], boxf[1, 1], boxf[2, 1], boxf[3, 1]]xs = [boxf[0, 0], boxf[1, 0], boxf[2, 0], boxf[3, 0]]ys_sorted_index = np.argsort(ys)xs_sorted_index = np.argsort(xs)x1 = boxf[xs_sorted_index[0], 0]x2 = boxf[xs_sorted_index[3], 0]y1 = boxf[ys_sorted_index[0], 1]y2 = boxf[ys_sorted_index[3], 1]img_org2 = img.copy()img_plate = img_org2[y1:y2, x1:x2]#cv2.imshow('number plate', img_plate)#cv2.imwrite("./plate.png",img_plate)#cv2.waitKey(0)#cv2.destroyAllWindows()return img_plateif __name__ == '__main__':imagePath = './car1.png'img = cv2.imread(imagePath)cv2.imshow('img', img)plate=detect(img)

字符分割:

import numpy as np
import cv2def preprocess(img):gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)# 高斯平滑gaussian = cv2.GaussianBlur(gray, (3, 3), 0, 0, cv2.BORDER_DEFAULT)# 中值滤波median = cv2.medianBlur(gaussian, 5)#cv2.imshow('gaussian&media', median)#cv2.waitKey(0)# 二值化ret, binary = cv2.threshold(gaussian, 225, 255, cv2.THRESH_BINARY)#ret, binary = cv2.threshold(sobel, 90, 255, cv2.THRESH_BINARY)#print("阈值:",ret)#cv2.imshow('binary', binary)#cv2.waitKey(0)# 膨胀和腐蚀操作的核函数element1 = cv2.getStructuringElement(cv2.MORPH_RECT, (9, 1))element2 = cv2.getStructuringElement(cv2.MORPH_RECT, (9, 7))# 膨胀一次,让轮廓突出dilation = cv2.dilate(binary, element2, iterations=1)# 腐蚀一次,去掉细节erosion = cv2.erode(dilation, element1, iterations=1)#cv2.imshow('erosion', erosion)#cv2.waitKey(0)dilation2 = cv2.dilate(erosion, element2, iterations=1)#cv2.imshow('dilation2', dilation2)#cv2.waitKey(0)return binary,dilation2def pickpoint(img):height, width = img.shape[:2]ImageArea=height*width# 查找轮廓,contours记录了每一个闭合的轮廓索引#image_process,contours, hierarchy = cv2.findContours(img, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)contours, hierarchy = cv2.findContours(img, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)#print("轮廓数:",len(contours))#print("原图面积",ImageArea)edgemax=ImageArea*0.0036#print("阈值:",edgemax)# 筛选面积小的for i in range(len(contours)):cnt = contours[i]# 计算该轮廓的面积area = cv2.contourArea(cnt)#print("面积:",area)# 面积小的都筛选掉if (area < edgemax):rect = cv2.minAreaRect(cnt)#print("rect is: ", rect)# box是四个点的坐标box = cv2.boxPoints(rect)box = np.int0(box)#print("box",box)img=cv2.drawContours(img, [box], -1, (0, 0, 255), thickness=-1)#cv2.imshow("pick",img)#cv2.waitKey(0)#腐蚀一次element1 = cv2.getStructuringElement(cv2.MORPH_RECT, (9, 1))img = cv2.erode(img, element1, iterations=1)#cv2.imshow("erimg", img)#cv2.waitKey(0)return imgdef find_end(start,arg,black,white,width,black_max,white_max):"""找到每个脉冲的终止"""end=start+1for m in range(start+1,width-1):if (black[m] if arg else white[m])>(0.95*black_max if arg else 0.95*white_max):end=mbreakreturn enddef cut(thresh,binary):char=[]white=[]black=[]height=thresh.shape[0]width=thresh.shape[1]print('height',height)print('width',width)white_max=0black_max=0#计算每一列的黑白像素总和for i in range(width):line_white=0line_black=0for j in range(height):if thresh[j][i]==255:line_white+=1if thresh[j][i]==0:line_black+=1white_max=max(white_max,line_white)black_max=max(black_max,line_black)white.append(line_white)black.append(line_black)#print('white',white)#print('black',black)#arg为true表示黑底白字,False为白底黑字arg=Trueif black_max<white_max:arg=Falsen=1while n<width-2:n+=1#判断是白底黑字还是黑底白字  0.05参数对应上面的0.95 可作调整if(white[n] if arg else black[n])>(0.05*white_max if arg else 0.05*black_max):start=nend=find_end(start,arg,black,white,width,black_max,white_max)n=endif end-start>5:cj=binary[1:height,start:end]#左右填充cjwidth = cj.shape[1]cjheight=cj.shape[0]cj=cv2.copyMakeBorder(cj,0,0,int(cjwidth*0.2),int(cjwidth*0.2),cv2.BORDER_CONSTANT, value=0)#上下裁剪,因为要适应到数据集cjwidth = cj.shape[1]length=int(cjheight*0.25)cj=cj[length:cjheight-length,0:cjwidth]#平滑cj = cv2.GaussianBlur(cj, (3, 3), 0, 0, cv2.BORDER_DEFAULT)# 均值平滑cj = cv2.blur(cj, (3, 5))#直方图均衡化cj=cv2.equalizeHist(cj)#二值化扩大亮度ret, cj = cv2.threshold(cj, 60, 255, cv2.THRESH_BINARY)cj = cv2.GaussianBlur(cj, (3, 3), 0, 0, cv2.BORDER_DEFAULT)cj = cv2.blur(cj, (3, 5))char.append(cj)#print("result/%s.jpg" % (n))#cv2.imshow('cutlicense',cj)#cv2.waitKey(0)return charif __name__ == '__main__':imagePath = './plate.png'img = cv2.imread(imagePath)cv2.imshow('img', img)binary,dilation2=preprocess(img)thresh=pickpoint(dilation2)charlist=cut(thresh,binary)cv2.waitKey(0)cv2.destroyAllWindows()

SVM训练:

import pandas as pd
from sklearn.decomposition import PCA
from sklearn import svm
from sklearn.externals import joblib
import time
from sklearn.utils import shuffleif __name__ =="__main__":data = pd.read_csv('./train.csv')data = shuffle(data)train_num = 5000test_num = 7000train_data = data.values[0:train_num,1:]train_label = data.values[0:train_num,0]test_data = data.values[train_num:test_num,1:]test_label = data.values[train_num:test_num,0]t = time.time()#PCA降维pca = PCA(n_components=0.8, whiten=True)print('start pca...')train_x = pca.fit_transform(train_data)test_x = pca.transform(test_data)print(train_x.shape)# svm训练print('start svc...')svc = svm.SVC(kernel = 'rbf', C = 10)svc.fit(train_x,train_label)pre = svc.predict(test_x)#保存模型joblib.dump(svc, 'model.m')joblib.dump(pca, 'pca.m')# 计算准确率score = svc.score(test_x, test_label)"""start pca...(5000, 21)start svc...准确率:0.980500,花费时间:1.99s"""print(u'准确率:%f,花费时间:%.2fs' % (score, time.time() - t))

Demo:

import locate.locateplate as locateplate
import split.splitarea as splitarea
import svm.loadsvc as loadsvc
import cv2class Demo():def __init__(self,img_path,svc_path,pca_path):self.img_path=img_pathself.svc_path=svc_pathself.pca_path=pca_pathdef run(self):#车牌定位img = cv2.imread(self.img_path)cv2.imshow("car",img)plate=locateplate.detect(img)#字符分割binary,dilation=splitarea.preprocess(plate)thresh = splitarea.pickpoint(dilation)charlist = splitarea.cut(thresh,binary)#加载svm模型svc, pca = loadsvc.load_model(self.svc_path,self.pca_path)string=[]#每个字符进行识别for i in range(len(charlist)):name="result{}".format(str(i))cv2.imshow(name,charlist[i])#没有中文数据集,所以不进行识别中文if(i==0):continuechar=cv2.resize(charlist[i], (20, 20), interpolation=cv2.INTER_CUBIC)test=char.reshape(1,400)test_x = pca.transform(test)pre = svc.predict(test_x)string.append(loadsvc.nameindex(pre))print("车牌非中文字符:",string)cv2.waitKey(0)if __name__ == '__main__':img_path="./valimg/car.jpg"svc_path="./svm/model.m"pca_path="./svm/pca.m"platedemo=Demo(img_path,svc_path,pca_path)platedemo.run()

能和大家一起学习很开心,Bye~

python车牌识别(包括SVM原理)相关推荐

  1. python车牌识别系统+车辆管理+计费系统(图像识别)django框架 计算机毕业设计

    python车牌识别系统+车辆管理+计费系统(图像识别)django框架 计算机毕业设计 一.开发技术 技术栈:基于Django框架,涉及停车费计算,用户管理,车牌识别(百度云) 功能: [1]用户管 ...

  2. mser python车牌识别_基于MSER与SVM算法的车牌定位识别方法

    基于 MSER 与 SVM 算法的车牌定位识别方法 胡成伟 ; 袁明辉 [期刊名称] <软件> [年 ( 卷 ), 期] 2020(041)002 [摘要] 针对实际车牌识别系统中车牌位置 ...

  3. python车牌识别系统开源代码_python+opencv实现车牌定位功能(实例代码)

    写在前面 HIT大三上学期视听觉信号处理课程中视觉部分的实验三,经过和学长们实验的对比发现每一级实验要求都不一样,因此这里标明了是2019年秋季学期的视觉实验三. 由于时间紧张,代码没有进行任何优化, ...

  4. python车牌识别算法_python实现车牌识别的示例代码

    某天回家之时,听到有个朋友说起他正在做一个车牌识别的项目 于是对其定位车牌的位置算法颇有兴趣,今日有空得以研究,事实上车牌识别算是比较成熟的技术了, 这里我只是简单实现. 我的思路为: 对图片进行一些 ...

  5. 免费直播:1小时带你体验Python车牌识别实战

    Python基础学会了,实战又是爬虫?太枯燥? 别无聊,CSDN学院邀请章秀淞老师开设技术直播课:1小时带你体验车牌识别实战.让你从众多车中,能用Python技术找到夏树上的那辆叔叔的奔驰车牌(玩笑) ...

  6. python车牌识别系统开源代码_汽车牌照识别系统【YOLO+MLP】

    车牌识别系统可以自动检测并识别图像中的车辆牌照,其算法主要包括牌照定位.牌照分割.字符识别等步骤.本文将给出一种基于深度学习的车牌识别系统方案. 要快速掌握开发人工智能系统的技能,推荐汇智网的 机器学 ...

  7. python车牌识别系统开源代码_天津谁做车牌识别系统供应商,伸缩栅栏门_郑州荣锋科技有限公司...

    首页 > 新闻中心 发布时间:2020-11-13 22:54:57 导读:郑州荣锋科技有限公司为您提供天津谁做车牌识别系统供应商,伸缩栅栏门的相关知识与详情: (1)门处于关闭状态,控制器应骆 ...

  8. 免费直播:1 小时带你体验 Python 车牌识别实战

    Python基础学会了,实战又是爬虫?太枯燥? 别无聊,CSDN学院邀请章秀淞老师开设技术直播课:1小时带你体验车牌识别实战.让你从众多车中,能用Python技术找到夏树上的那辆叔叔的奔驰车牌(玩笑) ...

  9. python车牌识别系统开源代码_北京百万庄车牌识别的软件人气火爆

    北京车牌识别厂家直销 北京百万庄车牌识别的软件人气火爆 与字符数据库模板中的标准字符表达形式进行匹配判别,结果输出:将车牌识别的结果以文本格式输出,以上就是车牌识别系统的工作原理,希望能够帮助大家更好 ...

  10. python车牌识别系统抬杆_昆明车牌识别自动抬杆系统

    您当前的位置:首页 » 供应产品 » 昆明车牌识别自动抬杆系统 昆明车牌识别自动抬杆系统 点击图片查看大图 产品/服务: 浏览次数:679车牌识别自动抬杆系统 规 格: 标准 品 牌: 交安通 单 价 ...

最新文章

  1. 大数据应用开发八大基本原则
  2. IB客座主编(一)--安普布线亚太区业务总监黎启枝
  3. c++runtime error单调栈
  4. jdk8中java.util.concurrent包分析
  5. python扩展库简介_python非官方扩展库
  6. 《OSPF和IS-IS详解》一2.4 理解内部BGP
  7. MSAgent 详细解说(上)
  8. 西瓜数据集的各种版本,比如说2.0,3.0,4.0都在这
  9. 【阿里云镜像】更新阿里巴巴开源镜像站镜像——Ubuntu镜像
  10. 什么相片可以两张弄成一张_美图秀秀怎么把两张图片合成一张?美图秀秀两张图片融合方法汇总...
  11. 关于pdms中设备参数模板的更新PML代码
  12. Java实现身份证号合法性校验(包含港澳台地区)
  13. JAVA就业培训班一周有感杂记
  14. ps4看直播 HTML,ps4直播教学 怎么样才能直播
  15. iphonex 序列号_iPhoneX如何查看手机序列号?三种查看方法全教给你!
  16. MySQL(九):InnoDB 表空间(Tables)
  17. 区块链将如何彻底改变自动驾驶
  18. 攻防世界forgot
  19. android桌面悬浮窗,Android桌面悬浮窗
  20. 数据库中删除重复数据并保留一条。

热门文章

  1. 从《达芬奇的人生密码》看艺工交叉
  2. 美图秀秀一寸照片的制作
  3. 肌营养不良最新研究进展(2021年)
  4. 一个抄底指标(52周新低的股票占比)
  5. 架构师之路(二)-概念架构
  6. java 咖啡 典故,解读六大咖啡种类 常见咖啡种类及特点、背后典故、历史和定义...
  7. 用EXCEL批量改变文件的名称
  8. python爬虫(三)爬取js动态页面之b站粉丝数观看数点赞数爬取
  9. B站粉丝数监控(Python实现)
  10. Word限制编辑忘记密码怎么解锁