cnn验证码识别

import tensorflow as tf
import os
import pandas as pd


def load_pics(filename_list):
    """
    1、读取图像数据,csv文件中的file_num为标签值的编号
    :return:
    """
    # print(filename_queue)
    #    构造文件名队列
    filename_queue = tf.train.string_input_producer(filename_list)
    #    构造文件读取器
    image_reader = tf.WholeFileReader()
    #    读取文件(filename为文件名,对应csv文件中的file_num,image为图像原始编码)
    filename, image = image_reader.read(filename_queue)
    #    解码文件
    decoded = tf.image.decode_jpeg(image)
    #    更改图像形状和格式,方便进行批处理(conv2d中input参数要求张量类型必须为float32或float64)
    #    注意:在输入目标shape时一定要和图像数据的真实分辨率保持一致,否则会报错!
    #    (1)、可以调用set_shape直接修改形状
    # decoded.set_shape([60, 160, 3])
    # image_cast = tf.cast(decoded, dtype=tf.float32)
    #    (2)、也可以使用reshape函数修改,但不会改变原张量对象
    image_reshape = tf.reshape(decoded, shape=[60, 160, 3])
    image_cast = tf.cast(image_reshape, dtype=tf.float32)
    # print(image_cast)
    #    批处理
    filename_batch, image_batch = tf.train.batch([filename, image_cast], batch_size=100, num_threads=1, capacity=200)
    return filename_batch, image_batch


def read_csv(csv_data):
    """
    2、解析csv文件,将标签值转换为数值表示(根据26英文字母对应索引0-25建立标签对应的数值表)
       得到“图像-标签值”表
    :return:
    """
    # 将characters对应的数值列labels添加到data的新列“labels”中
    # # 当原文件第一行不是数值时要删去,drop函数中axis为1表示从行中查找,1表示从列中查找,
    # # index表示要删除的行名,columns为要删除的列名
    # data = csv_data.drop(axis=-1, index="file_num")
    data = csv_data
    labels = []
    for label_name in data["characters"]:
        label_num = []
        for letter in label_name:
            # ord()返回字符对应的ASCII码
            label_num.append(ord(letter) - ord('A'))
        labels.append(label_num)
    data["labels"] = labels
    # print(csv_data)
    return data


def filename2labels(file_name, batch_data):
    """
    3、根据filename与file_num对应相同来联系特征值(图片)与目标值(标签)
       通过文件名查表得到当前图像对应的标签
    :param batch_data:
    :return:
    """
    label_list = []
    # print(file_name)
    for name in file_name:
        # print(name)
        # 先把name转换为字符串类型,然后使用isdigit查找其中的数字,即文件名
        num_str = "".join(list(filter(str.isdigit, str(name))))
        # print(type(num_str))
        target = batch_data.loc[num_str, "labels"]
        # print(target)
        label_list.append(target)
    return label_list


def variable_init(shape):
    """
    定义给定形状的变量
    :return:
    """
    return tf.Variable(initial_value=tf.random.normal(shape=shape))


def cnn_identifying(x):
    """
    4、构建卷积神经网络得到y_predict
    :return:
    """
    input_image = tf.reshape(x, [-1, 60, 160, 3])
    with tf.variable_scope("conv1"):
        # 卷积层1
        Weights_filter1 = variable_init([5, 5, 3, 32])
        bias_filter1 = variable_init([32])
        conv1 = tf.nn.conv2d(input=input_image, filter=Weights_filter1, strides=[1, 1, 1, 1], padding="SAME") + bias_filter1
        # 激活函数
        conv1_relu = tf.nn.relu(conv1)
        # 池化层
        conv1_pool = tf.nn.max_pool(value=conv1_relu, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding="SAME")
    with tf.variable_scope("conv2"):
        # 卷积层2
        Weights_filter2 = variable_init([5, 5, 32, 64])
        bias_filter2 = variable_init([64])
        conv2 = tf.nn.conv2d(input=conv1_pool, filter=Weights_filter2, strides=[1, 1, 1, 1], padding="SAME") + bias_filter2
        # 激活函数
        conv2_relu = tf.nn.relu(conv2)
        # 池化层
        conv2_pool = tf.nn.max_pool(value=conv2_relu, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding="SAME")
    with tf.variable_scope("fc"):
        # 全连接层
        conv2_reshape = tf.reshape(conv2_pool, shape=[-1, 15*40*64])
        Weights_fc = variable_init([15*40*64, 4*26])
        bias_fc = variable_init([4*26])
        y_predict = tf.matmul(conv2_reshape, Weights_fc) + bias_fc
    return y_predict


