# 滑块验证码匹配引擎

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

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

## Source Files

- `ddddocr/core/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]()
