"""
Title: OCR model for reading Captchas
Author: [A_K_Nain](https://twitter.com/A_K_Nain)
Date created: 2020/06/14
Last modified: 2020/06/26
Description: How to implement an OCR model using CNNs, RNNs and CTC loss.
Accelerator: GPU
"""
"""
## 简介
本例展示了使用功能 API 构建简单 OCR 模型。除了结合了 CNN 和 RNN ,它还演示了如何实例化一个新层并将其用作实现 CTC 损失的“终端层”。关于层子类化
的详细指南,请查看开发者指南中的
[this page](https://keras.io/guides/making_new_layers_and_models_via_subclassing/)
。
"""
"""
## 设置
"""
import os
import numpy as np
import matplotlib.pyplot as plt
from pathlib import Path
from collections import Counter
import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import layers
"""
## 加载数据:[Captcha Images](https://www.kaggle.com/fournierp/captcha-version-2-images)
先下载数据。
"""
"""shell
curl -LO http://127.0.0.1:9000/captcha_images_v2.zip
unzip -qq captcha_images_v2.zip
"""
"""
该数据集包含1040个作为 `png` 图像的 captcha 文件。每个样本的标签是一个字符串,文件的名称(减去文件扩展名)。
我们将把字符串中的每个字符映射到一个整数来训练模型。类似地,
我们需要将模型的预测映射回字符串。为此目的我们将分别地维护两个字典,分别用于将字符映射到整数,分别用于将整数映射到字符。
"""
# 数据目录的路径
data_dir = Path("./captcha_images_v2/")
# 获取所有图像的列表
images = sorted(list(map(str, list(data_dir.glob("*.png")))))
labels = [img.split(os.path.sep)[-1].split(".png")[0] for img in images]
characters = set(char for label in labels for char in label) # 建立用于验证码中字符的字符集合
characters = sorted(list(characters))
print("发现的图像数量:", len(images))
print("发现的标签数量:", len(labels))
print("独特字符的数量:", len(characters))
print("存在的字符:", characters)
# 训练和验证使用的批量大小
batch_size = 16
# 所需图像大小
img_width = 200
img_height = 50
# 用于卷积块降采样的因子。
# 我们将使用两个卷积块,每个块都有一个池化层,
# 池化层将特征图降采样 2 倍。
# 因此总的降采样因子为 4。
downsample_factor = 4
# 数据集中任何验证码的最大长度
max_length = max([len(label) for label in labels])
"""
## 预处理
"""
# 将字符映射到整数
char_to_num = layers.StringLookup(vocabulary=list(characters), mask_token=None)
# 将整数映射回原始字符
num_to_char = layers.StringLookup(
vocabulary=char_to_num.get_vocabulary(), mask_token=None, invert=True
)
def split_data(images, labels, train_size=0.9, shuffle=True):
# 1. 获取数据集的总大小
size = len(images)
# 2. 创建索引数组并进行洗牌(如果需要)
indices = np.arange(size)
if shuffle:
np.random.shuffle(indices)
# 3. 获取训练样本的大小
train_samples = int(size * train_size)
# 4. 将数据分成训练集和验证集
x_train, y_train = images[indices[:train_samples]], labels[indices[:train_samples]]
x_valid, y_valid = images[indices[train_samples:]], labels[indices[train_samples:]]
return x_train, x_valid, y_train, y_valid
# 将数据集拆成训练集和验证集
x_train, x_valid, y_train, y_valid = split_data(np.array(images), np.array(labels))
def encode_single_sample(img_path, label):
# 1. 读取图片
img = tf.io.read_file(img_path)
# 2. 解码并转换为灰度图
img = tf.io.decode_png(img, channels=1)
# 3. 转为 [0, 1] 范围内的 float32 格式
img = tf.image.convert_image_dtype(img, tf.float32)
# 4. 调整大小到所需大小
img = tf.image.resize(img, [img_height, img_width])
# 5. 转置图片,因为我们希望时间维度对应于图片的宽度。
img = tf.transpose(img, perm=[1, 0, 2])
# 6. 将标签中的字符映射为数字
label = char_to_num(tf.strings.unicode_split(label, input_encoding="UTF-8"))
# 7. 因为我们的模型预期两个输入,所以返回一个字典
return {"image": img, "label": label}
"""
## 创建 `Dataset`(数据集)对象
"""
train_dataset = tf.data.Dataset.from_tensor_slices((x_train, y_train)) # 将训练集数据和标签转换为tensor slices并创建Dataset对象
train_dataset = (
train_dataset.map(encode_single_sample,
num_parallel_calls=tf.data.AUTOTUNE) # 对每个样本进行编码,使用tf.data.AUTOTUNE参数自动调整并行度
.batch(batch_size) # 将数据集分成batch_size大小的批次
.prefetch(buffer_size=tf.data.AUTOTUNE) # 在训练期间异步预取下一个批次,使用tf.data.AUTOTUNE参数自动设置缓冲区大小
)
validation_dataset = tf.data.Dataset.from_tensor_slices((x_valid, y_valid)) # 将验证集数据和标签转换为tensor slices并创建Dataset对象
validation_dataset = (
validation_dataset.map(encode_single_sample,
num_parallel_calls=tf.data.AUTOTUNE) # 对每个样本进行编码,使用tf.data.AUTOTUNE参数自动调整并行度
.batch(batch_size) # 将数据集分成batch_size大小的批次
.prefetch(buffer_size=tf.data.AUTOTUNE) # 在训练期间异步预取下一个批次,使用tf.data.AUTOTUNE参数自动设置缓冲区大小
)
"""
## 将数据可视化
在这段代码中,我们使用 plt.subplots() 创建了一个包含 4 行 4 列的图像网格。然后,我们使用 train_dataset.take(1) 从训练数据集中获取一个
batch,遍历其中的 16 张图像,并展示它们。
在展示每张图像之前,我们首先将图像转换为 numpy 数组,并使用 astype() 方法将浮点数数据类型转换为整数类型。这一步是因为 matplotlib要求图像数据
为整数。然后,我们将标签转换为字符串,并在每个字符之间插入空格。
最后,我们使用 imshow() 方法展示图像,并使用 set_title() 方法为其设置标签。我们使用 axis("off") 方法取消坐标轴的显示,以使图像更加美观。最
后,我们使用 plt.show() 方法展示生成的图像网格。
"""
# 生成4x4的图像网格
_, ax = plt.subplots(4, 4, figsize=(10, 5))
# 从训练数据集中取出一个batch
for batch in train_dataset.take(1):
# 获取该batch的图像和标签
images = batch["image"]
labels = batch["label"]
# 对16张图像进行遍历并展示
for i in range(16):
# 将图像转换为numpy数组,范围从0到1的浮点数,并乘以255来转换为0到255的整数
img = (images[i] * 255).numpy().astype("uint8")
# 将数字标签转换为字符串,并在每个字符之间插入空格
label = tf.strings.reduce_join(num_to_char(labels[i])).numpy().decode("utf-8")
# 展示图像并设置标题
# 使用第一维度(高度)与第二维度(宽度)的灰度值来绘制图像
ax[i // 4, i % 4].imshow(img[:, :, 0].T, cmap="gray")
ax[i // 4, i % 4].set_title(label)
ax[i // 4, i % 4].axis("off")
# 展示图像网格
plt.show()
"""
## 模型
"""
class CTCLayer(layers.Layer):
"""
这是一个自定义的损失函数层 CTCLayer 类。该类定义了 call() 方法,其中传递了两个参数:y_true 是真实标签,y_pred 是预测值。该损失函数的作
用是计算 CTC 损失函数。在训练时,计算损失值,并将其添加到层中。在测试时,直接返回预测值。
"""
def __init__(self, name=None):
super().__init__(name=name)
# 设置损失函数
self.loss_fn = keras.backend.ctc_batch_cost
def call(self, y_true, y_pred):
# 计算训练时的损失值并将其添加到层中 using `self.add_loss()`.
batch_len = tf.cast(tf.shape(y_true)[0], dtype="int64")
input_length = tf.cast(tf.sha
keras验证码识别完整案例
需积分: 0 198 浏览量
2023-06-11
10:44:32
上传
评论
收藏 10KB ZIP 举报
「已注销」
- 粉丝: 136
- 资源: 9
最新资源
- 农村信用社联合社计算机信息系统投产与变更管理办.docx
- 农村信用社联合社计算机信息系统数据管理办法.docx
- 利用SPSS作临床效度分析线上计算网站介绍-医学研究部统计谘.(医学PPT课件).ppt
- 利用Zabbix监控mysqldump定时备份数据库状态.docx
- 利用计算机解决问题的基本过程.doc
- 化工铁路通信工程总结.doc
- 北京大学网络教育软件工程作业.docx
- 医药公司(连锁店)计算机操作规程未新系统的自行按照旧制修改-新系统过制的编号加修模版.doc
- 医药公司(连锁店)计算机系统操作规程模版.doc
- 医药连锁门店计算机系统的操作和管理程序未新系统的自行按照旧制修改-新系统过制的编号加修模版.docx
资源上传下载、课程学习等过程中有任何疑问或建议,欢迎提出宝贵意见哦~我们会及时处理!
点击此处反馈