目录

一、效果

1、成功案例

2、经典失败案例(单字符识别成类似字符)

3、其他失败案例

二、总结

三、车牌识别总代码


一、效果

1、成功案例

2、经典失败案例(单字符识别成类似字符)

3、其他失败案例

二、总结

前面字符提取比较成功的,大多数的识别都没太大问题,但是字符提取不到位,后面的识别工作自然也很难进行。这次的测试失败有很多都是前面的工作没有做好,尤其是第一步的车牌提取,个人感觉车牌提取是本次项目最困难的地方

三、车牌识别总代码

# 车牌识别
import cv2 as cv
import numpy as np
import os
from matplotlib import pyplot as plt
from PIL import Image, ImageDraw, ImageFont# 总文件夹
List = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K', 'L', 'M', 'N', 'P', 'Q','R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '云','京','冀','吉','宁','川','新','晋','桂','沪','津','浙','渝','湘','琼','甘','皖','粤','苏','蒙','藏','豫','贵','赣','辽','鄂','闽','陕','青','鲁','黑']
# 车牌数字列表(10)
Num_List = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']
# 车牌英文列表(24)
Eng_List = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K', 'L', 'M', 'N', 'P', 'Q','R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z']
# 车牌汉字列表(31)
Chinese_List = ['云','京','冀','吉','宁','川','新','晋','桂','沪','津','浙','渝','湘','琼','甘','皖','粤','苏','蒙','藏','豫','贵','赣','辽','鄂','闽','陕','青','鲁','黑']
final_result = []# 得到黑底白字(白色多则返回真)
def IsWhiteMore(binary):white = black = 0height, width = binary.shape# 遍历每个像素for i in range(height):for j in range(width):if binary[i,j]==0:black+=1else:white+=1if white >= black:return Trueelse:return False# 限制图像大小(车牌)
def Limit(image):height, width, channel = image.shape# 设置权重weight = width/300# 计算输出图像的宽和高last_width = int(width/weight)last_height = int(height/weight)image = cv.resize(image, (last_width, last_height))return image# 二-5、统计白色像素点(分别统计每一行、每一列)
def White_Statistic(image):ptx = []  # 每行白色像素个数pty = []  # 每列白色像素个数height, width = image.shape# 逐行遍历for i in range(height):num = 0for j in range(width):if(image[i][j]==255):num = num+1ptx.append(num)# 逐列遍历for i in range(width):num = 0for j in range(height):if (image[j][i] == 255):num = num + 1pty.append(num)return ptx, pty# 二-6、绘制直方图
def Draw_Hist(ptx, pty):# 依次得到各行、列rows, cols = len(ptx), len(pty)row = [i for i in range(rows)]col = [j for j in range(cols)]# 横向直方图plt.barh(row, ptx, color='black', height=1)#       纵    横# plt.show()# 纵向直方图plt.bar(col, pty, color='black', width=1)#       横    纵# plt.show()# 二-7-2、横向分割:上下边框
def Cut_X(ptx, rows):# 横向切割(分为上下两张图,分别找其波谷,确定顶和底)# 1、下半图波谷min, r = 300, 0for i in range(int(rows / 2)):if ptx[i] < min:min = ptx[i]r = ih1 = r  # 添加下行(作为顶)# 2、上半图波谷min, r = 300, 0for i in range(int(rows / 2), rows):if ptx[i] < min:min = ptx[i]r = ih2 = r  # 添加上行(作为底)return h1, h2# 二-7-3、纵向分割:分割字符
def Cut_Y(pty, cols, h1, h2, binary):global con, final_resultWIDTH = 33          # 经过测试,一个字符宽度约为32w = w1 = w2 = 0     # 前谷 字符开始 字符结束begin = False       # 字符开始标记last = 10           # 上一次的值con = 0             # 计数(字符)final_result = []   # 清空已识别的车牌# 纵向切割(正式切割字符)for j in range(int(cols)):# 0、极大值判断if pty[j] == max(pty):if j < 30:  # 左边(跳过)w2 = jif begin == True:begin = Falsecontinueelif j > 270:  # 右边(直接收尾)if begin == True:begin = Falsew2 = jb_copy = binary.copy()b_copy = b_copy[h1:h2, w1:w2]# cv.imshow('binary%d-%d' % (count, con), b_copy)cv.imwrite('car_characters/image%d-%d.jpg' % (count, con), b_copy)Template_Match(b_copy)con += 1break# 1、前谷(前面的波谷)if pty[j] < 12 and begin == False:  # 前谷判断:像素数量<12last = pty[j]w = j# 2、字符开始(上升)elif last < 12 and pty[j] > 20:last = pty[j]w1 = jbegin = True# 3、字符结束elif pty[j] < 13 and begin == True:begin = Falselast = pty[j]w2 = jwidth = w2 - w1# 3-1、分割并显示(排除过小情况)if 10 < width < WIDTH + 3:  # 要排除掉干扰,又不能过滤掉字符”1“b_copy = binary.copy()b_copy = b_copy[h1:h2, w1:w2]# cv.imshow('binary%d-%d' % (count, con), b_copy)cv.imwrite('car_characters/image%d-%d.jpg' % (count, con), b_copy)Template_Match(b_copy)con += 1# 3-2、从多个贴合字符中提取单个字符elif width >= WIDTH + 3:# 统计贴合字符个数num = int(width / WIDTH + 0.5)  # 四舍五入for k in range(num):# w1和w2坐标向后移(用w3、w4代替w1和w2)w3 = w1 + k * WIDTHw4 = w1 + (k + 1) * WIDTHb_copy = binary.copy()b_copy = b_copy[h1:h2, w3:w4]# cv.imshow('binary%d-%d' % (count, con), b_copy)cv.imwrite('car_characters/image%d-%d.jpg' % (count, con), b_copy)Template_Match(b_copy)con += 1# 4、分割尾部噪声(距离过远默认没有字符了)elif begin == False and (j - w2) > 30:break# 最后检查收尾情况if begin == True:w2 = 295b_copy = binary.copy()b_copy = b_copy[h1:h2, w1:w2]# cv.imshow('binary%d-%d' % (count, con), b_copy)cv.imwrite('car_characters/image%d-%d.jpg' % (count, con), b_copy)Template_Match(b_copy)# 显示识别结果(图像)Show_Result_Image()# 二-7、分割车牌图像(根据直方图)
def Cut_Image(ptx, pty, binary, dilate):h1 = h2 = 0#顶  底begin = False        #标记开始/结束# 1、依次得到各行、列rows, cols = len(ptx), len(pty)row = [i for i in range(rows)]col = [j for j in range(cols)]# 2、横向分割:上下边框h1, h2 = Cut_X(ptx, rows)# cut_x = binary[h1:h2, :]# cv.imshow('cut_x', cut_x)# 3、纵向分割:分割字符Cut_Y(pty, cols, h1, h2, binary)# 显示文字(中文)(用的PIL,RGB正常显示,即和opencv的RGB相反)
def Text(image, text, p, color, size):# cv2读取图片# BGR转RGB:cv2和PIL中颜色的hex码的储存顺序不同cv2_image = cv.cvtColor(image, cv.COLOR_RGB2BGR)pil_image = Image.fromarray(cv2_image)# PIL图片上打印汉字draw = ImageDraw.Draw(pil_image)  # 图片上打印font = ImageFont.truetype("./simhei.ttf", size, encoding="utf-8")  # 参数1:字体文件路径,参数2:字体大小draw.text((p[0]-60, p[1]-20), text, color, font=font)# PIL图片转cv2 图片cv2_result = cv.cvtColor(np.array(pil_image), cv.COLOR_RGB2BGR)# cv2.imshow("图片", cv2_result)      # 汉字窗口标题显示乱码# cv.imshow("photo", cv2_result)     # 输出汉字return cv2_result# 显示识别结果(文字)
def Show_Result_Words(index):print(List[index])final_result.append(List[index])print(final_result)# 显示识别结果(图像)
def Show_Result_Image():p = image_rect[0], image_rect[1]w, h = image_rect[2] , image_rect[3]# 框出车牌cv.rectangle(img, (p[0],p[1]), (p[0]+w, p[1]+h), (0,0,255), 2)# 输出字符(中文)result = Text(img, str(final_result), p, (255,0,0), 16)cv.imshow('result-%d'%count, result)# cv.waitKey(0)# 一、形态学提取车牌
def Get_Licenses(image):global image_rect       #待返回的矩形坐标# 1、转灰度图gray = cv.cvtColor(image, cv.COLOR_RGB2GRAY)# cv.imshow('gray', gray)# 2、顶帽运算# gray = cv.equalizeHist(gray)kernel = cv.getStructuringElement(cv.MORPH_RECT, (17,17))tophat = cv.morphologyEx(gray, cv.MORPH_TOPHAT, kernel)# cv.imshow('tophat', tophat)# 3、Sobel算子提取y方向边缘(揉成一坨)y = cv.Sobel(tophat, cv.CV_16S, 1,     0)absY = cv.convertScaleAbs(y)# cv.imshow('absY', absY)# 4、自适应二值化(阈值自己可调)ret, binary = cv.threshold(absY, 75, 255, cv.THRESH_BINARY)# cv.imshow('binary', binary)# 5、开运算分割(纵向去噪,分隔)kernel = cv.getStructuringElement(cv.MORPH_RECT, (1, 15))Open = cv.morphologyEx(binary, cv.MORPH_OPEN, kernel)# cv.imshow('Open', Open)# 6、闭运算合并,把图像闭合、揉团,使图像区域化,便于找到车牌区域,进而得到轮廓kernel = cv.getStructuringElement(cv.MORPH_RECT, (41, 15))close = cv.morphologyEx(Open, cv.MORPH_CLOSE, kernel)# cv.imshow('close', close)# 7、膨胀/腐蚀(去噪得到车牌区域)# 中远距离车牌识别kernel_x = cv.getStructuringElement(cv.MORPH_RECT, (25, 7))kernel_y = cv.getStructuringElement(cv.MORPH_RECT, (1, 11))# 近距离车牌识别# kernel_x = cv.getStructuringElement(cv.MORPH_RECT, (79, 15))# kernel_y = cv.getStructuringElement(cv.MORPH_RECT, (1, 31))# 7-1、腐蚀、膨胀(去噪)erode_y = cv.morphologyEx(close, cv.MORPH_ERODE, kernel_y)# cv.imshow('erode_y', erode_y)dilate_y = cv.morphologyEx(erode_y, cv.MORPH_DILATE, kernel_y)# cv.imshow('dilate_y', dilate_y)# 7-1、膨胀、腐蚀(连接)(二次缝合)dilate_x = cv.morphologyEx(dilate_y, cv.MORPH_DILATE, kernel_x)# cv.imshow('dilate_x', dilate_x)erode_x = cv.morphologyEx(dilate_x, cv.MORPH_ERODE, kernel_x)# cv.imshow('erode_x', erode_x)# 8、腐蚀、膨胀:去噪kernel_e = cv.getStructuringElement(cv.MORPH_RECT, (25, 9))erode = cv.morphologyEx(erode_x, cv.MORPH_ERODE, kernel_e)# cv.imshow('erode', erode)kernel_d = cv.getStructuringElement(cv.MORPH_RECT, (25, 11))dilate = cv.morphologyEx(erode, cv.MORPH_DILATE, kernel_d)# cv.imshow('dilate', dilate)# 9、获取外轮廓img_copy = image.copy()# 9-1、得到轮廓contours, hierarchy = cv.findContours(dilate, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)# 9-2、画出轮廓并显示cv.drawContours(img_copy, contours, -1, (255, 0, 255), 2)# cv.imshow('Contours', img_copy)# 10、遍历所有轮廓,找到车牌轮廓i = 0for contour in contours:# 10-1、得到矩形区域:左顶点坐标、宽和高rect = cv.boundingRect(contour)# 10-2、判断宽高比例是否符合车牌标准,截取符合图片if rect[2]>rect[3]*3 and rect[2]<rect[3]*7:# 截取车牌并显示print(rect)image_rect = rectimg_copy = image.copy()image = image[(rect[1]):(rect[1]+rect[3]), (rect[0]):(rect[0]+rect[2])] #高,宽try:# 限制大小(按照比例限制)image = Limit(image)cv.imshow('license plate%d-%d' % (count, i), image)cv.imwrite('car_licenses/image%d-%d.jpg'%(count, i), image)i += 1return imageexcept:passreturn image# 二、直方图提取字符
def Get_Character(image):# 清空final_result = []# 1、中值滤波mid = cv.medianBlur(image, 5)# 2、灰度化gray = cv.cvtColor(mid, cv.COLOR_BGR2GRAY)# 3、二值化ret, binary = cv.threshold(gray, 0, 255, cv.THRESH_OTSU)# 统一得到黑底白字if(IsWhiteMore(binary)):     #白色部分多则为真,意味着背景是白色,需要黑底白字ret, binary = cv.threshold(gray, 0, 255, cv.THRESH_OTSU | cv.THRESH_BINARY_INV)cv.imshow('binary', binary)# 4、膨胀(粘贴横向字符)kernel = cv.getStructuringElement(cv.MORPH_RECT, (7,1))     #横向连接字符dilate = cv.dilate(binary, kernel)# cv.imshow('dilate', dilate)# 5、统计各行各列白色像素个数(为了得到直方图横纵坐标)ptx, pty = White_Statistic(dilate)# 6、绘制直方图(横、纵)Draw_Hist(ptx, pty)# 7、分割(横、纵)(横向分割边框、纵向分割字符)Cut_Image(ptx, pty, binary, dilate)# cv.waitKey(0)# 三、模板匹配
# 原图和模板进行对比,越匹配,得分越大
def Template_Match(image):# 单文件夹内的最佳得分best_score = []# 遍历所有文件夹(每一个文件夹匹配)# (1) 汉字(首个位置只能是汉字(省))(为了节约时间)if con == 0:# 遍历34——65文件夹(汉字)for i in range(34,65):# 单个图片的得分score = []ForderPath = 'Template/' + List[i]# 遍历单文件夹(每一个文件匹配)for filename in os.listdir(ForderPath):# 路径path = 'Template/' + List[i] + '/' + filename# 1、得到模板template = cv.imdecode(np.fromfile(path, dtype=np.uint8), 1)    #彩(类似imread)gray = cv.cvtColor(template, cv.COLOR_RGB2GRAY)                 #灰ret, template = cv.threshold(gray, 0, 255, cv.THRESH_OTSU)      #二值# 2、原图限定大小(和模板相似)h, w = template.shapeimage = cv.resize(image, (w, h))# 3、模板匹配,得到得分(匹配度越高,得分越大)result = cv.matchTemplate(image, template, cv.TM_CCOEFF)score.append(result[0][0])          #得分(每张模板图)# 4、保存子文件夹的最高得分(得分越高,匹配度越高)best_score.append(max(score))# 5、根据所有文件夹的最佳得分确定下标index = best_score.index(max(best_score))+34# (2) 字母(第二个位置只能为字母)elif con == 1:# 遍历10~34文件夹(字母文件夹)for i in range(10,34):# 单个图片的得分score = []ForderPath = 'Template/' + List[i]# 遍历单文件夹(每一个文件匹配)for filename in os.listdir(ForderPath):# 路径path = 'Template/' + List[i] + '/' + filename# 模板template = cv.imdecode(np.fromfile(path, dtype=np.uint8), 1)    #彩(类似imread)gray = cv.cvtColor(template, cv.COLOR_RGB2GRAY)                 #灰ret, template = cv.threshold(gray, 0, 255, cv.THRESH_OTSU)      #二值h, w = template.shapeimage = cv.resize(image, (w, h))# 模板匹配,得到得分(匹配度越高,得分越大)result = cv.matchTemplate(image, template, cv.TM_CCOEFF)score.append(result[0][0])          #得分(每张模板图)# 一个文件夹的最高得分(得分越高,匹配度越高)best_score.append(max(score))# 根据所有文件夹的最佳得分确定下标index = best_score.index(max(best_score)) + 10# (3) 数字+字母else:# 遍历0~34文件夹(数字+字母)for i in range(34):# 单个图片的得分score = []ForderPath = 'Template/' + List[i]# 遍历单文件夹(每一个文件匹配)for filename in os.listdir(ForderPath):# 路径path = 'Template/' + List[i] + '/' + filename# 模板template = cv.imdecode(np.fromfile(path, dtype=np.uint8), 1)    #彩(类似imread)gray = cv.cvtColor(template, cv.COLOR_RGB2GRAY)                 #灰ret, template = cv.threshold(gray, 0, 255, cv.THRESH_OTSU)      #二值h, w = template.shapeimage = cv.resize(image, (w, h))# 模板匹配,得到得分(匹配度越高,得分越大)result = cv.matchTemplate(image, template, cv.TM_CCOEFF)score.append(result[0][0])          #得分(每张模板图)# 一个文件夹的最高得分(得分越高,匹配度越高)best_score.append(max(score))# 根据所有文件夹的最佳得分确定下标index = best_score.index(max(best_score))# 显示结果(文字)(每识别一个显示一次)Show_Result_Words(index)if __name__ == '__main__':global count, imgcount=0         #计数:第几张图片# cv.waitKey(0)# 遍历文件夹中的每张图片(车)for car in os.listdir('cars'):# 1、获取路径path = 'cars/'+'car'+str(count)+'.jpg'# 2、获取图片img = cv.imread(path)image = img.copy()# cv.imshow('image', image)# 3、提取车牌image = Get_Licenses(image)         #形态学提取车牌# 4、分割字符Get_Character(image)count += 1cv.waitKey(0)

