基于Tensorflow的验证码识别

最近在入门机器学习,本文作为入门阶段的 "Hello World",旨在学习一些Tensorflow的API和机器学习概念。

步骤

  1. 采集验证码图片
  2. 处理图片:灰度、去噪、分割
  3. 分类图片,准备训练数据:将0-9数字图片放入对应文件夹,转化成数据
  4. 编写训练模型
  5. 调用模型,形成识别系统

采集验证码图片

随便找一个需要输入图像验证码的网页,最好先简单一点的只有数字的,并且人眼识别也比较容易的。

这步比较简单,关键是去网页上识别验证码接口url,然后按照一些网上教程写个简单的Python程序抓取那些图片。python实现简单爬虫功能

处理图片

电脑装不上PIL,所以只能使用Java去处理,言语只是工具,注重方法。对图片进行灰度、去噪、分割处理。

灰度化

灰度处理是指将彩色图片转化成只有黑白灰色。

每个像素点有Red、Green、Blue三种颜色组成,每个分量用数字0-255表示(十六进制:0x00 - 0xff),当三个分量(RGB)一样时表现出来就是灰度色(白色RGB(255, 255, 255), 黑色RGB(0, 0, 0))。

所以,灰度化是将三分量转化成一样数值的过程

公式如下:

int gray = (int) (0.3 * r + 0.59 * g + 0.11 * b);

再使用二值法将图片色彩转化成非黑即白,可以过滤一些感染的噪音,因为人眼在识别验证码时也会自动过滤掉一些颜色比较淡的点或者色块图形。

如上图,我们只会关注中间颜色比较深的数字而一些背景淡色小字会被过滤掉。

gray = gray < 127 ? 0 : 255;

去噪处理

这里处理比较简陋,就是遍历所有图片中的像素点,如果这个点附近N个点(相邻的一共有8个点)颜色是白色,那么我们判定该是噪音点,将其颜色也设置为白色,这里我设置 N=8。

结合上面二值化处理后效果如下:

分割图片

比较恶的一步,因为数字旋转和字体大小不一所以宽度不定,而且还有重叠。

处理步骤:

  1. 扫描出每个数字左右边界,即找到最左最右的点
  2. 根据这个边界进行横向裁剪
  3. 如果发现最后裁剪出来不是4个数字而是3个或者更少,查看是否存在某个裁剪块的宽度比一般的要大,然后进行平均分割
  4. 对每个裁剪下来的图片再进行纵向裁剪,将上下多余的空白区裁剪掉

效果如下:

分类图片,准备训练数据

创建10个文件夹,命名为0、1、2.... 9,将裁剪后数字图片分类到那些文件夹中。

将图片转化为向量数据,形如:

0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,....

如果规定图片大小为36*36,那么该向量长度为1296。(数字表示该点的颜色,0为白色,1为黑色)

然后再需要一个标签数据

[1, 0, 0, 0, 0, 0, 0, 0, 0, 0]  // 表示0
[0, 0, 0, 0, 0, 1, 0, 0, 0, 0]  // 表示5

一条数据有10位,每个位置分别表示0到9

编写训练模型

刚开始只使用SVM做多分类,感觉有点复杂毕竟需要训练那么多组模型参数,所以放弃。后来单纯使用softmax训练,训练数据大概在1500左右,正确率在55%左右,可能需要更多的训练数据效果会好点,最后参照MNIST使用CNN去训练,同样的训练数据正确率达到80%左右,如果训练数据达到10000以上的话估计会更高(MNIST识别手写准确率在98%左右)。

CNN

TF提供2维卷积函数

tf.nn.conv2d(x, W, strides=[1, 1, 1, 1], padding='SAME')

x是输入;W是卷积参数如[5,5,1,32],5*5是卷积核大小;第三个参数表示channel,这里因为是灰度所以是1,彩色的话是3;第四个参数表示卷积核的数量,即提取多少特征;strides是移动步长都是1表示遍历每个点;padding参数指定边界处理方式,“SAME”表示输入输出保持一样。

