Files
CaptchBreaker/CLAUDE.md

26 KiB
Raw Permalink Blame History

CLAUDE.md - 验证码识别多模型系统 (CaptchaBreaker)

项目概述

构建一个本地验证码识别系统,采用 调度模型 + 多专家模型 的两级架构。调度模型负责分类验证码类型,专家模型负责具体识别。所有模型轻量化设计,最终导出 ONNX 用于部署。

技术栈

  • Python 3.10-3.12
  • uv (包管理,依赖定义在 pyproject.toml)
  • PyTorch 2.x (训练)
  • ONNX + ONNXRuntime (推理部署)
  • Pillow (图像处理)
  • OpenCV (可选,滑块求解与相关测试)
  • FastAPI (可选,提供 HTTP 识别服务)

当前命令入口

  • 优先使用 uv run captcha ... 调用 CLIpyproject.toml 已将 captcha 映射到 cli:main
  • 额外依赖按需安装:
    • uv sync --extra serverHTTP 服务
    • uv sync --extra cvOpenCV / 滑块 solver
    • uv sync --extra devpytest
  • Linux x86_64 环境通过 pyproject.tomltool.uv.sources / tool.uv.index 固定从官方 cu121 index 安装 torch==2.5.1torchvision==0.20.1
  • 该组合已验证可在 GTX 1050 Ti (sm_61) 上执行 CUDA仓库之前解析到的 torch 2.10.0 + cu128 不兼容这张卡
  • Python 3.10 环境下保持 onnxruntime < 1.24,避免 uv 解析到无 cp310 wheel 的版本
  • 当前 CLI 子命令包括:generatetrainexportpredictpredict-dirservegenerate-solvertrain-solversolvetrain-funcaptchapredict-funcaptcha

项目结构

captcha-breaker/
├── CLAUDE.md
├── pyproject.toml               # 项目配置与依赖 (uv 管理)
├── config.py                    # 全局配置 (字符集、图片尺寸、路径等)
├── data/
│   ├── synthetic/               # 合成训练数据 (自动生成,不入 git)
│   │   ├── normal/              # 普通字符型
│   │   ├── math/                # 算式型
│   │   ├── 3d_text/             # 3D立体文字型
│   │   ├── 3d_rotate/           # 3D旋转型
│   │   └── 3d_slider/           # 3D滑块型
│   ├── real/                    # 真实验证码样本 (手动标注)
│   │   ├── normal/
│   │   ├── math/
│   │   ├── 3d_text/
│   │   ├── 3d_rotate/
│   │   ├── 3d_slider/
│   │   └── funcaptcha/
│   │       └── 4_3d_rollball_animals/
│   ├── classifier/              # 调度分类器训练数据 (混合各类型)
│   └── solver/                  # Solver 训练数据
│       ├── slide/               # 滑块缺口检测训练数据
│       └── rotate/              # 旋转角度回归训练数据
├── generators/
│   ├── __init__.py
│   ├── base.py                  # 生成器基类
│   ├── normal_gen.py            # 普通字符验证码生成器
│   ├── math_gen.py              # 算式验证码生成器 (如 3+8=?)
│   ├── threed_gen.py            # 3D立体文字验证码生成器
│   ├── threed_rotate_gen.py     # 3D旋转验证码生成器
│   ├── threed_slider_gen.py     # 3D滑块验证码生成器
│   ├── slide_gen.py             # 滑块缺口训练数据生成器
│   └── rotate_solver_gen.py     # 旋转求解器训练数据生成器
├── models/
│   ├── __init__.py
│   ├── lite_crnn.py             # 轻量 CRNN (用于普通字符和算式)
│   ├── classifier.py            # 调度分类模型
│   ├── threed_cnn.py            # 3D文字验证码专用模型 (更深的CNN)
│   ├── regression_cnn.py        # 回归CNN (3D旋转+滑块, ~1MB)
│   ├── gap_detector.py          # 滑块缺口检测CNN (~1MB)
│   ├── rotation_regressor.py    # 旋转角度回归 sin/cos (~2MB)
│   └── fun_captcha_siamese.py   # FunCaptcha 专项 Siamese
├── training/
│   ├── __init__.py
│   ├── train_classifier.py      # 训练调度模型
│   ├── train_normal.py          # 训练普通字符识别
│   ├── train_math.py            # 训练算式识别
│   ├── train_3d_text.py         # 训练3D文字识别
│   ├── train_3d_rotate.py       # 训练3D旋转回归
│   ├── train_3d_slider.py       # 训练3D滑块回归
│   ├── train_slide.py           # 训练滑块缺口检测
│   ├── train_rotate_solver.py   # 训练旋转角度回归
│   ├── train_funcaptcha_rollball.py # 训练 4_3d_rollball_animals
│   ├── train_utils.py           # CTC 训练通用逻辑
│   ├── train_regression_utils.py # 回归训练通用逻辑
│   ├── data_fingerprint.py      # 合成数据指纹 / manifest
│   └── dataset.py               # 通用 Dataset 类
├── inference/
│   ├── __init__.py
│   ├── pipeline.py              # 核心推理流水线 (调度+识别)
│   ├── fun_captcha.py           # FunCaptcha 专项推理
│   ├── export_onnx.py           # PyTorch → ONNX 导出脚本
│   ├── model_metadata.py        # ONNX sidecar metadata
│   └── math_eval.py             # 算式计算模块
├── solvers/                     # 交互式验证码求解器
│   ├── __init__.py
│   ├── base.py                  # 求解器基类
│   ├── slide_solver.py          # 滑块求解 (OpenCV + CNN)
│   └── rotate_solver.py         # 旋转求解 (ONNX sin/cos)
├── utils/
│   ├── __init__.py
│   └── slide_utils.py           # 滑块轨迹生成工具
├── checkpoints/                 # 训练产出的模型文件
│   ├── classifier.pth
│   ├── normal.pth
│   ├── math.pth
│   ├── threed_text.pth
│   ├── threed_rotate.pth
│   ├── threed_slider.pth
│   ├── gap_detector.pth
│   ├── rotation_regressor.pth
│   └── funcaptcha_rollball_animals.pth
├── onnx_models/                 # 导出的 ONNX 模型
│   ├── classifier.onnx
│   ├── classifier.meta.json
│   ├── normal.onnx
│   ├── math.onnx
│   ├── threed_text.onnx
│   ├── threed_rotate.onnx
│   ├── threed_slider.onnx
│   ├── gap_detector.onnx
│   ├── rotation_regressor.onnx
│   └── funcaptcha_rollball_animals.onnx
├── server.py                    # FastAPI 推理服务 (可选)
├── cli.py                       # 命令行入口
└── tests/
    ├── test_generators.py
    ├── test_models.py
    └── test_pipeline.py

