数字图像处理--车牌识别

article/2025/9/21 11:30:00

数字图像处理–车牌识别

主要内容

实现车牌识别

算法流程

本文中,车牌识别具体流程设计以及算法使用主要分为以下几步。
1、读取源车牌图像。
2、对原始车牌图像进行预处理:灰度化,运用基于几何运算的滤波器(开运算)消除毛刺噪声。
3、二值化操作。
4、利用canny边缘检测算法消除小的区域保留大的区域。
5、通过颜色识别判断定位车牌位置。
6、利用掩膜处理对定位车牌后的图像进行分割,直接分割出车牌。
7、再次对车牌进行二值化处理。
8、分割字符。
9、对分割字符进行神经网络模型匹配,输出车牌字符串。
针对上述实验设计步骤,做出实验流程图,如下图所示。
在这里插入图片描述

源代码

上代码

import numpy as np
import matplotlib.pyplot as plt
from matplotlib import font_manager
import ddddocr#读取字体文件
font = font_manager.FontProperties(fname=r".\OPPOSans-Heavy.ttf")class Get_license():#图像拉伸函数def stretch(self, 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 img#二值化处理函数def dobinaryzation(self, 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 thresh#寻找矩形的轮廓def find_rectangle(self, 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(self, img, afterimg):contours, hierarchy = cv2.findContours(img, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)#找出最大的三个区域block = []for c in contours:#找出轮廓的左上点和右下点#由此计算它的面积和长度比r = self.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(self, 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 = self.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 = self.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 = self.locate_license(openingimg, img)return rect, img#图像分割函数def cut_license(self, afterimg, rect):#转换为宽度和高度rect[2] = rect[2] - rect[0]rect[3] = rect[3] - rect[1]rect_copy = tuple(rect.copy())#创建掩膜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]#cv2.imshow('111',img_show)return img_showclass Segmentation():def __init__(self, cutimg):#1、读取图像,并把图像转换为灰度图像并显示# cutimg = cv2.imread("3.jpg")  #读取图片img_gray = cv2.cvtColor(cutimg, cv2.COLOR_BGR2GRAY)  #转换了灰度化#cv2.imshow('gray', img_gray)   #显示图片#cv2.waitKey(0)#2、将灰度图像二值化,设定阈值是100self.img_thre = img_graycv2.threshold(img_gray, 100, 255, cv2.THRESH_BINARY_INV, self.img_thre)#cv2.waitKey(0)#3、保存黑白图片cv2.imwrite('thre_res.png', self.img_thre)#4、分割字符self.white = []               #记录每一列的白色像素总和self.black = []               #黑色self.height = self.img_thre.shape[0]self.width = self.img_thre.shape[1]self.white_max = 0self.black_max = 0#计算每一列的黑白色像素总和for i in range(self.width):s = 0                     #这一列白色总数t = 0                     #这一列黑色总数for j in range(self.height):if self.img_thre[j][i] == 255:s += 1if self.img_thre[j][i] == 0:t += 1self.white_max = max(self.white_max, s)self.black_max = max(self.black_max, t)self.white.append(s)self.black.append(t)self.arg = False                #False表示白底黑字;True表示黑底白字if self.black_max > self.white_max:self.arg = Truedef heibai(self):return self.img_thredef find_end(self, start_):end_ = start_ + 1for m in range(start_ + 1, self.width - 1):if (self.black[m] if self.arg else self.white[m]) > (0.85 * self.black_max if self.arg else 0.85 * self.white_max):end_ = mbreakreturn end_def display(self):#img_list = []n = 1plt.figure()img_num = 0while n < self.width - 2:n += 1if (self.white[n] if self.arg else self.black[n]) > (0.15 * self.white_max if self.arg else 0.15 * self.black_max):#上面这些判断用来辨别是白底黑字还是黑底白字start = nend = self.find_end(start)n = endif end - start > 5:cj = self.img_thre[1:self.height, start:end]img_num += 1cj = cv2.cvtColor(cj, cv2.COLOR_RGB2BGR)plt.figure(2)plt.subplot(2, 4, img_num)plt.title('{}'.format(img_num))plt.imshow(cj)plt.show()return self.img_threif __name__ == '__main__':#读取源图像img = cv2.imread('8.png')img1 = cv2.cvtColor(img, cv2.COLOR_RGB2BGR)#绘图plt.figure(1)plt.suptitle('车牌识别',fontproperties=font)plt.subplot(2, 3, 1)plt.title('原始图像', fontproperties=font)plt.imshow(img1)#预处理图像license = Get_license()rect, afterimg = license.find_license(img)afterimg = cv2.cvtColor(afterimg, cv2.COLOR_RGB2BGR)plt.subplot(2, 3, 2)plt.title('预处理后图像', fontproperties=font)plt.imshow(afterimg)#车牌号打框cv2.rectangle(afterimg, (rect[0], rect[1]), (rect[2], rect[3]), (0, 255, 0), 1)x1, y1, x2, y2 = int(rect[0]), int(rect[1]), int(rect[2]), int(rect[3])print('车牌框出:',x1, x2, y1, y2)plt.subplot(2, 3, 3)plt.title('车牌框出', fontproperties=font)plt.imshow(afterimg)#背景去除cutimg = license.cut_license(afterimg, rect)plt.subplot(2, 3, 4)plt.title('车牌背景去除', fontproperties=font)plt.imshow(cutimg)# print(int(_rect[0]), int(_rect[3]), int(_rect[2]), int(_rect[1]))print('车牌背景去除',x1, y1, x2, y2)#开始分割车牌# cutimg = cutimg[140:165, 151:240]cutimg = cutimg[y1 + 3:y2 - 3, x1 - 1:x2 - 3]# cutimg = cutimg[int(_rect[0]):int(_rect[3]),int(_rect[2]):int(_rect[1])]print('cutimg:',cutimg)height, width = cutimg.shape[:2]cutimg1 = cv2.resize(cutimg, (2 * width, 2 * height), interpolation=cv2.INTER_CUBIC)plt.subplot(2, 3, 5)plt.title('分割车牌与背景', fontproperties=font)plt.imshow(cutimg)#字符切割seg = Segmentation(cutimg)plt.subplot(2, 3, 6)img_hei = seg.heibai()img_hei = cv2.cvtColor(img_hei, cv2.COLOR_RGB2BGR)plt.title('车牌二值化处理', fontproperties=font)plt.imshow(img_hei)seg.display()plt.show()#打印车牌ocr = ddddocr.DdddOcr()with open('thre_res.png', 'rb') as f:image = f.read()res = ocr.classification(image)print(res)