if __name__ == "__main__":
    # 使用QueueRunner的方式读取文件
    # 构造“路径、文件名”列表
    file_list = os.listdir(r"C:\Users\Username\Desktop\Con-LSTM\captcha_cnn\captcha_train_pic")
    # print(filename_list)
    filename_list = [os.path.join(r"C:\Users\Username\Desktop\Con-LSTM\captcha_cnn\captcha_train_pic", filename)
                     for filename in file_list if filename[-3:] == "jpg"]
    filename, image = load_pics(filename_list)
    # 得到“图像-标签值”表
    # 读取csv文件,列命名为file_num、characters, 列索引设为file_num
    csv_data = pd.read_csv(r"C:\Users\Username\Desktop\Con-LSTM\captcha_cnn\captcha_train_pic\labels.csv",
                           names={"file_no", "characters"}, index_col="file_no")
    csv_data_train = read_csv(csv_data)
    # print(csv_data)
    x = tf.placeholder(dtype=tf.float32, shape=[None, 60, 160, 3])
    # 计算损失时需要一维数组(需要知道4*26个数字的损失),计算准确率时需要二维数组(四行分别代表四个字母)
    y_true = tf.placeholder(dtype=tf.float32, shape=[None, 4*26])
    y_predict = cnn_identifying(x)

    # 构造数据流图:
    # 5、构造损失函数(一个样本涵盖多个目标值时,应用sigmoid交叉熵作为损失函数)
    loss_list = tf.nn.sigmoid_cross_entropy_with_logits(labels=y_true, logits=y_predict)
    loss = tf.reduce_mean(loss_list)
    # 6、优化损失
    optimizer = tf.train.AdamOptimizer(learning_rate=0.001).minimize(loss)
    # 7、计算准确率
    #    先转换为4行26列形式,才能表示出字母所在位置
    y_predict_reshape = tf.reshape(y_predict, shape=[-1, 4, 26])
    y_true_reshape = tf.reshape(y_true, shape=[-1, 4, 26])
    #    因为要根据第三阶的最大值判断字母,所以axis为2或-1,最终形式形如[[True, True, False, True], [...], ...]
    equal_list = tf.equal(tf.argmax(y_predict_reshape, axis=2), tf.argmax(y_true_reshape, axis=2))
    #    用reduce_all()转换为一维数组[False, ..., ...], 用cast()转换为浮点型,再用reduce_mean()计算得平均值,即准确率
    accuracy = tf.reduce_mean(tf.cast(tf.reduce_all(equal_list, axis=1), tf.float32))
    # 8、开启会话(线程的开启与关闭)
    # 使用文件名队列进行数据读取时要先开启线程
    # 初始化变量
    init = tf.global_variables_initializer()
    # 构造模型存储器
    saver = tf.train.Saver()
    with tf.compat.v1.Session() as sess:
        sess.run(init)
        # 开启线程
        # 创建线程协调员
        coord = tf.train.Coordinator()
        threads = tf.train.start_queue_runners(sess=sess, coord=coord)

        filename_val, image_val = sess.run([filename, image])
        # 通过文件名查表得到当前图像对应的标签(真实值)
        image_labels = filename2labels(filename_val, csv_data_train)
        # 对真实值进行one-hot编码(depth为一个编码的长度,axis默认为-1,即按最后一个维度)
        labels_onehot = tf.one_hot(image_labels, depth=26)
        labels_value = tf.reshape(labels_onehot, shape=[-1, 4*26]).eval()
        # print(labels_onehot.eval())
        # print(sess.run(equal_list, feed_dict={x: image_val, y_true: labels_value}))
        for i in range(1000):
            # 注意feed_dict中的值应为Python scalar, string, list, numpy ndarray类型,不能为张量
            _, error, accuracy_value = sess.run([optimizer, loss, accuracy], feed_dict={x: image_val, y_true: labels_value})
            # print("第%d次训练的误差为:%f,准确率为:%f" % (i+1, error, accuracy_value))
            if i % 100 == 0:
                saver.save(sess=sess, save_path=r"C:\Users\Username\Desktop\Con-LSTM\captcha_cnn\model")

        # print(filename_val, image_val)
        # 回收线程
        coord.request_stop()
        coord.join(threads=threads)
#coding:utf8
# 验证码生成
from captcha.image import ImageCaptcha
from random import randint
import os
import csv


def captcha_pic_builder():
    '''
    生成序列验证码图片及包含其对应目标值的csv文件
    :return:
    '''
    list = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V',
            'W', 'X', 'Y', 'Z']
    # 因为csv标签名不能放在循环里的缘故,故将创建及增加内容放在外面
    # newline='',是为了防止以Excel打开时会多出空行
    with open(r'C:\Users\Username\Desktop\Con-LSTM\captcha_cnn\captcha_test_pic\labels.csv', 'a+', newline='') as csvfile:
        writer = csv.writer(csvfile, dialect='excel')
        writer.writerow(['file_num', 'chars'])
        for j in range(100):
            chars = ''
            for i in range(4):
                chars += list[randint(0, 25)]
            # 随机生成图片内字符
            print(chars)
            # 生成图片
            image = ImageCaptcha().generate_image(chars)
            # image.show()
            filename = str(j) +'.jpg'
            # 将图片保存到本地
            image.save(os.path.join(r'C:\Users\Username\Desktop\Con-LSTM\captcha_cnn\captcha_test_pic', filename))
            # 添加样本序列及目标值
            writer.writerow([j, chars])
    return None


if __name__ == '__main__':
    captcha_pic_builder()

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值