极简验证码识别实战代码

  1. 安装依赖(只需运行一次)
    bash
    pip install tensorflow==2.8.0 opencv-python pillow numpy matplotlib
  2. 完整可运行代码(保存为captcha_recognition.py)
    python
    import cv2
    import numpy as np
    from PIL import Image, ImageDraw, ImageFont
    import random
    import string
    import os
    from tensorflow import keras
    from tensorflow.keras import layers
    更多内容访问ttocr.com或联系1436423940

配置参数

CHAR_SET = string.digits + string.ascii_uppercase # 数字+大写字母
CAPTCHA_LEN = 4 # 验证码长度
IMG_WIDTH, IMG_HEIGHT = 160, 60 # 图片尺寸
FONT_PATH = 'arial.ttf' if os.path.exists('arial.ttf') else None

1. 验证码生成函数

def generate_captcha(text=None):
"""生成单张验证码图片"""
text = text or ''.join(random.choices(CHAR_SET, k=CAPTCHA_LEN))
img = Image.new('RGB', (IMG_WIDTH, IMG_HEIGHT), color=(255, 255, 255))
draw = ImageDraw.Draw(img)

try:
    font = ImageFont.truetype(FONT_PATH, 36) if FONT_PATH else ImageFont.load_default()
except:
    font = ImageFont.load_default()

# 绘制文本(带随机偏移)
x = 10
for char in text:
    y = random.randint(5, IMG_HEIGHT-40)
    angle = random.randint(-15, 15)
    char_img = Image.new('RGBA', (40, 40), (0, 0, 0, 0))
    char_draw = ImageDraw.Draw(char_img)
    char_draw.text((0, 0), char, font=font, fill=(0, 0, 0))
    char_img = char_img.rotate(angle, expand=1)
    img.paste(char_img, (x, y), char_img)
    x += 30 + random.randint(-5, 5)

# 添加干扰线
for _ in range(3):
    x1, y1 = random.randint(0, IMG_WIDTH), random.randint(0, IMG_HEIGHT)
    x2, y2 = random.randint(0, IMG_WIDTH), random.randint(0, IMG_HEIGHT)
    draw.line([(x1, y1), (x2, y2)], fill=(random.randint(0, 255), random.randint(0, 255), random.randint(0, 255)), width=1)

# 添加噪点
for _ in range(100):
    img.putpixel((random.randint(0, IMG_WIDTH-1), random.randint(0, IMG_HEIGHT-1)), 
                (random.randint(0, 255), random.randint(0, 255), random.randint(0, 255)))

return text, np.array(img)

2. 生成数据集

def generate_dataset(size=1000, output_dir='captchas'):
if not os.path.exists(output_dir):
os.makedirs(output_dir)

with open(f'{output_dir}/labels.txt', 'w') as f:
    for i in range(size):
        text, img = generate_captcha()
        cv2.imwrite(f'{output_dir}/{i}_{text}.png', cv2.cvtColor(img, cv2.COLOR_RGB2BGR))
        f.write(f'{i}_{text}.png\t{text}\n')

3. 数据加载与预处理

def load_dataset(data_dir='captchas'):
with open(f'{data_dir}/labels.txt') as f:
lines = f.read().splitlines()

images, labels = [], []
char_to_num = {c:i for i,c in enumerate(CHAR_SET)}

for line in lines:
    path, text = line.split('\t')
    img = cv2.imread(f'{data_dir}/{path}', cv2.IMREAD_GRAYSCALE)
    img = cv2.resize(img, (IMG_WIDTH, IMG_HEIGHT))
    img = img.astype(np.float32) / 255.0
    images.append(np.expand_dims(img, axis=-1))
    labels.append([char_to_num[c] for c in text])

return np.array(images), np.array(labels)

4. 构建模型

def build_model():
input_img = layers.Input(shape=(IMG_HEIGHT, IMG_WIDTH, 1))

# CNN部分
x = layers.Conv2D(32, (3,3), activation='relu', padding='same')(input_img)
x = layers.MaxPooling2D((2,2))(x)
x = layers.Conv2D(64, (3,3), activation='relu', padding='same')(x)
x = layers.MaxPooling2D((2,2))(x)

# 转换为序列
x = layers.Reshape(((IMG_WIDTH//4), (IMG_HEIGHT//4)*64))(x)

# RNN部分
x = layers.Bidirectional(layers.LSTM(128, return_sequences=True))(x)
x = layers.Bidirectional(layers.LSTM(64, return_sequences=True))(x)

# 输出层
output = layers.Dense(len(CHAR_SET), activation='softmax')(x)

return keras.Model(inputs=input_img, outputs=output)

5. 训练与评估

def train_and_evaluate():
# 生成数据
generate_dataset(1000)

# 加载数据
X, y = load_dataset()
X_train, X_test = X[:800], X[800:]
y_train, y_test = y[:800], y[800:]

# 构建模型
model = build_model()
model.compile(optimizer='adam',
              loss='sparse_categorical_crossentropy',
              metrics=['accuracy'])

# 训练
model.fit(X_train, y_train,
          validation_data=(X_test, y_test),
          epochs=20,
          batch_size=32)

# 评估
y_pred = np.argmax(model.predict(X_test), axis=-1)
char_acc = np.mean(y_pred.flatten() == y_test.flatten())
captcha_acc = np.mean(np.all(y_pred == y_test, axis=1))
print(f"\n字符准确率: {char_acc:.2%}")
print(f"验证码准确率: {captcha_acc:.2%}")

return model

6. 预测函数

def predict_captcha(model, image_path):
img = cv2.imread(image_path, cv2.IMREAD_GRAYSCALE)
img = cv2.resize(img, (IMG_WIDTH, IMG_HEIGHT))
img = img.astype(np.float32) / 255.0
img = np.expand_dims(img, axis=(0, -1))

pred = model.predict(img)
pred_text = ''.join([CHAR_SET[i] for i in np.argmax(pred[0], axis=-1)])
return pred_text

主程序

if name == 'main':
model = train_and_evaluate()

# 测试预测
test_img = 'captchas/0_ABCD.png'  # 替换为你的测试图片路径
if os.path.exists(test_img):
    print(f"\n测试图片识别结果: {predict_captcha(model, test_img)}")
else:
    print("\n训练完成!使用predict_captcha(model, '图片路径')进行预测")
posted @ 2025-05-18 13:03  ttocr、com  阅读(17)  评论(0)    收藏  举报