除此之外,还需要池化函数(降采样,将2x2降为1x1提取最显著的特征),这里使用最大池化max_pooling

tf.nn.max_pool(x, ksize=[1,2,2,1], strides=[1,2,2,1], padding='SAME')

x是输入;ksize表示使用2x2池化,即将2x2的色块降为1x1,最大池化会保留灰度值最高的那个像素点;因为需要整体缩小图片所以这里strides在横向纵向的步长都为2。

构建处理层

这里还加入了dropout防止过拟合。

def weight_variable(shape, name):
    initial = tf.truncated_normal(shape, stddev=0.1)
    return tf.Variable(initial, name=name)

def bias_variable(shape, name):
    initial = tf.constant(0.1, shape=shape)
    return tf.Variable(initial, name=name)

def conv2d(x, W):
    # stride [1, x_movement, y_movement, 1]
    return tf.nn.conv2d(x, W, strides=[1, 1, 1, 1], padding='SAME')

def max_pool_2x2(x):
    # stride [1, x_movement, y_movement, 1]
    return tf.nn.max_pool(x, ksize=[1,2,2,1], strides=[1,2,2,1], padding='SAME')

#define weights & biases
weights = {
    "h1": weight_variable([5, 5, 1, 32], "w_h1"),
    "h2": weight_variable([5, 5, 32, 64], "w_h2"),
    "f1": weight_variable([9*9*64, 1024], "w_f1"),
    "f2": weight_variable([1024, 10], "w_f2")
}

biases = {
    "h1": bias_variable([32], "b_h1"),
    "h2": bias_variable([64], "b_h2"),
    "f1": bias_variable([1024], "b_f1"),
    "f2": bias_variable([10], "b_f2")
}

x_image = tf.reshape(xs, [-1, 36, 36, 1]) # [n_samples, 28,28,1]

## conv1 layer ##
W_conv1 = weights["h1"] # patch 5x5, in size 1, out size 32
b_conv1 = biases["h1"]
h_conv1 = tf.nn.relu(conv2d(x_image, W_conv1) + b_conv1) # output size 36x36x32
h_pool1 = max_pool_2x2(h_conv1)                          # output size 18x18x32

## conv2 layer ##
W_conv2 = weights["h2"] # patch 5x5, in size 32, out size 64
b_conv2 = biases["h2"]
h_conv2 = tf.nn.relu(conv2d(h_pool1, W_conv2) + b_conv2) # output size 18x18x64
h_pool2 = max_pool_2x2(h_conv2)                          # output size 9x9x64

## fc1 layer ##
W_fc1 = weights["f1"]
b_fc1 = biases["f1"]
# [n_samples, 9, 9, 64] ->> [n_samples, 9*9*64]
h_pool2_flat = tf.reshape(h_pool2, [-1, 9*9*64])
h_fc1 = tf.nn.relu(tf.matmul(h_pool2_flat, W_fc1) + b_fc1)
h_fc1_drop = tf.nn.dropout(h_fc1, keep_prob)

## fc2 layer ##
W_fc2 = weights["f2"]
b_fc2 = biases["f2"]
prediction = tf.nn.softmax(tf.matmul(h_fc1_drop, W_fc2) + b_fc2)

定义Loss和Optimizer

cross_entropy = tf.reduce_mean(-tf.reduce_sum(ys * tf.log(prediction),
                                                  reduction_indices=[1]))       # loss
train_step = tf.train.AdamOptimizer(1e-4).minimize(cross_entropy)

使用交叉熵作为Loss函数,优化器使用Adam,这些TF都有提供。

执行训练

for i in range(150):
        sess.run(train_step, feed_dict={xs: datas, ys: labels, keep_prob: 0.5})

执行150个迭代,这里有个需要优化的地方,datas可以每次选取其中部分训练数据而不是全量的训练,这样速度会快一点。

计算正确率

