# CLAUDE.md - 验证码识别多模型系统 (CaptchaBreaker) ## 项目概述 构建一个本地验证码识别系统,采用 **调度模型 + 多专家模型** 的两级架构。调度模型负责分类验证码类型,专家模型负责具体识别。所有模型轻量化设计,最终导出 ONNX 用于部署。 ## 技术栈 - Python 3.10-3.12 - uv (包管理,依赖定义在 pyproject.toml) - PyTorch 2.x (训练) - ONNX + ONNXRuntime (推理部署) - Pillow (图像处理) - OpenCV (可选,滑块求解与相关测试) - FastAPI (可选,提供 HTTP 识别服务) ## 当前命令入口 - 优先使用 `uv run captcha ...` 调用 CLI;`pyproject.toml` 已将 `captcha` 映射到 `cli:main` - 额外依赖按需安装: - `uv sync --extra server`:HTTP 服务 - `uv sync --extra cv`:OpenCV / 滑块 solver - `uv sync --extra dev`:pytest - Linux `x86_64` 环境通过 `pyproject.toml` 的 `tool.uv.sources` / `tool.uv.index` 固定从官方 `cu121` index 安装 `torch==2.5.1` 与 `torchvision==0.20.1` - 该组合已验证可在 GTX 1050 Ti (`sm_61`) 上执行 CUDA;仓库之前解析到的 `torch 2.10.0 + cu128` 不兼容这张卡 - Python 3.10 环境下保持 `onnxruntime < 1.24`,避免 `uv` 解析到无 `cp310` wheel 的版本 - 当前 CLI 子命令包括:`generate`、`train`、`export`、`predict`、`predict-dir`、`serve`、`generate-solver`、`train-solver`、`solve`、`train-funcaptcha`、`predict-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 导出时同步生成 `.meta.json`,保存 OCR 字符集、分类器类别顺序、回归标签范围等部署时必需的信息。 - `inference/pipeline.py` 优先读取 sidecar metadata;缺失时才回退到 `config.py`,以兼容历史导出产物。 ### 调度分类器 (classifier.py) - 任务: 图像分类,判断验证码属于哪个类型 - 架构: 轻量 CNN,3-4 层卷积 + 全局平均池化 + 全连接 - 输入: 灰度图 1x64x128 - 输出: softmax 概率分布,类别数 = 验证码类型数 - 要求: 准确率 99%+,推理 < 5ms - 模型体积目标: < 500KB ```python 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 ```python # 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` - 架构: 共享编码器 Siamese,`candidate/reference` 特征拼接后输出单个匹配 logit - 训练方式: 每个 challenge 展开成 4 组 pair,正确候选为正样本,其余为负样本 - 推理输出: 对 4 个候选分别打分,取 argmax,返回 `objects=[index]` - 模型体积目标: < 2MB ## 数据生成器规范 ### 基类 (base.py) ```python 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]`,运行时再映射回原图宽度 ## 训练规范 ### 通用训练配置 ```python # 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` 仍必须覆盖 `+ - × ÷`,缺失 `÷` 时必须重建数据后再训练。 ### 数据增强策略 ```python # 训练时增强 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) ```python 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) ```python 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) ```bash # 安装依赖 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。 ```python # POST /solve - JSON base64 图片识别 (同步) # 请求: {"image": "", "type": "normal"} (type 可选) # 请求也可用 {"image":"", "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":"","captchaType":"normal"}} # 或: {"clientKey":"local","task":{"type":"FunCaptcha","body":"","question":"4_3d_rollball_animals"}} # 响应: {"errorId":0,"taskId":"","status":"processing","createTime":1710000000,"expiresAt":1710000600} # # POST /getTaskResult - 查询异步任务结果 # 处理中: {"errorId":0,"taskId":"","status":"processing"} # 完成: {"errorId":0,"taskId":"","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":"","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": {...}} ``` - 异步任务接口参考 `ohmycaptcha` 的 `taskId` 轮询模式实现 - 兼容根路径与 `/api/v1/*` 双路由;如设置环境变量 `CLIENT_KEY`,则任务接口要求请求体中的 `clientKey` 匹配 - 普通 OCR 任务通过 `task.captchaType` 路由;FunCaptcha 专项任务通过 `task.question` 路由,不进入 `CaptchaPipeline` 调度分类器 - `callbackUrl` 会在任务完成后触发一次 `application/x-www-form-urlencoded` POST 回调,字段包含 `id/taskId` 与 `code`;默认失败重试 2 次并按退避间隔重发 - 若设置环境变量 `CALLBACK_SIGNING_SECRET`,回调请求会携带 `X-CaptchaBreaker-Timestamp`、`X-CaptchaBreaker-Signature-Alg` 和 `X-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}_{任意}.png`,label 部分是标注内容 11. **数据集字符过滤**: `CRNNDataset` 加载标签时,若发现字符不在字符集内会发出 warning,便于排查标注/字符集不匹配问题 7. **模型保存格式**: CTC checkpoint 包含 model_state_dict, chars, best_acc, epoch; 回归 checkpoint 包含 model_state_dict, label_range, best_mae, best_tol_acc, epoch 8. **不使用 GPU 特有功能**,确保 CPU 也能训练和推理 (只是慢一些) 9. **类型扩展**: OCR/回归验证码类型继续遵循 “生成器 + 专家模型 + 分类器类别” 的主线;FunCaptcha 这类专项 challenge 优先走 `task.question` 专项路由,不强行塞进 `CAPTCHA_TYPES` 10. **文档同步**: 对项目结构、配置、架构等做出变更时,必须同步更新 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 用法 ```bash # 生成训练数据 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 |