返回专辑
·Johan·3 分钟阅读

模板匹配:受控才好用

matchTemplate 的 TM_CCOEFF_NORMED 对亮度有一定归一化,但尺度旋转变化仍脆;适合 fix camera、fix pose 工位。

模板匹配:受控才好用

1. 产线快,换场景就飘

固定机位找 OK/NG 标记,模板匹配毫秒级出结果,比跑整图目标检测省一个数量级。换班次光照、镜头轻微虚焦,最大响应值从零点九二掉到零点六一,峰值位置漂移或误匹配——不是 OpenCV 的 bug,是受控假设破了:模板与场景只差平移(加可选小尺度),旋转、形变、遮挡一出现就该换工具。产线能固化参数的前提是光照、机位、镜头焦距都不变;离开这个盒子,硬调阈值只是在噪声上找峰值。

2. OpenCV API 与响应图语义

python
res = cv2.matchTemplate(gray, templ, cv2.TM_CCOEFF_NORMED)
min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res)

输出尺寸为图像宽减模板宽加一、高减模板高加一;峰值位置加模板尺寸得边界框。TM_CCOEFF_NORMED 减均值后对线性亮度变化较鲁棒,一分最好;TM_SQDIFF_NORMED 零最好;TM_CCOEFF 减均值抗亮度但无上界归一化。OpenCV 文档明确要求模板不大于图像,违反直接断言失败。全图峰值是最优平移假设——没有旋转、没有形变自由度。

3. 多实例与 NMS

单一峰值不够时:阈值过滤后在响应图做非极大值抑制,抑制邻域(通常模板宽高的一半)再取次峰,循环至分数低于工作阈值。产线可记录最大响应值分布定阈值(如低于零点八判无匹配);跨班次统计峰值偏移和分数分布,比单次调参可靠。亚像素可对峰值邻域做二次曲面拟合 refine,产线精度要求到零点一像素时有价值。重复纹理场景多峰值是结构性问题,非极大值抑制只能缓解不能根治。

4. 多尺度与旋转边界

matchTemplate 不处理旋转。旋转目标需模板库多角度(每五到十五度一张),或升级到 ORB 特征加单应矩阵验证。尺度变化靠外层循环:

python
for scale in np.linspace(0.8, 1.2, 10):
    t = cv2.resize(templ, None, fx=scale, fy=scale)
    if t.shape[0] > gray.shape[0]: continue
    res = cv2.matchTemplate(gray, t, cv2.TM_CCOEFF_NORMED)

成本随尺度步数线性涨。由粗到精可在低分辨率金字塔层找峰值区域,再 refine 到全分辨率,是经典加速。模板与场景必须同分辨率、同色彩空间——灰度彩色混用是静默失败的常见源。

5. 何时换方案

形变、遮挡、背景杂乱 → 目标检测器或特征匹配(ORB 加 RANSAC 单应验证)。固定工位加受控光照加小尺度变化:模板匹配仍是性价比最高的选择。我会把匹配方法、工作阈值、尺度步长写进产线配置,换班时对比最大响应值分布是否漂移。

6. 失败模式

情况表现
光照变分数降、误 peak
尺度变漏检
重复纹理多 peak
轻微旋转peak 偏移

7. 验收

分数阈值的 ROC 曲线;跨班次峰值偏移统计;固定工位延迟与误检率一起报。模板匹配是受控假设的算法:假设成立时极快,假设破了别硬撑——换工具比调参诚实。

8. 案例:跨班次 score 漂移

某产线 OK/NG 判定用 TM_CCOEFF_NORMED,早班最大响应值均值零点八八,晚班零点七二——不是模板磨损,是顶灯色温变化导致线性亮度偏移。记录每班 score 分布、用减均值归一化方法后,晚班阈值从零点八调到零点七五,误检率回到可接受范围。没有 score 分布基线,只能凭手感调阈值。

9. 配置与验收清单

产线固定机位应把匹配方法、工作阈值、尺度步长、模板尺寸写进 yaml,启动时 assert 输入分辨率与采模板时一致。验收:分数阈值 ROC;跨班次 peak 偏移;latency 与误检率;故意换光照/虚焦后的 score 分布是否仍可用。模板匹配是行为接口——阈值与模板版本要可审计、可回滚。

← 全部文章

johan's blog