# 三个引擎：OCR、检测、滑块

> ddddocr 内部有三个独立引擎，各司其职——文字识别、目标检测、滑块缺口定位。

- Repository: sml2h3/ddddocr
- GitHub: https://github.com/sml2h3/ddddocr
- Human wiki: https://grok-wiki.com/public/wiki/sml2h3-ddddocr-a34dd45d9f63
- Complete Markdown: https://grok-wiki.com/public/wiki/sml2h3-ddddocr-a34dd45d9f63/llms-full.txt

## Source Files

- `ddddocr/core/base.py`
- `ddddocr/core/ocr_engine.py`
- `ddddocr/core/detection_engine.py`
- `ddddocr/core/slide_engine.py`
- `ddddocr/compat/v1.py`

---

<details>
<summary>相关源文件</summary>
以下文件用于生成此维基页面：
- [ddddocr/core/base.py](ddddocr/core/base.py)
- [ddddocr/core/ocr_engine.py](ddddocr/core/ocr_engine.py)
- [ddddocr/core/detection_engine.py](ddddocr/core/detection_engine.py)
- [ddddocr/core/slide_engine.py](ddddocr/core/slide_engine.py)
- [ddddocr/compat/v1.py](ddddocr/compat/v1.py)
- [ddddocr/models/model_loader.py](ddddocr/models/model_loader.py)
</details>

# 三个引擎：OCR、检测、滑块

ddddocr 内部设计了三个独立引擎，分别承担**文字识别（OCR）**、**目标检测（Detection）**、**滑块缺口定位（Slide）**三项任务。三者共享同一套抽象基类，但各自走完全不同的推理路径——OCR 和检测依赖 ONNX 模型做深度学习推理，滑块引擎则完全基于 OpenCV 的传统图像算法，不加载任何模型。

理解这三个引擎的职责边界和协作方式，是读懂 ddddocr 代码的关键。

## 架构总览

三个引擎均由 `BaseEngine` 抽象基类派生（`ddddocr/core/base.py:15-112`），统一暴露 `initialize()`、`predict()`、`is_ready()`、`cleanup()` 等接口。入口类 `DdddOcr`（`ddddocr/compat/v1.py:18`）按用户配置决定实例化哪些引擎，并将方法调用转发到对应的引擎。

```
┌─────────────────────────────────────────────────┐
│                  DdddOcr (门面)                   │
│          ddddocr/compat/v1.py:18-284             │
├─────────────┬──────────────┬────────────────────┤
│ OCREngine   │DetectionEngine│   SlideEngine      │
│ ocr_engine  │detection_engine│  slide_engine      │
│ .py:20      │.py:20         │  .py:20            │
├─────────────┼──────────────┼────────────────────┤
│ common_old  │ common_det   │  无模型（纯算法）    │
│ .onnx       │ .onnx        │                    │
│ common.onnx │              │                    │
└──────┬──────┴──────┬───────┴────────┬───────────┘
       │             │                │
       ▼             ▼                ▼
  ONNX Runtime   ONNX Runtime    OpenCV 模板匹配
  + CTC 解码     + YOLOX 后处理   + 边缘检测 + 轮廓分析
```

## 公共基类：BaseEngine

`BaseEngine`（`ddddocr/core/base.py:15`）定义了所有引擎的"合约"：

| 方法 | 作用 | 行号 |
|------|------|------|
| `initialize()` | 加载模型、准备资源（抽象方法） | `base.py:32` |
| `predict()` | 执行推理并返回结果（抽象方法） | `base.py:45` |
| `is_ready()` | 检查引擎是否已初始化且模型已加载 | `base.py:70` |
| `switch_device()` | 切换 CPU/GPU 设备，已初始化时自动重载模型 | `base.py:79` |
| `cleanup()` | 释放 ONNX 会话等资源 | `base.py:100` |

基类内部持有一个 `ModelLoader` 实例（`base.py:28`）和一个 `onnxruntime.InferenceSession`（`base.py:29`），供 OCR 和检测引擎复用。滑块引擎因为不加载模型，选择不调用父类 `__init__`，自行管理状态。

## 引擎一：OCR 引擎（文字识别）

**职责：** 接收一张图片，输出其中的文字内容。

