# 模板像素差分分析法

当没有视觉模型时，用 Pillow 对比模板图和干净底板，精确定位文字位置。

## 原理

模板图（含文字）− 干净底板 = 差异像素 = 文字精确位置。

## 脚本

```python
from PIL import Image
import numpy as np

bg = np.array(Image.open('小红书封面.jpeg').convert('RGB'))
tmpl = np.array(Image.open('小红书封面模板.png').convert('RGB'))

H, W = bg.shape[:2]
diff = np.abs(bg.astype(int) - tmpl.astype(int))
diff_gray = diff.max(axis=2)  # 每像素最大通道差异

# 行活动度：每行有多少像素与底板不同
threshold = 30
row_activity = (diff_gray > threshold).mean(axis=1)

# 找连续的有差异的行 → 文字区块
text_rows = [(y, row_activity[y]) for y in range(H) if row_activity[y] > 0.01]

# 分组连续行
groups = []
current = [text_rows[0]]
for i in range(1, len(text_rows)):
    if text_rows[i][0] - text_rows[i-1][0] <= 3:
        current.append(text_rows[i])
    else:
        groups.append(current)
        current = [text_rows[i]]
groups.append(current)

for i, g in enumerate(groups):
    y_start, y_end = g[0][0], g[-1][0]
    # 水平范围
    block = diff_gray[y_start:y_end+1, :]
    col_act = (block > threshold).mean(axis=0)
    active_cols = np.where(col_act > 0.005)[0]
    if len(active_cols):
        x_start, x_end = active_cols[0], active_cols[-1]
        cx = (x_start + x_end) // 2
        print(f"区块{i+1}: y={y_start}-{y_end} (高{y_end-y_start}px) "
              f"x={x_start}-{x_end} 中心偏移{cx - W//2:+d}px")
```

## 颜色检测

分别用白色/橙色掩码定位不同颜色文字：

```python
# 白色文字
white = (tmpl[:,:,0] > 200) & (tmpl[:,:,1] > 200) & (tmpl[:,:,2] > 200)

# 橙色文字 (R>200, 100<G<180, B<80)
orange = (tmpl[:,:,0] > 200) & (tmpl[:,:,1] > 100) & (tmpl[:,:,1] < 180) & (tmpl[:,:,2] < 80)
```

## 字体大小估算

用 Pillow 不同字号渲染已知文字，对比实际像素高度：

```python
from PIL import ImageFont
font = ImageFont.truetype('YouSheBiaoTiHei-2.ttf', size)
bbox = font.getbbox('测试文字')
pixel_height = bbox[3] - bbox[1]
# 调节 size 直到 pixel_height ≈ 模板文字高度
```

## 注意事项

- 反锯齿边缘可能导致测量偏差 ±2px
- 模板图最好是 PNG（无损压缩），JPEG 压缩伪影会污染差异检测
- 此方法只能检测「有文字 vs 无文字」的差异，不能识别文字的语义内容
- 优先用视觉模型（百炼 Qwen-VL），差分法作为无视觉模型时的降级方案
