用OpenCV、Imultis和EasyOCR自动检测车牌号程序介绍

289 阅读6分钟

在过去的几篇文章中,我们已经介绍了一些基本的图像处理概念和OpenCV库。让我们用这些知识来解决一些现实生活中的问题。今天我们要做一个计算机视觉项目,让汽车根据车牌号进入一个特定的物体或车库。同时,我们将向你展示如何使用两个额外的库,它们将在这个项目中派上用场。

在这篇文章中,我们将介绍:

  1. 要求和安装
  2. 概述
  3. 解释代码
  4. 最终结果

1.要求

如果你想和我们一起学习,请确保你已经安装了python3.6或更新版本。此外,你还需要安装。OpenCV(用于图像处理),Easyocr(用于读取图像)和Imutils(用于轮廓操作)。最好的方法是在你的命令行中运行以下代码。

pip install easyocr
pip install imutils
pip install opencv-python

2.2.概述

我们的目标是定义一个允许进入的车牌号列表,根据我们提供给算法的汽车图片,它将告诉我们该车是否被允许进入。现在我们来解释一下我们打算如何做。我们的想法是找到图片的轮廓,然后根据统计学上的几率,车牌将是一张图片中唯一用4个点定义的多边形轮廓。

Data Visual

这因图片而异,但我们可以理智地认为,在现实生活中解决这个问题时,所有的图片都是从同一角度拍摄的。在我们检测到车牌后,我们将使用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)

Data Visual

我们可以看到车牌是'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)

Data Visual

Data Visual

正如我们所看到的,发现的边缘总数之间的差异是相当大的。我们应该注意到,在选择高斯模糊的参数时,你必须小心,因为选择太大的掩码会导致你失去重要的信息。现在让我们根据这个图像找到所有的轮廓线。

#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,我们将在原始图像上绘制轮廓线。

Data Visual

好了,现在我们有了图像的轮廓线,我们应该试着找到代表我们车牌的那个小的矩形。正如我们之前提到的,我们要假设我们的图像在按面积计算的前二十个等高线中只有一个长方形,从大到小开始。因此,让我们按照这个顺序对它们进行排序。

之后,我们将需要cv2.actroxPolyDP函数来用一个n顶点的polyleader来近似每个轮廓。自然,当我们来到一个矩形的近似时,我们找到的顶点数量将是四个。空间中的这四个点将代表我们板材的位置。

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)

Histogram OpenCV

之后,让我们定义一个我们将称之为阅读器的东西。读取器将是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)

Data Visual

而如果由于某种原因,我们把这辆车从我们的列表中删除。我们会显示这样的信息。

valid_licence_plates.remove("PL8REC")

Data Visual

3.总结

正如我们所看到的,我们已经成功地建立了这个小而有用的应用程序,非常简单。OpenCV在现实生活的项目中是非常棒的。它在安全、体育、工业、娱乐等方面有很多应用。在这样的项目中,当你需要引导一些电动设备,如斜坡或门时,它可以用微控制器来实现。这种可能性是无穷无尽的。在接下来的几篇文章中,我们将探索更多的好东西,包括为我们的计算机视觉项目导入实时视频片段。因此,请继续关注。