使用tensorflow搭建自己的验证码识别系统

学习tensorflow有一段时间了,想做点东西来练一下手。为了更有意思点,下面将搭建一个简单的验证码识别系统。

准备验证码数据

下面将生成一万张四位英文字母的验证码,验证码的大小是100 * 30的图片,只包含大写的英文字母,并将目标值保存到csv文件。

import random
import pandas as pd
from PIL import Image, ImageDraw, ImageFont


def generate_captcha(filename, format):
    """
    生成四位验证码
    :param filename: 要保存的文件名
    :param format: 保存图片格式
    :return: 验证码的值
    """
    # 定义使用Image类实例化一个长为100px,宽为30px,基于RGB的(255,255,255)颜色的图片
    img = Image.new(mode="RGB", size=(100, 30), color=(255, 255, 255))
    # 实例化一支画笔
    draw = ImageDraw.Draw(img, mode="RGB")
    # 定义要使用的字体
    font = ImageFont.truetype("arial", 28)

    result = ""

    for i in range(4):
        # 每循环一次,从a到z中随机生成一个字母
        # 65到90为字母的ASCII码,使用chr把生成的ASCII码转换成字符
        # str把生成的数字转换成字符串
        char = random.choice([chr(random.randint(65, 90))])
        result += char

        # 每循环一次重新生成随机颜色
        color = (random.randint(0, 255), random.randint(0, 255), random.randint(0, 255))

        # 把生成的字母或数字添加到图片上
        # 图片长度为100px,要生成4个数字或字母则每添加一个,其位置就要向后移动24px
        draw.text([i * 24 + 3, 0], char, color, font=font)

    # 保存生成的文件
    with open(filename, "wb") as f:
        img.save(f, format=format)

    return result


if __name__ == "__main__":

    data = []

    # 生成10000张验证码图片,并将目标值存入csv文件
    for j in range(10000):
        val = generate_captcha("./pics/{}.png".format(j), "png")
        data.append([val])

    # 将验证码的值保存到csv文件
    df = pd.DataFrame(data, columns=['label'])
    df.to_csv('./pics/data.csv', header=False)

生成的验证码图片是这样子的,如下:

1156642-20190410113946652-1397337489.png

1156642-20190410114017472-86903244.png

csv文件内容:

0,EFGQ
1,ZDKO
2,UWLD
3,CPDH
....

保存为tfrecords文件

上面生成的图片和其目标值是分开的,在进行训练时不太方便(训练时每次都要单独的读取图片和特征值)。保存为tfrecords文件,在训练时会方便很多,读取出来的每条记录既有图片特征值又有目标值。

import tensorflow as tf
import os
import numpy as np


class CaptchaInput(object):

    def __init__(self, captcha_dir, letter, tfrecords_dir):
        """
        :param captcha_dir: 验证码路径
        :param letter: 验证码字符种类
        :param tfrecords_dir: tfrecords文件保存的目录
        """
        self.captcha_dir = captcha_dir
        self.letter = letter
        self.tfrecords_dir = tfrecords_dir

        # 列出图片文件,并进行排序
        self.file_list = os.listdir(self.captcha_dir)
        self.file_list = [i for i in self.file_list if i.endswith(".png")]
        self.file_list.sort(key=lambda x: int(x[0:-4]))
        self.file_list = [os.path.join(self.captcha_dir, i) for i in self.file_list]

        # 标签文件路径
        self.labels_path = os.path.join(self.captcha_dir, "data.csv")

    def read_captcha_image(self):
        """读取验证码图片数据"""
        # 构造文件队列
        file_queue = tf.train.string_input_producer(self.file_list, shuffle=False)

        # 构建阅读器
        reader = tf.WholeFileReader()

        # 读取图片内容
        key, value = reader.read(file_queue)
        # 解码图片
        image = tf.image.decode_png(value)
        image.set_shape([30, 100, 3])

        # 批量读取
        image_batch = tf.train.batch([image], batch_size=len(self.file_list),
                                     num_threads=1, capacity=len(self.file_list))
        return image_batch

    def read_captcha_label(self):
        """读取 验证码标签数据"""
        # 构造文件队列
        file_queue = tf.train.string_input_producer([self.labels_path], shuffle=False)

        # 构建文件阅读器
        reader = tf.TextLineReader()

        # 读取标签内容
        key, value = reader.read(file_queue)

        records = [[0], [""]]
        index, label = tf.decode_csv(value, record_defaults=records)

        # 批量读取
        label_batch = tf.train.batch([label], batch_size=len(self.file_list),
                                     num_threads=1, capacity=len(self.file_list))

        return label_batch

    def process_labels(self, labels):
        """将标签字符转换成数字张量"""
        # 构建字符索引
        num_letter_dict = dict(enumerate(list(self.letter)))
        letter_num_dict = dict(zip(num_letter_dict.values(), num_letter_dict.keys()))

        ret = []

        for label in labels:
            arr = [letter_num_dict[i] for i in label.decode("utf-8")]
            ret.append(arr)

        return np.array(ret)

    def write_to_tfrecords(self, images, labels):
        """
        将图片和标签写入到tfrecords文件中
        :param images: 特征值
        :param labels: 目标值
        :return:
        """
        # labels = tf.cast(labels, tf.uint8)
        # images = tf.cast(images, tf.uint8)

        # 建立存储文件
        fw = tf.python_io.TFRecordWriter(self.tfrecords_dir)
        for i in range(len(self.file_list)):
            # images[i]为numpy.ndarray
            image_bytes = images[i].tobytes()
            # labels[i]为numpy.ndarray
            label_bytes = labels[i].tobytes()

            example = tf.train.Example(features=tf.train.Features(feature={
                "image": tf.train.Feature(bytes_list=tf.train.BytesList(value=[image_bytes])),
                "label": tf.train.Feature(bytes_list=tf.train.BytesList(value=[label_bytes]))
            }))

            print("保存第%d张图片" % (i, ))

            fw.write(example.SerializeToString())

        # 关闭
        fw.close()

    def execute(self):
        image_batch = self.read_captcha_image()
        label_batch = self.read_captcha_label()

        with tf.Session() as sess:

            coord = tf.train.Coordinator()

            threads = tf.train.start_queue_runners(sess, coord=coord)

            # [b'EFGQ' b'ZDKO' b'UWLD' ... b'TKPD' b'ZZEU' b'ATYA']
            labels = sess.run(label_batch)

            # labels为numpy.ndarray
            labels = self.process_labels(labels)
            # images为numpy.ndarray
            images = sess.run(image_batch)

            self.write_to_tfrecords(images, labels)

            coord.request_stop()
            coord.join(threads)