一张车牌约20秒,这些算法很多可能已经逐渐被淘汰了,这里只是作为学习用途,没有太高的实际应用价值。(后期进军深度学习/机器学习,可能会对这些进行优化)。有什么好的建议大家可以提出来,共同进步,谢谢~

OpenCV(项目)车牌识别4 -- 总结篇相关推荐

  1. Python+Opencv简易车牌识别(二):形态学运算,HSV颜色空间筛选与图像分割

    注:这是依然一个简单的车牌识别demo 1.前言 在上一篇Python+Opencv简易车牌识别(一):基于HSV颜色空间的图像分割中,我们讲了如何仅基于颜色来进行简单粗暴的车牌分割.今天我们考虑对图 ...

  2. 开源项目车牌识别EasyPR的使用

    开源项目车牌识别EasyPR的使用 1.配置Visual studio+opencv 2.下载源码 https://gitee.com/easypr/EasyPR?hmsr=aladdin1e6 3. ...

  3. 【树莓派开发】02-基于OpenCV的车牌识别处理(LPR)

    [说明]:疫情期间比较闲学习了python.LPR这个东西,基于OpenCV已经做过很多遍了,通过这个小项目利用树莓派来熟悉Python编程,而且通过实际操作可以掌握一些具体的细节与技巧,这里我将整个 ...

  4. 2021-01-07 python opencv实现车牌识别 颜色定位

    python opencv实现车牌识别 颜色定位 主要代码参考https://blog.csdn.net/wzh191920/article/details/79589506 GitHub:https ...

  5. Python 基于 opencv 的车牌识别系统, 可以准确识别车牌号

    大家好,我是程序员徐师兄,6 年大厂程序员经验,点击关注我 简介 毕业设计基于Opencv的车牌识别系统 车牌搜索识别找出某个车牌号 对比识别车牌系统 车牌数据库认证系统 车牌图文搜索系统 车牌数据库 ...

  6. 基于OpenCV的车牌识别的设计与实现

    随着大数据和互联网技术的快速发展,利用人工智能技术实现车牌信息的自动识别推荐成为研究的热门话题.通过对基于OpenCV的车牌识别系统的网站功能需要进行讨论研究,这种跨平台计算机视觉和机器学习非常适用于 ...

  7. 【开源分享】基于Python+OpenCV+PyQt5车牌识别(GUI界面)

    亲测无错:基于Python+OpenCV+PyQt5车牌识别(GUI界面)绝对可以用的!!!!! 基于Python+OpenCV+PyQt5车牌识别(GUI界面) 参考文档

  8. 基于Opencv的车牌识别系统想必大家都会了,那么识别后计费系统会了吗?

    概述 车牌识别脚本我相信大家都见过很多,最多的应该就是基于Opencv来实现的,这个小编也是写过几篇,如果有感兴趣的可以关注小编去查看一下.最近听学弟讲,毕业设计是越来越难了.以前毕设只需要实现车牌识 ...

  9. LabVIEW OCR 实现车牌识别(实战篇—3)

    目录 1.字符数据集训练 2.识别与验证 在学习本章之前,推荐先学习系列专栏文章:LabVIEW目标对象分类识别(理论篇-5) OCR(光学字符识别)是指机器自动从图像中识别文本字符的过程,OCR机器 ...

