当前位置: 首页 > news >正文

计算机视觉cv2入门之车牌号码识别

    前边我们已经讲解了使用cv2进行图像预处理与边缘检测等方面的知识,这里我们以车牌号码识别这一案例来实操一下。

大致思路

        车牌号码识别的大致流程可以分为这三步:图像预处理-寻找车牌轮廓-车牌OCR识别

接下来我们按照这三步来进行讲解。

图像预处理

首先,在网上随便找一张车牌照:

读取图像 

#读取原始图像
import cv2
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif']=['SimHei']
src_path=r'LicensePlate.jpg'
src_image=cv2.imread(filename=src_path,flags=cv2.IMREAD_COLOR_RGB)
print(src_image.shape)
plt.title('原始图像')
plt.imshow(src_image)

        这里我使用matplotlib的imshow函数来显示图像,这样在jupyter环境中可以不打开任何弹窗直接显示图像,比较方便。

转为灰度图

#转为灰度图
gray_image=cv2.cvtColor(src=src_image,code=cv2.COLOR_RGB2GRAY)
plt.title('原始图像(灰度图)')
plt.imshow(gray_image,cmap='gray')

        将原始图像转化为灰度图是为了后续的检测等操作,在计算机视觉任务中,基本上所有的操作都是针对灰度图来进行的,灰度图是将原始图像的多个通道按照一定权重求和叠加而来,这样一来多通道变成了单通道(Gray=w_1*B+w_2*G+w_3*R),在计算量上也会比较友好。

 阈值化

#阈值化
thresh,binary_image=cv2.threshold(src=gray_image,thresh=128,maxval=255,type=cv2.THRESH_OTSU+cv2.THRESH_BINARY)
plt.imshow(binary_image,cmap='gray')

        阈值化是为了后续的边缘检测,通常在边缘检测前都需要对图像进行阈值化操作,这样识别出来的边缘相对准确。这里阈值化我们使用cv2.THRESH+cv2.THRESH-OTSU方法来自动对图像进行二值化阈值分割。 

边缘检测

#canny边缘检测
edges=cv2.Canny(image=binary_image,threshold1=0.5*thresh,threshold2=thresh,apertureSize=5,L2gradient=True)
plt.imshow(edges,cmap='gray')

        边缘检测是为了初步提取出车牌的轮廓,便于后续的轮廓查找。常用的边缘检测算法有Canny、Sobel、Prewitt等,其中Canny算法具有较高的准确性和鲁棒性,因此在本系统中采用Canny算法进行边缘检测。不太熟悉边缘检测的小伙伴可以去看看我的往期文章:

https://blog.csdn.net/weixin_73953650/article/details/146284620?sharetype=blogdetail&sharerId=146284620&sharerefer=PC&sharesource=weixin_73953650&spm=1011.2480.3001.8118https://blog.csdn.net/weixin_73953650/article/details/146284620?sharetype=blogdetail&sharerId=146284620&sharerefer=PC&sharesource=weixin_73953650&spm=1011.2480.3001.8118

 车牌轮廓查找

#寻找矩形区域轮廓
contours,hiercahy=cv2.findContours(edges,mode=cv2.RETR_TREE,method=cv2.CHAIN_APPROX_SIMPLE)
contours=sorted(contours,key=cv2.contourArea,reverse=True)[:10]
rectangle=None
for point in contours:peri=cv2.arcLength(point,True)polygons=cv2.approxPolyDP(curve=point,epsilon=0.018*peri,closed=True)if len(polygons)==4:rectangle=polygonsplateArea=pointbreak
gray_image_copy=gray_image.copy()
src_image_copy=src_image.copy()
cv2.drawContours(image=src_image_copy,contours=[rectangle],contourIdx=0,color=(255,0,0),thickness=5)
cv2.drawContours(image=gray_image_copy,contours=[rectangle],contourIdx=0,color=255,thickness=5)
figure=plt.figure(figsize=(10,10),dpi=100)
plt.subplot(1,2,1),plt.imshow(src_image_copy),plt.title('车牌定位结果(原始图像)')
plt.subplot(1,2,2),plt.imshow(gray_image_copy,cmap='gray'),plt.title('车牌定位结果(灰度图)')

 

 

         查找轮廓时我们通常使用findContours函数来进行查找(返回值为所有可能的轮廓点contours以及这些点之间的拓扑结构hierachy),考虑到车牌是矩形区域,因此我们可以在查找到的轮廓点中使用cv2.approxPolyDP函数来对查找到的轮廓进行多边形拟合(返回值为各个顶点的坐标构成的列表)只要拟合出的多边形顶点个数为4,那么必然是车牌位置。

       然后,我们再使用cv2.drawContours函数将其在原始图像中标记出来即可。

车牌分割

# #分割提取车牌
x=[location[0][0] for location in plateArea]
y=[location[0][1] for location in plateArea]
Licenseplate=gray_image[min(y):max(y),min(x):max(x)]#切片图像
plt.imshow(Licenseplate,cmap='gray')
cv2.imwrite('Plate.jpg',Licenseplate)

 

 

        将车牌从原始图像中分割出来的思路也很简单,就是根据我们查找到的轮廓点,来查找其在图像中的位置。PlatArea是矩形车牌轮廓点构成的列表,其内部为各个点的坐标,其中对于任意一点location来说,location[0][0]表示x坐标,location[0][1]表示y坐标。那么,我们只需找到所有x坐标中的最小值与最大值,y坐标中的最小值与最大值,即可确定这个矩形区域在原图像中的范围。 

 最后,我们还需将这个车牌号码保存一下以便后续的字符识别

