# ddddocr 技术参考手册

> ddddocr 是一个离线通用验证码识别 Python SDK，基于 ONNX Runtime 推理，支持 OCR 文字识别、目标检测和滑块验证码匹配三大核心能力，同时提供 RESTful API 与 MCP 协议集成。

## Context Links

- [Agent index](https://grok-wiki.com/public/wiki/sml2h3-ddddocr-10e2eae686bf/llms.txt)
- [Human interactive wiki](https://grok-wiki.com/public/wiki/sml2h3-ddddocr-10e2eae686bf)
- [GitHub repository](https://github.com/sml2h3/ddddocr)

## Repository Metadata

- Repository: sml2h3/ddddocr

- Generated: 2026-06-23T07:57:43.214Z
- Updated: 2026-06-23T08:02:09.819Z
- Runtime: Claude Code
- Format: Technical
- Pages: 10

## Page Index

- 01. [技术概览](https://grok-wiki.com/public/wiki/sml2h3-ddddocr-10e2eae686bf/pages/01-page-1.md) - ddddocr 项目定位、整体架构、核心入口与模块职责全景图
- 02. [安装与环境配置](https://grok-wiki.com/public/wiki/sml2h3-ddddocr-10e2eae686bf/pages/02-page-2.md) - PyPI/源码安装方式、Python 版本要求、平台兼容性、GPU 加速配置与依赖说明
- 03. [CLI 命令与 API 服务启动](https://grok-wiki.com/public/wiki/sml2h3-ddddocr-10e2eae686bf/pages/03-cli-api.md) - ddddocr CLI 子命令用法、API 服务启动参数、Docker 部署与健康检查
- 04. [OCR 文字识别引擎](https://grok-wiki.com/public/wiki/sml2h3-ddddocr-10e2eae686bf/pages/04-ocr.md) - OCREngine 的初始化流程、图像预处理管线、CTC 解码逻辑、概率输出与字符集范围限制
- 05. [目标检测引擎](https://grok-wiki.com/public/wiki/sml2h3-ddddocr-10e2eae686bf/pages/05-page-5.md) - DetectionEngine 的 YOLOX 风格推理流程：预处理、锚点解码、NMS 后处理与边界框输出
- 06. [滑块验证码匹配引擎](https://grok-wiki.com/public/wiki/sml2h3-ddddocr-10e2eae686bf/pages/06-page-6.md) - SlideEngine 的两种匹配算法：边缘检测模板匹配与图像差异比较，以及结果坐标输出
- 07. [图像预处理与颜色过滤](https://grok-wiki.com/public/wiki/sml2h3-ddddocr-10e2eae686bf/pages/07-page-7.md) - ImageProcessor 的尺寸调整、灰度转换、去噪与二值化能力，以及 ColorFilter 的 HSV 颜色空间过滤机制
- 08. [模型加载与字符集管理](https://grok-wiki.com/public/wiki/sml2h3-ddddocr-10e2eae686bf/pages/08-page-8.md) - ModelLoader 的 ONNX 模型加载、GPU/CPU 提供者切换，CharsetManager 的字符集加载与范围限制机制
- 09. [RESTful API 参考](https://grok-wiki.com/public/wiki/sml2h3-ddddocr-10e2eae686bf/pages/09-restful-api.md) - FastAPI 服务的全部端点定义、请求/响应模型、功能初始化与运行时切换流程
- 10. [MCP 协议集成](https://grok-wiki.com/public/wiki/sml2h3-ddddocr-10e2eae686bf/pages/10-mcp.md) - MCP（Model Context Protocol）端点、能力声明与工具调用机制，使 AI Agent 能直接调用 ddddocr 识别服务

## Source File Index

- `ddddocr/__init__.py`
- `ddddocr/__main__.py`
- `ddddocr/api/__init__.py`
- `ddddocr/api/app.py`
- `ddddocr/api/mcp.py`
- `ddddocr/api/models.py`
- `ddddocr/api/routes.py`
- `ddddocr/api/server.py`
- `ddddocr/compat/v1.py`
- `ddddocr/core/__init__.py`
- `ddddocr/core/base.py`
- `ddddocr/core/detection_engine.py`
- `ddddocr/core/ocr_engine.py`
- `ddddocr/core/slide_engine.py`
- `ddddocr/models/__init__.py`
- `ddddocr/models/charset_manager.py`
- `ddddocr/models/model_loader.py`
- `ddddocr/preprocessing/__init__.py`
- `ddddocr/preprocessing/color_filter.py`
- `ddddocr/preprocessing/image_processor.py`
- `ddddocr/utils/exceptions.py`
- `ddddocr/utils/image_io.py`
- `ddddocr/utils/validators.py`
- `docker-compose.yml`
- `Dockerfile`
- `pyproject.toml`
- `README.md`
- `requirements.txt`

---

## 01. 技术概览

> ddddocr 项目定位、整体架构、核心入口与模块职责全景图

- Page Markdown: https://grok-wiki.com/public/wiki/sml2h3-ddddocr-10e2eae686bf/pages/01-page-1.md
- Generated: 2026-06-23T07:48:43.881Z

### Source Files

- `README.md`
- `pyproject.toml`
- `ddddocr/__init__.py`
- `ddddocr/compat/v1.py`
- `ddddocr/core/__init__.py`
- `ddddocr/core/base.py`

<details>
<summary>相关源文件</summary>
以下文件用于生成此维基页面：
- [README.md](README.md)
- [pyproject.toml](pyproject.toml)
- [ddddocr/__init__.py](ddddocr/__init__.py)
- [ddddocr/__main__.py](ddddocr/__main__.py)
- [ddddocr/compat/v1.py](ddddocr/compat/v1.py)
- [ddddocr/core/__init__.py](ddddocr/core/__init__.py)
- [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/api/app.py](ddddocr/api/app.py)
- [ddddocr/models/model_loader.py](ddddocr/models/model_loader.py)
- [ddddocr/utils/__init__.py](ddddocr/utils/__init__.py)
</details>

# 技术概览

本文梳理 ddddocr（v1.6.1）的整体定位、包结构、核心引擎职责以及对外入口形态，帮助开发者在阅读源码前建立全局认知。

---

## 项目定位

ddddocr 是一个**离线、本地运行**的通用验证码识别 Python SDK，由 sml2h3 与 kerlomz 共同开发。项目通过大批量随机数据训练深度网络，以 ONNX 格式分发模型，推理层完全依赖 `onnxruntime`，无需联网即可工作。

核心设计原则是**最简依赖**——`pyproject.toml` 声明的运行时依赖仅 `numpy`、`onnxruntime`、`Pillow` 和 `opencv-python`（或 `opencv-python-headless`），Python 版本要求 ≥ 3.10。

**来源:** [pyproject.toml:6-28]() | [README.md:62-69]()

---

## 功能矩阵

ddddocr 通过初始化参数组合切换三种工作模式：

| 模式 | 典型参数 | 公开方法 | 说明 |
|------|----------|----------|------|
| OCR 文字识别 | `ocr=True, det=False`（默认） | `classification()` | 识别英数、中文、特殊字符验证码 |
| 目标检测 | `ocr=False, det=True` | `detection()` | 返回目标边界框坐标 `[[x1,y1,x2,y2], ...]` |
| 滑块验证码 | `ocr=False, det=False` | `slide_match()` / `slide_comparison()` | 边缘匹配或图像差异比较 |

此外支持 `import_onnx_path` + `charsets_path` 导入自定义模型（由 [dddd_trainer](https://github.com/sml2h3/dddd_trainer) 训练），此时 `ocr`/`det` 参数被忽略。

**来源:** [README.md:107-174]() | [ddddocr/compat/v1.py:72-93]()

---

## 包结构与模块职责

```
ddddocr/
├── __init__.py          # 公开 API 入口，从 compat.v1 导入 DdddOcr
├── __main__.py          # CLI 入口（ddddocr api 子命令）
├── compat/
│   └── v1.py            # 向后兼容外观类 DdddOcr，组合三大引擎
├── core/
│   ├── base.py          # BaseEngine 抽象基类（initialize/predict/switch_device/cleanup）
│   ├── ocr_engine.py    # OCREngine — 文字识别
│   ├── detection_engine.py  # DetectionEngine — 目标检测
│   └── slide_engine.py  # SlideEngine — 滑块匹配（不依赖模型）
├── models/
│   ├── model_loader.py  # ModelLoader — ONNX 模型加载与 Provider 管理
│   └── charset_manager.py  # CharsetManager — 字符集管理与范围过滤
├── preprocessing/
│   ├── image_processor.py  # 图像预处理（尺寸、格式转换）
│   └── color_filter.py     # HSV 颜色过滤
├── utils/
│   ├── image_io.py      # 图片加载、PNG 透明通道修复
│   ├── exceptions.py    # DDDDOCRError / ModelLoadError / ImageProcessError
│   ├── validators.py    # 输入校验（图片、模型配置）
│   └── compat.py        # 向后兼容常量与别名
└── api/
    ├── app.py           # FastAPI 应用定义与全部路由
    ├── server.py        # uvicorn 启动逻辑
    ├── models.py        # Pydantic 请求/响应模型
    └── routes.py        # 路由分组（若存在）
```

**来源:** 通过 `find` 命令枚举 `ddddocr/` 目录下所有 `.py` 文件得到。

---

## 核心架构：兼容层 → 引擎层 → 模型层

### 兼容层（compat/v1.py）

`DdddOcr` 类是唯一的用户入口。它在 `__init__` 中根据参数决定初始化哪个引擎：

```python
# ddddocr/compat/v1.py:72-93
if det:
    self.detection_engine = DetectionEngine(use_gpu, device_id)
elif ocr or import_onnx_path:
    self.ocr_engine = OCREngine(...)
else:
    pass  # 滑块模式，不需要模型
self.slide_engine = SlideEngine()  # 滑块引擎始终可用
```

`classification()`、`detection()`、`slide_match()`、`slide_comparison()` 等方法均为委托调用，先检查模式合法性再转发到对应引擎。

**来源:** [ddddocr/compat/v1.py:72-93]() | [ddddocr/compat/v1.py:95-127]()

### 引擎层（core/）

`BaseEngine`（`core/base.py`）定义了所有引擎的公共接口：

- `initialize()` — 抽象方法，子类实现模型加载
- `predict()` — 抽象方法，子类实现推理逻辑
- `switch_device()` — 运行时切换 CPU/GPU
- `cleanup()` — 释放 `onnxruntime.InferenceSession`

| 引擎 | 文件 | 继承自 BaseEngine | 依赖模型 | 关键方法 |
|------|------|-------------------|----------|----------|
| `OCREngine` | `core/ocr_engine.py` | ✓ | ✓（ONNX） | `predict(image, png_fix, probability, colors)` |
| `DetectionEngine` | `core/detection_engine.py` | ✓ | ✓（ONNX） | `predict(image)` → `List[List[int]]` |
| `SlideEngine` | `core/slide_engine.py` | ✓ | ✗ | `slide_match()` / `slide_comparison()` |

`SlideEngine` 比较特殊——它不调用父类 `__init__`，不需要模型加载器，仅依赖 OpenCV 的边缘检测和图像差分算法。

**来源:** [ddddocr/core/base.py:15-43]() | [ddddocr/core/slide_engine.py:20-29]()

### 模型层（models/）

`ModelLoader`（`models/model_loader.py`）负责：
1. 根据 `use_gpu` 选择 `CUDAExecutionProvider` 或 `CPUExecutionProvider`
2. 从包内资源（`*.onnx` 文件）或自定义路径加载模型
3. 管理 `onnxruntime.InferenceSession` 的生命周期

`CharsetManager`（`models/charset_manager.py`）管理字符集的加载、过滤（`set_ranges()` 支持 0-7 预设或自定义字符串）。

**来源:** [ddddocr/models/model_loader.py:16-30]() | [pyproject.toml:51-52]()

---

## 入口形态

### Python SDK

```python
import ddddocr
ocr = ddddocr.DdddOcr()          # 初始化（加载模型）
result = ocr.classification(img)  # 识别
```

`ddddocr/__init__.py` 将 `DdddOcr` 从 `compat.v1` 导入并重新导出，同时导出 `DdddOcrInputError`、`InvalidImageError` 等异常类和 `base64_to_image`、`get_img_base64` 工具函数。

**来源:** [ddddocr/__init__.py:1-26]()

### CLI（python -m ddddocr api）

`__main__.py` 提供 `ddddocr api` 子命令，将命令行参数写入环境变量后调用 `ddddocr.api.main()` 启动 uvicorn 服务。

**来源:** [ddddocr/__main__.py:8-69]()

### REST API（FastAPI）

`api/app.py` 定义 FastAPI 应用，暴露以下端点：

| 端点 | 方法 | 功能 |
|------|------|------|
| `/health` | GET | 健康检查 |
| `/ocr`、`/ocr/file` | POST | 文字识别（Base64 / 文件上传） |
| `/det`、`/det/file` | POST | 目标检测 |
| `/slide_match` | POST | 滑块边缘匹配 |
| `/slide_comparison` | POST | 滑块图像差异比较 |
| `/set_charset_range` | POST | 设置字符范围 |
| `/config` | GET | 查看当前配置与活跃实例数 |

API 层通过 `get_ocr_instance()` 按配置键缓存 `DdddOcr` 实例，并在每次请求后通过 `BackgroundTasks` 异步清理超过 1 小时不活跃的实例。

**来源:** [ddddocr/api/app.py:300-307]() | [ddddocr/api/app.py:330-333]() | [ddddocr/api/app.py:335-404]()

---

## 数据流概览

以 OCR 识别为例，请求从入口到结果的完整路径：

```
用户代码 / HTTP 请求
       │
       ▼
  DdddOcr.classification(image)          ← compat/v1.py
       │
       ▼
  OCREngine.predict(image, ...)          ← core/ocr_engine.py
       │
       ├─ validate_image_input()          ← utils/validators.py
       ├─ load_image_from_input()         ← utils/image_io.py
       ├─ png_rgba_black_preprocess()     ← PNG 透明通道修复
       ├─ ColorFilter.apply()             ← 颜色过滤（可选）
       ├─ ImageProcessor.preprocess()     ← 尺寸/格式预处理
       ├─ session.run()                   ← onnxruntime 推理
       └─ CharsetManager.decode()         ← 索引→字符解码
              │
              ▼
         返回 str 或 {charsets, probability}
```

---

## 运行时依赖与兼容性

| 依赖 | 用途 |
|------|------|
| `onnxruntime` | ONNX 模型推理（CPU/GPU） |
| `numpy` | 图像张量处理 |
| `Pillow` | 图片加载与格式转换 |
| `opencv-python` / `opencv-python-headless` | 预处理、边缘检测、滑块匹配 |

支持平台：Windows 64 位、Linux 64/ARM64、macOS X64（含 Apple Silicon 适配），最大 Python 版本 3.12。不支持 32 位系统。

**来源:** [pyproject.toml:22-28]() | [README.md:73-80]()

---

## 小结

ddddocr 采用**兼容层 → 引擎层 → 模型层**的三层架构：兼容层（`compat/v1.py`）提供稳定的 `DdddOcr` 类接口；引擎层（`core/`）将 OCR、目标检测、滑块匹配三种能力封装为独立引擎，共享 `BaseEngine` 抽象基类；模型层（`models/`）负责 ONNX 模型加载与字符集管理。项目同时提供 Python SDK、CLI 和 FastAPI 三种入口形态，通过最少的依赖实现离线验证码识别的全流程覆盖。

---

## 02. 安装与环境配置

> PyPI/源码安装方式、Python 版本要求、平台兼容性、GPU 加速配置与依赖说明

- Page Markdown: https://grok-wiki.com/public/wiki/sml2h3-ddddocr-10e2eae686bf/pages/02-page-2.md
- Generated: 2026-06-23T07:48:02.582Z

### Source Files

- `pyproject.toml`
- `requirements.txt`
- `ddddocr/utils/exceptions.py`
- `ddddocr/models/model_loader.py`

<details>
<summary>相关源文件</summary>
以下文件用于生成此维基页面：
- [pyproject.toml](pyproject.toml)
- [requirements.txt](requirements.txt)
- [ddddocr/utils/exceptions.py](ddddocr/utils/exceptions.py)
- [ddddocr/models/model_loader.py](ddddocr/models/model_loader.py)
- [README.md](README.md)
</details>

# 安装与环境配置

本页面介绍 DdddOcr（ddddocr）的安装方式、Python 版本要求、平台兼容性、GPU 加速配置以及各依赖库的用途说明。DdddOcr 是一个通用验证码离线本地识别 SDK，采用"最简依赖"设计理念，尽量减少用户的配置成本。

## Python 版本要求

DdddOcr 要求 **Python ≥ 3.10**，官方测试覆盖 Python 3.10 至 3.13。

| 分类器声明 | 来源 |
|-----------|------|
| `Programming Language :: Python :: 3.10` | `pyproject.toml:16` |
| `Programming Language :: Python :: 3.11` | `pyproject.toml:17` |
| `Programming Language :: Python :: 3.12` | `pyproject.toml:18` |
| `Programming Language :: Python :: 3.13` | `pyproject.toml:19` |

> **注意**：低于 3.10 的 Python 版本不受支持，pip 在安装时会直接拒绝。

## 平台兼容性

DdddOcr 支持 64 位主流操作系统，不支持 32 位系统。

| 平台 | CPU 支持 | GPU 支持 | 备注 |
|------|---------|---------|------|
| Windows 64 位 | ✓ | ✓ | 部分版本需安装 [VC 运行库](https://www.ghxi.com/yxkhj.html) |
| Linux x86_64 / ARM64 | ✓ | ✓ | — |
| macOS x64（Intel） | ✓ | ✓ | — |
| macOS ARM64（M1/M2/M3） | ✓ | — | 参考 [Issue #67](https://github.com/sml2h3/ddddocr/issues/67) |

OpenCV 依赖按平台自动区分包名（`opencv-python` vs `opencv-python-headless`），详见下文依赖说明。

Sources: [README.md:73-80](README.md), [pyproject.toml:26-28](pyproject.toml)

## 安装方式

### 从 PyPI 安装（推荐）

```bash
pip install ddddocr
```

这是最简单的方式，pip 会自动解析并安装所有依赖。

### 从源码安装

```bash
git clone https://github.com/sml2h3/ddddocr.git
cd ddddocr
pip install .
```

项目使用 `setuptools` 作为构建后端，`pip install .` 会自动读取 `pyproject.toml` 并完成安装。

Sources: [pyproject.toml:1-4](pyproject.toml)

### 安装可选 API 依赖

如需通过 RESTful API 方式使用 DdddOcr，可安装 `api` 额外依赖组：

```bash
pip install "ddddocr[api]"
# 或从源码
pip install ".[api]"
```

`api` 依赖组包含 FastAPI、Uvicorn、Pydantic 等 Web 服务组件。

Sources: [pyproject.toml:34-39](pyproject.toml)

### Docker 部署

项目提供 `Dockerfile` 和 `docker-compose.yml`，可用于容器化部署 API 服务：

```bash
# 构建并运行
docker build -t ddddocr-api .
docker run -d --name ddddocr-api -p 8000:8000 ddddocr-api

# 或使用 docker-compose
docker-compose up -d
```

容器内可通过环境变量（如 `DDDDOCR_OCR`、`DDDDOCR_BETA`、`DDDDOCR_WORKERS` 等）配置服务参数。

## 核心依赖说明

DdddOcr 的核心运行依赖如下：

| 依赖库 | 最低版本 | 用途 |
|--------|---------|------|
| `numpy` | — | 数值计算，图像数组处理 |
| `onnxruntime` | — | ONNX 模型推理引擎，核心推理后端 |
| `Pillow` | — | 图像读取与格式转换 |
| `opencv-python` | — | 图像处理（Windows / macOS） |
| `opencv-python-headless` | — | 图像处理（Linux，无 GUI 依赖） |

Sources: [pyproject.toml:22-28](pyproject.toml), [requirements.txt:1-5](requirements.txt)

**平台特定 OpenCV 包选择**：在 Linux 服务器环境下自动使用 `opencv-python-headless`（无 GUI 依赖），在 Windows 和 macOS 上使用完整的 `opencv-python`。

```toml
# pyproject.toml 中的平台条件依赖
"opencv-python; sys_platform == 'win32' or sys_platform == 'darwin'",
"opencv-python-headless; sys_platform == 'linux'",
```

### 可选 API 依赖

| 依赖库 | 版本要求 | 用途 |
|--------|---------|------|
| `fastapi` | ≥ 0.68.0 | Web API 框架 |
| `uvicorn` | ≥ 0.15.0 | ASGI 服务器 |
| `python-multipart` | ≥ 0.05 | 文件上传支持 |
| `pydantic` | ≥ 1.8.0, < 3 | 请求/响应数据校验 |
| `requests` | ≥ 2.25.0 | HTTP 客户端（requirements.txt 中） |

Sources: [pyproject.toml:34-39](pyproject.toml), [requirements.txt:6-10](requirements.txt)

## GPU 加速配置

DdddOcr 通过 ONNX Runtime 的 `CUDAExecutionProvider` 支持 GPU 加速推理。启用前需满足以下条件：

1. **安装 NVIDIA CUDA Toolkit**：确保系统已安装与 onnxruntime-gpu 兼容的 CUDA 版本。
2. **安装 onnxruntime-gpu**：替换默认的 `onnxruntime` 为 `onnxruntime-gpu`。
3. **初始化时指定 GPU 参数**：

```python
import ddddocr

# 使用 GPU 加速
ocr = ddddocr.DdddOcr(use_gpu=True, device_id=0)

# 多卡环境下使用第二张 GPU
ocr = ddddocr.DdddOcr(use_gpu=True, device_id=1)
```

GPU 模式下的 ONNX Runtime 提供者配置（来自 `ModelLoader._setup_providers`）：

```python
# ddddocr/models/model_loader.py:36-44
providers = [
    ('CUDAExecutionProvider', {
        'device_id': device_id,
        'arena_extend_strategy': 'kNextPowerOfTwo',
        'gpu_mem_limit': 2 * 1024 * 1024 * 1024,  # 2GB
        'cudnn_conv_algo_search': 'EXHAUSTIVE',
        'do_copy_in_default_stream': True,
    }),
    'CPUExecutionProvider'  # GPU 不可用时自动回退
]
```

**GPU 初始化失败回退机制**：如果 GPU 设置失败（如 CUDA 未安装或驱动不兼容），`ModelLoader` 会自动回退到 CPU 模式并输出警告信息，不会导致程序崩溃。

Sources: [ddddocr/models/model_loader.py:31-53](ddddocr/models/model_loader.py)

## OpenCV 导入问题排查

OpenCV 是最容易出现安装问题的依赖。当导入失败时，`exceptions.py` 中的 `handle_opencv_import_error` 会根据操作系统提供针对性的解决方案：

### Linux 系统

```bash
# Ubuntu/Debian
sudo apt-get install build-essential libglib2.0-0 libsm6 libxext6 libxrender-dev libgl1-mesa-glx

# CentOS/RHEL
sudo yum install gcc gcc-c++ make glib2-devel libSM libXext libXrender mesa-libGL
```

### Windows 系统

- 安装 [Visual C++ 运行库](https://www.ghxi.com/yxkhj.html)
- 确保使用 64 位 Python
- 尝试：`pip install opencv-python --force-reinstall`

### macOS 系统

```bash
# 使用 Homebrew
brew install opencv

# 或使用 conda
conda install opencv
```

M1/M2/M3 芯片用户请参考 [Issue #67](https://github.com/sml2h3/ddddocr/issues/67)。

### 通用解决方案

```bash
pip uninstall opencv-python opencv-python-headless
pip install opencv-python-headless
```

Sources: [ddddocr/utils/exceptions.py:31-81](ddddocr/utils/exceptions.py)

## 构建系统

项目使用现代 Python 打包规范：

- **构建后端**：`setuptools ≥ 64` + `wheel`
- **包发现**：自动发现以 `ddddocr` 开头的子包
- **内嵌资源**：ONNX 模型文件（`*.onnx`）、`logo.png`、`README.md` 随包分发
- **CLI 入口点**：`ddddocr` 命令映射到 `ddddocr.__main__:main`

```toml
# pyproject.toml 关键配置
[project.scripts]
ddddocr = "ddddocr.__main__:main"

[tool.setuptools.package-data]
ddddocr = ["*.onnx", "logo.png", "README.md"]
```

Sources: [pyproject.toml:42-53](pyproject.toml)

## 注意事项

1. **目录命名冲突**：请勿在 `ddddocr` 项目根目录内直接 `import ddddocr`，确保你的开发项目目录名称不为 `ddddocr`，否则会导致模块导入冲突。
2. **实例复用**：`DdddOcr` 对象初始化时会加载 ONNX 模型，耗时较长。应避免在循环中反复创建实例，推荐全局复用同一实例。
3. **ONNX 模型随包安装**：模型文件（`common_old.onnx`、`common.onnx`、`common_det.onnx`）内嵌在包中，无需额外下载。

---

## 03. CLI 命令与 API 服务启动

> ddddocr CLI 子命令用法、API 服务启动参数、Docker 部署与健康检查

- Page Markdown: https://grok-wiki.com/public/wiki/sml2h3-ddddocr-10e2eae686bf/pages/03-cli-api.md
- Generated: 2026-06-23T07:50:22.456Z

### Source Files

- `ddddocr/__main__.py`
- `ddddocr/api/__init__.py`
- `ddddocr/api/app.py`
- `ddddocr/api/server.py`
- `Dockerfile`
- `docker-compose.yml`

<details>
<summary>相关源文件</summary>
以下文件用于生成此维基页面：
- [ddddocr/__main__.py](ddddocr/__main__.py)
- [ddddocr/api/__init__.py](ddddocr/api/__init__.py)
- [ddddocr/api/app.py](ddddocr/api/app.py)
- [ddddocr/api/server.py](ddddocr/api/server.py)
- [Dockerfile](Dockerfile)
- [docker-compose.yml](docker-compose.yml)
</details>

# CLI 命令与 API 服务启动

ddddocr 提供了命令行接口（CLI）和基于 FastAPI 的 HTTP API 服务，用于启动验证码识别服务。本文档说明 CLI 子命令用法、API 服务启动参数、Docker 部署方式及健康检查机制。

## CLI 子命令

ddddocr 通过 `python -m ddddocr` 调用 CLI 入口，当前支持 `api` 子命令用于启动 HTTP API 服务。

```
python -m ddddocr api [--host HOST] [--port PORT] [--workers N] [其他选项...]
```

CLI 入口在 `ddddocr/__main__.py` 中定义，使用 `argparse` 解析参数后将所有配置写入环境变量，再调用 `ddddocr.api.main()` 启动服务。

### api 子命令参数

| 参数 | 类型 | 默认值 | 说明 |
|------|------|--------|------|
| `--host` | str | `0.0.0.0` | 服务绑定地址 |
| `--port` | int | `8000` | 服务监听端口 |
| `--workers` | int | `1` | uvicorn 工作进程数 |
| `--ocr` | bool | `true` | 启用 OCR 功能 |
| `--det` | bool | `false` | 启用目标检测功能 |
| `--old` | bool | `false` | 使用旧版 OCR 模型 |
| `--beta` | bool | `false` | 使用 Beta 版 OCR 模型 |
| `--use-gpu` | bool | `false` | 启用 GPU 加速 |
| `--device-id` | int | `0` | GPU 设备 ID |
| `--show-ad` | bool | `true` | 显示广告 |
| `--import-onnx-path` | str | `""` | 自定义模型路径 |
| `--charsets-path` | str | `""` | 自定义字符集路径 |

所有参数均通过环境变量 `DDDDOCR_*` 传递给 API 服务模块。

**Sources:** [ddddocr/__main__.py:8-79](), [Dockerfile:59-73]()

## API 服务架构

ddddocr 提供两套 FastAPI 应用实现：

1. **app.py 中的应用**（默认入口）：直接定义 FastAPI 路由，适用于简单部署场景。
2. **server.py 中的服务类**（`DDDService`）：通过 `create_app()` 工厂函数创建，支持 MCP 协议，适用于需要动态初始化和模型切换的场景。

```
ddddocr/api/
├── __init__.py   # 统一导出入口
├── app.py        # 直接路由的 FastAPI 应用 + main()
├── server.py     # DDDService 服务管理 + create_app()
├── routes.py     # 路由注册
├── models.py     # 请求/响应模型
└── mcp.py        # MCP 协议处理器
```

### 启动流程

当执行 `python -m ddddocr api` 时：

1. `__main__.py` 解析 CLI 参数，写入 `os.environ`
2. 调用 `ddddocr.api.main()`（来自 `app.py`）
3. `main()` 从环境变量读取 `host`、`port`、`workers`
4. 通过 `uvicorn.run("ddddocr.api:app", ...)` 启动服务

**Sources:** [ddddocr/api/app.py:743-751](), [ddddocr/api/__init__.py:1-14]()

## API 端点

### 基础端点

| 端点 | 方法 | 说明 |
|------|------|------|
| `/health` | GET | 健康检查，返回 `{"status": "ok", "timestamp": ...}` |
| `/config` | GET | 获取当前配置和活跃实例数 |
| `/docs` | GET | Swagger API 文档 |
| `/redoc` | GET | ReDoc API 文档 |

### OCR 识别

| 端点 | 方法 | 说明 |
|------|------|------|
| `/ocr` | POST | Base64 图片 OCR 识别 |
| `/ocr/file` | POST | 文件上传 OCR 识别 |

请求体（JSON 模式）：
```json
{
  "image": "<base64>",
  "probability": false,
  "colors": [],
  "custom_color_ranges": null
}
```

**Sources:** [ddddocr/api/app.py:330-332](), [ddddocr/api/app.py:335-404]()

### 目标检测

| 端点 | 方法 | 说明 |
|------|------|------|
| `/det` | POST | Base64 图片目标检测 |
| `/det/file` | POST | 文件上传目标检测 |

### 滑块验证码

| 端点 | 方法 | 说明 |
|------|------|------|
| `/slide_match` | POST | 滑块缺口位置匹配 |
| `/slide_comparison` | POST | 滑块图像差异比较 |

### 其他

| 端点 | 方法 | 说明 |
|------|------|------|
| `/set_charset_range` | POST | 设置 OCR 识别字符范围 |

### 实例管理机制

API 服务采用实例池模式管理 OCR 实例。相同配置的请求复用同一实例，以配置键（如 `ocr=true-det=false-old=false-...`）为标识。后台任务会定期清理超过 3600 秒未使用的实例以释放内存。

**Sources:** [ddddocr/api/app.py:239-298]()

## Docker 部署

### 使用 Dockerfile 构建

```bash
docker build -t ddddocr-api .
docker run -d -p 8000:8000 --name ddddocr-api ddddocr-api
```

Dockerfile 基于 `python:3.10-slim`，安装系统依赖（`libgl1-mesa-glx`、`libglib2.0-0` 等），将所有配置项设为环境变量，通过 `CMD python -m ddddocr api` 启动服务。

### 使用 Docker Compose

```bash
docker-compose up -d
```

docker-compose.yml 定义了服务 `ddddocr-api`，支持通过宿主机环境变量覆盖所有配置：

```bash
DDDDOCR_USE_GPU=true DDDDOCR_PORT=9000 docker-compose up -d
```

compose 配置还预留了 GPU 支持和资源限制的注释示例，可根据需要启用。

**Sources:** [Dockerfile:1-77](), [docker-compose.yml:1-80]()

## 健康检查

Dockerfile 和 docker-compose.yml 均配置了健康检查，通过定时请求 `/health` 端点判断服务是否正常：

```
HEALTHCHECK --interval=30s --timeout=10s --retries=3 \
  CMD curl -f http://localhost:${DDDDOCR_PORT}/health || exit 1
```

`/health` 端点返回 HTTP 200 及 JSON 响应 `{"status": "ok", "timestamp": <unix_time>}`。Docker 会在连续 3 次检查失败后将容器标记为 unhealthy。

**Sources:** [Dockerfile:76-77](), [ddddocr/api/app.py:330-332](), [docker-compose.yml:71-76]()

## server.py 服务管理（高级用法）

`server.py` 中的 `DDDService` 类提供更细粒度的服务管理能力：

- **动态初始化**：通过 `/initialize` 端点按需加载 OCR、检测或滑块模型
- **模型切换**：通过 `/switch_model` 端点在运行时切换模型版本
- **功能开关**：通过 `/toggle_feature` 端点动态启用/禁用功能
- **状态查询**：通过 `/status` 端点获取已加载模型、启用功能和运行时长
- **MCP 协议**：通过 `/mcp` 前缀提供 MCP 协议支持

**Sources:** [ddddocr/api/server.py:22-206]()

---

## 04. OCR 文字识别引擎

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

- Page Markdown: https://grok-wiki.com/public/wiki/sml2h3-ddddocr-10e2eae686bf/pages/04-ocr.md
- Generated: 2026-06-23T07:49:36.661Z

### 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]()

---

## 05. 目标检测引擎

> DetectionEngine 的 YOLOX 风格推理流程：预处理、锚点解码、NMS 后处理与边界框输出

- Page Markdown: https://grok-wiki.com/public/wiki/sml2h3-ddddocr-10e2eae686bf/pages/05-page-5.md
- Generated: 2026-06-23T07:51:33.353Z

### Source Files

- `ddddocr/core/detection_engine.py`
- `ddddocr/core/base.py`
- `ddddocr/models/model_loader.py`
- `ddddocr/utils/image_io.py`

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

# 目标检测引擎

`DetectionEngine` 是 ddddocr 中负责验证码目标检测的核心模块。它实现了完整的 YOLOX 风格推理流程：从原始图像字节输入，经过 letterbox 预处理、ONNX 模型推理、锚点解码、NMS 后处理，最终输出裁剪后的整数边界框列表。该引擎主要用于在验证码图片中定位文字区域，为后续 OCR 识别提供精确的区域坐标。

本文档覆盖 `DetectionEngine` 的类结构、完整推理流水线、各阶段的算法细节，以及与上层调用方的集成方式。

## 类继承结构

`DetectionEngine` 继承自 `BaseEngine` 抽象基类，获得 ONNX 推理会话管理、设备切换和生命周期控制等通用能力。

```text
BaseEngine (ABC)
 ├── session: onnxruntime.InferenceSession
 ├── model_loader: ModelLoader
 ├── initialize() → abstract
 ├── predict() → abstract
 ├── is_ready() → bool
 ├── switch_device()
 └── cleanup()

DetectionEngine
 ├── initialize()        加载 common_det.onnx
 ├── predict()           统一入口，支持 bytes/str/Image
 ├── preproc()           letterbox 预处理
 ├── demo_postprocess()  YOLOX 锚点解码
 ├── nms()               单类别 NMS
 ├── multiclass_nms()    多类别 NMS（class-agnostic）
 └── get_bbox()          完整推理流水线
```

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

## 模型加载与初始化

`DetectionEngine.__init__` 接受 `use_gpu` 和 `device_id` 参数，调用父类构造后立即执行 `initialize()`。初始化过程通过 `ModelLoader.load_detection_model()` 加载 `common_det.onnx` 模型文件，该文件位于 ddddocr 包根目录下。

`ModelLoader` 内部根据 GPU 配置选择 ONNX Runtime 执行提供者：GPU 模式优先使用 `CUDAExecutionProvider`（分配 2GB 显存上限），失败时回退到 `CPUExecutionProvider`。

| 参数 | 类型 | 默认值 | 说明 |
|------|------|--------|------|
| `use_gpu` | `bool` | `False` | 是否启用 GPU 推理 |
| `device_id` | `int` | `0` | CUDA 设备编号 |

Sources: [ddddocr/core/detection_engine.py:23-47](ddddocr/core/detection_engine.py), [ddddocr/models/model_loader.py:152-168](ddddocr/models/model_loader.py)

## 推理流水线概览

`get_bbox()` 方法是完整推理流水线的入口，从原始图像字节到最终边界框列表的完整流程如下：

```text
image_bytes (bytes)
    │
    ▼
cv2.imdecode → BGR numpy array
    │
    ▼
preproc(img, (416, 416))
    ├── letterbox 等比缩放 + 填充 (灰度 114)
    ├── 转置为 CHW 格式
    └── 返回 (padded_img, ratio)
    │
    ▼
ONNX Runtime 推理 → raw output
    │
    ▼
demo_postprocess(output, (416, 416))
    ├── 生成 3 级网格锚点 (stride 8/16/32)
    ├── 解码中心坐标: (offset + grid) × stride
    └── 解码宽高: exp(raw) × stride
    │
    ▼
boxes_xyxy 转换 (cxcywh → xyxy) + 除以 ratio
    │
    ▼
multiclass_nms(boxes, scores, nms_thr=0.45, score_thr=0.1)
    ├── 每个锚点取最高类别分数
    ├── 过滤低于 score_thr 的预测
    ├── 贪心 NMS 按 IoU 去重
    └── 返回 [x1, y1, x2, y2, score, class_id]
    │
    ▼
边界框裁剪到图像范围 → List[List[int]]
```

Sources: [ddddocr/core/detection_engine.py:173-212](ddddocr/core/detection_engine.py)

## 预处理：Letterbox 缩放

`preproc()` 方法将输入图像缩放到模型要求的固定尺寸（默认 416×416），同时保持原始宽高比：

1. 创建一个 416×416 的灰色画布（像素值 114），作为 YOLOX 系列模型的标准填充值。
2. 计算缩放比例 `r = min(416/H, 416/W)`，使用双线性插值等比缩放。
3. 将缩放后的图像粘贴到画布左上角，右侧和下方保留灰色填充。
4. 从 HWC 格式转置为 CHW 格式，转为 `float32` 连续数组。

返回值包含预处理后的张量和缩放比例 `ratio`，后者用于后续将检测坐标映射回原图尺寸。

```python
# ddddocr/core/detection_engine.py:89-104
def preproc(self, img, input_size, swap=(2, 0, 1)):
    padded_img = np.ones((input_size[0], input_size[1], 3), dtype=np.uint8) * 114
    r = min(input_size[0] / img.shape[0], input_size[1] / img.shape[1])
    resized_img = cv2.resize(
        img,
        (int(img.shape[1] * r), int(img.shape[0] * r)),
        interpolation=cv2.INTER_LINEAR,
    ).astype(np.uint8)
    padded_img[: int(img.shape[0] * r), : int(img.shape[1] * r)] = resized_img
    padded_img = padded_img.transpose(swap)
    padded_img = np.ascontiguousarray(padded_img, dtype=np.float32)
    return padded_img, r
```

Sources: [ddddocr/core/detection_engine.py:89-104](ddddocr/core/detection_engine.py)

## 锚点解码：demo_postprocess

YOLOX 模型输出的原始张量并非直接的边界框坐标，而是相对于网格锚点的偏移量。`demo_postprocess()` 负责将这些偏移量解码为实际的像素坐标。

### 多尺度网格生成

模型在三个特征图尺度上生成锚点，每个尺度对应不同的下采样步长：

| 尺度 | 步长 (stride) | 特征图大小 | 锚点数量 |
|------|---------------|------------|----------|
| P3 | 8 | 52×52 | 2704 |
| P4 | 16 | 26×26 | 676 |
| P5 | 32 | 13×13 | 169 |
| **合计** | | | **3549** |

对每个尺度，使用 `np.meshgrid` 生成二维网格坐标，展平后拼接为 `(1, 3549, 2)` 的锚点矩阵。同时生成等长的步长矩阵。

### 坐标解码公式

原始输出的形状为 `(1, 3549, N)`，其中前 4 列为边界框参数：

- **中心坐标** `cx, cy`：`decoded = (raw_offset + grid_anchor) × stride`
- **宽高** `w, h`：`decoded = exp(raw) × stride`

```python
# ddddocr/core/detection_engine.py:124-125
outputs[..., :2] = (outputs[..., :2] + grids) * expanded_strides
outputs[..., 2:4] = np.exp(outputs[..., 2:4]) * expanded_strides
```

解码后的输出格式为 `(1, 3549, N)`，其中前 4 列是 `cx, cy, w, h` 格式的边界框坐标（相对于 416×416 输入空间）。

Sources: [ddddocr/core/detection_engine.py:106-126](ddddocr/core/detection_engine.py)

## 坐标格式转换

`get_bbox()` 在锚点解码后执行两步坐标转换：

1. **cxcywh → xyxy**：将中心点+宽高格式转换为左上角+右下角格式。
2. **缩放回原图**：将 416×416 空间的坐标除以预处理阶段的缩放比例 `ratio`，映射回原图像素坐标。

```python
# ddddocr/core/detection_engine.py:182-187
boxes_xyxy[:, 0] = boxes[:, 0] - boxes[:, 2] / 2.  # x1
boxes_xyxy[:, 1] = boxes[:, 1] - boxes[:, 3] / 2.  # y1
boxes_xyxy[:, 2] = boxes[:, 0] + boxes[:, 2] / 2.  # x2
boxes_xyxy[:, 3] = boxes[:, 1] + boxes[:, 3] / 2.  # y2
boxes_xyxy /= ratio
```

Sources: [ddddocr/core/detection_engine.py:182-187](ddddocr/core/detection_engine.py)

## NMS 后处理

NMS（非极大值抑制）用于去除重叠的冗余检测框。`DetectionEngine` 实现了两层 NMS 逻辑。

### 单类别 NMS

`nms()` 方法实现标准的贪心 NMS 算法：

1. 按置信度降序排列所有候选框。
2. 取最高分框加入保留列表。
3. 计算该框与所有剩余框的 IoU（交并比）。
4. 移除 IoU 超过阈值的框。
5. 重复直到候选列表为空。

IoU 计算使用标准公式：`IoU = 交集面积 / (框A面积 + 框B面积 - 交集面积)`。

### 多类别 NMS（Class-Agnostic）

`multiclass_nms_class_agnostic()` 是实际调用的入口，流程如下：

1. 对每个锚点，取所有类别分数中最高的类别和分数。
2. 过滤掉最高分数低于 `score_thr`（默认 0.1）的预测。
3. 对剩余预测调用 `nms()`，IoU 阈值为 0.45。
4. 返回形状为 `(K, 6)` 的数组，每行包含 `[x1, y1, x2, y2, score, class_id]`。

| 参数 | 默认值 | 说明 |
|------|--------|------|
| `nms_thr` | 0.45 | IoU 重叠阈值，超过此值的框被抑制 |
| `score_thr` | 0.1 | 最低置信度阈值，低于此值的预测被丢弃 |

Sources: [ddddocr/core/detection_engine.py:128-171](ddddocr/core/detection_engine.py)

## 输出边界框裁剪

NMS 之后，`get_bbox()` 将浮点坐标裁剪到原图有效范围内并转为整数：

- `x1`、`y1` 负值修正为 0。
- `x2` 不超过原图宽度，`y2` 不超过原图高度。
- 若 NMS 返回空结果（`pred` 为 `None`），捕获异常后返回空列表 `[]`。

最终输出格式为 `List[List[int]]`，每个子列表为 `[x1, y1, x2, y2]`。

Sources: [ddddocr/core/detection_engine.py:189-212](ddddocr/core/detection_engine.py)

## 上层集成

`DetectionEngine` 通过 `compat.v1.DdddOcr` 类对外暴露。当用户以 `det=True` 初始化 `DdddOcr` 时，创建 `DetectionEngine` 实例并禁用 OCR 功能。调用 `doddocr.detection(img)` 即可触发完整检测流程。

```python
# ddddocr/compat/v1.py:73-76
if det:
    self.det = True
    self.detection_engine = DetectionEngine(use_gpu, device_id)
```

API 服务层（`api/server.py`）和 MCP 工具层（`api/mcp.py`）也支持检测功能的按需启用，通过 `ddddocr_detection` 工具名对外暴露。

Sources: [ddddocr/compat/v1.py:69-76](ddddocr/compat/v1.py), [ddddocr/compat/v1.py:129-148](ddddocr/compat/v1.py)

## 异常处理

`DetectionEngine` 在关键路径上定义了两类自定义异常：

| 异常类 | 触发场景 |
|--------|----------|
| `ModelLoadError` | 模型文件不存在、ONNX 会话创建失败、引擎未初始化时调用 `predict()` |
| `ImageProcessError` | 图像解码失败、预处理或后处理过程中出现运行时错误 |

OpenCV 导入失败时，`safe_import_opencv()` 会根据操作系统输出针对性的安装指导，而非直接崩溃。

Sources: [ddddocr/utils/exceptions.py:11-98](ddddocr/utils/exceptions.py), [ddddocr/core/detection_engine.py:34-47](ddddocr/core/detection_engine.py)

## 总结

`DetectionEngine` 实现了一条紧凑的 YOLOX 风格目标检测流水线：416×416 letterbox 预处理保持宽高比，三尺度网格锚点解码（stride 8/16/32）将模型输出转换为像素坐标，class-agnostic NMS 以 0.45 IoU 阈值去除重叠框，最终输出裁剪到原图范围的整数边界框。整个流程以 ONNX Runtime 为推理后端，支持 CPU/GPU 切换，通过 `ModelLoader` 管理模型生命周期。

---

## 06. 滑块验证码匹配引擎

> SlideEngine 的两种匹配算法：边缘检测模板匹配与图像差异比较，以及结果坐标输出

- Page Markdown: https://grok-wiki.com/public/wiki/sml2h3-ddddocr-10e2eae686bf/pages/06-page-6.md
- Generated: 2026-06-23T07:52:06.994Z

### Source Files

- `ddddocr/core/slide_engine.py`
- `ddddocr/core/base.py`
- `ddddocr/utils/image_io.py`

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

# 滑块验证码匹配引擎

ddddocr 的滑块验证码匹配引擎（`SlideEngine`）提供两种独立的图像匹配算法，用于自动化破解滑块验证码。一种基于边缘检测的模板匹配，适用于独立滑块图片与背景图的定位；另一种基于图像差异比较，适用于带缺口坑位的图片与完整背景图的对比。两种算法均不依赖深度学习模型，完全基于 OpenCV 的经典图像处理管线运行，因此无需 GPU 或 ONNX Runtime 支持。

## 引擎架构

`SlideEngine` 继承自 `BaseEngine` 抽象类，但刻意跳过了父类的模型加载逻辑。它不使用 `ModelLoader`、`onnxruntime.InferenceSession` 等组件，构造函数中直接设置 `is_initialized = True`，`is_ready()` 始终返回 `True`。

```python
class SlideEngine(BaseEngine):
    def __init__(self):
        # 不调用父类的__init__，因为不需要模型加载器
        self.is_initialized = True
```

这种设计使得 `SlideEngine` 可以在没有 ONNX Runtime 或 GPU 驱动的环境中独立运行，仅依赖 OpenCV 和 NumPy。

**Sources:** [ddddocr/core/slide_engine.py:20-36]()，[ddddocr/core/base.py:15-30]()

## 算法一：边缘检测模板匹配（slide_match）

`slide_match` 方法接收滑块图片和背景图片，通过模板匹配定位滑块在背景中的目标位置。该方法支持两种子算法，由 `simple_target` 参数控制。

### 输入预处理

两种图片输入经过统一的预处理管线：

1. **格式标准化**：`load_image_from_input` 支持 `bytes`、`str`（文件路径或 base64）、`pathlib.PurePath`、`PIL.Image`、`np.ndarray` 五种输入类型，统一转换为 PIL Image
2. **颜色空间转换**：`image_to_numpy` 将 PIL Image 转为 RGB numpy 数组
3. **灰度化**：通过 `cv2.cvtColor(target, cv2.COLOR_RGB2GRAY)` 转为单通道灰度图

**Sources:** [ddddocr/core/slide_engine.py:62-76]()，[ddddocr/utils/image_io.py:82-119]()

### 简单模板匹配（simple_target=True）

当 `simple_target=True` 时，直接对灰度图执行模板匹配：

```python
result = cv2.matchTemplate(background, target, cv2.TM_CCOEFF_NORMED)
_, max_val, _, max_loc = cv2.minMaxLoc(result)
center_x = max_loc[0] + target_w // 2
center_y = max_loc[1] + target_h // 2
```

使用 `TM_CCOEFF_NORMED`（归一化相关系数法）作为匹配度量，返回值范围为 `[-1, 1]`，值越接近 1 表示匹配度越高。适用于滑块图片边缘清晰、背景干扰较小的场景。

**Sources:** [ddddocr/core/slide_engine.py:200-234]()

### 边缘检测匹配（simple_target=False，默认）

当 `simple_target=False`（默认值）时，先对两幅灰度图执行 Canny 边缘检测，再在边缘图上进行模板匹配：

```python
target_edges = cv2.Canny(target, 50, 150)
background_edges = cv2.Canny(background, 50, 150)
result = cv2.matchTemplate(background_edges, target_edges, cv2.TM_CCOEFF_NORMED)
```

Canny 边缘检测的双阈值设定为 `(50, 150)`。通过先提取边缘特征，算法对光照变化、背景纹理、颜色差异等干扰因素具有更强的鲁棒性。这是大多数滑块验证码场景的默认选择。

**Sources:** [ddddocr/core/slide_engine.py:236-274]()

### 返回坐标计算

两种子算法共享相同的坐标计算逻辑：取 `matchTemplate` 返回的最佳匹配位置 `max_loc`（左上角坐标），加上滑块宽高的一半，得到滑块的中心点坐标。

返回字典结构：

| 字段 | 类型 | 说明 |
|------|------|------|
| `target` | `[int, int]` | 中心坐标 `[x, y]` |
| `target_x` | `int` | 中心点 X 坐标 |
| `target_y` | `int` | 中心点 Y 坐标 |
| `confidence` | `float` | 匹配置信度（`TM_CCOEFF_NORMED` 值） |

**Sources:** [ddddocr/core/slide_engine.py:226-231]()，[ddddocr/core/slide_engine.py:266-271]()

## 算法二：图像差异比较（slide_comparison）

`slide_comparison` 方法适用于"带坑位图片"与"完整背景图"的对比场景。它不使用模板匹配，而是通过像素级差异来定位缺口位置。

### 处理管线

```text
背景图 + 坑位图 → cv2.absdiff → 灰度化 → 二值化(threshold=30)
    → 形态学闭运算(3×3) → 形态学开运算(3×3)
    → findContours → 最大轮廓 → boundingRect → 中心点
```

关键步骤说明：

1. **差异计算**：`cv2.absdiff` 逐像素取两幅 RGB 图的绝对差值，消除相同区域
2. **二值化**：阈值 30，将差异区域与背景区分开
3. **形态学去噪**：先闭运算（`MORPH_CLOSE`）填充内部空洞，再开运算（`MORPH_OPEN`）去除小噪点，核大小均为 3×3
4. **轮廓提取**：使用 `RETR_EXTERNAL` 仅提取外层轮廓，`CHAIN_APPROX_SIMPLE` 压缩水平/垂直/对角线段
5. **最大轮廓选择**：取面积最大的轮廓作为缺口区域

**Sources:** [ddddocr/core/slide_engine.py:149-198]()

### 返回坐标

返回缺口轮廓边界框的中心点坐标。当未检测到任何轮廓时，返回 `[0, 0]`。

| 字段 | 类型 | 说明 |
|------|------|------|
| `target` | `[int, int]` | 缺口中心坐标 `[x, y]` |
| `target_x` | `int` | 缺口中心点 X 坐标 |
| `target_y` | `int` | 缺口中心点 Y 坐标 |

注意：与 `slide_match` 不同，`slide_comparison` 不返回 `confidence` 字段。

**Sources:** [ddddocr/core/slide_engine.py:179-195]()

## 两种算法对比

| 维度 | slide_match | slide_comparison |
|------|-------------|-----------------|
| 适用场景 | 滑块图 + 背景图 | 坑位图 + 完整背景图 |
| 核心算法 | 模板匹配（可选边缘检测） | 像素差异 + 轮廓检测 |
| 是否使用 Canny | `simple_target=False` 时使用 | 不使用 |
| 返回 confidence | 是 | 否 |
| 未匹配时行为 | 返回最佳匹配位置（可能不准） | 返回 `[0, 0]` |
| 图像预处理 | 灰度化 | RGB 差异 → 灰度化 → 二值化 → 形态学 |

## 外部接口

`SlideEngine` 通过 `DdddOcr` 兼容层暴露给用户，同时提供 HTTP API 和 MCP 工具接口。

### Python API

```python
import ddddocr
ocr = ddddocr.DdddOcr(ocr=False, det=False)

# 边缘检测模板匹配
result = ocr.slide_match(target_img, background_img, simple_target=False)

# 图像差异比较
result = ocr.slide_comparison(target_img, background_img)
```

**Sources:** [ddddocr/compat/v1.py:150-190]()

### HTTP API 端点

- `POST /slide_match`：滑块匹配，接收 base64 编码的目标图和背景图
- `POST /slide_comparison`：滑块比较，接收 base64 编码的坑位图和背景图

**Sources:** [ddddocr/api/app.py:592-674]()

### MCP 工具

- `ddddocr_slide_match`
- `ddddocr_slide_comparison`

**Sources:** [ddddocr/api/mcp.py:84-97]()

## 错误处理

所有图像处理失败均抛出 `ImageProcessError` 异常。输入验证通过 `validate_image_input` 确保图片类型合法，不合法时抛出 `DDDDOCRError`。OpenCV 导入失败时，`safe_import_opencv` 会提供平台特定的安装指导。

**Sources:** [ddddocr/utils/exceptions.py:22-23]()，[ddddocr/utils/validators.py:15-31]()，[ddddocr/utils/exceptions.py:84-98]()

---

## 07. 图像预处理与颜色过滤

> ImageProcessor 的尺寸调整、灰度转换、去噪与二值化能力，以及 ColorFilter 的 HSV 颜色空间过滤机制

- Page Markdown: https://grok-wiki.com/public/wiki/sml2h3-ddddocr-10e2eae686bf/pages/07-page-7.md
- Generated: 2026-06-23T07:51:31.125Z

### Source Files

- `ddddocr/preprocessing/image_processor.py`
- `ddddocr/preprocessing/color_filter.py`
- `ddddocr/preprocessing/__init__.py`
- `ddddocr/utils/image_io.py`

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

# 图像预处理与颜色过滤

ddddocr 的图像预处理子系统位于 `ddddocr/preprocessing/` 包中，包含两个核心类：`ImageProcessor` 和 `ColorFilter`。它们负责在图像送入 OCR 推理引擎之前完成尺寸归一化、灰度转换、噪声去除、对比度增强和基于 HSV 颜色空间的区域过滤。这一层是 OCR 准确率的关键保障——不规范的输入尺寸或背景噪声会直接降低识别效果。

## 模块结构

`ddddocr/preprocessing/__init__.py` 导出了两个公共类，形成预处理子系统的全部对外接口：

```python
from .color_filter import ColorFilter
from .image_processor import ImageProcessor
```

两个类均依赖 `ddddocr/utils/` 中的工具函数完成图像格式转换（PIL ↔ numpy）和参数校验，同时通过 `safe_import_opencv()` 安全加载 OpenCV，确保在缺少 cv2 时给出明确的安装指导而非静默失败。

Sources: [ddddocr/preprocessing/__init__.py:7-13](ddddocr/preprocessing/__init__.py), [ddddocr/utils/exceptions.py:84-98](ddddocr/utils/exceptions.py)

## ImageProcessor：图像处理流水线

`ImageProcessor` 是一个纯静态方法集合，所有方法均为 `@staticmethod`，无需实例化即可调用。核心能力分为四类：尺寸调整、颜色空间转换、噪声处理与图像增强。

### 尺寸调整（resize_image）

`resize_image` 接受 PIL Image、目标尺寸 `(width, height)` 和可选的宽高比保持标志。当 `keep_aspect_ratio=True` 时，方法计算宽高两个方向的缩放比例，取较小值作为统一缩放因子，确保图像不被拉伸变形。

```python
# 计算缩放比例
width_ratio = target_width / original_width
height_ratio = target_height / original_height
scale_ratio = min(width_ratio, height_ratio)
```

默认重采样方法为 `Image.LANCZOS`（高质量 Lanczos 滤波），适合 OCR 场景下的文字清晰度需求。

Sources: [ddddocr/preprocessing/image_processor.py:22-60](ddddocr/preprocessing/image_processor.py)

### 灰度转换（convert_to_grayscale）

`convert_to_grayscale` 封装了 PIL 的 `'L'` 模式转换，将 RGB 或 RGBA 图像降为单通道灰度图。这是 OCR 模型推理前的必要步骤——多数 OCR 模型期望单通道输入。

Sources: [ddddocr/preprocessing/image_processor.py:63-79](ddddocr/preprocessing/image_processor.py)

### 噪声去除（remove_noise）

`remove_noise` 使用 OpenCV 的中值滤波（`cv2.medianBlur`），默认核大小为 3×3。中值滤波对椒盐噪声特别有效，同时能较好地保留文字边缘锐度，优于均值滤波。方法内部根据输入数组的维度自动区分彩色图像和灰度图像的处理路径，但实际上两者调用的 OpenCV 函数相同。

Sources: [ddddocr/preprocessing/image_processor.py:169-197](ddddocr/preprocessing/image_processor.py)

### 图像二值化（binarize_image）

`binarize_image` 支持三种二值化策略：

| 方法 | 参数值 | 实现方式 | 适用场景 |
|------|--------|----------|----------|
| 固定阈值 | `'simple'` | `cv2.threshold` + `THRESH_BINARY` | 光照均匀的简单验证码 |
| Otsu 自动阈值 | `'otsu'` | `cv2.threshold` + `THRESH_OTSU` | 光照不均匀、直方图双峰 |
| 自适应阈值 | `'adaptive'` | `cv2.adaptiveThreshold` + `GAUSSIAN_C` | 复杂背景、局部光照差异大 |

方法内部会先将非灰度图像转为 `'L'` 模式，再执行二值化。

Sources: [ddddocr/preprocessing/image_processor.py:200-238](ddddocr/preprocessing/image_processor.py)

### 图像增强

`ImageProcessor` 还提供两种基于 PIL `ImageEnhance` 的增强方法：

- **`enhance_contrast`**：对比度增强，接受 `factor` 参数（默认 1.5），大于 1 增强、小于 1 降低。
- **`enhance_sharpness`**：锐度增强，同样基于 `factor` 控制强度。

两者均通过延迟导入 `PIL.ImageEnhance` 避免不必要的模块加载。

Sources: [ddddocr/preprocessing/image_processor.py:125-166](ddddocr/preprocessing/image_processor.py)

### OCR 预处理流水线（preprocess_for_ocr）

`preprocess_for_ocr` 将上述单项能力组装为一条完整的 OCR 预处理流水线：

```
RGBA 透明背景处理 → 尺寸调整（保持宽高比，目标高度 64px）→ 对比度增强 → 中值滤波去噪 → 灰度转换
```

其中 PNG 透明背景处理委托给 `image_io.png_rgba_black_preprocess`，它创建白色背景并将透明图层合成上去。

Sources: [ddddocr/preprocessing/image_processor.py:241-287](ddddocr/preprocessing/image_processor.py), [ddddocr/utils/image_io.py:59-79](ddddocr/utils/image_io.py)

## ColorFilter：HSV 颜色空间过滤

`ColorFilter` 实现基于 HSV（色相-饱和度-明度）颜色空间的图像过滤，用于从复杂背景中提取特定颜色区域的文字或图形。

### 设计原理

HSV 颜色空间比 RGB 更适合颜色过滤，因为色相（H）通道独立编码颜色信息，不受明度和饱和度干扰。`ColorFilter` 将用户指定的颜色需求转化为 HSV 范围掩码，通过逐像素匹配保留目标颜色区域，其余区域设为白色。

### 内置颜色预设

`COLOR_PRESETS` 字典定义了 10 种常见颜色的 HSV 范围值：

| 颜色 | HSV 范围数 | 色相区间 | 备注 |
|------|-----------|----------|------|
| `red` | 2 | 0–10, 170–180 | 红色跨越 0°/180° 边界，需两个范围 |
| `blue` | 1 | 100–130 | — |
| `green` | 1 | 40–80 | — |
| `yellow` | 1 | 20–40 | — |
| `orange` | 1 | 10–20 | — |
| `purple` | 1 | 130–170 | — |
| `cyan` | 1 | 80–100 | — |
| `black` | 1 | H: 0–180, S: 0–255, V: 0–50 | 低明度区域 |
| `white` | 1 | H: 0–180, S: 0–30, V: 200–255 | 低饱和度高明度 |
| `gray` | 1 | H: 0–180, S: 0–30, V: 50–200 | 低饱和度中明度 |

所有预设的 S/V 下限均为 50，避免将接近灰色的像素误纳入。

Sources: [ddddocr/preprocessing/color_filter.py:23-34](ddddocr/preprocessing/color_filter.py)

### 初始化与参数校验

构造函数接受 `colors`（预设颜色名列表）和 `custom_ranges`（自定义 HSV 范围列表）两个可选参数，至少提供其一。参数校验由 `validators.validate_color_filter_params` 完成，检查项包括：

- `colors` 中每个元素必须是字符串
- `custom_ranges` 中每个元素必须是二元组，包含两个三元组
- H 通道值范围 0–180，S/V 通道值范围 0–255
- 每个范围的下界不能大于上界

Sources: [ddddocr/preprocessing/color_filter.py:36-66](ddddocr/preprocessing/color_filter.py), [ddddocr/utils/validators.py:83-137](ddddocr/utils/validators.py)

### 核心过滤流程（filter_image）

`filter_image` 的处理流程如下：

```
输入图像 → RGB→BGR → BGR→HSV → 逐范围生成掩码 → 合并掩码 → 应用掩码 → 背景设白色 → BGR→RGB → 输出
```

关键步骤：

1. **颜色空间转换**：输入统一转为 BGR（OpenCV 格式），再转 HSV
2. **掩码生成**：对每个 HSV 范围调用 `cv2.inRange` 生成二值掩码，通过 `cv2.bitwise_or` 合并
3. **掩码应用**：`cv2.bitwise_and` 保留匹配区域，非匹配区域设为白色 `[255, 255, 255]`

`get_mask` 方法提供同样的掩码生成逻辑但不应用滤镜，返回原始二值掩码供下游自定义处理。

Sources: [ddddocr/preprocessing/color_filter.py:68-148](ddddocr/preprocessing/color_filter.py)

### 动态范围管理

`ColorFilter` 提供运行时修改颜色范围的能力：

- `add_color_range(lower, upper)` — 追加自定义 HSV 范围
- `add_preset_color(color)` — 追加预设颜色
- `clear_ranges()` — 清空所有范围
- `get_ranges()` — 获取当前范围副本
- `get_available_colors()` — 类方法，列出所有预设颜色名
- `get_color_range(color)` — 类方法，查询指定颜色的 HSV 范围

Sources: [ddddocr/preprocessing/color_filter.py:150-220](ddddocr/preprocessing/color_filter.py)

## OCR 引擎中的集成

`OCREngine` 在推理前将 `ColorFilter` 和 `ImageProcessor` 串联使用：

1. **颜色过滤**（可选）：如果用户指定了 `color_filter_colors` 或 `color_filter_custom_ranges`，先创建 `ColorFilter` 实例对图像进行颜色过滤。过滤失败时仅打印警告并跳过，不影响后续流程。
2. **图像预处理**：`_preprocess_image` 根据模型类型选择不同的尺寸策略：
   - 默认模型：固定目标高度 64px，宽度按比例计算，然后灰度转换
   - 自定义模型（`use_import_onnx`）：根据 `resize` 配置决定是否固定宽高或保持宽高比；根据 `channel` 配置决定是否灰度转换
3. **标准化**：像素值归一化到 `[0, 1]`，维度从 HWC 转为 CHW 格式

```python
# OCR引擎中的集成示例
color_filter = ColorFilter(colors=color_filter_colors,
                           custom_ranges=color_filter_custom_ranges)
pil_image = color_filter.filter_image(pil_image)
# ...
image = ImageProcessor.resize_image(image, (target_width, target_height))
image = ImageProcessor.convert_to_grayscale(image)
```

Sources: [ddddocr/core/ocr_engine.py:130-196](ddddocr/core/ocr_engine.py)

## 图像 I/O 工具层

`ddddocr/utils/image_io.py` 提供预处理模块依赖的基础图像格式转换函数：

| 函数 | 功能 |
|------|------|
| `image_to_numpy` | PIL Image → numpy 数组，支持自动模式转换 |
| `numpy_to_image` | numpy 数组 → PIL Image |
| `png_rgba_black_preprocess` | RGBA 透明背景转白色背景 |
| `load_image_from_input` | 统一加载入口，支持 bytes、base64、文件路径、PIL Image、numpy 数组 |
| `base64_to_image` / `get_img_base64` | base64 编解码 |

`load_image_from_input` 是 OCR 引擎的统一图像加载入口，支持 5 种输入格式，内部通过类型分发路由到对应的解码逻辑。字符串输入优先尝试文件路径，失败后作为 base64 解码。

Sources: [ddddocr/utils/image_io.py:18-209](ddddocr/utils/image_io.py)

## 错误处理策略

预处理模块采用统一的异常层次结构：所有图像处理异常抛出 `ImageProcessError`（继承自 `DDDDOCRError`），OpenCV 导入失败时通过 `safe_import_opencv` 提供跨平台安装指导。`ColorFilter` 的构造函数通过 `validate_color_filter_params` 在初始化阶段即拦截非法参数，遵循"快速失败"原则。

Sources: [ddddocr/utils/exceptions.py:22-23](ddddocr/utils/exceptions.py), [ddddocr/utils/validators.py:83-137](ddddocr/utils/validators.py)

---

## 08. 模型加载与字符集管理

> ModelLoader 的 ONNX 模型加载、GPU/CPU 提供者切换，CharsetManager 的字符集加载与范围限制机制

- Page Markdown: https://grok-wiki.com/public/wiki/sml2h3-ddddocr-10e2eae686bf/pages/08-page-8.md
- Generated: 2026-06-23T07:57:43.213Z

### Source Files

- `ddddocr/models/model_loader.py`
- `ddddocr/models/charset_manager.py`
- `ddddocr/models/__init__.py`
- `ddddocr/utils/validators.py`

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

# 模型加载与字符集管理

本文介绍 ddddocr 中两个核心基础设施模块：`ModelLoader`（ONNX 模型加载器）和 `CharsetManager`（字符集管理器）。`ModelLoader` 负责 ONNX Runtime 推理会话的创建与 GPU/CPU 执行提供者的切换；`CharsetManager` 负责字符集的加载、索引映射以及输出字符范围的限制。两者在 `OCREngine` 初始化时协同工作，共同决定 OCR 识别的模型能力和输出字符空间。

## 架构概览

```
┌─────────────────────────────────────────────────┐
│                   OCREngine                      │
│  (core/ocr_engine.py)                            │
│                                                  │
│  ┌──────────────┐     ┌──────────────────┐       │
│  │ ModelLoader  │     │ CharsetManager   │       │
│  │  (via Base)  │     │                  │       │
│  │              │     │  charset[]       │       │
│  │  providers[] │     │  charset_range[] │       │
│  │  session     │     │  valid_indices[] │       │
│  └──────┬───────┘     └────────┬─────────┘       │
│         │                      │                 │
│         ▼                      ▼                 │
│  onnxruntime            CTC decode +             │
│  InferenceSession       charset lookup           │
└─────────────────────────────────────────────────┘
```

`ModelLoader` 和 `CharsetManager` 定义在 `ddddocr/models/` 包中，通过 `models/__init__.py` 统一导出。`BaseEngine`（`core/base.py`）持有 `ModelLoader` 实例，`OCREngine`（`core/ocr_engine.py`）额外持有 `CharsetManager` 实例，并在 `initialize()` 中协调两者的加载流程。

Sources: [ddddocr/models/__init__.py:1-13](), [ddddocr/core/base.py:15-28](), [ddddocr/core/ocr_engine.py:20-47]()

## ModelLoader：ONNX 模型加载

### 类初始化与提供者配置

`ModelLoader.__init__` 接受 `use_gpu` 和 `device_id` 两个参数，构造时立即调用 `_setup_providers()` 配置 ONNX Runtime 的执行提供者列表。

- **GPU 模式**：providers 列表为 `[('CUDAExecutionProvider', {...}), 'CPUExecutionProvider']`。CUDA 提供者配置包括 `device_id`、`arena_extend_strategy: 'kNextPowerOfTwo'`、`gpu_mem_limit: 2GB`、`cudnn_conv_algo_search: 'EXHAUSTIVE'` 和 `do_copy_in_default_stream: True`。
- **CPU 模式**：providers 列表为 `['CPUExecutionProvider']`。
- **回退机制**：如果 GPU 配置过程中抛出异常，自动回退到 CPU 模式并打印警告。

Sources: [ddddocr/models/model_loader.py:19-53]()

### 模型加载方法

| 方法 | 功能 | 说明 |
|------|------|------|
| `load_model(path)` | 通用 ONNX 加载 | 检查文件存在性，设置日志级别为 3，创建 `InferenceSession` |
| `load_ocr_model(old, beta, import_onnx_path)` | 加载 OCR 模型 | 根据 old/beta 标志选择 `common_old.onnx` 或 `common.onnx`，也支持自定义路径 |
| `load_detection_model()` | 加载检测模型 | 加载 `common_det.onnx` |
| `load_custom_model(model_path, charset_path)` | 加载自定义模型+字符集 | 同时加载 ONNX 模型和 JSON 格式的字符集文件 |

`load_custom_model` 会验证字符集 JSON 文件包含 `charset`、`word`、`image`、`channel` 四个必需字段，返回 `(session, charset_info)` 元组。

Sources: [ddddocr/models/model_loader.py:55-204]()

### 模型兼容性验证与设备切换

`validate_model_compatibility` 检查模型输入形状是否与期望匹配（忽略 batch 维度和动态维度 `-1`）。`switch_provider` 允许运行时切换 GPU/CPU，并由 `BaseEngine.switch_device` 调用，在设备变更时触发模型重新加载。

Sources: [ddddocr/models/model_loader.py:206-257](), [ddddocr/core/base.py:79-98]()

## CharsetManager：字符集管理

### 字符集加载

`CharsetManager` 支持两种字符集来源：

1. **内置默认字符集**：通过 `load_default_charset(old, beta)` 加载。旧版（`_get_old_charset`）和 beta 版（`_get_beta_charset`）各包含约 5900+ 个硬编码字符，以空字符串 `""` 作为索引 0（blank token）。默认情况下使用旧版字符集。

2. **自定义字符集文件**：通过 `load_custom_charset(charset_path)` 从 JSON 文件加载。文件必须包含 `charset`（字符列表）、`word`（词级标志）、`image`（图像尺寸配置）、`channel`（通道数）四个字段。

加载字符集后，会自动调用 `_update_valid_indices()` 初始化有效索引。

Sources: [ddddocr/models/charset_manager.py:29-81](), [ddddocr/core/ocr_engine.py:64-92]()

### 字符集范围限制机制

`set_ranges(charset_range)` 是字符集范围限制的核心方法，支持三种参数类型：

| 参数类型 | 行为 | 示例 |
|----------|------|------|
| `int` | 取字符集前 N+1 个字符作为范围 | `set_ranges(9)` → 仅允许索引 0-9 的字符 |
| `str` | 将字符串中每个字符作为允许范围 | `set_ranges("0123456789")` → 仅允许数字 |
| `list` | 直接使用字符列表作为允许范围 | `set_ranges(["你", "好"])` → 仅允许指定字符 |

设置范围后会自动去重并追加空字符串 `""`，然后调用 `_update_valid_indices()` 将范围中的字符映射回字符集中的索引位置。

`_update_valid_indices()` 的工作方式：遍历 `charset_range` 中的每个字符，查找其在完整 `charset` 中的索引，存入 `valid_charset_range_index`。不在字符集中的字符会被忽略。当未设置范围时，`valid_charset_range_index` 包含完整字符集的所有索引。

Sources: [ddddocr/models/charset_manager.py:83-124]()

### 验证层

`validate_charset_range`（`utils/validators.py`）在 `set_ranges` 调用前验证参数合法性：int 必须非负，str 不能为空，list 不能为空且元素必须为字符串。`validate_model_config` 则验证模型配置参数，包括 `old` 和 `beta` 不能同时为 `True`。

Sources: [ddddocr/utils/validators.py:34-80](), [ddddocr/utils/validators.py:140-171]()

## 协同工作流程

在 `OCREngine.initialize()` 中，模型和字符集的加载遵循以下流程：

1. **自定义模型路径**（`import_onnx_path` 非空）：调用 `model_loader.load_custom_model()` 同时加载模型和字符集 JSON，直接设置 `charset_manager.charset` 和模型配置（`word`、`resize`、`channel`）。
2. **默认模型**：先调用 `model_loader.load_ocr_model(old, beta)` 加载 ONNX 模型，再调用 `charset_manager.load_default_charset(old, beta)` 加载对应版本的内置字符集。

在 `predict()` 推理阶段，`charset_range` 通过 `charset_manager.set_ranges()` 设置后，`valid_charset_range_index` 被用于 CTC 解码后的字符过滤——只有索引在有效范围内的字符才会被保留在最终识别结果中。

Sources: [ddddocr/core/ocr_engine.py:56-97](), [ddddocr/core/ocr_engine.py:99-157](), [ddddocr/core/ocr_engine.py:244-298]()

## 异常处理

模型加载和字符集管理过程中产生的异常统一为 `ModelLoadError`（继承自 `DDDDOCRError`）。常见触发场景包括：模型文件不存在、字符集文件缺少必需字段、字符集文件格式错误等。

Sources: [ddddocr/utils/exceptions.py:11-18]()

## 总结

`ModelLoader` 和 `CharsetManager` 是 ddddocr OCR 引擎的两个基础设施模块。`ModelLoader` 封装了 ONNX Runtime 的模型加载和 GPU/CPU 提供者管理，提供统一的模型加载接口和 GPU 回退机制；`CharsetManager` 管理 OCR 输出的字符空间，支持内置和自定义字符集，并通过范围限制机制允许用户约束识别结果的字符集。两者在 `OCREngine` 中协同初始化，并在推理阶段通过 CTC 解码和有效索引过滤共同决定最终的识别输出。

---

## 09. RESTful API 参考

> FastAPI 服务的全部端点定义、请求/响应模型、功能初始化与运行时切换流程

- Page Markdown: https://grok-wiki.com/public/wiki/sml2h3-ddddocr-10e2eae686bf/pages/09-restful-api.md
- Generated: 2026-06-23T07:54:00.344Z

### Source Files

- `ddddocr/api/routes.py`
- `ddddocr/api/models.py`
- `ddddocr/api/server.py`
- `ddddocr/api/app.py`

<details>
<summary>相关源文件</summary>
以下文件用于生成此维基页面：
- [ddddocr/api/app.py](ddddocr/api/app.py)
- [ddddocr/api/routes.py](ddddocr/api/routes.py)
- [ddddocr/api/models.py](ddddocr/api/models.py)
- [ddddocr/api/server.py](ddddocr/api/server.py)
- [ddddocr/api/mcp.py](ddddocr/api/mcp.py)
</details>

# RESTful API 参考

DDDDOCR 项目提供两套互补的 FastAPI HTTP 服务：一套**独立应用**（`app.py`）面向单次请求即用的场景，自动按配置键缓存实例；一套**模块化服务**（`server.py` + `routes.py`）支持显式初始化、运行时模型切换、功能开关以及 MCP 协议集成。两者共享同一套 Pydantic 数据模型，均默认监听 `8000` 端口并开启全量 CORS。

---

## 架构概览

```text
┌─────────────────────────────────────────────────────┐
│                    FastAPI 应用层                     │
├──────────────┬──────────────────────────────────────┤
│  独立应用     │  模块化服务                            │
│  app.py       │  server.py → routes.py → mcp.py     │
├──────────────┴──────────────────────────────────────┤
│          公共数据模型  models.py                      │
├─────────────────────────────────────────────────────┤
│              ddddocr 核心引擎 (DdddOcr)              │
└─────────────────────────────────────────────────────┘
```

---

## 独立应用（app.py）

`app.py` 是一个可直接运行的 FastAPI 应用，通过环境变量控制默认参数，按配置键自动创建和缓存 OCR 实例，并在后台任务中清理闲置实例。

### 环境变量配置

| 环境变量 | 默认值 | 说明 |
|---|---|---|
| `DDDDOCR_OCR` | `true` | 是否启用 OCR |
| `DDDDOCR_DET` | `false` | 是否启用目标检测 |
| `DDDDOCR_OLD` | `false` | 是否使用旧版模型 |
| `DDDDOCR_BETA` | `false` | 是否使用 Beta 模型 |
| `DDDDOCR_USE_GPU` | `false` | 是否使用 GPU |
| `DDDDOCR_DEVICE_ID` | `0` | GPU 设备 ID |
| `DDDDOCR_SHOW_AD` | `true` | 是否显示广告 |
| `DDDDOCR_IMPORT_ONNX_PATH` | `""` | 自定义 ONNX 模型路径 |
| `DDDDOCR_CHARSETS_PATH` | `""` | 自定义字符集路径 |
| `DDDDOCR_HOST` | `127.0.0.1` | 监听地址 |
| `DDDDOCR_PORT` | `8000` | 监听端口 |
| `DDDDOCR_WORKERS` | `1` | 工作进程数 |

`Sources: [ddddocr/api/app.py:319-327]()`

### 端点一览

#### `GET /health`

健康检查端点，返回服务状态与时间戳。

**响应示例：**
```json
{"status": "ok", "timestamp": 1719100000.0}
```

`Sources: [ddddocr/api/app.py:330-332]()`

---

#### `POST /ocr`

接收 Base64 编码图片，执行 OCR 文字识别。通过 Query 参数控制模型配置，首次请求某配置时自动创建实例并缓存。

**Query 参数（均有环境变量默认值）：**

| 参数 | 类型 | 说明 |
|---|---|---|
| `ocr` | bool | 启用 OCR |
| `det` | bool | 启用目标检测 |
| `old` | bool | 使用旧版模型 |
| `beta` | bool | 使用 Beta 模型 |
| `use_gpu` | bool | 使用 GPU |
| `device_id` | int | GPU 设备 ID |
| `show_ad` | bool | 显示广告 |

**请求体（`OCRRequest`）：**

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `image` | string | ✅ | Base64 编码图片（最大 8 MB） |
| `probability` | bool | ❌ | 是否返回概率信息，默认 `false` |
| `colors` | List[str] | ❌ | 颜色过滤列表，如 `["red", "blue"]` |
| `custom_color_ranges` | Dict | ❌ | 自定义 HSV 颜色范围 |

**响应（`OCRResponse`）：**

| 字段 | 类型 | 说明 |
|---|---|---|
| `result` | str 或 Dict | 识别文本，或概率字典 |
| `probability` | Any | 概率信息（仅 `probability=true` 时） |
| `processing_time` | float | 处理耗时（秒） |

`Sources: [ddddocr/api/app.py:126-158](模型定义), [ddddocr/api/app.py:335-404](端点实现)`

---

#### `POST /ocr/file`

文件上传版 OCR 端点。接受 `multipart/form-data`，无需 Base64 编码。

**表单字段：**

| 字段 | 类型 | 说明 |
|---|---|---|
| `file` | UploadFile | 图片文件 |
| `probability` | bool/str | 是否返回概率 |
| `colors` | str (JSON) | 颜色列表 JSON 字符串 |
| `custom_color_ranges` | str (JSON) | 自定义颜色范围 JSON 字符串 |

Query 参数与 `/ocr` 相同。

`Sources: [ddddocr/api/app.py:408-495]()`

---

#### `POST /det`

目标检测端点，接收 Base64 编码图片，返回检测到的边界框列表。

**请求体（`Base64Image`）：**

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `image` | string | ✅ | Base64 编码图片 |

**响应（`DetectionResponse`）：**

| 字段 | 类型 | 说明 |
|---|---|---|
| `result` | List[List[int]] | 边界框坐标列表 `[[x1,y1,x2,y2], ...]` |
| `processing_time` | float | 处理耗时 |

`Sources: [ddddocr/api/app.py:500-539]()`

---

#### `POST /det/file`

文件上传版目标检测端点。

`Sources: [ddddocr/api/app.py:542-589]()`

---

#### `POST /slide_match`

滑块验证码匹配，接收目标图与背景图的 Base64 编码。

**请求体（`SlideMatchRequest`）：**

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `target_image` | string | ✅ | 滑块图片 Base64 |
| `background_image` | string | ✅ | 背景图片 Base64 |
| `simple_target` | bool | ❌ | 是否简化目标，默认 `false` |
| `flag` | bool | ❌ | 标记选项，默认 `false` |

**响应（`SlideMatchResponse`）：**

| 字段 | 类型 | 说明 |
|---|---|---|
| `result.target_x` | int | 滑块 X 偏移 |
| `result.target_y` | int | 滑块 Y 偏移 |
| `result.target` | List[int] | 目标位置坐标 |
| `processing_time` | float | 处理耗时 |

`Sources: [ddddocr/api/app.py:160-172](模型), [ddddocr/api/app.py:592-633](端点)`

---

#### `POST /slide_comparison`

滑块验证码图像差异比较，返回目标区域坐标。

**请求体（`SlideComparisonRequest`）：**

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `target_image` | string | ✅ | 带坑位图片 Base64 |
| `background_image` | string | ✅ | 完整背景图片 Base64 |

**响应（`SlideComparisonResponse`）：**

| 字段 | 类型 | 说明 |
|---|---|---|
| `result` | Dict[str, List[int]] | 差异区域坐标 |
| `processing_time` | float | 处理耗时 |

`Sources: [ddddocr/api/app.py:174-184](模型), [ddddocr/api/app.py:636-676](端点)`

---

#### `POST /set_charset_range`

设置当前 OCR 实例的字符识别范围。

**请求体（`CharsetRangeRequest`）：**

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `charset_range` | List[str] | ✅ | 字符范围列表，如 `["0-9", "a-z"]` |

**响应：**
```json
{
  "result": "字符范围设置成功",
  "charset_range": ["0-9", "a-z"],
  "processing_time": 0.001
}
```

`Sources: [ddddocr/api/app.py:186-198](模型), [ddddocr/api/app.py:680-718](端点)`

---

#### `GET /config`

获取当前默认配置、活跃实例数和运行环境信息。

`Sources: [ddddocr/api/app.py:721-740]()`

---

#### `GET /docs`、`GET /redoc`

自动生成的 Swagger UI 和 ReDoc API 文档。

---

## 模块化服务（server.py + routes.py）

模块化服务采用 `DDDDDOCRService` 类管理状态，通过 `/initialize` 端点显式初始化，支持运行时模型切换和功能开关。

### 服务生命周期

```text
客户端                   API 服务                     DDDDService
  │                        │                            │
  │  POST /initialize      │                            │
  │──────────────────────▶│  initialize(config)         │
  │                        │───────────────────────────▶│
  │                        │  创建 ocr/det/slide 实例    │
  │◀──────────────────────│  返回已加载模型列表          │
  │                        │                            │
  │  POST /switch-model    │                            │
  │──────────────────────▶│  switch_model(config)       │
  │                        │───────────────────────────▶│
  │                        │  替换指定模型实例            │
  │◀──────────────────────│                            │
  │                        │                            │
  │  POST /toggle-feature  │                            │
  │──────────────────────▶│  toggle_feature(config)     │
  │                        │───────────────────────────▶│
  │                        │  修改 enabled_features      │
  │◀──────────────────────│                            │
  │                        │                            │
  │  POST /ocr             │                            │
  │──────────────────────▶│  检查实例 + 功能开关        │
  │                        │  ocr_instance.classification│
  │◀──────────────────────│  返回识别结果               │
```

### 端点一览

#### `POST /initialize`

初始化服务，按需加载 OCR、目标检测和滑块模型。**每次调用会清除已有实例并重新创建**。

**请求体（`InitializeRequest`）：**

| 字段 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| `ocr` | bool | `true` | 启用 OCR 功能 |
| `det` | bool | `false` | 启用目标检测功能 |
| `old` | bool | `false` | 使用旧版 OCR 模型 |
| `beta` | bool | `false` | 使用 Beta 版 OCR 模型 |
| `use_gpu` | bool | `false` | 使用 GPU |
| `device_id` | int | `0` | GPU 设备 ID |
| `import_onnx_path` | str | `""` | 自定义 ONNX 模型路径 |
| `charsets_path` | str | `""` | 自定义字符集路径 |

**响应（`APIResponse`）：**
```json
{
  "success": true,
  "message": "服务初始化成功",
  "data": {
    "loaded_models": ["ocr", "slide"],
    "message": "服务初始化成功"
  }
}
```

`Sources: [ddddocr/api/models.py:10-19](模型), [ddddocr/api/server.py:33-80](服务逻辑)`

---

#### `POST /switch-model`

运行时切换模型配置，无需重新初始化整个服务。

**请求体（`SwitchModelRequest`）：**

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `model_type` | str | ✅ | 模型类型：`ocr`、`ocr_old`、`ocr_beta`、`det` |
| `use_gpu` | bool | ❌ | 使用 GPU，默认 `false` |
| `device_id` | int | ❌ | GPU 设备 ID，默认 `0` |

`Sources: [ddddocr/api/models.py:22-26](模型), [ddddocr/api/server.py:82-120](服务逻辑)`

---

#### `POST /toggle-feature`

动态开启或关闭特定功能。

**请求体（`ToggleFeatureRequest`）：**

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `feature` | str | ✅ | 功能名称：`ocr`、`detection`、`color_filter` |
| `enabled` | bool | ✅ | 是否启用 |

`Sources: [ddddocr/api/models.py:29-32](模型), [ddddocr/api/server.py:122-135](服务逻辑)`

---

#### `POST /ocr`

执行 OCR 识别。需先调用 `/initialize` 启用 OCR 功能。

**请求体（`OCRRequest`）：**

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `image` | string | ✅ | Base64 编码图片 |
| `png_fix` | bool | ❌ | 修复 PNG 透明背景问题 |
| `probability` | bool | ❌ | 返回概率信息 |
| `color_filter_colors` | List[str] | ❌ | 颜色过滤预设颜色列表 |
| `color_filter_custom_ranges` | List[List[List[int]]] | ❌ | 自定义 HSV 颜色范围 |
| `charset_range` | int 或 str | ❌ | 字符集范围限制 |

**响应（`APIResponse` 包装 `OCRResponse`）：**

| 字段 | 类型 | 说明 |
|---|---|---|
| `data.text` | str 或 null | 识别文本 |
| `data.probability` | Dict 或 null | 概率信息 |

`Sources: [ddddocr/api/models.py:35-42](模型), [ddddocr/api/routes.py:79-118](端点)`

---

#### `POST /detect`

执行目标检测。需先调用 `/initialize` 启用检测功能。

**请求体（`DetectionRequest`）：** 仅需 `image`（Base64）。

**响应：** `data.bboxes` 为 `List[List[int]]` 边界框列表。

`Sources: [ddddocr/api/models.py:45-47](模型), [ddddocr/api/routes.py:120-145](端点)`

---

#### `POST /slide-match`

滑块匹配。

**请求体（`SlideMatchRequest`）：**

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `target_image` | string | ✅ | 滑块图片 Base64 |
| `background_image` | string | ✅ | 背景图片 Base64 |
| `simple_target` | bool | ❌ | 是否为简单滑块 |

**响应（`SlideResponse`）：**

| 字段 | 类型 | 说明 |
|---|---|---|
| `target` | List[int] | 目标位置坐标 |
| `target_x` | int 或 null | X 偏移 |
| `target_y` | int 或 null | Y 偏移 |

`Sources: [ddddocr/api/models.py:50-54](模型), [ddddocr/api/routes.py:147-172](端点)`

---

#### `POST /slide-comparison`

滑块图像差异比较。

**请求体（`SlideComparisonRequest`）：** `target_image` + `background_image`，均为 Base64。

`Sources: [ddddocr/api/models.py:57-60](模型), [ddddocr/api/routes.py:174-197](端点)`

---

#### `GET /status`

获取当前服务状态。

**响应（`StatusResponse`）：**

| 字段 | 类型 | 说明 |
|---|---|---|
| `service_status` | str | 服务状态，固定 `"running"` |
| `loaded_models` | List[str] | 已加载模型列表 |
| `enabled_features` | List[str] | 已启用功能列表 |
| `version` | str | 版本号 |
| `uptime` | float | 运行时长（秒） |

`Sources: [ddddocr/api/models.py:70-76](模型), [ddddocr/api/server.py:137-153](服务逻辑)`

---

#### `GET /health`

健康检查，返回 `{"status": "healthy", "timestamp": ...}`。

`Sources: [ddddocr/api/routes.py:204-207]()`

---

#### `GET /`

根路径，返回 HTML 页面，包含 Swagger UI、ReDoc 和服务状态的链接。

`Sources: [ddddocr/api/routes.py:20-50]()`

---

## MCP 协议端点

模块化服务通过 `/mcp` 前缀暴露 MCP（Model Context Protocol）接口，供 AI Agent 调用。

```text
GET  /mcp/capabilities   → 声明可用工具及其参数 Schema
POST /mcp/call           → 调用指定工具
GET  /mcp/               → 协议信息与端点索引
```

### 可用 MCP 工具

| 工具名 | 功能 | 必填参数 |
|---|---|---|
| `ddddocr_initialize` | 初始化服务 | 无（均可选） |
| `ddddocr_ocr` | OCR 识别 | `image` |
| `ddddocr_detection` | 目标检测 | `image` |
| `ddddocr_slide_match` | 滑块匹配 | `target_image`, `background_image` |
| `ddddocr_slide_comparison` | 滑块比较 | `target_image`, `background_image` |
| `ddddocr_status` | 服务状态 | 无 |

### MCP 请求/响应模型

**请求（`MCPRequest`）：**

```json
{
  "method": "ddddocr_ocr",
  "params": {"image": "<base64>", "probability": true},
  "id": "req-001"
}
```

**成功响应（`MCPResponse`）：**

```json
{
  "result": {"text": "abc123"},
  "error": null,
  "id": "req-001"
}
```

**错误响应：**

```json
{
  "result": null,
  "error": {"code": -1, "message": "OCR功能未初始化", "data": null},
  "id": "req-001"
}
```

`Sources: [ddddocr/api/mcp.py:1-228]()`

---

## 通用响应模型

所有模块化服务端点（除 `/status` 和 `/health`）使用统一的 `APIResponse` 包装：

```json
{
  "success": true,
  "message": "操作成功",
  "data": { ... }
}
```

独立应用端点（`app.py`）直接返回业务数据，不使用统一包装。

`Sources: [ddddocr/api/models.py:63-67]()`

---

## 实例管理策略

两套服务采用不同的实例管理策略：

| 维度 | 独立应用（app.py） | 模块化服务（server.py） |
|---|---|---|
| 初始化时机 | 首次请求时自动创建 | 显式调用 `/initialize` |
| 缓存键 | 配置参数组合字符串 | 无缓存，直接替换 |
| 清理策略 | 后台任务清理闲置 >1h 的实例 | 无自动清理 |
| 模型切换 | 请求不同的 Query 参数 | 调用 `/switch-model` |
| 功能开关 | 通过 Query 参数即时切换 | 调用 `/toggle-feature` 影响后续请求 |

独立应用的实例缓存键格式为 `ocr={ocr}-det={det}-old={old}-beta={beta}-gpu={use_gpu}-dev={device_id}`，每种配置组合对应一个独立实例。

`Sources: [ddddocr/api/app.py:239-281](实例管理), [ddddocr/api/server.py:22-153](服务类)`

---

## 启动方式

**独立应用：**

```bash
# 直接运行
python -m ddddocr.api.app

# 环境变量配置
DDDDOCR_HOST=0.0.0.0 DDDDOCR_PORT=8080 python -m ddddocr.api.app
```

**模块化服务：**

```python
from ddddocr.api.server import run_server
run_server(host="0.0.0.0", port=8000)
```

`Sources: [ddddocr/api/app.py:743-751](独立启动), [ddddocr/api/server.py:200-206](模块化启动)`

---

## 错误处理

所有端点均返回标准 HTTP 错误码：

| 状态码 | 含义 | 典型场景 |
|---|---|---|
| 400 | 请求参数错误 | Base64 解码失败、图片为空、功能未初始化 |
| 500 | 服务器内部错误 | 模型加载失败、识别异常 |

模块化服务还配有全局异常处理器，未捕获的异常统一返回 500 并附带错误详情（调试模式下包含完整堆栈）。

`Sources: [ddddocr/api/routes.py:209-219](全局异常处理)`

---

## 10. MCP 协议集成

> MCP（Model Context Protocol）端点、能力声明与工具调用机制，使 AI Agent 能直接调用 ddddocr 识别服务

- Page Markdown: https://grok-wiki.com/public/wiki/sml2h3-ddddocr-10e2eae686bf/pages/10-mcp.md
- Generated: 2026-06-23T07:53:45.792Z

### Source Files

- `ddddocr/api/mcp.py`
- `ddddocr/api/models.py`
- `ddddocr/api/server.py`

<details>
<summary>相关源文件</summary>
以下文件用于生成此维基页面：
- [ddddocr/api/mcp.py](ddddocr/api/mcp.py)
- [ddddocr/api/models.py](ddddocr/api/models.py)
- [ddddocr/api/server.py](ddddocr/api/server.py)
- [ddddocr/api/routes.py](ddddocr/api/routes.py)
- [ddddocr/api/__init__.py](ddddocr/api/__init__.py)
</details>

# MCP 协议集成

本文档说明 ddddocr 如何通过 MCP（Model Context Protocol）端点暴露其 OCR、目标检测和滑块匹配能力，使外部 AI Agent 能以标准化工具调用方式直接使用 ddddocr 服务，无需自行管理模型生命周期。

## 协议概览

ddddocr 的 MCP 集成基于 FastAPI 实现，采用自定义的 JSON-RPC 风格协议，而非官方 MCP SDK。协议通过三个 HTTP 端点运作：能力声明、工具调用和协议信息查询。所有 MCP 端点挂载在 `/mcp` 路径前缀下，与 RESTful API 共存于同一 FastAPI 应用。

Sources: [ddddocr/api/mcp.py:1-228](), [ddddocr/api/server.py:193-195]()

## 端点说明

### `GET /mcp` — 协议信息

返回 MCP 协议的元信息，包括协议名称、版本和可用端点路径。

```json
{
  "protocol": "MCP",
  "version": "1.6.1",
  "description": "DDDDOCR MCP协议支持",
  "endpoints": {
    "capabilities": "/mcp/capabilities",
    "call": "/mcp/call"
  }
}
```

Sources: [ddddocr/api/mcp.py:216-227]()

### `GET /mcp/capabilities` — 能力声明

返回 `MCPCapabilities` 对象，声明该服务暴露的全部工具。每个工具包含 `name`、`description` 和 `inputSchema`（JSON Schema 格式），AI Agent 可据此了解可调用的功能及其参数。

当前声明的工具共 6 个：

| 工具名 | 说明 | 必填参数 |
|--------|------|----------|
| `ddddocr_initialize` | 初始化服务，选择加载的模型类型 | 无（全部可选） |
| `ddddocr_ocr` | 执行 OCR 文字识别 | `image`（base64） |
| `ddddocr_detection` | 执行目标检测 | `image`（base64） |
| `ddddocr_slide_match` | 滑块边缘匹配算法 | `target_image`, `background_image` |
| `ddddocr_slide_comparison` | 滑块图像差异比较 | `target_image`, `background_image` |
| `ddddocr_status` | 获取服务状态 | 无 |

Sources: [ddddocr/api/mcp.py:28-118]()

### `POST /mcp/call` — 工具调用

接收 `MCPRequest`（含 `method`、`params`、`id`），根据 `method` 字段分发到对应处理逻辑，返回 `MCPResponse`。

## 请求与响应模型

MCP 协议使用三个 Pydantic 模型：

```python
class MCPRequest(BaseModel):
    method: str          # 工具名，如 "ddddocr_ocr"
    params: Dict[str, Any]  # 工具参数
    id: Optional[Union[str, int]]  # 请求关联 ID

class MCPResponse(BaseModel):
    result: Optional[Any]          # 成功时的结果
    error: Optional[Dict[str, Any]]  # 失败时的错误 {code, message, data}
    id: Optional[Union[str, int]]  # 与请求对应的 ID

class MCPCapabilities(BaseModel):
    tools: List[Dict[str, Any]]       # 工具声明列表
    resources: List[Dict[str, Any]]   # 资源列表（当前为空）
    prompts: List[Dict[str, Any]]     # 提示列表（当前为空）
```

Sources: [ddddocr/api/models.py:97-117]()

## 调用流程

以下序列图展示 AI Agent 通过 MCP 协议调用 OCR 识别的典型流程：

```mermaid
sequenceDiagram
    participant Agent as AI Agent
    participant MCP as MCPHandler
    participant Service as DDDDOCRService
    participant Core as ddddocr.DdddOcr

    Agent->>MCP: GET /mcp/capabilities
    MCP-->>Agent: 返回工具声明列表

    Agent->>MCP: POST /mcp/call {method: "ddddocr_initialize", params: {ocr: true}}
    MCP->>Service: service.initialize(config)
    Service->>Core: DdddOcr(ocr=True, ...)
    Core-->>Service: 实例就绪
    Service-->>MCP: {loaded_models: ["ocr", "slide"], message: "..."}
    MCP-->>Agent: MCPResponse {result: ...}

    Agent->>MCP: POST /mcp/call {method: "ddddocr_ocr", params: {image: "<base64>"}}
    MCP->>MCP: base64.b64decode(image)
    MCP->>Core: ocr_instance.classification(image_data)
    Core-->>MCP: "识别文本"
    MCP-->>Agent: MCPResponse {result: "识别文本"}
```

Sources: [ddddocr/api/mcp.py:120-214](), [ddddocr/api/server.py:22-80]()

## 服务架构

```text
FastAPI 应用 (create_app)
├── RESTful 路由 (routes.py)
│   ├── POST /initialize
│   ├── POST /ocr
│   ├── POST /detect
│   ├── POST /slide-match
│   └── GET  /status
│
└── MCP 路由 (/mcp 前缀, mcp.py)
    ├── GET  /mcp           → 协议信息
    ├── GET  /mcp/capabilities → 工具声明
    └── POST /mcp/call      → 工具分发
```

`MCPHandler` 在 `server.py:194` 中被实例化并注入同一个 `DDDDDOCRService` 服务实例。RESTful API 和 MCP 协议共享同一个 OCR/检测/滑块实例池，因此通过 MCP 初始化后，RESTful 端点也能使用已加载的模型，反之亦然。

Sources: [ddddocr/api/server.py:170-197](), [ddddocr/api/server.py:22-30]()

## 错误处理

MCP 工具调用采用统一的错误响应格式。当 `method` 对应的服务实例未初始化时，返回 HTTP 400；当遇到未知方法名时，同样返回 400。所有其他异常被捕获并封装为：

```json
{
  "error": {
    "code": -1,
    "message": "错误描述",
    "data": null
  }
}
```

与 RESTful API 不同，MCP 端点的错误不抛出 HTTP 异常，而是通过 `MCPResponse.error` 字段返回，保持了 JSON-RPC 风格的一致性。

Sources: [ddddocr/api/mcp.py:206-214]()

## 图像数据传输

所有涉及图像的工具（OCR、检测、滑块）均使用 **base64 编码** 传输图像数据。`image`、`target_image`、`background_image` 参数均为 base64 字符串，MCPHandler 在分发前调用 `base64.b64decode()` 解码为原始字节再传递给 ddddocr 核心。

Sources: [ddddocr/api/mcp.py:140-141](), [ddddocr/api/mcp.py:163-164](), [ddddocr/api/mcp.py:176-177]()

## 与 RESTful API 的对比

| 特性 | RESTful API (`/ocr`, `/det` 等) | MCP 协议 (`/mcp/call`) |
|------|----------------------------------|------------------------|
| 协议风格 | REST + JSON | JSON-RPC 风格 |
| 能力发现 | 无（需阅读文档） | `GET /mcp/capabilities` 自动声明 |
| 错误格式 | HTTP 状态码 + `APIResponse` | `MCPResponse.error` 字段 |
| 文件上传 | 支持（`/ocr/file`） | 不支持（仅 base64） |
| Agent 友好度 | 需手写调用代码 | 标准化工具声明，适合 Agent 自动发现和调用 |
| 实例管理 | 按需创建、自动清理 | 通过 `ddddocr_initialize` 显式初始化 |

Sources: [ddddocr/api/routes.py:52-68](), [ddddocr/api/mcp.py:120-214](), [ddddocr/api/app.py:239-281]()

## 使用示例

AI Agent 典型调用序列：

```bash
# 1. 查询可用工具
curl http://localhost:8000/mcp/capabilities

# 2. 初始化 OCR 服务
curl -X POST http://localhost:8000/mcp/call \
  -H "Content-Type: application/json" \
  -d '{"method": "ddddocr_initialize", "params": {"ocr": true}, "id": 1}'

# 3. 执行 OCR 识别
curl -X POST http://localhost:8000/mcp/call \
  -H "Content-Type: application/json" \
  -d '{"method": "ddddocr_ocr", "params": {"image": "<base64_encoded_image>"}, "id": 2}'

# 4. 查询服务状态
curl -X POST http://localhost:8000/mcp/call \
  -H "Content-Type: application/json" \
  -d '{"method": "ddddocr_status", "params": {}, "id": 3}'
```

## 服务启动

通过 `python -m ddddocr.api` 或直接调用 `run_server()` 启动时，MCP 端点随 FastAPI 应用自动挂载：

```
DDDDOCR API服务启动在 http://0.0.0.0:8000
MCP协议地址: http://0.0.0.0:8000/mcp
```

Sources: [ddddocr/api/server.py:200-206](), [ddddocr/api/__main__.py:1-10]()

## 总结

ddddocr 的 MCP 集成提供了一条标准化路径，使 AI Agent 无需了解 ddddocr 的 Python API 细节，即可通过 JSON-RPC 风格的 HTTP 调用完成 OCR 识别、目标检测和滑块匹配。协议实现简洁——一个 `MCPHandler` 类承载了能力声明、请求分发和错误处理的全部逻辑，通过 FastAPI Router 挂载到主应用，与 RESTful API 共享同一服务实例池。

---