核心架构设计

推理流水线

输入图片 → 预处理 → 调度分类器 → 路由到专家模型 → 后处理 → 输出结果
                         │
            ┌────────┬───┼───────┬──────────┐
            ▼        ▼   ▼       ▼          ▼
         normal    math  3d_text  3d_rotate  3d_slider
         (CRNN)   (CRNN) (CNN)   (RegCNN)   (RegCNN)
            │        │     │       │          │
            ▼        ▼     ▼       ▼          ▼
         "A3B8" "3+8=?"→11 "X9K2"  "135"      "87"

补充规则:

  • ONNX 导出时同步生成 <model>.meta.json,保存 OCR 字符集、分类器类别顺序、回归标签范围等部署时必需的信息。
  • inference/pipeline.py 优先读取 sidecar metadata缺失时才回退到 config.py,以兼容历史导出产物。

调度分类器 (classifier.py)

  • 任务: 图像分类,判断验证码属于哪个类型
  • 架构: 轻量 CNN3-4 层卷积 + 全局平均池化 + 全连接
  • 输入: 灰度图 1x64x128
  • 输出: softmax 概率分布,类别数 = 验证码类型数
  • 要求: 准确率 99%+,推理 < 5ms
  • 模型体积目标: < 500KB
class CaptchaClassifier(nn.Module):
    """
    轻量分类器,几层卷积即可区分不同类型验证码。
    不同类型验证码视觉差异大有无运算符、3D效果等分类很容易。
    """
    def __init__(self, num_types=5):
        # 4层卷积 + GAP + FC
        # Conv2d(1,16) -> Conv2d(16,32) -> Conv2d(32,64) -> Conv2d(64,64)
        # AdaptiveAvgPool2d(1) -> Linear(64, num_types)
        pass