实现结果

选取车牌照片,成功完成了对车牌号码的识别。如下图所示,即是原始图像到最后分割车牌与背景后的图片显示。

在这里插入图片描述
接着,对二值化处理过后的图片进行字符分割,所得结果如下图所示。
在这里插入图片描述
最后,通过利用ddddocr图片识别库对每个字符进行匹配。从而,实现字符图片到文本转换,成功打印输出车牌号码。
在这里插入图片描述
注意:选取其他照片后,可能需要微调代码里面 (车牌号打框)的参数值。就是图片局限性有点大。希望后续有小伙伴提出更泛化的代码实现!!!


http://chatgpt.dhexx.cn/article/IDKgDyoR.shtml

相关文章

数字图像处理——基于matlab的车牌号识别

希望大家有问题多多评论留言鸭 码字不易&#xff0c;老阿姨头发都没啦&#xff0c;小可爱们记得给三连鸭&#xff0c;么么哒。 &#xff08;只收藏&#xff0c;不点赞&#xff0c;好运连连会中断&#xff01;&#xff01;&#xff01;&#xff09; <--!&#xff08;源码资源…

【OpenCV实战】简洁易懂的车牌号识别Python+OpenCV实现“超详解”(含代码)

前面4篇博客介绍了OpenCV图像处理的基础知识&#xff0c;本篇博客利用前4篇的知识完成一个小项目——车牌号码识别。该篇博客的代码可以满足小区门禁车牌号的识别。本篇博客是前4篇博客知识的一个综合运用。感觉学会了这个可以实现一系列的图像识别任务。。。毕竟好多技巧都是共…

