摘要
《英雄无敌:上古纪元》的战斗中有一个战斗日志(下称 Logs)面板,逐行写着“[时间] 玩家:某某攻击了某某,造成多少伤害”之类的事件。这些文字是推断对手构筑的重要证据。
本实验做了一条只在用户显式选中一张截图时才走的私有读取路径:整张原始截图 → 自动识别界面并找到日志面板 → 只对日志这一块跑一次 OCR(文字识别)→ 输出原始文字行、按时间戳拼出的事件候选,以及无法归属的碎片。它能读只有一条事件的日志,不需要前面的帧,也不改动战斗记录 App、状态估计等其他模块。
在最新的开发组(同一次录像会话里的 5 场战斗)上,136 条事件全部被找到,事件正文完全一致 134 条、含数字的行数字全对 117/117;但玩家名前面的小方块和名字经常漏读,时钟、玩家、正文三项全对只有 47/136(34.6%)。预热后读一整张图的 p95(95% 的请求不超过的时间)为 1.099 秒。
要回答的问题
在不依赖前后帧、不预先告诉程序“这是日志画面”的情况下,能否从单张截图里自动定位日志面板并读出每一条事件?读出的哪些字段可靠,哪些不可靠?速度是否满足项目“预热后单帧 p95 ≤ 3 秒”的目标?
数据与来源
- 复用前一个实验已审核过的截图分组:22 张日志页、共 472 条可见事件。其中 14 张为训练 / 诊断用,3 张用于校准,5 张为“最新开发组”。
- 最新开发组的 5 场战斗来自同一次录像会话,是一个已经被看过的开发组,不是 5 个独立的盲测来源。
- 一张半透明的训练日志页保留在分母里作为诊断失败。
- 项目冻结的独立测试素材没有打开。
方法
定位。 用上一个实验交付的纯图像界面面板检测器找日志面板的位置;不告诉读取器真值框、预期场景或行数。不是日志的截图不会触发文字识别,用来检查文字请求是否只针对日志区域。
读文字。 对检测到的日志面板原始像素跑一次已缓存的 PP-OCRv6 中等模型(检测 + 识别)。因为在 Windows 上 Paddle 和 Torch 不能在同一进程里共用 cuDNN,OCR 放在一个常驻的独立子进程里,所选像素直接在内存中传过去,不再读一次文件;等待有上限,超时只关闭自己启动的子进程;模型只用本地缓存,缺缓存就报错而不是下载或返回空结果。
事件拼接。 保留每一个 OCR 行及其在原图上的坐标。第一次在训练 / 校准数据上发现:读出的行里有关闭按钮“X”、半透明的战场文字、被裁到一半的边缘文字;还有两条训练事件的右半部分被识别成单独的文字框。于是单独做了一个 events 投影:带时间戳的行作为锚点,一个未归属的碎片只有在“与锚点垂直重叠 ≥60%、间隔不超过两个字高、只有唯一可能的锚点、锚点句子还没结束”时才接上,中间加一个空格。不修补字母、括号、玩家方块或被裁的边缘行。接不上的碎片明确标为未解决。
解析。 已有的严格字面解析器只在原文完全符合支持的句式时才给出结构化结果。
评分。 推理完成后才读审核文本。正文比较允许 Unicode 规范化、空白(数字之间的空白除外)、引号和句号写法差异,不做字词纠错,也不拼接断开的数字。另外分别统计时钟、玩家、含数字行的数字序列。
设置
| 项目 | 设置 |
|---|---|
| 输入 | 原生 2560×1440 截图(只支持这一分辨率) |
| OCR | PP-OCRv6 中等模型,一遍,常驻子进程 |
| 计时范围 | PNG 解码、自动界面识别、区域编码与进程通信、OCR、JSON 序列化;不含 App 截图与显示 |
结果
| 数据组 | 事件候选 / 标注 | 正文完全一致 | 时钟一致 | 含数字行全对 | 玩家一致 | 三项全对 |
|---|---|---|---|---|---|---|
| 训练 / 诊断 | 266/269 | 263/269 | 266/269 | 226/229 | 120/269 | 119/269 |
| 校准 | 67/67 | 66/67 | 67/67 | 61/61 | 33/67 | 32/67 |
| 最新开发组 | 136/136 | 134/136 | 136/136 | 117/117 | 47/136 | 47/136 |
最新组原始 OCR 里另有 12 个多余或无法解析的碎片(X、背景文字和数字、被裁的边缘文字),保留在原始行和未解决列表中;事件投影的 136 行与审核事件一一对应,没有缺失或多出。严格解析器能解析其中 102/136 行(这只是“句式覆盖率”,不是已确认的观察)。
和保存的历史结果对照:最新组旧的“三次读取一致才接受”文本正文匹配 113/136、数字行 98/117;旧的整图 OCR 正文匹配 133/136。这些只是覆盖诊断,不说明单次读取比多次独立证据更可信。
速度(预热后):
| 范围 | p95 | 最大 |
|---|---|---|
| 最新组 71 张整图 | 1.099 秒 | 1.256 秒 |
| 最新组 5 张日志 | 0.612 秒 | 0.617 秒 |
| 校准组 45 张 | 1.078 秒 | — |
108 张非日志截图没有发出任何日志 OCR 请求。冷启动:界面模型加载 5.114 秒、OCR 进程与模型加载 16.252 秒、首次训练预热 1.806 秒,所以冷启动超过 3 秒,模型必须常驻。
测试:手动界面 / 日志专项 20 项通过;Perception 全套 7,182 通过、6 跳过、2 个既有的导入顺序失败(与前两个实验相同,未放宽也未顺手修)。
失败与负结果
保留的实际错误:
- 最新组:“圣殿狮鹫”读成“圣殿狮鹭”;“死亡单位”读成“死亡单”。
- 校准组:“伤害”读成“伤”。
- 训练组:一张半透明日志面板没有被检测到,3 条事件全部缺失;另有一条被切开的事件仍不完整;一个狮鹫的字读错,英雄名丢了一个字。
- 玩家名前的小方块经常漏掉,最新组三项全对是 34.6%,不是正文的 98.5%。不能凭这些不完整的玩家字符串推断事件属于哪一方。
被否决的尝试:第一次只按几何位置拼接碎片,在一条训练事件里把背景上的“方回合”接到了一个已经完整的句子后面,所以在跑最新组之前加了“句子未结束、唯一锚点”等限制。另外,第一次正式运行在启动时就失败(OCR 适配器不接受新版库的一个参数),失败记录保留,修好后才有第一次完整的 130 张运行。
局限
- 只支持原生 2560×1440。
- 最新组是同一次录像会话,不是独立盲测;这些数字是开发集测量,不是项目目标所要求的独立准确率。
- 只读一遍 OCR,没有独立确认;所有输出状态都是“候选”。
- 英雄、生物、HUD(游戏界面上方的英雄属性条)数字的读取还没有组合进来,速度结论不覆盖它们。
结论与下一步
手动截图的日志读取路径已经可用:事件定位和正文、数字读得很好,速度在预热后远低于 3 秒;主要短板是玩家归属字段。下一步是读玩家标记字形和处理被切开的日志文字,然后在英雄、生物、HUD 截图上读数字字段;更多来源的覆盖、小元素框和局部遮挡仍待解决。
Comments