车牌识别及步骤
1.车牌检测:第一步是从车上检测车牌。我们将使用OpenCV中的轮廓选项来检测矩形对象以查找车牌。如果我们知道车牌的确切尺寸、颜色和大致位置,可以提高准确度。通常,检测算法是根据特定国家使用的摄像机位置和车牌类型进行训练的。如果图像中甚至没有汽车,这将变得更加棘手,在这种情况下,我们将执行额外的步骤来检测汽车,然后是车牌。
2.字符分割:一旦我们检测到车牌,我们必须将其裁剪出来并保存为新图像。同样,使用OpenCV也可以轻松地完成此操作。
3.字符识别:现在,我们在上一步中获得的新图像肯定会有一些字符(数字/字母)写在上面。因此,我们可以对其执行OCR(光学字符识别)来检测数字。
先决条件:
步骤1 安装依赖库
# installing OpenCV
>pip install opencv-python==4.1.0
# Installing Keras
>pip install keras
# Installing Jupyter
>pip install jupyter
#Installing Scikit-Learn
>pip install scikit-learn
步骤2 环境配置
我们将从运行jupyter笔记本开始,然后在我们的案例OpenCV、Keras和sklearn中导入必要的库。
#importing openCV
>import cv2#importing numpy
>import numpy as np#importing pandas to read the CSV file containing our data
>import pandas as pd#importing keras and sub-libraries
>from keras.models import Sequential
>from keras.layers import Dense
>from keras.layers import Dropout
>from keras.layers import Flatten, MaxPool2D
>from keras.layers.convolutional import Conv2D
>from keras.layers.convolutional import MaxPooling2D
>from keras import backend as K
>from keras.utils import np_utils
>from sklearn.model_selection import train_test_split
步骤3 车牌检测
让我们从导入带牌照汽车的示例图像开始,并定义一些函数:
def extract_plate(img): # the function detects and perfors blurring on the number plate.
plate_img = img.copy()
#Loads the data required for detecting the license plates from cascade classifier.
plate_cascade = cv2.CascadeClassifier('./indian_license_plate.xml')
# detects numberplates and returns the coordinates and dimensions of detected license plate's contours.
plate_rect = plate_cascade.detectMultiScale(plate_img, scaleFactor = 1.3, minNeighbors = 7)
for (x,y,w,h) in plate_rect:
a,b = (int(0.02*img.shape[0]), int(0.025*img.shape[1])) #parameter tuning
plate = plate_img[y+a:y+h-a, x+b:x+w-b, :]
# finally representing the detected contours by drawing rectangles around the edges.
cv2.rectangle(plate_img, (x,y), (x+w, y+h), (51,51,255), 3)
return plate_img, plate # returning the processed image
上述函数的工作原理是将图像作为输入,然后应用“haar cascade”(经过预训练以检测印度车牌),这里的参数scaleFactor表示一个值,通过该值可以缩放输入图像以更好地检测车牌。minNeighbors只是一个减少误报的参数,如果该值较低,算法可能更容易给出错误识别的输出。
步骤4 车牌图像预处理
现在,让我们进一步处理此图像,以简化角色提取过程。我们将首先为此定义更多函数。
# Find characters in the resulting images
def segment_characters(image) :
# Preprocess cropped license plate image
img = cv2.resize(image, (333, 75))
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
_, img_binary = cv2.threshold(img_gray, 200, 255, cv2.THRESH_BINARY+cv2.THRESH_OTSU)
img_erode = cv2.erode(img_binary, (3,3))
img_dilate = cv2.dilate(img_erode, (3,3))
LP_WIDTH = img_dilate.shape[0]
LP_HEIGHT = img_dilate.shape[1]
# Make borders white
img_dilate[0:3,:] = 255
img_dilate[:,0:3] = 255
img_dilate[72:75,:] = 255
img_dilate[:,330:333] = 255
# Estimations of character contours sizes of cropped license plates
dimensions = [LP_WIDTH/6, LP_WIDTH/2, LP_HEIGHT/10, 2*LP_HEIGHT/3]
# Get contours within cropped license plate
char_list = find_contours(dimensions, img_dilate)
return char_list
上述函数接收图像作为输入,并对其执行以下操作:
步骤5 从车牌中分割字母数字字符
import numpy as np
import cv2
# Match contours to license plate or character template
def find_contours(dimensions, img) :
# Find all contours in the image
cntrs, _ = cv2.findContours(img.copy(), cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
# Retrieve potential dimensions
lower_width = dimensions[0]
upper_width = dimensions[1]
lower_height = dimensions[2]
upper_height = dimensions[3]
# Check largest 5 or 15 contours for license plate or character respectively
cntrs = sorted(cntrs, key=cv2.contourArea, reverse=True)[:15]
x_cntr_list = []
target_contours = []
img_res = []
for cntr in cntrs :
#detects contour in binary image and returns the coordinates of rectangle enclosing it
intX, intY, intWidth, intHeight = cv2.boundingRect(cntr)
#checking the dimensions of the contour to filter out the characters by contour's size
if intWidth > lower_width and intWidth < upper_width and intHeight > lower_height and intHeight < upper_height :
x_cntr_list.append(intX) #stores the x coordinate of the character's contour, to used later for indexing the contours
char_copy = np.zeros((44,24))
#extracting each character using the enclosing rectangle's coordinates.
char = img[intY:intY+intHeight, intX:intX+intWidth]
char = cv2.resize(char, (20, 40))
# Make result formatted for classification: invert colors
char = cv2.subtract(255, char)
# Resize the image to 24x44 with black border
char_copy[2:42, 2:22] = char
char_copy[0:2, :] = 0
char_copy[:, 0:2] = 0
char_copy[42:44, :] = 0
char_copy[:, 22:24] = 0
img_res.append(char_copy) #List that stores the character's binary image (unsorted)
#Return characters on ascending order with respect to the x-coordinate (most-left character first)
#arbitrary function that stores sorted list of character indeces
indices = sorted(range(len(x_cntr_list)), key=lambda k: x_cntr_list[k])
img_res_copy = []
for idx in indices:
img_res_copy.append(img_res[idx])# stores character images according to their index
img_res = np.array(img_res_copy)
return img_res
在第4步之后,我们应该有一个干净的二进制图像来处理。在这一步中,我们将应用更多的图像处理来从车牌中提取单个字符。
步骤6 创建机器学习模型并训练模型
## create model
>model = Sequential()
>model.add(Conv2D(filters=32, kernel_size=(5,5), input_shape=(28, 28, 1), activation='relu'))
>model.add(MaxPooling2D(pool_size=(2, 2)))
>model.add(Dropout(rate=0.4))
>model.add(Flatten())
>model.add(Dense(units=128, activation='relu'))
>model.add(Dense(units=36, activation='softmax'))
步骤7 训练CNN模型
import datetime
class stop_training_callback(tf.keras.callbacks.Callback):
def on_epoch_end(self, epoch, logs={}):
if(logs.get('val_acc') > 0.992):
self.model.stop_training = True
log_dir="logs/fit/" + datetime.datetime.now().strftime("%Y%m%d-%H%M%S")
tensorboard_callback = tf.keras.callbacks.TensorBoard(log_dir=log_dir, histogram_freq=1)
batch_size = 1
callbacks = [tensorboard_callback, stop_training_callback()]
model.fit_generator(train_generator,
steps_per_epoch = train_generator.samples // batch_size,
validation_data = validation_generator,
validation_steps = validation_generator.samples // batch_size,
epochs = 80, callbacks=callbacks)
经过23个阶段的训练,模型的准确率达到99.54%。
步骤8 输出
最后,让我们将图像输入到我们的模型中。