使用 OpenCV、Imultis 和 EasyOCR 进行自动车牌检测
liebian365 2024-10-27 13:19 18 浏览 0 评论
在过去的几篇文章中,我们已经介绍了一些基本的图像处理概念和OpenCV库。让我们利用这些知识来解决一些现实生活中的问题。今天,我们将制作一个计算机视觉项目,允许汽车根据车牌号进入特定的物体或车库。此外,我们将向您展示如何使用两个在本项目中派上用场的附加库。
在本文中,我们将介绍:
- 要求和安装
- 概述
- 解释代码
- 最终结果
1. 要求
如果您想关注我们,请确保您已安装 python3.6 或更高版本。您还需要安装:OpenCV(用于图像处理),Easyocr(用于从图像读取)和Imutils(用于轮廓操作)。执行此操作的最佳方法是在命令行中运行以下代码。
pip install easyocr
pip install imutils
pip install opencv-python
2. 概述
目标是定义允许进入的汽车车牌号列表,并根据我们提供给算法的汽车图片,它将告诉我们是否授予了该汽车的访问权限。现在让我们解释一下我们计划如何做到这一点。这个想法是找到图像的轮廓,然后根据统计几率,车牌将是唯一一个在图像中用 4 个点定义的多边形状轮廓。
这因图片而异,但明智的假设是在现实生活中解决这个问题时,所有照片都将从相同的角度拍摄。检测到车牌后,我们将使用 EasyOCR 从图片中读取字母和数字,并将它们存储为字符串。之后我们要做的就是检查车牌号是否与现有车牌号匹配。现在让我们开始编码。
3. 代码解释
让我们首先加载一个图像并查看其车牌。
import numpy as np
import cv2
import easyocr
import imutils
from google.colab.patches import cv2_imshow
#Loading the picture
img = cv2.imread('car1.png')
cv2_imshow(img)
正如我们所看到的,该板是“PL8REC”。现在我们将定义一个包含此车牌号和两个附加随机数的列表。在我们完成算法后,这辆车应该被授予访问权限。稍后我们将从列表中删除这辆车,看看会发生什么。
valid_licence_plates = ['PL8RSC', 'SP34AS', 'TEA34S']
正如我们已经说过的,这个想法是找到此图像上的所有轮廓,然后找到定义看起来像多边形并在空间中定义 4 个点的轮廓。在此之前,我们将对图像应用高斯模糊。
原因是我们可以通过模糊图像来减少找到的总边缘的数量,同时仍然保留图像的重要部分,即汽车。让我们看看执行Canny边缘检测时正常图像和模糊图像之间的区别。
#Converting the image to gray-scale
image_gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
#Blurring the image with a 11x11 mask
blured_image = cv2.GaussianBlur(image_gray,(11,11),0)
#Finding the edges of the non blurred image
edge_image_blur = cv2.Canny(blured_image,30,100)
#Finding the edges of blurred image
edge_image_normal = cv2.Canny(image_gray,30,100)
cv2_imshow(edge_image_normal)
cv2_imshow(edge_image_blur)
正如我们所看到的,找到的边缘总数之间的差异非常大。我们应该注意,在选择高斯模糊的参数时必须小心,因为选择太大的蒙版会导致您丢失重要信息。现在让我们找到基于此图像的所有轮廓。
#Finding points of contours
key_points
=cv2.findContours(edge_image_blur,cv2.RETR_LIST,cv2.CHAIN_APPROX_SIMPLE)
#defining contours from keypoints
contours = imutils.grab_contours(key_points)
#drawing contours
cv2.drawContours(img, contours, -1, (0,255,0), 3)
cv2_imshow(img)
参数 cv2。RETR_LIST指定我们想要所有的轮廓,没有任何特定的层次结构和 cv2。CHAIN_APPROX_SIMPLE返回构造等值线所需的最小点数。使用 Imutils,我们将基于这些点组装轮廓,最后使用 cv2.drawContours,我们将在原始图像上绘制轮廓。
好的,现在我们有了图像的轮廓,我们应该尝试找到代表我们车牌的小矩形。正如我们之前提到的,我们将假设我们的图像在按面积排列的前二十个轮廓中只有一个矩形形状,从大到小。因此,让我们按此顺序对它们进行排序。
之后,我们将需要 cv2.approxPolyDP 函数来使用 n 顶点多引线近似每个轮廓。当然,当我们得到一个矩形近似值时,我们发现的顶点数将是四个。空间中的这四个点将代表我们板块的位置。
contours = sorted(contours, key=cv2.contourArea, reverse=True)[:20]
plate_location = None
for cnt in contours:
sqaure_approx = cv2.approxPolyDP(cnt, 10, True)
if len(sqaure_approx) == 4:
plate_location = sqaure_approx
print(plate_location)
#Output:
#[[[299 281]]
#[[445 278]]
#[[449 305]]
#[[303 311]]]
伟大!我们找到了我们的车牌。现在我们需要做的就是在这些位置裁剪图像以提取车牌。我们将找到 x 轴和 y 轴的最大值和最小位置,这些值将代表我们的边界。
x1, x2 = min(plate_location[:,0][:,1]), max(plate_location[:,0][:,1])
y1, y2 = min(plate_location[:,0][:,0]), max(plate_location[:,0][:,0])
cropped_image = image[x1:x2, y1:y2]
cv2_imshow(cropped_image)
之后,让我们定义一些我们将要称为读者的东西。读者将是类 Reader 的对象,它只接受一个参数 [“en”],它告诉读者我们在图像中使用什么语言。读取器是来自名为 EasyOCR 的第三方库中的类,其中 OCR 代表光学字符识别。它使用起来非常简单,我们建议您进一步阅读。
我们告诉读者使用方法read_text从上图阅读。Read_text输出返回一个非常不寻常的元组列表,其中包含文本位置、读取的文本、是否有效读取的确定性等。我们感兴趣的是放置在列表每个元组中倒数第二位的文本。为了提取和连接我们读取的所有字符串,我们将使用 map 函数。
x1, x2 = min(plate_location[:,0][:,1]), max(plate_location[:,0][:,1])
y1, y2 = min(plate_location[:,0][:,0]), max(plate_location[:,0][:,0])
cropped_image = image[x1:x2, y1:y2]
cv2_imshow(cropped_image)
reader = easyocr.Reader(['en'])
all_reads = reader.readtext(cropped_image)
license_plate = "".join(map(lambda read: read[-2], all_reads))
print(license_plate)
#Output
#PL8REC
现在我们有了车牌号,我们可以根据该号码是否在我们的列表中在屏幕上显示我们的答案。我们将在车牌周围画一个矩形,并告诉司机是否允许他进入。如果他在列表中,消息将显示为绿色,而在相反的情况下,将显示红色。正如我们所知,我们将他列入名单,我们期待一个绿色信息。
if license_plate in valid_licence_plates:
cv2.rectangle(image, pt1=(y1, x1), pt2=(y2, x2), color=(0, 255, 0), thickness = 5)
cv2.putText(image, 'Access Allowed', (y1 - 30,x2 + 30), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2, cv2.LINE_AA)
else:
cv2.rectangle(image, pt1=(y1, x1), pt2=(y2, x2), color=(0, 0, 255), thickness = 5)
cv2.putText(image, 'Access Denied', (y1 - 30,x2 + 30), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 255), 2, cv2.LINE_AA)
如果由于某种原因我们将这辆车从列表中删除。我们将显示类似这样的内容。
valid_licence_plates.remove("PL8REC")
3. 结论
正如我们所看到的,我们已经设法非常简单地构建了这个小而有用的应用程序。OpenCV在现实生活中的项目非常棒。它在安全,体育,工业,娱乐等方面有很多应用。当您需要操纵某些电气设备(如坡道或门)时,可以在此类项目中使用微控制器实现。可能性是无穷无尽的。在接下来的几篇文章中,我们将探索一些更伟大的事情,包括为我们的计算机视觉项目导入实时视频片段。敬请期待。
原文标题:Automatic License Plate Detection with OpenCV, Imultis and EasyOCR
原文链接:https://rubikscode.net/2022/06/27/automatic-license-plate-detection-with-opencv-imultis-and-easyocr/
作者:Stefan Nidzovic/Milos Marinkovic
编译:LCR
相关推荐
- 4万多吨豪华游轮遇险 竟是因为这个原因……
-
(观察者网讯)4.7万吨豪华游轮搁浅,竟是因为油量太低?据观察者网此前报道,挪威游轮“维京天空”号上周六(23日)在挪威近海发生引擎故障搁浅。船上载有1300多人,其中28人受伤住院。经过数天的调...
- “菜鸟黑客”必用兵器之“渗透测试篇二”
-
"菜鸟黑客"必用兵器之"渗透测试篇二"上篇文章主要针对伙伴们对"渗透测试"应该如何学习?"渗透测试"的基本流程?本篇文章继续上次的分享,接着介绍一下黑客们常用的渗透测试工具有哪些?以及用实验环境让大家...
- 科幻春晚丨《震动羽翼说“Hello”》两万年星间飞行,探测器对地球的最终告白
-
作者|藤井太洋译者|祝力新【编者按】2021年科幻春晚的最后一篇小说,来自大家喜爱的日本科幻作家藤井太洋。小说将视角放在一颗太空探测器上,延续了他一贯的浪漫风格。...
- 麦子陪你做作业(二):KEGG通路数据库的正确打开姿势
-
作者:麦子KEGG是通路数据库中最庞大的,涵盖基因组网络信息,主要注释基因的功能和调控关系。当我们选到了合适的候选分子,单变量研究也已做完,接着研究机制的时便可使用到它。你需要了解你的分子目前已有哪些...
- 知存科技王绍迪:突破存储墙瓶颈,详解存算一体架构优势
-
智东西(公众号:zhidxcom)编辑|韦世玮智东西6月5日消息,近日,在落幕不久的GTIC2021嵌入式AI创新峰会上,知存科技CEO王绍迪博士以《存算一体AI芯片:AIoT设备的算力新选择》...
- 每日新闻播报(September 14)_每日新闻播报英文
-
AnOscarstatuestandscoveredwithplasticduringpreparationsleadinguptothe87thAcademyAward...
- 香港新巴城巴开放实时到站数据 供科技界研发使用
-
中新网3月22日电据香港《明报》报道,香港特区政府致力推动智慧城市,鼓励公私营机构开放数据,以便科技界研发使用。香港运输署21日与新巴及城巴(两巴)公司签署谅解备忘录,两巴将于2019年第3季度,开...
- 5款不容错过的APP: Red Bull Alert,Flipagram,WifiMapper
-
本周有不少非常出色的app推出,鸵鸟电台做了一个小合集。亮相本周榜单的有WifiMapper's安卓版的app,其中包含了RedBull的一款新型闹钟,还有一款可爱的怪物主题益智游戏。一起来看看我...
- Qt动画效果展示_qt显示图片
-
今天在这篇博文中,主要实践Qt动画,做一个实例来讲解Qt动画使用,其界面如下图所示(由于没有录制为gif动画图片,所以请各位下载查看效果):该程序使用应用程序单窗口,主窗口继承于QMainWindow...
- 如何从0到1设计实现一门自己的脚本语言
-
作者:dong...
- 三年级语文上册 仿写句子 需要的直接下载打印吧
-
描写秋天的好句好段1.秋天来了,山野变成了美丽的图画。苹果露出红红的脸庞,梨树挂起金黄的灯笼,高粱举起了燃烧的火把。大雁在天空一会儿写“人”字,一会儿写“一”字。2.花园里,菊花争奇斗艳,红的似火,粉...
- C++|那些一看就很简洁、优雅、经典的小代码段
-
目录0等概率随机洗牌:1大小写转换2字符串复制...
- 二年级上册语文必考句子仿写,家长打印,孩子照着练
-
二年级上册语文必考句子仿写,家长打印,孩子照着练。具体如下:...
你 发表评论:
欢迎- 一周热门
- 最近发表
- 标签列表
-
- wireshark怎么抓包 (75)
- qt sleep (64)
- cs1.6指令代码大全 (55)
- factory-method (60)
- sqlite3_bind_blob (52)
- hibernate update (63)
- c++ base64 (70)
- nc 命令 (52)
- wm_close (51)
- epollin (51)
- sqlca.sqlcode (57)
- lua ipairs (60)
- tv_usec (64)
- 命令行进入文件夹 (53)
- postgresql array (57)
- statfs函数 (57)
- .project文件 (54)
- lua require (56)
- for_each (67)
- c#工厂模式 (57)
- wxsqlite3 (66)
- dmesg -c (58)
- fopen参数 (53)
- tar -zxvf -c (55)
- 速递查询 (52)