精华内容
下载资源
问答
  • CNN识别验证码的实用教程,从数据标定到搭建服务, tensorflow captcha recognization practical tutorial
  • 本项目针对字符型图片验证码,使用tensorflow实现卷积神经网络,进行验证码识别。 项目封装了比较通用的**校验、训练、验证、识别、API模块**,极大的减少了识别字符型验证码花费的时间和精力 1.1 关于验证码识别...
  • 我们使用卷积神经网络来实现验证码识别案列,具体流程如下: 1、使用python的captcha模块生成验证码图片。 2、使用tensorflow框架搭建神经网络模型。 3、将数据喂入搭建好的神经网络模型中。 4、保存训练好的网络...

    任务要求

    我们使用卷积神经网络来实现验证码识别案列,具体流程如下:

    1、使用python的captcha模块生成验证码图片。
    2、使用tensorflow框架搭建神经网络模型。
    3、将数据喂入搭建好的神经网络模型中。
    4、保存训练好的网络模型。

    下面我们来看具体的细节。
    一、定义字符集,验证码一般为数字、字母。练习的时候可以先只考虑数字的情况,这样模型训练的会快些。代码如下:

    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']  
    

    二、下面我们要从给定的字符集中选择4个字符,生成160*60的验证码图片,并将图片转化为numpy数组。然后将选择的四个字符生成为词向量形式。
    1、生成图片并转化为数组。

    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)  
        #image.write(captcha_text, captcha_text + '.jpg')   
       
        captcha_image = Image.open(captcha)
        captcha_image = captcha_image.convert('L')
        captcha_image = captcha_image.point(lambda i: 255 - i)
        #将图片取反,黑色变为白色,白色变为黑色,这样模型收敛更快
        captcha_image = np.array(captcha_image)
        return captcha_text, captcha_image
    

    2、传入验证码文本,转化为词向量的形式,假设我们现在只使用数字集0-9。那么就是10分类,我们用一个长度为10的向量来表示一个数字,比如[1, 0, 0, 0, 0, 0, 0, 0, 0, 0]表示数字0,[0, 1, 0, 0, 0, 0, 0, 0, 0, 0]表示数字1。我们有四个字符,所以是一个410的矩阵,再将这个矩阵拉平为一维的,就是长度为40的向量。
    如果我们现在采用数字加大小写字母为字符集,那就是4
    (10+26+26),再将矩阵拉平,就是长度为248的向量。代码如下:

    def text2vec(text):  
        text_len = len(text)  
        if text_len > MAX_CAPTCHA:  
            raise ValueError('验证码最长4个字符')  
       
        vector = np.zeros(MAX_CAPTCHA*CHAR_SET_LEN)  
        def char2pos(c):  
            if c =='_':  
                k = 62  
                return k  
            k = ord(c)-48  
            if k > 9:  
                k = ord(c) - 55  
                if k > 35:  
                    k = ord(c) - 61  
                    if k > 61:  
                        raise ValueError('No Map')   
            return k  
        for i, c in enumerate(text):  
            idx = i * CHAR_SET_LEN + char2pos(c)  
            vector[idx] = 1  
        return vector 
    

    三、以上代码每次只生成一张验证码,当然每次传入网络一个样本也可以,但我们习惯一次喂入多个样本,所以我们还要一次性生成多张图片传入网络。代码如下。

    # 生成一个训练batch  
    def get_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])  
       
        # 有时生成图像大小不是(60, 160, 3)  
        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 # (image.flatten()-128)/128  mean为0  
            batch_y[i,:] = text2vec(text)  
       
        return batch_x, batch_y  
    
    def convert2gray(img):  
        if len(img.shape) > 2:  
            gray = np.mean(img, -1)  
            # 上面的转法较快,正规转法如下  
            # r, g, b = img[:,:,0], img[:,:,1], img[:,:,2]  
            # gray = 0.2989 * r + 0.5870 * g + 0.1140 * b  
            return gray  
        else:  
            return img  
    

    四、现在图片生成好了,对应的词向量也生成好了,要开始搭建网络了,我们采用三层卷积,一层全连接层,最后输出成,代码如下:

    # 定义CNN
    def crack_captcha_cnn(w_alpha=0.01, b_alpha=0.1):  
        x = tf.reshape(X, shape=[-1, IMAGE_HEIGHT, IMAGE_WIDTH, 1])  
       
        #w_c1_alpha = np.sqrt(2.0/(IMAGE_HEIGHT*IMAGE_WIDTH)) #  
        #w_c2_alpha = np.sqrt(2.0/(3*3*32))   
        #w_c3_alpha = np.sqrt(2.0/(3*3*64))   
        #w_d1_alpha = np.sqrt(2.0/(8*32*64))  
        #out_alpha = np.sqrt(2.0/1024)  
       
        # 3 conv layer  
        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*32*40, 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.add(tf.matmul(dense, w_d), b_d))  
        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)  
        #out = tf.nn.softmax(out)  
        return out  
    

    五、网络构建好了,现在需要构建损失函数,以及准确率等等,并开始训练了。具体代码如下:

    # 训练  
    def train_crack_captcha_cnn():  
        output = crack_captcha_cnn()  
        # loss  
        #loss = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(output, Y))  
        loss = tf.reduce_mean(tf.nn.sigmoid_cross_entropy_with_logits(output, Y))  
            # 最后一层用来分类的softmax和sigmoid有什么不同?  
        # optimizer 为了加快训练 learning_rate应该开始大,然后慢慢衰  
        optimizer = tf.train.AdamOptimizer(learning_rate=0.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()  
        with tf.Session() as sess:  
            sess.run(tf.global_variables_initializer())  
       
            step = 0  
            while True:  
                batch_x, batch_y = get_next_batch(64)  
                _, loss_ = sess.run([optimizer, loss], feed_dict={X: batch_x, Y: batch_y, keep_prob: 0.75})  
                print(step, loss_)  
                  
                # 每100 step计算一次准确率  
                if step % 10 == 0:  
                    batch_x_test, batch_y_test = get_next_batch(100)
                    acc = sess.run(accuracy, feed_dict={X: batch_x_test, Y: batch_y_test, keep_prob: 1.})  
                    print(step, acc)  
                    # 如果准确率大于50%,保存模型,完成训练  
                    if acc > 0.50:  
                        saver.save(sess, "./model/crack_capcha.model", global_step=step)  
                        break
    
                step += 1
    

    整个结构基本就是这样,如果只采用数字集的话,基本一千次迭代,半小时左右,准确率就能到90%以上。如果采用数字加大小写字母,时间会稍微久一点。下面是完整的代码:

    import numpy as np  
    import tensorflow as tf
    from captcha.image import ImageCaptcha
    import numpy as np  
    import matplotlib.pyplot as plt  
    from PIL import Image  
    import random   
    
    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):  
    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():  
        image = ImageCaptcha()  
       
        captcha_text = random_captcha_text()  
        captcha_text = ''.join(captcha_text)  
       
        captcha = image.generate(captcha_text)  
        #image.write(captcha_text, captcha_text + '.jpg')   
       
        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, -1)  
            # 上面的转法较快,正规转法如下  
            # r, g, b = img[:,:,0], img[:,:,1], img[:,:,2]  
            # gray = 0.2989 * r + 0.5870 * g + 0.1140 * b  
            return gray  
        else:  
            return img  
    
       
      
    def text2vec(text):  
        text_len = len(text)  
        if text_len > MAX_CAPTCHA:  
            raise ValueError('验证码最长4个字符')  
       
        vector = np.zeros(MAX_CAPTCHA*CHAR_SET_LEN)  
    
        def char2pos(c):  
            if c =='_':  
                k = 62  
                return k  
            k = ord(c)-48  
            if k > 9:  
                k = ord(c) - 55  
                if k > 35:  
                    k = ord(c) - 61  
                    if k > 61:  
                        raise ValueError('No Map')   
            return k  
    
        for i, c in enumerate(text):  
            idx = i * CHAR_SET_LEN + int(c)  
            vector[idx] = 1  
        return vector
    
    
    # 传入验证码字符文本,生成对应的词向量
    # def text2vec(text):
    #     text_len = len(text)
    #     if text_len > MAX_CAPTCHA:
    #         raise ValueError('验证码最长4个字符')
    #     vector = np.zeros(MAX_CAPTCHA*CHAR_SET_LEN)
    #     def char2pos(c):
    #         if c =='_':
    #             k = 62
    #             return k
    #         k = ord(c)-48
    #         if k > 9:
    #             k = ord(c) - 55
    #             if k > 35:
    #                 k = ord(c) - 61
    #                 if k > 61:
    #                     raise ValueError('No Map')
    #         return k
    #     for i, c in enumerate(text):
    #         idx = i * CHAR_SET_LEN + char2pos(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 
    """  
       
    # 生成一个训练batch  
    def get_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])  
       
        # 有时生成图像大小不是(60, 160, 3)  
        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 # (image.flatten()-128)/128  mean为0  
            batch_y[i,:] = text2vec(text)  
       
        return batch_x, batch_y  
       
    
       
    # 定义CNN ,这里使用三层卷积和一层全连接操作,最后输出
    def crack_captcha_cnn(w_alpha=0.01, b_alpha=0.1):  
        x = tf.reshape(X, shape=[-1, IMAGE_HEIGHT, IMAGE_WIDTH, 1])  
       
        #w_c1_alpha = np.sqrt(2.0/(IMAGE_HEIGHT*IMAGE_WIDTH)) #  
        #w_c2_alpha = np.sqrt(2.0/(3*3*32))   
        #w_c3_alpha = np.sqrt(2.0/(3*3*64))   
        #w_d1_alpha = np.sqrt(2.0/(8*32*64))  
        #out_alpha = np.sqrt(2.0/1024)  
       
        # 3 conv layer  
        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.add(tf.matmul(dense, w_d), b_d))  
        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():  
        output = crack_captcha_cnn()  
        loss = tf.reduce_mean(tf.nn.sigmoid_cross_entropy_with_logits(output, Y))  
        optimizer = tf.train.AdamOptimizer(learning_rate=0.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()  
        with tf.Session() as sess:  
            sess.run(tf.global_variables_initializer())  
       
            step = 0  
            while True:  
                batch_x, batch_y = get_next_batch(64)  
                _, loss_ = sess.run([optimizer, loss], feed_dict={X: batch_x, Y: batch_y, keep_prob: 0.75})  
                print(step, loss_)  
                  
                # 每100 step计算一次准确率  
                if step % 10 == 0:  
                    batch_x_test, batch_y_test = get_next_batch(100)  
                    acc = sess.run(accuracy, feed_dict={X: batch_x_test, Y: batch_y_test, keep_prob: 1.})  
                    print(step, acc)  
                    # 如果准确率大于50%,保存模型,完成训练  
                    if acc > 0.50:  
                        saver.save(sess, "./model/crack_capcha.model", global_step=step)  
                        break  
       
                step += 1
    
    def crack_captcha(captcha_image):  
        output = crack_captcha_cnn()  
       
        saver = tf.train.Saver()  
        with tf.Session() as sess:  
            saver.restore(sess, "./model/crack_capcha.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 == 0:
            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("验证码图像channel:", image.shape)  # (60, 160, 3)  
            # 图像大小  
            IMAGE_HEIGHT = 60  
            IMAGE_WIDTH = 160  
            MAX_CAPTCHA = len(text)  
            print("验证码文本最长字符数", MAX_CAPTCHA)
            # 文本转向量  
            #char_set = number + alphabet + ALPHABET + ['_']  # 如果验证码长度小于4, '_'用来补齐  
            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) # dropout 
            
            train_crack_captcha_cnn()
        if train == 1:
            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(0.1, 0.9,text, ha='center', va='center', transform=ax.transAxes)  
            plt.imshow(image)  
           
            plt.show()  
            
            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))  
           
    
    展开全文
  • cnn验证码识别

    2019-10-18 22:07:13
    "C:\Users\Username\Desktop\Con-LSTM\captcha_cnn\captcha_train_pic\labels.csv" , names = { "file_no" , "characters" } , index_col = "file_no" ) csv_data_train = read_csv ( csv_data ) # ...
    import tensorflow as tf
    import os
    import pandas as pd
    
    
    def load_pics(filename_list):
        """
        1、读取图像数据,csv文件中的file_num为标签值的编号
        :return:
        """
        # print(filename_queue)
        #    构造文件名队列
        filename_queue = tf.train.string_input_producer(filename_list)
        #    构造文件读取器
        image_reader = tf.WholeFileReader()
        #    读取文件(filename为文件名,对应csv文件中的file_num,image为图像原始编码)
        filename, image = image_reader.read(filename_queue)
        #    解码文件
        decoded = tf.image.decode_jpeg(image)
        #    更改图像形状和格式,方便进行批处理(conv2d中input参数要求张量类型必须为float32或float64)
        #    注意:在输入目标shape时一定要和图像数据的真实分辨率保持一致,否则会报错!
        #    (1)、可以调用set_shape直接修改形状
        # decoded.set_shape([60, 160, 3])
        # image_cast = tf.cast(decoded, dtype=tf.float32)
        #    (2)、也可以使用reshape函数修改,但不会改变原张量对象
        image_reshape = tf.reshape(decoded, shape=[60, 160, 3])
        image_cast = tf.cast(image_reshape, dtype=tf.float32)
        # print(image_cast)
        #    批处理
        filename_batch, image_batch = tf.train.batch([filename, image_cast], batch_size=100, num_threads=1, capacity=200)
        return filename_batch, image_batch
    
    
    def read_csv(csv_data):
        """
        2、解析csv文件,将标签值转换为数值表示(根据26英文字母对应索引0-25建立标签对应的数值表)
           得到“图像-标签值”表
        :return:
        """
        # 将characters对应的数值列labels添加到data的新列“labels”中
        # # 当原文件第一行不是数值时要删去,drop函数中axis为1表示从行中查找,1表示从列中查找,
        # # index表示要删除的行名,columns为要删除的列名
        # data = csv_data.drop(axis=-1, index="file_num")
        data = csv_data
        labels = []
        for label_name in data["characters"]:
            label_num = []
            for letter in label_name:
                # ord()返回字符对应的ASCII码
                label_num.append(ord(letter) - ord('A'))
            labels.append(label_num)
        data["labels"] = labels
        # print(csv_data)
        return data
    
    
    def filename2labels(file_name, batch_data):
        """
        3、根据filename与file_num对应相同来联系特征值(图片)与目标值(标签)
           通过文件名查表得到当前图像对应的标签
        :param batch_data:
        :return:
        """
        label_list = []
        # print(file_name)
        for name in file_name:
            # print(name)
            # 先把name转换为字符串类型,然后使用isdigit查找其中的数字,即文件名
            num_str = "".join(list(filter(str.isdigit, str(name))))
            # print(type(num_str))
            target = batch_data.loc[num_str, "labels"]
            # print(target)
            label_list.append(target)
        return label_list
    
    
    def variable_init(shape):
        """
        定义给定形状的变量
        :return:
        """
        return tf.Variable(initial_value=tf.random.normal(shape=shape))
    
    
    def cnn_identifying(x):
        """
        4、构建卷积神经网络得到y_predict
        :return:
        """
        input_image = tf.reshape(x, [-1, 60, 160, 3])
        with tf.variable_scope("conv1"):
            # 卷积层1
            Weights_filter1 = variable_init([5, 5, 3, 32])
            bias_filter1 = variable_init([32])
            conv1 = tf.nn.conv2d(input=input_image, filter=Weights_filter1, strides=[1, 1, 1, 1], padding="SAME") + bias_filter1
            # 激活函数
            conv1_relu = tf.nn.relu(conv1)
            # 池化层
            conv1_pool = tf.nn.max_pool(value=conv1_relu, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding="SAME")
        with tf.variable_scope("conv2"):
            # 卷积层2
            Weights_filter2 = variable_init([5, 5, 32, 64])
            bias_filter2 = variable_init([64])
            conv2 = tf.nn.conv2d(input=conv1_pool, filter=Weights_filter2, strides=[1, 1, 1, 1], padding="SAME") + bias_filter2
            # 激活函数
            conv2_relu = tf.nn.relu(conv2)
            # 池化层
            conv2_pool = tf.nn.max_pool(value=conv2_relu, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding="SAME")
        with tf.variable_scope("fc"):
            # 全连接层
            conv2_reshape = tf.reshape(conv2_pool, shape=[-1, 15*40*64])
            Weights_fc = variable_init([15*40*64, 4*26])
            bias_fc = variable_init([4*26])
            y_predict = tf.matmul(conv2_reshape, Weights_fc) + bias_fc
        return y_predict
    
    
    if __name__ == "__main__":
        # 使用QueueRunner的方式读取文件
        # 构造“路径、文件名”列表
        file_list = os.listdir(r"C:\Users\Username\Desktop\Con-LSTM\captcha_cnn\captcha_train_pic")
        # print(filename_list)
        filename_list = [os.path.join(r"C:\Users\Username\Desktop\Con-LSTM\captcha_cnn\captcha_train_pic", filename)
                         for filename in file_list if filename[-3:] == "jpg"]
        filename, image = load_pics(filename_list)
        # 得到“图像-标签值”表
        # 读取csv文件,列命名为file_num、characters, 列索引设为file_num
        csv_data = pd.read_csv(r"C:\Users\Username\Desktop\Con-LSTM\captcha_cnn\captcha_train_pic\labels.csv",
                               names={"file_no", "characters"}, index_col="file_no")
        csv_data_train = read_csv(csv_data)
        # print(csv_data)
        x = tf.placeholder(dtype=tf.float32, shape=[None, 60, 160, 3])
        # 计算损失时需要一维数组(需要知道4*26个数字的损失),计算准确率时需要二维数组(四行分别代表四个字母)
        y_true = tf.placeholder(dtype=tf.float32, shape=[None, 4*26])
        y_predict = cnn_identifying(x)
    
        # 构造数据流图:
        # 5、构造损失函数(一个样本涵盖多个目标值时,应用sigmoid交叉熵作为损失函数)
        loss_list = tf.nn.sigmoid_cross_entropy_with_logits(labels=y_true, logits=y_predict)
        loss = tf.reduce_mean(loss_list)
        # 6、优化损失
        optimizer = tf.train.AdamOptimizer(learning_rate=0.001).minimize(loss)
        # 7、计算准确率
        #    先转换为4行26列形式,才能表示出字母所在位置
        y_predict_reshape = tf.reshape(y_predict, shape=[-1, 4, 26])
        y_true_reshape = tf.reshape(y_true, shape=[-1, 4, 26])
        #    因为要根据第三阶的最大值判断字母,所以axis为2或-1,最终形式形如[[True, True, False, True], [...], ...]
        equal_list = tf.equal(tf.argmax(y_predict_reshape, axis=2), tf.argmax(y_true_reshape, axis=2))
        #    用reduce_all()转换为一维数组[False, ..., ...], 用cast()转换为浮点型,再用reduce_mean()计算得平均值,即准确率
        accuracy = tf.reduce_mean(tf.cast(tf.reduce_all(equal_list, axis=1), tf.float32))
        # 8、开启会话(线程的开启与关闭)
        # 使用文件名队列进行数据读取时要先开启线程
        # 初始化变量
        init = tf.global_variables_initializer()
        # 构造模型存储器
        saver = tf.train.Saver()
        with tf.compat.v1.Session() as sess:
            sess.run(init)
            # 开启线程
            # 创建线程协调员
            coord = tf.train.Coordinator()
            threads = tf.train.start_queue_runners(sess=sess, coord=coord)
    
            filename_val, image_val = sess.run([filename, image])
            # 通过文件名查表得到当前图像对应的标签(真实值)
            image_labels = filename2labels(filename_val, csv_data_train)
            # 对真实值进行one-hot编码(depth为一个编码的长度,axis默认为-1,即按最后一个维度)
            labels_onehot = tf.one_hot(image_labels, depth=26)
            labels_value = tf.reshape(labels_onehot, shape=[-1, 4*26]).eval()
            # print(labels_onehot.eval())
            # print(sess.run(equal_list, feed_dict={x: image_val, y_true: labels_value}))
            for i in range(1000):
                # 注意feed_dict中的值应为Python scalar, string, list, numpy ndarray类型,不能为张量
                _, error, accuracy_value = sess.run([optimizer, loss, accuracy], feed_dict={x: image_val, y_true: labels_value})
                # print("第%d次训练的误差为:%f,准确率为:%f" % (i+1, error, accuracy_value))
                if i % 100 == 0:
                    saver.save(sess=sess, save_path=r"C:\Users\Username\Desktop\Con-LSTM\captcha_cnn\model")
    
            # print(filename_val, image_val)
            # 回收线程
            coord.request_stop()
            coord.join(threads=threads)
    
    #coding:utf8
    # 验证码生成
    from captcha.image import ImageCaptcha
    from random import randint
    import os
    import csv
    
    
    def captcha_pic_builder():
        '''
        生成序列验证码图片及包含其对应目标值的csv文件
        :return:
        '''
        list = ['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']
        # 因为csv标签名不能放在循环里的缘故,故将创建及增加内容放在外面
        # newline='',是为了防止以Excel打开时会多出空行
        with open(r'C:\Users\Username\Desktop\Con-LSTM\captcha_cnn\captcha_test_pic\labels.csv', 'a+', newline='') as csvfile:
            writer = csv.writer(csvfile, dialect='excel')
            writer.writerow(['file_num', 'chars'])
            for j in range(100):
                chars = ''
                for i in range(4):
                    chars += list[randint(0, 25)]
                # 随机生成图片内字符
                print(chars)
                # 生成图片
                image = ImageCaptcha().generate_image(chars)
                # image.show()
                filename = str(j) +'.jpg'
                # 将图片保存到本地
                image.save(os.path.join(r'C:\Users\Username\Desktop\Con-LSTM\captcha_cnn\captcha_test_pic', filename))
                # 添加样本序列及目标值
                writer.writerow([j, chars])
        return None
    
    
    if __name__ == '__main__':
        captcha_pic_builder()
    
    
    展开全文
  • cnn网络验证码识别训练模型

    热门讨论 2017-05-25 19:04:24
    自定义cnn网络训练的验证码识别模型
  • 基于CNN验证码识别神经网络实现

    万次阅读 2017-08-23 19:58:38
    1、什么是CNN? 2、TensorFlow进阶 二、实战 1、验证码生成 import random import numpy as np from PIL import Image from captcha.image import ImageCaptcha NUMBER = ['0', '1', '2', '3', '4', '5', '6', '7'...

    一、前言

    1、什么是CNN?

    2、TensorFlow进阶

    二、实战

    1、验证码生成

    import random
    import numpy as np
    from PIL import Image
    from captcha.image import ImageCaptcha
    
    
    NUMBER = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']
    LOW_CASE = ['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']
    UP_CASE = ['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']
    CAPTCHA_LIST = NUMBER + LOW_CASE + UP_CASE
    CAPTCHA_LEN = 4
    CAPTCHA_HEIGHT = 60
    CAPTCHA_WIDTH = 160
    
    
    def random_captcha_text(char_set=CAPTCHA_LIST, captcha_size=CAPTCHA_LEN):
        '''
        随机生成验证码文本
        :param char_set:
        :param captcha_size:
        :return:
        '''
        captcha_text = [random.choice(char_set) for _ in range(captcha_size)]
        return ''.join(captcha_text)
    
    
    def gen_captcha_text_and_image(width=CAPTCHA_WIDTH, height=CAPTCHA_HEIGHT,save=None):
        '''
        生成随机验证码
        :param width:
        :param height:
        :param save:
        :return: np数组
        '''
        image = ImageCaptcha(width=width, height=height)
        # 验证码文本
        captcha_text = random_captcha_text()
        captcha = image.generate(captcha_text)
        # 保存
        if save: image.write(captcha_text, captcha_text + '.jpg')
        captcha_image = Image.open(captcha)
        # 转化为np数组
        captcha_image = np.array(captcha_image)
        return captcha_text, captcha_image
    基于captcha包做的简单验证码生成器,用来练手挺好的,直接看代码就行啦

    2、权重、偏置及工具函数定义

    def weight_variable(shape, w_alpha=0.01):
        '''
        增加噪音,随机生成权重
        :param shape:
        :param w_alpha:
        :return:
        '''
        initial = w_alpha * tf.random_normal(shape)
        return tf.Variable(initial)
    
    
    def bias_variable(shape, b_alpha=0.1):
        '''
        增加噪音,随机生成偏置项
        :param shape:
        :param b_alpha:
        :return:
        '''
        initial = b_alpha * tf.random_normal(shape)
        return tf.Variable(initial)
    
    
    def conv2d(x, w):
        '''
        局部变量线性组合,步长为1,模式‘SAME’代表卷积后图片尺寸不变,即零边距
        :param x:
        :param w:
        :return:
        '''
        return tf.nn.conv2d(x, w, strides=[1, 1, 1, 1], padding='SAME')
    
    
    def max_pool_2x2(x):
        '''
        max pooling,取出区域内最大值为代表特征, 2x2pool,图片尺寸变为1/2
        :param x:
        :return:
        '''
        return tf.nn.max_pool(x, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='SAME')
    3、CNN三层神经网络定义

    def cnn_graph(x, keep_prob, size, captcha_list=CAPTCHA_LIST, captcha_len=CAPTCHA_LEN):
        '''
        三层卷积神经网络计算图
        :param x:
        :param keep_prob:
        :param size:
        :param captcha_list:
        :param captcha_len:
        :return:
        '''
        # 图片reshape为4维向量
        image_height, image_width = size
        x_image = tf.reshape(x, shape=[-1, image_height, image_width, 1])
    
        # layer 1
        # filter定义为3x3x1, 输出32个特征, 即32个filter
        w_conv1 = weight_variable([3, 3, 1, 32])
        b_conv1 = bias_variable([32])
        # rulu激活函数
        h_conv1 = tf.nn.relu(tf.nn.bias_add(conv2d(x_image, w_conv1), b_conv1))
        # 池化
        h_pool1 = max_pool_2x2(h_conv1)
        # dropout防止过拟合
        h_drop1 = tf.nn.dropout(h_pool1, keep_prob)
    
        # layer 2
        w_conv2 = weight_variable([3, 3, 32, 64])
        b_conv2 = bias_variable([64])
        h_conv2 = tf.nn.relu(tf.nn.bias_add(conv2d(h_drop1, w_conv2), b_conv2))
        h_pool2 = max_pool_2x2(h_conv2)
        h_drop2 = tf.nn.dropout(h_pool2, keep_prob)
    
        # layer 3
        w_conv3 = weight_variable([3, 3, 64, 64])
        b_conv3 = bias_variable([64])
        h_conv3 = tf.nn.relu(tf.nn.bias_add(conv2d(h_drop2, w_conv3), b_conv3))
        h_pool3 = max_pool_2x2(h_conv3)
        h_drop3 = tf.nn.dropout(h_pool3, keep_prob)
    
        # full connect layer
        image_height = int(h_drop3.shape[1])
        image_width = int(h_drop3.shape[2])
        w_fc = weight_variable([image_height*image_width*64, 1024])
        b_fc = bias_variable([1024])
        h_drop3_re = tf.reshape(h_drop3, [-1, image_height*image_width*64])
        h_fc = tf.nn.relu(tf.add(tf.matmul(h_drop3_re, w_fc), b_fc))
        h_drop_fc = tf.nn.dropout(h_fc, keep_prob)
    
        # out layer
        w_out = weight_variable([1024, len(captcha_list)*captcha_len])
        b_out = bias_variable([len(captcha_list)*captcha_len])
        y_conv = tf.add(tf.matmul(h_drop_fc, w_out), b_out)
        return y_conv
    4、优化及偏差

    def optimize_graph(y, y_conv):
        '''
        优化计算图
        :param y:
        :param y_conv:
        :return:
        '''
        # 交叉熵计算loss 注意logits输入是在函数内部进行sigmod操作
        # sigmod_cross适用于每个类别相互独立但不互斥,如图中可以有字母和数字
        # softmax_cross适用于每个类别独立且排斥的情况,如数字和字母不可以同时出现
        loss = tf.reduce_mean(tf.nn.sigmoid_cross_entropy_with_logits(logits=y_conv, labels=y))
        # 最小化loss优化
        optimizer = tf.train.AdamOptimizer(learning_rate=0.001).minimize(loss)
        return optimizer
    
    
    def accuracy_graph(y, y_conv, width=len(CAPTCHA_LIST), height=CAPTCHA_LEN):
        '''
        偏差计算图
        :param y:
        :param y_conv:
        :param width:
        :param height:
        :return:
        '''
        # 这里区分了大小写 实际上验证码一般不区分大小写
        # 预测值
        predict = tf.reshape(y_conv, [-1, height, width])
        max_predict_idx = tf.argmax(predict, 2)
        # 标签
        label = tf.reshape(y, [-1, height, width])
        max_label_idx = tf.argmax(label, 2)
        correct_p = tf.equal(max_predict_idx, max_label_idx)
        accuracy = tf.reduce_mean(tf.cast(correct_p, tf.float32))
        return accuracy
    5、训练

    def train(height=CAPTCHA_HEIGHT, width=CAPTCHA_WIDTH, y_size=len(CAPTCHA_LIST)*CAPTCHA_LEN):
        '''
        cnn训练
        :param height:
        :param width:
        :param y_size:
        :return:
        '''
        # cnn在图像大小是2的倍数时性能最高, 如果图像大小不是2的倍数,可以在图像边缘补无用像素
        # 在图像上补2行,下补3行,左补2行,右补2行
        # np.pad(image,((2,3),(2,2)), 'constant', constant_values=(255,))
    
        acc_rate = 0.95
        # 按照图片大小申请占位符
        x = tf.placeholder(tf.float32, [None, height * width])
        y = tf.placeholder(tf.float32, [None, y_size])
        # 防止过拟合 训练时启用 测试时不启用
        keep_prob = tf.placeholder(tf.float32)
        # cnn模型
        y_conv = cnn_graph(x, keep_prob, (height, width))
        # 最优化
        optimizer = optimize_graph(y, y_conv)
        # 偏差
        accuracy = accuracy_graph(y, y_conv)
        # 启动会话.开始训练
        saver = tf.train.Saver()
        sess = tf.Session()
        sess.run(tf.global_variables_initializer())
        step = 0
        while 1:
            batch_x, batch_y = next_batch(64)
            sess.run(optimizer, feed_dict={x: batch_x, y: batch_y, keep_prob: 0.75})
            # 每训练一百次测试一次
            if step % 100 == 0:
                batch_x_test, batch_y_test = next_batch(100)
                acc = sess.run(accuracy, feed_dict={x: batch_x_test, y: batch_y_test, keep_prob: 1.0})
                print(datetime.now().strftime('%c'), ' step:', step, ' accuracy:', acc)
                # 偏差满足要求,保存模型
                if acc > acc_rate:
                    model_path = os.getcwd() + os.sep + str(acc_rate) + "captcha.model"
                    saver.save(sess, model_path, global_step=step)
                    acc_rate += 0.01
                    if acc_rate > 0.99: break
            step += 1
        sess.close()
    这里设定准确率到达95%就保存模型,实际训练半个多小时可以达到98%的准确率

    三、其他

    详细代码可以在我的github上找到: https://github.com/lpty/tensorflow_tutorial





    展开全文
  • CNN识别验证码

    千次阅读 2018-09-26 20:41:56
    我们这里生成的验证码是当前最常见的验证码即由26位大小写英文字母和0到9十个数字组成的字符型验证码。 2.生成方式 我们可以选择两种方式来生成我们的训练数据。一种是一次性生成几万张图(保存到本地),另一种是...

    一,基本思路

    生成数据(验证码样本)

    1.验证码类型

    我们这里生成的验证码是当前最常见的验证码即由26位大小写英文字母和0到9十个数字组成的字符型验证码。

    2.生成方式

    我们可以选择两种方式来生成我们的训练数据。一种是一次性生成几万张图(保存到本地),另一种是定义一个数据生成器(数据未被保存)。两种方式各有千秋,第一种方式的好处是训练的时候显卡利用率高,如果你需要经常调参,可以一次生成,多次使用;第二种方式的好处是你不需要生成大量数据,训练过程中可以利用 CPU 生成数据,而且还有一个好处是你可以无限生成数据。我们这里采用第二种方式来生成数据。

    3.验证码图片如下

     

    处理数据

    1.色彩在验证码中并不重要,我们将彩色验证码图片转为黑白,3维转1维,减少干扰数据。

    2.将黑白验证码图片及其文本内容转化为数值数据。

    3.设置验证码图片组,以便让图片数据分批次进行训练。

     

    创建模型

    这里用到了 5 层网络,前 3 层为卷积层,第 4、5 层为全连接层。对 4 层隐藏层都进行 dropout。网络结构如下所示: input——>conv——>pool——>dropout——>conv——>pool——>dropout——>conv——>pool——>dropout——>fully connected layer——>dropout——>fully connected layer——>output

     

    训练数据

    这里选择交叉熵损失函数。sigmod_cross适用于每个类别相互独立但不互斥,如图中可以有字母和数字。每批次采用 64 个训练样本,每训练100次测试一次样本识别的准确度,当准确度大于 95% 时保存模型,当准确度大于99%时训练结束。我们这里采用CPU来训练模型,训练大概需要7个小时左右才能达到95%的准确度,什么时候能达到99%呢?抱歉,看到过了0.95就激动了,我没能等到0.99。

     

    测试模型

    生成验证码——>调用保存的模型——>识别验证码——>输出识别结果。

     

    二,主要工具

    Anaconda

    Anaconda指的是一个开源的Python发行版本,其包含了conda、Python等180多个科学包及其依赖项。

     

    Python3.6

    Python 是一个有条理的和强大的面向对象的程序设计语言,类似于Perl, Ruby, Scheme, Java.

     

    TensorFlow

    TensorFlow是谷歌基于DistBelief进行研发的第二代人工智能学习系统,是一种通用深度学习框架,可被用于语音识别图像识别等多项机器学习和深度学习领域。

     

    Captcha

    captcha 是用 python 写的生成验证码的库,它支持图片验证码和语音验证码,我们使用的是它生成图片验证码的功能。

     

    PyCharm(其他IDE当然也行)

    PyCharm是一种Python IDE,带有一整套可以帮助用户在使用Python语言开发时提高其效率的工具。

     

    三,准备工作

    安装Anaconda

    1.从官方网站下载Anaconda:

    https://www.anaconda.com/download/

    2.进行软件安装(这个和普通的没什么特别区别):

    注意一点:

    3.安装完成Anaconda之后进行环境变量的检测:  进入Anaconda Prompt,输入 conda info --envs

    4.检测anaconda环境是否安装成功:进入Anaconda Prompt,输入 conda --version

     

    安装TensorFlow(Python3.6)

    1.检测目前安装了哪些环境变量:打开Anaconda Prompt,输入  conda info --envs

    2.接着在Anaconda中安装一个内置的python版本解析器(其实就是python的版本),安装python版本:输入 conda create --name tensorflow python=3.6

    3.检测tensflow的环境是否添加到了Anaconda里面:输入 conda info --envs

    4.启动tensorflow环境:在Anaconda Prompt中,输入  activate   tensorflow 

    5.正式安装tensorflow:在tensorflow环境下,输入  pip install --upgrade --ignore-installed tensorflow

    6.使用时注意:创建新python项目时,python解析器必须选择我们之前安装tensorflow的目录下的解析器,否则的话,我们之后使用不了tensorflow模块的内容。

    7.测试是否安装成功:在tensorflow环境下,调出python,运行一个简单程序。

    import tensorflow as tf

    hello = tf.constant('Hello, TensorFlow!')

    sess = tf.Session() print(sess.run(hello))

    这里运行程序时它会跳出一句话(不解决的话以后也一直有)说我们下载TensorFlow的版本不支持cpu的AVX2编译,一般没啥影响,不用管他。当然解决办法也有,请参考 https://blog.csdn.net/Fourierrr_/article/details/79749899

    8.注意:tensorflow环境下没有的模块,需要在tensorflow环境下安装。如下面的captcha等python库。

     

    安装Captcha

    1.启动tensorflow环境:在Anaconda Prompt中,直接输入  activate   tensorflow
    2.在tensorflow环境下安装captcha:输入pip install captcha

     

    安装其他python

    random,numpy ,matplotlib,os,datetime ——同上,从略

     

    四,详细代码

    代码分成4个部分,分别是captcha_create.py,captcha_process.py,cnn_train.py,cnn_test.py,将它们全部放到一个名为captchaCnn的python packge下。

     

    captcha_create.py(生成数据)

    import random
    
    import numpy as np
    
    from PIL import Image
    
    import matplotlib.pyplot as plt
    
    from captcha.image import ImageCaptcha
    
    
    
    # 验证码基本信息
    
    NUMBER = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']
    
    LOW_CASE = ['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']
    
    UP_CASE = ['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']
    
    CAPTCHA_LIST = NUMBER + LOW_CASE + UP_CASE
    
    CAPTCHA_LEN = 4
    
    CAPTCHA_HEIGHT = 60
    
    CAPTCHA_WIDTH = 160
    
    
    
    # 随机生成验证码文本
    
    def random_captcha_text(char_set=CAPTCHA_LIST, captcha_size=CAPTCHA_LEN):
    
        '''
    
        :param char_set:
    
        :param captcha_size:
    
        :return:
    
        '''
    
        captcha_text = [random.choice(char_set) for _ in range(captcha_size)]
    
        return ''.join(captcha_text)
    
    
    
    # 生成随机验证码
    
    def gen_captcha_text_and_image(width=CAPTCHA_WIDTH, height=CAPTCHA_HEIGHT,save=None):
    
        '''
    
        :param width:
    
        :param height:
    
        :param save:
    
        :return: np数组
    
        '''
    
        image = ImageCaptcha(width=width, height=height)
    
        # 验证码文本
    
        captcha_text = random_captcha_text()
    
        captcha = image.generate(captcha_text)
    
        # 保存
    
        if save: image.write(captcha_text, captcha_text + '.jpg')
    
        captcha_image = Image.open(captcha)
    
        # 转化为np数组
    
        captcha_image = np.array(captcha_image)
    
        return captcha_text, captcha_image
    
    
    
    if __name__ == '__main__':
    
        a = gen_captcha_text_and_image(CAPTCHA_WIDTH, CAPTCHA_HEIGHT, save=False)
    
        print(a[0])
    
        plt.imshow(a[1])
    
        plt.show()

     

    captcha_process.py(处理数据)

    import numpy as np
    
    from captchaCnn.captcha_create import gen_captcha_text_and_image
    
    from captchaCnn.captcha_create import CAPTCHA_LIST, CAPTCHA_LEN, CAPTCHA_HEIGHT, CAPTCHA_WIDTH
    
    
    
    # 图片转为黑白,3维转1维
    
    def convert2gray(img):
    
        '''
    
        :param img:
    
        :return:
    
        '''
    
        if len(img.shape) > 2:
    
            img = np.mean(img, -1)
    
        return img
    
    
    
    # 验证码文本转为向量
    
    def text2vec(text, captcha_len=CAPTCHA_LEN, captcha_list=CAPTCHA_LIST):
    
        '''
    
        :param text:
    
        :param captcha_len:
    
        :param captcha_list:
    
        :return:
    
        '''
    
        text_len = len(text)
    
        if text_len > captcha_len:
    
            raise ValueError('验证码最长4个字符')
    
        vector = np.zeros(captcha_len * len(captcha_list))
    
        for i in range(text_len): vector[captcha_list.index(text[i])+i*len(captcha_list)] = 1
    
        return vector
    
    
    
    # 验证码向量转为文本
    
    def vec2text(vec, captcha_list=CAPTCHA_LIST, size=CAPTCHA_LEN):
    
        '''
    
        :param vec:
    
        :param captcha_list:
    
        :param size:
    
        :return:
    
        '''
    
        vec_idx = vec
    
        text_list = [captcha_list[v] for v in vec_idx]
    
        return ''.join(text_list)
    
    
    
    # 返回特定shape图片
    
    def wrap_gen_captcha_text_and_image(shape=(CAPTCHA_HEIGHT, CAPTCHA_WIDTH, 3)):
    
        '''
    
        :param shape:
    
        :return:
    
        '''
    
        while True:
    
            t, im = gen_captcha_text_and_image()
    
            if im.shape == shape: return t, im
    
    
    
    # 获取训练图片组
    
    def next_batch(batch_count=60, width=CAPTCHA_WIDTH, height=CAPTCHA_HEIGHT):
    
        '''
    
        :param batch_count:
    
        :param width:
    
        :param height:
    
        :return:
    
        '''
    
        batch_x = np.zeros([batch_count, width * height])
    
        batch_y = np.zeros([batch_count, CAPTCHA_LEN * len(CAPTCHA_LIST)])
    
        for i in range(batch_count):
    
            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
    
    
    
    if __name__ == '__main__':
    
        x, y = next_batch(batch_count=1)
    
        print(x,'\n\n', y)

     

    cnn_train.py(创建模型,训练数据)

    import os
    
    import tensorflow as tf
    
    from datetime import datetime
    
    from captchaCnn.captcha_process import next_batch
    
    from captchaCnn.captcha_create import CAPTCHA_HEIGHT, CAPTCHA_WIDTH, CAPTCHA_LEN, CAPTCHA_LIST
    
    
    
    # 随机生成权重
    
    def weight_variable(shape, w_alpha=0.01):
    
        '''
    
        :param shape:
    
        :param w_alpha:
    
        :return:
    
        '''
    
        initial = w_alpha * tf.random_normal(shape)
    
        return tf.Variable(initial)
    
    
    
    # 随机生成偏置项
    
    def bias_variable(shape, b_alpha=0.1):
    
        '''
    
        :param shape:
    
        :param b_alpha:
    
        :return:
    
        '''
    
        initial = b_alpha * tf.random_normal(shape)
    
        return tf.Variable(initial)
    
    
    
    # 局部变量线性组合,步长为1,模式‘SAME’代表卷积后图片尺寸不变,即零边距
    
    def conv2d(x, w):
    
        '''
    
        :param x:
    
        :param w:
    
        :return:
    
        '''
    
        return tf.nn.conv2d(x, w, strides=[1, 1, 1, 1], padding='SAME')
    
    
    
    # max pooling,取出区域内最大值为代表特征, 2x2pool,图片尺寸变为1/2
    
    def max_pool_2x2(x):
    
        '''
    
        :param x:
    
        :return:
    
        '''
    
        return tf.nn.max_pool(x, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='SAME')
    
    
    
    # 三层卷积神经网络计算图
    
    def cnn_graph(x, keep_prob, size, captcha_list=CAPTCHA_LIST, captcha_len=CAPTCHA_LEN):
    
        '''
    
        :param x:
    
        :param keep_prob:
    
        :param size:
    
        :param captcha_list:
    
        :param captcha_len:
    
        :return:
    
        '''
    
        # 图片reshape为4维向量
    
        image_height, image_width = size
    
        x_image = tf.reshape(x, shape=[-1, image_height, image_width, 1])
    
    
    
        # 第一层
    
        # filter定义为3x3x1, 输出32个特征, 即32个filter
    
        w_conv1 = weight_variable([3, 3, 1, 32])
    
        b_conv1 = bias_variable([32])
    
        # rulu激活函数
    
        h_conv1 = tf.nn.relu(tf.nn.bias_add(conv2d(x_image, w_conv1), b_conv1))
    
        # 池化
    
        h_pool1 = max_pool_2x2(h_conv1)
    
        # dropout防止过拟合
    
        h_drop1 = tf.nn.dropout(h_pool1, keep_prob)
    
    
    
        # 第二层
    
        w_conv2 = weight_variable([3, 3, 32, 64])
    
        b_conv2 = bias_variable([64])
    
        h_conv2 = tf.nn.relu(tf.nn.bias_add(conv2d(h_drop1, w_conv2), b_conv2))
    
        h_pool2 = max_pool_2x2(h_conv2)
    
        h_drop2 = tf.nn.dropout(h_pool2, keep_prob)
    
    
    
        # 第三层
    
        w_conv3 = weight_variable([3, 3, 64, 64])
    
        b_conv3 = bias_variable([64])
    
        h_conv3 = tf.nn.relu(tf.nn.bias_add(conv2d(h_drop2, w_conv3), b_conv3))
    
        h_pool3 = max_pool_2x2(h_conv3)
    
        h_drop3 = tf.nn.dropout(h_pool3, keep_prob)
    
    
    
        # 全连接层
    
        image_height = int(h_drop3.shape[1])
    
        image_width = int(h_drop3.shape[2])
    
        w_fc = weight_variable([image_height*image_width*64, 1024])
    
        b_fc = bias_variable([1024])
    
        h_drop3_re = tf.reshape(h_drop3, [-1, image_height*image_width*64])
    
        h_fc = tf.nn.relu(tf.add(tf.matmul(h_drop3_re, w_fc), b_fc))
    
        h_drop_fc = tf.nn.dropout(h_fc, keep_prob)
    
    
    
        # 全连接层(输出层)
    
        w_out = weight_variable([1024, len(captcha_list)*captcha_len])
    
        b_out = bias_variable([len(captcha_list)*captcha_len])
    
        y_conv = tf.add(tf.matmul(h_drop_fc, w_out), b_out)
    
        return y_conv
    
    
    
    # 最小化loss
    
    def optimize_graph(y, y_conv):
    
        '''
    
        优化计算图
    
        :param y:
    
        :param y_conv:
    
        :return:
    
        '''
    
        # 交叉熵计算loss
    
        # sigmod_cross适用于每个类别相互独立但不互斥,如图中可以有字母和数字
    
        loss = tf.reduce_mean(tf.nn.sigmoid_cross_entropy_with_logits(logits=y_conv, labels=y))
    
        # 最小化loss优化
    
        optimizer = tf.train.AdamOptimizer(learning_rate=0.001).minimize(loss)
    
        return optimizer
    
    
    
    # 偏差计算
    
    def accuracy_graph(y, y_conv, width=len(CAPTCHA_LIST), height=CAPTCHA_LEN):
    
        '''
    
        :param y:
    
        :param y_conv:
    
        :param width:
    
        :param height:
    
        :return:
    
        '''
    
        # 预测值
    
        predict = tf.reshape(y_conv, [-1, height, width])
    
        max_predict_idx = tf.argmax(predict, 2)
    
        # 标签
    
        label = tf.reshape(y, [-1, height, width])
    
        max_label_idx = tf.argmax(label, 2)
    
        correct_p = tf.equal(max_predict_idx, max_label_idx)
    
        accuracy = tf.reduce_mean(tf.cast(correct_p, tf.float32))
    
        return accuracy
    
    
    
    # 训练cnn
    
    def train(height=CAPTCHA_HEIGHT, width=CAPTCHA_WIDTH, y_size=len(CAPTCHA_LIST)*CAPTCHA_LEN):
    
        '''
    
        :param height:
    
        :param width:
    
        :param y_size:
    
        :return:
    
        '''
    
        acc_rate = 0.95
    
        # 按照图片大小申请占位符
    
        x = tf.placeholder(tf.float32, [None, height * width])
    
        y = tf.placeholder(tf.float32, [None, y_size])
    
        # 防止过拟合 训练时启用 测试时不启用
    
        keep_prob = tf.placeholder(tf.float32)
    
        # cnn模型
    
        y_conv = cnn_graph(x, keep_prob, (height, width))
    
        # 最优化
    
        optimizer = optimize_graph(y, y_conv)
    
        # 偏差
    
        accuracy = accuracy_graph(y, y_conv)
    
        # 启动会话.开始训练
    
        saver = tf.train.Saver()
    
        sess = tf.Session()
    
        sess.run(tf.global_variables_initializer())
    
        step = 0
    
        while 1:
    
            # 每批次64个样本
    
            batch_x, batch_y = next_batch(64)
    
            sess.run(optimizer, feed_dict={x: batch_x, y: batch_y, keep_prob: 0.75})
    
            # 每训练一百次测试一次
    
            if step % 100 == 0:
    
                batch_x_test, batch_y_test = next_batch(100)
    
                acc = sess.run(accuracy, feed_dict={x: batch_x_test, y: batch_y_test, keep_prob: 1.0})
    
                print(datetime.now().strftime('%c'), ' step:', step, ' accuracy:', acc)
    
                # 偏差满足要求,保存模型
    
                if acc > acc_rate:
    
                    model_path = os.getcwd() + os.sep + str(acc_rate) + "captcha.model"
    
                    saver.save(sess, model_path, global_step=step)
    
                    acc_rate += 0.01
    
                    if acc_rate > 0.99: break
    
            step += 1
    
        sess.close()
    
    
    
    if __name__ == '__main__':
    
        train()

    刚开始准确度很低,但不能就此断定程序写错了,要运行久一点才能说明问题。前3000样本的准确度都比较低也基本上变化不大,3000样本以后就有点起色了,准确度在缓缓上升。到13000个样本左右时,准确度达到0.9左右。到20000个样本左右时,准确度达到0.95左右。

    我这里用CPU花了7个小时训练了20600个样本才达到95%的准确率。保存的模型包括4个文件,如下图。

     

    cnn_test.py(测试模型)

    import tensorflow as tf
    
    from captchaCnn.cnn_train import cnn_graph
    
    from captchaCnn.captcha_create import gen_captcha_text_and_image
    
    from captchaCnn.captcha_process import vec2text, convert2gray
    
    from captchaCnn.captcha_process import CAPTCHA_LIST, CAPTCHA_WIDTH, CAPTCHA_HEIGHT, CAPTCHA_LEN
    
    
    
    # 验证码图片转化为文本
    
    def captcha2text(image_list, height=CAPTCHA_HEIGHT, width=CAPTCHA_WIDTH):
    
        '''
    
        :param image_list:
    
        :param height:
    
        :param width:
    
        :return:
    
        '''
    
        x = tf.placeholder(tf.float32, [None, height * width])
    
        keep_prob = tf.placeholder(tf.float32)
    
        y_conv = cnn_graph(x, keep_prob, (height, width))
    
        saver = tf.train.Saver()
    
        with tf.Session() as sess:
    
            saver.restore(sess, tf.train.latest_checkpoint('.'))
    
            predict = tf.argmax(tf.reshape(y_conv, [-1, CAPTCHA_LEN, len(CAPTCHA_LIST)]), 2)
    
            vector_list = sess.run(predict, feed_dict={x: image_list, keep_prob: 1})
    
            vector_list = vector_list.tolist()
    
            text_list = [vec2text(vector) for vector in vector_list]
    
            return text_list
    
    
    
    if __name__ == '__main__':
    
        text, image = gen_captcha_text_and_image()
    
        image = convert2gray(image)
    
        image = image.flatten() / 255
    
        pre_text = captcha2text([image])
    
        print('Label:', text, ' Predict:', pre_text)

     

    五,总结

    CNN识别验证码的优点

    1.模型高效

    经过不算特别长的时间的训练可以达到很高的识别准确度。

    2.模型存粹

    不需要额外的OCR软件或验证码识别API等。

     

    CNN识别验证码的缺点

    1.样本获取难

    若想将模型实际应用,那么训练样本的获得就是个问题。要么找不到已知验证码的生成器,要么找到的验证码没有文本标签,需要通过人工打码或打码平台等获得验证码标签。

    2.灵活性不高

    CNN识别验证码不同于将图片进行分割等处理的识别方法,而直接对整个图片进行学习。因此只要验证码的风格与原样本不同时,识别准确率就比较低。

    在CNN识别验证码中,卷积层对于图像是没有尺寸限制要求的。卷积仅于自身的卷积核大小,维度有关,输入向量大小对其无影响。但全连接层的输入是固定大小的,如果输入向量的维数不固定,那么全连接的权值参数的量也是不固定的,就会造成网络的动态变化,无法实现参数训练的目的。因此即使是同样的验证码如果改变了图片的大小,程序就会报错。不过这个问题貌似是可以解决的,具体请参见 https://blog.csdn.net/zhangjunhit/article/details/53909548

     

    六,写在最后

    本人第一次做这个,知识精力有限,如有疏漏之处还望各位大佬指正。

     

     

    展开全文
  • 请参考我的博客:基于CNN的为数字验证码识别,内容包含验证码去噪,字符分割,CNN搭建,测试集验证,在线识别
  • 基于pytorch和CNN的图片验证码识别

    千次阅读 2020-06-19 20:31:41
    是一种区分用户是计算机还是人的公共全自动程序,本文利用新兴的深度学习框架PyTorch,并结合卷积神经网络(CNN)搭建的模型进行训练,对于收集到的由数字和字母(区分大小写)组成的复杂的图片验证码识别取得了...
  • Tensorflow搭建CNN实现验证码识别

    千次阅读 2020-03-25 13:53:14
    ​整个项目代码分为三部分: Generrate_Captcha: ...cnn_model:卷积神经网络; driver:模型训练及评估。 1、配置项 class Config(object): width = 160 # 验证码图片的宽 height = 60 # 验证码图片的高 ...
  • 【Matlab验证码识别】CNN验证码识别【含源码 098期】 二、matlab版本及参考文献 1 matlab版本 2014a 2 参考文献 [1] 蔡利梅.MATLAB图像处理——理论、算法与实例分析[M].清华大学出版社,2020. [2]杨丹,赵海滨,龙哲....
  • Tensorflow是目前最流行的深度学习框架,我们可以用它来搭建自己的卷积神经网络并训练自己的分类器,本文介绍怎样使用Tensorflow构建自己的CNN,怎样训练用于简单的验证码识别的分类器。本文假设你已经安装好了...
  • 最近做一个小玩意需要识别验证码,之前从来没有接触过识别验证码这块,这可难倒了我。所以,在网上搜索如何识别验证码,许多前辈写的博文教会了我。怕以后又忘记了,故此写篇随笔记录。 我要识别验证码是一种非常...
  • 深度学习实战之CNN验证码识别

    千次阅读 2018-12-11 01:54:49
    我们要使用卷积神经网络实现验证码识别,具体流程大致为: 1、使用python的captcha模块生成验证码图片。 2、使用tensorflow搭建神经网络模型。 3、将数据喂入神经网络进行训练。 4、保存训练好的网络模型。 下面...
  • 人工神经网络 基于CNN卷积神经网络 基于Python 实现图片验证码识别
  • 之前我们做了一个验证码识别逻辑回归案例,我们将使用该案例中的‘cut_number/’文件夹下的数据作为卷积网络的训练数据。 在使用这些数据之前,我们要对数据进行处理,以对应卷积网络要求的数据格式! 数据处理分为...
  • 解压后运行interface.fig。含有界面,分为网络训练、网络测试、验证码识别三个功能。
  • 基于CNN+keras的验证码识别项目

    千次阅读 2019-06-06 15:33:29
    构建CNN神经网络并开始训练 import numpy as np import os from keras.preprocessing import image from keras.models import Model from keras.layers import Dense, Dropout, Flatten, Input, concatenate ,...
  • 本项目针对字符型图片验证码,使用张量流实现卷积神经网络,进行验证码识别。项目封装了比较通用的校验,训练,验证,识别,API模块,极大地减少了识别字符型验证码花费的时间和能量。 如果您在使用过程中出现了一个...
  • lstm+ctc+cnn架构,进行不定长度验证码识别,达到不分割字符而识别验证码内容的效果。验证码内容包含了大小字母以及数字,并增加点、线、颜色、位置、字体等干扰项。本项目对gru +ctc+cnn
  • cnn进行验证码识别

    2019-11-20 15:50:22
    验证码识别程序 :return: “”" # 1.读取验证码的数据文件 label_batch [100, 4] image_batch, label_batch = read_and_decode() # 2.通过输入图片特征数据,建立模型,得出预测结果 # 一层全连接神经网络进行...
  • 自定义cnn网络训练的验证码识别模型,cnn网络验证码识别训练模型
  • 目录python生成验证码→处理验证码→建立CNN模型训练→测试模型准确率→识别验证码前言一、生成验证码二、处理验证码三、建立CNN模型训练四、测试CNN模型的准确率五、识别验证码写在最后 前言 本文使用了pillow库来...
  • 北京 上海巡回站 | NVIDIA DLI深度学习培训2018年1月26/1月12日NVIDIA 深度学习学院 带你快速进入火热的DL领域阅读全文 >正文共2929个字,17张图,预计阅读时间:8分钟。...目前,在图像识别和视觉
  • 用递归神经网络采用端到端识别图片文字,递归...本 Chat 的例子用验证码来做识别,可用于文字识别、车牌识别、手写字识别、各种证件识别。 本次 Chat ,我将分享如下内容: RNN 原理,递归的基础,重点讲向前传播(...
  • 深度神经网络实现验证码识别 前段时间接到了一个小项目,要做一个验证码的识别,验证码包含数字和英文字母,实现识别的过程用到了CNN网络,最后单个字符的准确率达到90%以上。 准备数据集 登录界面有一个验证码的...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,574
精华内容 629
关键字:

cnn验证码识别