实战七:手把手教你用TensorFlow进行验证码识别(上)

实战七:手把手教你用TensorFlow进行验证码识别(上)

github下载地址

目录

  • 准备模型开发环境
  • 生成验证码数据集
  • 输入与输出数据处理
  • 模型结构设计
  • 模型损失函数设计
  • 模型训练过程分析
  • 模型部署与效果演示

一、准备模型开发环境

1.第三方依赖包

pip install Pillow captcha pydot flask

在这里插入图片描述

2.Pillow(PUL Fork)

PIL(Python Imaging Library)为Python解释器添加了图像处理功能。但是,在2009年发布1.17版本之后,社区便停止更新和维护。

Pillow是由Alex Clark及社区贡献者一起开发和维护的一款分叉自PIL的图像工具库。至今,社区依然非常活跃,Pillow仍在快速迭代。

Pillow提供广泛的文件格式支持,高效的内部表示和相当强大的图像处理功能。核心图像库旨在快速访问以几种基本像素格式存储的数据,它应该为一般的图像处理工具提供坚实的基础。

3.catpcha

Catpcha是一个生成图像和音频验证码的开源工具库

from captcha.image import ImageCaptcha
from captcha.audio import AudioCaptcha

image = ImageCaptcha(fonts=["/path/A.ttf","/path/B.ttf")
data = image.generate("1234")
image.write("1234","out.png")

audio = AudioCaptcha(voicedir="/path/voices")
data = audio.generate("1234")
audio.write("1234","out.wav")

4.pydot

pydot是用纯Python实现的GraphViz接口,支持使用GraphViz解析和存储DOT语言(graph description language).其主要依赖pyparsingGraphViz这两个工具库

pyparsing:仅用于加载DOT文件,在pydot安装期间自动安装。

Graphviz:将图形渲染为PDF,PNG,SVG等格式文件,需独立安装。

5.flask

flask是一个基于Werkzeug和jinja2开发的Python Web应用程序框架,遵从BSD开源协议。它以一种简约的方式实现了框架核心,又保留了扩展性。

from flask import Flask

app = Flask(__name__)

@app.route("/")
def hello():
    return "Hello,World!"

二、生成验证码数据集

1.验证码(catpcha)简介

全自动区分计算机和人类对的公开图灵测试,俗称验证码,是一种区分用户是计算机或人的公共全自动程序。在captcha测试中,作为服务器的计算机会自动生成一个问题由用户来解答。这个问题可以由计算机生成并评判,但是必须只有人类才能解答。由于计算机无法解答captcha的问题,所以回答出问题的用户就可以被认为是人类。

一种常用的captcha测试是让用户输入一个扭曲变形的图片上所显示的文字或数字,扭曲变形式为了避免被光学字符识别(OCR)之类的计算机程序自动识别出图片上的数字而失去效果。由于这个测试是由计算机来考人类,而不是标准图灵测试中那样由人类来考计算机,人们有时称captcha是一种反向图灵测试

2.验证码的演进

在这里插入图片描述

3.验证码的生成

a.引入第三方包

from captcha.image import ImageCaptcha

import random 
import numpy as np

import tensorflow.gfile as gfile
import matplotlib.pyplot as plt
import PIL.Image as Image

b.定义常量和字符集

NUMBER = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']
LOWERCASE = ['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']
UPPERCASE = ['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']

CAPTCHA_CHARSET = NUMBER   # 验证码字符集
CAPTCHA_LEN = 4            # 验证码长度
CAPTCHA_HEIGHT = 60        # 验证码高度
CAPTCHA_WIDTH = 160        # 验证码宽度

TRAIN_DATASET_SIZE = 5000  # 验证码数据集大小
TEST_DATASET_SIZE = 1000   # 验证码测试集大小
TRAIN_DATA_DIR = "./train-data/" # 验证码数据集目录
TEST_DATA_DIR = "./test-data/"   # 验证码测试集目录

c.生成随机字符的方法

def gen_random_text(charset=CAPTCHA_CHARSET,length=CAPTCHA_LEN):
    text = [random.choice(charset) for _ in range(length)]
    return "".join(text)

d.创建并保存验证码数据集的方法

def create_captcha_dataset(size=100,data_dir="./data/",height=60,width=160,image_format=".png"):
    
    # 如果保存验证码图像,先清空data_dir目录
    if gfile.Exists(data_dir):
        gfile.DeleteRecursively(data_dir)
    gfile.MakeDirs(data_dir)
    
    # 创建ImageCaptcha实例captcha
    captcha = ImageCaptcha(width=width,height=height)
    
    for _ in range(size):
        # 生成随机的验证码字符
        text = gen_random_text(CAPTCHA_CHARSET,CAPTCHA_LEN)
        captcha.write(text,data_dir + text + image_format)
    
    return None

e.创建并保存训练集及测试集

# 创建并保存训练集
create_captcha_dataset(TRAIN_DATASET_SIZE,TRAIN_DATA_DIR)

# 创建并保存测试集
create_captcha_dataset(TEST_DATASET_SIZE,TEST_DATA_DIR)

f.生成并返回验证码数据集的方法

def gen_captcha_dataset(size=100,height=60,width=160,image_font=".png"):
    
    # 创建ImageCaptcha实例captcha
    captcha = ImageCaptcha(width=width,height=height)
    
    # 创建图像和文本数组
    images,texts = [None]*size,[None]*size
    for i in range(size):
        # 生成随机的验证码字符
        texts[i] = gen_random_text(CAPTCHA_CHARSET,CAPTCHA_LEN)
        # 使用PIL.Image.open() 识别新生成的验证码图像
        # 然后,将图像转换为形如(CAPTCHA_WIDTH,CAPTCHA_HEIGHT,3)的numpy数组
        images[i] = np.array(Image.open(captcha.generate(texts[i])))
        
    return images,texts

g.生成100张验证码图像和字符

# 生成并返回图像和标签
images,texts = gen_captcha_dataset()
# 展示
plt.figure()
for i in range(20):
    plt.subplot(5,4,i+1) # 绘制前20个验证码,以5行4列子图形式展示
    plt.tight_layout()   # 自动适配子图尺寸
    plt.imshow(images[i])
    plt.title("Label:{}".format(texts[i])) # 设置标签为子图标题
    plt.xticks([])       # 删除x轴标记
    plt.yticks([])       # 删除y轴标记
plt.show()

在这里插入图片描述

三、输入与输出数据处理

1.输入数据处理

在这里插入图片描述

在这里插入图片描述

2.输出数据处理

在这里插入图片描述

在这里插入图片描述

3.数据处理

a.引入第三方包

from PIL import Image
from keras import backend as K

import random
import glob

import numpy as np
import tensorflow.gfile as gfile
import matplotlib.pyplot as plt

b.定义超参数和字符集

NUMBER = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']
LOWERCASE = ['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']
UPPERCASE = ['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']

CAPTCHA_CHARSET = NUMBER   # 验证码字符集
CAPTCHA_LEN = 4            # 验证码长度
CAPTCHA_HEIGHT = 60        # 验证码高度
CAPTCHA_WIDTH = 160        # 验证码宽度

TRAIN_DATA_DIR = '.\\train-data\\' # 验证码数据集目录

c.读取训练集前100张图片,并通过文件名解析验证码(标签)

image = []
text = []
count = 0
for filename in glob.glob(TRAIN_DATA_DIR + "*.png"):
    image.append(np.array(Image.open(filename)))
    text.append(filename.lstrip(TRAIN_DATA_DIR).rstrip(".png"))
    count +=  1
    if count >= 100:
        break

d.数据可视化

plt.figure()
for i in range(20):
    plt.subplot(5,4,i+1) # 绘制前20个验证码,以5行4列子图形式展示
    plt.tight_layout()   # 自动适配子图尺寸
    plt.imshow(image[i])
    plt.title("Label:{}".format(text[i])) # 设置标签为子图标题
    plt.xticks([])       # 删除x轴标记
    plt.yticks([])       # 删除y轴标记
plt.show()

在这里插入图片描述

image = np.array(image,dtype=np.float32)
print(image.shape,type(image))
(100, 60, 160, 3) <class 'numpy.ndarray'>

e.将RGB验证码图像转成灰度图

# 定义转灰度图函数
def rgb2gray(img):
    # 这里利用公式来转换 Y' = 0.299 R + 0.587 G + 0.114 B 
    return np.dot(img[...,:3],[0.299,0.587,0.114])

# 转换
image = rgb2gray(image)
# 输出维度
print(image.shape)
(100, 60, 160)
# 查看图形
plt.figure()
for i in range(20):
    plt.subplot(5,4,i+1)  # 绘制前20个验证码,以5行4列子图形式展示
    plt.tight_layout()    # 自动适配子图尺寸
    plt.imshow(image[i],cmap="Greys")
    plt.title("Label:{}".format(text[i])) # 设置标签为子图标题
    plt.xticks([])        # 删除x轴标记
    plt.yticks([])        # 删除y轴标记
plt.show()

在这里插入图片描述

f.数据规范化

image = image / 255
image[0]
array([[0.96912157, 0.96912157, 0.96912157, ..., 0.96912157, 0.96912157,
        0.96912157],
       [0.96912157, 0.96912157, 0.96912157, ..., 0.96912157, 0.96912157,
        0.96912157],
       [0.96912157, 0.96912157, 0.96912157, ..., 0.96912157, 0.96912157,
        0.96912157],
       ...,
       [0.96912157, 0.96912157, 0.96912157, ..., 0.96912157, 0.96912157,
        0.96912157],
       [0.96912157, 0.96912157, 0.96912157, ..., 0.96912157, 0.96912157,
        0.96912157],
       [0.96912157, 0.96912157, 0.96912157, ..., 0.96912157, 0.96912157,
        0.96912157]])

g.适配Keras图像数据格式

# 先查看一下数据的维度
print(image.shape,type(image))
(100, 60, 160) <class 'numpy.ndarray'>
# 定义适配函数
def fit_keras_channels(batch,rows=CAPTCHA_HEIGHT,cols=CAPTCHA_WIDTH):
    if K.image_data_format() == "channels_first":
        batch = batch.reshape(batch.shape[0],1,rows,cols)
        input_shape = (1,rows,cols)
    else:
        batch = batch.reshape(batch.shape[0],rows,cols,1)
        input_shape = (rows,cols,1)
    
    return batch,input_shape
# 再重新查看一下数据的维度
image,input_shape = fit_keras_channels(image)
print(image.shape,type(image))
print(input_shape)
(100, 60, 160, 1) <class 'numpy.ndarray'>
(60, 160, 1)

h.对验证按中每个字符进行one-hot编码

# 查看一下text中的数据
print(text[:10])
print(len(text[0]))
print(len(text))
['0002', '0004', '0007', '0009', '0011', '0012', '0014', '0015', '0017', '0018']
4
100
# 定义one-hot编码函数
# CAPTCHA_CHARSET = NUMBER   # 验证码字符集
# CAPTCHA_LEN = 4            # 验证码长度
def text2vec(text,length=CAPTCHA_LEN,charset=CAPTCHA_CHARSET):
    text_len = len(text)
    # 验证码长度校验
    if text_len != length:
        raise ValueError("Error:length of captcha should be{},but got {}".format(length,text_len))
    # 生成一个形如(CAPTCHA_LEN*CAPTCHA_CHARSET)的一维向量
    # 例如,4个纯数字的验证码生成形如(4*10,)的一维向量
    vec = np.zeros(length*len(charset))
    for i in range(length):
        # One-hot编码验证码中的每个数字
        # 每个字符的热码 = 索引 +偏移量
        vec[charset.index(text[i]) + i*len(charset)] = 1
    return vec
text = list(text)
vec = [None]*len(text)

for i in range(len(vec)):
    vec[i] = text2vec(text[i])
print(text[0])
print(vec[0])
0002
[1. 0. 0. 0. 0. 0. 0. 0. 0. 0. 1. 0. 0. 0. 0. 0. 0. 0. 0. 0. 1. 0. 0. 0.
 0. 0. 0. 0. 0. 0. 0. 0. 1. 0. 0. 0. 0. 0. 0. 0.]
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

mind_programmonkey

你的鼓励是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值