最新文章

  1. 一个功能非常全面的增强出口查找工具
  2. oracle中字符串的脚本表示什么意思,sql脚本中rem与prompt,define等的含义
  3. springboot+thymeleaf+jpa博客多级评论展示案例
  4. mysql utf8mb4 造成慢_mysql使用utf8mb4经验吐血总结
  5. Office2010翻译无处不在
  6. python数字图像处理(5):图像的绘制
  7. Linux 查看盘结构命令
  8. 【实用工具】之移除PDF的密码PDF Password Remover 3.0 汉化版
  9. 第 11 章 树结构实际应用
  10. 问题记录 - 调试程序时桌面程序可以运行,却不自动生成桌面快捷方式
  11. flux架构浅谈:什么数据才应该放store
  12. 旺旺的计算机无法打开,电脑任务栏中点击阿里旺旺图标无法打开界面的解决方法...
  13. esp8266 windows烧录问题
  14. TFS映射关系出错的几种
  15. Could not set property ‘XXX‘ of ‘class com.entity.XXX‘
  16. word2016如何插入题注并交叉引用
  17. 07_Numpy渐变图片的生成
  18. vb ADO控件连接ACCESS数据库做登录密码的例子
  19. vue2[初级]事件处理器
  20. 使用微信+树莓派+Arduino+服务器构建你的看门狗

热门文章

  1. java 增强for循环(foreach)
  2. CF533A Berland Miners
  3. 面向过程和面向对象的区别(转)
  4. wcf客户端捕获异常
  5. 水题/poj 1852 Ants
  6. 大型企业门户网站设计开发一般性原则和建议
  7. OpenCV+python:分水岭算法
  8. 北京计算机学院 肖战,Shuai Li
  9. 基于python的手写数字识别knn_KNN分类算法实现手写数字识别
  10. linux停止客户端,linux – 从客户端打印motd停止ssh登录?