Metadata-Version: 2.4
Name: ddddocr-1.6.1
Version: 1.6.1
Summary: 带带弟弟OCR
Author: sml2h3
License: The MIT License (MIT)
        Copyright © 2022 <copyright holders>
        
        Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
        
        The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
        
        THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Project-URL: Homepage, https://github.com/sml2h3/ddddocr
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: numpy
Requires-Dist: onnxruntime
Requires-Dist: Pillow
Requires-Dist: opencv-python; sys_platform == "win32" or sys_platform == "darwin"
Requires-Dist: opencv-python-headless; sys_platform == "linux"
Provides-Extra: api
Requires-Dist: fastapi>=0.68.0; extra == "api"
Requires-Dist: uvicorn>=0.15.0; extra == "api"
Requires-Dist: python-multipart>=0.0.5; extra == "api"
Requires-Dist: pydantic<3,>=1.8.0; extra == "api"
Dynamic: license-file

# DdddOcr - 通用验证码识别SDK

<p align="center">
  <img src="logo.png" alt="DdddOcr Logo" width="300">
</p>

<p align="center">
  <strong>一个简单易用的通用验证码识别Python库</strong>
</p>

## 目录

- [赞助合作商](#赞助合作商)
- [项目介绍](#项目介绍)
- [环境支持](#环境支持)
- [安装方法](#安装方法)
- [功能概览](#功能概览)
- [初始化参数详解](#初始化参数详解)
  - [参数详细说明](#参数详细说明)
  - [功能组合与冲突](#功能组合与冲突)
  - [模型选择指南](#模型选择指南)
  - [性能优化参数](#性能优化参数)
- [详细使用说明](#详细使用说明)
  - [文字识别功能](#文字识别功能)
    - [基础OCR识别](#基础ocr识别)
    - [OCR概率输出](#ocr概率输出)
    - [自定义字符范围](#自定义字符范围)
    - [颜色过滤功能](#颜色过滤功能)
  - [目标检测功能](#目标检测功能)
  - [滑块验证码处理](#滑块验证码处理)
    - [算法1：边缘匹配](#算法1边缘匹配)
    - [算法2：图像差异比较](#算法2图像差异比较)
  - [自定义模型导入](#自定义模型导入)
- [高级用法](#高级用法)
  - [批量处理](#批量处理)
  - [多线程优化](#多线程优化)
  - [验证码预处理](#验证码预处理)
- [常见问题](#常见问题)
  - [初始化速度慢](#初始化速度慢)
  - [识别准确率不高](#识别准确率不高)
  - [GPU加速](#gpu加速)
  - [处理复杂验证码](#如何处理复杂验证码)
  - [内存占用过高](#内存占用过高)
  - [参数冲突问题](#参数冲突问题)
  - [支持的图片格式](#支持的图片格式)
  - [多线程并发问题](#多线程并发问题)
- [项目技术支持](#项目技术支持)
- [使用示例](#使用示例)
- [许可证](#许可证)

## 赞助合作商

|                                                            | 赞助合作商 | 推荐理由                                                                                             |
|------------------------------------------------------------|------------|--------------------------------------------------------------------------------------------------|
| ![YesCaptcha](https://cdn.wenanzhe.com/img/yescaptcha.png) | [YesCaptcha](https://yescaptcha.com/i/NSwk7i) | 谷歌reCaptcha验证码 / hCaptcha验证码 / funCaptcha验证码商业级识别接口 [点我](https://yescaptcha.com/i/NSwk7i) 直达VIP4 |
| ![超级鹰](https://cdn.wenanzhe.com/img/logo.gif) | [超级鹰](https://www.chaojiying.com/) | 全球领先的智能图片分类及识别商家，安全、准确、高效、稳定、开放，强大的技术及校验团队，支持大并发。7*24h作业进度管理 |
| ![Malenia](https://cdn.wenanzhe.com/img/malenia.png!/scale/50)    | [Malenia](https://malenia.iinti.cn/malenia-doc/) | Malenia企业级代理IP网关平台/代理IP分销软件 |
| 雨云VPS    | [注册首月5折](https://www.rainyun.com/ddddocr_) | 浙江节点低价大带宽，100M每月30元 |

## 项目介绍

DdddOcr 是一个通用验证码离线本地识别SDK，由 [sml2h3](https://github.com/sml2h3) 与 [kerlomz](https://github.com/kerlomz) 共同开发完成。该项目通过大批量生成随机数据进行深度网络训练，可以识别各种类型的验证码，包括：

- 常见的数字字母组合验证码
- 中文验证码
- 滑块验证码
- 各种特殊字符验证码

项目设计理念是"最简依赖"，尽量减少用户的配置和使用成本，提供简单易用的API接口。

## 环境支持

| 系统 | CPU | GPU | 最大支持Python版本 | 备注 |
|-----|-----|-----|--------------|-----|
| Windows 64位 | ✓ | ✓ | 3.12 | 部分版本Windows需要安装[vc运行库](https://www.ghxi.com/yxkhj.html) |
| Linux 64 / ARM64 | ✓ | ✓ | 3.12 | |
| macOS X64 | ✓ | ✓ | 3.12 | M1/M2/M3芯片用户请参考[相关说明](https://github.com/sml2h3/ddddocr/issues/67) |

不支持的环境：
- Windows 32位
- Linux 32位

## 安装方法

### 从PyPI安装（推荐）

```bash
pip install ddddocr
```

### 从源码安装

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

### 安装 API 依赖（可选）

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

> **注意**：请勿直接在ddddocr项目的根目录内直接import ddddocr，请确保你的开发项目目录名称不为ddddocr。

## 功能概览

DdddOcr提供以下核心功能：

| 功能 | 描述 | 初始化参数 |
|-----|-----|----------|
| 文字识别 | 识别图片中的文字内容 | `ocr=True`（默认） |
| 目标检测 | 检测图片中的目标位置 | `det=True` |
| 滑块验证码识别 | 识别滑块验证码的缺口位置 | `ocr=False` |
| 自定义模型导入 | 导入自定义训练的模型 | `import_onnx_path="模型路径"` |

## 初始化参数详解

`DdddOcr` 类初始化时支持多种参数配置，以适应不同的使用场景：

```python
ddddocr.DdddOcr(
    ocr=True,           # 是否启用OCR功能
    det=False,          # 是否启用目标检测功能
    old=False,          # 是否使用旧版OCR模型
    beta=False,         # 是否使用Beta版OCR模型（新模型）
    use_gpu=False,      # 是否使用GPU加速
    device_id=0,        # 使用的GPU设备ID
    show_ad=True,       # 是否显示广告信息
    import_onnx_path="", # 自定义模型路径
    charsets_path="",    # 自定义字符集路径
    max_image_bytes=None, # 单图最大字节数（默认 8MB）
    max_image_side=None   # 单图最长边限制（默认 4096px）
)
```

### 参数详细说明

| 参数 | 类型 | 默认值 | 说明 |
|-----|-----|-----|-----|
| `ocr` | bool | True | 是否启用OCR功能，用于识别图片中的文字。**互斥性**：当`det=True`时会强制关闭OCR |
| `det` | bool | False | 是否启用目标检测功能，用于检测图片中的目标位置。**互斥性**：`det=True`会覆盖`ocr=True` |
| `old` | bool | False | 兼容参数，当前不会改变模型选择（默认即使用旧版模型） |
| `beta` | bool | False | 是否使用Beta版OCR模型（新模型），对某些验证码识别效果更好。**互斥性**：与`old=True`参数互斥（但`old`当前不生效） |
| `use_gpu` | bool | False | 是否使用GPU加速。**依赖关系**：需要安装CUDA和相应的onnxruntime-gpu版本，否则会初始化失败 |
| `device_id` | int | 0 | 使用的GPU设备ID。**依赖关系**：仅在`use_gpu=True`时生效，指定使用哪个GPU设备 |
| `show_ad` | bool | True | 是否在初始化时显示广告信息 |
| `import_onnx_path` | str | "" | 自定义模型的onnx文件路径。**依赖关系**：设置此参数时，`charsets_path`参数必须同时提供；此时`ocr/det`设置会被忽略 |
| `charsets_path` | str | "" | 自定义字符集的json文件路径。**依赖关系**：必须与`import_onnx_path`一起使用，否则无效 |
| `max_image_bytes` | int/str | 8MB | 单图最大字节数上限（入参可为 int 或数字字符串） |
| `max_image_side` | int/str | 4096 | 单图最长边像素上限（入参可为 int 或数字字符串） |

### 功能组合与冲突

根据参数组合，ddddocr具有不同的工作模式：

1. **标准OCR模式**：
   - 参数设置：`ocr=True, det=False`（默认）
   - 功能：识别图片中的文字

2. **目标检测模式**：
   - 参数设置：`ocr=False, det=True`
   - 功能：检测图片中的目标位置
   - 注意：同时设置`ocr=True, det=True`时，会进入目标检测模式（`det`优先）

3. **滑块识别模式**：
   - 参数设置：`ocr=False, det=False`
   - 功能：使用滑块匹配算法（需调用`slide_match`或`slide_comparison`方法）

4. **自定义模型模式**：
   - 参数设置：`import_onnx_path="模型路径", charsets_path="字符集路径"`
   - 功能：使用自定义训练的模型进行识别
   - 注意：设置此模式时，`ocr`和`det`参数会被忽略，且自定义字符集文件需包含 `charset/word/image/channel` 字段

5. **OCR模型选择**：
   - 默认模型：不设置特殊参数（当前使用 `common_old.onnx`）
   - Beta模型：`beta=True`（使用 `common.onnx`）
   - 旧版模型参数：`old=True`（当前不改变模型，仅为兼容保留）
   - 注意：`beta`和`old`参数互斥，但`old`当前不生效

### 模型选择指南

- **默认模型**：当前默认使用 `common_old.onnx`，适用于多数简单验证码场景
- **Beta模型**：`beta=True` 使用 `common.onnx`，对部分复杂验证码效果更好
- **自定义模型**：当默认模型无法满足需求时，可以通过[dddd_trainer](https://github.com/sml2h3/dddd_trainer)训练自己的模型

### 性能优化参数

- **GPU加速**：对于处理大量图片时，开启GPU加速可显著提升性能
  ```python
  ocr = ddddocr.DdddOcr(use_gpu=True, device_id=0)
  ```
  
- **GPU设备选择**：在多GPU环境中，可通过`device_id`指定使用的GPU
  ```python
  # 使用第二张GPU卡
  ocr = ddddocr.DdddOcr(use_gpu=True, device_id=1)
  ```

- **关闭广告显示**：在生产环境中可关闭广告提示
  ```python
  ocr = ddddocr.DdddOcr(show_ad=False)
  ```

## 详细使用说明

### 文字识别功能

#### 基础OCR识别

主要用于识别单行文字，如常见的英数验证码等。支持中文、英文、数字以及部分特殊字符的识别。

```python
import ddddocr

# 初始化OCR对象
ocr = ddddocr.DdddOcr()

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

# 识别图片
result = ocr.classification(image)
print(result)  # 输出识别结果
```

**OCR识别示例图片**

**参考例图**

包括且不限于以下图片

<img src="https://cdn.wenanzhe.com/img/20210715211733855.png" alt="captcha" width="150">
<img src="https://cdn.wenanzhe.com/img/78b7f57d-371d-4b65-afb2-d19608ae1892.png" alt="captcha" width="150">
<img src="https://cdn.wenanzhe.com/img/%E5%BE%AE%E4%BF%A1%E5%9B%BE%E7%89%87_20211226142305.png" alt="captcha" width="150">
<img src="https://cdn.wenanzhe.com/img/%E5%BE%AE%E4%BF%A1%E5%9B%BE%E7%89%87_20211226142325.png" alt="captcha" width="150">
<img src="https://cdn.wenanzhe.com/img/2AMLyA_fd83e1f1800e829033417ae6dd0e0ae0.png" alt="captcha" width="150">
<img src="https://cdn.wenanzhe.com/img/aabd_181ae81dd5526b8b89f987d1179266ce.jpg" alt="captcha" width="150">
<br />
<img src="https://cdn.wenanzhe.com/img/2bghz_b504e9f9de1ed7070102d21c6481e0cf.png" alt="captcha" width="150">
<img src="https://cdn.wenanzhe.com/img/0000_z4ecc2p65rxc610x.jpg" alt="captcha" width="150">
<img src="https://cdn.wenanzhe.com/img/2acd_0586b6b36858a4e8a9939db8a7ec07b7.jpg" alt="captcha" width="150">
<img src="https://cdn.wenanzhe.com/img/2a8r_79074e311d573d31e1630978fe04b990.jpg" alt="captcha" width="150">
<img src="https://cdn.wenanzhe.com/img/aftf_C2vHZlk8540y3qAmCM.bmp" alt="captcha" width="150">
<img src="https://cdn.wenanzhe.com/img/%E5%BE%AE%E4%BF%A1%E6%88%AA%E5%9B%BE_20211226144057.png" alt="captcha" width="150">

**OCR模型选择**

DdddOcr内置两套OCR模型，可以通过`beta`参数切换：

```python
# 使用第二套OCR模型
ocr = ddddocr.DdddOcr(beta=True)
```

**透明PNG图片处理**

对于透明黑色PNG图片，可以使用`png_fix`参数（对所有 OCR 模式生效）：

```python
result = ocr.classification(image, png_fix=True)
```

> **注意**：`png_fix` 仅对带透明通道的图片生效；初始化DdddOcr对象只需要一次，不要在每次识别时都重新初始化，这会导致速度变慢。

#### OCR概率输出

可以获取OCR识别结果的概率分布，便于进行更灵活的结果处理：

```python
import ddddocr

ocr = ddddocr.DdddOcr()
image = open("test.jpg", "rb").read()

# 获取识别结果的概率分布
result = ocr.classification(image, probability=True)

# 处理概率结果
s = ""
for i in result['probability']:
    s += result['charsets'][i.index(max(i))]

print(s)
```

**概率输出示例**（仅对内置模型生效，自定义模型会忽略`probability=True`并直接返回字符串）：

```python
# 概率输出结果示例
{
    'charsets': ['', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', ...],
    'probability': [
        [0.01, 0.02, 0.01, 0.03, 0.02, 0.01, 0.02, 0.75, 0.03, 0.05, 0.01, ...],  # 第一个字符的概率分布
        [0.01, 0.01, 0.02, 0.01, 0.03, 0.02, 0.01, 0.02, 0.01, 0.80, 0.01, ...],  # 第二个字符的概率分布
        ...
    ]
}
```

#### 自定义字符范围

可以通过`set_ranges`方法限定OCR识别的字符范围：

```python
import ddddocr

ocr = ddddocr.DdddOcr()
image = open("test.jpg", "rb").read()

# 设置识别范围为数字
ocr.set_ranges(0)  # 等同于 ocr.set_ranges("0123456789")

# 或自定义字符范围
ocr.set_ranges("0123456789+-x/=")

result = ocr.classification(image)
print(result)
```

**内置字符范围参数**：

| 参数值 | 含义 |
|-----|-----|
| 0 | 纯数字 0-9 |
| 1 | 纯小写英文 a-z |
| 2 | 纯大写英文 A-Z |
| 3 | 小写英文 + 大写英文 |
| 4 | 小写英文 + 数字 |
| 5 | 大写英文 + 数字 |
| 6 | 小写英文 + 大写英文 + 数字 |
| 7 | 默认字符库 - 小写英文 - 大写英文 - 数字 |

#### 颜色过滤功能

对于一些特殊的验证码，可以通过颜色过滤来提高识别准确率：

```python
import ddddocr

ocr = ddddocr.DdddOcr()
image = open("test.jpg", "rb").read()

# 只保留红色和蓝色部分
result = ocr.classification(image, colors=["red", "blue"])
print(result)
```

**支持的颜色**：
- red (红色)
- green (绿色)
- blue (蓝色)
- yellow (黄色)
- orange (橙色)
- purple (紫色)
- pink (粉色)
- brown (棕色)

也可以自定义颜色范围：

```python
# 自定义颜色范围
custom_ranges = {
    'light_blue': [(90, 30, 30), (110, 255, 255)]  # HSV颜色空间
}

result = ocr.classification(image, colors=["light_blue"], custom_color_ranges=custom_ranges)
```

> **提示**：`custom_color_ranges` 只有在 `colors` 列表包含对应键名时才会生效。

### 目标检测功能

用于检测图像中可能的目标主体位置，返回目标的边界框坐标：

```python
import ddddocr
import cv2

# 初始化检测对象
det = ddddocr.DdddOcr(det=True, ocr=False)

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

# 检测目标
bboxes = det.detection(image)
print(bboxes)  # 输出格式：[[x1, y1, x2, y2], ...]

# 可视化检测结果
im = cv2.imread("test.jpg")
for bbox in bboxes:
    x1, y1, x2, y2 = bbox
    im = cv2.rectangle(im, (x1, y1), (x2, y2), color=(0, 0, 255), thickness=2)
cv2.imwrite("result.jpg", im)
```

**目标检测示例**：

**参考例图**

包括且不限于以下图片

<img src="https://cdn.wenanzhe.com/img/page1_1.jpg" alt="captcha" width="200">
<img src="https://cdn.wenanzhe.com/img/page1_2.jpg" alt="captcha" width="200">
<img src="https://cdn.wenanzhe.com/img/page1_3.jpg" alt="captcha" width="200">
<img src="https://cdn.wenanzhe.com/img/page1_4.jpg" alt="captcha" width="200">
<br />
<img src="https://cdn.wenanzhe.com/img/result.jpg" alt="captcha" width="200">
<img src="https://cdn.wenanzhe.com/img/result2.jpg" alt="captcha" width="200">
<img src="https://cdn.wenanzhe.com/img/result4.jpg" alt="captcha" width="200">
### 滑块验证码处理

DdddOcr提供两种滑块验证码处理算法：

#### 算法1：边缘匹配

适用于有透明背景的滑块图片，通过边缘检测找到滑块在背景图中的位置：

```python
import ddddocr

# 初始化滑块检测对象
slide = ddddocr.DdddOcr(det=False, ocr=False)

# 读取滑块图和背景图
with open('target.png', 'rb') as f:
    target_bytes = f.read()

with open('background.png', 'rb') as f:
    background_bytes = f.read()

# 匹配位置
res = slide.slide_match(target_bytes, background_bytes)
print(f"滑块位置: {res}")

# 可视化结果
background = cv2.imdecode(np.frombuffer(background_bytes, np.uint8), cv2.IMREAD_COLOR)
x1, y1, x2, y2 = res["target"]

# 在背景图上绘制匹配位置
cv2.rectangle(background, (x1, y1), (x2, y2), (0, 255, 0), 2)

# 显示结果
plt.figure(figsize=(10, 6))
plt.imshow(cv2.cvtColor(background, cv2.COLOR_BGR2RGB))
plt.title("滑块匹配结果")
plt.axis('off')
plt.savefig("slide_result.jpg")
plt.show()
```

**滑块匹配示例**：

<table>
  <tr>
    <td align="center">
      <img src="https://cdn.wenanzhe.com/img/b.png" width="50"/><br/>
      <strong>滑块图</strong>
    </td>
    <td align="center">
      <img src="https://cdn.wenanzhe.com/img/a.png" width="300"/><br/>
      <strong>背景图</strong>
    </td>
  </tr>
</table>

对于没有透明背景的滑块图，可以使用`simple_target`参数：

```python
res = slide.slide_match(target_bytes, background_bytes, simple_target=True)
```

#### 算法2：图像差异比较

适用于比较两张图片的不同之处，找出滑块缺口位置：

```python
import ddddocr

slide = ddddocr.DdddOcr(det=False, ocr=False)

# 读取带有缺口阴影的图片和完整图片
with open('bg.jpg', 'rb') as f:
    target_bytes = f.read()

with open('fullpage.jpg', 'rb') as f:
    background_bytes = f.read()

# 比较差异
res = slide.slide_comparison(target_bytes, background_bytes)
print(res)  # 输出格式：{"target": [x, y]}
```

**图像差异比较示例**：

<table>
  <tr>
    <td align="center">
      <img src="https://cdn.wenanzhe.com/img/bg.jpg" width="300"/><br/>
      <strong>带缺口阴影的图片</strong>
    </td>
    <td align="center">
      <img src="https://cdn.wenanzhe.com/img/fullpage.jpg" width="300"/><br/>
      <strong>完整图片</strong>
    </td>
  </tr>
</table>

### 自定义模型导入

DdddOcr支持导入通过[dddd_trainer](https://github.com/sml2h3/dddd_trainer)训练的自定义模型：

```python
import ddddocr

# 导入自定义模型
ocr = ddddocr.DdddOcr(
    det=False, 
    ocr=False, 
    import_onnx_path="mymodel.onnx", 
    charsets_path="charsets.json"
)

with open('test.jpg', 'rb') as f:
    image_bytes = f.read()

res = ocr.classification(image_bytes)
print(res)
```

## 高级用法

### 批量处理

对大量验证码进行批量处理时，保持OCR实例的复用可以显著提高效率：

```python
import ddddocr
import os
import time

# 初始化OCR对象（只需一次）
ocr = ddddocr.DdddOcr()

# 批量处理目录中的所有图片
def batch_process(directory):
    results = {}
    
    start_time = time.time()
    for filename in os.listdir(directory):
        if filename.endswith(('.png', '.jpg', '.jpeg', '.bmp')):
            file_path = os.path.join(directory, filename)
            
            with open(file_path, 'rb') as f:
                image = f.read()
                
            # 使用同一个OCR实例处理所有图片
            result = ocr.classification(image)
            results[filename] = result
    
    end_time = time.time()
    print(f"处理 {len(results)} 张图片耗时: {end_time - start_time:.2f} 秒")
    return results

# 使用示例
results = batch_process("./captchas/")
for filename, text in results.items():
    print(f"{filename}: {text}")
```

### 多线程优化

在多线程环境下使用时，应当为每个线程创建独立的OCR实例：

```python
import ddddocr
import concurrent.futures
import os

def process_image(file_path):
    # 每个线程创建自己的OCR实例
    ocr = ddddocr.DdddOcr()
    
    with open(file_path, 'rb') as f:
        image = f.read()
    
    result = ocr.classification(image)
    return os.path.basename(file_path), result

def parallel_process(directory, max_workers=4):
    file_paths = [os.path.join(directory, f) for f in os.listdir(directory) 
                 if f.endswith(('.png', '.jpg', '.jpeg', '.bmp'))]
    
    results = {}
    with concurrent.futures.ThreadPoolExecutor(max_workers=max_workers) as executor:
        future_to_file = {executor.submit(process_image, file_path): file_path for file_path in file_paths}
        
        for future in concurrent.futures.as_completed(future_to_file):
            filename, result = future.result()
            results[filename] = result
    
    return results

# 使用示例
results = parallel_process("./captchas/", max_workers=8)
```

### 验证码预处理

对于干扰较多的验证码，可以先进行预处理再识别：

```python
import ddddocr
import cv2
import numpy as np
from PIL import Image
import io

def preprocess_captcha(image_bytes):
    # 转换为OpenCV格式
    nparr = np.frombuffer(image_bytes, np.uint8)
    img = cv2.imdecode(nparr, cv2.IMREAD_COLOR)
    
    # 灰度化
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    
    # 二值化
    _, binary = cv2.threshold(gray, 150, 255, cv2.THRESH_BINARY_INV)
    
    # 去除小噪点
    kernel = np.ones((2, 2), np.uint8)
    opening = cv2.morphologyEx(binary, cv2.MORPH_OPEN, kernel)
    
    # 转回字节流
    is_success, buffer = cv2.imencode(".jpg", opening)
    processed_bytes = io.BytesIO(buffer).getvalue()
    
    return processed_bytes

# 使用示例
ocr = ddddocr.DdddOcr()

with open("noisy_captcha.jpg", "rb") as f:
    image_bytes = f.read()

# 预处理验证码
processed_bytes = preprocess_captcha(image_bytes)

# 识别处理后的图片
result = ocr.classification(processed_bytes)
print(f"验证码识别结果: {result}")
```

## 常见问题

1. **初始化速度慢**  
   首次初始化DdddOcr对象时会加载模型，可能会比较慢，但只需要初始化一次即可。避免在循环中反复初始化。
   ```python
   # 错误的用法
   for img in images:
       ocr = ddddocr.DdddOcr()  # 每次都初始化，严重影响性能
       result = ocr.classification(img)
   
   # 正确的用法
   ocr = ddddocr.DdddOcr()  # 只初始化一次
   for img in images:
       result = ocr.classification(img)
   ```

2. **识别准确率不高**  
   - 尝试使用另一个OCR模型（设置`beta=True`）
   - 对于特殊验证码，尝试使用颜色过滤功能
   - 限定识别字符范围（使用`set_ranges`方法）
   - 对于透明PNG图片，使用`png_fix=True`参数

3. **GPU加速**  
   可以通过设置`use_gpu=True`和`device_id`参数来启用GPU加速：
   ```python
   ocr = ddddocr.DdddOcr(use_gpu=True, device_id=0)
   ```
   使用GPU需确保已安装对应的CUDA版本和onnxruntime-gpu库。

4. **如何处理复杂验证码**  
   对于复杂的验证码，可以尝试以下步骤：
   - 先使用目标检测功能定位验证码位置
   - 对检测到的区域进行裁剪
   - 应用颜色过滤去除干扰
   - 使用OCR识别处理后的图片

5. **内存占用过高**  
   如果在同一程序中需要使用多个功能，建议不要同时初始化多个不同功能的实例，而是根据需要初始化：
   ```python
   # 根据需要初始化不同的对象
   if need_ocr:
       processor = ddddocr.DdddOcr(ocr=True, det=False)
   elif need_detection:
       processor = ddddocr.DdddOcr(ocr=False, det=True)
   ```

6. **参数冲突问题**  
   当同时设置多个模式参数时，需注意优先级：
   - `ocr=True`和`det=True`同时设置时，优先使用目标检测模式
   - `beta=True`和`old=True`同时设置时，使用Beta模型（`old`当前不生效）
   - 设置`import_onnx_path`时，`ocr`和`det`参数会被忽略

7. **支持的图片格式**  
   ddddocr支持多种图片格式：
   - JPG/JPEG
   - PNG (带透明通道时可配合`png_fix=True`)
   - BMP
   - GIF (仅识别第一帧)
   
   对于不常见格式或Base64编码的图片，可以先转换为bytes：
   ```python
   # Base64编码图片处理
   import base64
   image_bytes = base64.b64decode(base64_str)
   result = ocr.classification(image_bytes)
   ```

8. **多线程并发问题**  
   在多线程环境下使用时，每个线程应当创建独立的OCR实例，否则可能导致识别结果错乱。

## 项目技术支持

本项目基于[dddd_trainer](https://github.com/sml2h3/dddd_trainer)训练所得，训练底层框架为PyTorch，推理底层依赖于[onnxruntime](https://pypi.org/project/onnxruntime/)。

## 使用示例

### 完整的验证码识别流程

```python
import ddddocr
import cv2
import numpy as np
from PIL import Image
import io

# 初始化OCR对象
ocr = ddddocr.DdddOcr()

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

# 转换为OpenCV格式进行预处理
# img = cv2.imdecode(np.frombuffer(image_bytes, np.uint8), cv2.IMREAD_COLOR)

# 预处理：灰度化、二值化等
# gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# _, binary = cv2.threshold(gray, 150, 255, cv2.THRESH_BINARY_INV)

# 转回字节流
# is_success, buffer = cv2.imencode(".jpg", binary)
# processed_bytes = io.BytesIO(buffer).getvalue()

# 识别处理后的图片
result = ocr.classification(image_bytes)
print(f"验证码识别结果: {result}")
```

### 滑块验证码完整示例

```python
import ddddocr
import cv2
import numpy as np
import matplotlib.pyplot as plt

# 初始化滑块检测对象
slide = ddddocr.DdddOcr(det=False, ocr=False)

# 读取滑块图和背景图
with open('target.png', 'rb') as f:
    target_bytes = f.read()

with open('background.png', 'rb') as f:
    background_bytes = f.read()

# 匹配位置
res = slide.slide_match(target_bytes, background_bytes)
print(f"滑块位置: {res}")

# 可视化结果
background = cv2.imdecode(np.frombuffer(background_bytes, np.uint8), cv2.IMREAD_COLOR)
x1, y1, x2, y2 = res["target"]

# 在背景图上绘制匹配位置
cv2.rectangle(background, (x1, y1), (x2, y2), (0, 255, 0), 2)

# 显示结果
plt.figure(figsize=(10, 6))
plt.imshow(cv2.cvtColor(background, cv2.COLOR_BGR2RGB))
plt.title("滑块匹配结果")
plt.axis('off')
plt.savefig("slide_result.jpg")
plt.show()
```

## API 服务

DdddOcr 提供了一键启动 API 服务的功能，可以通过 RESTful API 的方式访问 DdddOcr 的所有功能。

### 命令行启动 API 服务

```bash
# 使用默认配置启动 API 服务
python -m ddddocr api

# 指定 API 服务配置
python -m ddddocr api --host 0.0.0.0 --port 8000 --workers 4

# 配置 OCR 功能
python -m ddddocr api --ocr true --beta true

# 配置目标检测功能
python -m ddddocr api --ocr false --det true
```

> **提示**：如果直接运行 `python -m ddddocr.api`，默认会绑定在 `127.0.0.1`，可通过环境变量 `DDDDOCR_HOST` 覆盖。

### API 命令行参数说明

| 参数名 | 类型 | 默认值 | 说明 |
|-------|------|-------|------|
| `--host` | 字符串 | 0.0.0.0 | API 服务主机地址（`python -m ddddocr api` 默认） |
| `--port` | 整数 | 8000 | API 服务端口 |
| `--workers` | 整数 | 1 | API 服务工作进程数 |
| `--ocr` | 布尔值 | true | 是否启用 OCR 功能 |
| `--det` | 布尔值 | false | 是否启用目标检测功能 |
| `--old` | 布尔值 | false | 是否使用旧版 OCR 模型 |
| `--beta` | 布尔值 | false | 是否使用 Beta 版 OCR 模型 |
| `--use-gpu` | 布尔值 | false | 是否使用 GPU 加速 |
| `--device-id` | 整数 | 0 | GPU 设备 ID |
| `--show-ad` | 布尔值 | true | 是否显示广告 |
| `--import-onnx-path` | 字符串 | "" | 自定义模型路径 |
| `--charsets-path` | 字符串 | "" | 自定义字符集路径 |

### 使用 Docker 运行 API 服务

#### 构建并运行 Docker 镜像

```bash
# 构建 Docker 镜像
docker build -t ddddocr-api .

# 运行 Docker 容器
docker run -d --name ddddocr-api -p 8000:8000 ddddocr-api

# 使用自定义配置运行
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 运行 API 服务

```bash
# 使用默认配置启动
docker-compose up -d

# 使用自定义配置启动
DDDDOCR_OCR=true DDDDOCR_BETA=true DDDDOCR_WORKERS=4 docker-compose up -d
```

### API 接口说明

API 服务提供了以下接口：

#### 1. 文字识别接口 (OCR)

```
POST /ocr
```

请求体：

```json
{
  "image": "图片的Base64编码字符串",
  "probability": false,
  "colors": [],
  "custom_color_ranges": null
}
```

响应：

```json
{
  "result": "识别到的文字",
  "processing_time": 0.123
}
```

> **注意**：当 `probability=true` 时，API 会返回 `result` 为一个字典，包含 `charsets` 与 `probability` 字段，结构与本地 `classification(probability=True)` 一致。

#### 2. 目标检测接口

```
POST /det
```

请求体：

```json
{
  "image": "图片的Base64编码字符串"
}
```

响应：

```json
{
  "result": [
    [x1, y1, x2, y2],
    ...
  ],
  "processing_time": 0.123
}
```

#### 3. 滑块匹配接口

```
POST /slide_match
```

请求体：

```json
{
  "target_image": "目标图片的Base64编码字符串",
  "background_image": "背景图片的Base64编码字符串",
  "simple_target": false,
  "flag": false
}
```

响应：

```json
{
  "result": {
    "target_x": 0,
    "target_y": 0,
    "target": [x1, y1, x2, y2]
  },
  "processing_time": 0.123
}
```

#### 4. 滑块比较接口

```
POST /slide_comparison
```

请求体：

```json
{
  "target_image": "目标图片的Base64编码字符串",
  "background_image": "背景图片的Base64编码字符串"
}
```

响应：

```json
{
  "result": {
    "target": [x, y]
  },
  "processing_time": 0.123
}
```

#### 5. 设置字符范围接口

```
POST /set_charset_range
```

请求体：

```json
{
  "charset_range": ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"]
}
```

响应：

```json
{
  "result": "字符范围设置成功",
  "charset_range": ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"],
  "processing_time": 0.123
}
```


#### 6. 健康检查接口

```
GET /health
```

响应：

```json
{
  "status": "ok",
  "timestamp": 1628765432.1234
}
```

#### 文件上传接口

所有上述接口都支持通过表单上传文件的方式提交请求。例如：

```
POST /ocr/file
```

可以通过表单字段上传图片文件。

### API 客户端示例

#### Python 示例 (Base64编码方式)

```python
import requests
import base64

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

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

# 处理响应
result = response.json()
print(f"识别结果: {result['result']}")
```

#### Python 示例 (文件上传方式)

```python
import requests

# 准备文件
files = {"file": open("captcha.png", "rb")}

# 发送OCR请求
url = "http://localhost:8000/ocr/file"
response = requests.post(url, files=files)

# 处理响应
result = response.json()
print(f"识别结果: {result['result']}")
```

### Docker 环境变量配置参考

| 环境变量名 | 默认值 | 说明 |
|-----------|-------|------|
| `DDDDOCR_HOST` | 0.0.0.0（CLI 默认）/ 127.0.0.1（直接运行 api.py 默认） | API 服务主机地址 |
| `DDDDOCR_PORT` | 8000 | API 服务端口 |
| `DDDDOCR_WORKERS` | 1 | API 服务工作进程数 |
| `DDDDOCR_OCR` | true | 是否启用 OCR 功能 |
| `DDDDOCR_DET` | false | 是否启用目标检测功能 |
| `DDDDOCR_OLD` | false | 是否使用旧版 OCR 模型 |
| `DDDDOCR_BETA` | false | 是否使用 Beta 版 OCR 模型 |
| `DDDDOCR_USE_GPU` | false | 是否使用 GPU 加速 |
| `DDDDOCR_DEVICE_ID` | 0 | GPU 设备 ID |
| `DDDDOCR_SHOW_AD` | true | 是否显示广告 |
| `DDDDOCR_IMPORT_ONNX_PATH` | "" | 自定义模型路径 |
| `DDDDOCR_CHARSETS_PATH` | "" | 自定义字符集路径 |

## 许可证

本项目采用MIT许可证，详情请参阅[LICENSE](https://github.com/sml2h3/ddddocr/blob/master/LICENSE)文件。 
## 输入与输出校验说明

- **图片合法性**：所有 Base64 与文件上传都会做尺寸、格式与大小校验（默认上限 8192 KB、最长边 4096px，可在实例化 `DdddOcr(max_image_bytes=..., max_image_side=...)` 时自定义），异常时返回 400。
- **允许格式**：PNG / JPEG / JPG / WEBP / BMP / GIF / TIFF。
- **输入类型**：本地调用支持 `bytes/bytearray`、Base64 字符串、文件路径或 `PIL.Image`。
- **类型约束**：`DdddOcr` 的公开方法会校验布尔/整数参数，`FastAPI` 层也通过 Pydantic 验证请求体，错误会带具体字段。
- **统一异常**：核心库新增 `DdddOcrInputError` / `InvalidImageError`，API 会把这些异常映射为 400，方便调用方处理。
- **响应结构**：HTTP 接口现有明确的 `response_model`，文档 (`/docs`) 中可直接查看字段含义。
- **模式提示**：在 `det=True` 模式下调用 `classification` 会抛出 “当前识别类型为目标检测”。

## 示例库

仓库新增 `examples/` 目录，覆盖本地调用、目标检测和 HTTP 客户端等典型场景：

- `basic_ocr.py`：最小 OCR 示例，可演示概率输出与颜色过滤。
- `detector.py`：演示如何用 `det=True` 模式返回所有检测框。
- `api_client.py`：演示如何向 `python -m ddddocr api` 服务发送 JSON 请求。
- `generate_basic_ocr_cases.py`：生成基础 OCR 测试用例图片。

详细说明见 `examples/README.md`，可结合 README 其他章节快速起步。
