验证码识别--基于tensorflow和CNN

 

captchaIdentify.py   


#导入验证码生成的包
A captcha library that generates audio and image CAPTCHAs.
CAPTCHA项目是Completely Automated Public Turing Test to Tell Computers and Humans Apart (全自动区分计算机和人类的图灵测试)的简称,卡内基梅隆大学试图将其注册为商标,但2008年请求被驳回。 CAPTCHA的目的是区分计算机和人类的一种程序算法,是一种区分用户是计算机和人的计算程序,这种程序必须能生成并评价人类能很容易通过但计算机却通不过的测试。

# -*- coding: utf-8 -*-
"""
Created on Sun Feb 24 09:03:05 2019

@author: Administrator
"""
import tensorflow as tf
import numpy as np
import matplotlib.pyplot as plt
from PIL import Image
import random
from captcha.image import ImageCaptcha
number=['0','1','2','3','4','5','6','7','8','9']
alphabet=['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']
ALPHABET=['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']

#%%
def random_captcha_text(char_set=number+alphabet+ALPHABET,captcha_size=4):
    captcha_text=[]
    for i in range(captcha_size):
        c=random.choice(char_set)
        captcha_text.append(c)
    return captcha_text
def gen_captcha_text_and_image():
    image=ImageCaptcha()
    
    captcha_text=random_captcha_text()
    captcha_text=''.join(captcha_text)
    
    captcha=image.generate(captcha_text)
    captcha_image=Image.open(captcha)
    captcha_image=np.array(captcha_image)
    return captcha_text,captcha_image

    

#%%
if __name__=='__main__':
    text,image=gen_captcha_text_and_image()
    
    f=plt.figure()
    ax=f.add_subplot(111)
    ax.text(.1,.9,text,ha='center',va='center',transform=ax.transAxes)
    plt.imshow(image)



生成效果如下: 

 

onlynumber.py

 

# -*- coding: utf-8 -*-
"""
Created on Sun Feb 24 09:46:47 2019

@author: Administrator
"""
import tensorflow as tf
import numpy as np
import matplotlib.pyplot as plt
from PIL import Image
import random
from captcha.image import ImageCaptcha
number=['0','1','2','3','4','5','6','7','8','9']
#alphabet=['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']
#ALPHABET=['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']

#%%
#%%
def random_captcha_text(char_set=number,captcha_size=4):
    '生成验证码文本'
    captcha_text=[]
    for i in range(captcha_size):
        c=random.choice(char_set)
        captcha_text.append(c)
    return captcha_text
def gen_captcha_text_and_image():
    '调用random_captcha_text,生成验证码的文本,并产生相应文本的验证码图片,返回值:(验证码label, 验证码图片)'
    image=ImageCaptcha()
    
    captcha_text=random_captcha_text()
    captcha_text=''.join(captcha_text)
    
    captcha=image.generate(captcha_text)
    captcha_image=Image.open(captcha)
    captcha_image=np.array(captcha_image)
    return captcha_text,captcha_image
#%%
def convert2gray(img):
    '将图像转换为灰度图'
    if len(img.shape)>2:
        gray=np.mean(img,axis=-1)
        return gray
    else:
        return img
def text2vec(text):
    '将验证码文本转换为向量'
    '此处可以优化,使用onthot编码charset即可,见sklearn中preprocessing中的相应方法'
    text_len=len(text)
    if text_len>MAX_CAPTCHA:
        raise ValueError('验证码最长4个字符')
    vector=np.zeros(MAX_CAPTCHA*CHAR_SET_LEN)
    for i,c in enumerate(text):
        idx=i*CHAR_SET_LEN+int(c)
        vector[idx]=1
    return vector
#%%

