# OCR 文字识别引擎

> OCREngine 的初始化流程、图像预处理管线、CTC 解码逻辑、概率输出与字符集范围限制

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

## Source Files

- `ddddocr/core/ocr_engine.py`
- `ddddocr/core/base.py`
- `ddddocr/models/charset_manager.py`
- `ddddocr/preprocessing/image_processor.py`
- `ddddocr/utils/image_io.py`

---

<details>
<summary>相关源文件</summary>
以下文件用于生成此维基页面：
- [ddddocr/core/ocr_engine.py](ddddocr/core/ocr_engine.py)
- [ddddocr/core/base.py](ddddocr/core/base.py)
- [ddddocr/models/charset_manager.py](ddddocr/models/charset_manager.py)
- [ddddocr/models/model_loader.py](ddddocr/models/model_loader.py)
- [ddddocr/preprocessing/image_processor.py](ddddocr/preprocessing/image_processor.py)
- [ddddocr/preprocessing/color_filter.py](ddddocr/preprocessing/color_filter.py)
- [ddddocr/utils/image_io.py](ddddocr/utils/image_io.py)
- [ddddocr/utils/validators.py](ddddocr/utils/validators.py)
</details>

# OCR 文字识别引擎

`OCREngine` 是 ddddocr 项目的核心识别组件，负责从图像中提取文字。它基于 ONNX Runtime 推理后端，将图像经预处理、模型推理、CTC 解码后输出文本结果。本文档详细说明其初始化流程、图像预处理管线、CTC 解码逻辑、概率输出以及字符集范围限制机制。

---

## 整体架构

`OCREngine` 继承自抽象基类 `BaseEngine`，遵循"初始化 → 预处理 → 推理 → 解码"的标准 OCR 推理管线。

```
┌─────────────────────────────────────────────────────┐
│                     OCREngine                        │
│                                                      │
│  ┌──────────────┐  ┌──────────────┐  ┌────────────┐ │
│  │ ModelLoader   │  │CharsetManager│  │ImageProc.  │ │
│  │ (ONNX加载)    │  │ (字符集管理)  │  │ (图像处理)  │ │
│  └──────┬───────┘  └──────┬───────┘  └─────┬──────┘ │
│         │                 │                │         │
│  ┌──────┴─────────────────┴────────────────┴──────┐  │
│  │              predict() 推理管线                 │  │
│  │  load_image → color_filter → preprocess →      │  │
│  │  onnx_session.run → ctc_decode → charset_range │  │
│  └────────────────────────────────────────────────┘  │
└─────────────────────────────────────────────────────┘
```

`BaseEngine` 定义了 `session`（ONNX 推理会话）、`model_loader`（模型加载器）等通用属性，以及 `is_ready()`、`cleanup()`、`switch_device()` 等生命周期方法。`OCREngine` 在此基础上组合了 `CharsetManager` 实现字符集管理。

Sources: [ddddocr/core/base.py:15-113](), [ddddocr/core/ocr_engine.py:20-54]()

---

## 初始化流程

`OCREngine.__init__()` 接收以下参数：

| 参数 | 类型 | 默认值 | 说明 |
|------|------|--------|------|
| `use_gpu` | `bool` | `False` | 是否启用 GPU 推理 |
| `device_id` | `int` | `0` | GPU 设备编号 |
| `old` | `bool` | `False` | 使用旧版模型（`common_old.onnx`） |
| `beta` | `bool` | `False` | 使用 beta 版模型（`common.onnx`） |
| `import_onnx_path` | `str` | `""` | 自定义 ONNX 模型路径 |
| `charsets_path` | `str` | `""` | 自定义字符集 JSON 路径 |

构造函数立即调用 `initialize()`，分两条路径完成初始化：

**默认模型路径：** 调用 `ModelLoader.load_ocr_model()` 加载内置 ONNX 模型，再通过 `CharsetManager.load_default_charset()` 加载内置字符集。默认配置为 `resize=[64, 64]`、`channel=1`（灰度）。

**自定义模型路径：** 当 `import_onnx_path` 非空时，调用 `ModelLoader.load_custom_model()` 同时加载模型和字符集 JSON 文件。字符集文件必须包含 `charset`、`word`、`image`、`channel` 四个字段，引擎据此配置识别模式。

两条路径最终都会调用 `CharsetManager._update_valid_indices()` 建立初始的有效字符索引映射。

Sources: [ddddocr/core/ocr_engine.py:23-97](), [ddddocr/models/model_loader.py:119-150](), [ddddocr/models/charset_manager.py:29-46]()

---

## 图像预处理管线

`predict()` 接受多种输入格式（`bytes`、文件路径字符串、`base64` 编码字符串、`PIL.Image`、`numpy.ndarray`），经统一加载后进入预处理管线。

### 输入统一化

`load_image_from_input()` 将所有输入格式转换为 `PIL.Image` 对象。对于字符串输入，优先按文件路径加载，失败则尝试 base64 解码。

Sources: [ddddocr/utils/image_io.py:82-119]()

