Files
CaptchBreaker/README.md

12 KiB
Raw Permalink Blame History

CaptchaBreaker

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

架构

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

支持的验证码类型

类型 模型 说明
normal LiteCRNN + CTC 普通字符验证码 (数字+字母)
math LiteCRNN + CTC 算式验证码 (如 3+8=?11)
3d_text ThreeDCNN + CTC 3D 立体文字验证码
3d_rotate RegressionCNN 3D 旋转角度回归 (0-359°)
3d_slider RegressionCNN 3D 滑块偏移回归 (10-200px)

交互式 Solver

类型 模型 说明
slide GapDetectorCNN 滑块缺口检测 (统一输出缺口中心 xOpenCV 优先 + CNN 兜底)
rotate RotationRegressor 旋转角度回归 (sin/cos 编码)

FunCaptcha 专项

question 模型 说明
4_3d_rollball_animals FunCaptchaSiamese 整张 challenge 图裁切后做 reference/candidate 配对打分,返回 objects

安装

# 核心依赖
uv sync

# 含 HTTP 服务
uv sync --extra server

# 含 OpenCV (滑块求解)
uv sync --extra cv

# 含测试
uv sync --extra dev

说明:

  • 项目当前通过 pyproject.tomlonnxruntime 约束在 <1.24,以保持 Python 3.10 环境下的 uv 可安装性。
  • Linux x86_64 环境下,uv sync 会从官方 PyTorch cu121 index 安装 torch==2.5.1torchvision==0.20.1。这组版本已验证可在 GTX 1050 Ti (sm_61) 上执行 CUDA。
  • 仓库之前自动解析到的 torch 2.10 + cu128 对 GTX 1050 Ti 不兼容;如果后续升级 torch,先重新验证 GPU 实际能执行 CUDA 张量运算。

快速开始

1. 生成训练数据

uv run captcha generate --type normal --num 60000
uv run captcha generate --type math --num 60000
uv run captcha generate --type 3d_text --num 80000
uv run captcha generate --type 3d_rotate --num 60000
uv run captcha generate --type 3d_slider --num 60000
uv run captcha generate --type classifier --num 50000

2. 训练模型

# 逐个训练
uv run captcha train --model normal
uv run captcha train --model math
uv run captcha train --model 3d_text
uv run captcha train --model 3d_rotate
uv run captcha train --model 3d_slider
uv run captcha train --model classifier

# 或通过 CLI 一键训练
uv run captcha train --all

OCR / 回归训练在合成数据指纹与 checkpoint 一致时支持断点续训;生成规则变化会自动刷新数据并从 epoch 1 重新训练。分类器和 rotate solver 当前仍按整轮训练处理。

3. 导出 ONNX

uv run captcha export --all
# 或单个导出
uv run captcha export --model normal
uv run captcha export --model 4_3d_rollball_animals

导出会同时生成 <model>.meta.json sidecar保存 OCR 字符集、分类器类别顺序、回归标签范围或 FunCaptcha challenge 裁切元信息,部署推理优先读取这些 metadata。

4. 推理

# 单张识别 (自动分类 + 识别)
uv run captcha predict image.png

# 指定类型跳过分类
uv run captcha predict image.png --type normal

# 批量识别
uv run captcha predict-dir ./test_images/

# FunCaptcha 专项识别
uv run captcha predict-funcaptcha challenge.jpg --question 4_3d_rollball_animals

5. 交互式 Solver

# 生成 Solver 训练数据
uv run captcha generate-solver slide --num 30000
uv run captcha generate-solver rotate --num 50000

# 训练
uv run captcha train-solver slide
uv run captcha train-solver rotate

# 求解
uv run captcha solve slide --bg bg.png --tpl tpl.png
uv run captcha solve rotate --image img.png

6. FunCaptcha 专项训练

准备整张 challenge 标注图到 data/real/funcaptcha/4_3d_rollball_animals/,文件名前缀为正确候选索引,例如 2_demo.jpg

uv run captcha train-funcaptcha --question 4_3d_rollball_animals
uv run captcha export --model 4_3d_rollball_animals
uv run captcha predict-funcaptcha challenge.jpg --question 4_3d_rollball_animals