#%%
def vec2text(vec):  
    """
    char_pos = vec.nonzero()[0]  
    text=[]  
    for i, c in enumerate(char_pos):  
        char_at_pos = i #c/63  
        char_idx = c % CHAR_SET_LEN  
        if char_idx < 10:  
            char_code = char_idx + ord('0')  
        elif char_idx <36:  
            char_code = char_idx - 10 + ord('A')  
        elif char_idx < 62:  
            char_code = char_idx-  36 + ord('a')  
        elif char_idx == 62:  
            char_code = ord('_')  
        else:  
            raise ValueError('error')  
        text.append(chr(char_code)) 
    """
    text=[]
    char_pos = vec.nonzero()[0]
    for i, c in enumerate(char_pos):  
        number = i % 10
        text.append(str(number)) 
             
    return "".join(text)  
   
""" 
#向量(大小MAX_CAPTCHA*CHAR_SET_LEN)用0,1编码 每63个编码一个字符,这样顺利有,字符也有 
vec = text2vec("F5Sd") 
text = vec2text(vec) 
print(text)  # F5Sd 
vec = text2vec("SFd5") 
text = vec2text(vec) 
print(text)  # SFd5 
"""  
#%%
def gen_next_batch(batch_size=128):
    '生成下一批次的训练数据'
    batch_x=np.zeros([batch_size,IMAGE_HEIGHT*IMAGE_WIDTH])
    batch_y=np.zeros([batch_size,MAX_CAPTCHA*CHAR_SET_LEN])
    
    def wrap_gen_captcha_text_and_image():
        while True:
            text,image=gen_captcha_text_and_image()
            if image.shape==(60,160,3):
                return text,image
            
    for i in range(batch_size):
        text,image = wrap_gen_captcha_text_and_image()
        image=convert2gray(image)
        
        batch_x[i,:]=image.flatten()/255
        batch_y[i,:]=text2vec(text)
    return batch_x,batch_y