普通字符识别专家 (lite_crnn.py - normal 模式)

  • 任务: 识别彩色字符验证码 (数字+字母混合)
  • 架构: CRNN + CTC
  • 字符集: 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ (36个包含易混淆字符按本地配置训练)
  • 输入: 灰度图 1x40x120
  • 输出: 字符序列,通过 CTC 贪心解码
  • 验证码特征: 浅色背景、彩色字符、轻微干扰线、字符有倾斜
  • 模型体积目标: < 2MB

算式识别专家 (lite_crnn.py - math 模式)

  • 任务: 识别算式验证码并计算结果
  • 架构: 复用 CRNN + CTC字符集不同
  • 字符集: 0123456789+-×÷=? (数字+运算符)
  • 输入: 灰度图 1x40x160 (算式通常更宽)
  • 输出: 识别出算式字符串,然后交给 math_eval.py 计算
  • 分两步: (1) OCR 识别 → "3+8=?" (2) 正则解析并计算 → 11
  • 模型体积目标: < 2MB
# math_eval.py 核心逻辑
def eval_captcha_math(expr: str) -> str:
    """
    解析并计算验证码算式。
    支持: 加减乘除,个位到两位数运算。
    输入: "3+8=?" 或 "12×3=?" 或 "15-7=?"
    输出: "11" 或 "36" 或 "8"
    用正则提取数字和运算符,不要用 eval()。
    """
    pass

3D立体文字识别专家 (threed_cnn.py)

  • 任务: 识别带 3D 透视/阴影效果的文字验证码
  • 架构: 更深的 CNN + CRNN或 ResNet-lite backbone
  • 输入: 灰度图 1x60x160
  • 需要更强的特征提取能力来处理透视变形和阴影
  • 模型体积目标: < 5MB

3D旋转识别专家 (regression_cnn.py - 3d_rotate 模式)

  • 任务: 预测旋转验证码的正确旋转角度
  • 架构: 轻量回归 CNN (4层卷积 + GAP + FC + Sigmoid)
  • 输入: 灰度图 1x80x80
  • 输出: [0,1] sigmoid 值,按 (0, 360) 缩放回角度
  • 标签范围: 0-359°
  • 模型体积目标: ~1MB

3D滑块识别专家 (regression_cnn.py - 3d_slider 模式)

  • 任务: 预测滑块拼图缺口的 x 偏移
  • 架构: 同上回归 CNN不同输入尺寸
  • 输入: 灰度图 1x80x240
  • 输出: [0,1] sigmoid 值,按 (10, 200) 缩放回像素偏移
  • 标签范围: 10-200px
  • 模型体积目标: ~1MB

FunCaptcha 专项专家 (fun_captcha_siamese.py)

  • 任务: 识别 task.question=4_3d_rollball_animals
  • 路由方式: 不走调度分类器,而是由 HTTP/CLI 的 question 直接路由到专项模型
  • 输入: 从整张 challenge 截图中裁出 reference 和 4 个 top-row candidates
  • 预处理: RGB 3x48x48
  • 架构: 共享编码器 Siamesecandidate/reference 特征拼接后输出单个匹配 logit
  • 训练方式: 每个 challenge 展开成 4 组 pair正确候选为正样本其余为负样本
  • 推理输出: 对 4 个候选分别打分,取 argmax返回 objects=[index]
  • 模型体积目标: < 2MB

数据生成器规范

基类 (base.py)

class BaseCaptchaGenerator:
    def generate(self, text=None) -> tuple[Image.Image, str]:
        """生成一张验证码,返回 (图片, 标签文本)"""
        raise NotImplementedError

    def generate_dataset(self, num_samples: int, output_dir: str):
        """批量生成,文件名格式: {label}_{index:06d}.png"""
        pass

普通字符生成器 (normal_gen.py)

模拟目标风格:

  • 浅色随机背景 (RGB 各通道 230-255)
  • 每个字符随机颜色 (深色: 蓝/红/绿/紫/棕等)
  • 字符数量: 4-5 个
  • 字符有 ±15° 随机旋转
  • 2-5 条浅色干扰线
  • 少量噪点
  • 可选轻微高斯模糊

