# ddddocr 技术百科 — 验证码离线识别 SDK

> ddddocr 是一个基于 ONNX Runtime 的离线验证码识别 Python 库，内置 OCR 文字识别、目标检测和滑块匹配三大引擎，支持自定义模型、颜色过滤，并提供 FastAPI HTTP 服务与 MCP 协议接入。

## Context Links

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

## Repository Metadata

- Repository: sml2h3/ddddocr

- Generated: 2026-06-23T07:41:07.977Z
- Updated: 2026-06-23T07:42:25.470Z
- Runtime: Claude Code
- Format: Explain Like I'm 5
- Pages: 9

## Page Index

- 01. [用大白话说 ddddocr](https://grok-wiki.com/public/wiki/sml2h3-ddddocr-a34dd45d9f63/pages/01-ddddocr.md) - 这个仓库做什么、最简单的类比、以及你需要记住的几件事。
- 02. [安装与第一次运行](https://grok-wiki.com/public/wiki/sml2h3-ddddocr-a34dd45d9f63/pages/02-page-2.md) - 从 pip 安装到跑通第一个验证码识别的完整步骤，包括 Docker 方式。
- 03. [三个引擎：OCR、检测、滑块](https://grok-wiki.com/public/wiki/sml2h3-ddddocr-a34dd45d9f63/pages/03-ocr.md) - ddddocr 内部有三个独立引擎，各司其职——文字识别、目标检测、滑块缺口定位。
- 04. [OCR 识别流水线：从图片到文字](https://grok-wiki.com/public/wiki/sml2h3-ddddocr-a34dd45d9f63/pages/04-ocr.md) - 一张验证码图片如何经过加载、预处理、模型推理、CTC 解码，最终变成一行文字。
- 05. [图像预处理与增强](https://grok-wiki.com/public/wiki/sml2h3-ddddocr-a34dd45d9f63/pages/05-page-5.md) - 在送入模型之前，图像经历了哪些尺寸调整、灰度化、去噪和标准化操作。
- 06. [自定义模型与字符集](https://grok-wiki.com/public/wiki/sml2h3-ddddocr-a34dd45d9f63/pages/06-page-6.md) - 如何加载自己训练的 ONNX 模型和自定义字符集文件，突破内置模型的限制。
- 07. [颜色过滤：只看你想看的颜色](https://grok-wiki.com/public/wiki/sml2h3-ddddocr-a34dd45d9f63/pages/07-page-7.md) - 在识别前用 HSV 颜色空间过滤干扰色，保留目标字符的颜色，提升识别准确率。
- 08. [HTTP API 与 MCP 协议服务](https://grok-wiki.com/public/wiki/sml2h3-ddddocr-a34dd45d9f63/pages/08-http-api-mcp.md) - 通过 FastAPI 暴露 REST 接口，或通过 MCP 协议让 AI Agent 直接调用 ddddocr 能力。
- 09. [总结与下一步](https://grok-wiki.com/public/wiki/sml2h3-ddddocr-a34dd45d9f63/pages/09-page-9.md) - 回顾核心思想、最值得记住的一句话，以及推荐阅读路径。

## Source File Index

- `ddddocr/__init__.py`
- `ddddocr/__main__.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/base.py`
- `ddddocr/core/detection_engine.py`
- `ddddocr/core/ocr_engine.py`
- `ddddocr/core/slide_engine.py`
- `ddddocr/models/charset_manager.py`
- `ddddocr/models/model_loader.py`
- `ddddocr/preprocessing/color_filter.py`
- `ddddocr/preprocessing/image_processor.py`
- `ddddocr/utils/image_io.py`
- `ddddocr/utils/validators.py`
- `docker-compose.yml`
- `Dockerfile`
- `examples/api_client.py`
- `examples/basic_ocr.py`
- `pyproject.toml`
- `README.md`
- `requirements.txt`

---

## 01. 用大白话说 ddddocr

> 这个仓库做什么、最简单的类比、以及你需要记住的几件事。

- Page Markdown: https://grok-wiki.com/public/wiki/sml2h3-ddddocr-a34dd45d9f63/pages/01-ddddocr.md
- Generated: 2026-06-23T07:38:18.472Z

### Source Files

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

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

# 用大白话说 ddddocr

ddddocr 是一个**离线验证码识别 Python 库**。它的核心卖点是：把训练好的神经网络模型打包进库本身，用户只需 `pip install ddddocr`，不需要自己下载模型文件、配置深度学习框架，就能直接识别验证码图片里的文字。

本页用最直白的方式解释这个仓库做什么、怎么工作的、以及你需要记住的几件事。

---

## 一句话类比

把 ddddocr 想象成一台**自动售货机**：你把验证码图片塞进去（`bytes`），它把识别出的文字吐出来（`str`）。你不需要知道里面的齿轮怎么转——模型文件、推理引擎、字符集映射全都封装好了。

---

## 它能做什么

ddddocr 提供三种核心能力，通过一个统一的入口类 `DdddOcr` 暴露：

| 能力 | 用法 | 背后原理 |
|------|------|----------|
| **文字识别（OCR）** | `ocr.classification(image)` | 神经网络模型 + 字符集解码 |
| **目标检测** | `det.detection(image)` | 神经网络模型，返回边界框坐标 |
| **滑块验证码匹配** | `slide.slide_match(target, bg)` | 纯 OpenCV 模板匹配，**不需要模型** |

Sources: [ddddocr/compat/v1.py:72-93]()、[ddddocr/core/slide_engine.py:23-29]()

---

## 最简使用示例

```python
import ddddocr

ocr = ddddocr.DdddOcr()                    # 初始化一次，加载模型
with open("captcha.jpg", "rb") as f:
    image = f.read()

result = ocr.classification(image)          # 识别图片文字
print(result)                               # 输出类似 "a3K9"
```

关键点：**`DdddOcr()` 只需要创建一次**，之后可以反复调用 `classification()`。每次重新创建会重新加载模型，白白浪费时间。

Sources: [README.md:214-227]()、[ddddocr/compat/v1.py:26-42]()

---

## 内部架构：三层结构

ddddocr 的代码分为三层，每层职责清晰：

```
用户代码
  │
  ▼
┌─────────────────────────────────┐
│  DdddOcr（兼容门面层）           │  ← ddddocr/compat/v1.py
│  统一入口，根据参数选择引擎       │
└──────────┬──────────────────────┘
           │
     ┌─────┼─────────┐
     ▼     ▼         ▼
┌────────┐┌────────┐┌────────┐
│OCR 引擎││检测引擎││滑块引擎│  ← ddddocr/core/
│(ONNX) ││(ONNX) ││(OpenCV)│
└───┬────┘└───┬────┘└────────┘
    ▼         ▼
┌─────────────────┐
│  模型加载器      │  ← ddddocr/models/model_loader.py
│  字符集管理器    │  ← ddddocr/models/charset_manager.py
└─────────────────┘
```

**要点**：OCR 引擎和检测引擎依赖 ONNX 模型文件；滑块引擎**不使用任何模型**，纯粹靠 OpenCV 的图像处理算法工作。

Sources: [ddddocr/compat/v1.py:72-93]()、[ddddocr/core/slide_engine.py:23-29]()

---

## 模型文件说明

ddddocr 随库附带了三个 ONNX 模型文件，打包在 `ddddocr/` 目录下：

| 文件名 | 用途 | 触发方式 |
|--------|------|----------|
| `common_old.onnx` | 默认 OCR 模型 | 默认使用 |
| `common.onnx` | Beta OCR 模型 | `beta=True` |
| `common_det.onnx` | 目标检测模型 | `det=True` |

模型选择逻辑在 `ModelLoader.load_ocr_model()` 中实现：当 `beta=True` 时加载 `common.onnx`，否则加载 `common_old.onnx`。

Sources: [ddddocr/models/model_loader.py:119-145]()

---

## 三种工作模式

通过初始化参数组合，`DdddOcr` 会进入不同模式：

```python
# 模式1：文字识别（默认）
ocr = ddddocr.DdddOcr(ocr=True, det=False)

# 模式2：目标检测
det = ddddocr.DdddOcr(det=True, ocr=False)

# 模式3：滑块匹配（两个都关）
slide = ddddocr.DdddOcr(ocr=False, det=False)
```

模式选择的优先级规则（在 `compat/v1.py` 的 `__init__` 中实现）：

1. `det=True` → 目标检测模式（**最高优先级**，即使同时设 `ocr=True`）
2. `ocr=True` 或提供了 `import_onnx_path` → OCR 模式
3. 都不设 → 滑块模式（`SlideEngine` 始终会创建）

Sources: [ddddocr/compat/v1.py:72-93]()

---

## 推理流程：图片进去，文字出来

以 OCR 识别为例，一次 `classification()` 调用的完整流程：

1. **输入校验** — `validate_image_input()` 检查类型是否为 `bytes`、`str`、`PIL.Image` 等
2. **图片加载** — 统一转为 numpy 数组
3. **预处理** — 缩放到 64×64、转灰度（单通道）、可选的 PNG 透明修复或颜色过滤
4. **ONNX 推理** — `onnxruntime.InferenceSession.run()` 得到输出矩阵
5. **后处理** — 对输出矩阵取 argmax，通过 `CharsetManager.index_to_char()` 映射为文字

如果调用 `classification(image, probability=True)`，则跳过第 5 步，直接返回每个字符位置的概率分布字典。

Sources: [ddddocr/core/ocr_engine.py:39-54]()、[ddddocr/models/charset_manager.py:168]()

---

## 你需要记住的几件事

### 1. 只初始化一次

模型加载是最慢的步骤。创建 `DdddOcr()` 后，应该复用同一个实例处理所有图片。在循环中反复创建实例会严重拖慢速度。

### 2. 线程安全：每个线程一个实例

如果在多线程环境中使用，**每个线程应创建独立的 `DdddOcr` 实例**。共享实例可能导致识别结果错乱。

### 3. 滑块引擎不需要模型

`SlideEngine` 不加载任何 ONNX 文件，它直接用 OpenCV 做模板匹配。这意味着滑块匹配的初始化速度远快于 OCR/检测。

Sources: [ddddocr/core/slide_engine.py:23-29]()

### 4. 字符集可以缩小

通过 `set_ranges()` 方法可以限定识别范围，减少误识别：

```python
ocr.set_ranges(0)                    # 只识别数字 0-9
ocr.set_ranges("0123456789+-x/=")   # 自定义字符集
```

预设值 `0`-`7` 分别对应数字、小写英文、大写英文等组合。

Sources: [README.md:303-335]()

### 5. GPU 加速可选

默认用 CPU 推理。设置 `use_gpu=True` 会尝试加载 `CUDAExecutionProvider`，需要预装 CUDA 和 `onnxruntime-gpu`。如果 GPU 不可用，会自动回退到 CPU。

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

### 6. 还能跑 HTTP API

除了作为库使用，ddddocr 还内置了一个 FastAPI 服务：

```bash
python -m ddddocr api --host 0.0.0.0 --port 8000
```

这会启动一个 REST API，提供 `/ocr`、`/det`、`/slide_match` 等端点，适合需要网络调用的场景。API 依赖（`fastapi`、`uvicorn` 等）是可选的，需要额外安装：`pip install ddddocr[api]`。

Sources: [ddddocr/__main__.py:8-75]()、[pyproject.toml:34-39]()

---

## 依赖关系

ddddocr 的设计哲学是"最简依赖"。核心依赖只有：

- **onnxruntime** — ONNX 模型推理引擎
- **Pillow** — 图片读取
- **opencv-python** — 图像处理（滑块匹配、预处理）
- **numpy** — 数组运算

不需要 PyTorch、TensorFlow 等重量级框架。训练模型用的是 PyTorch（通过 [dddd_trainer](https://github.com/sml2h3/dddd_trainer)），但推理阶段只依赖 ONNX Runtime。

Sources: [pyproject.toml:22-28]()

---

## 总结

ddddocr 本质上是一个**预训练模型的便捷封装**：把用 PyTorch 训练好的验证码识别模型转成 ONNX 格式，打包进 Python 库，再用 `onnxruntime` 做推理。用户不需要了解深度学习的任何细节，三行代码就能识别验证码。它的三种引擎（OCR、检测、滑块）通过一个统一的 `DdddOcr` 类对外暴露，根据初始化参数自动切换工作模式。

---

## 02. 安装与第一次运行

> 从 pip 安装到跑通第一个验证码识别的完整步骤，包括 Docker 方式。

- Page Markdown: https://grok-wiki.com/public/wiki/sml2h3-ddddocr-a34dd45d9f63/pages/02-page-2.md
- Generated: 2026-06-23T07:32:19.589Z

### Source Files

- `pyproject.toml`
- `requirements.txt`
- `Dockerfile`
- `docker-compose.yml`
- `ddddocr/__main__.py`
- `examples/basic_ocr.py`

<details>
<summary>相关源文件</summary>

以下文件用于生成此维基页面：

- [pyproject.toml](pyproject.toml)
- [requirements.txt](requirements.txt)
- [Dockerfile](Dockerfile)
- [docker-compose.yml](docker-compose.yml)
- [ddddocr/__main__.py](ddddocr/__main__.py)
- [ddddocr/__init__.py](ddddocr/__init__.py)
- [ddddocr/api/app.py](ddddocr/api/app.py)
- [examples/basic_ocr.py](examples/basic_ocr.py)
- [examples/api_client.py](examples/api_client.py)
</details>

# 安装与第一次运行

本页面介绍如何从零开始安装 DdddOcr 并成功运行第一个验证码识别程序。无论你是想在本地 Python 脚本中直接调用，还是通过 Docker 部署一个 HTTP API 服务，这里都有完整步骤。

DdddOcr 是一个离线的通用验证码识别 SDK，核心依赖 ONNX Runtime 做推理，不需要联网即可使用。安装完成后，只需 5 行代码就能识别一张验证码图片。

---

## 环境要求

在安装之前，请确认你的环境满足以下条件：

| 要求 | 最低版本 | 说明 |
|------|----------|------|
| Python | 3.10 | 支持 3.10、3.11、3.12、3.13 |
| 操作系统 | — | Windows 64 位、Linux 64/ARM64、macOS X64 |
| 磁盘空间 | ~200MB | 主要用于 ONNX 模型文件和依赖包 |

> **不支持**：Windows 32 位、Linux 32 位系统。macOS M1/M2/M3 (ARM) 芯片用户需参考 [issue #67](https://github.com/sml2h3/ddddocr/issues/67)。

Sources: [pyproject.toml:10-21](pyproject.toml#L10-L21)

---

## 方式一：从 PyPI 安装（推荐）

最简单的安装方式，一条命令搞定：

```bash
pip install ddddocr
```

安装完成后，`pip` 会自动拉取以下依赖：

| 依赖包 | 用途 |
|--------|------|
| `numpy` | 数值计算 |
| `onnxruntime` | ONNX 模型推理引擎 |
| `Pillow` | 图片读取与处理 |
| `opencv-python` (Windows/macOS) 或 `opencv-python-headless` (Linux) | 图像处理（滑块匹配、颜色过滤等） |

如果需要同时使用内置的 HTTP API 服务功能，安装时加上 `[api]` 额外依赖：

```bash
pip install "ddddocr[api]"
```

这会额外安装 `fastapi`、`uvicorn`、`python-multipart` 和 `pydantic`。

Sources: [pyproject.toml:22-39](pyproject.toml#L22-L39)

---

## 方式二：从源码安装

适合需要修改源码或参与开发的用户：

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

如果需要 API 依赖：

```bash
pip install ".[api]"
```

> **注意**：请勿在 ddddocr 项目根目录内直接 `import ddddocr`，否则会因目录名冲突导致导入失败。请确保你的工作目录名称不是 `ddddocr`。

Sources: [pyproject.toml:44-53](pyproject.toml#L44-L53)

---

## 方式三：Docker 部署（API 服务）

如果你想以 HTTP API 的方式对外提供验证码识别服务，可以使用 Docker 一键部署。

### 构建镜像

```bash
docker build -t ddddocr-api .
```

镜像基于 `python:3.10-slim`，会自动安装系统依赖（`libgl1-mesa-glx`、`libglib2.0-0` 等 OpenCV 所需库）和 Python 依赖。

### 运行容器

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

启动后，API 服务默认监听 `0.0.0.0:8000`，可通过环境变量覆盖配置：

```bash
docker run -d --name ddddocr-api \
  -p 8000:8000 \
  -e DDDDOCR_OCR=true \
  -e DDDDOCR_BETA=true \
  -e DDDDOCR_WORKERS=4 \
  ddddocr-api
```

### 使用 Docker Compose

项目提供了 `docker-compose.yml`，启动更简洁：

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

也可以通过环境变量自定义配置：

```bash
DDDDOCR_BETA=true DDDDOCR_WORKERS=4 docker-compose up -d
```

### Docker 环境变量一览

| 环境变量 | 默认值 | 说明 |
|----------|--------|------|
| `DDDDOCR_HOST` | 0.0.0.0 | 服务绑定地址 |
| `DDDDOCR_PORT` | 8000 | 服务监听端口 |
| `DDDDOCR_WORKERS` | 1 | uvicorn 工作进程数 |
| `DDDDOCR_OCR` | true | 是否启用 OCR |
| `DDDDOCR_DET` | false | 是否启用目标检测 |
| `DDDDOCR_BETA` | false | 是否使用 Beta 模型 |
| `DDDDOCR_USE_GPU` | false | 是否使用 GPU 加速 |
| `DDDDOCR_SHOW_AD` | true | 是否显示广告 |

容器内置健康检查，每 30 秒访问 `http://localhost:8000/health`。

Sources: [Dockerfile:1-77](Dockerfile), [docker-compose.yml:1-80](docker-compose.yml), [ddddocr/api/app.py:319-328](ddddocr/api/app.py#L319-L328)

---

## 第一次运行：本地 Python 脚本

安装完成后，用以下代码识别一张验证码图片：

```python
import ddddocr

# 初始化（只需一次，会加载模型）
ocr = ddddocr.DdddOcr(show_ad=False)

# 读取图片
with open("captcha.jpg", "rb") as f:
    image = f.read()

# 识别
result = ocr.classification(image)
print(result)
```

这就是全部代码。`DdddOcr()` 初始化时会加载内置的 ONNX 模型，第一次调用可能需要几秒钟，之后复用同一个实例即可。

### 使用示例脚本

仓库的 `examples/` 目录提供了多个现成示例：

```bash
# 基础 OCR 识别
python examples/basic_ocr.py path/to/captcha.jpg

# 带概率输出
python examples/basic_ocr.py path/to/captcha.jpg --probability

# 使用 Beta 模型
python examples/basic_ocr.py path/to/captcha.jpg --beta
```

`basic_ocr.py` 的核心逻辑非常简洁：创建 `DdddOcr` 实例，读取图片字节，调用 `classification()` 方法，打印结果。

Sources: [examples/basic_ocr.py:1-82](examples/basic_ocr.py), [ddddocr/__init__.py:1-27](ddddocr/__init__.py)

---

## 第一次运行：HTTP API 服务

如果你更希望通过 HTTP 接口调用，可以启动内置的 API 服务。

### 启动服务

```bash
# 使用默认配置（OCR 模式，端口 8000）
python -m ddddocr api

# 自定义配置
python -m ddddocr api --host 0.0.0.0 --port 8080 --workers 4 --beta true
```

服务启动后，访问 `http://localhost:8000/docs` 可查看 Swagger 交互式文档。

### 调用 API

```python
import requests
import base64

# 读取图片并 Base64 编码
with open("captcha.png", "rb") as f:
    img_base64 = base64.b64encode(f.read()).decode()

# 发送 OCR 请求
response = requests.post(
    "http://localhost:8000/ocr",
    json={"image": img_base64}
)

print(response.json()["result"])
```

或者使用文件上传方式：

```python
import requests

with open("captcha.png", "rb") as f:
    response = requests.post(
        "http://localhost:8000/ocr/file",
        files={"file": f}
    )

print(response.json()["result"])
```

### 主要 API 端点

| 端点 | 方法 | 功能 |
|------|------|------|
| `/ocr` | POST | OCR 文字识别（Base64） |
| `/ocr/file` | POST | OCR 文字识别（文件上传） |
| `/det` | POST | 目标检测 |
| `/slide_match` | POST | 滑块匹配 |
| `/slide_comparison` | POST | 滑块差异比较 |
| `/health` | GET | 健康检查 |
| `/docs` | GET | Swagger 文档 |

Sources: [ddddocr/__main__.py:1-79](ddddocr/__main__.py), [ddddocr/api/app.py:335-404](ddddocr/api/app.py#L335-L404), [examples/api_client.py:1-72](examples/api_client.py)

---

## 初始化参数速查

`DdddOcr` 构造函数的常用参数：

```python
ocr = ddddocr.DdddOcr(
    ocr=True,            # 启用 OCR（默认）
    det=False,           # 启用目标检测
    beta=False,          # 使用 Beta 模型
    show_ad=False,       # 关闭广告（生产环境推荐）
    use_gpu=False,       # GPU 加速（需 onnxruntime-gpu）
)
```

| 参数 | 默认值 | 说明 |
|------|--------|------|
| `ocr` | True | 文字识别模式 |
| `det` | False | 目标检测模式（与 `ocr` 互斥，`det` 优先） |
| `beta` | False | 使用 Beta 模型，对部分复杂验证码效果更好 |
| `show_ad` | True | 初始化时是否显示广告 |
| `use_gpu` | False | GPU 加速，需额外安装 CUDA + onnxruntime-gpu |
| `import_onnx_path` | "" | 自定义模型路径（需同时设置 `charsets_path`） |

> **重要**：`DdddOcr` 实例只需初始化一次。在循环中反复创建实例会严重影响性能。多线程场景下，每个线程应创建独立的实例。

Sources: [ddddocr/__init__.py:1-4](ddddocr/__init__.py#L1-L4), [pyproject.toml:22-28](pyproject.toml#L22-L28)

---

## 常见问题

### 安装时报错找不到 opencv

Linux 服务器上如果安装 `opencv-python` 失败，可以改用无头版本：

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

项目已根据操作系统自动选择正确的包（`pyproject.toml` 中通过 `sys_platform` 条件指定），通常不需要手动处理。

### 初始化很慢

首次初始化需要加载 ONNX 模型文件（内置于包中），这是正常现象。关键是要**复用实例**，不要每次识别都重新创建。

### macOS M1/M2/M3 芯片兼容性

ARM 架构的 macOS 需要特殊处理，请参考 [GitHub issue #67](https://github.com/sml2h3/ddddocr/issues/67)。

### 在项目根目录 import 报错

确保你的工作目录名称不是 `ddddocr`，否则 Python 会优先导入当前目录而非已安装的包。

---

## 总结

DdddOcr 的安装流程非常简洁：`pip install ddddocr` 即可完成基础安装，5 行代码就能跑通第一个验证码识别。如果需要对外提供 HTTP 服务，`python -m ddddocr api` 一条命令启动 FastAPI 服务器，或者用 Docker 部署到生产环境。整个过程不需要额外下载模型文件——模型已内置于 pip 包中。

---

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

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

- Page Markdown: https://grok-wiki.com/public/wiki/sml2h3-ddddocr-a34dd45d9f63/pages/03-ocr.md
- Generated: 2026-06-23T07:33:12.881Z

### 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` 门面类对外暴露，既保持了各自内部实现的独立性，又为用户提供了简洁一致的使用体验。滑块引擎不依赖模型的特性使其始终可用，成为另外两个引擎的有力补充。

---

## 04. OCR 识别流水线：从图片到文字

> 一张验证码图片如何经过加载、预处理、模型推理、CTC 解码，最终变成一行文字。

- Page Markdown: https://grok-wiki.com/public/wiki/sml2h3-ddddocr-a34dd45d9f63/pages/04-ocr.md
- Generated: 2026-06-23T07:31:05.090Z

### Source Files

- `ddddocr/core/ocr_engine.py`
- `ddddocr/models/model_loader.py`
- `ddddocr/models/charset_manager.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/model_loader.py](ddddocr/models/model_loader.py)
- [ddddocr/models/charset_manager.py](ddddocr/models/charset_manager.py)
- [ddddocr/utils/image_io.py](ddddocr/utils/image_io.py)
- [ddddocr/preprocessing/image_processor.py](ddddocr/preprocessing/image_processor.py)
- [ddddocr/preprocessing/color_filter.py](ddddocr/preprocessing/color_filter.py)
</details>

# OCR 识别流水线：从图片到文字

本文介绍 ddddocr 的核心 OCR 识别流程——一张验证码图片如何经过**加载、预处理、模型推理、CTC 解码**四个阶段，最终变成一行可读文字。理解这条流水线有助于排查识别不准、自定义模型接入、以及字符集范围限制等问题。

---

## 整体流程概览

```
输入图片（bytes / base64 / 文件路径 / PIL Image / numpy）
    │
    ▼
┌─────────────┐
│ 1. 图片加载   │  load_image_from_input()
└─────┬───────┘
      │  PIL Image (可能为 RGBA)
      ▼
┌─────────────┐
│ 2. 颜色过滤   │  ColorFilter（可选，按 HSV 范围过滤干扰色）
└─────┬───────┘
      │  PIL Image
      ▼
┌─────────────┐
│ 3. 预处理     │  resize → grayscale → normalize → 维度调整
└─────┬───────┘
      │  numpy array, shape = (1, C, H, W), float32, 值域 [0,1]
      ▼
┌─────────────┐
│ 4. ONNX 推理  │  session.run()
└─────┬───────┘
      │  output shape = (seq_len, 1, num_classes) 或类似
      ▼
┌─────────────┐
│ 5. CTC 解码   │  去连续重复 → 去 blank(索引 0) → 映射字符
└─────┬───────┘
      │
      ▼
    识别文字 "aB3x"
```

---

## 第一阶段：图片加载

`load_image_from_input()` 函数是统一入口，接受五种输入格式并返回标准的 `PIL.Image` 对象：

| 输入类型 | 处理方式 |
|---------|---------|
| `bytes` | 用 `Image.open(io.BytesIO(...))` 解码 |
| `str`（文件路径） | 直接 `Image.open(path)` |
| `str`（base64） | 先 `base64.b64decode`，再 `Image.open` |
| `PIL.Image` | 调用 `.copy()` 避免外部修改 |
| `numpy.ndarray` | 按 shape/dtype 转为灰度或 RGB 的 PIL Image |

对于 PNG 透明背景的验证码，`png_rgba_black_preprocess()` 会创建白色背景并把原图 alpha 通道贴上去，避免透明像素导致文字丢失。

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

---

## 第二阶段：颜色过滤（可选）

当调用者传入 `color_filter_colors` 或 `color_filter_custom_ranges` 参数时，`ColorFilter` 会在 HSV 颜色空间对图片做掩码过滤——只保留指定颜色范围内的像素，其余变白。这在验证码含有干扰线或干扰色块时特别有用。

内置预设覆盖 `red`、`blue`、`green`、`yellow` 等常见颜色。例如 `red` 需要两个 HSV 区间（0-10 和 170-180），因为红色在色相环上跨越了 0° 边界。

Sources: [ddddocr/preprocessing/color_filter.py:23-34]()，[ddddocr/core/ocr_engine.py:133-139]()

---

## 第三阶段：图像预处理

这是流水线中最关键的一步，`_preprocess_image()` 负责把任意尺寸的 PIL Image 变成模型能吃的张量。

### 3.1 尺寸调整

默认模型要求**高度固定为 64 像素，宽度按比例缩放**：

```python
target_height = 64
target_width = int(image.size[0] * (target_height / image.size[1]))
```

自定义模型则根据 `charset_info['image']` 配置决定：若第一个维度为 `-1` 表示宽度自适应；否则使用固定尺寸。

Sources: [ddddocr/core/ocr_engine.py:176-192]()

### 3.2 灰度转换

默认模型和 `channel=1` 的自定义模型会将图片转为灰度（`mode='L'`），单通道。3 通道模型则保留彩色。

### 3.3 归一化与维度调整

```python
img_array = np.array(image).astype(np.float32) / 255.0  # 像素值归一化到 [0,1]

# 2D 灰度 → (1, H, W)，添加通道维
# 3D 彩色 → (C, H, W)，HWC 转 CHW
# 最后 → (1, C, H, W)，添加 batch 维
```

最终张量 shape 为 `(1, 1, 64, W)` 或 `(1, 3, H, W)`，dtype 为 `float32`。

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

---

## 第四阶段：ONNX 模型推理

模型通过 `onnxruntime.InferenceSession` 加载和执行。`ModelLoader` 负责：

- **选择模型文件**：默认 `common_old.onnx`，beta 模式用 `common.onnx`，自定义模型由用户指定路径
- **配置执行提供者**：优先 CUDA（GPU），失败回退 CPU
- **创建推理会话**：`onnxruntime.InferenceSession(model_path, providers=...)`

推理只需一次调用：

```python
input_name = self.session.get_inputs()[0].name
outputs = self.session.run(None, {input_name: image_array})
```

输出 `outputs[0]` 的典型 shape 为 `(sequence_length, 1, num_classes)`，其中 `num_classes` 等于字符集大小。

Sources: [ddddocr/models/model_loader.py:55-81]()，[ddddocr/core/ocr_engine.py:228-234]()

---

## 第五阶段：CTC 解码

这是将模型的"概率矩阵"变成最终文字的核心步骤，分为三个子步骤：

### 5.1 取最大概率索引

对输出的最后一维（字符类别维度）取 `argmax`，得到每个时间步的预测索引：

```python
predicted_indices = np.argmax(output[:, 0, :], axis=1)
# 例如：[0, 3, 3, 0, 7, 7, 12, 0] （0 代表 blank）
```

### 5.2 CTC 去重与去 blank

CTC（Connectionist Temporal Classification）的核心规则：

1. **去连续重复**：相邻相同的索引只保留一个
2. **去 blank**：索引 0 代表"无字符"（blank token），直接跳过

```python
# [0, 3, 3, 0, 7, 7, 12, 0]
# → 去连续重复后: [0, 3, 0, 7, 12, 0]
# → 去 blank 后: [3, 7, 12]
```

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

### 5.3 索引映射字符 & 范围过滤

解码后的索引通过字符集（charset）映射回文字。如果调用者设置了 `charset_range`（如只允许数字），不在有效索引内的字符会被跳过。

字符集是一个 Python 列表，索引 0 是空字符串 `""`（blank 对应位），后续索引依次对应各可识别字符。默认旧版字符集约有数千个中文、字母、数字、符号。

Sources: [ddddocr/core/ocr_engine.py:280-295]()，[ddddocr/models/charset_manager.py:237-238]()

---

## 字符集管理

`CharsetManager` 统一管理字符集的加载、索引映射和范围限制：

| 功能 | 方法 | 说明 |
|------|------|------|
| 加载默认字符集 | `load_default_charset()` | 内置 old/beta 两套字符列表 |
| 加载自定义字符集 | `load_custom_charset(path)` | 从 JSON 文件读取，需含 `charset`、`word`、`image`、`channel` 字段 |
| 设置范围限制 | `set_ranges(range)` | 支持按索引（int）、按字符串、按列表三种方式 |
| 获取有效索引 | `get_valid_indices()` | 返回 `charset_range` 中各字符在完整 charset 里的索引 |

范围限制会自动追加空字符串 `""`，确保 blank token 始终存在。

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

---

## 自定义模型接入

用户可以通过 `import_onnx_path` 和 `charsets_path` 参数加载自定义 ONNX 模型。字符集 JSON 文件格式：

```json
{
  "charset": ["", "a", "b", "c", ...],
  "word": false,
  "image": [64, 64],
  "channel": 1
}
```

- `charset`：字符列表，索引 0 必须为空字符串（CTC blank）
- `word`：是否为单词级别识别（影响 resize 策略）
- `image`：目标尺寸，`[-1, H]` 表示宽度自适应
- `channel`：通道数，1 为灰度，3 为彩色

Sources: [ddddocr/models/model_loader.py:170-204]()，[ddddocr/core/ocr_engine.py:64-78]()

---

## 概率模式

当 `probability=True` 时，引擎会在 CTC 解码之外额外计算 softmax 概率，返回字典：

```python
{
    'text': 'aB3x',           # 识别文字
    'probabilities': [...],   # 每个时间步对所有字符的概率
    'charset': [...],         # 完整字符集
    'confidence': 0.95        # 平均最高概率
}
```

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

---

## 总结

ddddocr 的 OCR 流水线是一条经典的**端到端文字识别管线**：图片加载 → 可选颜色过滤 → 尺寸/灰度/归一化预处理 → ONNX Runtime 推理 → CTC 贪心解码 → 字符映射。整条链路代码量不大，但每一步都有明确的职责划分——`image_io` 负责格式统一，`ImageProcessor` 负责像素变换，`ModelLoader` 负责模型生命周期，`CharsetManager` 负责字符映射和范围约束，`OCREngine` 则将它们串成完整的预测管线。

---

## 05. 图像预处理与增强

> 在送入模型之前，图像经历了哪些尺寸调整、灰度化、去噪和标准化操作。

- Page Markdown: https://grok-wiki.com/public/wiki/sml2h3-ddddocr-a34dd45d9f63/pages/05-page-5.md
- Generated: 2026-06-23T07:35:04.458Z

### Source Files

- `ddddocr/preprocessing/image_processor.py`
- `ddddocr/preprocessing/color_filter.py`
- `ddddocr/utils/image_io.py`
- `ddddocr/utils/validators.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/utils/image_io.py](ddddocr/utils/image_io.py)
- [ddddocr/utils/validators.py](ddddocr/utils/validators.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)
</details>

# 图像预处理与增强

ddddocr 是一个基于 ONNX Runtime 的验证码识别库。在将图像送入模型推理之前，系统会经过一套完整的预处理流水线——包括图像加载与格式归一化、颜色过滤、尺寸调整、灰度化、去噪、对比度增强以及像素值标准化。这些步骤确保无论用户传入什么格式的图片（bytes、base64、文件路径、PIL Image 或 numpy 数组），最终送入模型的张量都具有一致的形状和数值范围。

本页梳理 OCR、目标检测、滑块匹配三条引擎各自走过的预处理路径，并解释每一步的设计理由。

## 图像加载与格式归一化

用户可以向 ddddocr 传入多种格式的图像输入。`load_image_from_input()` 函数负责将它们统一转换为 PIL Image 对象：

| 输入类型 | 处理方式 |
|---------|---------|
| `bytes` | 通过 `io.BytesIO` 加载为 PIL Image |
| `str`（文件路径） | 直接 `Image.open()` |
| `str`（base64） | 先 base64 解码，再加载 |
| `pathlib.PurePath` | `Image.open()` |
| `Image.Image` | 复制一份副本，避免修改原图 |
| `np.ndarray` | 根据形状和 dtype 转换（灰度/RGB/RGBA，float→uint8） |

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

## PNG 透明背景处理

验证码图片有时是 RGBA 模式的 PNG，带有透明背景。`png_rgba_black_preprocess()` 将透明区域填充为白色（RGB 255,255,255），然后输出 RGB 模式图像。这一步在 OCR 预处理流水线中通过 `png_fix` 参数控制，仅在用户显式启用时执行。

```python
# ddddocr/utils/image_io.py:59-79
def png_rgba_black_preprocess(img: Image.Image) -> Image.Image:
    width = img.width
    height = img.height
    image = Image.new('RGB', size=(width, height), color=(255, 255, 255))
    image.paste(img, (0, 0), mask=img)
    return image
```

Sources: [ddddocr/utils/image_io.py:59-79](ddddocr/utils/image_io.py)

## 颜色过滤（HSV）

`ColorFilter` 类提供基于 HSV 颜色空间的颜色过滤功能。用户可以指定预设颜色名称（如 `red`、`blue`）或自定义 HSV 范围，系统会生成掩码并将匹配区域保留、不匹配区域设为白色背景。

内置预设涵盖 10 种常见颜色。红色因为 HSV 色相环的特性，需要两个范围来覆盖（0–10 和 170–180）。

```python
# ddddocr/preprocessing/color_filter.py:23-34
COLOR_PRESETS = {
    'red': [((0, 50, 50), (10, 255, 255)), ((170, 50, 50), (180, 255, 255))],
    'blue': [((100, 50, 50), (130, 255, 255))],
    'green': [((40, 50, 50), (80, 255, 255))],
    # ... 共 10 种
}
```

颜色过滤在 OCR 引擎的 `predict()` 方法中作为可选步骤执行，位于图像加载之后、预处理之前。如果过滤过程中出现异常，系统会打印警告并跳过该步骤，保证识别流程不中断。

Sources: [ddddocr/preprocessing/color_filter.py:19-67](ddddocr/preprocessing/color_filter.py), [ddddocr/core/ocr_engine.py:133-139](ddddocr/core/ocr_engine.py)

## OCR 引擎预处理流水线

OCR 引擎的 `_preprocess_image()` 方法是图像进入模型前的核心通道。流水线按顺序执行以下步骤：

### 1. 尺寸调整

目标高度固定为 64 像素，宽度按原始宽高比计算：

```python
# ddddocr/core/ocr_engine.py:178-180
target_height = 64
target_width = int(image.size[0] * (target_height / image.size[1]))
image = ImageProcessor.resize_image(image, (target_width, target_height))
```

`resize_image()` 使用 PIL 的 `LANCZOS` 重采样算法（高质量下采样）。宽度不固定，按比例缩放，这保证了不同宽高比的验证码都能被正确识别。

对于自定义模型，尺寸由模型配置文件中的 `image` 字段决定。如果宽度配置为 `-1`，则按高度等比缩放；否则使用固定的 `(width, height)`。当模型是 `word`（单词识别）模式时，输出为正方形。

### 2. 灰度化

默认模型要求单通道输入（`channel=1`），因此图像被转换为灰度图：

```python
image = ImageProcessor.convert_to_grayscale(image)
```

转换使用 PIL 的 `convert('L')` 方法，将 RGB 三通道加权合并为单通道。自定义模型如果 `channel` 不为 1，则跳过此步骤，保留彩色通道。

### 3. 像素值标准化

灰度化完成后，像素值从 `[0, 255]` 整数范围转换为 `[0.0, 1.0]` 浮点范围：

```python
# ddddocr/core/ocr_engine.py:199-202
img_array = np.array(image).astype(np.float32)
img_array = img_array / 255.0
```

### 4. 维度重排

最后一步是调整张量维度以匹配 ONNX 模型的输入格式：

- **灰度图**（2D 数组）：先 `expand_dims(axis=0)` 添加通道维度，得到 `(1, H, W)`
- **彩色图**（3D 数组 HWC）：`transpose(2, 0, 1)` 转为 CHW 格式 `(3, H, W)`
- 最终统一 `expand_dims(axis=0)` 添加 batch 维度，得到 `(1, C, H, W)`

```
原始图像 (PIL)
    │
    ▼
┌──────────────────┐
│ PNG透明背景处理   │  ← png_fix=True 时
│ (RGBA → RGB)     │
└────────┬─────────┘
         ▼
┌──────────────────┐
│ 颜色过滤 (可选)   │  ← HSV掩码过滤
│ ColorFilter       │
└────────┬─────────┘
         ▼
┌──────────────────┐
│ 尺寸调整          │  ← 高度64，宽度等比缩放
│ LANCZOS重采样     │
└────────┬─────────┘
         ▼
┌──────────────────┐
│ 灰度化            │  ← channel=1 时
│ RGB → L           │
└────────┬─────────┘
         ▼
┌──────────────────┐
│ 像素值标准化      │  ← float32, /255.0
└────────┬─────────┘
         ▼
┌──────────────────┐
│ 维度重排          │  ← (H,W) → (1,1,H,W)
│ 添加batch+channel │
└────────┬─────────┘
         ▼
    ONNX 模型推理
```

Sources: [ddddocr/core/ocr_engine.py:159-215](ddddocr/core/ocr_engine.py)

## ImageProcessor 增强工具

除了流水线中自动调用的步骤外，`ImageProcessor` 类还提供以下可独立使用的增强方法：

| 方法 | 功能 | 默认参数 |
|------|------|---------|
| `enhance_contrast()` | 对比度增强（PIL ImageEnhance） | factor=1.5 |
| `enhance_sharpness()` | 锐度增强（PIL ImageEnhance） | factor=1.5 |
| `remove_noise()` | 中值滤波去噪（OpenCV） | kernel_size=3 |
| `binarize_image()` | 二值化（simple/otsu/adaptive） | threshold=128 |
| `normalize_image()` | Z-score 标准化 | mean=0.0, std=1.0 |

`preprocess_for_ocr()` 是一个预设流水线，将上述多个步骤组合执行：RGBA 处理 → 等比缩放到目标高度 → 对比度增强（factor=1.2） → 中值滤波去噪 → 灰度化。这个方法适合需要完整预处理但不经过 ONNX 推理的场景。

二值化支持三种方法：
- **simple**：固定阈值，超过阈值的像素设为 255，否则为 0
- **otsu**：自动计算最优阈值（Otsu 算法）
- **adaptive**：自适应阈值，对图像不同区域使用不同阈值（高斯加权）

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

## 目标检测引擎预处理

目标检测引擎使用不同的预处理策略。`DetectionEngine.preproc()` 将图像缩放到固定的 416×416 尺寸，用灰度值 114 填充保持宽高比后的空白区域，然后将 HWC 格式转为 CHW：

```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
```

与 OCR 引擎的关键区别：
- 使用 OpenCV 的 `INTER_LINEAR` 插值（速度优先），而非 LANCZOS
- 固定正方形输入尺寸 416×416，而非等比缩放
- 保留三通道彩色，不转灰度
- 填充值 114（YOLO 系列模型的惯例），而非 0 或 255
- 不做 `/255.0` 归一化，直接以 uint8→float32 送入

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

## 滑块匹配引擎预处理

滑块匹配引擎不使用深度学习模型，而是基于传统图像处理。预处理路径取决于匹配模式：

**简单模板匹配**：将图像转为灰度后直接进行 `cv2.matchTemplate`（归一化相关系数法）。

**边缘检测匹配**：灰度化后使用 Canny 边缘检测（阈值 50/150），再在边缘图上做模板匹配。这种方法对光照变化更鲁棒。

**滑块比较**（带坑位）：计算两张图的像素差异 → 灰度化 → 固定阈值 30 二值化 → 形态学闭运算 + 开运算去噪 → 轮廓检测 → 取最大轮廓作为缺口位置。

```python
# ddddocr/core/slide_engine.py:162-173
diff = cv2.absdiff(target, background)
diff_gray = cv2.cvtColor(diff, cv2.COLOR_RGB2GRAY)
_, binary = cv2.threshold(diff_gray, 30, 255, cv2.THRESH_BINARY)
kernel = np.ones((3, 3), np.uint8)
binary = cv2.morphologyEx(binary, cv2.MORPH_CLOSE, kernel)
binary = cv2.morphologyEx(binary, cv2.MORPH_OPEN, kernel)
```

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

## 输入验证

所有图像输入在进入预处理之前都会经过 `validate_image_input()` 验证，确保类型在支持范围内。颜色过滤参数有专门的 `validate_color_filter_params()` 验证，检查 HSV 值范围（H: 0–180, S/V: 0–255）和结构正确性。

Sources: [ddddocr/utils/validators.py:15-31](ddddocr/utils/validators.py), [ddddocr/utils/validators.py:83-137](ddddocr/utils/validators.py)

## 总结

ddddocr 的图像预处理体系围绕三条引擎各自的特点设计。OCR 引擎追求固定高度、灵活宽度、单通道归一化输入；目标检测引擎追求固定正方形、三通道、YOLO 惯例的预处理；滑块引擎则完全基于传统图像处理（灰度化、边缘检测、形态学操作）。所有路径共享同一个图像加载层（`load_image_from_input`）和验证层（`validate_image_input`），确保格式兼容性的同时保持各引擎预处理的独立性。

---

## 06. 自定义模型与字符集

> 如何加载自己训练的 ONNX 模型和自定义字符集文件，突破内置模型的限制。

- Page Markdown: https://grok-wiki.com/public/wiki/sml2h3-ddddocr-a34dd45d9f63/pages/06-page-6.md
- Generated: 2026-06-23T07:40:11.393Z

### Source Files

- `ddddocr/models/model_loader.py`
- `ddddocr/models/charset_manager.py`
- `ddddocr/core/ocr_engine.py`
- `ddddocr/compat/v1.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/core/ocr_engine.py](ddddocr/core/ocr_engine.py)
- [ddddocr/compat/v1.py](ddddocr/compat/v1.py)
- [ddddocr/core/base.py](ddddocr/core/base.py)
</details>

# 自定义模型与字符集

ddddocr 内置了预训练的 OCR 模型和字符集，覆盖常见的中文验证码场景。但当你面对特殊字符集（如纯数字、纯字母、自定义符号）或需要更高识别精度时，加载自己训练的 ONNX 模型和配套字符集文件是突破内置限制的核心方式。本页介绍自定义模型与字符集的加载机制、字符集文件格式要求，以及加载后的预处理行为变化。

## 入口与参数

加载自定义模型有两个关键参数：`import_onnx_path`（ONNX 模型文件路径）和 `charsets_path`（字符集 JSON 文件路径）。当 `import_onnx_path` 非空时，引擎跳过内置模型，转而加载用户指定的模型和字符集。

通过兼容层 `DdddOcr` 类使用时，这两个参数直接传入构造函数：

```python
import ddddocr

ocr = ddddocr.DdddOcr(
    import_onnx_path="/path/to/custom.onnx",
    charsets_path="/path/to/charset.json"
)
result = ocr.classification(image_bytes)
```

Sources: [ddddocr/compat/v1.py:26-42]()、[ddddocr/compat/v1.py:77-87]()

当 `import_onnx_path` 非空时，即使 `ocr=False`，引擎也会初始化 OCR 功能（v1 兼容层中的 `ocr or import_onnx_path` 判断）。

Sources: [ddddocr/compat/v1.py:77]()

## 自定义模型加载流程

`OCREngine.initialize()` 根据 `use_import_onnx` 标志走两条不同的初始化路径：

```text
┌─────────────────────────────────────────────────────────┐
│                  OCREngine.initialize()                  │
├──────────────────────┬──────────────────────────────────┤
│  use_import_onnx     │  use_import_onnx = False         │
│  = True              │                                  │
├──────────────────────┼──────────────────────────────────┤
│ load_custom_model()  │ load_ocr_model(old/beta)         │
│ → ONNX session       │ → ONNX session                   │
│                      │                                  │
│ charset_info['charset│ load_default_charset(old/beta)   │
│ '] → charset         │ → 硬编码字符集                    │
│                      │                                  │
│ charset_info['word'] │ word = False                     │
│ → self.word          │                                  │
│                      │                                  │
│ charset_info['image']│ resize = [64, 64]                │
│ → self.resize        │                                  │
│                      │                                  │
│ charset_info['       │ channel = 1                      │
│ channel'] → channel  │                                  │
└──────────────────────┴──────────────────────────────────┘
```

Sources: [ddddocr/core/ocr_engine.py:56-97]()

`ModelLoader.load_custom_model()` 负责实际的文件加载工作。它先调用 `load_model()` 加载 ONNX 文件，再读取并验证字符集 JSON 文件，最后返回 `(session, charset_info)` 元组。

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

## 字符集 JSON 文件格式

自定义字符集文件必须是 UTF-8 编码的 JSON 文件，且包含以下四个必需字段：

| 字段 | 类型 | 说明 |
|------|------|------|
| `charset` | `List[str]` | 字符列表，索引 0 对应 CTC blank 字符（通常为空字符串 `""`） |
| `word` | `bool` | 是否为单词/词组模式，影响图像预处理的缩放策略 |
| `image` | `List[int]` | 目标图像尺寸 `[width, height]`，`-1` 表示自适应宽度 |
| `channel` | `int` | 图像通道数，`1` 为灰度，`3` 为 RGB |

字符集文件在两处被独立验证——`ModelLoader.load_custom_model()` 和 `CharsetManager.load_custom_charset()` 都会检查这四个必需字段是否存在。

Sources: [ddddocr/models/model_loader.py:196-199]()、[ddddocr/models/charset_manager.py:67-71]()

### 示例字符集文件

```json
{
  "charset": ["", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9"],
  "word": false,
  "image": [-1, 64],
  "channel": 1
}
```

这个示例定义了一个纯数字识别模型：字符集包含空字符（CTC blank）加 10 个数字，图像高度固定 64 像素、宽度自适应，灰度输入。

## 图像预处理差异

加载自定义模型后，图像预处理行为会根据字符集配置自动调整，主要体现在尺寸缩放和通道转换两方面：

**尺寸缩放**（由 `image` 和 `word` 字段共同控制）：

- `image[0] == -1` 且 `word == True`：按正方形缩放，边长为 `image[1]`
- `image[0] == -1` 且 `word == False`：高度固定为 `image[1]`，宽度按原始宽高比自适应
- `image[0] != -1`：强制缩放到 `image[0] × image[1]`

**通道转换**（由 `channel` 字段控制）：

- `channel == 1`：转换为灰度图
- `channel != 1`：保持原始通道（如 RGB 三通道）

Sources: [ddddocr/core/ocr_engine.py:182-197]()

相比之下，内置模型始终使用固定的 64 像素高度、按比例缩放宽度、灰度输入。

Sources: [ddddocr/core/ocr_engine.py:177-181]()

## CTC 解码与字符映射

模型输出经 CTC（Connectionist Temporal Classification）解码后，通过字符集索引映射为最终文本。解码过程分两步：

1. **索引级去重**：去除连续重复的预测索引，并跳过索引 0（blank 字符）
2. **字符映射**：将有效索引映射到字符集中的对应字符

```python
# CTC 解码核心逻辑
for idx in predicted_indices:
    idx = int(idx)
    if idx != prev_idx:      # 跳过连续重复
        if idx != 0:          # 跳过 blank（索引 0）
            decoded_indices.append(idx)
    prev_idx = idx
```

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

如果设置了字符集范围限制（`charset_range`），解码后还会过滤掉不在指定范围内的索引。

Sources: [ddddocr/core/ocr_engine.py:283-288]()

## 字符集范围限制

加载自定义模型后，仍然可以通过 `set_ranges()` 方法限制输出字符范围。支持三种传参方式：

| 参数类型 | 示例 | 行为 |
|----------|------|------|
| `int` | `set_ranges(10)` | 只使用字符集的前 11 个字符（索引 0-10） |
| `str` | `set_ranges("0123456789")` | 只输出字符串中包含的字符 |
| `List[str]` | `set_ranges(["0","1","2"])` | 只输出列表中指定的字符 |

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

范围限制在推理时生效，不会修改原始字符集，调用 `clear_ranges()` 可恢复完整字符集。

## GPU 支持

自定义模型同样支持 GPU 加速。在构造 `DdddOcr` 时设置 `use_gpu=True` 即可，ONNX Runtime 会自动选择 CUDA 执行提供者。如果 GPU 不可用，会自动回退到 CPU 模式。

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

## 常见问题

**Q：字符集文件缺少字段会怎样？**
会抛出 `ModelLoadError`，提示缺少的具体字段名。

**Q：`charset` 列表的第一个元素必须是空字符串吗？**
推荐是空字符串，因为 CTC 解码假设索引 0 为 blank 字符。如果你的模型训练时 blank 对应其他值，需要相应调整。

**Q：能否同时使用 `old`/`beta` 和自定义模型？**
不能。当 `import_onnx_path` 非空时，`old` 和 `beta` 参数被忽略，引擎直接使用自定义模型。

**Q：字符集大小必须和模型输出维度匹配吗？**
是的。`charset` 列表的长度应与模型最后一层的输出类别数一致，否则索引映射会产生错误结果。

## 总结

ddddocr 的自定义模型支持通过 `import_onnx_path` 和 `charsets_path` 两个参数实现。核心要求是提供一个符合格式的字符集 JSON 文件（包含 `charset`、`word`、`image`、`channel` 四个字段），以及一个与字符集匹配的 ONNX 模型。加载后，引擎会根据字符集配置自动调整图像预处理策略，通过 CTC 解码完成从模型输出到文本的映射。字符集范围限制功能在自定义模型下同样可用，可用于进一步约束输出空间。

---

## 07. 颜色过滤：只看你想看的颜色

> 在识别前用 HSV 颜色空间过滤干扰色，保留目标字符的颜色，提升识别准确率。

- Page Markdown: https://grok-wiki.com/public/wiki/sml2h3-ddddocr-a34dd45d9f63/pages/07-page-7.md
- Generated: 2026-06-23T07:34:55.439Z

### Source Files

- `ddddocr/preprocessing/color_filter.py`
- `ddddocr/core/ocr_engine.py`
- `ddddocr/utils/validators.py`

<details>
<summary>相关源文件</summary>
以下文件用于生成此维基页面：
- [ddddocr/preprocessing/color_filter.py](ddddocr/preprocessing/color_filter.py)
- [ddddocr/core/ocr_engine.py](ddddocr/core/ocr_engine.py)
- [ddddocr/utils/validators.py](ddddocr/utils/validators.py)
- [ddddocr/compat/v1.py](ddddocr/compat/v1.py)
- [ddddocr/api/models.py](ddddocr/api/models.py)
- [ddddocr/api/routes.py](ddddocr/api/routes.py)
- [ddddocr/api/mcp.py](ddddocr/api/mcp.py)
</details>

# 颜色过滤：只看你想看的颜色

验证码图片常常不是"干净"的黑字白底——背景里可能有彩色干扰线、噪点色块，或者字符本身被设计成特定颜色。颜色过滤功能让你在送入 OCR 识别**之前**，先把不想要的颜色"擦掉"，只留下目标字符的颜色。这样 OCR 模型看到的图片更干净，识别准确率自然更高。

这个功能基于 **HSV 颜色空间**工作。相比 RGB，HSV 把"颜色是什么"（H 色相）、"颜色有多鲜艳"（S 饱和度）、"颜色有多亮"（V 明度）拆成三个独立维度，更容易用数值范围来圈定一种颜色。

## 工作原理

颜色过滤发生在 OCR 识别流程的最前端。当你调用 `classification()` 或 `predict()` 时，如果传入了颜色过滤参数，引擎会先创建一个 `ColorFilter` 对象对图片做过滤，再把过滤后的图片交给模型。

```text
原始图片
  │
  ▼
ColorFilter.filter_image()
  │  1. RGB → BGR → HSV 转换
  │  2. 对每个颜色范围生成二值掩码
  │  3. 合并所有掩码（OR 运算）
  │  4. 用掩码保留目标像素，其余变白
  │
  ▼
干净图片 → OCR 模型推理
```

Sources: [ddddocr/core/ocr_engine.py:130-139]()，[ddddocr/preprocessing/color_filter.py:68-111]()

## 内置颜色预设

`ColorFilter` 类内置了 10 种常见颜色的 HSV 范围，开箱即用：

| 预设名称 | HSV 下界 (H, S, V) | HSV 上界 (H, S, V) | 说明 |
|---------|-------------------|-------------------|------|
| `red` | (0, 50, 50) | (10, 255, 255) | 红色需要**两段**范围（0-10 和 170-180），因为红色在色相环首尾 |
| `red` (续) | (170, 50, 50) | (180, 255, 255) | |
| `blue` | (100, 50, 50) | (130, 255, 255) | |
| `green` | (40, 50, 50) | (80, 255, 255) | |
| `yellow` | (20, 50, 50) | (40, 255, 255) | |
| `orange` | (10, 50, 50) | (20, 255, 255) | |
| `purple` | (130, 50, 50) | (170, 255, 255) | |
| `cyan` | (80, 50, 50) | (100, 255, 255) | |
| `black` | (0, 0, 0) | (180, 255, 50) | 低明度即可，不限色相 |
| `white` | (0, 0, 200) | (180, 30, 255) | 高明度、低饱和度 |
| `gray` | (0, 0, 50) | (180, 30, 200) | 低饱和度的中间明度 |

> **注意：** OpenCV 的 HSV 中 H 通道范围是 0-180（不是常见的 0-360），S 和 V 是 0-255。

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

## 两种使用方式

### 方式一：使用预设颜色名称

直接传入颜色名列表，最简单：

```python
import ddddocr

ocr = ddddocr.DdddOcr()
result = ocr.classification(
    img_bytes,
    color_filter_colors=['red', 'blue']  # 只保留红色和蓝色
)
```

### 方式二：自定义 HSV 范围

当预设颜色不够精确时，可以自己指定 HSV 范围。每个范围是一个 `((H下, S下, V下), (H上, S上, V上))` 的元组：

```python
result = ocr.classification(
    img_bytes,
    color_filter_custom_ranges=[
        ((0, 100, 100), (10, 255, 255)),   # 深红色范围
        ((170, 100, 100), (180, 255, 255))  # 深红色范围（色相环另一端）
    ]
)
```

两种方式可以混合使用，`ColorFilter` 会把所有范围合并成一张掩码。

Sources: [ddddocr/core/ocr_engine.py:99-103]()，[ddddocr/compat/v1.py:95-127]()

## 参数验证

所有颜色过滤参数在创建 `ColorFilter` 前都会经过 `validate_color_filter_params()` 验证：

- `colors` 必须是字符串列表，且每个名称必须在预设表中
- `custom_ranges` 中每个元素必须是两个三元组，H 值在 0-180，S/V 值在 0-255
- 每个范围的下界不能大于上界
- `colors` 和 `custom_ranges` 至少要提供一个

验证失败会抛出 `DDDDOCRError`。

Sources: [ddddocr/utils/validators.py:83-137]()

## 内部实现细节

### 掩码生成流程

`filter_image()` 的核心逻辑：

```python
# 1. 转换到 HSV
hsv = cv2.cvtColor(img_array, cv2.COLOR_BGR2HSV)

# 2. 对每个颜色范围生成掩码并合并
mask = np.zeros(hsv.shape[:2], dtype=np.uint8)
for lower, upper in self.hsv_ranges:
    range_mask = cv2.inRange(hsv, np.array(lower), np.array(upper))
    mask = cv2.bitwise_or(mask, range_mask)

# 3. 应用掩码：保留目标颜色，其余变白
result = cv2.bitwise_and(img_array, img_array, mask=mask)
result[mask == 0] = [255, 255, 255]
```

Sources: [ddddocr/preprocessing/color_filter.py:88-108]()

### 容错设计

颜色过滤失败不会导致整个 OCR 识别崩溃。在 `OCREngine.predict()` 中，颜色过滤被包裹在 `try/except` 中——如果过滤出错，会打印警告并跳过过滤步骤，直接用原图继续识别：

```python
try:
    color_filter = ColorFilter(colors=color_filter_colors, ...)
    pil_image = color_filter.filter_image(pil_image)
except Exception as e:
    print(f"颜色过滤警告: {str(e)}，将跳过颜色过滤步骤")
```

Sources: [ddddocr/core/ocr_engine.py:133-139]()

## API 接口

颜色过滤在 REST API 和 MCP 协议中均可使用。请求体中通过 `color_filter_colors` 和 `color_filter_custom_ranges` 字段传入：

```json
{
    "image": "<base64编码的图片>",
    "color_filter_colors": ["red"],
    "color_filter_custom_ranges": [[[0, 100, 100], [10, 255, 255]]]
}
```

Sources: [ddddocr/api/models.py:35-42]()，[ddddocr/api/routes.py:100-106]()，[ddddocr/api/mcp.py:56-60]()

## 动态管理颜色范围

`ColorFilter` 还提供了运行时管理方法，方便在不重新创建对象的情况下调整过滤规则：

| 方法 | 作用 |
|------|------|
| `add_color_range(lower, upper)` | 添加一个自定义 HSV 范围 |
| `add_preset_color(color)` | 添加一个预设颜色 |
| `clear_ranges()` | 清空所有颜色范围 |
| `get_ranges()` | 获取当前所有范围 |
| `get_available_colors()` | 列出所有可用预设颜色名 |
| `get_color_range(color)` | 查看某个预设颜色的 HSV 范围 |
| `get_mask(image)` | 只获取掩码，不应用过滤（用于调试） |

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

## 使用建议

1. **先观察图片**：用 `get_mask()` 看看掩码效果，确认目标字符被正确保留
2. **从预设开始**：先用内置颜色名试，不够精确再换自定义范围
3. **调整 S/V 阈值**：如果干扰色和目标色色相接近，可以通过提高 S（饱和度）下限来区分——鲜艳的目标字符 vs 暗淡的干扰线
4. **黑色/白色字符**：验证码中最常见的字符颜色，直接用 `'black'` 或 `'white'` 预设通常就够了

---

## 08. HTTP API 与 MCP 协议服务

> 通过 FastAPI 暴露 REST 接口，或通过 MCP 协议让 AI Agent 直接调用 ddddocr 能力。

- Page Markdown: https://grok-wiki.com/public/wiki/sml2h3-ddddocr-a34dd45d9f63/pages/08-http-api-mcp.md
- Generated: 2026-06-23T07:41:07.976Z

### Source Files

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

<details>
<summary>相关源文件</summary>
以下文件用于生成此维基页面：
- [ddddocr/api/app.py](ddddocr/api/app.py)
- [ddddocr/api/routes.py](ddddocr/api/routes.py)
- [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/__init__.py](ddddocr/api/__init__.py)
- [ddddocr/__main__.py](ddddocr/__main__.py)
</details>

# HTTP API 与 MCP 协议服务

ddddocr 提供两种方式让外部程序调用其验证码识别能力：一是通过 **FastAPI** 暴露的标准 REST API，二是通过 **MCP（Model Context Protocol）** 协议让 AI Agent 直接发现和调用工具。本页面介绍这两套服务的架构、接口和启动方式。

## 架构概览

项目中存在 **两套并行的 API 实现**，它们共享同一版本号（1.6.1），但设计思路不同：

| 实现 | 入口文件 | 特点 |
|------|----------|------|
| 直接模式 | `ddddocr/api/app.py` | 单文件内联所有路由，按配置键缓存多个 `DdddOcr` 实例，无需预初始化即可使用 |
| 服务模式 | `ddddocr/api/server.py` + `routes.py` + `mcp.py` | 分层架构：`DDDDDOCRService` 管理实例生命周期，路由工厂注册端点，`MCPHandler` 提供 MCP 协议支持 |

两种模式都通过 `ddddocr/api/__init__.py` 导出，最终由 `ddddocr/__main__.py` 的 `api` 子命令统一启动。

Sources: [ddddocr/api/__init__.py:1-14](), [ddddocr/__main__.py:52-69]()

## 启动方式

### 命令行启动

```bash
# 使用默认配置启动（0.0.0.0:8000）
python -m ddddocr api

# 自定义主机和端口
python -m ddddocr api --host 127.0.0.1 --port 9000

# 启用 GPU 加速和目标检测
python -m ddddocr api --use-gpu true --det true --device-id 0

# 使用旧版 OCR 模型
python -m ddddocr api --old true
```

CLI 会将所有参数写入环境变量（如 `DDDDOCR_HOST`、`DDDDOCR_PORT`），然后调用 `ddddocr.api.main()` 启动 uvicorn 服务器。

Sources: [ddddocr/__main__.py:18-69](), [ddddocr/api/app.py:743-754]()

### 环境变量配置

| 环境变量 | 默认值 | 说明 |
|----------|--------|------|
| `DDDDOCR_HOST` | `0.0.0.0` | 服务监听地址 |
| `DDDDOCR_PORT` | `8000` | 服务监听端口 |
| `DDDDOCR_WORKERS` | `1` | uvicorn 工作进程数 |
| `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` | `""` | 自定义字符集路径 |

Sources: [ddddocr/api/app.py:319-328](), [ddddocr/__main__.py:54-65]()

## REST API 端点（直接模式）

直接模式（`app.py`）提供以下端点，启动后即可直接调用，无需预初始化：

### 健康检查与配置

| 方法 | 路径 | 说明 |
|------|------|------|
| `GET` | `/health` | 健康检查，返回 `{"status": "ok"}` |
| `GET` | `/config` | 获取当前默认配置、活跃实例数和环境信息 |

### OCR 文字识别

| 方法 | 路径 | 说明 |
|------|------|------|
| `POST` | `/ocr` | JSON 方式提交 Base64 图片进行 OCR |
| `POST` | `/ocr/file` | 文件上传方式进行 OCR |

请求体示例（JSON 方式）：

```json
{
  "image": "<base64编码的图片>",
  "probability": false,
  "colors": [],
  "custom_color_ranges": null
}
```

OCR 端点支持通过查询参数动态选择模型配置：

```
POST /ocr?ocr=true&det=false&old=false&beta=false&use_gpu=false&device_id=0&show_ad=true
```

系统会根据这些参数自动生成配置键（如 `ocr=true-det=false-old=false-beta=false-gpu=false-dev=0`），并缓存对应的 `DdddOcr` 实例以供复用。空闲超过 3600 秒的实例会被自动清理。

Sources: [ddddocr/api/app.py:335-404](), [ddddocr/api/app.py:239-298]()

### 目标检测

| 方法 | 路径 | 说明 |
|------|------|------|
| `POST` | `/det` | JSON 方式提交图片进行目标检测 |
| `POST` | `/det/file` | 文件上传方式进行目标检测 |

返回检测到的边界框坐标列表。

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

### 滑块验证码

| 方法 | 路径 | 说明 |
|------|------|------|
| `POST` | `/slide_match` | 滑块匹配：根据滑块图和背景图计算偏移位置 |
| `POST` | `/slide_comparison` | 滑块比较：对比带坑位图片和完整背景图的差异 |

`slide_match` 请求体：

```json
{
  "target_image": "<base64>",
  "background_image": "<base64>",
  "simple_target": false,
  "flag": false
}
```

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

### 字符集配置

| 方法 | 路径 | 说明 |
|------|------|------|
| `POST` | `/set_charset_range` | 设置 OCR 识别的字符范围 |

Sources: [ddddocr/api/app.py:680-718]()

## REST API 端点（服务模式）

服务模式（`server.py` + `routes.py`）提供了更结构化的接口，需要先调用 `/initialize` 进行初始化：

| 方法 | 路径 | 说明 |
|------|------|------|
| `GET` | `/` | 首页，包含 API 文档链接 |
| `POST` | `/initialize` | 初始化服务，选择加载的模型类型 |
| `POST` | `/switch-model` | 运行时切换模型（支持 `ocr`、`ocr_old`、`ocr_beta`、`det`） |
| `POST` | `/toggle-feature` | 开启/关闭特定功能（`ocr`、`detection`、`color_filter`） |
| `POST` | `/ocr` | 执行 OCR 识别 |
| `POST` | `/detect` | 执行目标检测 |
| `POST` | `/slide-match` | 滑块匹配 |
| `POST` | `/slide-comparison` | 滑块比较 |
| `GET` | `/status` | 获取服务状态（已加载模型、已启用功能、运行时间） |
| `GET` | `/health` | 健康检查 |

服务模式的核心是 `DDDDDOCRService` 类，它管理三个独立的实例（`ocr_instance`、`det_instance`、`slide_instance`），并通过 `enabled_features` 集合控制功能开关。

Sources: [ddddocr/api/server.py:22-153](), [ddddocr/api/routes.py:17-219]()

## MCP 协议服务

MCP（Model Context Protocol）是一种让 AI Agent 发现和调用外部工具的协议。ddddocr 的 MCP 实现位于 `ddddocr/api/mcp.py`，挂载在 `/mcp` 前缀下。

### 端点

| 方法 | 路径 | 说明 |
|------|------|------|
| `GET` | `/mcp/` | 协议信息（版本、端点描述） |
| `GET` | `/mcp/capabilities` | 能力声明，返回可用工具列表及参数 schema |
| `POST` | `/mcp/call` | 调用指定工具 |

### 可用工具

AI Agent 通过 `/mcp/capabilities` 获取工具列表，然后通过 `/mcp/call` 调用：

| 工具名 | 功能 | 必需参数 |
|--------|------|----------|
| `ddddocr_initialize` | 初始化服务 | 无（可选 `ocr`、`det`、`old`、`beta`、`use_gpu`） |
| `ddddocr_ocr` | OCR 文字识别 | `image`（Base64） |
| `ddddocr_detection` | 目标检测 | `image`（Base64） |
| `ddddocr_slide_match` | 滑块匹配 | `target_image`、`background_image`（Base64） |
| `ddddocr_slide_comparison` | 滑块比较 | `target_image`、`background_image`（Base64） |
| `ddddocr_status` | 获取服务状态 | 无 |

### 调用示例

```json
// 请求：调用 OCR 工具
POST /mcp/call
{
  "method": "ddddocr_ocr",
  "params": {
    "image": "<base64编码的图片>",
    "probability": false
  },
  "id": "req-001"
}

// 响应
{
  "result": "识别结果文本",
  "error": null,
  "id": "req-001"
}
```

MCP 处理器内部会将 `method` 字段路由到对应的处理逻辑，复用 `DDDDDOCRService` 的实例管理能力。错误统一通过 `error` 字段返回，包含 `code`、`message` 和 `data`。

Sources: [ddddocr/api/mcp.py:17-227](), [ddddocr/api/models.py:97-117]()

## 数据模型

所有请求/响应模型均使用 Pydantic 定义，同时服务于 REST 和 MCP 两种协议：

| 模型 | 用途 |
|------|------|
| `InitializeRequest` | 服务初始化参数 |
| `SwitchModelRequest` | 模型切换参数 |
| `ToggleFeatureRequest` | 功能开关参数 |
| `OCRRequest` | OCR 识别请求 |
| `DetectionRequest` | 目标检测请求 |
| `SlideMatchRequest` | 滑块匹配请求 |
| `SlideComparisonRequest` | 滑块比较请求 |
| `APIResponse` | 统一 API 响应（`success` + `message` + `data`） |
| `StatusResponse` | 服务状态响应 |
| `MCPRequest` | MCP 工具调用请求（`method` + `params` + `id`） |
| `MCPResponse` | MCP 工具调用响应（`result` 或 `error`） |
| `MCPCapabilities` | MCP 能力声明（`tools` 列表） |

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

## API 文档

FastAPI 自动生成交互式 API 文档，启动后可访问：

- **Swagger UI**：`http://<host>:<port>/docs`
- **ReDoc**：`http://<host>:<port>/redoc`

CORS 中间件默认允许所有来源的跨域请求（`allow_origins=["*"]`）。

Sources: [ddddocr/api/app.py:301-316](), [ddddocr/api/server.py:170-198]()

## 总结

ddddocr 的 HTTP API 与 MCP 服务设计了两条路径来暴露相同的底层能力：REST API 适合传统的 Web 应用和自动化脚本集成，MCP 协议则让 AI Agent 能够自主发现和调用 OCR、目标检测、滑块匹配等工具。两套 API 实现（直接模式和服务模式）共存于 `ddddocr/api` 模块中，通过 `__main__.py` 的 `api` 子命令统一启动，用户可根据需求选择适合的调用方式。

---

## 09. 总结与下一步

> 回顾核心思想、最值得记住的一句话，以及推荐阅读路径。

- Page Markdown: https://grok-wiki.com/public/wiki/sml2h3-ddddocr-a34dd45d9f63/pages/09-page-9.md
- Generated: 2026-06-23T07:38:08.722Z

### Source Files

- `README.md`
- `ddddocr/__init__.py`
- `examples/basic_ocr.py`
- `examples/api_client.py`

<details>
<summary>相关源文件</summary>
以下文件用于生成此维基页面：
- [README.md](README.md)
- [ddddocr/__init__.py](ddddocr/__init__.py)
- [ddddocr/compat/v1.py](ddddocr/compat/v1.py)
- [ddddocr/core/base.py](ddddocr/core/base.py)
- [ddddocr/core/ocr_engine.py](ddddocr/core/ocr_engine.py)
- [ddddocr/preprocessing/color_filter.py](ddddocr/preprocessing/color_filter.py)
- [ddddocr/api/app.py](ddddocr/api/app.py)
- [pyproject.toml](pyproject.toml)
- [examples/basic_ocr.py](examples/basic_ocr.py)
- [examples/api_client.py](examples/api_client.py)
</details>

# 总结与下一步

本页回顾 DdddOcr 项目的核心设计思想、关键架构决策和最值得记住的实践经验，并为希望深入贡献或扩展的开发者提供推荐阅读路径。

## 核心思想回顾

### 设计理念：最简依赖

DdddOcr 的设计哲学是"最简依赖"——用最少的配置成本换取最大的验证码识别能力。用户只需一行 `pip install ddddocr` 和三行代码即可完成 OCR 识别，无需理解底层模型细节。

```python
import ddddocr
ocr = ddddocr.DdddOcr()
result = ocr.classification(image_bytes)
```

这种"开箱即用"的体验背后是精心设计的模块化架构：通过兼容层（`compat/v1.py`）对外暴露统一接口，内部则拆分为独立的引擎模块（OCR、目标检测、滑块匹配），每个引擎继承自 `BaseEngine` 抽象类。

Sources: [ddddocr/__init__.py:1-26](ddddocr/__init__.py), [ddddocr/compat/v1.py:18-284](ddddocr/compat/v1.py), [ddddocr/core/base.py:15-112](ddddocr/core/base.py)

### 三模式架构

项目围绕三种核心工作模式组织：

| 模式 | 初始化参数 | 核心引擎 | 典型场景 |
|------|-----------|----------|----------|
| OCR 识别 | `ocr=True`（默认） | `OCREngine` | 数字字母、中文验证码 |
| 目标检测 | `det=True` | `DetectionEngine` | 定位验证码在图片中的位置 |
| 滑块匹配 | `ocr=False, det=False` | `SlideEngine` | 滑块验证码缺口定位 |

这三种模式通过参数互斥规则避免冲突：`det=True` 会覆盖 `ocr=True`，`import_onnx_path` 会忽略 `ocr/det` 设置。

Sources: [ddddocr/compat/v1.py:73-93](ddddocr/compat/v1.py), [README.md:155-179](README.md)

## 最值得记住的一句话

**"初始化一次，复用多次"**——这是使用 DdddOcr 最重要的性能原则。模型加载是耗时操作，循环中反复初始化会严重拖慢程序。

```python
# 正确做法
ocr = ddddocr.DdddOcr()
for img in images:
    result = ocr.classification(img)

# 错误做法
for img in images:
    ocr = ddddocr.DdddOcr()  # 每次都重新加载模型
    result = ocr.classification(img)
```

Sources: [README.md:660-672](README.md)

## 架构全景

```text
┌─────────────────────────────────────────────────────────┐
│                     用户接口层                           │
│  ddddocr/__init__.py  →  compat/v1.py (DdddOcr 类)     │
├─────────────────────────────────────────────────────────┤
│                     引擎层 (core/)                       │
│  BaseEngine ← OCREngine / DetectionEngine / SlideEngine │
├─────────────────────────────────────────────────────────┤
│                   模型与预处理层                          │
│  models/ (model_loader, charset_manager)                │
│  preprocessing/ (image_processor, color_filter)         │
├─────────────────────────────────────────────────────────┤
│                   基础设施层                             │
│  utils/ (validators, exceptions, image_io, compat)      │
│  api/ (FastAPI 服务, routes, models, mcp)               │
└─────────────────────────────────────────────────────────┘
```

这种分层设计使得各模块可以独立测试和替换。例如，`OCREngine` 的 `predict` 方法内部依次调用：图像加载 → 颜色过滤 → 预处理 → ONNX 推理 → CTC 解码，每一步都有明确的输入输出边界。

Sources: [ddddocr/core/ocr_engine.py:99-157](ddddocr/core/ocr_engine.py), [ddddocr/preprocessing/color_filter.py:19-66](ddddocr/preprocessing/color_filter.py)

## 关键技术要点

### CTC 解码

OCR 引擎使用 CTC（Connectionist Temporal Classification）解码策略：在索引级别去除连续重复和 blank 字符，再映射到字符集。这是序列识别模型的标准后处理方式。

```python
# 核心解码逻辑
for idx in predicted_indices:
    if idx != prev_idx:      # 跳过连续重复
        if idx != 0:         # 跳过 blank（索引 0）
            decoded_indices.append(idx)
    prev_idx = idx
```

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

### 颜色过滤机制

颜色过滤基于 HSV 颜色空间，内置 10 种预设颜色（red、blue、green 等），也支持自定义 HSV 范围。过滤时创建掩码，保留目标颜色区域，其余设为白色背景。

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

### 输入校验与安全

项目在多个层面实施输入校验：

- **图片大小限制**：默认 8MB，可通过 `max_image_bytes` 自定义
- **图片尺寸限制**：最长边默认 4096px
- **格式校验**：支持 PNG/JPEG/JPG/WEBP/BMP/GIF/TIFF
- **Base64 校验**：API 层严格验证 Base64 编码合法性
- **类型检查**：公开方法校验布尔/整数参数类型

Sources: [pyproject.toml:1-52](pyproject.toml), [ddddocr/api/app.py:43-54](ddddocr/api/app.py)

## 实践经验速查

| 场景 | 推荐做法 | 避免 |
|------|---------|------|
| 批量识别 | 复用单个 `DdddOcr` 实例 | 循环中反复初始化 |
| 多线程并发 | 每线程独立实例 | 多线程共享同一实例 |
| 提高准确率 | `beta=True` + `set_ranges` + 颜色过滤 | 直接识别干扰严重的原图 |
| 透明 PNG | `png_fix=True` | 不处理直接识别 |
| 生产环境 API | `show_ad=False` + Docker 部署 | 默认广告配置 |
| 内存优化 | 按需初始化（OCR 或检测，不同时开） | 同时初始化多个不同功能实例 |

Sources: [README.md:536-610](README.md), [README.md:660-702](README.md)

## 推荐阅读路径

### 入门路径（新用户）

1. **README.md** → 了解安装、基本用法和功能概览
2. **examples/basic_ocr.py** → 运行第一个 OCR 示例
3. **examples/api_client.py** → 体验 API 服务调用

### 进阶路径（集成开发者）

1. **ddddocr/compat/v1.py** → 理解完整 API 接口和参数组合
2. **ddddocr/core/ocr_engine.py** → 理解 OCR 推理流程和 CTC 解码
3. **ddddocr/preprocessing/color_filter.py** → 掌握颜色过滤和自定义颜色范围
4. **ddddocr/api/app.py** → 部署和配置 API 服务

### 贡献路径（项目贡献者）

1. **ddddocr/core/base.py** → 理解引擎抽象基类设计
2. **ddddocr/models/model_loader.py** → 理解模型加载机制
3. **ddddocr/models/charset_manager.py** → 理解字符集管理
4. **ddddocr/utils/exceptions.py** → 理解错误处理体系
5. **dddd_trainer**（外部项目）→ 训练自定义模型

## 下一步行动建议

| 目标 | 行动 |
|------|------|
| 快速上手 | `pip install ddddocr`，运行 `examples/basic_ocr.py` |
| 部署 API 服务 | `python -m ddddocr api` 或使用 Docker Compose |
| 提升识别率 | 尝试 `beta=True`、颜色过滤、`set_ranges` 限定字符范围 |
| 训练自定义模型 | 使用 [dddd_trainer](https://github.com/sml2h3/dddd_trainer) |
| GPU 加速 | 安装 CUDA + `onnxruntime-gpu`，设置 `use_gpu=True` |
| 贡献代码 | Fork 仓库，阅读 `core/` 模块，从 issue 列表入手 |

## 项目快速档案

| 属性 | 值 |
|------|-----|
| 版本 | 1.6.1 |
| Python 要求 | ≥ 3.10 |
| 许可证 | MIT |
| 核心依赖 | numpy, onnxruntime, Pillow, opencv-python |
| 训练框架 | PyTorch（训练）+ ONNX Runtime（推理） |
| 支持平台 | Windows 64位、Linux 64/ARM64、macOS X64 |

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

---
