在过去的几篇文章中,我们已经介绍了一些基本的图像处理概念和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