算式生成器 (math_gen.py)

  • 生成形如 A op B = ? 的算式图片
  • A, B 范围: 1-30 的整数
  • op: +, -, ×, ÷ (除法只生成能整除的)
  • 确保结果为非负整数
  • 标签格式: 3+8 (存储算式本身,不存结果)
  • 视觉风格: 与目标算式验证码一致

3D文字生成器 (threed_gen.py)

  • 使用 Pillow 的仿射变换模拟 3D 透视
  • 添加阴影效果
  • 字符有深度感和倾斜
  • 字符旋转角度由 config.py GENERATE_CONFIG["3d_text"]["rotation_range"] 统一配置
  • 标签: 纯字符内容

3D旋转生成器 (threed_rotate_gen.py)

  • 圆盘上绘制字符 + 方向标记,随机旋转 0-359°
  • 标签 = 旋转角度(整数字符串)
  • 文件名格式: {angle}_{index:06d}.png

3D滑块生成器 (threed_slider_gen.py)

  • 纹理背景 + 拼图缺口 + 拼图块在左侧
  • 标签 = 缺口 x 坐标偏移(整数字符串)
  • 文件名格式: {offset}_{index:06d}.png

Slide Solver 目标约定

  • slide_gen.py / GapDetectorCNN / slide_solver.py 统一使用缺口中心点 x 作为输出语义
  • 训练时先按 solver 输入宽度归一化到 [0, 1],运行时再映射回原图宽度

训练规范

通用训练配置

# config.py 中定义
TRAIN_CONFIG = {
    'classifier': {
        'epochs': 30,
        'batch_size': 128,
        'lr': 1e-3,
        'scheduler': 'cosine',
        'synthetic_samples': 50000,  # 每类 10000 × 5 类
    },
    'normal': {
        'epochs': 50,
        'batch_size': 128,
        'lr': 1e-3,
        'scheduler': 'cosine',
        'synthetic_samples': 60000,
        'loss': 'CTCLoss',
    },
    'math': {
        'epochs': 50,
        'batch_size': 128,
        'lr': 1e-3,
        'scheduler': 'cosine',
        'synthetic_samples': 60000,
        'loss': 'CTCLoss',
    },
    '3d_text': {
        'epochs': 80,
        'batch_size': 64,
        'lr': 5e-4,
        'scheduler': 'cosine',
        'synthetic_samples': 80000,
        'loss': 'CTCLoss',
    },
    '3d_rotate': {
        'epochs': 60,
        'batch_size': 128,
        'lr': 1e-3,
        'scheduler': 'cosine',
        'synthetic_samples': 60000,
        'loss': 'SmoothL1',
    },
    '3d_slider': {
        'epochs': 60,
        'batch_size': 128,
        'lr': 1e-3,
        'scheduler': 'cosine',
        'synthetic_samples': 60000,
        'loss': 'SmoothL1',
    },
}

训练脚本要求

每个训练脚本必须:

  1. 训练开始前设置全局随机种子 (random/numpy/torch),使用 config.RANDOM_SEED,保证可复现
  2. 检查合成数据是否已生成,没有则自动调用生成器
  3. 支持混合真实数据 (如果 data/real/{type}/ 有文件)
  4. 使用数据增强: RandomAffine, ColorJitter, GaussianBlur, RandomErasing
  5. 输出训练日志: epoch, loss, 整体准确率, 字符级准确率 (CTC) 或 MAE, 容差准确率 (回归)
  6. 保存最佳模型到 checkpoints/
  7. 训练结束自动导出 ONNX 到 onnx_models/
  8. DataLoader 统一使用 num_workers=0 避免多进程兼容问题

补充规则:

  • 合成数据目录写入 .dataset_meta.json,其指纹由生成器源码哈希与配置快照共同构成。
  • OCR / 回归训练只在 checkpoint 中的 synthetic_data_spec_hash 与当前数据指纹一致时续训;合成数据被刷新后必须从 epoch 1 重新训练。
  • legacy normal / math 数据在 manifest 缺失时可被采纳,但 math 仍必须覆盖 + - × ÷,缺失 ÷ 时必须重建数据后再训练。

数据增强策略

