CNN簡單驗證碼訓練識別

config.py

from os.path import join
f = open('./chinese.txt', 'r', encoding='utf-8')#加載3500個常用漢字
CH_CHAR = []
lines = f.read()
f.close()
CH_CHAR = eval(lines)

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

# 如果驗證碼長度小於4, '_'用來補齊
gen_char_set = number+ ALPHABET + CH_CHAR + ['_']

IMAGE_HEIGHT = 76
IMAGE_WIDTH = 420

MAX_CAPTCHA = 33
CHAR_SET_LEN = len(gen_char_set)

run.py

#encoding:utf-8
from PIL import Image
import train
import sys


def run(image_path):

    image = Image.open(image_path)
    image = train.convert2gray(image)
    image = image.flatten() / 255
    predict_text = train.crack_captcha(image)

    file = open('C:/Users/Administrator/Desktop/' + predict_text + '.txt', 'w')
    file.write(predict_text)

    print("succ")

    return "".join(predict_text)

run(sys.argv[1])


"""
image_path = sys.argv[1]
image = Image.open(image_path)
image = train.convert2gray(image)
image = image.flatten() / 255
predict_text = train.crack_captcha(image)

file = open('C:/Users/Administrator/Desktop/' + predict_text + '.txt', 'w')
file.write(predict_text)

"""

train.py

#encoding:utf-8


import tensorflow as tf
import numpy as np
from config import IMAGE_WIDTH, IMAGE_HEIGHT, MAX_CAPTCHA, CHAR_SET_LEN, gen_char_set
import os
import random
import math
from PIL import Image
import sys

def convert2gray(image):
    if len(image.shape) > 2:
        gray = np.mean(image, -1)
        #上面的轉換方法較快,正規轉法如下
        #r, g, b = image[:, :, 0], image[:, :, 1], image[:, :, 2]
        #gray = 0.2989 * r + 0.5870 * g + 0.1140 * b
        return gray
    else:
        return image

def gen_captch_text_and_image():
    all_image = os.listdir("F:/D/")
    random_file = random.randint(0, 5)
    base = os.path.basename("F:/D/" + all_image[random_file])
    text = os.path.splitext(base)[0]
    image = Image.open("F:/D/" + all_image[random_file])

    #image.save("F:/E/" + text + ".png")

    image = np.array(image)
    return text, image

"""
cnn在圖像大小是2的倍數時性能最高, 如果你用的圖像大小不是2的倍數,可以在圖像邊緣補無用像素。
np.pad(image,((2,3),(2,2)), 'constant', constant_values=(255,))  # 在圖像上補2行,下補3行,左補2行,右補2行
"""

"""
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
        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))
    return "".join(text)
"""

def text2vec(text):
    #
    text_len = len(text)
    if text_len > MAX_CAPTCHA:
        print("warming: ", text)
        raise ValueError('驗證碼最長MAX_CAPTCHA個字符')
    #
    vector = np.zeros(MAX_CAPTCHA * CHAR_SET_LEN)
    for i, c in enumerate(text):
        #
        idx = i * CHAR_SET_LEN + gen_char_set.index(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
        char_idx = c % CHAR_SET_LEN
        char_code = gen_char_set[char_idx]
        text.append(char_code)
    return "".join(text)

def get_next_batch(batch_size = 64):
    batch_x = np.zeros([batch_size, IMAGE_HEIGHT * IMAGE_WIDTH])
    batch_y = np.zeros([batch_size, MAX_CAPTCHA * CHAR_SET_LEN])

    for i in range(batch_size):
        text, image = gen_captch_text_and_image()
        image = convert2gray(image)

        batch_x[i, :] = image.flatten() / 255
        batch_y[i, :] = text2vec(text)

        str = text

    return batch_x, batch_y, str

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)