网络安全检测技术

一&#xff0c;网络安全漏洞 安全威胁是指所有能够对计算机网络信息系统的网络服务和网络信息的机密性&#xff0c;可用性和完整性产生阻碍&#xff0c;破坏或中断的各种因素。安全威胁可分为人为安全威胁和非人为安全威胁两大类。 1&#xff0c;网络安全漏洞威胁 漏洞分析的…

深度学习网络安全

Introduction 我们在社区中看到的大多数深度学习应用程序通常面向营销&#xff0c;销售&#xff0c;财务等领域。我们几乎从未阅读过文章或找到有关深度学习的资源用于保护这些产品和业务&#xff0c; 恶意软件和黑客攻击。 虽然像谷歌&#xff0c;Facebook&#xff0c;微软和…

网络安全法学习整理笔记

网络安全法 一、背景 概念 网络&#xff1a;是指由计算机或者其他信息终端及相关设备组成的按照一定的规则和程序对信息进行收集、存储、传输、交换、处理的系统。网络安全&#xff1a;是指通过采取必要措施&#xff0c;防范对网络的攻击、侵入、干扰、破坏和非法使用以及意…

网络安全免费学习网址(英文)

转载 作者&#xff1a;W-Pwn 链接&#xff1a;https://www.zhihu.com/question/49222590/answer/339206050 来源&#xff1a;知乎 著作权归作者所有。商业转载请联系作者获得授权&#xff0c;非商业转载请注明出处。 知识就是力量 但是知识太贵了&#xff0c;现在随便拎…

【论文阅读】基于强化学习的网络安全防护策略

【论文阅读】基于强化学习的网络安全防护策略 本篇文章将介绍一篇针对网络安全问题&#xff0c;运用强化学习方法寻找最优的网络防御策略。 Finding Effective Security Strategies through Reinforcement Learning and Self-Play 前言 通过强化学习和 自对弈(self-play) 寻…

还在为不知道怎么学习网络安全而烦恼吗?这篇文带你从入门级开始学习网络安全—认识网络安全

随着网络安全被列为国家安全战略的一部分&#xff0c;这个曾经细分的领域发展提速了不少&#xff0c;除了一些传统安全厂商以外&#xff0c;一些互联网大厂也都纷纷加码了在这一块的投入&#xff0c;随之而来的吸引了越来越多的新鲜血液不断涌入。 不同于Java、C/C等后端开发岗…

[网络安全自学篇] 一.入门笔记之看雪Web安全学习及异或解密示例

最近开始学习网络安全相关知识&#xff0c;接触了好多新术语&#xff0c;感觉自己要学习的东西太多&#xff0c;真是学无止境&#xff0c;也发现了好几个默默无闻写着博客、做着开源的大神。准备好好学习下新知识&#xff0c;并分享些博客与博友们一起进步&#xff0c;加油。非…

码农翻身,卧虎藏龙

写公众号是很不容易的&#xff0c;在现在信息爆炸的情况下&#xff0c;好文章也很容易被标题党埋没&#xff0c;在我的知识星球“码农翻身”中&#xff0c;我发起了一个活动&#xff1a;免费给写公众号的球友们做个推广。 这个不是互推&#xff0c;就是我单方面的推广&#xf…

现在转行码农的成本已经非常高了,别盲目转行..

