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

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

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

## Source Files

- `ddddocr/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'` 预设通常就够了