如果暂时没有训练数据,也可以直接复用外部 ONNX

FUNCAPTCHA_ROLLBALL_MODEL_PATH=/path/to/4_3d_rollball_animals.onnx \
  uv run captcha predict-funcaptcha challenge.jpg --question 4_3d_rollball_animals

推理查找顺序为:

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

不要把 ONNX 文件放到 models/;该目录用于 Python 模型定义源码,运行时模型产物应放在 onnx_models/

HTTP API

uv sync --extra server
uv run captcha serve --port 8080

如需和 ohmycaptcha / YesCaptcha 风格客户端对齐,可在启动前设置 CLIENT_KEY

CLIENT_KEY=local uv run captcha serve --port 8080

如需让回调接收方校验来源,可再设置 CALLBACK_SIGNING_SECRET;服务会在回调请求头里附带 HMAC-SHA256 签名:

CLIENT_KEY=local CALLBACK_SIGNING_SECRET=shared-secret uv run captcha serve --port 8080

同步/异步接口都提供根路径和 /api/v1/* 兼容别名,例如 /solve/api/v1/solve/createTask/api/v1/createTask 都可用。

POST /solve — base64 图片识别(同步)

curl -X POST http://localhost:8080/solve \
  -H "Content-Type: application/json" \
  -d '{"image": "'$(base64 -w0 captcha.png)'", "type": "normal"}'

请求体:

{
  "image": "<base64 编码的图片>",
  "type": "normal"
}

type 可选,省略则自动分类。可选值:normal / math / 3d_text / 3d_rotate / 3d_slider

如需专项 FunCaptcha 路由,可额外传 question,例如:

{
  "image": "<base64 编码的图片>",
  "question": "4_3d_rollball_animals"
}

此时响应会额外包含 objects

响应:

{
  "type": "normal",
  "result": "A3B8",
  "raw": "A3B8",
  "time_ms": 12.3
}

POST /solve/upload — 文件上传识别(同步)

curl -X POST "http://localhost:8080/solve/upload?type=normal" \
  -F "image=@captcha.png"

POST /createTask — 创建异步识别任务

接口风格参考 ohmycaptchataskId 轮询方案,适合需要统一异步协议的接入方。任务结果会持久化到 data/server_tasks/,服务重启后仍可继续查询,默认保留 10 分钟;如设置了 CLIENT_KEY,则 clientKey 必须匹配。callbackUrlsoftIdlanguagePool 字段可传入,其中 callbackUrl 会在任务完成后收到一次 application/x-www-form-urlencoded POST 回调;默认失败重试 2 次,可通过 SERVER_CONFIG 调整超时、重试次数和退避间隔。如设置了 CALLBACK_SIGNING_SECRET,回调还会带上 X-CaptchaBreaker-TimestampX-CaptchaBreaker-Signature-AlgX-CaptchaBreaker-Signature。普通 OCR 任务走 task.captchaType,专项 FunCaptcha 任务走 task.question

curl -X POST http://localhost:8080/createTask \
  -H "Content-Type: application/json" \
  -d '{"clientKey":"local","task":{"type":"ImageToTextTask","body":"'"$(base64 -w0 captcha.png)"'","captchaType":"normal"}}'

FunCaptcha 示例:

curl -X POST http://localhost:8080/createTask \
  -H "Content-Type: application/json" \
  -d '{"clientKey":"local","task":{"type":"FunCaptcha","body":"'"$(base64 -w0 challenge.jpg)"'","question":"4_3d_rollball_animals"}}'

响应:

{
  "errorId": 0,
  "taskId": "4ec6f1904da2446caa6c6313c0f7d2b0",
  "status": "processing",
  "createTime": 1710000000,
  "expiresAt": 1710000600
}

POST /getTaskResult — 查询异步任务结果

curl -X POST http://localhost:8080/getTaskResult \
  -H "Content-Type: application/json" \
  -d '{"clientKey":"local","taskId":"4ec6f1904da2446caa6c6313c0f7d2b0"}'

处理中:

{
  "errorId": 0,
  "taskId": "4ec6f1904da2446caa6c6313c0f7d2b0",
  "status": "processing",
  "createTime": 1710000000
}

完成:

{
  "errorId": 0,
  "taskId": "4ec6f1904da2446caa6c6313c0f7d2b0",
  "status": "ready",
  "cost": "0.00000",
  "ip": "127.0.0.1",
  "createTime": 1710000000,
  "endTime": 1710000001,
  "expiresAt": 1710000600,
  "solveCount": 1,
  "task": {
    "type": "ImageToTextTask",
    "captchaType": "normal"
  },
  "callback": {
    "configured": true,
    "url": "https://example.com/callback",
    "attempts": 1,
    "delivered": true,
    "deliveredAt": 1710000001,
    "lastError": null
  },
  "solution": {
    "text": "A3B8",
    "answer": "A3B8",
    "raw": "A3B8",
    "captchaType": "normal",
    "timeMs": 12.3
  }
}

POST /getBalance — 本地兼容接口

{"errorId": 0, "balance": 999999.0}

GET /health 或 /api/v1/health — 健康检查

{
  "status": "ok",
  "models_loaded": true,
  "client_key_required": false,
  "async_tasks": {
    "active": 0,
    "processing": 0,
    "ready": 0,
    "failed": 0,
    "ttl_seconds": 600
  }
}

项目结构

├── config.py                 # 全局配置 (字符集、尺寸、训练超参)
├── cli.py                    # 命令行入口
├── server.py                 # FastAPI HTTP 服务 (纯推理,不依赖 torch)
├── generators/               # 验证码数据生成器
│   ├── normal_gen.py         # 普通字符
│   ├── math_gen.py           # 算式
│   ├── threed_gen.py         # 3D 文字
│   ├── threed_rotate_gen.py  # 3D 旋转
│   ├── threed_slider_gen.py  # 3D 滑块
│   ├── slide_gen.py          # 滑块缺口训练数据
│   └── rotate_solver_gen.py  # 旋转求解器训练数据
├── models/                   # 模型定义
│   ├── classifier.py         # 调度分类器
│   ├── lite_crnn.py          # 轻量 CRNN (normal/math)
│   ├── threed_cnn.py         # 3D 文字 CNN
│   ├── regression_cnn.py     # 回归 CNN (3d_rotate/3d_slider)
│   ├── gap_detector.py       # 滑块缺口检测
│   └── rotation_regressor.py # 旋转角度回归
├── training/                 # 训练脚本
│   ├── data_fingerprint.py   # 合成数据指纹 / manifest
│   ├── train_utils.py        # CTC 训练通用逻辑
│   ├── train_regression_utils.py  # 回归训练通用逻辑
│   ├── dataset.py            # 通用 Dataset 类
│   └── train_*.py            # 各模型训练入口
├── inference/                # 推理 (仅依赖 onnxruntime)
│   ├── model_metadata.py     # ONNX sidecar metadata
│   ├── pipeline.py           # 核心推理流水线
│   ├── export_onnx.py        # ONNX 导出
│   └── math_eval.py          # 算式计算
├── solvers/                  # 交互式验证码求解器
│   ├── slide_solver.py       # 滑块求解
│   └── rotate_solver.py      # 旋转求解
├── utils/
│   └── slide_utils.py        # 滑块轨迹生成
└── tests/                    # 测试 (57 tests)

目标指标

模型 准确率目标 推理延迟 模型体积
调度分类器 > 99% < 5ms < 500KB
普通字符 > 95% < 30ms < 2MB
算式识别 > 93% < 30ms < 2MB
3D 立体文字 > 85% < 50ms < 5MB
3D 旋转 (±5°) > 85% < 30ms ~1MB
3D 滑块 (±3px) > 90% < 30ms ~1MB
滑块 CNN (±5px) > 85% < 30ms ~1MB
旋转回归 (±5°) > 85% < 30ms ~2MB

测试

uv sync --extra dev
python -m pytest tests/ -v

技术栈

  • Python 3.10-3.12
  • PyTorch 2.x (训练)
  • ONNX + ONNXRuntime (推理部署)
  • FastAPI + uvicorn (HTTP 服务)
  • Pillow (图像处理)
  • OpenCV (可选,滑块求解)
  • uv (包管理)