计算机视觉:使用opencv实现车牌识别

1 引言

汽车车牌识别(License Plate Recognition)是一个日常生活中的普遍应用,特别是在智能交通系统中,汽车牌照识别发挥了巨大的作用。汽车牌照的自动识别技术是把处理图像的方法与计算机的软件技术相连接在一起,以准确识别出车牌牌照的字符为目的,将识别出的数据传送至交通实时管理系统,以最终实现交通监管的功能。在车牌自动识别系统中,从汽车图像的获取到车牌字符处理是一个复杂的过程,主要分为四个阶段:图像获取、车牌定位、字符分割以及字符识别。目前关于车牌识别的算法有很多,本文基于opencv构建了车牌识别的整个流程,供大家学习参考。

1 车牌识别概述

1.1 opencv介绍

OpenCV的全称是:Open Source Computer Vision Library。OpenCV是一个基于开源发行的跨平台计算机视觉库,可以运行在Linux、Windows和Mac OS操作系统上。它轻量级而且高效——由一系列 C 函数和少量 C++ 类构成,同时提供了Python、Ruby、MATLAB等语言的接口,实现了图像处理和计算机视觉方面的很多通用算法。

1.2 车牌识别分解

车牌辨认的整个过程,可以拆解为以下三个步骤:

  • 车牌定位: 第一步是从轿车上检测车牌地点方位。本文将运用OpenCV中矩形的边框检测来找到车牌位置。
  • 字符切割:检测到车牌后,使用opencv将其裁剪并保存为新的图片,用于后续识别。
  • 字符辨认: 在新的图片运用光学字符识(OCR)技术,提取图片中的文字、字符、数字。

2 车牌识别的实现

2.1 车牌定位

我国的汽车牌照一般由七个字符和一个点组成,车牌字符的高度和宽度是固定的,分别为90mm和45mm,七个字符之间的距离也是固定的12mm,点分割符的直径是10mm,字符间的差异可能会引起字符间的距离变化。

在民用车牌中,字符的排列位置遵循以下规律:

  • 第一个字符通常是我国各省区的简称,用汉字表示;
  • 第二个字符通常是发证机关的代码号,最后五个字符由英文字母和数字组合而成,字母是二十四个大写字母(除去I和O这两个字母)的组合,数字用"0-9"之间的数字表示。

从图像处理角度看,汽车牌照有以下几个特征:

  • 第一个特征是是车牌的几何特征,即车牌形状统一为长宽高固定的矩形;
  • 第二个特征是车牌的灰度分布呈现出连续的波谷-波峰-波谷分布,这是因为我国车牌颜色单一,字符直线排列;
  • 第三个特征是车牌直方图呈现出双峰状的特点,即车牌直方图中可以看到双个波峰;
  • 第四个特征是车牌具有强边缘信息,这是因为车牌的字符相对集中在车牌的中心,而车牌边缘无字符,因此车牌的边缘信息感较强;
  • 第五个特征是车牌的字符颜色和车牌背景颜色对比鲜明。目前,我国国内的车牌大致可分为蓝底白字和黄底黑字,特殊用车采用白底黑字或黑底白字,有时辅以红色字体等。

为了简化处理,本次学习中只考虑蓝底白字的车牌。

2.1.1 图像加载与灰度化

import cv2img = cv2.imread('../data/bmw01.jpg')# 调整图片大小
img = cv2.resize(img, (1024, 800))# 灰度图
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)# 显示效果
cv2.imshow('gray', gray)
cv2.waitKey(0)
cv2.destroyAllWindows()

显示结果如下:

2.1.2 双边滤波去除噪声

# 双边滤波
blf = cv2.bilateralFilter(gray, 13, 15, 15)
show_image('bilateralFilter', blf)

显示结果如下:

2.1.3 边缘检测

# 边缘检测
edged = cv2.Canny(blf, 30, 200)
show_image('canny', edged)

显示结果如下:

2.1.4 寻找车牌轮廓(四边形)

cv2.findContours说明:

  • opencv3.x
image, contours, hierarchy = cv.findContours(image, mode, method[, contours[, hierarchy[, offset]]])
  • opencv2.x和4.x