### 颜色过滤（可选）

当传入 `color_filter_colors` 或 `color_filter_custom_ranges` 参数时，使用 `ColorFilter` 在 HSV 颜色空间进行颜色过滤。内置预设包括 red、blue、green、yellow 等 10 种颜色，每种对应预定义的 HSV 范围。过滤后的非目标颜色区域被设为白色背景。

Sources: [ddddocr/preprocessing/color_filter.py:19-111]()

### 尺寸调整与灰度转换

`_preprocess_image()` 根据模型类型执行不同的缩放策略：

- **默认模型**：固定目标高度为 64 像素，宽度按原始宽高比等比缩放，然后转换为灰度图。
- **自定义模型**：根据 `resize` 配置决定。当 `resize[0] == -1` 时，`word` 模式下缩放为正方形，否则按高度等比缩放；否则直接缩放到指定尺寸。仅当 `channel == 1` 时转为灰度。

Sources: [ddddocr/core/ocr_engine.py:159-215](), [ddddocr/preprocessing/image_processor.py:21-60](), [ddddocr/preprocessing/image_processor.py:62-79]()

### 张量标准化

预处理最后将图像转为 `float32` 的 numpy 数组，归一化到 `[0, 1]` 范围，并调整维度为 `(batch, channel, height, width)` 的 NCHW 格式，送入 ONNX 模型。

Sources: [ddddocr/core/ocr_engine.py:198-212]()

---

## CTC 解码逻辑

OCR 模型输出的原始张量形状通常为 `(sequence_length, batch_size, num_classes)` 或 `(batch_size, sequence_length, num_classes)`。解码分两步完成。

### 第一步：索引级 CTC 解码

`_ctc_decode_indices()` 实现标准 CTC（Connectionist Temporal Classification）贪心解码：

1. 对每个时间步取 `argmax` 得到预测索引。
2. 去除连续重复索引（如 `[..., 3, 3, 3, ...]` → 只保留一个 `3`）。
3. 跳过 blank 字符（索引 0，对应字符集中的空字符串 `""`）。

```python
def _ctc_decode_indices(self, predicted_indices: np.ndarray) -> List[int]:
    decoded_indices = []
    prev_idx = None
    for idx in predicted_indices:
        idx = int(idx)
        if idx != prev_idx:      # 去除连续重复
            if idx != 0:         # 跳过 blank（索引0）
                decoded_indices.append(idx)
        prev_idx = idx
    return decoded_indices
```

### 第二步：字符映射与范围过滤

解码后的索引列表依次与 `CharsetManager` 的有效索引比对。不在 `valid_charset_range_index` 中的索引被丢弃；有效索引通过字符集映射为字符后拼接为最终文本。

Sources: [ddddocr/core/ocr_engine.py:244-298](), [ddddocr/core/ocr_engine.py:300-329]()

---

## 概率输出

当 `probability=True` 时，`_process_probability_output()` 在原始输出上沿类别轴执行 softmax，生成每个时间步的概率分布。返回的字典结构如下：

| 字段 | 类型 | 说明 |
|------|------|------|
| `text` | `str` | 识别文本（同样经 CTC 解码） |
| `probabilities` | `list` | 每个时间步各类别的概率值 |
| `confidence` | `float` | 所有时间步最大概率的均值 |
| `charset` | `list` | 完整字符集列表 |

softmax 实现使用数值稳定版本（先减去最大值），避免指数溢出。

Sources: [ddddocr/core/ocr_engine.py:331-377]()

---

## 字符集范围限制

`CharsetManager.set_ranges()` 支持三种方式限制识别字符范围，用于约束模型只输出指定字符子集：

| 输入类型 | 行为 |
|----------|------|
| `int` | 取字符集前 N+1 个字符作为有效范围 |
| `str` | 将字符串中的每个字符作为有效范围 |
| `List[str]` | 直接使用列表中的字符作为有效范围 |

设置范围后，`_update_valid_indices()` 计算这些字符在原始字符集中的索引列表 `valid_charset_range_index`。推理时，CTC 解码后的索引若不在该列表中则被跳过。

范围列表末尾会自动追加空字符串 `""`（即 blank 字符），以确保 CTC blank 机制正常工作。调用 `predict()` 时不传 `charset_range` 参数，或传入 `None`，则使用完整字符集的所有索引。

Sources: [ddddocr/models/charset_manager.py:83-124](), [ddddocr/core/ocr_engine.py:141-146]()

---

## 错误处理

引擎在关键环节设置了异常捕获与转换：

- 模型加载失败抛出 `ModelLoadError`。
- 图像处理失败抛出 `ImageProcessError`。
- 颜色过滤失败时仅打印警告并跳过该步骤，不中断识别流程。
- 未初始化时调用 `predict()` 会直接抛出 `ModelLoadError("OCR引擎未初始化")`。

Sources: [ddddocr/core/ocr_engine.py:96-97](), [ddddocr/core/ocr_engine.py:122-123](), [ddddocr/core/ocr_engine.py:137-139]()