`OCREngine`（`ddddocr/core/ocr_engine.py:20`）是使用最频繁的引擎。它的核心流程可以分为四步：

1. **图像预处理**（`ocr_engine.py:159-215`）——将图片缩放到模型要求的尺寸（默认高度 64px，宽度按比例计算），转灰度，归一化到 `[0, 1]`，再调整为 `(batch, channel, H, W)` 的张量格式。
2. **ONNX 推理**（`ocr_engine.py:217-242`）——将预处理后的数组送入 `onnxruntime.InferenceSession.run()`，获得形状为 `(sequence_length, 1, num_classes)` 的原始输出。
3. **CTC 解码**（`ocr_engine.py:300-329`）——逐位置取 argmax 得到索引序列，然后按 CTC 规则去掉连续重复和 blank（索引 0），得到去重后的字符索引列表。
4. **字符映射**（`ocr_engine.py:244-298`）——通过 `CharsetManager` 将索引映射为实际字符，并应用可选的字符集范围限制（`charset_range`），最终拼接为字符串返回。

OCR 引擎支持三种模型选择（`ocr_engine.py:39-43`）：
- **默认旧版模型**：`common_old.onnx`
- **Beta 版模型**：`common.onnx`
- **自定义模型**：用户通过 `import_onnx_path` 指定自己的 ONNX 文件和字符集 JSON

此外还支持两个图像增强功能：
- **PNG 透明背景修复**（`png_fix`）：将 RGBA 透明区域替换为黑色
- **颜色过滤**（`color_filter_colors` / `color_filter_custom_ranges`）：通过 HSV 颜色空间过滤特定颜色区域

Sources: [ddddocr/core/ocr_engine.py:20-43]() | [ddddocr/core/ocr_engine.py:159-215]() | [ddddocr/core/ocr_engine.py:300-329]() | [ddddocr/models/model_loader.py:119-150]()

## 引擎二：检测引擎（目标检测）

**职责：** 在图片中定位目标物体的位置，返回边界框坐标。

`DetectionEngine`（`ddddocr/core/detection_engine.py:20`）使用 YOLOX 风格的检测模型（`common_det.onnx`），其推理流程如下：

1. **预处理**（`detection_engine.py:89-104`）——将图片等比缩放并填充到 `(416, 416)` 的固定尺寸，填充值为 114（灰色），然后转置为 CHW 格式。
2. **模型推理**（`detection_engine.py:173-188`）——送入 ONNX 会话获得原始输出。
3. **后处理**（`detection_engine.py:106-126`）——根据多尺度 stride（8, 16, 32）生成网格坐标，将模型输出的偏移量解码为实际的边界框中心坐标和宽高。
4. **NMS 过滤**（`detection_engine.py:128-171`）——先按类别分数筛选（阈值 0.1），再用非极大值抑制（IoU 阈值 0.45）去除重叠框。
5. **坐标裁剪**（`detection_engine.py:189-212`）——将边界框坐标缩放回原始图片尺寸，并裁剪到图片范围内，最终输出 `[[x1, y1, x2, y2], ...]` 格式的列表。

检测引擎不支持自定义模型路径或字符集——它只做"找到目标在哪"这一件事，不关心目标是什么文字。

Sources: [ddddocr/core/detection_engine.py:89-104]() | [ddddocr/core/detection_engine.py:106-126]() | [ddddocr/core/detection_engine.py:128-171]() | [ddddocr/core/detection_engine.py:173-212]()

## 引擎三：滑块引擎（缺口定位）

**职责：** 比对滑块拼图的背景图和缺口图，计算出滑块需要水平移动的距离。

`SlideEngine`（`ddddocr/core/slide_engine.py:20`）是三个引擎中最特殊的一个——它**不加载任何 ONNX 模型**，完全依赖 OpenCV 的传统图像处理算法。初始化时直接标记为已就绪（`slide_engine.py:29`），`is_ready()` 永远返回 `True`（`slide_engine.py:276-284`）。

它提供两种匹配模式：

### slide_match：模板匹配模式

适用于用户分别持有**滑块小图**和**背景大图**的场景（`slide_engine.py:45-81`）。