OCR识别

        考虑到车牌是标准的印刷体,这里我们使用现成的OCR字符识别库,这里我使用的是ddddocr

获取方式

pip install ddddocr

OCR识别

#使用ddddocr进行光学识别
import ddddocr
ocr=ddddocr.DdddOcr(show_ad=False,beta=True)
image=open('Plate.jpg','rb')
answer=ocr.classification(image.read())
image.close()
print(f'车牌号为:{answer.upper()}')
plt.imshow(src_image,cmap='gray')
plt.text(x=src_image.shape[1]//4,y=src_image.shape[0]/2,s=f'车牌号为:{answer.upper()}',size=20,color='red')

 

        使用ddddocr时需要传入的图像数据是Bytes类型,因此我们使用open(‘.jpg’,'rb').read()语句即可实现读取图像的bytes数据,最后我们再将得到的结果其标注在原始图像上。 

 

完整代码

#读取原始图像
import cv2
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif']=['SimHei']
src_path=r'LicensePlate.jpg'
src_image=cv2.imread(filename=src_path,flags=cv2.IMREAD_COLOR_RGB)
print(src_image.shape)
plt.title('原始图像')
plt.imshow(src_image)
#转为灰度图
gray_image=cv2.cvtColor(src=src_image,code=cv2.COLOR_RGB2GRAY)
plt.title('原始图像(灰度图)')
plt.imshow(gray_image,cmap='gray')
#阈值化
thresh,binary_image=cv2.threshold(src=gray_image,thresh=128,maxval=255,type=cv2.THRESH_OTSU+cv2.THRESH_BINARY)
plt.imshow(binary_image,cmap='gray')
#canny边缘检测
edges=cv2.Canny(image=binary_image,threshold1=0.5*thresh,threshold2=thresh,apertureSize=5,L2gradient=True)
plt.imshow(edges,cmap='gray')
#寻找矩形区域轮廓
contours,hiercahy=cv2.findContours(edges,mode=cv2.RETR_TREE,method=cv2.CHAIN_APPROX_SIMPLE)
contours=sorted(contours,key=cv2.contourArea,reverse=True)[:10]
rectangle=None
for point in contours:peri=cv2.arcLength(point,True)polygons=cv2.approxPolyDP(curve=point,epsilon=0.018*peri,closed=True)if len(polygons)==4:rectangle=polygonsplateArea=pointbreak
gray_image_copy=gray_image.copy()
src_image_copy=src_image.copy()
cv2.drawContours(image=src_image_copy,contours=[rectangle],contourIdx=0,color=(255,0,0),thickness=5)
cv2.drawContours(image=gray_image_copy,contours=[rectangle],contourIdx=0,color=255,thickness=5)
figure=plt.figure(figsize=(10,10),dpi=100)
plt.subplot(1,2,1),plt.imshow(src_image_copy),plt.title('车牌定位结果(原始图像)')
plt.subplot(1,2,2),plt.imshow(gray_image_copy,cmap='gray'),plt.title('车牌定位结果(灰度图)')
# #分割提取车牌
x=[location[0][0] for location in plateArea]
y=[location[0][1] for location in plateArea]
Licenseplate=gray_image[min(y):max(y),min(x):max(x)]#切片图像
plt.imshow(Licenseplate,cmap='gray')
cv2.imwrite('Plate.jpg',Licenseplate)
#使用ddddocr进行光学识别
import ddddocr
ocr=ddddocr.DdddOcr(show_ad=False,beta=True)
image=open('Plate.jpg','rb')
answer=ocr.classification(image.read())
image.close()
print(f'车牌号为:{answer.upper()}')
plt.imshow(src_image,cmap='gray')
plt.text(x=src_image.shape[1]//4,y=src_image.shape[0]/2,s=f'车牌号为:{answer.upper()}',size=20,color='red')

总结 

 

        以上便是计算机视觉cv2入门之车牌号码识别的所有内容,如果本文对你有用,还劳驾各位一键三连支持一下博主。

相关文章:

  • 代码随想录算法训练营day7(字符串)
  • C++:PTA L1-006 连续因子
  • 中华传承-医山命相卜-梅花易数
  • leetcode0145. 二叉树的后序遍历-easy
  • 班翎流程平台 | 全新Agent节点,助您构建企业智能流程
  • 极狐GitLab 登录限制如何设置?
  • React 列表渲染基础示例
  • 【裁判文书网DES3数据解密】逆向分析
  • HTTP测试智能化升级:动态变量管理实战与效能跃迁
  • C++使用STL容器迭代器失效情况
  • 安全测试报告模板
  • 小刚说C语言刷题——1033 判断奇偶数
  • Spark on K8s 在 vivo 大数据平台的混部实战与优化
  • 处理图像的深度神经网络(DNN)有哪些呢?
  • MCP服务端开发
  • Thymeleaf简介
  • 基于单片机的温湿度采集系统(论文+源码)
  • uniapp打包报错,
  • 第12篇:Linux程序访问控制FPGA端Switch<一>
  • 习题2.8 输出全排列
  • 独家专访|苏童:《好天气》是一部献给中国郊区的作品
  • 青创上海—2025浦东徒步行活动举行,“青年草坪创新创业湃对”正式亮相
  • 美国国务卿:乌克兰问题谈判不能一直停滞不前
  • 许志强评《伐木》|伯恩哈德的文人共和国
  • 一季度江西GDP达7927.1亿元,同比增长5.7%
  • 正义网评“一男两女举办婚礼”:“一夫多妻”流量闹剧该歇了