# 训练时增强
train_augment = transforms.Compose([
    transforms.Grayscale(),
    transforms.Resize((H, W)),
    transforms.RandomAffine(degrees=8, translate=(0.05, 0.05), scale=(0.95, 1.05)),
    transforms.ColorJitter(brightness=0.3, contrast=0.3),
    transforms.GaussianBlur(3, sigma=(0.1, 0.5)),
    transforms.ToTensor(),
    transforms.Normalize([0.5], [0.5]),
    transforms.RandomErasing(p=0.15, scale=(0.01, 0.05)),
])

推理流水线 (pipeline.py)

class CaptchaPipeline:
    """
    核心推理流水线。
    加载调度模型和所有专家模型 (ONNX 格式)。
    提供统一的 solve(image) 接口。
    """

    def __init__(self, models_dir='onnx_models/'):
        """
        初始化加载所有 ONNX 模型。
        使用 onnxruntime.InferenceSession。
        """
        pass

    def preprocess(self, image: Image.Image, target_size: tuple) -> np.ndarray:
        """图片预处理: resize, grayscale, normalize, 转 numpy"""
        pass

    def classify(self, image: Image.Image) -> str:
        """调度分类,返回类型名: 'normal' / 'math' / '3d_text' / '3d_rotate' / '3d_slider'"""
        pass

    def solve(self, image) -> str:
        """
        完整识别流程:
        1. 分类验证码类型
        2. 路由到对应专家模型 (CTC 或回归)
        3. 后处理 (算式型需要计算结果)
        4. 返回最终答案字符串
        
        image: PIL.Image 或文件路径或 bytes
        """
        pass

ONNX 导出 (export_onnx.py)

def export_model(model, model_name, input_shape, onnx_dir='onnx_models/'):
    """
    导出单个模型为 ONNX。
    - 使用 opset_version=18
    - 开启 dynamic_axes 支持动态 batch
    - 导出后用 onnxruntime 验证推理一致性
    - 可选: onnx 模型简化 (onnxsim)
    """
    pass

def export_all():
    """依次导出 classifier, normal, math, threed_text, threed_rotate, threed_slider 六个模型"""
    pass

CLI 入口 (cli.py)

# 安装依赖
uv sync                         # 核心依赖
uv sync --extra server           # 含 HTTP 服务依赖

# 生成训练数据
uv run python cli.py generate --type normal --num 60000
uv run python cli.py generate --type math --num 60000
uv run python cli.py generate --type 3d_text --num 80000
uv run python cli.py generate --type 3d_rotate --num 60000
uv run python cli.py generate --type 3d_slider --num 60000
uv run python cli.py generate --type classifier --num 50000

# 训练模型
uv run python cli.py train --model classifier
uv run python cli.py train --model normal
uv run python cli.py train --model math
uv run python cli.py train --model 3d_text
uv run python cli.py train --model 3d_rotate
uv run python cli.py train --model 3d_slider
uv run python cli.py train --all    # 按依赖顺序全部训练
uv run python cli.py train-funcaptcha --question 4_3d_rollball_animals

# 导出 ONNX
uv run python cli.py export --all
uv run python cli.py export --model 3d_text     # "3d_text" 自动映射为 "threed_text"
uv run python cli.py export --model 4_3d_rollball_animals

# 推理
uv run python cli.py predict image.png                    # 自动分类+识别
uv run python cli.py predict image.png --type normal       # 跳过分类直接识别
uv run python cli.py predict image.png --type 3d_rotate    # 指定为旋转类型
uv run python cli.py predict-dir ./test_images/            # 批量识别
uv run python cli.py predict-funcaptcha challenge.jpg --question 4_3d_rollball_animals
FUNCAPTCHA_ROLLBALL_MODEL_PATH=/path/to/4_3d_rollball_animals.onnx \
  uv run python cli.py predict-funcaptcha challenge.jpg --question 4_3d_rollball_animals

# 启动 HTTP 服务 (需先安装 server 可选依赖)
uv run python cli.py serve --port 8080

FunCaptcha 专项 ONNX 查找顺序:

  • onnx_models/funcaptcha_rollball_animals.onnx
  • 环境变量 FUNCAPTCHA_ROLLBALL_MODEL_PATH
  • 默认回退 /mnt/data/code/python/funcaptcha-server/model/4_3d_rollball_animals.onnx

注意:

  • models/ 目录用于 Python 源码,不放 ONNX 产物
  • 本仓库导出的 FunCaptcha ONNX 会携带 sidecar metadata 并使用 centered RGB 预处理
  • 外部兼容 ONNX 若无 metadata推理层需回退到 funcaptcha-server/255.0 RGB 预处理契约

