1500字范文,内容丰富有趣,写作好帮手!
1500字范文 > Python+Tensorflow+CNN实现车牌识别

Python+Tensorflow+CNN实现车牌识别

时间:2019-10-15 22:02:01

相关推荐

Python+Tensorflow+CNN实现车牌识别

前言:文章如有错误之处,敬请告知,谢谢~

文章目录

一、项目概述二、生成车牌数据集三、数据导入四、CNN模型构建五、模型训练六、训练结果展示七、预测单张车牌八、总结

一、项目概述

本次项目目标是实现对自动生成的带有各种噪声的车牌识别。在噪声干扰情况下,车牌字符分割较困难,此次车牌识别是将车牌7个字符同时训练,字符包括31个省份简称、10个阿拉伯数字、24个英文字母('O’和’I’除外),共有65个类别,7个字符使用单独的loss函数进行训练。

(运行环境:tensorflow1.14.0-GPU版)

二、生成车牌数据集

import osimport cv2 as cvimport numpy as npfrom math import *from PIL import ImageFontfrom PIL import Imagefrom PIL import ImageDrawindex = {"京": 0, "沪": 1, "津": 2, "渝": 3, "冀": 4, "晋": 5, "蒙": 6, "辽": 7, "吉": 8, "黑": 9,"苏": 10, "浙": 11, "皖": 12, "闽": 13, "赣": 14, "鲁": 15, "豫": 16, "鄂": 17, "湘": 18, "粤": 19,"桂": 20, "琼": 21, "川": 22, "贵": 23, "云": 24, "藏": 25, "陕": 26, "甘": 27, "青": 28, "宁": 29,"新": 30, "0": 31, "1": 32, "2": 33, "3": 34, "4": 35, "5": 36, "6": 37, "7": 38, "8": 39,"9": 40, "A": 41, "B": 42, "C": 43, "D": 44, "E": 45, "F": 46, "G": 47, "H": 48, "J": 49,"K": 50, "L": 51, "M": 52, "N": 53, "P": 54, "Q": 55, "R": 56, "S": 57, "T": 58, "U": 59,"V": 60, "W": 61, "X": 62, "Y": 63, "Z": 64}chars = ["京", "沪", "津", "渝", "冀", "晋", "蒙", "辽", "吉", "黑","苏", "浙", "皖", "闽", "赣", "鲁", "豫", "鄂", "湘", "粤","桂", "琼", "川", "贵", "云", "藏", "陕", "甘", "青", "宁","新", "0", "1", "2", "3", "4", "5", "6", "7", "8","9", "A", "B", "C", "D", "E", "F", "G", "H", "J","K", "L", "M", "N", "P", "Q", "R", "S", "T", "U","V", "W", "X", "Y", "Z"]def AddSmudginess(img, Smu):"""模糊处理:param img: 输入图像:param Smu: 模糊图像:return: 添加模糊后的图像"""rows = r(Smu.shape[0] - 50)cols = r(Smu.shape[1] - 50)adder = Smu[rows:rows + 50, cols:cols + 50]adder = cv.resize(adder, (50, 50))img = cv.resize(img,(50,50))img = cv.bitwise_not(img)img = cv.bitwise_and(adder, img)img = cv.bitwise_not(img)return imgdef rot(img, angel, shape, max_angel):"""添加透视畸变"""size_o = [shape[1], shape[0]]size = (shape[1]+ int(shape[0] * cos((float(max_angel ) / 180) * 3.14)), shape[0])interval = abs(int(sin((float(angel) / 180) * 3.14) * shape[0]))pts1 = np.float32([[0, 0], [0, size_o[1]], [size_o[0], 0], [size_o[0], size_o[1]]])if angel > 0:pts2 = np.float32([[interval, 0], [0, size[1]], [size[0], 0], [size[0] - interval, size_o[1]]])else:pts2 = np.float32([[0, 0], [interval, size[1]], [size[0] - interval, 0], [size[0], size_o[1]]])M = cv.getPerspectiveTransform(pts1, pts2)dst = cv.warpPerspective(img, M, size)return dstdef rotRandrom(img, factor, size):"""添加放射畸变:param img: 输入图像:param factor: 畸变的参数:param size: 图片目标尺寸:return: 放射畸变后的图像"""shape = sizepts1 = np.float32([[0, 0], [0, shape[0]], [shape[1], 0], [shape[1], shape[0]]])pts2 = np.float32([[r(factor), r(factor)], [r(factor), shape[0] - r(factor)], [shape[1] - r(factor), r(factor)],[shape[1] - r(factor), shape[0] - r(factor)]])M = cv.getPerspectiveTransform(pts1, pts2)dst = cv.warpPerspective(img, M, size)return dstdef tfactor(img):"""添加饱和度光照的噪声"""hsv = cv.cvtColor(img,cv.COLOR_BGR2HSV)hsv[:, :, 0] = hsv[:, :, 0] * (0.8 + np.random.random() * 0.2)hsv[:, :, 1] = hsv[:, :, 1] * (0.3 + np.random.random() * 0.7)hsv[:, :, 2] = hsv[:, :, 2] * (0.2 + np.random.random() * 0.8)img = cv.cvtColor(hsv, cv.COLOR_HSV2BGR)return imgdef random_envirment(img, noplate_bg):"""添加自然环境的噪声, noplate_bg为不含车牌的背景图"""bg_index = r(len(noplate_bg))env = cv.imread(noplate_bg[bg_index])env = cv.resize(env, (img.shape[1], img.shape[0]))bak = (img == 0)bak = bak.astype(np.uint8) * 255inv = cv.bitwise_and(bak, env)img = cv.bitwise_or(inv, img)return imgdef GenCh(f, val):"""生成中文字符"""img = Image.new("RGB", (45, 70), (255, 255, 255))draw = ImageDraw.Draw(img)draw.text((0, 3), val, (0, 0, 0), font=f)img = img.resize((23, 70))A = np.array(img)return Adef GenCh1(f, val):"""生成英文字符"""img =Image.new("RGB", (23, 70), (255, 255, 255))draw = ImageDraw.Draw(img)draw.text((0, 2), val, (0, 0, 0), font=f) # val.decode('utf-8')A = np.array(img)return Adef AddGauss(img, level):"""添加高斯模糊""" return cv.blur(img, (level * 2 + 1, level * 2 + 1))def r(val):return int(np.random.random() * val)def AddNoiseSingleChannel(single):"""添加高斯噪声"""diff = 255 - single.max()noise = np.random.normal(0, 1 + r(6), single.shape)noise = (noise - noise.min()) / (noise.max() - noise.min())noise *= diff# noise= noise.astype(np.uint8)dst = single + noisereturn dstdef addNoise(img): # sdev = 0.5,avg=10img[:, :, 0] = AddNoiseSingleChannel(img[:, :, 0])img[:, :, 1] = AddNoiseSingleChannel(img[:, :, 1])img[:, :, 2] = AddNoiseSingleChannel(img[:, :, 2])return imgclass GenPlate:def __init__(self, fontCh, fontEng, NoPlates):self.fontC = ImageFont.truetype(fontCh, 43, 0)self.fontE = ImageFont.truetype(fontEng, 60, 0)self.img = np.array(Image.new("RGB", (226, 70),(255, 255, 255)))self.bg = cv.resize(cv.imread("data\\images\\template.bmp"), (226, 70)) # template.bmp:车牌背景图self.smu = cv.imread("data\\images\\smu2.jpg") # smu2.jpg:模糊图像self.noplates_path = []for parent, parent_folder, filenames in os.walk(NoPlates):for filename in filenames:path = parent + "\\" + filenameself.noplates_path.append(path)def draw(self, val):offset = 2self.img[0:70, offset+8:offset+8+23] = GenCh(self.fontC, val[0])self.img[0:70, offset+8+23+6:offset+8+23+6+23] = GenCh1(self.fontE, val[1])for i in range(5):base = offset + 8 + 23 + 6 + 23 + 17 + i * 23 + i * 6self.img[0:70, base:base+23] = GenCh1(self.fontE, val[i+2])return self.imgdef generate(self, text):if len(text) == 7:fg = self.draw(text) # decode(encoding="utf-8")fg = cv.bitwise_not(fg)com = cv.bitwise_or(fg, self.bg)com = rot(com, r(60)-30, com.shape,30)com = rotRandrom(com, 10, (com.shape[1], com.shape[0]))com = tfactor(com)com = random_envirment(com, self.noplates_path)com = AddGauss(com, 1+r(4))com = addNoise(com)return com@staticmethoddef genPlateString(pos, val):"""生成车牌string,存为图片生成车牌list,存为label"""plateStr = ""plateList=[]box = [0, 0, 0, 0, 0, 0, 0]if pos != -1:box[pos] = 1for unit, cpos in zip(box, range(len(box))):if unit == 1:plateStr += valplateList.append(val)else:if cpos == 0:plateStr += chars[r(31)]plateList.append(plateStr)elif cpos == 1:plateStr += chars[41 + r(24)]plateList.append(plateStr)else:plateStr += chars[31 + r(34)]plateList.append(plateStr)plate = [plateList[0]]b = [plateList[i][-1] for i in range(len(plateList))]plate.extend(b[1:7])return plateStr, plate@staticmethoddef genBatch(batchsize, outputPath, size):"""将生成的车牌图片写入文件夹,对应的label写入label.txt:param batchsize: 批次大小:param outputPath: 输出图像的保存路径:param size: 输出图像的尺寸:return: None"""if not os.path.exists(outputPath):os.mkdir(outputPath)outfile = open('data\\plate\\label.txt', 'w', encoding='utf-8')for i in range(batchsize):plateStr, plate = G.genPlateString(-1, -1)# print(plateStr, plate)img = G.generate(plateStr)img = cv.resize(img, size)cv.imwrite(outputPath + "\\" + str(i).zfill(2) + ".jpg", img)outfile.write(str(plate) + "\n")if __name__ == '__main__':G = GenPlate("data\\font\\platech.ttf", 'data\\font\\platechar.ttf', "data\\NoPlates")G.genBatch(101, 'data\\plate', (272, 72))

生成的车牌图像尺寸尽量不要超过300,本次尺寸选取:272 * 72

生成车牌所需文件:

字体文件:中文‘platech.ttf’,英文及数字‘platechar.ttf’背景图:来源于不含车牌的车辆裁剪图片车牌(蓝底):template.bmp噪声图像:smu2.jpg

文件百度云盘下载链接 密码:h67g

车牌生成后保存至plate文件夹,示例如下:

三、数据导入

from genplate import *import matplotlib.pyplot as plt# 产生用于训练的数据class OCRIter:def __init__(self, batch_size, width, height):super(OCRIter, self).__init__()self.genplate = GenPlate("data\\font\\platech.ttf", 'data\\font\\platechar.ttf', "data\\NoPlates")self.batch_size = batch_sizeself.height = heightself.width = widthdef iter(self):data = []label = []for i in range(self.batch_size):img, num = self.gen_sample(self.genplate, self.width, self.height)data.append(img)label.append(num)return np.array(data), np.array(label)@staticmethoddef rand_range(lo, hi):return lo + r(hi - lo)def gen_rand(self):name = ""label = list([])label.append(self.rand_range(0, 31)) #产生车牌开头32个省的标签label.append(self.rand_range(41, 65)) #产生车牌第二个字母的标签for i in range(5):label.append(self.rand_range(31, 65)) #产生车牌后续5个字母的标签name += chars[label[0]]name += chars[label[1]]for i in range(5):name += chars[label[i+2]]return name, labeldef gen_sample(self, genplate, width, height):num, label = self.gen_rand()img = genplate.generate(num)img = cv.resize(img, (height, width))img = np.multiply(img, 1/255.0)return img, label #返回的label为标签,img为车牌图像'''# 测试代码O = OCRIter(2, 272, 72)img, lbl = O.iter()for im in img:plt.imshow(im, cmap='gray')plt.show()print(img.shape)print(lbl)'''

四、CNN模型构建

import tensorflow as tfdef cnn_inference(images, keep_prob):W_conv = {'conv1': tf.Variable(tf.random.truncated_normal([3, 3, 3, 32],stddev=0.1)),'conv2': tf.Variable(tf.random.truncated_normal([3, 3, 32, 32],stddev=0.1)),'conv3': tf.Variable(tf.random.truncated_normal([3, 3, 32, 64],stddev=0.1)),'conv4': tf.Variable(tf.random.truncated_normal([3, 3, 64, 64],stddev=0.1)),'conv5': tf.Variable(tf.random.truncated_normal([3, 3, 64, 128],stddev=0.1)),'conv6': tf.Variable(tf.random.truncated_normal([3, 3, 128, 128],stddev=0.1)),'fc1_1': tf.Variable(tf.random.truncated_normal([5*30*128, 65],stddev=0.01)),'fc1_2': tf.Variable(tf.random.truncated_normal([5*30*128, 65],stddev=0.01)),'fc1_3': tf.Variable(tf.random.truncated_normal([5*30*128, 65],stddev=0.01)),'fc1_4': tf.Variable(tf.random.truncated_normal([5*30*128, 65],stddev=0.01)),'fc1_5': tf.Variable(tf.random.truncated_normal([5*30*128, 65],stddev=0.01)),'fc1_6': tf.Variable(tf.random.truncated_normal([5*30*128, 65],stddev=0.01)),'fc1_7': tf.Variable(tf.random.truncated_normal([5*30*128, 65],stddev=0.01)),} b_conv = {'conv1': tf.Variable(tf.constant(0.1, dtype=tf.float32, shape=[32])),'conv2': tf.Variable(tf.constant(0.1, dtype=tf.float32,shape=[32])),'conv3': tf.Variable(tf.constant(0.1, dtype=tf.float32,shape=[64])),'conv4': tf.Variable(tf.constant(0.1, dtype=tf.float32,shape=[64])),'conv5': tf.Variable(tf.constant(0.1, dtype=tf.float32,shape=[128])),'conv6': tf.Variable(tf.constant(0.1, dtype=tf.float32,shape=[128])),'fc1_1': tf.Variable(tf.constant(0.1, dtype=tf.float32,shape=[65])),'fc1_2': tf.Variable(tf.constant(0.1, dtype=tf.float32,shape=[65])),'fc1_3': tf.Variable(tf.constant(0.1, dtype=tf.float32,shape=[65])),'fc1_4': tf.Variable(tf.constant(0.1, dtype=tf.float32,shape=[65])),'fc1_5': tf.Variable(tf.constant(0.1, dtype=tf.float32,shape=[65])),'fc1_6': tf.Variable(tf.constant(0.1, dtype=tf.float32,shape=[65])),'fc1_7': tf.Variable(tf.constant(0.1, dtype=tf.float32,shape=[65])),} # 第1层卷积层conv1 = tf.nn.conv2d(images, W_conv['conv1'], strides=[1,1,1,1], padding='VALID')conv1 = tf.nn.bias_add(conv1, b_conv['conv1'])conv1 = tf.nn.relu(conv1)# 第2层卷积层conv2 = tf.nn.conv2d(conv1, W_conv['conv2'], strides=[1,1,1,1], padding='VALID')conv2 = tf.nn.bias_add(conv2, b_conv['conv2'])conv2 = tf.nn.relu(conv2)# 第1层池化层pool1 = tf.nn.max_pool2d(conv2, ksize=[1,2,2,1], strides=[1,2,2,1], padding='VALID')# 第3层卷积层conv3 = tf.nn.conv2d(pool1, W_conv['conv3'], strides=[1,1,1,1], padding='VALID')conv3 = tf.nn.bias_add(conv3, b_conv['conv3'])conv3 = tf.nn.relu(conv3)# 第4层卷积层conv4 = tf.nn.conv2d(conv3, W_conv['conv4'], strides=[1,1,1,1], padding='VALID')conv4 = tf.nn.bias_add(conv4, b_conv['conv4'])conv4 = tf.nn.relu(conv4)# 第2层池化层pool2 = tf.nn.max_pool2d(conv4, ksize=[1,2,2,1], strides=[1,2,2,1], padding='VALID')# 第5层卷积层conv5 = tf.nn.conv2d(pool2, W_conv['conv5'], strides=[1,1,1,1], padding='VALID')conv5 = tf.nn.bias_add(conv5, b_conv['conv5'])conv5 = tf.nn.relu(conv5)# 第4层卷积层conv6 = tf.nn.conv2d(conv5, W_conv['conv6'], strides=[1,1,1,1], padding='VALID')conv6 = tf.nn.bias_add(conv6, b_conv['conv6'])conv6 = tf.nn.relu(conv6)# 第3层池化层pool3 = tf.nn.max_pool2d(conv6, ksize=[1,2,2,1], strides=[1,2,2,1], padding='VALID')#第1_1层全连接层# print(pool3.shape)reshape = tf.reshape(pool3, [-1, 5 * 30 * 128])fc1 = tf.nn.dropout(reshape, keep_prob)fc1_1 = tf.add(tf.matmul(fc1, W_conv['fc1_1']), b_conv['fc1_1'])#第1_2层全连接层fc1_2 = tf.add(tf.matmul(fc1, W_conv['fc1_2']), b_conv['fc1_2'])#第1_3层全连接层fc1_3 = tf.add(tf.matmul(fc1, W_conv['fc1_3']), b_conv['fc1_3'])#第1_4层全连接层fc1_4 = tf.add(tf.matmul(fc1, W_conv['fc1_4']), b_conv['fc1_4'])#第1_5层全连接层fc1_5 = tf.add(tf.matmul(fc1, W_conv['fc1_5']), b_conv['fc1_5'])#第1_6层全连接层fc1_6 = tf.add(tf.matmul(fc1, W_conv['fc1_6']), b_conv['fc1_6'])#第1_7层全连接层fc1_7 = tf.add(tf.matmul(fc1, W_conv['fc1_7']), b_conv['fc1_7'])return fc1_1, fc1_2, fc1_3, fc1_4, fc1_5, fc1_6, fc1_7def calc_loss(logit1, logit2, logit3, logit4, logit5, logit6, logit7, labels):labels = tf.convert_to_tensor(labels, tf.int32)loss1 = tf.reduce_mean(tf.nn.sparse_softmax_cross_entropy_with_logits(logits=logit1, labels=labels[:, 0]))pat.v1.summary.scalar('loss1', loss1)loss2 = tf.reduce_mean(tf.nn.sparse_softmax_cross_entropy_with_logits(logits=logit2, labels=labels[:, 1]))pat.v1.summary.scalar('loss2', loss2)loss3 = tf.reduce_mean(tf.nn.sparse_softmax_cross_entropy_with_logits(logits=logit3, labels=labels[:, 2]))pat.v1.summary.scalar('loss3', loss3)loss4 = tf.reduce_mean(tf.nn.sparse_softmax_cross_entropy_with_logits(logits=logit4, labels=labels[:, 3]))pat.v1.summary.scalar('loss4', loss4)loss5 = tf.reduce_mean(tf.nn.sparse_softmax_cross_entropy_with_logits(logits=logit5, labels=labels[:, 4]))pat.v1.summary.scalar('loss5', loss5)loss6 = tf.reduce_mean(tf.nn.sparse_softmax_cross_entropy_with_logits(logits=logit6, labels=labels[:, 5]))pat.v1.summary.scalar('loss6', loss6)loss7 = tf.reduce_mean(tf.nn.sparse_softmax_cross_entropy_with_logits(logits=logit7, labels=labels[:, 6]))pat.v1.summary.scalar('loss7', loss7)return loss1, loss2, loss3, loss4, loss5, loss6, loss7def train_step(loss1, loss2, loss3, loss4, loss5, loss6, loss7, learning_rate):optimizer1 = pat.v1.train.AdamOptimizer(learning_rate=learning_rate)train_op1 = optimizer1.minimize(loss1)optimizer2 = pat.v1.train.AdamOptimizer(learning_rate=learning_rate)train_op2 = optimizer2.minimize(loss2)optimizer3 = pat.v1.train.AdamOptimizer(learning_rate=learning_rate)train_op3 = optimizer3.minimize(loss3)optimizer4 = pat.v1.train.AdamOptimizer(learning_rate=learning_rate)train_op4 = optimizer4.minimize(loss4)optimizer5 = pat.v1.train.AdamOptimizer(learning_rate=learning_rate)train_op5 = optimizer5.minimize(loss5)optimizer6 = pat.v1.train.AdamOptimizer(learning_rate=learning_rate)train_op6 = optimizer6.minimize(loss6)optimizer7 = pat.v1.train.AdamOptimizer(learning_rate=learning_rate)train_op7 = optimizer7.minimize(loss7)return train_op1, train_op2, train_op3, train_op4, train_op5, train_op6, train_op7def pred_model(logit1, logit2, logit3, logit4, logit5, logit6, logit7, labels):labels = tf.convert_to_tensor(labels, tf.int32)labels = tf.reshape(tf.transpose(labels), [-1])logits = tf.concat([logit1, logit2, logit3, logit4, logit5, logit6, logit7], 0)prediction = tf.nn.in_top_k(logits, labels, 1)accuracy = tf.reduce_mean(tf.cast(prediction, tf.float32))pat.v1.summary.scalar('accuracy', accuracy)return accuracy

五、模型训练

import osimport timeimport datetimeimport numpy as npimport tensorflow as tffrom input_data import OCRIterimport modelos.environ["TF_CPP_MIN_LOG_LEVEL"] = '3'img_h = 72img_w = 272num_label = 7batch_size = 32epoch = 10000learning_rate = 0.0001logs_path = 'logs\\1005'model_path = 'saved_model\\1005'image_holder = pat.v1.placeholder(tf.float32, [batch_size, img_h, img_w, 3])label_holder = pat.v1.placeholder(tf.int32, [batch_size, 7])keep_prob = pat.v1.placeholder(tf.float32)def get_batch():data_batch = OCRIter(batch_size, img_h, img_w)image_batch, label_batch = data_batch.iter()return np.array(image_batch), np.array(label_batch)logit1, logit2, logit3, logit4, logit5, logit6, logit7 = n_inference(image_holder, keep_prob)loss1, loss2, loss3, loss4, loss5, loss6, loss7 = model.calc_loss(logit1, logit2, logit3, logit4, logit5, logit6, logit7, label_holder)train_op1, train_op2, train_op3, train_op4, train_op5, train_op6, train_op7 = model.train_step(loss1, loss2, loss3, loss4, loss5, loss6, loss7, learning_rate)accuracy = model.pred_model(logit1, logit2, logit3, logit4, logit5, logit6, logit7, label_holder)input_image=pat.v1.summary.image('input', image_holder)summary_op = pat.v1.summary.merge(pat.v1.get_collection(pat.v1.GraphKeys.SUMMARIES))init_op = pat.v1.global_variables_initializer()with pat.v1.Session() as sess:sess.run(init_op)train_writer = pat.v1.summary.FileWriter(logs_path, sess.graph)saver = pat.v1.train.Saver()start_time1 = time.time()for step in range(epoch):# 生成车牌图像以及标签数据img_batch, lbl_batch = get_batch()start_time2 = time.time()time_str = datetime.datetime.now().isoformat()feed_dict = {image_holder:img_batch, label_holder:lbl_batch, keep_prob:0.6}_1, _2, _3, _4, _5, _6, _7, ls1, ls2, ls3, ls4, ls5, ls6, ls7, acc = sess.run([train_op1, train_op2, train_op3, train_op4, train_op5, train_op6, train_op7, loss1, loss2, loss3, loss4, loss5, loss6, loss7, accuracy], feed_dict)summary_str = sess.run(summary_op, feed_dict)train_writer.add_summary(summary_str,step)duration = time.time() - start_time2loss_total = ls1 + ls2 + ls3 + ls4 + ls5 + ls6 + ls7if step % 10 == 0:sec_per_batch = float(duration)print('%s: Step %d, loss_total = %.2f, acc = %.2f%%, sec/batch = %.2f' %(time_str, step, loss_total, acc * 100, sec_per_batch))if step % 5000 == 0 or (step + 1) == epoch:checkpoint_path = os.path.join(model_path,'model.ckpt')saver.save(sess, checkpoint_path, global_step=step)end_time = time.time()print("Training over. It costs {:.2f} minutes".format((end_time - start_time1) / 60))

六、训练结果展示

训练参数:

batch_size = 32

epoch = 10000

learning_rate = 0.0001

在tensorboard中查看训练过程

accuracy :

accuracy曲线在epoch = 10000左右时达到收敛,最终精确度在94%左右

loss :

以上三张分别是loss1,loss2, loss7的曲线图像,一号位字符是省份简称,识别相对字母数字较难,loss1=0.08左右,二号位字符是字母,loss2稳定在0.001左右,但是随着字符往后,loss值也将越来越大,7号位字符loss7稳定在0.6左右。

七、预测单张车牌

import osimport cv2 as cvimport numpy as npimport tensorflow as tfimport matplotlib.pyplot as pltfrom PIL import Imageimport modelos.environ["TF_CPP_MIN_LOG_LEVEL"] = '3' # 只显示 Errorindex = {"京": 0, "沪": 1, "津": 2, "渝": 3, "冀": 4, "晋": 5, "蒙": 6, "辽": 7, "吉": 8, "黑": 9,"苏": 10, "浙": 11, "皖": 12, "闽": 13, "赣": 14, "鲁": 15, "豫": 16, "鄂": 17, "湘": 18, "粤": 19,"桂": 20, "琼": 21, "川": 22, "贵": 23, "云": 24, "藏": 25, "陕": 26, "甘": 27, "青": 28, "宁": 29,"新": 30, "0": 31, "1": 32, "2": 33, "3": 34, "4": 35, "5": 36, "6": 37, "7": 38, "8": 39,"9": 40, "A": 41, "B": 42, "C": 43, "D": 44, "E": 45, "F": 46, "G": 47, "H": 48, "J": 49,"K": 50, "L": 51, "M": 52, "N": 53, "P": 54, "Q": 55, "R": 56, "S": 57, "T": 58, "U": 59,"V": 60, "W": 61, "X": 62, "Y": 63, "Z": 64}chars = ["京", "沪", "津", "渝", "冀", "晋", "蒙", "辽", "吉", "黑","苏", "浙", "皖", "闽", "赣", "鲁", "豫", "鄂", "湘", "粤","桂", "琼", "川", "贵", "云", "藏", "陕", "甘", "青", "宁","新", "0", "1", "2", "3", "4", "5", "6", "7", "8","9", "A", "B", "C", "D", "E", "F", "G", "H", "J","K", "L", "M", "N", "P", "Q", "R", "S", "T", "U","V", "W", "X", "Y", "Z"]def get_one_image(test):""" 随机获取单张车牌图像 """n = len(test)rand_num =np.random.randint(0,n)img_dir = test[rand_num]image_show = Image.open(img_dir)plt.imshow(image_show) # 显示车牌图片image = cv.imread(img_dir)image = image.reshape(72, 272, 3)image = np.multiply(image, 1 / 255.0)return imagebatch_size = 1x = pat.v1.placeholder(tf.float32, [batch_size, 72, 272, 3])keep_prob = pat.v1.placeholder(tf.float32)test_dir = 'data\\plate\\'test_image = []for file in os.listdir(test_dir):test_image.append(test_dir + file)test_image = list(test_image)image_array = get_one_image(test_image)logit1, logit2, logit3, logit4, logit5, logit6, logit7 = n_inference(x, keep_prob)model_path = 'saved_model\\1005'saver = pat.v1.train.Saver()with pat.v1.Session() as sess:print ("Reading checkpoint...")ckpt = tf.train.get_checkpoint_state(model_path)if ckpt and ckpt.model_checkpoint_path:global_step = ckpt.model_checkpoint_path.split('/')[-1].split('-')[-1]saver.restore(sess, ckpt.model_checkpoint_path)print('Loading success, global_step is %s' % global_step)else:print('No checkpoint file found')pre1, pre2, pre3, pre4, pre5, pre6, pre7 = sess.run([logit1, logit2, logit3, logit4, logit5, logit6, logit7],feed_dict={x:image_array, keep_prob:1.0})prediction = np.reshape(np.array([pre1, pre2, pre3, pre4, pre5, pre6, pre7]), [-1, 65])max_index = np.argmax(prediction, axis=1)print(max_index)line = ''result = np.array([])for i in range(prediction.shape[0]):if i == 0:result = np.argmax(prediction[i][0:31])if i == 1:result = np.argmax(prediction[i][41:65]) + 41if i > 1:result = np.argmax(prediction[i][31:65]) + 31line += chars[result]+" "print ('predicted: ' + line)plt.show()

随机测试20张车牌,18张预测正确,2张预测错误,从最后两幅预测错误的图片可以看出,模型对相似字符以及遮挡字符识别成功率仍有待提高。测试结果部分展示如下:

八、总结

本次构建的CNN模型较为简单,只有6卷积层+3池化层+1全连接层,可以通过增加模型深度以及每层之间的神经元数量来优化模型,提高识别的准确率。此次训练数据集来源于自动生成的车牌,由于真实的车牌图像与生成的车牌图像在噪声干扰上有所区分,所以识别率上会有所出入。如果使用真实的车牌数据集,需要对车牌进行滤波、均衡化、腐蚀、矢量量化等预处理方法。

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。