contours, hierarchy = cv.findContours(image, mode, method[, contours[, hierarchy[, offset]]])

OpenCV中HSV空间颜色对照表

提取图像区域的颜色

def reg_area_color(image):"""找到原图像最多的颜色,当该颜色为红色或蓝色时返回该颜色的名称"""kernel = np.ones((35, 35), np.uint8)hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)# 以上为图像处理Open = cv2.morphologyEx(hsv, cv2.MORPH_OPEN, kernel)# 对Open图像的H通道进行直方图统计hist = cv2.calcHist([Open], [0], None, [180], [0, 180])# 找到直方图hist中列方向最大的点hist_maxhist_max = np.where(hist == np.max(hist))# hist_max[0]为hist_max的行方向的值,即H的值,H在0~10为红色if 0 < hist_max[0] < 10:res_color = 'red'elif 100 < hist_max[0] < 124:  # H在100~124为蓝色res_color = 'blue'else:# H不在前两者之间跳出函数res_color = 'unknow'return res_color

寻找车牌轮廓:

# 寻找轮廓(图像矩阵,输出模式,近似方法)
contours, _ = cv2.findContours(edged.copy(), cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
# 根据区域大小排序取前十
contours = sorted(contours, key=cv2.contourArea, reverse=True)[:10]
screenCnt = None
# 遍历轮廓,找到车牌轮廓
for c in contours:if cv2.contourArea(c) > 1024 * 768 * 0.05:continue# 计算轮廓周长(轮廓,是否闭合)peri = cv2.arcLength(c, True)# 折线化(轮廓,阈值(越小越接近曲线),是否闭合)返回折线顶点坐标approx = cv2.approxPolyDP(c, 0.018 * peri, True)# 获取四个顶点(即四边形, 左下/右下/右上/左上if len(approx) == 4:# [参数]左上角纵坐标:左下角纵坐标,左上角横坐标:右上角横坐标crop_image = img[approx[3][0][1]:approx[0][0][1], approx[3][0][0]:approx[2][0][0]]show_image('crop', crop_image)if 'blue' == reg_area_color(crop_image):screenCnt = approxbreak
# 如果找到了四边形
if screenCnt is not None:# 根据四个顶点坐标对img画线(图像矩阵,轮廓坐标集,轮廓索引,颜色,线条粗细)cv2.drawContours(img, [screenCnt], -1, (0, 0, 255), 3)show_image('contour', img)

运行结果显示:

2.1.5 图像位运算进行遮罩

"""遮罩"""
# 创建一个灰度图一样大小的图像矩阵
mask = np.zeros(gray.shape, np.uint8)
# 将创建的图像矩阵的车牌区域画成白色
cv2.drawContours(mask, [screenCnt], 0, 255, -1, )
# 图像位运算进行遮罩
mask_image = cv2.bitwise_and(img, img, mask=mask)
show_image('mask_image', mask_image)

运行结果显示:

2.1.6 图像剪裁

"""图像剪裁"""
# 获取车牌区域的所有坐标点
(x, y) = np.where(mask == 255)
# 获取底部顶点坐标
(topx, topy) = (np.min(x), np.min(y))
# 获取底部坐标
(bottomx, bottomy,) = (np.max(x), np.max(y))
# 剪裁
Cropped = gray[topx:bottomx, topy:bottomy]

运行结果显示:

2.1.7 OCR字符识别

paddleocr是一款轻量型字符识别工具库,支持多语言识别,支持pip安装与自定义训练。

  • conda下工具类安装
pip install paddleocr -i https://mirror.baidu.com/pypi/simple 
pip install paddlepaddle -i https://mirror.baidu.com/pypi/simple 

代码实现:

"""OCR识别"""# 使用CPU预加载,不用GPU
ocr = PaddleOCR(use_angle_cls=True, use_gpu=False, ocr_version='PP-OCRv3')
text = ocr.ocr(cropped, cls=True)
for t in text:print(t[0][1])

运行结果显示如下:

[2023/11/15 20:57:43] ppocr DEBUG: dt_boxes num : 1, elapsed : 0.016942501068115234
[2023/11/15 20:57:43] ppocr DEBUG: cls num  : 1, elapsed : 0.013955354690551758
[2023/11/15 20:57:43] ppocr DEBUG: rec_res num  : 1, elapsed : 0.12021970748901367
('苏A·0MR20', 0.8559348583221436)

2.2 完整代码实现

import cv2
import numpy as np
from paddleocr import PaddleOCRdef show_image(desc, image):cv2.imshow(desc, image)cv2.waitKey(0)cv2.destroyAllWindows()def reg_area_color(image):"""找到原图像最多的颜色,当该颜色为红色或蓝色时返回该颜色的名称"""kernel = np.ones((35, 35), np.uint8)hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)# 以上为图像处理Open = cv2.morphologyEx(hsv, cv2.MORPH_OPEN, kernel)# 对Open图像的H通道进行直方图统计hist = cv2.calcHist([Open], [0], None, [180], [0, 180])# 找到直方图hist中列方向最大的点hist_maxhist_max = np.where(hist == np.max(hist))# hist_max[0]为hist_max的行方向的值,即H的值,H在0~10为红色if 0 < hist_max[0] < 10:res_color = 'red'elif 100 < hist_max[0] < 124:  # H在100~124为蓝色res_color = 'blue'else:# H不在前两者之间跳出函数res_color = 'unknow'return res_colorimg = cv2.imread('../data/bmw01.jpg')# 调整图片大小
img = cv2.resize(img, (1024, 768))# 灰度图
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
show_image('gray', gray)# 双边滤波
blf = cv2.bilateralFilter(gray, 13, 15, 15)
show_image('bilateralFilter', blf)# 边缘检测
edged = cv2.Canny(blf, 30, 200)
show_image('canny', edged)# 寻找轮廓(图像矩阵,输出模式,近似方法)
contours, _ = cv2.findContours(edged.copy(), cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
# 根据区域大小排序取前十
contours = sorted(contours, key=cv2.contourArea, reverse=True)[:10]
screenCnt = None
# 遍历轮廓,找到车牌轮廓
for c in contours:if cv2.contourArea(c) > 1024 * 768 * 0.05:continue# 计算轮廓周长(轮廓,是否闭合)peri = cv2.arcLength(c, True)# 折线化(轮廓,阈值(越小越接近曲线),是否闭合)返回折线顶点坐标approx = cv2.approxPolyDP(c, 0.018 * peri, True)# 获取四个顶点(即四边形, 左下/右下/右上/左上if len(approx) == 4:# [参数]左上角纵坐标:左下角纵坐标,左上角横坐标:右上角横坐标crop_image = img[approx[3][0][1]:approx[0][0][1], approx[3][0][0]:approx[2][0][0]]show_image('crop', crop_image)if 'blue' == reg_area_color(crop_image):screenCnt = approxbreak
# 如果找到了四边形
if screenCnt is not None:# 根据四个顶点坐标对img画线(图像矩阵,轮廓坐标集,轮廓索引,颜色,线条粗细)cv2.drawContours(img, [screenCnt], -1, (0, 0, 255), 3)show_image('contour', img)"""遮罩"""
# 创建一个灰度图一样大小的图像矩阵
mask = np.zeros(gray.shape, np.uint8)
# 将创建的图像矩阵的车牌区域画成白色
cv2.drawContours(mask, [screenCnt], 0, 255, -1, )
# 图像位运算进行遮罩
mask_image = cv2.bitwise_and(img, img, mask=mask)
show_image('mask_image', mask_image)"""图像剪裁"""
# 获取车牌区域的所有坐标点
(x, y) = np.where(mask == 255)
# 获取底部顶点坐标
(topx, topy) = (np.min(x), np.min(y))
# 获取底部坐标
(bottomx, bottomy,) = (np.max(x), np.max(y))
# 剪裁
cropped = gray[topx:bottomx, topy:bottomy]
show_image('cropped', cropped)"""OCR识别"""
# 使用CPU预加载,不用GPU
ocr = PaddleOCR(use_angle_cls=True, use_gpu=False, ocr_version='PP-OCRv3')
text = ocr.ocr(cropped, cls=True)
for t in text:print(t[0][1])

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/148463.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Flutter 中在单个屏幕上实现多个列表

今天&#xff0c;我将提供一个实际的示例&#xff0c;演示如何在单个页面上实现多个列表&#xff0c;这些列表可以水平排列、网格格式、垂直排列&#xff0c;甚至是这些常用布局的组合。 下面是要做的&#xff1a; 实现 让我们从创建一个包含产品所有属性的产品模型开始。 …

ZJU Beamer学习手册(二)

ZJU Beamer学习手册基于 Overleaf 的 ZJU Beamer模板 进行解读&#xff0c;本文则基于该模版进行进一步修改。 参考文献 首先在frame文件夹中增加reference.tex文件&#xff0c;文件内容如下。这段代码对参考文献的引用进行了预处理。 \usepackage[backendbiber]{biblatex} \…

【机器学习】划分训练集和测试集的方法

在机器学习中&#xff0c;我们的模型建立完成后&#xff0c;通常要根据评估指标来对模型进行评估&#xff0c;以此来判断模型的可用性。而评估指标主要的目的是让模型在未知数据上的预测能力最好。因此&#xff0c;我们在模型训练之前&#xff0c;要对训练集和测试集进行划分。…

【Python数据结构与算法】——(线性结构)精选好题分享,不挂科必看系列

&#x1f308;个人主页: Aileen_0v0&#x1f525;系列专栏:<<Python数据结构与算法专栏>>&#x1f4ab;个人格言:"没有罗马,那就自己创造罗马~" 时间复杂度大小比较 1.time complexity of algorithm A is O(n^3) while algorithm B is O(2^n). Which o…

股东入股可用的出资形式主要有哪些

股东入股&#xff0c;可用的出资形式主要包括货币以及实物、知识产权、土地使用权等可以用货币估价并可以依法转让的非货币财产。 第一&#xff0c;货币。设立公司必然需要一定数量的流动资金。以支付创建公司时的开支和启动公司运营。因此&#xff0c;股东可以用货币出资。 第…

自学嵌入式,已经会用stm32做各种小东西了

自学嵌入式&#xff0c;已经会用stm32做各种小东西了 1、stm32 工程中&#xff0c;定义一个变量&#xff0c;记录复位次数&#xff0c;即复位一次变量加一。要求不许用备份寄存器和 flash 保存信息。本题只讨论不断电热启动情况&#xff0c;至于冷启动&#xff0c;不在此讨论。…

【MATLAB源码-第80期】基于蚯蚓优化算法(EOA)的无人机三维路径规划,输出做短路径图和适应度曲线

操作环境&#xff1a; MATLAB 2022a 1、算法描述 蚯蚓优化算法&#xff08;Earthworm Optimisation Algorithm, EOA&#xff09;是一种启发式算法&#xff0c;灵感来源于蚯蚓在自然界中的行为模式。蚯蚓优化算法主要模仿了蚯蚓在寻找食物和逃避天敌时的行为策略。以下是蚯蚓…

【论文阅读】基于隐蔽带宽的汽车控制网络鲁棒认证(二)

文章目录 第三章 识别CAN中的隐藏带宽信道3.1 隐蔽带宽vs.隐藏带宽3.1.1 隐蔽通道3.1.2 隐藏带宽通道 3.2 通道属性3.3 CAN隐藏带宽信道3.3.1 CAN帧ID字段3.3.2 CAN帧数据字段3.3.3 帧错误检测领域3.3.4 时间通道3.3.5 混合通道 3.4 构建信道带宽公式3.5通道矩阵3.6 结论 第四章…

视频集中存储/云存储平台EasyCVR级联下级平台的详细步骤

安防视频监控/视频集中存储/云存储/磁盘阵列EasyCVR平台可拓展性强、视频能力灵活、部署轻快&#xff0c;可支持的主流标准协议有国标GB28181、RTSP/Onvif、RTMP等&#xff0c;以及支持厂家私有协议与SDK接入&#xff0c;包括海康Ehome、海大宇等设备的SDK等。平台既具备传统安…

前台页面从数据库中获取下拉框值

后端&#xff1a;查询所有信息 前台&#xff1a;elementUI <el-select v-model"searchData.stationName" clearable> <el-option :label"item.stationName" :value"item.stationName" v-for"item in stationNameList&quo…

GoLong的学习之路,进阶,标准库之并发(context)补充并发三部曲,你真的明白context吗?

其实对于&#xff0c;context来说&#xff0c;如果只是用来做并发处理就有些不太合适。因为对于golang来说&#xff0c;context应用场景不仅在并发有用&#xff0c;并且在网络链接&#xff0c;http处理&#xff0c;gorm中都有体现。但是其实&#xff0c;本质来说。以上这些场景…

【Java 进阶篇】JQuery 事件绑定:`on` 与 `off` 的奇妙舞曲

在前端开发的舞台上&#xff0c;用户与页面的互动是一场精彩的表演。而 JQuery&#xff0c;作为 JavaScript 的一种封装库&#xff0c;为这场表演提供了更为便捷和优雅的事件绑定方式。其中&#xff0c;on 和 off 两位主角&#xff0c;正是这场奇妙舞曲中的核心演员。在这篇博客…

Flask 接口

目录 前言 代码实现 简单接口实现 执行其它程序接口 携带参数访问接口 前言 有时候会想着开个一个接口来访问试试&#xff0c;这里就给出一个基础接口代码示例 代码实现 导入Flask模块&#xff0c;没安装Flask 模块需要进行 安装&#xff1a;pip install flask 使用镜…

Redis数据的持久化

Redis的持久化有两种方式&#xff1a; RDB&#xff08;Redis Database&#xff09;和AOF&#xff08;Append Only File&#xff09; 目录 一、RDB 保存方式 2、rdb在redis.conf文件中的配置 二、AOF 1、保存方式 2、aof方式持久化在redis.conf文件中的配置 三、持久化建…

【迅搜01】安装运行并测试XunSearch

安装运行并测试XunSearch 这回的新系列&#xff0c;我们将学习到的是一个搜索引擎 迅搜 XunSearch 的使用。这个搜索引擎在 PHP 圈可能还是有一点名气的&#xff0c;而且也是一直在更新的&#xff0c;虽说现在 ElasticSearch 已经是实际上的搜索引擎霸主了&#xff0c;而且还有…

Vue3 shallowRef 和 shallowReactive

一、shallowRef 使用shallowRef之前需要进行引入&#xff1a; import { shallowRef } from vue; 使用方法和ref 的使用方法一致&#xff0c;以下是二者的区别&#xff1a; 1. 如果ref 和 shallowRef 都传入的是普通数据类型的数据&#xff0c;那么他们的效果是一样的&#x…

【计算机基础】优雅的PPT就应该这样设计

&#x1f4e2;&#xff1a;如果你也对机器人、人工智能感兴趣&#xff0c;看来我们志同道合✨ &#x1f4e2;&#xff1a;不妨浏览一下我的博客主页【https://blog.csdn.net/weixin_51244852】 &#x1f4e2;&#xff1a;文章若有幸对你有帮助&#xff0c;可点赞 &#x1f44d;…

【顺序表的实现】

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 目录 前言 1. 数据结构相关概念 1、什么是数据结构 2、为什么需要数据结构&#xff1f; 2、顺序表 1、顺序表的概念及结构 1.1 线性表 2、顺序表分类 3、动态顺序表的实现 总…

6. hdfs的命令操作

简介 本文主要介绍hdfs通过命令行操作文件 操作文件有几种方式&#xff0c;看个人习惯 hdfs dfs hdfs fs hadoop fs个人习惯使用 hadoop fs 可操作任何对象&#xff0c;命令基本上跟linux命令一样 Usage [hadoophadoop01 ~]$ hadoop fs Usage: hadoop fs [generic option…

【广州华锐互动VRAR】VR元宇宙技术在气象卫星知识科普中的应用

随着科技的不断发展&#xff0c;虚拟现实&#xff08;VR&#xff09;和元宇宙等技术正逐渐走进我们的生活。这些技术为我们提供了一个全新的互动平台&#xff0c;使我们能够以更加直观和生动的方式了解和学习各种知识。在气象天文领域&#xff0c;VR元宇宙技术的应用也日益显现…