从 OpenCV 模板匹配到 YOLO:TFT 截图识别模块的一次升级
摘要
在前几篇文章中,项目已经完成了 TFT 阵容顾问的资源构建、英雄识别、装备识别和截图路由层。旧方案主要依赖 tft_screen_capture.py,通过 OpenCV 完成六边形边框检测、HSV 直方图粗筛、灰度 NCC 模板匹配等流程。
这套方案的优点是实现清晰、依赖轻、CPU 即可运行,但随着识别场景变复杂,它的上限也逐渐暴露出来:截图来源不统一、边框颜色变化、英雄头像缩放、UI 遮挡、无框截图等情况都会影响识别稳定性。
因此,本阶段项目开始引入新的识别引擎:tft_yolo_clip.py。它采用 YOLO + CLIP 的双阶段思路,将原来“靠规则找位置、靠模板猜身份”的流程,升级为“YOLO 负责定位,CLIP 负责识别”。
一、旧方案已经解决了什么
旧版本截图识别链路主要集中在 tft_screen_capture.py 中。
整体流程可以概括为:
截图
↓
判断截图类型
↓
检测英雄候选框
↓
裁剪英雄头像区域
↓
HSV 直方图粗筛
↓
灰度 NCC 精匹配
↓
输出英雄、星级、装备、站位
这个方案不是简单的模板匹配,而是经过多轮工程优化的结果。
例如:
- 模板图片不是手动维护,而是由 tft_fetch_assets.py 从赛季数据库中构建。
- 英雄 PNG 的透明区域会合成到中性灰背景,避免透明像素变成黑色影响匹配。
- 英雄识别不是全库暴力匹配,而是先用 HSV 直方图筛出候选,再用零均值 NCC 精筛。
- 棋盘图、横排结算图、全局阵容表、战绩回顾图会先通过 detect_screenshot_mode() 分流。
所以旧方案的价值在于:它把截图识别从“能跑”推进到了“有工程结构”。
二、为什么仍然需要切换到 YOLO
OpenCV 方案的核心假设是:截图中存在可解释的视觉规律。
例如棋盘模式里,英雄通常位于带颜色边框的六边形格子中,所以可以通过 HSV 范围检测青色、紫色、金色、蓝色边框。
但真实截图并不总是这么理想。
当截图来自不同分辨率、不同客户端、不同页面,甚至头像区域没有明显边框时,旧方案就会遇到几个问题:
| 问题 | OpenCV 方案的表现 |
|---|---|
| 边框颜色变化 | HSV 阈值需要重新调 |
| 头像缩放不同 | 模板匹配分数下降 |
| UI 图标干扰 | 需要继续补过滤规则 |
| 无明显六边形边框 | 候选框可能检测不到 |
| 新赛季英雄变化 | 模板库和阈值都要维护 |
也就是说,旧方案的问题不是某一行代码写得不好,而是方法本身依赖太多人工规则。
当规则越来越多时,系统会从“可解释”慢慢变成“难维护”。
这就是引入 YOLO 的原因。
三、迁移的核心思路:先拆开“定位”和“识别”
旧方案中,“找到英雄在哪里”和“判断英雄是谁”是强绑定的。
例如:
检测六边形边框 → 裁剪头像 → 模板匹配
如果第一步边框检测失败,后面的英雄识别也就没有机会执行。
新方案把问题拆成两个阶段:
截图
↓
YOLO 检测英雄位置
↓
裁剪英雄区域
↓
CLIP 判断英雄身份
↓
输出结构化结果
这里最重要的变化是:
YOLO 不需要知道边框是什么颜色,它只需要学习“英雄头像区域长什么样”。
而 CLIP 不依赖本地模板图片逐像素相似,它通过图像和文本之间的语义相似度来判断候选英雄。
这让整个识别链路从“像素规则”开始转向“目标检测 + 语义识别”。
四、当前新增的 YOLO+CLIP 模块
本阶段新增的核心文件是:tft_yolo_clip.py
它的定位是一个新的截图识别引擎,而不是直接删除旧的 OpenCV 方案。
原因很实际:旧方案已经支持装备识别、截图路由、Web 上传入口等功能,直接替换风险较高。因此当前更合理的做法是并行引入新引擎,先验证 YOLO 的检测能力,再逐步接入主流程。
当前模块中的关键配置包括:
YOLO_MODEL_PATH = Path("./tft_yolo_models/tft_champion_det.pt")
CLIP_MODEL_NAME = "ViT-B/32"
DETECT_CONF = 0.25
IOU_THRESHOLD = 0.45
CLIP_THRESHOLD = 0.50
其中:
- DETECT_CONF 控制 YOLO 检测框的置信度;
- IOU_THRESHOLD 用于去除重复框;
- CLIP_THRESHOLD 控制英雄语义识别的最低相似度;
- tft_yolo_models/ 用来存放后续训练得到的检测模型。
五、YOLO 在这里主要解决“英雄在哪里”
新模块中的 detect_heroes_yolo() 负责检测英雄候选框。
它不再扫描 HSV 边框,也不再依赖六边形轮廓,而是让 YOLO 直接输出 bounding box。
这一步的意义很大:
旧方案识别的是“边框”,再推断里面有英雄;新方案识别的是“英雄区域”本身。
这会让识别更适合处理以下场景:
- 无边框或弱边框截图;
- 英雄头像尺寸变化;
- 棋盘、结算、回顾等不同截图版式;
- UI 颜色变化;
- 后续接入真实游戏截图。
当然,当前如果只使用预训练 yolov8n.pt,检测效果不会理想,因为通用 YOLO 没有专门学过 TFT 英雄头像。因此后续仍需要准备截图数据并训练专用模型。
六、CLIP 在这里主要解决“这个英雄是谁”
YOLO 检测到框以后,系统会裁剪每个英雄区域,然后交给 CLIP 做分类。
项目中不是只给 CLIP 一个英雄名字,而是为每个英雄构造多种文本提示:
a photo of Draven champion from Teamfight Tactics
the League of Legends character Draven
Draven from TFT game
hero portrait of Draven
这种设计比单纯写一个 "Draven" 更稳,因为 CLIP 比较的是图像和文本描述之间的语义相似度,多提示模板可以提高匹配鲁棒性。
同时,英雄列表会优先从 tft_champion_db.json 中读取,而不是完全写死。这一点延续了前面项目的数据驱动思路:赛季数据更新以后,识别候选集合也可以跟着更新。
七、这次迁移不是推翻旧方案,而是重新划分职责
我觉得这次升级最关键的技术理解不是“YOLO 比 OpenCV 高级”,而是识别系统的职责重新划分了。
旧方案更像是:OpenCV 同时负责定位、过滤、识别、部分后处理
新方案开始变成:
YOLO:负责目标定位
CLIP:负责身份识别
OpenCV:继续负责星级、装备等局部规则
Converter:负责羁绊与阵容摘要
RAG Agent:负责策略分析
这样做的好处是,每个模块的边界更清楚。
例如星级检测依然适合用 OpenCV,因为星星颜色和位置比较固定;装备识别后续可以继续模板匹配,也可以训练单独的装备检测模型;英雄位置检测则更适合交给 YOLO。
这不是把传统视觉方法全部丢掉,而是把它们放到更合适的位置上。
八、当前阶段的技术进度
目前项目已经完成了 YOLO+CLIP 引擎的基础骨架:
- 新增 tft_yolo_clip.py;
- 支持 YOLO 检测英雄框;
- 支持 CLIP 对裁剪头像做零样本识别;
- 支持 yolo_clip、yolo_only、clip_only 三种模式;
- 保留星级检测逻辑;
- 预留装备识别扩展入口;
- 提供训练配置生成与命令行入口。
运行方式示例:
python tft_yolo_clip.py screenshot.png --mode yolo_clip --debug
如果只想看 YOLO 框检测结果,可以使用:
python tft_yolo_clip.py screenshot.png --detect-only
九、总结
从 OpenCV 模板匹配迁移到 YOLO,并不是简单换一个库,也不是把代码改成深度学习版本。
这次变化的核心是:项目对截图识别问题的理解变了。
旧方案证明了整条链路可以跑通:资源构建、模板加载、英雄识别、装备识别、截图分流、阵容分析都已经形成闭环。
新方案则开始解决旧方案的上限问题:减少手工视觉规则,提高对复杂截图的适应能力,并为后续真实游戏截图识别打基础。
当前项目正处在一个比较关键的阶段:OpenCV 方案仍然是稳定 fallback,YOLO+CLIP 则是下一代识别引擎的雏形。
更多推荐




所有评论(0)