车牌识别系统三:python+tensorflow实现车牌字符的识别

字符识别

在前面两篇博客中分别介绍了车牌定位以及字符分割的代码实现,那么在这篇文章中,我主要想介绍一下车牌识别系统的最后一个模块:字符识别。字符识别可以说是整个系统的核心部分了,这一部分可以有很多中实现方法:模板匹配、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、由于汉字和字母、数字一起识别其识别率过低,因此本文采用了的两个模型,但是两个模型的模型恢复时长过长,并不适合于实时检测的要求。
以上就是本小白的一些拙见,希望各位大佬能够给小弟提出一些建议与意见来进行改进。

  • 16
    点赞
  • 93
    收藏
    觉得还不错? 一键收藏
  • 69
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 69
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值