完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
【MYD-JX8MMA7】 十四、OpenCV车牌识别 一、基本理论 通过模板匹配的方法进行字符识别,每个字符依次在模板集中寻找与自己最相似的模板,并将最相似的模板对应的字符识别为当前字符。 必须使用量化指标衡量相似度,简单来说,必须用一个数值来衡量两幅图像之间的相似程度。在OpenCV中可以使用函数matchTemplate来衡量两幅图像之间的相似度。 因此,字符识别转换成立如下两个问题: 使用函数matchTemplate依次衡量待识别字符与模板集中每一个字符的匹配值。 将最匹配的模板对应的字符确定为识别结果。 通过如下三个函数解决上述两个问题。 函数1:读取模板图像。模板图像较多,因此构造一个函数来读取模板图像,以便后续计算其与待识别图像间的匹配值。 函数2:计算匹配值。该函数用来计算两幅图像之间的匹配值,主要借助OPenCV中的函数matchTemplate完成。 函数3:识别字符。该函数用来识别字符。 二、主要函数代码 2.1、函数1:读取模板图像 首先,构造一个字典用于存储包含所有数字、字母、部分省份简称在内的字符集;然后,使用glob库获取所有模板的文件名,具体如下: #=================模板,部分省份,使用字典表示============================== templateDict = {0:'0',1:'1',2:'2',3:'3',4:'4',5:'5',6:'6',7:'7',8:'8',9:'9', 10:'A',11:'B',12:'C',13:'D',14:'E',15:'F',16:'G',17:'H', 18:'J',19:'K',20:'L',21:'M',22:'N',23:'P',24:'Q',25:'R', 26:'S',27:'T',28:'U',29:'V',30:'W',31:'X',32:'Y',33:'Z', 34:'京',35:'津',36:'冀',37:'晋',38:'蒙',39:'辽',40:'吉',41:'黑', 42:'沪',43:'苏',44:'浙',45:'皖',46:'闽',47:'赣',48:'鲁',49:'豫', 50:'鄂',51:'湘',52:'粤',53:'桂',54:'琼',55:'渝',56:'川',57:'贵', 58:'云',59:'藏',60:'陕',61:'甘',62:'青',63:'宁',64:'新', 65:'港',66:'澳',67:'台'} # ==================获取所有字符的路径信息=================== def getcharacters(): c=[] for i in range(0,67): words=[] words.extend(glob.glob('template/'+templateDict.get(i)+'/*.*')) c.append(words) return c 2.2、计算匹配值 将匹配度进行量化,即使用一个数值来表示两幅图像的相似程度。在OpenCV内可使用函数matchTemplate计算两幅图像的匹配值。 构造函数getMatchValue,以计算匹配值。其中,参数template是文件名,参数image是待检测的图像。 #=============计算匹配值函数===================== def getMatchValue(template,image): #读取模板图像 # templateImage=cv2.imread(template) #cv2读取中文文件名不友好 templateImage=cv2.imdecode(np.fromfile(template,dtype=np.uint8),1) #模板图像色彩空间转换,BGR-->灰度 templateImage = cv2.cvtColor(templateImage, cv2.COLOR_BGR2GRAY) #模板图像阈值处理, 灰度-->二值 ret, templateImage = cv2.threshold(templateImage, 0, 255, cv2.THRESH_OTSU) # 获取待识别图像的尺寸 height, width = image.shape # 将模板图像调整为与待识别图像尺寸一致 templateImage = cv2.resize(templateImage, (width, height)) #计算模板图像、待识别图像的模板匹配值 result = cv2.matchTemplate(image, templateImage, cv2.TM_CCOEFF) # 将计算结果返回 return result[0][0] 2.3、识别字符 2.3.1、字符模板 先针对模板内的每个字符计算出一个与待识别字最匹配的模板;然后在逐字符匹配结果中找出最佳匹配模板,从而确定最终识别结果。 使用到了3层循环关系检测: 1.逐个遍历提取的各个字符。 2.遍历所有特征字符(字符集中的每个字符)。 3.遍历每一个特征字符的多有模板。 # ===========对车牌内字符进行识别==================== #plates,要识别的字符集, # 也就是从车牌图像“GUA211”中分离出来的每一个字符的图像"G","U","A","2","1","1" #chars,所有字符的模板集合,也就是0-9,A-Z,京-台,每一个字符模板 def matchChars(plates,chars): results=[] #存储所有的识别结果 #最外层循环:逐个遍历要识别的字符。 # 例如,逐个遍历从车牌图像“GUA211”中分离出来的每一个字符的图像 # 如"G","U","A","2","1","1" # plateChar分别存储,"G","U","A","2","1","1" for plateChar in plates:#逐个遍历要识别的字符 #bestMatch,存储的是待识别字符与每个特征字符的所有模板中最匹配的模板 # 例如,待识别图像“G”,与所有的字符0-9,A-Z,京-台,每一个字符最匹配的模板 bestMatch = [] #最佳匹配 #中间层循环:针对模板内的字符,进行逐个遍历(每次循环针对一个特定的字符), #words 对应的是每一个字符(例如字符A)的所有模板 for words in chars: #遍历字符。chars:所有模板,words:某个字符的所有模板 #match,存储的是每个特征字符的所有匹配值 # 例如:待识别图像“G”,与字符7的所有模板的匹配值 match = [] #每个字符的匹配值 #最内层循环:针对的是单个字符的所有模板,找到最佳的模板 # word对应的是单个模板 for word in words: #遍历模板。words:某个字符所有模板,word单个模板 result = getMatchValue(word,plateChar) match.append(result) bestMatch.append(max(match)) #将每个字符模板的最佳匹配加入bestMatch i = bestMatch.index(max(bestMatch)) #i是最佳匹配的字符模板的索引值 r = templateDict #r是单个待识别字符的识别结果 results.append(r) #将每一个分割字符的识别结果加入到results内 return results #返回所有的识别结果 三、实现程序 # -*- coding: utf-8 -*- # ==========================导入库============================== import cv2 # from matplotlib import pyplot as plt import numpy as np import glob # ==========================提取车牌函数============================== def getPlate(image): rawImage=image.copy() # 去噪处理 image = cv2.GaussianBlur(image, (3, 3), 0) # 色彩空间转换(RGB-->GRAY) image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) # Sobel算子(X方向边缘梯度) Sobel_x = cv2.Sobel(image, cv2.CV_16S, 1, 0) absX = cv2.convertScaleAbs(Sobel_x) # 映射到[0.255]内 image = absX # 阈值处理 ret, image = cv2.threshold(image, 0, 255, cv2.THRESH_OTSU) # 闭运算:先膨胀后腐蚀,车牌各个字符是分散的,让车牌构成一体 kernelX = cv2.getStructuringElement(cv2.MORPH_RECT, (17, 5)) image = cv2.morphologyEx(image, cv2.MORPH_CLOSE, kernelX) # 开运算:先腐蚀后膨胀,去除噪声 kernelY = cv2.getStructuringElement(cv2.MORPH_RECT, (1, 19)) image = cv2.morphologyEx(image, cv2.MORPH_OPEN, kernelY) # 中值滤波:去除噪声 image = cv2.medianBlur(image, 15) # 查找轮廓 contours, w1 = cv2.findContours(image, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE) #测试语句,查看处理结果 # image = cv2.drawContours(rawImage.copy(), contours, -1, (0, 0, 255), 3) # cv2.imshow('imagecc', image) #逐个遍历,将宽度>3倍高度的轮廓确定为车牌 for item in contours: rect = cv2.boundingRect(item) x = rect[0] y = rect[1] weight = rect[2] height = rect[3] if weight > (height * 3): plate = rawImage[y:y + height, x:x + weight] return plate #======================预处理函数,图像去噪等处理================= def preprocessor(image): # 图像去噪灰度处理 image = cv2.GaussianBlur(image, (3, 3), 0) # 色彩空间转换 gray_image = cv2.cvtColor(image, cv2.COLOR_RGB2GRAY) # 阈值处理(二值化) ret, image = cv2.threshold(gray_image, 0, 255, cv2.THRESH_OTSU) #膨胀处理,让一个字构成一个整体(大多数字不是一体的,是分散的) kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (2, 2)) image = cv2.dilate(image, kernel) return image #===========拆分车牌函数,将车牌内各个字符分离================== def splitPlate(image): # 查找轮廓,各个字符的轮廓 contours, hierarchy = cv2.findContours(image, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) words = [] # 遍历所有轮廓 for item in contours: rect = cv2.boundingRect(item) words.append(rect) # print(len(contours)) #测试语句:看看找到多少个轮廓 #-----测试语句:看看轮廓效果----- # imageColor=cv2.cvtColor(image,cv2.COLOR_GRAY2BGR) # x = cv2.drawContours(imageColor, contours, -1, (0, 0, 255), 1) # cv2.imshow("contours",x) #-----测试语句:看看轮廓效果----- # 按照x轴坐标值排序(自左向右排序) words = sorted(words,key=lambda s:s[0],reverse=False) # 用word存放左上角起始点及长宽值 plateChars = [] for word in words: # 筛选字符的轮廓(高宽比在1.5-8之间,宽度大于3) if (word[3] > (word[2] * 1.5)) and (word[3] < (word[2] * 8)) and (word[2] > 3): plateChar = image[word[1]:word[1] + word[3], word[0]:word[0] + word[2]] plateChars.append(plateChar) # 测试语句:查看各个字符 # for i,im in enumerate(plateChars): # cv2.imshow("char"+str(i),im) return plateChars #=================模板,部分省份,使用字典表示============================== templateDict = {0:'0',1:'1',2:'2',3:'3',4:'4',5:'5',6:'6',7:'7',8:'8',9:'9', 10:'A',11:'B',12:'C',13:'D',14:'E',15:'F',16:'G',17:'H', 18:'J',19:'K',20:'L',21:'M',22:'N',23:'P',24:'Q',25:'R', 26:'S',27:'T',28:'U',29:'V',30:'W',31:'X',32:'Y',33:'Z', 34:'京',35:'津',36:'冀',37:'晋',38:'蒙',39:'辽',40:'吉',41:'黑', 42:'沪',43:'苏',44:'浙',45:'皖',46:'闽',47:'赣',48:'鲁',49:'豫', 50:'鄂',51:'湘',52:'粤',53:'桂',54:'琼',55:'渝',56:'川',57:'贵', 58:'云',59:'藏',60:'陕',61:'甘',62:'青',63:'宁',64:'新', 65:'港',66:'澳',67:'台'} # ==================获取所有字符的路径信息=================== def getcharacters(): c=[] for i in range(0,67): words=[] words.extend(glob.glob('template/'+templateDict.get(i)+'/*.*')) c.append(words) return c #=============计算匹配值函数===================== def getMatchValue(template,image): #读取模板图像 # templateImage=cv2.imread(template) #cv2读取中文文件名不友好 templateImage=cv2.imdecode(np.fromfile(template,dtype=np.uint8),1) #模板图像色彩空间转换,BGR-->灰度 templateImage = cv2.cvtColor(templateImage, cv2.COLOR_BGR2GRAY) #模板图像阈值处理, 灰度-->二值 ret, templateImage = cv2.threshold(templateImage, 0, 255, cv2.THRESH_OTSU) # 获取待识别图像的尺寸 height, width = image.shape # 将模板图像调整为与待识别图像尺寸一致 templateImage = cv2.resize(templateImage, (width, height)) #计算模板图像、待识别图像的模板匹配值 result = cv2.matchTemplate(image, templateImage, cv2.TM_CCOEFF) # 将计算结果返回 return result[0][0] # ===========对车牌内字符进行识别==================== #plates,要识别的字符集, # 也就是从车牌图像“GUA211”中分离出来的每一个字符的图像"G","U","A","2","1","1" #chars,所有字符的模板集合,也就是0-9,A-Z,京-台,每一个字符模板 def matchChars(plates,chars): results=[] #存储所有的识别结果 #最外层循环:逐个遍历要识别的字符。 # 例如,逐个遍历从车牌图像“GUA211”中分离出来的每一个字符的图像 # 如"G","U","A","2","1","1" # plateChar分别存储,"G","U","A","2","1","1" for plateChar in plates:#逐个遍历要识别的字符 #bestMatch,存储的是待识别字符与每个特征字符的所有模板中最匹配的模板 # 例如,待识别图像“G”,与所有的字符0-9,A-Z,京-台,每一个字符最匹配的模板 bestMatch = [] #最佳匹配 #中间层循环:针对模板内的字符,进行逐个遍历(每次循环针对一个特定的字符), #words 对应的是每一个字符(例如字符A)的所有模板 for words in chars: #遍历字符。chars:所有模板,words:某个字符的所有模板 #match,存储的是每个特征字符的所有匹配值 # 例如:待识别图像“G”,与字符7的所有模板的匹配值 match = [] #每个字符的匹配值 #最内层循环:针对的是单个字符的所有模板,找到最佳的模板 # word对应的是单个模板 for word in words: #遍历模板。words:某个字符所有模板,word单个模板 result = getMatchValue(word,plateChar) match.append(result) bestMatch.append(max(match)) #将每个字符模板的最佳匹配加入bestMatch i = bestMatch.index(max(bestMatch)) #i是最佳匹配的字符模板的索引值 r = templateDict #r是单个待识别字符的识别结果 results.append(r) #将每一个分割字符的识别结果加入到results内 return results #返回所有的识别结果 # ================主程序============= image = cv2.imread("car11.jpeg") #读取原始图像 cv2.imshow("original",image) #显示原始图像 image=getPlate(image) #获取车牌 cv2.imshow('plate', image) #测试语句:看看车牌定位情况 image=preprocessor(image) #预处理 # cv2.imshow("imagePre",image) #测试语句,看看预处理结果 plateChars=splitPlate(image) #分割车牌,将每个字符独立出来 for i,im in enumerate(plateChars): #逐个遍历字符 cv2.imshow("plateChars"+str(i),im) #显示分割的字符 chars=getcharacters() #获取所有模板文件(文件名) results=matchChars(plateChars, chars) #使用模板chars逐个识别字符集plates results="".join(results) #将列表转换为字符串 print("识别结果为:",results) #输出识别结果 cv2.waitKey(0) #显示暂停 cv2.destroyAllWindows() #释放窗口 四、运行效果 |
|
相关推荐
|
|
只有小组成员才能发言,加入小组>>
【米尔-紫光MYB-J7A100T国产FPGA开发板试用】米尔-紫光PG2L100H国产FPGA开发板开箱评测
1039 浏览 0 评论
【米尔-紫光PG2L100H国产FPGA开发板试用】官方LED例程测试体验
5322 浏览 0 评论
【米尔-紫光PG2L100H国产FPGA开发板试用】上电测试报告
4970 浏览 0 评论
【米尔-紫光PG2L100H国产FPGA开发板试用】开箱评测!米尔电子PG2L100H开发板深度体验报告
1010 浏览 0 评论
【米尔-Xilinx XC7A100T FPGA开发板试用】+04.SFP之Aurora测试(zmj)
831 浏览 0 评论
【米尔-瑞米派兼容树莓派扩展模块-试用体验】基于ROS系统的三麦轮小车自主导航
3657浏览 2评论
【米尔NXP i.MX 93开发板试用评测】5、安装Debian和排除启动故障
734浏览 2评论
【米尔NXP i.MX 93开发板试用评测】2、异构通信环境搭建和源码编译
876浏览 2评论
【米尔-瑞米派兼容树莓派扩展模块-试用体验】Free RTOS应用开发环境部署
1464浏览 1评论
【米尔-芯驰D9开发板- 国产平台试用】- 03- 外设接口测试-U盘、485总线
6823浏览 1评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-12-23 22:33 , Processed in 0.711227 second(s), Total 66, Slave 49 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号