转行码农一直是个比较火热的话题&#xff0c;也有很多读者咨询过这个问题&#xff0c;转成功的也不少&#xff0c;比如下面这位香港的同学&#xff1a; 这位朋友半年前就跟我聊过&#xff0c;他不太想干没有技术含量的体力活&#xff0c;一直在坚持自学&#xff0c;这也算如愿…

农村出身的 90 后程序员,如何逆袭为中产阶级?| 程序员有话说

作者 | 阿文 责编 | 伍杏玲 出品 | 程序人生&#xff08;ID&#xff1a;coder_life&#xff09; 小蔡&#xff0c; 90 年 10 月出生&#xff0c;Java开发工程师&#xff0c;目前就职于杭州滨江某知名互联网公司从事云计算开发工作&#xff0c;2013 年毕业就从山东来到了杭州。 …

【一哥闲聊】程序员如何打破35岁魔咒

公众号推文规则变了&#xff0c;点击上方 "数据社"关注, 设为星标 后台回复【加群】&#xff0c;申请加入数据学习交流群 大家好&#xff0c;我是一哥。今天跟大家聊聊程序员35岁以后的方向怎么选&#xff1f; 作为程序员&#xff0c;行业内一直流传着35岁的魔咒&…

码农翻身(随笔)

书一直都有在读&#xff0c;我会一直更新博文&#xff0c;欢迎大家前来阅读、指教&#xff01; XML和注解 xml&#xff1a;应用于集中配置的场合&#xff0c;比如数据源的配置&#xff1b; 注解&#xff1a;像Controller、RequestMapping、Transactional这样的注解&#xff…

读《码农翻身》有感

前几日偶得一本《码农翻身》&#xff0c;闲来品读&#xff0c;收获颇丰。 作者刘欣老师可能是码农中故事讲得最好的人&#xff0c;能把线程&#xff0c;进程&#xff0c;死锁这种概念讲成计算机内部王国漫游记&#xff0c;能把分布式事务这种高级概念讲成java王国中的权贵大臣勾…

告别码农,成为真正的程序员

本文是我借助 Google 从网上拼凑的文章&#xff0c;可能条理不是很清晰&#xff0c;希望对广大程序员们有些帮助。 一、成长的寓言&#xff1a;做一棵永远成长的苹果树 一棵苹果树&#xff0c;终于结果了。 第一年&#xff0c;它结了10个苹果&#xff0c;9个被拿走&#xff0c;…

达到年薪百万,就算码农翻身了吗?

上周末有个小伙伴问我&#xff1a;码农怎么样才能真正地翻身&#xff1f; 我自己都没有翻身&#xff0c;更没有达到财务自由&#xff0c; 回答这样的问题显然是力不从心的。 &#xff08;郑渊洁对财务自由的定义&#xff1a;从现在开始不工作&#xff0c;能保持现在的生活水平不…

《码农翻身》之技术之路

《码农翻身》读书笔记之技术之路 这是我的后端读书笔记系列文章的第四三篇&#xff0c;选取的是最近刚刚圈粉的知名博主刘欣创作的《码农翻身》。这篇文章只是最后一部分内容。 本文内容主要根据知名博主刘欣一作《码农翻身》的内容总结而来&#xff0c;本书的内容风趣幽默&a…

给大忙人看的码农翻身记

码农翻身记个人读后感 文章目录 码农翻身记个人读后感本书介绍大纲启发分享个人的能力欠缺的地方书中比较棒的建议 本书介绍 《码农翻身》用故事的方式讲解了软件编程的若干重要领域&#xff0c;侧重于基础性、原理性的知识。 非常适合刚入门大学生或者 计算机领域入行 一两年左…

码农翻身之编程语言的巅峰

“哇塞&#xff0c;怎么可能这么简单&#xff01;” 当C语言老头儿还是小伙子的时候&#xff0c;第一次见到了汇编&#xff0c;发出了这么一声感慨。 在C语言看来&#xff0c;这汇编的指令实在是太简单了&#xff0c;简单到了令人发指的地步&#xff0c;只有这么几类指令&…