(见https://blog.csdn.net/diOSyu/article/details/98758877)
验证码生成配置文件
yes
105,179,90
red
180
60
40
4
宋体,楷体,微软雅黑
1234567890
black
com.google.code.kaptcha.impl.WaterRipple
com.google.code.kaptcha.impl.DefaultNoise
2
生成验证码接口
package com.demo.controller;
import com.google.code.kaptcha.Constants;
import com.google.code.kaptcha.Producer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.imageio.ImageIO;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.awt.image.BufferedImage;
@Controller
public class CaptchaController {
@Autowired
private Producer captchaProducer = null;
@RequestMapping("/kaptcha/{capText}")
public void getKaptchaImage(@PathVariable("capText") String capText, HttpServletRequest request, HttpServletResponse response) throws Exception {
HttpSession session = request.getSession();
response.setDateHeader("Expires", 0);
response.setHeader("Cache-Control", "no-store, no-cache, must-revalidate");
response.addHeader("Cache-Control", "post-check=0, pre-check=0");
response.setHeader("Pragma", "no-cache");
response.setContentType("image/jpeg");
//生成验证码
if (capText == null || capText.length() != 4) {
capText = captchaProducer.createText();
}
System.out.println("验证码是:");
System.out.println(capText);
session.setAttribute(Constants.KAPTCHA_SESSION_KEY, capText);
//向客户端写出
BufferedImage bi = captchaProducer.createImage(capText);
ServletOutputStream out = response.getOutputStream();
ImageIO.write(bi, "jpg", out);
try {
out.flush();
} finally {
out.close();
}
}
}
# -*- coding:utf-8 -*-
from random import choice
from PIL import Image
import requests
import numpy as np
from config import *
import pickle
from preprocess import text2vec
def get_random_text():
_text = ''
for _i in range(CAPTCHA_LENGTH):
_text += choice(VOCAB)
return _text
def get_one_image(_text):
_url = 'http://localhost:8080/kaptcha/' + _text
r = requests.get(_url, stream=True)
r.raise_for_status()
return r.raw
def generate_captcha(_text):
image = Image.open(get_one_image(_text)).convert('RGB')
data = image.load()
for y in range(IMAGE_HEIGHT):
for x in range(IMAGE_WIDTH):
r, g, b = data[x, y]
if r > 10 and b < 170 and g < 170 and r - g > 20 and r - b > 20:
data[x, y] = (0, 0, 0)
else:
data[x, y] = (255, 255, 255)
image_l = image.convert('L')
image_array = np.array(image_l)
return image_array
def generate_data():
print('Generating Data...')
data_x, data_y = [], []
# generate data x and y
for i in range(30000):
text = get_random_text()
# get captcha array
captcha_array = generate_captcha(text)
# get vector
vector = text2vec(text)
data_x.append(captcha_array)
data_y.append(vector)
if i % 100 == 0:
print(i)
x = np.asarray(data_x, np.float32)
y = np.asarray(data_y, np.float32)
with open('./data/data.pkl', 'wb') as f:
pickle.dump(x, f)
pickle.dump(y, f)
def main():
generate_data()
if __name__ == '__main__':
main()
preprocess.py
# -*- coding:utf-8 -*-
from numpy import zeros, reshape, argmax
from config import *
# 将名字转为向量
def text2vec(_text):
_vector = zeros(OUTPUT_LENGTH)
for i, c in enumerate(_text):
idx = i * VOCAB_LENGTH + VOCAB.index(c)
_vector[idx] = 1
return _vector
# 将向量转为名字
def vec2text(_vector):
_vector = reshape(_vector, [CAPTCHA_LENGTH, -1])
text = [VOCAB[argmax(i)] for i in _vector]
return ''.join(text)
config.py
# 字符表
VOCAB = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']
# 字符表长度
VOCAB_LENGTH = len(VOCAB)
# 4位验证码
CAPTCHA_LENGTH = 4
# 验证码宽度
IMAGE_WIDTH = 180
# 验证码长度
IMAGE_HEIGHT = 60
# 输入长度
INPUT_LENGTH = IMAGE_WIDTH * IMAGE_HEIGHT
# 输出长度
OUTPUT_LENGTH = VOCAB_LENGTH * CAPTCHA_LENGTH
main.py
# -*-coding:utf-8 -*-
from preprocess import vec2text
from numpy import zeros
from random import randint
from config import *
import tensorflow as tf
import pickle
"""
全局变量
"""
with open('./data/data.pkl', 'rb') as f:
DATA_X = pickle.load(f)
DATA_Y = pickle.load(f)
DATA_LENGTH = len(DATA_X)
X = tf.placeholder(tf.float32, [None, INPUT_LENGTH])
Y = tf.placeholder(tf.float32, [None, OUTPUT_LENGTH])
keep_prob = tf.placeholder(tf.float32)
"""
函数
"""
# 得到文件名和图像
def get_vector_and_image():
i = randint(0, DATA_LENGTH - 1)
return DATA_Y[i], DATA_X[i]
# 生成一个训练batch
def get_next_batch(batch_size=64):
_batch_x = zeros([batch_size, INPUT_LENGTH])
_batch_y = zeros([batch_size, OUTPUT_LENGTH])
for i in range(batch_size):
vector, image = get_vector_and_image()
_batch_x[i, :] = image.flatten()
_batch_y[i, :] = vector
return _batch_x, _batch_y
# 定义CNN
def inference(w_alpha=0.01, b_alpha=0.1):
_num_channels = 1
_conv1_deep = 32
_conv2_deep = 64
_conv3_deep = 64
_fc_size = 1024
x = tf.reshape(X, shape=[-1, IMAGE_HEIGHT, IMAGE_WIDTH, 1])
# 3 conv layer
_conv1_size = 3
w_c1 = tf.Variable(w_alpha * tf.random_normal([_conv1_size, _conv1_size, _num_channels, _conv1_deep]))
b_c1 = tf.Variable(b_alpha * tf.random_normal([_conv1_deep]))
conv1 = tf.nn.conv2d(x, w_c1, strides=[1, 1, 1, 1], padding='SAME')
conv1 = tf.nn.relu(tf.nn.bias_add(conv1, b_c1))
conv1 = tf.nn.max_pool(conv1, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding="SAME")
conv1 = tf.nn.dropout(conv1, keep_prob)
_conv2_size = 3
w_c2 = tf.Variable(w_alpha * tf.random_normal([_conv2_size, _conv2_size, _conv1_deep, _conv2_deep]))
b_c2 = tf.Variable(b_alpha * tf.random_normal([_conv2_deep]))
conv2 = tf.nn.conv2d(conv1, w_c2, strides=[1, 1, 1, 1], padding='SAME')
conv2 = tf.nn.relu(tf.nn.bias_add(conv2, b_c2))
conv2 = tf.nn.max_pool(conv2, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='SAME')
conv2 = tf.nn.dropout(conv2, keep_prob)
_conv3_size = 3
w_c3 = tf.Variable(w_alpha * tf.random_normal([_conv3_size, _conv3_size, _conv2_deep, _conv3_deep]))
b_c3 = tf.Variable(b_alpha * tf.random_normal([_conv3_deep]))
conv3 = tf.nn.conv2d(conv2, w_c3, strides=[1, 1, 1, 1], padding='SAME')
conv3 = tf.nn.relu(tf.nn.bias_add(conv3, b_c3))
conv3 = tf.nn.max_pool(conv3, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='SAME')
conv3 = tf.nn.dropout(conv3, keep_prob)
#
pool_shape = conv3.get_shape().as_list()
nodes = pool_shape[1] * pool_shape[2] * pool_shape[3]
# Fully connected layer
w_d = tf.Variable(w_alpha * tf.random_normal([nodes, _fc_size]))
b_d = tf.Variable(b_alpha * tf.random_normal([_fc_size]))
dense = tf.reshape(conv3, [-1, nodes])
dense = tf.nn.relu(tf.add(tf.matmul(dense, w_d), b_d))
dense = tf.nn.dropout(dense, keep_prob)
w_out = tf.Variable(w_alpha * tf.random_normal([_fc_size, OUTPUT_LENGTH]))
b_out = tf.Variable(b_alpha * tf.random_normal([OUTPUT_LENGTH]))
out = tf.add(tf.matmul(dense, w_out), b_out)
return out
# 训练
def train():
# 局部变量
_learning_rate = 0.001
_acc = 0.99
# 定义前向传播
o = inference()
loss = tf.reduce_mean(tf.nn.sigmoid_cross_entropy_with_logits(logits=o, labels=Y))
train_op = tf.train.AdamOptimizer(learning_rate=_learning_rate).minimize(loss)
# 计算正确率
max_index_logits = tf.argmax(tf.reshape(o, [-1, CAPTCHA_LENGTH, VOCAB_LENGTH]), 2)
max_index_labels = tf.argmax(tf.reshape(Y, [-1, CAPTCHA_LENGTH, VOCAB_LENGTH]), 2)
correct_predict = tf.equal(max_index_logits, max_index_labels)
accuracy = tf.reduce_mean(tf.cast(correct_predict, tf.float32))
# 训练
saver = tf.train.Saver()
with tf.Session() as sess:
# 初始化变量
sess.run(tf.global_variables_initializer())
step = 1
while True:
batch_x, batch_y = get_next_batch(128)
# _, loss_ = sess.run([train_op, loss], feed_dict={X: batch_x, Y: batch_y, keep_prob: 0.5})
sess.run(train_op, feed_dict={X: batch_x, Y: batch_y, keep_prob: 0.5})
# 每100 step计算一次准确率
if step % 100 == 0:
batch_x_test, batch_y_test = get_next_batch(256)
acc = sess.run(accuracy, feed_dict={X: batch_x_test, Y: batch_y_test, keep_prob: 1.})
print('Step =', step, ', Accuracy =', acc)
# 如果准确率大于50%,保存模型,完成训练
if acc > _acc:
saver.save(sess, "./captcha.model", global_step=step)
break
step += 1
def test():
_test_num = 100
test_x = DATA_X[:_test_num]
test_y = DATA_Y[:_test_num]
output = inference()
saver = tf.train.Saver()
wrong_num = 0
with tf.Session() as sess:
saver.restore(sess, tf.train.latest_checkpoint('./'))
for i in range(_test_num):
text = vec2text(test_y[i])
image = test_x[i].flatten()
out = sess.run(output, feed_dict={X: [image], keep_prob: 1})
predict_text = vec2text(out[0])
print("正确: {} 预测: {} {}".format(text, predict_text, text == predict_text))
if text != predict_text:
wrong_num += 1
print(wrong_num, '/', _test_num)
def main():
# 训练模型
train()
# 测试模型
# test()
if __name__ == '__main__':
main()
main.py先运行train函数,输出如下:
Step = 100 , Accuracy = 0.09863281
Step = 200 , Accuracy = 0.8125
Step = 300 , Accuracy = 0.99121094
Process finished with exit code 0
main.py生成模型后, 注视了train函数,运行test函数, 输出如下:
正确: 3118 预测: 1110 False
正确: 9753 预测: 9753 True
正确: 8838 预测: 8838 True
正确: 9718 预测: 9718 True
正确: 4615 预测: 4615 True
正确: 7017 预测: 7017 True
正确: 7693 预测: 7693 True
正确: 7362 预测: 7362 True
正确: 6405 预测: 6405 True
正确: 5032 预测: 5032 True
1 / 10
Process finished with exit code 0