FLAGS = tf.app.flags.FLAGS

tf.app.flags.DEFINE_string("captcha_dir", "./pics", "验证码图片路径")
tf.app.flags.DEFINE_string("letter", "ABCDEFGHIJKLMNOPQRSTUVWXYZ", "验证码字符种类")
tf.app.flags.DEFINE_string("tfrecords_dir", "./tfrecords/captcha.tfrecords", "验证码tfrecords文件")


if __name__ == "__main__":
    c = CaptchaInput(FLAGS.captcha_dir, FLAGS.letter, FLAGS.tfrecords_dir)
    c.execute()

需要注意:

  • os.listdir返回的文件名称的顺序是按照ascii表的顺序(1.png, 10.png...)需要对其进行排序
  • 使用tensorflow读取图片和标签文件时,需要加上shuffle=False,避免文件乱序了,图片和目标值对应不上。

验证码训练

import tensorflow as tf


FLAGS = tf.app.flags.FLAGS

tf.app.flags.DEFINE_string("captcha_dir", "./tfrecords/captcha.tfrecords", "验证码数据文件")
tf.app.flags.DEFINE_integer("batch_size", 100, "每批次训练样本数")


def read_and_decode():
    """读取验证码数据
    :return image_batch, label_batch
    """
    # 文件队列
    file_queue = tf.train.string_input_producer([FLAGS.captcha_dir])

    # 文件读取器
    reader = tf.TFRecordReader()

    # 读取内容
    key, value = reader.read(file_queue)
    # 解析tfrecords
    features = tf.parse_single_example(value, features={
        "image": tf.FixedLenFeature([], tf.string),
        "label": tf.FixedLenFeature([], tf.string)
    })
    # 解码
    image = tf.decode_raw(features["image"], tf.uint8)
    label = tf.decode_raw(features["label"], tf.uint8)
    # print(image, label)

    # 改变形状
    image_reshape = tf.reshape(image, [30, 100, 3])
    label_reshape = tf.reshape(label, [4])
    # print(image_reshape, label_reshape)

    # 批处理
    image_batch, label_batch = tf.train.batch([image_reshape, label_reshape],
                                              batch_size=FLAGS.batch_size, num_threads=1, capacity=FLAGS.batch_size)
    return image_batch, label_batch


def weight_variables(shape):
    """权重初始化函数"""
    w = tf.Variable(tf.random_normal(shape=shape, mean=0.0, stddev=1.0))
    return w


def bias_variables(shape):
    """偏置初始化函数"""
    b = tf.Variable(tf.constant(0.0, shape=shape))
    return b


def fc_model(image):
    """全连接模型"""
    with tf.variable_scope("fc_model"):
        image_reshape = tf.reshape(image, [-1, 30 * 100 * 3])

        # 随机初始化权重和偏重
        weights = weight_variables([30 * 100 * 3, 4 * 26])
        bias = bias_variables([4 * 26])

        # 全连接计算
        y_predict = tf.matmul(tf.cast(image_reshape, tf.float32), weights) + bias

    return y_predict


def label_to_onehot(label):
    """目标值转换成one-hot编码"""
    label_onehot = tf.one_hot(label, depth=26, on_value=1.0, axis=2)
    return label_onehot


