feat: ddddocr-rs 完成 core/ort/tract2 规范整改与发布

准备

  - core:内置官方字符集(OLD/BETA)与 ModelMetadata::from_builtin_*
  构造器
  - ort:导出 Session、实现 Info、修正 cuda feature 接线、共享推理工具
  - tract2:包名更名(原 ddddocr-tract 已被占用)并完成规范整改
  - 集成测试按领域拆分(ocr / det / slide / common / api_surface)
  - 发布准备:Cargo.toml 元数据、workspace 版本 0.2.4、LICENSE/
  NOTICE、README 模型下载说明
This commit is contained in:
2026-08-10 19:56:29 +08:00
parent fe61895926
commit 00e8ab5308
58 changed files with 2542 additions and 2237 deletions

144
README.md
View File

@@ -1,45 +1,135 @@
# ddddocr-rs
带带弟弟 OCR (ddddocr) 的 Rust 移植版。高性能、低占用,支持多种验证码识别与检测
[带带弟弟 OCRddddocr](https://github.com/sml2h3/ddddocr) 的 Rust 移植版:提供验证码 OCR 识别、目标检测与滑块匹配能力。核心库与推理引擎解耦,同一套 API 可切换 [Tract](https://github.com/sonos/tract) 或 [ONNX Runtime](https://onnxruntime.ai/) 后端
🧩 滑块识别算法核心知识点总结
本项目实现了两种核心匹配模式,其底层逻辑与 OpenCV 的对齐情况如下:
## 架构
1. 匹配模式对比 (Match Modes)
|**模式**|**算法原理**|**适用场景**|**备注**|
|---|---|---|---|
|**边缘模式** (Edge-based)|基于 **Canny 边缘检测** 提取轮廓后再进行匹配。|**推荐方案**
。适用于绝大多数拼图滑块。|天然免疫拼图周边的透明/黑色留白干扰,坐标最精准。|
|**简单模式** (Simple/Gray)|直接基于 **灰度像素值** 进行归一化互相关计算。|适用于无明显边缘、靠颜色差异识别的场景。|对背景和透明边框敏感,可能存在重心偏移。|
项目为 Cargo workspace包含三个 crate
2. 数学公式差异 (NCC vs. CCOEFF)
在简单模式下,本项目采用的是 归一化互相关 (NCC),对应 OpenCV 中的 TM_CCORR_NORMED。
| crate | 说明 |
|---|---|
| `ddddocr-core` | 引擎无关的核心库OCR / 目标检测 / 滑块匹配、模型元数据与图像预处理 |
| `ddddocr-ort` | ONNX Runtime 推理后端(可选 `cuda` feature 启用 GPU 加速) |
| `ddddocr-tract2` | Tract纯 Rust推理后端 |
逻辑对齐Rust 的 match_template 结果与 Python cv2.TM_CCORR_NORMED 完全一致
`ddddocr-core` 通过 `traits::InferenceEngine` / `OcrEngine` / `DetEngine` 抽象推理能力,由 `ddddocr-ort` / `ddddocr-tract2` 实现,业务代码只依赖核心库接口即可
关于偏移若拼图原始图片Target四周包含大量的透明留白
## 快速开始
CCORR (本项目):会将留白视为图像的一部分,计算出的是整张图片框的中心。
在 Cargo.toml 中添加:
CCOEFF (OpenCV 默认):会自动进行“均值中心化”,在一定程度上能削弱留白的影响。
```toml
[dependencies]
ddddocr-core = "0.2"
ddddocr-ort = "0.2" # 或 ddddocr-tract2 = "0.2"
```
最佳实践:若发现坐标有固定位移,建议优先切换至 边缘模式,或对滑块图进行 Bounding Box 裁剪 后再匹配。
核心库自带一个不依赖真实模型的演示示例(用假引擎演示完整调用链):
3. 图像预处理一致性
```bash
cargo run -p ddddocr-core --example quick_start
```
为确保识别精度,本项目在 Rust 中完美复刻了 Python OpenCV 的预处理链路
真实推理需要自行准备 ONNX 模型文件crate 包内不包含模型)。以 ORT 后端为例
- **灰度化权重**:采用 OpenCV 标准感光公式 $0.299R + 0.587G + 0.114B$。
```rust
use ddddocr_core::traits::{Info, Loader};
use ddddocr_core::{ModelMetadata, Normalization, Ocr, Resize};
- **Alpha 处理**:在将 PNG 转为 RGB 时,自动将透明区域填充为黑色,确保与 PIL (Python Imaging Library) 行为一致。
// 1. 构建会话等价写法ddddocr_tract2::loader::ModelLoader
let session = ddddocr_ort::loader::ModelLoader::default()
.build_for_path("models/common.onnx")?;
- **坐标定义**:所有返回坐标均为匹配区域的 **几何中心点** $(x + w/2, y + h/2)$。
// 2. 组装 OCR 运行时
let metadata = ModelMetadata::from_static_slice(
&["a", "b"], // 字符集
false, // 非单字模型
Resize::DynamicWidth(64), // 高度固定 64、宽度等比缩放
1, // 灰度单通道
Normalization::MinusOneToOne,
);
let ocr = ddddocr_ort::OcrRuntime::new(session, metadata);
💡 开发者建议:
// 3. 识别图片
let result = Ocr::builder().build_with(&ocr).predict(&image)?;
println!("识别结果: {}", result);
```
如果识别结果在 $X$ 轴上有大约 $10px$ 左右的固定误差,通常是因为滑块原图自带了透明边距(留白)。此时请确保
simple_target=false。该模式会通过 Canny 边缘检测 提取轮廓特征,能自动锁定拼图实体并忽略背景留白的像素干扰。
鸣谢 (Credits)
目标检测与滑块匹配类似:`Detector::new(&engine).predict(&image)` 返回检测框列表;`Slider::new().slide_match(target, background, simple_target)` 返回匹配坐标与置信度。
- 本项目是 [ddddocr](https://github.com/sml2h3/ddddocr) 的 Rust 移植版本,原作者为 sml2h3。衷心感谢原作者对 OCR 社区做出的杰出贡献。
- 推理引擎基于 [tract (Sonos)](https://github.com/sonos/tract)。感谢其为 Rust 生态提供的轻量级推理方案。
## 模型下载
OCR / 目标检测需要 ONNX 模型文件。官方模型位于 [ddddocr 仓库 `ddddocr/` 目录](https://github.com/sml2h3/ddddocr/blob/master/ddddocr/),下载后放入仓库根目录的 `models/` 文件夹:
| 文件 | 大小 | 用途 | 直链 |
|---|---|---|---|
| `common.onnx` | 约 51.6 MB | 新版 OCR 模型(默认) | [下载](https://raw.githubusercontent.com/sml2h3/ddddocr/master/ddddocr/common.onnx) |
| `common_det.onnx` | 约 19.2 MB | 目标检测模型 | [下载](https://raw.githubusercontent.com/sml2h3/ddddocr/master/ddddocr/common_det.onnx) |
| `common_old.onnx` | 约 13 MB | 旧版 OCR 模型 | [下载](https://raw.githubusercontent.com/sml2h3/ddddocr/master/ddddocr/common_old.onnx) |
> 注意:`ddddocr-tract2` 不支持旧版模型 `common_old.onnx`,请使用 `common.onnx`。
>
> 字符集配对:`common.onnx` 对应内置 Beta 字符集(`Charset` / `ModelMetadata::from_builtin_beta`,归一化 `MinusOneToOne``common_old.onnx` 对应旧版字符集(`from_builtin_old`,归一化 `ZeroToOne`)。
>
> 仓库测试使用的 `common_sml2h3_f32.onnx`、`common_huashi666_i64.onnx` 为社区转换的 f32 / i64 变体模型(与 `common.onnx` 同源),不在上述官方目录中,需自行获取。
## 字符集与内置默认值
OCR 模型的字符集token 列表)是模型的一部分:字符 `i` 对应模型输出 logits 的第 `i` 列,必须与模型训练时一致,否则识别结果会错位。
字符集有两种提供方式:
- 通过模型元数据 JSON 的 `charset` 字段(`Metadata::from_json_str` / `from_json_bytes` 自动解析);
- 代码内显式指定:`ModelMetadata::from_static_slice(&["", "a", "b"], ...)``Charset::new(...)`
`ddddocr-core` 内置官方模型的默认字符集(旧版 `CHARSET_OLD` 与 Beta `CHARSET_BETA`),作为免配置的快速通道。字符集数据独立存放在 `ddddocr-core/src/ocr/builtin.rs` 私有模块中(与业务逻辑分离),通过 `ModelMetadata` 的公开构造方法使用:
```rust
use ddddocr_core::{ModelMetadata, Normalization, Resize};
// 官方旧版模型配套
let meta = ModelMetadata::from_builtin_old(
false,
Resize::DynamicWidth(64),
1,
Normalization::ZeroToOne,
);
// 官方 Beta 模型配套
let meta = ModelMetadata::from_builtin_beta(
false,
Resize::DynamicWidth(64),
1,
Normalization::MinusOneToOne,
);
```
数据内置于代码,不依赖外部文件。若使用自有模型,请仍以元数据 JSON 或 `from_static_slice` 指定匹配的字符集。
## 滑块匹配核心知识点
项目实现两种匹配模式,底层逻辑与 OpenCV 对齐:
| 模式 | 算法原理 | 适用场景 | 备注 |
|---|---|---|---|
| 边缘模式Edge-based | 基于 Canny 边缘检测提取轮廓后匹配 | **推荐方案**,适用于绝大多数拼图滑块 | 天然免疫拼图周边透明/黑色留白干扰,坐标最精准 |
| 简单模式Simple/Gray | 基于灰度像素值做归一化互相关NCC | 无明显边缘、靠颜色差异识别的场景 | 对背景和透明边框敏感,可能存在重心偏移 |
关键点:
- 简单模式采用归一化互相关NCC与 OpenCV 的 `TM_CCORR_NORMED` 完全一致。
- 若拼图原图四周带透明留白本项目会将留白计入整张图片框中心OpenCV 默认的 CCOEFF 会做均值中心化削弱留白影响。
- 图像预处理与 Python 链路保持一致:灰度权重采用 OpenCV 标准感光公式 `0.299R + 0.587G + 0.114B`PNG 转 RGB 时透明区域填充为黑色;返回坐标为匹配区域的几何中心 `(x + w/2, y + h/2)`
> 若识别结果在 X 轴上有约 10px 固定误差,通常是滑块原图自带透明边距所致。此时请确保 `simple_target = false`,边缘模式会自动锁定拼图实体并忽略留白干扰。
## 致谢
- [sml2h3 (ddddocr)](https://github.com/sml2h3/ddddocr) - 模型权重与原始逻辑。
- [Sonos (tract)](https://github.com/sonos/tract) - 纯 Rust ONNX 推理引擎。
- [pyke.io (ort)](https://github.com/pykeio/ort) - ONNX Runtime 的 Rust 绑定。
- [Microsoft (ONNX Runtime)](https://onnxruntime.ai/) - ONNX 推理引擎。
## License
`MIT OR Apache-2.0`,许可证文本见仓库根目录的 `LICENSE-MIT``LICENSE-APACHE`