验证码识别系统开发精简版
一、核心代码实现
- 验证码生成
python
from PIL import Image, ImageDraw, ImageFont
import random
import string
def generate_captcha(length=4):
img = Image.new('RGB', (120, 40), (255, 255, 255))
draw = ImageDraw.Draw(img)
text = ''.join(random.choice(string.ascii_uppercase + string.digits) for _ in range(length))
更多内容访问ttocr.com或联系1436423940
# 绘制文字
font = ImageFont.truetype("arial.ttf", 24)
x = 10
for ch in text:
y = random.randint(5, 15)
angle = random.randint(-15, 15)
char_img = Image.new('RGBA', (30, 30), (0, 0, 0, 0))
char_draw = ImageDraw.Draw(char_img)
char_draw.text((5, 0), ch, font=font, fill=(0, 0, 0))
char_img = char_img.rotate(angle, expand=1)
img.paste(char_img, (x, y), char_img)
x += 25 + random.randint(-3, 3)
# 添加干扰线
for _ in range(3):
draw.line([(random.randint(0, 120), random.randint(0, 40))]*2,
fill=(random.randint(0, 180),)*3, width=1)
return text, img
- 模型构建与训练
python
import tensorflow as tf
import numpy as np
def build_model(char_count):
model = tf.keras.Sequential([
tf.keras.layers.Conv2D(32, (3,3), activation='relu', input_shape=(40, 120, 1)),
tf.keras.layers.MaxPooling2D((2,2)),
tf.keras.layers.Conv2D(64, (3,3), activation='relu'),
tf.keras.layers.MaxPooling2D((2,2)),
tf.keras.layers.Flatten(),
tf.keras.layers.Dense(128, activation='relu'),
tf.keras.layers.Dense(char_count*4),
tf.keras.layers.Reshape((4, char_count)),
tf.keras.layers.Softmax()
])
model.compile(optimizer='adam', loss='sparse_categorical_crossentropy', metrics=['accuracy'])
return model
训练示例
def train():
char_set = string.ascii_uppercase + string.digits
char_to_idx = {c:i for i,c in enumerate(char_set)}
# 生成训练数据
X, y = [], []
for _ in range(1000):
text, img = generate_captcha()
X.append(np.array(img.convert('L'))/255.0)
y.append([char_to_idx[c] for c in text])
model = build_model(len(char_set))
model.fit(np.expand_dims(X, -1), np.array(y), epochs=10, batch_size=32)
model.save('captcha_model.h5')
- 预测接口
python
from flask import Flask, request, jsonify
app = Flask(name)
model = tf.keras.models.load_model('captcha_model.h5')
char_set = string.ascii_uppercase + string.digits
@app.route('/predict', methods=['POST'])
def predict():
file = request.files['file']
img = Image.open(file.stream).convert('L').resize((120, 40))
img_array = np.array(img)/255.0
pred = model.predict(np.expand_dims(img_array, axis=(0,-1)))
result = ''.join([char_set[i] for i in np.argmax(pred[0], axis=1)])
return jsonify({'result': result})
if name == 'main':
app.run(host='0.0.0.0', port=5000)
二、关键优化点
数据增强
python
def augment_image(img):
# 随机旋转
img = img.rotate(random.randint(-5,5))
# 添加高斯噪声
noise = np.random.normal(0, 0.05, img.size)
img = Image.fromarray(np.clip(np.array(img) + noise*255, 0, 255).astype(np.uint8))
return img
模型量化
python
converter = tf.lite.TFLiteConverter.from_keras_model(model)
converter.optimizations = [tf.lite.Optimize.DEFAULT]
tflite_model = converter.convert()
with open('model.tflite', 'wb') as f:
f.write(tflite_model)
三、部署建议
使用Gunicorn部署Flask应用:
bash
gunicorn -w 4 -b :5000 predict:app
浙公网安备 33010602011771号