- **简单滑块**（`simple_target=True`）：直接用 `cv2.matchTemplate` 做模板匹配（`TM_CCOEFF_NORMED`），找到最佳匹配位置（`slide_engine.py:200-234`）。
- **复杂滑块**（`simple_target=False`）：先对两张图做 Canny 边缘检测（阈值 50/150），再在边缘图上做模板匹配（`slide_engine.py:236-274`）。这种方式对背景干扰更鲁棒。

两种方式都返回 `{target: [x, y], confidence: float}` 格式的结果，其中 `[x, y]` 是滑块中心在背景图中的目标坐标。

### slide_comparison：差异比较模式

适用于用户持有一张**带缺口的完整图**和一张**无缺口的完整背景图**的场景（`slide_engine.py:83-117`）。

处理流程（`slide_engine.py:149-198`）：
1. 用 `cv2.absdiff` 计算两张图的像素级差异
2. 转灰度后二值化（阈值 30）
3. 用形态学闭运算 + 开运算去噪
4. `findContours` 查找轮廓，取面积最大的轮廓作为缺口
5. 返回该轮廓的边界框中心坐标

Sources: [ddddocr/core/slide_engine.py:20-29]() | [ddddocr/core/slide_engine.py:119-147]() | [ddddocr/core/slide_engine.py:149-198]() | [ddddocr/core/slide_engine.py:236-274]()

## 三个引擎的对比

| 特性 | OCR 引擎 | 检测引擎 | 滑块引擎 |
|------|---------|---------|---------|
| **类名** | `OCREngine` | `DetectionEngine` | `SlideEngine` |
| **是否需要 ONNX 模型** | 是（`common_old.onnx` 或 `common.onnx`） | 是（`common_det.onnx`） | 否 |
| **推理框架** | ONNX Runtime | ONNX Runtime | OpenCV |
| **输入** | 单张验证码图片 | 单张图片 | 两张图（滑块+背景 或 有坑图+无坑图） |
| **输出** | 识别文字字符串 | 边界框列表 `[[x1,y1,x2,y2]]` | 目标坐标 `{target: [x, y]}` |
| **支持自定义模型** | 是（`import_onnx_path`） | 否 | 不适用 |
| **支持 GPU** | 是 | 是 | 不适用 |
| **后处理核心算法** | CTC 解码 | YOLOX 解码 + NMS | 模板匹配 / 差异比较 |

## 引擎的组装与调度

`DdddOcr` 类（`ddddocr/compat/v1.py:18`）是面向用户的统一入口。它的 `__init__` 方法（`v1.py:26-93`）根据参数决定引擎的实例化策略：

- `det=True` → 创建 `DetectionEngine`，标记为检测模式
- `ocr=True`（默认）或提供了 `import_onnx_path` → 创建 `OCREngine`
- 以上都不满足 → 仅启用滑块模式

**关键设计：滑块引擎始终被创建**（`v1.py:93`），无论用户选择的是 OCR 模式还是检测模式。这意味着用户可以在同一个 `DdddOcr` 实例上同时做 OCR 识别和滑块匹配，但 OCR 和检测是互斥的——一个实例只能处于其中一种模式。

调用时，`classification()` 方法转发到 `ocr_engine.predict()`（`v1.py:95-127`），`detection()` 方法转发到 `detection_engine.predict()`（`v1.py:129-148`），`slide_match()` 和 `slide_comparison()` 则转发到 `slide_engine` 的对应方法（`v1.py:150-190`）。

Sources: [ddddocr/compat/v1.py:26-93]() | [ddddocr/compat/v1.py:95-127]() | [ddddocr/compat/v1.py:129-148]() | [ddddocr/compat/v1.py:150-190]()

## 总结

ddddocr 的三引擎架构体现了一个清晰的职责分离原则：OCR 引擎专注文字识别的深度学习推理与 CTC 解码，检测引擎负责通用目标定位的 YOLOX 流水线，滑块引擎则用传统图像算法高效解决验证码缺口定位问题。三者通过 `BaseEngine` 统一接口、通过 `DdddOcr` 门面类对外暴露，既保持了各自内部实现的独立性，又为用户提供了简洁一致的使用体验。滑块引擎不依赖模型的特性使其始终可用，成为另外两个引擎的有力补充。
