这篇文章主要是使用vgg16网络实现验证码的自动识别:
(1) captcha库
这个库可以自动生成验证码,生成验证码的代码如下:
from captcha.image import ImageCaptcha
from PIL import Image
import matplotlib.pyplot as plt
import numpy as np
number = [str(i) for i in range(10)]
alphabet = [chr(i+ord('a')) for i in range(26)]
ALPHABET = [chr(i+ord('A')) for i in range(26)]
captcha_content = number+alphabet+ALPHABET
def gen_captcha(captcha_content,captcha_len=4):
# captcha_content 构成验证码的字符list
# captcha_len 验证码的长度
captcha_str = np.random.choice(captcha_content,captcha_len)
imageCaptcha = ImageCaptcha()
captcha = imageCaptcha.generate(captcha_str)
captcha = Image.open(captcha)
captcha = np.array(captcha)
return captcha,captcha_str
if __name__ == '__main__':
captcha, captcha_str = gen_captcha(captcha_content, captcha_len=4)
fig = plt.figure()
ax = fig.add_subplot(111)
ax.set_title(captcha_str)
ax.imshow(captcha)
plt.show()
生成效果如下:
(2) 定义验证码识别的模型
import numpy as np
import tensorflow as tf
#image_size = [60,160,3]
def captcha_model(image_size,cap_size,input_data):
with tf.name_scope('preprocess'):
img_mean = tf.constant([123.68, 116.779, 103.939],tf.float32,shape=[1,1,1,3],name='img_mean')
input_net = input_data - img_mean
with tf.variable_scope('conv1') as scope:
conv1_1 = tf.layers.conv2d(input_net,64,[3,3],[1,1],padding='same',activation=tf.nn.relu,kernel_initializer=tf.truncated_normal_initializer(stddev=0.01),bias_initializer=tf.zeros_initializer(),name='conv1_1')
conv1_2 = tf.layers.conv2d(conv1_1, 64, [3, 3], [1,1], padding='same', activation=tf.nn.relu,kernel_initializer=tf.truncated_normal_initializer(stddev=0.01), name='conv1_2')
pool1_1 = tf.layers.max_pooling2d(conv1_2,[2,2],[2,2],'same',name='conv1_pool')
with tf.variable_scope('conv2') as scope:
conv2_1 = tf.layers.conv2d(pool1_1,128,[3,3],[1,1],padding='same',activation=tf.nn.relu,kernel_initializer=tf.truncated_normal_initializer(stddev=0.01),bias_initializer=tf.zeros_initializer(),name='conv2_1')
conv2_2 = tf.layers.conv2d(conv2_1, 128, [3, 3], [1, 1], padding='same', activation=tf.nn.relu,kernel_initializer=tf.truncated_normal_initializer(stddev=0.01),bias_initializer=tf.zeros_initializer(), name='conv2_2')
pool2_1 = tf.layers.max_pooling2d(conv2_2, [2, 2], [2, 2], 'same', name='conv2_pool')
with tf.variable_scope('conv3') as scope:
conv3_1 = tf.layers.conv2d(pool2_1,256,[3,3],[1,1],padding='same',activation=tf.nn.relu,kernel_initializer=tf.truncated_normal_initializer(stddev=0.01),bias_initializer=tf.zeros_initializer(),name='conv3_1')
conv3_2 = tf.layers.conv2d(conv3_1, 256, [3, 3], [1, 1], padding='same', activation=tf.nn.relu,kernel_initializer=tf.truncated_normal_initializer(stddev=0.01),bias_initializer=tf.zeros_initializer(), name='conv3_2')
conv3_3 = tf.layers.conv2d(conv3_2, 256, [3, 3], [1, 1], padding='same', activation=tf.nn.relu,kernel_initializer=tf.truncated_normal_initializer(stddev=0.01),bias_initializer=tf.zeros_initializer(), name='conv3_3')
pool3_1 = tf.layers.max_pooling2d(conv3_3, [2, 2], [2, 2], 'same', name='conv3_pool')
with tf.variable_scope('conv4') as scope:
conv4_1 = tf.layers.conv2d(pool3_1,512,[3,3],[1,1],padding='same',activation=tf.nn.relu,kernel_initializer=tf.truncated_normal_initializer(stddev=0.01),bias_initializer=tf.zeros_initializer(),name='conv4_1')
conv4_2 = tf.layers.conv2d(conv4_1, 512, [3, 3], [1, 1], padding='same', activation=tf.nn.relu,kernel_initializer=tf.truncated_normal_initializer(stddev=0.01),bias_initializer=tf.zeros_initializer(), name='conv4_2')
conv4_3 = tf.layers.conv2d(conv4_2, 512, [3, 3], [1, 1], padding='same', activation=tf.nn.relu,kernel_initializer=tf.truncated_normal_initializer(stddev=0.01),bias_initializer=tf.zeros_initializer(), name='conv4_3')
pool4_1 = tf.layers.max_pooling2d(conv4_3, [2, 2], [2, 2], 'same', name='conv4_pool')
with tf.variable_scope('conv5') as scope:
conv5_1 = tf.layers.conv2d(pool4_1,512,[3,3],[1,1],padding='same',activation=tf.nn.relu,kernel_initializer=tf.truncated_normal_initializer(stddev=0.01),bias_initializer=tf.zeros_initializer(),name='conv5_1')
conv5_2 = tf.layers.conv2d(conv5_1, 512, [3, 3], [1, 1], padding='same', activation=tf.nn.relu,kernel_initializer=tf.truncated_normal_initializer(stddev=0.01),bias_initializer=tf.zeros_initializer(), name='conv5_2')
conv5_3 = tf.layers.conv2d(conv5_2, 512, [3, 3], [1, 1], padding='same', activation=tf.nn.relu,kernel_initializer=tf.truncated_normal_initializer(stddev=0.01),bias_initializer=tf.zeros_initializer(), name='conv5_3')
pool5_1 = tf.layers.max_pooling2d(conv5_3, [2, 2], [2, 2], 'same', name='conv4_pool')
with tf.variable_scope('fc') as scope:
#flat = tf.layers.flatten(pool5_1)
flat = tf.reshape(pool5_1,shape=[-1,5120])
fc1 = tf.layers.dense(flat,1024,name='fc1',kernel_initializer=tf.truncated_normal_initializer(stddev=0.01),bias_initializer=tf.zeros_initializer(),activation=tf.nn.relu)
fc2 = tf.layers.dense(fc1, 512,kernel_initializer=tf.truncated_normal_initializer(stddev=0.01),bias_initializer=tf.zeros_initializer(),name='fc2')
logits = tf.layers.dense(fc2,cap_size,name='fc3',activation=None)
return logits
定义数据生成py文件:
from captcha.image import ImageCaptcha
from PIL import Image
import matplotlib.pyplot as plt
import numpy as np
def gen_captcha(captcha_content,captcha_len=4):
# captcha_content 构成验证码的字符list
# captcha_len 验证码的长度
captcha_str = np.random.choice(captcha_content,captcha_len)
imageCaptcha = ImageCaptcha()
captcha = imageCaptcha.generate(captcha_str)
captcha = Image.open(captcha)
captcha = np.array(captcha)
return captcha,captcha_str
def gen_batch(batch_size,image_size,captcha_content,str_to_int,captcha_len=4):
x_train = np.zeros([batch_size,*image_size])
y_ture = np.zeros([batch_size,captcha_len])
while True:
for i in range(batch_size):
xs,ys = gen_captcha(captcha_content,captcha_len)
x_train[i,:,:,:] = xs
y_ture[i,:] = np.array([str_to_int[i] for i in ys])
yield x_train,y_ture
定义训练py文件:
from model import captcha_model
from utils import gen_batch,build_dict_str_int
import tensorflow as tf
import numpy as np
number = [str(i) for i in range(10)]
alphabet = [chr(i+ord('a')) for i in range(26)]
ALPHABET = [chr(i+ord('A')) for i in range(26)]
image_size = [60,160,3]
lr = 0.001
epochs = 100
batch_size = 64
captcha_content = number
captcha_len = 4
captcha_size = len(captcha_content)
cap_size = captcha_size*captcha_len
str_to_int,int_to_str = build_dict_str_int(captcha_content)
input_data = tf.placeholder(dtype=tf.float32, shape=[None, *image_size], name='input_data')
label = tf.placeholder(dtype=tf.int32, shape=[None, captcha_len])
logits = captcha_model(image_size,cap_size,input_data)
y_true_one = tf.one_hot(indices=label,depth=captcha_size,axis=2,name='one_hot')
re_y_true = tf.reshape(y_true_one,shape=[batch_size,-1])
loss = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(logits=logits,labels=re_y_true))
optimizer = tf.train.AdamOptimizer(lr).minimize(loss)
y_pre = tf.argmax(tf.reshape(logits,[-1,captcha_len,captcha_size]),2)
y_true = tf.argmax(y_true_one,2)
accuracy = tf.reduce_mean(tf.cast(tf.equal(y_pre,y_true),tf.float32))
with tf.Session() as sess:
sess.run(tf.global_variables_initializer())
writer = tf.summary.FileWriter('./graph/crack_capcha',sess.graph)
saver = tf.train.Saver()
gen_data = gen_batch(batch_size,image_size,captcha_content,str_to_int,captcha_len)
epoch = 0
while True:
#for epoch in range(epochs):
xs, ys = next(gen_data)
_,train_loss,train_acc = sess.run([optimizer,loss,accuracy],feed_dict={input_data:xs,label:ys})
if epoch % 10 == 0:
print('Epochs {}/{} train_acc {},train_loss {}'.format(epoch,epochs,train_acc,train_loss))
#saver.save(sess, "./model/crack_capcha.model", global_step=epoch)
if train_acc > 0.9:
saver.save(sess, "./model/crack_capcha.model", global_step=epoch)
break
epoch += 1
writer.close()
训练时间可能比较长,耐心等待