字符识别
在前面两篇博客中分别介绍了车牌定位以及字符分割的代码实现,那么在这篇文章中,我主要想介绍一下车牌识别系统的最后一个模块:字符识别。字符识别可以说是整个系统的核心部分了,这一部分可以有很多中实现方法:模板匹配、SVM以及人工神经网络等方法。本系统采用的是卷积神经网络算法(LeNet-5模型)来进行字符的识别。部分代码参考自下面这位博主(非常感谢博主的分享):
链接: TensorFlow车牌识别完整版.
车牌字符数据集
在进行CNN网络模型训练前,需要收集大量的数据集,并对其进行一些预处理。在对网上进行了大量的收刮之后,总共收集到了约4万张数据样本,车牌数据集的下载链接:
链接: 百度云.(提取码4b2a)
如果链接有问题,请在下方留言,以便及时修改。
模型的训练
本系统主要采用两个模型分别进行省份和数字/字母的识别,首先是省份的训练代码:
# coding=gbk
"""
汉字训练代码模块(LeNet-5)
__author__ = 'kuang'
2019.5.4 7号宿舍楼
"""
#载入模块
import sys
import os
import time
import random
import numpy as np
import tensorflow as tf
import cv2 as cv
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2' #设置警告等级
#设置基本参数
SIZE = 1024
WIDTH = 32
HEIGHT = 32
NUM_CLASSES = 31 #总共是31个省份
iterations = 1000
#设置存储模型的地址
SAVER_DIR = "XXX" #自己的路径
PROVINCES = ("川","鄂","赣","甘","贵","桂","黑","沪","冀","津","京","吉","辽","鲁","蒙","闽","宁","青","琼","陕","苏","晋","皖","湘","新","豫","渝","粤","云","藏","浙")
nProvinceIndex = 0
time_begin = time.time()
#定义输入节点,对应于图像像素值矩阵集合和图像标签(即所代表的数字)
x = tf.placeholder(tf.float32,shape=[None,SIZE]) #None表示batch size的大小
y_ = tf.placeholder(tf.float32,shape=[None,NUM_CLASSES]) #输出标签的占位
x_image = tf.reshape(x,[-1,WIDTH,HEIGHT,1]) #生成一个四维的数组
#定义卷积函数
def conv_layer(inputs,W,b,conv_strides,kernel_size,pool_strides,padding):
L1_conv = tf.nn.conv2d(inputs,W,strides=conv_strides,padding=padding) #卷积操作
L1_relu = tf.nn.relu(L1_conv + b) #激活函数RELU
return tf.nn.max_pool(L1_relu,ksize=kernel_size,strides=pool_strides,padding='SAME')
#定义全连接函数
def full_connect(inputs,W,b):
return tf.nn.relu(tf.matmul(inputs,W)+b)
def average(seq):
return float(sum(seq)) / len(seq)
#训练模型
if __name__ == "__main__":
#第一次遍历图片目录是为了获取图片总数
input_count = 0
for i in range(0,31):
dir = 'XXX\\train\\%s\\' % i #自己的路径
for root,dirs,files in os.walk(dir):
for filename in files:
input_count = input_count + 1
#定义对应维数和各维长度的数组
input_images = np.array([[0]*SIZE for i in range(input_count)]) #生成一个input_count行,SIZE列的全零二维数组
input_labels = np.array([[0]*NUM_CLASSES for i in range(input_count)]) #生成一个input_count行,NUM_CLASSES列的全零二维数组
#第二次遍历图片目录是为了生成图片数据和标签
index = 0
for i in range(0,31):
dir = 'XXX\\train\\%s\\' % i
a = 0
for root,dirs,files in os.walk(dir):
for filename in files:
filename = dir + filename
img = cv.imread(filename,0)
print(filename)
print(a)
#cv.imshow('threshold',img)
#cv.waitKey(0)
height = img.shape[0] #行数
width = img.shape[1] #列数
a = a + 1
for h in range(0,height):
for w in range(0,width):
m = img[h][w]
if m > 150:
input_images[index][w+h*width] = 1
else:
input_images[index][w+h*width] = 0
input_labels[index][i] = 1
index = index + 1
#第一次遍历图片目录是为了获得图片总数
val_count = 0
for i in range(0,31):
dir = 'XXX\\train\\%s\\' % i
for root,dirs,files in os.walk(dir):
for filename in files:
val_count = val_count + 1
#定义对应维数和各维长度的数组
val_images = np.array([[0]*SIZE for i in range(val_count)]) #生成一个input_count行,SIZE列的全零二维数组
val_labels = np.array([[0]*NUM_CLASSES for i in range(val_count)]) #生成一个input_count行,NUM_CLASSES列的全零二维数组
#第二次遍历图片目录是为了生成图片数据和标签
index = 0
for i in range(0,31):
dir = 'XXX\\train\\%s\\' % i
for root,dirs,files in os.walk(dir):
for filename in files:
filename = dir + filename
img = cv.imread(filename,0)
height = img.shape[0] #行数
width = img.shape[1] #列数
for h in range(0,height):
for w in range(0,width):
m = img[h][w]
if m > 150:
val_images[index][w+h*width] = 1
else:
val_images[index][w+h*width] = 0
val_labels[index][i] = 1
index = index + 1
with tf.Session() as sess:
#第一个卷积层
W_conv1 = tf.Variable(tf.truncated_normal([5,5,1,12],stddev=0.1),name="W_conv1")
b_conv1 = tf.Variable(tf.constant(0.1,shape=[12]),name="b_conv1") #生成偏置项,并初始化
conv_strides = [1,1,1,1] #行,列的卷积步长均为1
kernel_size = [1,2,2,1] #池化层卷积核的尺寸为2*2
pool_strides = [1,2,2,1] #池化行,列步长为2
L1_pool = conv_layer(x_image,W_conv1,b_conv1,conv_strides,kernel_size,pool_strides,padding='SAME') #第一层卷积池化的输出 ,x_image为输入(后文代码中输入)
#第二个卷积层
W_conv2 = tf.Variable(tf.truncated_normal([5,5,12,24],stddev=0.1),name="W_conv2")
b_conv2 = tf.Variable(tf.constant(0.1,shape=[24]),name="b_conv2")
conv_strides = [1,1,1,1]
kernel_size = [1,2,2,1]
pool_strides = [1,2,2,1]
L2_pool = conv_layer(L1_pool,W_conv2,b_conv2,conv_strides,kernel_size,pool_strides,padding="SAME")
#全连接层
W_fc1 = tf.Variable(tf.truncated_normal([8*8*24,512],stddev=0.1),name="W_fc1")
b_fc1 = tf.Variable(tf.constant(0.1,shape=[512]),name="b_fc1")
h_pool2_flat = tf.reshape(L2_pool,[-1,8*8*24]) #将第二次池化的二维特征图排列成一维的一个数组 全连接相当于一维的数组
h_fc1 = full_connect(h_pool2_flat,W_fc1,b_fc1) #进行全连接操作
#dropout
keep_prob = tf.placeholder(tf.float32)
h_fc1_drop = tf.nn.dropout(h_fc1,keep_prob)
#readout层
W_fc2 = tf.Variable(tf.truncated_normal([512,NUM_CLASSES],stddev=0.1),name="W_fc2")
b_fc2 = tf.Variable(tf.constant(0.1,shape=[NUM_CLASSES]),name="b_fc2")
#定义优化器和训练OP
y_conv = tf.matmul(h_fc1_drop,W_fc2) + b_fc2 #最后的输出层,因为是全连接,相当于每个神经元与权重相乘再加偏移
cross_entropy = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(labels=y_,logits=y_conv)) #交叉熵损失函数
train_step = tf.train.AdamOptimizer((1e-5)).minimize(cross_entropy)
correct_prediction = tf.equal(tf.argmax(y_conv,1),tf.argmax(y_,1))
accuracy = tf.reduce_mean(tf.cast(correct_prediction,tf.float32))
#初始化saver
saver = tf.train.Saver()
sess.run(tf.global_variables_initializer()) #初始化所有变量
time_elapsed = time.time() - time_begin #运行时间
print("读取图片文件耗费时间:%d秒" % time_elapsed)
time_begin = time.time()
print("一共读取了%s个训练图像,%s个标签"%(input_count,input_count))
#设置每次训练操作的输入个数和迭代次数,这里为了支持任意图片总数,定义了一个余数remainder,譬如,如果每次训练训练操作的输入个数为60,图片总数为150张,则前面两次各输入60张,最后一次输入30张(余数30)
batch_size = 64 #每次训练的图片数
iterations = iterations #迭代次数
batches_count = int(input_count/batch_size)
remainder = input_count % batch_size
print("训练数据集分成%s批,前面每批%s个数据,最后一批%s个数据" %(batches_count+1,batch_size,remainder))
#执行训练迭代
for it in range(iterations):
#这里的关键是要把输入数组转为np.array
sum_loss = []
for n in range(batches_count):
loss, out = sess.run([cross_entropy, train_step], feed_dict = {x:input_images[n*batch_size:(n+1)*batch_size],y_:input_labels[n*batch_size:(n+1)*batch_size],keep_prob:0.5}) #feed_dict相当于一次喂进去的数据,x表示输入,前面已经将输入的图片转化为input_image数组形式了
sum_loss.append(loss)
if remainder > 0:
start_index = batches_count * batch_size
loss, out =sess.run([cross_entropy, train_step], feed_dict = {x:input_images[start_index:input_count-1],y_:input_labels[start_index:input_count-1],keep_prob:0.5})
sum_loss.append(loss)
avg_loss = average(sum_loss)
#每完成5次迭代,判断准确度是否已达到100%,达到则退出迭代循环
iterate_accuracy = 0
if it % 5 == 0:
loss1 , iterate_accuracy = sess.run([cross_entropy,accuracy],feed_dict = {x : val_images,y_ : val_labels,keep_prob : 1.0})
print('第%d次训练迭代:准确率 %0.5f%% ' % (it,iterate_accuracy*100) + ' 损失值为:%s' % loss + ' 测试损失值:%s' % loss1)
if iterate_accuracy >= 0.9999999:
break
#完成训练,并输出训练时间
print('完成训练')
time_elapsed = time.time() - time_begin
print("训练耗费时间:%d秒" % time_elapsed)
time_begin = time.time()
#保存训练结果
if not os.path.exists(SAVER_DIR) :
print('不存在训练数据保存目录,现在创建保存目录')
os.makedirs(SAVER_DIR)
saver_path = saver.save(sess,"%smodel.ckpt"%(SAVER_DIR))
print("保存路径为:",saver_path)
然后是数字/字母的训练代码:
# coding=gbk
"""
数字/字母训练代码模块(LeNet-5)
__author__ = 'kuang'
2019.5.4 7号宿舍楼
"""
#载入模块
import sys
import os
import time
import random
import numpy as np
import tensorflow as tf
import cv2 as cv
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2' #设置警告等级
#设置基本参数
SIZE = 1024
WIDTH = 32
HEIGHT = 32
NUM_CLASSES = 34 #总共是34个数字字母
iterations = 1000
#设置保存的路径
SAVER_DIR = XXX\\train_saver\\numbers\\"
LETTERS_DIGITS = ("A","B","C","D","E","F","G","H","J","K","L","M","N","P","Q","R","S","T","U","V","W","X","Y","Z","0","1","2","3","4","5","6","7","8","9")
#license_num = []
time_begin = time.time()
#定义输入节点,对应于图像像素值矩阵集合和图像标签(即所代表的数字)
x = tf.placeholder(tf.float32,shape=[None,SIZE]) #None表示batch size的大小
y_ = tf.placeholder(tf.float32,shape=[None,NUM_CLASSES]) #输出标签的占位
x_image = tf.reshape(x,[-1,WIDTH,HEIGHT,1]) #对图像重新定义尺寸
#定义卷积函数
def conv_layer(inputs,W,b,conv_strides,kernel_size,pool_strides,padding):
L1_conv = tf.nn.conv2d(inputs,W,strides=conv_strides,padding=padding) #卷积操作
L1_relu = tf.nn.relu(L1_conv + b) #激活函数RELU
return tf.nn.max_pool(L1_relu,ksize=kernel_size,strides=pool_strides,padding='SAME')
#定义全连接函数
def full_connect(inputs,W,b):
return tf.nn.relu(tf.matmul(inputs,W)+b)
def average(seq):
return float(sum(seq)) / len(seq)
#训练模型
if __name__ == "__main__":
#第一次遍历图片目录是为了获取图片总数
input_count = 0
for i in range(31,65):
dir = 'XXX\\train\\%s\\' % i
for root,dirs,files in os.walk(dir):
for filename in files:
input_count = input_count + 1
#定义对应维数和各维长度的数组
input_images = np.array([[0]*SIZE for i in range(input_count)]) #生成一个input_count行,SIZE列的全零二维数组
input_labels = np.array([[0]*NUM_CLASSES for i in range(input_count)]) #生成一个input_count行,NUM_CLASSES列的全零二维数组
#第二次遍历图片目录是为了生成图片数据和标签
index = 0
for i in range(31,65):
dir = 'XXX\\train\\%s\\' % i
a = 0
for root,dirs,files in os.walk(dir):
for filename in files:
filename = dir + filename
img = cv.imread(filename,0)
print(filename)
print(a)
#cv.imshow('threshold',img)
#cv.waitKey(0)
height = img.shape[0] #行数
width = img.shape[1] #列数
a = a + 1
for h in range(0,height):
for w in range(0,width):
m = img[h][w]
if m > 150:
input_images[index][w+h*width] = 1
else:
input_images[index][w+h*width] = 0
input_labels[index][i-31] = 1
index = index + 1
#第一次遍历图片目录是为了获得图片总数
val_count = 0
for i in range(31,65):
dir = 'XXX\\train\\%s\\' % i
for root,dirs,files in os.walk(dir):
for filename in files:
val_count = val_count + 1
#定义对应维数和各维长度的数组
val_images = np.array([[0]*SIZE for i in range(val_count)]) #生成一个input_count行,SIZE列的全零二维数组
val_labels = np.array([[0]*NUM_CLASSES for i in range(val_count)]) #生成一个input_count行,NUM_CLASSES列的全零二维数组
#第二次遍历图片目录是为了生成图片数据和标签
index = 0
for i in range(31,65):
dir = 'XXX\\train\\%s\\' % i
for root,dirs,files in os.walk(dir):
for filename in files:
filename = dir + filename
img = cv.imread(filename,0)
height = img.shape[0] #行数
width = img.shape[1] #列数
for h in range(0,height):
for w in range(0,width):
m = img[h][w]
if m > 150:
val_images[index][w+h*width] = 1
else:
val_images[index][w+h*width] = 0
val_labels[index][i-31] = 1
index = index + 1
with tf.Session() as sess:
#第一个卷积层
W_conv1 = tf.Variable(tf.truncated_normal([5,5,1,12],stddev=0.1),name="W_conv1")
b_conv1 = tf.Variable(tf.constant(0.1,shape=[12]),name="b_conv1") #生成偏置项,并初始化
conv_strides = [1,1,1,1] #行,列的卷积步长均为1
kernel_size = [1,2,2,1] #池化层卷积核的尺寸为2*2
pool_strides = [1,2,2,1] #池化行,列步长为2
L1_pool = conv_layer(x_image,W_conv1,b_conv1,conv_strides,kernel_size,pool_strides,padding='SAME') #第一层卷积池化的输出 ,x_image为输入(后文代码中输入)
#第二个卷积层
W_conv2 = tf.Variable(tf.truncated_normal([5,5,12,24],stddev=0.1),name="W_conv2")
b_conv2 = tf.Variable(tf.constant(0.1,shape=[24]),name="b_conv2")
conv_strides = [1,1,1,1]
kernel_size = [1,2,2,1]
pool_strides = [1,2,2,1]
L2_pool = conv_layer(L1_pool,W_conv2,b_conv2,conv_strides,kernel_size,pool_strides,padding="SAME")
#全连接层
W_fc1 = tf.Variable(tf.truncated_normal([8*8*24,512],stddev=0.1),name="W_fc1")
b_fc1 = tf.Variable(tf.constant(0.1,shape=[512]),name="b_fc1")
h_pool2_flat = tf.reshape(L2_pool,[-1,8*8*24]) #将第二次池化的二维特征图排列成一维的一个数组 全连接相当于一维的数组
h_fc1 = full_connect(h_pool2_flat,W_fc1,b_fc1) #进行全连接操作
#dropout
keep_prob = tf.placeholder(tf.float32)
h_fc1_drop = tf.nn.dropout(h_fc1,keep_prob)
#readout层
W_fc2 = tf.Variable(tf.truncated_normal([512,NUM_CLASSES],stddev=0.1),name="W_fc2")
b_fc2 = tf.Variable(tf.constant(0.1,shape=[NUM_CLASSES]),name="b_fc2")
#定义优化器和训练OP
y_conv = tf.matmul(h_fc1_drop,W_fc2) + b_fc2 #最后的输出层,因为是全连接,相当于每个神经元与权重相乘再加偏移
#global_step = tf.Variable(0,trainable=False)
#learing_rate = tf.train.exponential_decay(0.1,global_step,100,0.96,staircase=False)
cross_entropy = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(labels=y_,logits=y_conv))
train_step = tf.train.AdamOptimizer((1e-5)).minimize(cross_entropy)
correct_prediction = tf.equal(tf.argmax(y_conv,1),tf.argmax(y_,1))
accuracy = tf.reduce_mean(tf.cast(correct_prediction,tf.float32))
#初始化saver
saver = tf.train.Saver()
sess.run(tf.global_variables_initializer()) #初始化所有变量
time_elapsed = time.time() - time_begin #运行时间
print("读取图片文件耗费时间:%d秒" % time_elapsed)
time_begin = time.time()
print("一共读取了%s个训练图像,%s个标签"%(input_count,input_count))
#设置每次训练操作的输入个数和迭代次数,这里为了支持任意图片总数,定义了一个余数remainder,譬如,如果每次训练训练操作的输入个数为60,图片总数为150张,则前面两次各输入60张,最后一次输入30张(余数30)
batch_size = 64 #每次训练的图片数
iterations = iterations #迭代次数
batches_count = int(input_count/batch_size)
remainder = input_count % batch_size
print("训练数据集分成%s批,前面每批%s个数据,最后一批%s个数据" %(batches_count+1,batch_size,remainder))
#执行训练迭代
for it in range(iterations):
#这里的关键是要把输入数组转为np.array
sum_loss = []
for n in range(batches_count):
loss, out = sess.run([cross_entropy, train_step], feed_dict = {x:input_images[n*batch_size:(n+1)*batch_size],y_:input_labels[n*batch_size:(n+1)*batch_size],keep_prob:0.5}) #feed_dict相当于一次喂进去的数据,x表示输入,前面已经将输入的图片转化为input_image数组形式了
sum_loss.append(loss)
if remainder > 0:
start_index = batches_count * batch_size
loss, out =sess.run([cross_entropy, train_step], feed_dict = {x:input_images[start_index:input_count-1],y_:input_labels[start_index:input_count-1],keep_prob:0.5})
sum_loss.append(loss)
avg_loss = average(sum_loss)
#每完成5次迭代,判断准确度是否已达到100%,达到则退出迭代循环
iterate_accuracy = 0
if it % 5 == 0:
loss1 , iterate_accuracy = sess.run([cross_entropy,accuracy], feed_dict = {x : val_images,y_ : val_labels,keep_prob : 1.0})
print('第%d次训练迭代:准确率 %0.5f%% ' % (it,iterate_accuracy*100) + ' 损失值为:%s' % avg_loss + ' 测试损失值:%s' % loss1)
if iterate_accuracy >= 0.9999999:
break
#完成训练,并输出训练时间
print('完成训练')
time_elapsed = time.time() - time_begin
print("训练耗费时间:%d秒" % time_elapsed)
time_begin = time.time()
#保存训练结果
if not os.path.exists(SAVER_DIR) :
print('不存在训练数据保存目录,现在创建保存目录')
os.makedirs(SAVER_DIR)
saver_path = saver.save(sess,"%smodel.ckpt"%(SAVER_DIR))
print("保存路径为:",saver_path)
两个模型的调用
训练完成后即可进行测试,多模型加载代码如下:
# coding=gbk
"""
多模型恢复模块(测试)
__author__ = 'kuang'
2019.5.10 7号宿舍楼
"""
import tensorflow as tf
import numpy as np
import cv2 as cv
import sys
import os
import random
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2' #设置警告等级
#定义卷积函数
def conv_layer(inputs,W,b,conv_strides,kernel_size,pool_strides,padding):
L1_conv = tf.nn.conv2d(inputs,W,strides=conv_strides,padding=padding) #卷积操作
L1_relu = tf.nn.relu(L1_conv + b) #激活函数RELU
return tf.nn.max_pool(L1_relu,ksize=kernel_size,strides=pool_strides,padding='SAME')
#定义全连接函数
def full_connect(inputs,W,b):
return tf.nn.relu(tf.matmul(inputs,W)+b)
#定义第一个预测函数
def predicts():
PROVINCES = ("川","鄂","赣","甘","贵","桂","黑","沪","冀","津","京","吉","辽","鲁","蒙","闽","宁","青","琼","陕","苏","晋","皖","湘","新","豫","渝","粤","云","藏","浙")
nProvinceIndex = 0
SAVER_DIR = "XXX\\train_saver\\province\\"
#新建一个图
g1 = tf.Graph()
with g1.as_default():
x = tf.placeholder(tf.float32,shape=[None,1024]) #None表示batch size的大小,这里可以是任何数,因为不知道待训练的图片数,SIZE指图片的大小
y_ = tf.placeholder(tf.float32,shape=[None,31]) #输出标签的占位
x_image = tf.reshape(x,[-1,32,32,1]) #生成一个四维的数组
sess1 = tf.Session(graph=g1)
saver = tf.train.import_meta_graph("%smodel.ckpt.meta"%(SAVER_DIR))
#model_file = "%smodel.ckpt"%(SAVER_DIR)
model_file = tf.train.latest_checkpoint(SAVER_DIR) #找出所有模型中最新的模型
saver.restore(sess1,model_file) #恢复模型,相当于加载模型
#第一个卷积层
W_conv1 = sess1.graph.get_tensor_by_name("W_conv1:0")
b_conv1 = sess1.graph.get_tensor_by_name("b_conv1:0")
conv_strides = [1,1,1,1]
kernel_size = [1,2,2,1]
pool_strides = [1,2,2,1]
L1_pool = conv_layer(x_image,W_conv1,b_conv1,conv_strides,kernel_size,pool_strides,padding='SAME')
print("第一个卷积层")
#第二个卷积层
W_conv2 = sess1.graph.get_tensor_by_name("W_conv2:0")
b_conv2 = sess1.graph.get_tensor_by_name("b_conv2:0")
conv_strides = [1,1,1,1]
kernel_size = [1,2,2,1]
pool_strides = [1,2,2,1]
L2_pool = conv_layer(L1_pool,W_conv2,b_conv2,conv_strides,kernel_size,pool_strides,padding='SAME')
#全连接层
W_fc1 = sess1.graph.get_tensor_by_name("W_fc1:0")
b_fc1 = sess1.graph.get_tensor_by_name("b_fc1:0")
h_pool2_flat = tf.reshape(L2_pool,[-1,8*8*24])
h_fc1 = full_connect(h_pool2_flat,W_fc1,b_fc1)
#dropout
keep_prob = tf.placeholder(tf.float32)
h_fc1_drop = tf.nn.dropout(h_fc1,keep_prob)
#readout层
W_fc2 = sess1.graph.get_tensor_by_name("W_fc2:0")
b_fc2 = sess1.graph.get_tensor_by_name("b_fc2:0")
#定义优化器和训练op
conv = tf.nn.softmax(tf.matmul(h_fc1_drop,W_fc2) + b_fc2)
for n in range(1,2):
path = "XXX\\test\\%s.bmp" % (n) #测试图的路径
img = cv.imread(path,0)
#cv.imshow('threshold',img)
#cv.waitKey(0)
height = img.shape[0] #行数
width = img.shape[1] #列数
img_data = [[0]*1024 for i in range(1)] #创建一个数组,用于将输入的图片转换成数组形式
for h in range(0,height):
for w in range(0,width):
m = img[h][w]
if m > 150:
img_data[0][w+h*width] = 1
else:
img_data[0][w+h*width] = 0
result = sess1.run(conv,feed_dict = {x:np.array(img_data),keep_prob:1.0})
#用于输出概率最大的3类
max1 = 0
max2 = 0
max3 = 0
max1_index = 0
max2_index = 0
max3_index = 0
for j in range(31):
if result[0][j] > max1:
max1 = result[0][j]
max1_index = j
continue
if (result[0][j]>max2) and (result[0][j]<=max1):
max2 = result[0][j]
max2_index = j
continue
if (result[0][j]>max3) and (result[0][j]<=max2):
max3 = result[0][j]
max3_index = j
continue
nProvinceIndex = max1_index #最大概率的类
print("概率:[%s %0.2f%%] [%s %0.2f%%] [%s %0.2f%%]" % (PROVINCES[max1_index],max1*100,PROVINCES[max2_index],max2*100,PROVINCES[max3_index],max3*100))
print("省份简称是:%s" % PROVINCES[nProvinceIndex])
return PROVINCES[nProvinceIndex],nProvinceIndex
sess1.close()
#定义第二个预测函数
def predictn():
LETTERS_DIGITS = ("A","B","C","D","E","F","G","H","J","K","L","M","N","P","Q","R","S","T","U","V","W","X","Y","Z","0","1","2","3","4","5","6","7","8","9")
license_num = ""
SAVER_DIR = "XXX\\train_saver\\numbers\\"
print("进入调用")
g2 = tf.Graph()
with g2.as_default():
x = tf.placeholder(tf.float32,shape=[None,1024]) #None表示batch size的大小,这里可以是任何数,因为不知道待训练的图片数,SIZE指图片的大小
y_ = tf.placeholder(tf.float32,shape=[None,34]) #输出标签的占位
x_image = tf.reshape(x,[-1,32,32,1]) #生成一个四维的数组
sess2 = tf.Session(graph=g2)
saver = tf.train.import_meta_graph("%smodel.ckpt.meta"%(SAVER_DIR))
model_file = tf.train.latest_checkpoint(SAVER_DIR) #找出所有模型中最新的模型
saver.restore(sess2,model_file)
#第一个卷积层
W_conv1 = sess2.graph.get_tensor_by_name("W_conv1:0")
b_conv1 = sess2.graph.get_tensor_by_name("b_conv1:0")
conv_strides = [1,1,1,1]
kernel_size = [1,2,2,1]
pool_strides = [1,2,2,1]
L1_pool = conv_layer(x_image,W_conv1,b_conv1,conv_strides,kernel_size,pool_strides,padding='SAME')
#第二个卷积层
W_conv2 = sess2.graph.get_tensor_by_name("W_conv2:0")
b_conv2 = sess2.graph.get_tensor_by_name("b_conv2:0")
conv_strides = [1,1,1,1]
kernel_size = [1,2,2,1]
pool_strides = [1,2,2,1]
L2_pool = conv_layer(L1_pool,W_conv2,b_conv2,conv_strides,kernel_size,pool_strides,padding='SAME')
#全连接层
W_fc1 = sess2.graph.get_tensor_by_name("W_fc1:0")
b_fc1 = sess2.graph.get_tensor_by_name("b_fc1:0")
h_pool2_flat = tf.reshape(L2_pool,[-1,8*8*24])
h_fc1 = full_connect(h_pool2_flat,W_fc1,b_fc1)
#dropout
keep_prob = tf.placeholder(tf.float32)
h_fc1_drop = tf.nn.dropout(h_fc1,keep_prob)
#readout层
W_fc2 = sess2.graph.get_tensor_by_name("W_fc2:0")
b_fc2 = sess2.graph.get_tensor_by_name("b_fc2:0")
#定义优化器和训练op
conv = tf.nn.softmax(tf.matmul(h_fc1_drop,W_fc2) + b_fc2)
#想尝试将城市代码和车牌后五位一起识别,因此可以将3-8改为2-8
for n in range(2,8):
path = "XXX\\test\\%s.bmp" % (n)
img = cv.imread(path,0)
height = img.shape[0]
width = img.shape[1]
img_data = [[0]*1024 for i in range(1)]
for h in range(0,height):
for w in range(0,width):
m = img[h][w]
if m > 150:
img_data[0][w+h*width] = 1
else:
img_data[0][w+h*width] = 0
result = sess2.run(conv,feed_dict = {x:np.array(img_data),keep_prob:1.0})
max1 = 0
max2 = 0
max3 = 0
max1_index = 0
max2_index = 0
max3_index = 0
for j in range(34):
if result[0][j] > max1:
max1 = result[0][j]
max1_index = j
continue
if (result[0][j]>max2) and (result[0][j]<=max1):
max2 = result[0][j]
max2_index = j
continue
if (result[0][j]>max3) and (result[0][j]<=max2):
max3 = result[0][j]
max3_index = j
continue
license_num = license_num + LETTERS_DIGITS[max1_index]
print("概率:[%s %0.2f%%] [%s %0.2f%%] [%s %0.2f%%]" % (LETTERS_DIGITS[max1_index],max1*100,LETTERS_DIGITS[max2_index],max2*100,LETTERS_DIGITS[max3_index],max3*100))
print("车牌编号是:%s" % license_num)
return license_num
sess2.close()
if __name__ == "__main__":
a,b = predicts()
c = predictn()
print("车牌号为:" + a + c[0]+ "·" + c[1:6] )
测试结果
测试结果为:
总结
在训练之后对模型进行测试,模型基本能够识别出部分省份、字母等。但是在一些数字、字母(相近的特征)上,模型并不能很好的进行识别,其目前存在的问题主要有:
1、模型的识别率不高,并且其与前面两个模块的进行有直接的联系,三个模块误差累积,导致最后识别效果不佳。
2、由于汉字和字母、数字一起识别其识别率过低,因此本文采用了的两个模型,但是两个模型的模型恢复时长过长,并不适合于实时检测的要求。
以上就是本小白的一些拙见,希望各位大佬能够给小弟提出一些建议与意见来进行改进。