OpenCV实例(八)车牌字符识别技术(二)字符识别
车牌字符识别技术(二)字符识别
- 1.字符识别原理及其发展阶段
- 2.字符识别方法
- 3.英文、数字识别
- 4.车牌定位实例
1.字符识别原理及其发展阶段
匹配判别是字符识别的基本思想,与其他模式识别的应用非常类似。字符识别的基本原理就是对字符图像进行预处理、模式表达、判别和字典学习。
字符识别一般可分为三个阶段:
第一阶段为初级阶段,主要是应用一维图像的处理方法实现对二维图像的识别。此阶段主要涉及相关函数的构造以及特征向量的抽取。目前,该阶段的字符识别方法仍然在匹配方法的庞大家族中扮演着很重要的角色。
第二阶段为对基础理论进行相关研究的阶段。细化思想、链码法以及对一些离散图形上的拓扑性研究在这一阶段进行,其中细化思想主要用于结构的分析,链码法主要用于边界的表示。本阶段实现了抽取大范围的孔、凹凸区域、连通性以及抽取局部特征等算法,同时还实现了对K-L展开法“特征抽取理论”作为核心相关工作的研究。
第三阶段为发展阶段。本阶段在依据实际系统的要求以及设备难以提供的条件的基础上提出更为复杂的技术,主要研究工作是将技术与实际结合起来。另外,在以构造解析法以及相关法为主的基础上,许多各具特色且不同类的实用系统得以研究出来。

2.字符识别方法
目前字符识别方法主要有基于神经网络的识别方法、基于特征分析的匹配方法和基于模板的匹配方法。
(1)基于神经网络的识别方法
基于神经网络的识别方法主要包括4个步骤:预处理样本字符、提取字符的特征、对神经网络进行训练、神经网络接受经过相关预处理和特征提取的字符并对这些字符进行识别。
(2)基于特征分析的匹配方法
基于特征分析的匹配方法,主要利用特征平面来进行字符匹配。与其他匹配方法进行比较可知,它不但对噪声具有不明显的反应,而且可以获得效果更好的字符特征。
(3)基于模板的匹配方法
基于模板的匹配方法也是字符识别的一种方法,主要权衡输入模式与标准模式之间的相似程度。因此,从结果来看,输入模式的类别其实也是标准模式,单从与输入模式相似度的程度来讲,这里提到的标准模式最高。对于离散输入模式分类的实现,此方法所起的作用非常明显也非常奏效。
组成汽车牌照的字符大约有50个汉字、20多个英文字符和10个阿拉伯数字,相对而言,字符数比较少,所以可以使用模板匹配法识别这些字符。其中,用于匹配的模板的标准形式可由前面所述的字符制作而成。与其他的字符识别的方法进行比较可知,模板匹配法具有相对来说较为简单的识别过程和较快的字符识别速度,只不过准确率不是很高。

3.英文、数字识别
目前,小波识别法、模板匹配法与神经网络法等常被作为汽车牌照字符识别的主要方法。数字字符是在汽车牌照的字符集中具有最小规模、最简单结构的子集。虽然字母字符相对于数字字符而言并不复杂,但是单从字符的结构上来讲,不难看出车牌字符集中的数字字符要相对简单一些。一般采用模板匹配法来识别字母字符以及数字字符,只是有时采用模板匹配法不一定能取得理想的识别效果,例如字符存在划伤破损、褪色、污迹等问题时。本章采用的匹配模式为两级模板匹配,首先通过一级模板实现对字母数字字符的匹配,然后基于边缘霍斯多夫距离对一级模板匹配不成功的字符进行匹配。
真实的汽车图像的采集主要通过CCD工业相机进行的,输入的汽车牌照的字符图像在经过汽车牌照的定位以及汽车牌照内字符的分割之后形成,其中约有50%的高质量的字符包含在3000个字符组成的字符集中,剩下的汽车牌照内的字符质量都有一定程度的降低。相较于传统的模板匹配法和基于细化图像霍斯多夫距离的模板匹配法,准确率在基于边缘霍斯多夫距离的模板匹配识别方法中表现得更高(为98%,字符的错误识别率只有2%)。
4.车牌定位实例
测试照片:

代码实例:
# -*- coding: utf-8 -*-import cv2
import numpy as npdef stretch(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 imgdef dobinaryzation(img):'''二值化处理函数'''maxi=float(img.max())mini=float(img.min())x=maxi-((maxi-mini)/2)#二值化,返回阈值ret 和 二值化操作后的图像threshret,thresh=cv2.threshold(img,x,255,cv2.THRESH_BINARY)#返回二值化后的黑白图像return threshdef find_rectangle(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(img,afterimg):'''定位车牌号'''contours,hierarchy=cv2.findContours(img,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)#找出最大的三个区域block=[]for c in contours:#找出轮廓的左上点和右下点,由此计算它的面积和长度比r=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,-1for i in range(len(block)):b=afterimg[block[i][0][1]:block[i][0][3],block[i][0][0]:block[i][0][2]]#BGR转HSVhsv=cv2.cvtColor(b,cv2.COLOR_BGR2HSV)#蓝色车牌的范围lower=np.array([100,50,50])upper=np.array([140,255,255])#根据阈值构建掩膜mask=cv2.inRange(hsv,lower,upper)#统计权值w1=0for m in mask:w1+=m/255w2=0for n in w1:w2+=n#选出最大权值的区域if w2>maxweight:maxindex=imaxweight=w2return block[maxindex][0]def find_license(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=stretch(gray_img)'''进行开运算,用来去除噪声'''r=16h=w=r*2+1kernel=np.zeros((h,w),np.uint8)cv2.circle(kernel,(r,r),r,1,-1)#开运算openingimg=cv2.morphologyEx(stretchedimg,cv2.MORPH_OPEN,kernel)#获取差分图,两幅图像做差 cv2.absdiff('图像1','图像2')strtimg=cv2.absdiff(stretchedimg,openingimg)#图像二值化binaryimg=dobinaryzation(strtimg)#canny边缘检测canny=cv2.Canny(binaryimg,binaryimg.shape[0],binaryimg.shape[1])'''消除小的区域,保留大块的区域,从而定位车牌'''#进行闭运算kernel=np.ones((5,19),np.uint8)closingimg=cv2.morphologyEx(canny,cv2.MORPH_CLOSE,kernel)#进行开运算openingimg=cv2.morphologyEx(closingimg,cv2.MORPH_OPEN,kernel)#再次进行开运算kernel=np.ones((11,5),np.uint8)openingimg=cv2.morphologyEx(openingimg,cv2.MORPH_OPEN,kernel)#消除小区域,定位车牌位置rect=locate_license(openingimg,img)return rect,imgdef cut_license(afterimg,rect):'''图像分割函数'''#转换为宽度和高度rect[2]=rect[2]-rect[0]rect[3]=rect[3]-rect[1]rect_copy=tuple(rect.copy())rect=[0,0,0,0]#创建掩膜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_showdef deal_license(licenseimg):'''车牌图片二值化'''#车牌变为灰度图像gray_img=cv2.cvtColor(licenseimg,cv2.COLOR_BGR2GRAY)#均值滤波 去除噪声kernel=np.ones((3,3),np.float32)/9gray_img=cv2.filter2D(gray_img,-1,kernel)#二值化处理ret,thresh=cv2.threshold(gray_img,120,255,cv2.THRESH_BINARY)return threshdef 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.98*black_max if arg else 0.98*white_max):end=mbreakreturn endif __name__=='__main__':img=cv2.imread('car.jpg',cv2.IMREAD_COLOR)#预处理图像rect,afterimg=find_license(img)#框出车牌号cv2.rectangle(afterimg,(rect[0],rect[1]),(rect[2],rect[3]),(0,255,0),2)cv2.imshow('afterimg',afterimg)#分割车牌与背景cutimg=cut_license(afterimg,rect)cv2.imshow('cutimg',cutimg)#二值化生成黑白图thresh=deal_license(cutimg)cv2.imshow('thresh',thresh)cv2.imwrite("cp.jpg",thresh)cv2.waitKey(0)#分割字符'''判断底色和字色'''#记录黑白像素总和white=[]black=[]height=thresh.shape[0] #263width=thresh.shape[1] #400#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=1start=1end=2while n<width-2:n+=1#判断是白底黑字还是黑底白字 0.05参数对应上面的0.95 可作调整if(white[n] if arg else black[n])>(0.02*white_max if arg else 0.02*black_max):start=nend=find_end(start,arg,black,white,width,black_max,white_max)n=endif end-start>5:cj=thresh[1:height,start:end]cv2.imshow('cutlicense',cj)cv2.waitKey(0)cv2.waitKey(0)cv2.destroyAllWindows()
输出结果:

相关文章:
OpenCV实例(八)车牌字符识别技术(二)字符识别
车牌字符识别技术(二)字符识别 1.字符识别原理及其发展阶段2.字符识别方法3.英文、数字识别4.车牌定位实例 1.字符识别原理及其发展阶段 匹配判别是字符识别的基本思想,与其他模式识别的应用非常类似。字符识别的基本原理就是对字符图像进行…...
svn文章五:问题排查与修复 - 出了问题怎么办?SVN故障排除与修复指南
文章五:问题排查与修复 - “出了问题怎么办?SVN故障排除与修复指南” 概述:在使用SVN时,难免会遇到一些问题和错误。在这篇文章中,我们将教您如何进行故障排查和修复,保护您的SVN仓库和数据安全。 1. 引言…...
国产开源ambari之DataSophon部署
介绍 DataSophon致力于快速实现部署、管理、监控以及自动化运维大数据云原生平台,帮助您快速构建起稳定、高效、可弹性伸缩的大数据云原生平台。 主要特性有: 快速部署,可快速完成300个节点的大数据集群部署兼容复杂环境,极少的依赖使其很容易适配各种复杂环境监控指标全面丰…...
面试之快速学习STL- vector
1. vector底层实现机制刨析: 简述:使用三个迭代器表示的:  这也就解释了,为什么 vector 容器在进行扩容后,与其相关的指针、引用以及迭代器可能会失效的原因。 insert 整体向后移 erase 整体向前移…...
LeetCode_03Java_1572. 矩阵对角线元素的和
给你一个正方形矩阵 mat,请你返回矩阵对角线元素的和。 请你返回在矩阵主对角线上的元素和副对角线上且不在主对角线上元素的和。 输入:mat [[1,2,3],[4,5,6],[7,8,9]] 输出:25 解释:对角线的和为:1 5 9 3 7 2…...
系统架构设计师---职责及与其他角色的关系区别
一. 系统架构设计师的职责如下: 系统架构设计师是系统或产品线的设计责任人,是一个负责理解和管理并最终确认和评估非功能性系统需求(比如软件的可维护性、性能、复用性、可靠性、有效性和可测试性等),给出 开发规范,搭建系统实现的核心构架,对整个软件架构、关键构件、…...
【Visual Studio Code】--- Win11 C盘爆满 修改 Code 插件数据和缓存的保存路径
Win11 C盘爆满 修改 Code 插件数据和缓存的保存路径 一、概述二、修改 Code 插件数据和缓存的保存路径 一、概述 一个好的文章能够帮助开发者完成更便捷、更快速的开发。书山有路勤为径,学海无涯苦作舟。我是秋知叶i、期望每一个阅读了我的文章的开发者都能够有所成…...
mapbox-gl中mvt、pbf 矢量切片 feature id bug
1.版本:mapbox-gl.js 2.13.0,pbf采用 postgis生成 2.调用矢量切片时,采用如下方法查询矢量切片要素,报错 map.on(mousemove, function(e) { var bbox = [ [e.point.x - 5, e.point.y - 5], [e.point…...
206、仿真-51单片机锂电池蓄电池电压电流加按键控制开关状态Proteus仿真设计(程序+Proteus仿真+配套资料等)
毕设帮助、开题指导、技术解答(有偿)见文未 目录 一、硬件设计 二、设计功能 三、Proteus仿真图 四、程序源码 资料包括: 需要完整的资料可以点击下面的名片加下我,找我要资源压缩包的百度网盘下载地址及提取码。 方案选择 单片机的选择 方案一&a…...
【Realtek sdk-3.4.14b】RTL8197F+RTL8812F欧洲屏蔽5G天气雷达信道DFS信道120、124、128方法
需求描述 对于欧洲国家来说,默认支持DFS信道,但是有三个信道比较特殊,是天气雷达信道,如下图所示120、124、128,天气雷达信道有个特点就是在信号可以发射之前需要检测静默15min,如果信道自动选择到了天气雷达信道,就会有15min的时间无法连接到WiFi热点,严重影响用户体验…...
【嵌入式学习笔记】嵌入式入门7——IIC总线协议
1.IIC简介 IIC即Inter Integrated Circuit,集成电路总线,是一种同步,串行,半双工通信总线。 IIC总线协议——总线就是传输数据通道,协议就是传输数据的规则,有以下特点: 由时钟线SCL和数据线S…...
你永远想象不到有多折磨的 Android 开发 react-native gradle*!¥%#
很难过,拿到项目运行不起来,错误报告研究几天没研究明白,改代码,装gradle,忙和好久还是一个样,也不知道是码的问题还是什么,一开始 后面装完gradle,不报错了,但是也跑不起…...
关于STM32 hal printf重定向 “FILE“ is undefined
> 关于STM32 hal printf重定向,及报错。“FILE” is undefined 增加以下内容: #include "string.h" #include "stdio.h" #pragma import(__use_no_semihosting) 标准库需要的支持函数 struct __…...
“深入剖析JVM内部机制:理解Java虚拟机的工作原理“
标题:深入剖析JVM内部机制:理解Java虚拟机的工作原理 介绍: Java虚拟机(JVM)是Java语言的核心组件,负责将Java源代码转换为可以在计算机上运行的机器码。了解JVM的内部机制对于开发人员来说非常重要&#…...
939. 最小面积矩形;2166. 设计位集;2400. 恰好移动 k 步到达某一位置的方法数目
939. 最小面积矩形 核心思想:枚举矩形的右边那条边的两个点,并用一个哈希表存储相同纵坐标的最近出现的列的列数,不断更新最近出现的左边那条边。 2166. 设计位集 核心思想:这题主要是时间复杂度的优化,用一个flag来标记当前翻转…...
GPT垂直领域相关模型 现有的开源领域大模型
对于ToC端来说,广大群众的口味已经被ChatGPT给养叼了,市场基本上被ChatGPT吃的干干净净。虽然国内大厂在紧追不舍,但目前绝大多数都还在实行内测机制,大概率是不会广泛开放的(毕竟,各大厂还是主盯ToB、ToG市…...
学习Vue:slot使用
在Vue.js中,组件高级特性之一是插槽(Slots)。插槽允许您在父组件中插入内容到子组件的特定位置,从而实现更灵活的组件复用和布局控制。本文将详细介绍插槽的使用方法和优势。 什么是插槽? 插槽是一种让父组件可以向子…...
【Linux】Shell脚本之流程控制语句 if判断、for循环、while循环、case循环判断 + 实战详解[⭐建议收藏!!⭐]
👨🎓博主简介 🏅云计算领域优质创作者 🏅华为云开发者社区专家博主 🏅阿里云开发者社区专家博主 💊交流社区:运维交流社区 欢迎大家的加入! 🐋 希望大家多多支…...
【数据结构】“栈”的模拟实现
💐 🌸 🌷 🍀 🌹 🌻 🌺 🍁 🍃 🍂 🌿 🍄🍝 🍛 🍤 📃个人主页 :阿然成长日记 …...
12 注册登录
12 注册登录 整体概述 使用数据库连接池实现服务器访问数据库的功能,使用POST请求完成注册和登录的校验工作。 本文内容 介绍同步实现注册登录功能,具体涉及到流程图、载入数据库表、提取用户名和密码、注册登录流程与页面跳转的代码实现。 流程图&a…...
MPNet:旋转机械轻量化故障诊断模型详解python代码复现
目录 一、问题背景与挑战 二、MPNet核心架构 2.1 多分支特征融合模块(MBFM) 2.2 残差注意力金字塔模块(RAPM) 2.2.1 空间金字塔注意力(SPA) 2.2.2 金字塔残差块(PRBlock) 2.3 分类器设计 三、关键技术突破 3.1 多尺度特征融合 3.2 轻量化设计策略 3.3 抗噪声…...
Debian系统简介
目录 Debian系统介绍 Debian版本介绍 Debian软件源介绍 软件包管理工具dpkg dpkg核心指令详解 安装软件包 卸载软件包 查询软件包状态 验证软件包完整性 手动处理依赖关系 dpkg vs apt Debian系统介绍 Debian 和 Ubuntu 都是基于 Debian内核 的 Linux 发行版ÿ…...
五年级数学知识边界总结思考-下册
目录 一、背景二、过程1.观察物体小学五年级下册“观察物体”知识点详解:由来、作用与意义**一、知识点核心内容****二、知识点的由来:从生活实践到数学抽象****三、知识的作用:解决实际问题的工具****四、学习的意义:培养核心素养…...
质量体系的重要
质量体系是为确保产品、服务或过程质量满足规定要求,由相互关联的要素构成的有机整体。其核心内容可归纳为以下五个方面: 🏛️ 一、组织架构与职责 质量体系明确组织内各部门、岗位的职责与权限,形成层级清晰的管理网络…...
跨链模式:多链互操作架构与性能扩展方案
跨链模式:多链互操作架构与性能扩展方案 ——构建下一代区块链互联网的技术基石 一、跨链架构的核心范式演进 1. 分层协议栈:模块化解耦设计 现代跨链系统采用分层协议栈实现灵活扩展(H2Cross架构): 适配层…...
【C语言练习】080. 使用C语言实现简单的数据库操作
080. 使用C语言实现简单的数据库操作 080. 使用C语言实现简单的数据库操作使用原生APIODBC接口第三方库ORM框架文件模拟1. 安装SQLite2. 示例代码:使用SQLite创建数据库、表和插入数据3. 编译和运行4. 示例运行输出:5. 注意事项6. 总结080. 使用C语言实现简单的数据库操作 在…...
IoT/HCIP实验-3/LiteOS操作系统内核实验(任务、内存、信号量、CMSIS..)
文章目录 概述HelloWorld 工程C/C配置编译器主配置Makefile脚本烧录器主配置运行结果程序调用栈 任务管理实验实验结果osal 系统适配层osal_task_create 其他实验实验源码内存管理实验互斥锁实验信号量实验 CMISIS接口实验还是得JlINKCMSIS 简介LiteOS->CMSIS任务间消息交互…...
大学生职业发展与就业创业指导教学评价
这里是引用 作为软工2203/2204班的学生,我们非常感谢您在《大学生职业发展与就业创业指导》课程中的悉心教导。这门课程对我们即将面临实习和就业的工科学生来说至关重要,而您认真负责的教学态度,让课程的每一部分都充满了实用价值。 尤其让我…...
OPENCV形态学基础之二腐蚀
一.腐蚀的原理 (图1) 数学表达式:dst(x,y) erode(src(x,y)) min(x,y)src(xx,yy) 腐蚀也是图像形态学的基本功能之一,腐蚀跟膨胀属于反向操作,膨胀是把图像图像变大,而腐蚀就是把图像变小。腐蚀后的图像变小变暗淡。 腐蚀…...
python报错No module named ‘tensorflow.keras‘
是由于不同版本的tensorflow下的keras所在的路径不同,结合所安装的tensorflow的目录结构修改from语句即可。 原语句: from tensorflow.keras.layers import Conv1D, MaxPooling1D, LSTM, Dense 修改后: from tensorflow.python.keras.lay…...