def captcharec():
    """验证码识别"""
    image_batch, label_batch = read_and_decode()
    # [100, 104]
    y_predict = fc_model(image_batch)

    y_true = label_to_onehot(label_batch)

    # softmax计算,交叉熵损失计算
    with tf.variable_scope("soft_cross"):
        loss = tf.nn.softmax_cross_entropy_with_logits(
            labels=tf.reshape(y_true, [-1, 4 * 26]),
            logits=y_predict
        )

    # 梯度下降损失优化
    with tf.variable_scope("optimizer"):
        train_op = tf.train.GradientDescentOptimizer(0.01).minimize(loss)

    # 准确率
    with tf.variable_scope("acc"):
        equal_list = tf.equal(tf.argmax(y_true, 2), tf.argmax(tf.reshape(y_predict, [-1, 4, 26]), 2))
        accuracy = tf.reduce_mean(tf.cast(equal_list, tf.float32))

    init_op = tf.global_variables_initializer()

    with tf.Session() as sess:

        sess.run(init_op)

        coord = tf.train.Coordinator()
        threads = tf.train.start_queue_runners(sess, coord=coord)

        for i in range(3000):
            sess.run(train_op)

            print("第%d次训练的准确率为:%f" % (i, accuracy.eval()))

        coord.request_stop()
        coord.join(threads)


if __name__ == '__main__':
    captcharec()

转载于:https://www.cnblogs.com/zhangfengxian/p/10686482.html

使用过程注意事项: 1.调用DLL识别识别,多线程下不需要加许可证,支持并发识别. 2.调用DLL识别,识别参数设置命令SetWmOption必须与你弄字库时候的设置参数一样,不然会导致识别率下降具体参数说明,请看调用例子里的[我的函数.txt]文档有对应参数说明. 3.如果遇见本工具无法识别的验证码,可以找群主(用神经网络识别)定制,价格便宜公道. [2017-07-27] 完美验证码识别系统V3.2 1.增加DLL识别返回方式2和3具体看我的函数.txt里说明,主要是增加一个可以返回识别后的总体信任度.这个值你可以给它个阀值,比如说如果总体信任度小于60,那么你就不提交服务器,直接重新获取图片识别,直到总体信任度大于60你才提交给服务器,这个阀值具体多少,自己可以先测试. 2.修复导出字库没有导出完,直接关闭窗口崩溃问题 3.添加批量下载后定位到批量下载文件夹 4.增加可以使用验证码长度进行过滤,增加可以使用总体信任度进行过滤.(这两个功能可以快速的制作字库,比如说你验证码是4位的,你可以设置验证码小于4,大于4那这张图片肯定是识别错误的,那么软件就会把这张图片保存下来,同理可以使用总体信任度进行此保存) [2017-07-20] 完美验证码识别系统V3.1 1.修复数组下标越界问题 2.字库列表添加可以多选然后右键批量删除选中项 [2017-07-13] 完美验证码识别系统V3.0 1.修复导出字库,重复导出不会覆盖原来的BUG,导出的图片会累加上去(注意,以前导出的字模导入新版中会出错,新版字模导出格式为a_md5.bmp 请自行写个软件修改文件名,然后再导入) 2.修复添加字库空格都可以添加进去 3.修复崩溃问题.(崩溃应该绝大多数都是此原因造成的.) 4.其它一些调整. [2017-06-25] 完美验证码识别系统V2.6 1.解决输入焦点问题. 2.批量下载增加可以过滤掉宽度范围,面积范围,高度范围,黑色数范围,可以去掉没有用的干扰图片. 3.其它的一些细节调整 [2017-06-07] 完美验证码识别系统V2.5 1.修复去除干扰滤镜在没有先二值化图片都可以使用. 2.尝试解决添加字库崩溃问题(代码较多,找到1处问题.不知道还有没有其他问题) 3.编辑字库页面增加个选中框[添加字库后自动下载图片],使用批量下载图片,可以快速添加字库 4.使用截图工具,截取图片后,会自动切换到划线工具. [2017-05-17] 完美验证码识别系统V2.3 1.修复设置滤镜默认都有选择项. 2.修复当使用本地图像时,没有新建项目都可以编辑的问题. 3.修复黑白处理滤镜在没有先二值化图片都可以使用. 4.修复处理很多逻辑错误会导致程序崩溃. 5.增加字库列表添加右键删除当前选中的字库 6.增加禁止重复运行,由于重复运行会导致字库添加失败,和读取不到已经做过的字库. 7.增加快捷键"自动分割(Alt+R)" ,"手动分割(Alt+T)" 8.编辑页面增加个批量下载按钮,可以实现批量下载并自动分割图片功能(批量下载的图片保存在当前项目文件夹下的"批量下载"文件夹中) 9.主窗口增加一个选择框_图像已处理不使用滤镜,由于批量下载后图片都是已经使用过滤镜了,处理批量下载的图片这里必须得勾选上,不然会重复运用滤镜 [2017-05-07] 完美验证码识别系统V2.2 1.新增分辨率1024*768布局 2.修改注册热键方式为本进程方式(原为全局热键,感谢群友XGSoft提供源代码) [2017-05-06] 完美验证码识别系统V2.1(要求屏幕分辨率最低1440*900) 1.去掉窗口最大化,去掉自动调整窗口大小代码,修复部分控件显示不全 2.增加检测图像是否二值化,没二值化的图片不允许编辑 3.尝试解决添加字库崩溃的问题(不确定问题出在哪!!) 4.解决滤波数组越界问题.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值