HTTP 服务 (server.py可选)

纯推理服务,不依赖 torch / 训练代码,仅需 onnxruntime + FastAPI。

# POST /solve         - JSON base64 图片识别 (同步)
#   请求: {"image": "<base64>", "type": "normal"}   (type 可选)
#   请求也可用 {"image":"<base64>", "question":"4_3d_rollball_animals"}
#   响应: {"type": "normal", "result": "A3B8", "raw": "A3B8", "time_ms": 12.3}
#   FunCaptcha 响应: {"type":"funcaptcha","question":"4_3d_rollball_animals","objects":[2],"result":"2","raw":"2","time_ms":12.3}
#
# POST /solve/upload  - multipart 文件上传识别 (同步)
#   请求: multipart/form-data, 字段名 image, 可选 query param type/question
#   响应: 同上
#
# POST /createTask    - 创建异步识别任务
#   请求: {"clientKey":"local","callbackUrl":"https://...","softId":1,"languagePool":"en","task":{"type":"ImageToTextTask","body":"<base64>","captchaType":"normal"}}
#   或: {"clientKey":"local","task":{"type":"FunCaptcha","body":"<base64>","question":"4_3d_rollball_animals"}}
#   响应: {"errorId":0,"taskId":"<uuid>","status":"processing","createTime":1710000000,"expiresAt":1710000600}
#
# POST /getTaskResult - 查询异步任务结果
#   处理中: {"errorId":0,"taskId":"<uuid>","status":"processing"}
#   完成: {"errorId":0,"taskId":"<uuid>","status":"ready","cost":"0.00000","ip":"127.0.0.1","solveCount":1,"task":{"type":"ImageToTextTask","captchaType":"normal"},"callback":{"configured":true,"attempts":1,"delivered":true},"solution":{"text":"A3B8","answer":"A3B8","raw":"A3B8","captchaType":"normal","timeMs":12.3}}
#   FunCaptcha 完成: {"errorId":0,"taskId":"<uuid>","status":"ready","task":{"type":"FunCaptcha","question":"4_3d_rollball_animals"},"solution":{"objects":[2],"answer":2,"raw":"2","text":"2","question":"4_3d_rollball_animals","timeMs":12.3}}
#
# POST /getBalance    - 本地兼容接口
#   响应: {"errorId":0,"balance":999999.0}
#
# GET  /health        - 健康检查
# GET  /api/v1/health - 健康检查兼容别名
#   响应: {"status": "ok", "models_loaded": true, "client_key_required": false, "async_tasks": {...}}
  • 异步任务接口参考 ohmycaptchataskId 轮询模式实现
  • 兼容根路径与 /api/v1/* 双路由;如设置环境变量 CLIENT_KEY,则任务接口要求请求体中的 clientKey 匹配
  • 普通 OCR 任务通过 task.captchaType 路由FunCaptcha 专项任务通过 task.question 路由,不进入 CaptchaPipeline 调度分类器
  • callbackUrl 会在任务完成后触发一次 application/x-www-form-urlencoded POST 回调,字段包含 id/taskIdcode;默认失败重试 2 次并按退避间隔重发
  • 若设置环境变量 CALLBACK_SIGNING_SECRET,回调请求会携带 X-CaptchaBreaker-TimestampX-CaptchaBreaker-Signature-AlgX-CaptchaBreaker-Signature 头,签名算法为 hmac-sha256
  • 任务结果额外暴露 task / callback 元信息,便于接入方排查异步状态
  • 任务结果持久化在 data/server_tasks/,默认 TTL 为 600 秒,服务重启后可恢复未过期任务

关键约束和注意事项

  1. 所有模型用 float32 训练,导出 ONNX 时不做量化,先保证精度
  2. CTC 解码统一用贪心解码,不需要 beam search验证码场景贪心够用
  3. 字符集由 config.py 统一定义: 当前 normal 保留易混淆字符3d_text 继续使用去混淆字符集
  4. 算式识别分两步: 先 OCR 识别字符串,再用规则计算,不要让模型直接输出数值
  5. 随机种子: 生成数据和训练时均通过 config.RANDOM_SEED 设置全局种子 (random/numpy/torch),保证可复现
  6. 真实数据文件名格式: {label}_{任意}.pnglabel 部分是标注内容
  7. 数据集字符过滤: CRNNDataset 加载标签时,若发现字符不在字符集内会发出 warning便于排查标注/字符集不匹配问题
  8. 模型保存格式: CTC checkpoint 包含 model_state_dict, chars, best_acc, epoch; 回归 checkpoint 包含 model_state_dict, label_range, best_mae, best_tol_acc, epoch
  9. 不使用 GPU 特有功能,确保 CPU 也能训练和推理 (只是慢一些)
  10. 类型扩展: OCR/回归验证码类型继续遵循 “生成器 + 专家模型 + 分类器类别” 的主线FunCaptcha 这类专项 challenge 优先走 task.question 专项路由,不强行塞进 CAPTCHA_TYPES
  11. 文档同步: 对项目结构、配置、架构等做出变更时,必须同步更新 CLAUDE.md 中的对应内容,保持文档与代码一致

目标指标

模型 准确率目标 推理延迟 模型体积
调度分类器 (5类) > 99% < 5ms < 500KB
普通字符 > 95% < 30ms < 2MB
算式识别 > 93% < 30ms < 2MB
3D立体文字 > 85% < 50ms < 5MB
3D旋转 (±5°) > 85% < 30ms ~1MB
3D滑块 (±3px) > 90% < 30ms ~1MB
FunCaptcha rollball > 90% challenge acc < 30ms < 2MB
全流水线 - < 80ms < 12MB 总计

开发顺序

  1. 先实现 config.py 和 generators/
  2. 实现 models/ 中所有模型定义
  3. 实现 training/dataset.py 通用数据集类
  4. 按顺序训练: normal → math → 3d_text → 3d_rotate → 3d_slider → classifier
  5. 实现 inference/pipeline.py 和 export_onnx.py
  6. 实现 FunCaptcha 专项推理/训练支线 (fun_captcha.py, train_funcaptcha_rollball.py)
  7. 实现 cli.py 统一入口
  8. 可选: server.py HTTP 服务
  9. 编写 tests/

交互式 Solver 扩展

概述

在现有验证码识别架构之上,新增滑块 (slide) 和旋转 (rotate) 两种交互式验证码求解能力。与现有 3d_rotate/3d_slider 的区别:

  • 3d_slider (合成拼图回归) → slide solver: 真实滑块验证码OpenCV 优先 + CNN 兜底
  • 3d_rotate (合成圆盘 sigmoid 回归) → rotate solver: 真实旋转验证码sin/cos 编码 + 自然图

每个 solver 模型独立训练、独立导出 ONNX、独立替换互不依赖。

滑块求解器 (SlideSolver)

  • 三种方法按优先级: 模板匹配 → 边缘检测 → CNN 兜底
  • 模型: GapDetectorCNN (1x128x256 灰度 → sigmoid [0,1])
  • OpenCV 延迟导入,未安装时退化到 CNN only
  • 输出: {"gap_x", "gap_x_percent", "confidence", "method"}

旋转求解器 (RotateSolver)

  • ONNX 推理 → (sin, cos) → atan2 → 角度
  • 模型: RotationRegressor (3x128x128 RGB → tanh (sin θ, cos θ))
  • 输出: {"angle", "confidence"}

Solver CLI 用法

# 生成训练数据
uv run python cli.py generate-solver slide --num 30000
uv run python cli.py generate-solver rotate --num 50000

# 训练 (各模型独立)
uv run python cli.py train-solver slide
uv run python cli.py train-solver rotate

# 求解
uv run python cli.py solve slide --bg bg.png [--tpl tpl.png]
uv run python cli.py solve rotate --image img.png

# 导出 (已集成到 export --all)
uv run python cli.py export --model gap_detector
uv run python cli.py export --model rotation_regressor

滑块轨迹生成

utils/slide_utils.py 提供 generate_slide_track(distance):

  • 贝塞尔曲线 ease-out 加速减速
  • y 轴 ±1~3px 随机抖动
  • 时间间隔不均匀
  • 末尾微小过冲回退

Solver 目标指标

模型 准确率目标 推理延迟 模型体积
滑块 CNN (±5px) > 85% < 30ms ~1MB
旋转回归 (±5°) > 85% < 30ms ~2MB