#%%
def crack_captcha_cnn(w_alpha=0.01,b_alpha=0.1):
    '构建破解验证码的CNN网络'
    x=tf.reshape(X,shape=[-1,IMAGE_HEIGHT,IMAGE_WIDTH,1])
    w_c1=tf.Variable(w_alpha*tf.random_normal([3,3,1,32]))
    b_c1=tf.Variable(b_alpha*tf.random_normal([32]))
    
    conv1=tf.nn.relu(tf.nn.bias_add(tf.nn.conv2d(x,w_c1,strides=[1,1,1,1],padding='SAME'),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)
    
    w_c2=tf.Variable(w_alpha*tf.random_normal([3,3,32,64]))
    b_c2=tf.Variable(b_alpha*tf.random_normal([64]))
    conv2=tf.nn.relu(tf.nn.bias_add(tf.nn.conv2d(conv1,w_c2,strides=[1,1,1,1],padding='SAME'),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)
    
    w_c3=tf.Variable(w_alpha*tf.random_normal([3,3,64,64]))
    b_c3=tf.Variable(b_alpha*tf.random_normal([64]))
    conv3=tf.nn.relu(tf.nn.bias_add(tf.nn.conv2d(conv2,w_c3,strides=[1,1,1,1],padding='SAME'),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)
    
    'fully connected layer'
    w_d=tf.Variable(w_alpha*tf.random_normal([8*20*64,1024]))
    b_d=tf.Variable(b_alpha*tf.random_normal([1024]))
    dense=tf.reshape(conv3,[-1,w_d.get_shape().as_list()[0]])
    dense=tf.nn.relu(tf.nn.bias_add(tf.matmul(dense,w_d),b_d))
#    dense=tf.nn.max_pool(dense,ksize=[1,2,2,1],strides=[1,2,2,1],padding='SAME')
    dense=tf.nn.dropout(dense,keep_prob)
    
    w_out=tf.Variable(w_alpha*tf.random_normal([1024,MAX_CAPTCHA*CHAR_SET_LEN]))
    b_out=tf.Variable(b_alpha*tf.random_normal([MAX_CAPTCHA*CHAR_SET_LEN]))
    out=tf.add(tf.matmul(dense,w_out),b_out)
    return out

#%%
def train_crack_captcha_cnn():
    '训练CNN'
    output=crack_captcha_cnn()
    loss=tf.reduce_mean(tf.nn.sigmoid_cross_entropy_with_logits(logits=output,labels=Y))
    optimizer=tf.train.AdamOptimizer(learning_rate=.001).minimize(loss)
    predict=tf.reshape(output,[-1,MAX_CAPTCHA,CHAR_SET_LEN])
    max_idx_p=tf.argmax(predict,2)
    max_idx_l=tf.argmax(tf.reshape(Y,[-1,MAX_CAPTCHA,CHAR_SET_LEN]),2)
    correct_pred=tf.equal(max_idx_p,max_idx_l)
    accuracy=tf.reduce_mean(tf.cast(correct_pred,tf.float32))
    
    saver=tf.train.Saver()
    print('session preparing')
    with tf.Session() as sess:
        print('session created!!')
        sess.run(tf.global_variables_initializer())
        step=0
        print('sess initiated!! ready to train!!')
        while True:
#            print(step)
            batch_x,batch_y=gen_next_batch(64)
            _,loss_=sess.run([optimizer,loss],feed_dict={X:batch_x,Y:batch_y,keep_prob:.75})
            print('step:',step,'loss:',loss_)
            
            '每100 step计算一次准确率'
            if step%10==0:
                batch_x_test,batch_y_test=gen_next_batch(100)
                acc=sess.run(accuracy,feed_dict={X:batch_x_test,Y:batch_y_test,keep_prob:1.})
                print('_____step:',step,'accuracy:',acc,'_____')
                if acc > 0.50:
                    saver.save(sess,'./model/crack_captcha.model',global_step=step)
                    break
            step+=1
#%%
def crack_captcha(captcha_image):
    '调用训练好的CNN,输入验证码灰度图,返回CNN预测的text'
    output=crack_captcha_cnn()
    saver=tf.train.Saver()
    with tf.Session() as sess:
        saver.restore(sess,'./model/crack_captcha.model-810')
        
        predict=tf.argmax(tf.reshape(output,[-1,MAX_CAPTCHA,CHAR_SET_LEN]),2)
        text_list=sess.run(predict,feed_dict={X:[captcha_image],keep_prob:1.})
        text=text_list[0].tolist()
        return text
    
#%%
if __name__ == '__main__':
    train=1
    if train==1:
        'train=1的时候训练模型'
        number=['0','1','2','3','4','5','6','7','8','9']
#        alphabet=['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']
#        ALPHABET=['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']
        
        text,image=gen_captcha_text_and_image()
        print('验证码图像shape:',image.shape) #(60,160,3)
        '图像大小'
        IMAGE_HEIGHT=60
        IMAGE_WIDTH=160
        MAX_CAPTCHA=len(text)
        print('验证码文本最长字符数:',MAX_CAPTCHA)
        
        '文本转向量'
        char_set=number
        CHAR_SET_LEN=len(char_set)
        X=tf.placeholder(tf.float32,[None,IMAGE_HEIGHT*IMAGE_WIDTH])
        Y=tf.placeholder(tf.float32,[None,MAX_CAPTCHA*CHAR_SET_LEN])
        keep_prob=tf.placeholder(tf.float32)
        
        train_crack_captcha_cnn()
    if train==0:
        'train=0的时候调用模型'
        number = ['0','1','2','3','4','5','6','7','8','9']  
        IMAGE_HEIGHT = 60  
        IMAGE_WIDTH = 160  
        char_set = number
        CHAR_SET_LEN = len(char_set)
        
        text,image=gen_captcha_text_and_image()
        
        f=plt.figure()
        ax=f.add_subplot(111)
        ax.text(.1,.9,text,ha='center',va='center',transform=ax.transAxes)
        plt.imshow(image)
        
        MAX_CAPTCHA=len(text)
        image=convert2gray(image)
        image=image.flatten()/255
        
        X = tf.placeholder(tf.float32, [None, IMAGE_HEIGHT*IMAGE_WIDTH])  
        Y = tf.placeholder(tf.float32, [None, MAX_CAPTCHA*CHAR_SET_LEN])  
        keep_prob = tf.placeholder(tf.float32) # dropout 
        
        predict_text=crack_captcha(image)
        print("正确: {}  预测: {}".format(text, predict_text)) 
        
        
        
 


 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值