车牌识别程序python代码_Python+Tensorflow+CNN实现车牌识别的示例代码
摘要:这篇Python开发技术栏目下的“Python+Tensorflow+CNN实现车牌识别的示例代码”,介绍的技术点是“TensorFlow、Python、示例代码、车牌识别、CNN、代码”,希望对大家开发技术学习和问题解决有帮助。这篇文章主要介绍了Python+Tensorflow+CNN实现车牌识别的示例代码,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
一、项目概述
本次项目目标是实现对自动生成的带有各种噪声的车牌识别。在噪声干扰情况下,车牌字符分割较困难,此次车牌识别是将车牌7个字符同时训练,字符包括31个省份简称、10个阿拉伯数字、24个英文字母('O'和'I'除外),共有65个类别,7个字符使用单独的loss函数进行训练。
(运行环境:tensorflow1.14.0-GPU版)
二、生成车牌数据集
import os
import cv2 as cv
import numpy as np
from math import *
from PIL import ImageFont
from PIL import Image
from PIL import ImageDraw
index = {"京": 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 img
def 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 dst
def rotRandrom(img, factor, size):
"""
添加放射畸变
:param img: 输入图像
:param factor: 畸变的参数
:param size: 图片目标尺寸
:return: 放射畸变后的图像
"""
shape = size
pts1 = 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 dst
def 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 img
def 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) * 255
inv = cv.bitwise_and(bak, env)
img = cv.bitwise_or(inv, img)
return img
def 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 A
def 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 A
def 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 + noise
return dst
def addNoise(img): # sdev = 0.5,avg=10
img[:, :, 0] = AddNoiseSingleChannel(img[:, :, 0])
img[:, :, 1] = AddNoiseSingleChannel(img[:, :, 1])
img[:, :, 2] = AddNoiseSingleChannel(img[:, :, 2])
return img
class 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 + "\\" + filename
self.noplates_path.append(path)
def draw(self, val):
offset = 2
self.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 * 6
self.img[0:70, base:base+23] = GenCh1(self.fontE, val[i+2])
return self.img
def 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
@staticmethod
def genPlateString(pos, val):
"""
生成车牌string,存为图片
生成车牌list,存为label
"""
plateStr = ""
plateList=[]
box = [0, 0, 0, 0, 0, 0, 0]
if pos != -1:
box[pos] = 1
for unit, cpos in zip(box, range(len(box))):
if unit == 1:
plateStr += val
plateList.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
@staticmethod
def 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
车牌生成后保存至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_size
self.height = height
self.width = width
def 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)
@staticmethod
def 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, label
def 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 tf
def 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_7
def 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]))
tf.compat.v1.summary.scalar('loss1', loss1)
loss2 = tf.reduce_mean(tf.nn.sparse_softmax_cross_entropy_with_logits(
logits=logit2, labels=labels[:, 1]))
tf.compat.v1.summary.scalar('loss2', loss2)
loss3 = tf.reduce_mean(tf.nn.sparse_softmax_cross_entropy_with_logits(
logits=logit3, labels=labels[:, 2]))
tf.compat.v1.summary.scalar('loss3', loss3)
loss4 = tf.reduce_mean(tf.nn.sparse_softmax_cross_entropy_with_logits(
logits=logit4, labels=labels[:, 3]))
tf.compat.v1.summary.scalar('loss4', loss4)
loss5 = tf.reduce_mean(tf.nn.sparse_softmax_cross_entropy_with_logits(
logits=logit5, labels=labels[:, 4]))
tf.compat.v1.summary.scalar('loss5', loss5)
loss6 = tf.reduce_mean(tf.nn.sparse_softmax_cross_entropy_with_logits(
logits=logit6, labels=labels[:, 5]))
tf.compat.v1.summary.scalar('loss6', loss6)
loss7 = tf.reduce_mean(tf.nn.sparse_softmax_cross_entropy_with_logits(
logits=logit7, labels=labels[:, 6]))
tf.compat.v1.summary.scalar('loss7', loss7)
return loss1, loss2, loss3, loss4, loss5, loss6, loss7
def train_step(loss1, loss2, loss3, loss4, loss5, loss6, loss7, learning_rate):
optimizer1 = tf.compat.v1.train.AdamOptimizer(learning_rate=learning_rate)
train_op1 = optimizer1.minimize(loss1)
optimizer2 = tf.compat.v1.train.AdamOptimizer(learning_rate=learning_rate)
train_op2 = optimizer2.minimize(loss2)
optimizer3 = tf.compat.v1.train.AdamOptimizer(learning_rate=learning_rate)
train_op3 = optimizer3.minimize(loss3)
optimizer4 = tf.compat.v1.train.AdamOptimizer(learning_rate=learning_rate)
train_op4 = optimizer4.minimize(loss4)
optimizer5 = tf.compat.v1.train.AdamOptimizer(learning_rate=learning_rate)
train_op5 = optimizer5.minimize(loss5)
optimizer6 = tf.compat.v1.train.AdamOptimizer(learning_rate=learning_rate)
train_op6 = optimizer6.minimize(loss6)
optimizer7 = tf.compat.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_op7
def 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))
tf.compat.v1.summary.scalar('accuracy', accuracy)
return accuracy
五、模型训练
import os
import time
import datetime
import numpy as np
import tensorflow as tf
from input_data import OCRIter
import model
os.environ["TF_CPP_MIN_LOG_LEVEL"] = '3'
img_h = 72
img_w = 272
num_label = 7
batch_size = 32
epoch = 10000
learning_rate = 0.0001
logs_path = 'logs\\1005'
model_path = 'saved_model\\1005'
image_holder = tf.compat.v1.placeholder(tf.float32, [batch_size, img_h, img_w, 3])
label_holder = tf.compat.v1.placeholder(tf.int32, [batch_size, 7])
keep_prob = tf.compat.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 = model.cnn_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=tf.compat.v1.summary.image('input', image_holder)
summary_op = tf.compat.v1.summary.merge(tf.compat.v1.get_collection(tf.compat.v1.GraphKeys.SUMMARIES))
init_op = tf.compat.v1.global_variables_initializer()
with tf.compat.v1.Session() as sess:
sess.run(init_op)
train_writer = tf.compat.v1.summary.FileWriter(logs_path, sess.graph)
saver = tf.compat.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_time2
loss_total = ls1 + ls2 + ls3 + ls4 + ls5 + ls6 + ls7
if 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 os
import cv2 as cv
import numpy as np
import tensorflow as tf
import matplotlib.pyplot as plt
from PIL import Image
import model
os.environ["TF_CPP_MIN_LOG_LEVEL"] = '3' # 只显示 Error
index = {"京": 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 image
batch_size = 1
x = tf.compat.v1.placeholder(tf.float32, [batch_size, 72, 272, 3])
keep_prob = tf.compat.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 = model.cnn_inference(x, keep_prob)
model_path = 'saved_model\\1005'
saver = tf.compat.v1.train.Saver()
with tf.compat.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]) + 41
if i > 1:
result = np.argmax(prediction[i][31:65]) + 31
line += chars[result]+" "
print ('predicted: ' + line)
plt.show()
随机测试20张车牌,18张预测正确,2张预测错误,从最后两幅预测错误的图片可以看出,模型对相似字符以及遮挡字符识别成功率仍有待提高。测试结果部分展示如下:
八、总结
本次构建的CNN模型较为简单,只有6卷积层+3池化层+1全连接层,可以通过增加模型深度以及每层之间的神经元数量来优化模型,提高识别的准确率。此次训练数据集来源于自动生成的车牌,由于真实的车牌图像与生成的车牌图像在噪声干扰上有所区分,所以识别率上会有所出入。如果使用真实的车牌数据集,需要对车牌进行滤波、均衡化、腐蚀、矢量量化等预处理方法。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持Java大数据社区。
车牌识别程序python代码_Python+Tensorflow+CNN实现车牌识别的示例代码相关推荐
- python车牌识别系统开源代码_Python+Tensorflow+CNN实现车牌识别的示例代码
一.项目概述 本次项目目标是实现对自动生成的带有各种噪声的车牌识别.在噪声干扰情况下,车牌字符分割较困难,此次车牌识别是将车牌7个字符同时训练,字符包括31个省份简称.10个阿拉伯数字.24个英文字母 ...
- python调用程序压缩文件_Python实现文件压缩和解压的示例代码
大家可能都熟悉.zip格式的文件.它可以把多个文件,压缩成一个文件.这在网络上传输时很有用,而且节省硬盘空间. 接下来,我们使用Python实现压缩和解压. 读取ZIP文件信息 要读取ZIP文件的内容 ...
- python修改自己的代码_python修改微信和支付宝步数的示例代码
项目意义 如果你想在支付宝蚂蚁森林收集很多能量种树,为环境绿化出一份力量,又或者是想每天称霸微信运动排行榜装逼,却不想出门走路,那么该python脚本可以帮你实现. 实现方法 手机安装第三方软件乐心健 ...
- python简单目标检测代码_Python Opencv实现单目标检测的示例代码
一 简介 目标检测即为在图像中找到自己感兴趣的部分,将其分割出来进行下一步操作,可避免背景的干扰.以下介绍几种基于opencv的单目标检测算法,算法总体思想先尽量将目标区域的像素值全置为1,背景区域全 ...
- python遥感影像分类代码_Python 实现遥感影像波段组合的示例代码
最近要做个遥感相关的小系统,需要波段组合功能,网上找了可以使用ArcGIS安装时自带的arcpy包,但是Python3.7不能使用现有ArcGIS10.2版本,也不想再装其他版本,所以只能自己想了个办 ...
- python随机生成四位验证码的代码_Python random随机生成6位验证码示例代码
随机生成6位验证码代码 # -*- coding: utf-8 -*- import random def generate_verification_code(): ''' randomly gen ...
- python数据统计代码_Python 数据的累加与统计的示例代码
问题 你需要处理一个很大的数据集并需要计算数据总和或其他统计量. 解决方案 对于任何涉及到统计.时间序列以及其他相关技术的数据分析问题,都可以考虑使用 Pandas库 . 为了让你先体验下,下面是一个 ...
- python两数相乘代码_Python 实现大整数乘法算法的示例代码
我们平时接触的长乘法,按位相乘,是一种时间复杂度为 O(n ^ 2) 的算法.今天,我们来介绍一种时间复杂度为 O (n ^ log 3) 的大整数乘法(log 表示以 2 为底的对数). 介绍原理 ...
- 支持向量机python代码_用TensorFlow实现多类支持向量机的示例代码
这篇文章主要介绍了用TensorFlow实现多类支持向量机的示例代码,现在分享给大家,也给大家做个参考.一起过来看看吧 本文将详细展示一个多类支持向量机分类器训练iris数据集来分类三种花. SVM算 ...
- python文字识别并获取位置_python实现简单的文字识别
将图片翻译成文字一般被称为光学文字识别(Optical Character Recognition,OCR).今天我们用到的就是一个OCR 库--Tesseract. 首先要安装Tesseract,除 ...
最新文章
- Java bitset转string_Java 二进制和十进制互转,二进制和BitSet互转
- sql增删改查_快速搞定数据库增删改查|附思维导图
- No ExecutorFactory found to execute the application
- mysql 循环创建列_mysql – 查询列中的循环值
- [Leedcode][JAVA][面试题 08.11][硬币][动态规划]
- silverlight 跨域socket
- 制作手风琴效果的注意事项(附代码)
- java-DateFormat
- 大数据工程师简历_大数据工程师简历范本02
- 页面s升级中_你的电脑要不要升级内存?怎么升级?答案都在这里
- 第008讲 div css开山篇
- 黑色的php编辑器,五款常用的免费php编辑器推荐
- 腾讯内部项目管理课程
- 计算机桌面图标不可以移动怎么调,win10电脑桌面图标不能移动怎么办,win10桌面图标移动不了的解决方法...
- 管理学的基础理论—德鲁克理论
- 前端xlsx插件简单说明
- CIO如何推广ERP系统
- 果壳网(guokr.com)发布了
- 强力破解E-mail密码三种方法(转)
- php定义json类型数据,PHP中使用json数据格式定义字面量对象的方法_PHP
热门文章
- mes系统和plc通讯案例_「MES系统 | 应用案例」奥松电子云MES系统项目启动大会顺利召开...
- linux系统怎么拨号上网,如何用 Linux 拨号上网
- 南昌大学c语言第八章函数答案,南昌大学计算机C语言答案8
- “云时代架构”经典文章阅读感想十五
- [SDOI2009]HH的项链 BZOJ1878
- 20145236《网络攻防》 Exp3 免杀原理与实践
- 微信开发-点击链接自己主动加入关注
- ShenNiu.MVC管理系统
- php上传文件+(中文转换为拼音的类)+ 输入字符提示信息+根据头部信息给出相对应得二维码扫描...
- Uboot详细解析1