def crack_captcha_cnn(w_alpha = 0.01, b_alpha = 0.1):
    x = tf.reshape(X, shape=[-1, IMAGE_HEIGHT, IMAGE_WIDTH, 1])

    L1_NEU_NUM = 128
    L2_NEU_NUM = 256
    L3_NEU_NUM = 512
    L4_NEU_NUM = 512

    CONV_CORE_SIZE = 5
    MAX_POOL_NUM = 4
    FULL_LAYER_FEATURE_NUM = 1024

    w_c1 = tf.Variable(w_alpha * tf.random_normal([CONV_CORE_SIZE, CONV_CORE_SIZE, 1, L1_NEU_NUM]))
    b_c1 = tf.Variable(b_alpha * tf.random_normal([L1_NEU_NUM]))
    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([CONV_CORE_SIZE, CONV_CORE_SIZE, L1_NEU_NUM, L2_NEU_NUM]))
    b_c2 = tf.Variable(b_alpha * tf.random_normal([L2_NEU_NUM]))
    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([CONV_CORE_SIZE, CONV_CORE_SIZE, L2_NEU_NUM, L3_NEU_NUM]))
    b_c3 = tf.Variable(b_alpha * tf.random_normal([L3_NEU_NUM]))
    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)

    w_c4 = tf.Variable(w_alpha * tf.random_normal([CONV_CORE_SIZE, CONV_CORE_SIZE, L3_NEU_NUM, L4_NEU_NUM]))
    b_c4 = tf.Variable(b_alpha * tf.random_normal([L4_NEU_NUM]))
    conv4 = tf.nn.relu(tf.nn.bias_add(tf.nn.conv2d(conv3, w_c4, strides=[1, 1, 1, 1], padding="SAME"), b_c4))
    conv4 = tf.nn.max_pool(conv4, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding="SAME")
    conv4 = tf.nn.dropout(conv4, keep_prob)

    # Fully connected layer
    r = int(math.ceil(IMAGE_HEIGHT / (2 ** MAX_POOL_NUM)) * math.ceil(IMAGE_WIDTH / (2 ** MAX_POOL_NUM)) * L4_NEU_NUM)
    w_d = tf.Variable(w_alpha * tf.random_normal([r, FULL_LAYER_FEATURE_NUM]))
    b_d = tf.Variable(b_alpha * tf.random_normal([FULL_LAYER_FEATURE_NUM]))
    dense = tf.reshape(conv4, [-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([FULL_LAYER_FEATURE_NUM, 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 = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(output, Y))
    loss = tf.reduce_mean(tf.nn.sigmoid_cross_entropy_with_logits(logits=output, labels=Y))
    # 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)
    accuray = 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, str = get_next_batch(64)
            _, loss_ = sess.run([optimizer, loss], feed_dict={X: batch_x, Y: batch_y, keep_prob: 0.75})

            print("**", step, loss_, str)

            if step % 5 == 0:
                batch_x_test, batch_y_test, str = get_next_batch(100)
                acc = sess.run(accuray, feed_dict={X: batch_x_test, Y: batch_y_test, keep_prob: 1.})
                print(step, acc)

                if acc > 0.6:
                    saver.save(sess, "./crack_captch.model", global_step=step)
                    break

            step += 1

#train_crack_captcha_cnn()


def crack_captcha(captcha_image):
    output = crack_captcha_cnn()

    saver = tf.train.Saver()
    with tf.Session() as sess:
        saver.restore(sess, tf.train.latest_checkpoint('.'))

        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()
        vector = np.zeros(MAX_CAPTCHA * CHAR_SET_LEN)
        i = 0
        for n in text:
            vector[i * CHAR_SET_LEN + n] = 1
            i += 1
        return vec2text(vector)


def crack_captcha2():
    output = crack_captcha_cnn()

    saver = tf.train.Saver()
    with tf.Session() as sess:
        saver.restore(sess, tf.train.latest_checkpoint('.'))
        n = 1
        while n <= 10:
            text, image = gen_captch_text_and_image()
            image = image.flatten() / 255
            predict = tf.argmax(tf.reshape(output, [-1, MAX_CAPTCHA, CHAR_SET_LEN]), 2)
            text_list = sess.run(predict, feed_dict={X: [image], keep_prob: 1})
            vec = text_list[0].tolist()

            predict_text = vec2text(vec)
            print("正確:{}  預測:{}".format(text, predict_text))
            n += 1

#crack_captcha2()

def main():
    text, image = gen_captch_text_and_image()
    image = convert2gray(image)
    image = image.flatten() / 255
    predict_text = crack_captcha(image)
    print("正確:{}  預測:{}".format(text, predict_text))
#main()

def run(image_path):
    image = Image.open(image_path)
    image = convert2gray(image)
    image = image.flatten() / 255
    predict_text = crack_captcha(image)
    return "".join(predict_text)

run(sys.argv[1])


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章