准备 - 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 模型下载说明
136 lines
6.5 KiB
Markdown
136 lines
6.5 KiB
Markdown
# ddddocr-rs
|
||
|
||
[带带弟弟 OCR(ddddocr)](https://github.com/sml2h3/ddddocr) 的 Rust 移植版:提供验证码 OCR 识别、目标检测与滑块匹配能力。核心库与推理引擎解耦,同一套 API 可切换 [Tract](https://github.com/sonos/tract) 或 [ONNX Runtime](https://onnxruntime.ai/) 后端。
|
||
|
||
## 架构
|
||
|
||
项目为 Cargo workspace,包含三个 crate:
|
||
|
||
| crate | 说明 |
|
||
|---|---|
|
||
| `ddddocr-core` | 引擎无关的核心库:OCR / 目标检测 / 滑块匹配、模型元数据与图像预处理 |
|
||
| `ddddocr-ort` | ONNX Runtime 推理后端(可选 `cuda` feature 启用 GPU 加速) |
|
||
| `ddddocr-tract2` | Tract(纯 Rust)推理后端 |
|
||
|
||
`ddddocr-core` 通过 `traits::InferenceEngine` / `OcrEngine` / `DetEngine` 抽象推理能力,由 `ddddocr-ort` / `ddddocr-tract2` 实现,业务代码只依赖核心库接口即可。
|
||
|
||
## 快速开始
|
||
|
||
在 Cargo.toml 中添加:
|
||
|
||
```toml
|
||
[dependencies]
|
||
ddddocr-core = "0.2"
|
||
ddddocr-ort = "0.2" # 或 ddddocr-tract2 = "0.2"
|
||
```
|
||
|
||
核心库自带一个不依赖真实模型的演示示例(用假引擎演示完整调用链):
|
||
|
||
```bash
|
||
cargo run -p ddddocr-core --example quick_start
|
||
```
|
||
|
||
真实推理需要自行准备 ONNX 模型文件(crate 包内不包含模型)。以 ORT 后端为例:
|
||
|
||
```rust
|
||
use ddddocr_core::traits::{Info, Loader};
|
||
use ddddocr_core::{ModelMetadata, Normalization, Ocr, Resize};
|
||
|
||
// 1. 构建会话(等价写法:ddddocr_tract2::loader::ModelLoader)
|
||
let session = ddddocr_ort::loader::ModelLoader::default()
|
||
.build_for_path("models/common.onnx")?;
|
||
|
||
// 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);
|
||
```
|
||
|
||
目标检测与滑块匹配类似:`Detector::new(&engine).predict(&image)` 返回检测框列表;`Slider::new().slide_match(target, background, simple_target)` 返回匹配坐标与置信度。
|
||
|
||
## 模型下载
|
||
|
||
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`。
|