#y_pre 是每个数据对应各个类别(0-9)的概率如[[0.1,0.2,0.3,0.4...],[0.2,0.1,0.9....]]
y_pre = sess.run(prediction, feed_dict={xs: test_datas, keep_prob: 1})
#tf.argmax返回最大数的索引,再比较预测数据索引和测试数据真实索引
correct_prediction = tf.equal(tf.argmax(y_pre,1), tf.argmax(test_labels,1))
#将上面比较结果True转为1,False转为0,相加计算平均值
accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))
result = sess.run(accuracy)

使用测试数据test_datas和测试数据对应的标签test_labels进行检验。

调用模型

上面已经执行训练了,当训练完成时可以保存模型,这样在使用模型时可以直接恢复然后调用,不用重新训练。

保存模型

saver = tf.train.Saver()
save_path = saver.save(sess, "./models/save_net.ckpt")

恢复模型

saver = tf.train.Saver()
saver.restore(sess, "./final_models/save_net.ckpt")

总结

代码等整理完成后会发布到github上,仓库地址在后续会贴出来。

如有不准确或者任何好的建议都可以提出来,谢谢!

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏数据科学学习手札

(数据科学学习手札08)系统聚类法的Python源码实现(与Python,R自带方法进行比较)

聚类分析是数据挖掘方法中应用非常广泛的一项,而聚类分析根据其大体方法的不同又分为系统聚类和快速聚类,其中系统聚类的优点是可以很直观的得到聚类数不同时具体类中包括...

2705
来自专栏机器之心

资源 | Feature Tools:可自动构造机器学习特征的Python库

机器学习越来越多地从人工设计模型转向使用 H20、TPOT 和 auto-sklearn 等工具自动优化的工具。这些库以及随机搜索(参见《Random Sear...

1532
来自专栏AI科技大本营的专栏

课程 |《深度学习原理与TensorFlow实践》学习笔记(二)

作者 | 王清 TensorFlow基础使用 环境准备 TensorFlow安装 常用Python库介绍 实例解析 Kaggle平台及Titanic题目介绍 代...

3958
来自专栏人工智能LeadAI

谈谈Tensorflow的dropout

Dropout这个概念已经推出4年了,它的详细描述见论文(https://arxiv.org/abs/1207.0580)。可是呢,它仿佛是个犹抱琵琶半遮面的美...

3467
来自专栏专知

【干货】用PyTorch进行RNN语言建模 - Packed Batching和Tied Weight

【导读】PyTorch是一个日益流行的神经网络框架,自然支持RNN。但是关于RNN,Pytorch的官方教程描述的不怎么详细,这篇文章将介绍使用Pytorch实...

5132
来自专栏Python小屋

Python扩展库scipy中值滤波算法的应用

中值滤波是数字信号处理、数字图像处理中常用的预处理技术,特点是将信号中每个值都替换为其邻域内的中值,即邻域内所有值排序后中间位置上的值。下面的代码演示了scip...

4546
来自专栏机器之心

资源 | 让手机神经网络速度翻倍:Facebook开源高性能内核库QNNPACK

为了将最新的计算机视觉模型部署到移动设备中,Facebook 开发了一个用于低密度卷积的优化函数库——QNNPACK,用在最佳神经网络中。

1404
来自专栏专知

Github上一些精致且实用的TensorFlow项目及相关论文

【导读】Github上有许多成熟的TensorFlow代码和模型,可以直接用于科研和工程中。本文会介绍其中一些与自动问答、机器翻译、风格转换等相关的精致且实用的...

1443
来自专栏奇点大数据

可自动构造机器学习特征的Python库

机器学习越来越多地从人工设计模型转向使用 H20、TPOT 和 auto-sklearn 等工具自动优化的工具。这些库以及随机搜索(参见《Random Sear...

1473
来自专栏iOSDevLog

Python机器学习:Scikit-Learn教程

一个易于理解的scikit-learn教程,可以帮助您开始使用Python机器学习。

5275

扫码关注云+社区

领取腾讯云代金券