摘要
玩家把鼠标指向敌方单位准备攻击时,目标上方会出现攻击预览牌:一行骷髅图标加“预计击杀数”,下一行拳头图标加“预计伤害”(固定值或范围,范围法术可能同时有好几块牌)。Battle Notes App 的实时模式会尝试读这些牌。
问题出在路由器(把一张截图分给各个读取器的程序):它只有在整帧 OCR 恰好凑出一对数字时才启动攻击预览读取。整帧 OCR 一旦漏掉一行、把两行并成一串、或者把骷髅图标读成字,这次预览就被拒或读不出来。
本实验换一个路线:先按白色掩码找到所有骷髅图标,用模板精确定位,再在下方找拳头图标;沿图标右侧的白字确定行范围,只裁数字、不裁图标,每行单独读两遍(原图和 3 倍放大)一致才接受。在一段训练录像的离线回放里,原来没读出的 9 次中,3 次真预览被补回(四块牌的范围法术补回 2 块)、1 次漏短横的读数被补回,4 次其实没有预览牌的线索误报仍然拒绝;全场扫描没有出现假数字对。
所有读数核对都是模型目视(MODEL_VISUAL_CHECKED),不是人工审核,不是准确率。
要回答的问题
- 实时回放中没读出的 9 次预览,原因是什么?局部重读能补回多少,会不会制造假数字?
- 已经读出的预览,局部重读是否给出相同结果?
- 能否用“有完整预览牌”的图标检查代替“整帧 OCR 凑出数字对”来触发攻击读取?
数据与来源
- 一段训练录像(10 月 10 日 16:57,前 23 分钟)上的 App 离线回放:54 次实时攻击预览读取,其中 7 次被拒(版面未确认)、2 次读了但没找到数字对。
- 同一段录像 373–1,304.5 秒的全场 2 fps 采样,共 1,863 个,配合已有的时间线(标出哪些时段是攻击预览)。
- 只有这一段录像;阈值也在这段录像上定。
方法
- 找图标:按之前实验的白色掩码找出所有骷髅候选峰(不只最高的那个),用灰度模板精确定位骷髅;在其下方(行居中,可略偏左)找拳头。
- 定行:沿每个图标右侧的白字确定行范围;同一行上另一块牌的图标是硬边界。
- 读字:裁图只含数字。每行单独一批(因为识别结果会受同批其他图片补边影响),原图和 3 倍各读一次,一致才接受,再严格解析数字。
- 两道额外保护:
- 两行居中:伤害行中心 − 击杀行中心必须在 0.5–6.5 像素之间。合并了邻牌或背景、多读或少读一位,都会偏离。
- 单值最多 5 位:没有短横的长数字(如
11881782)通常是范围里的短横粘连被漏读。
- 之后照常走原有的检查,不放宽任何一项。
发现门槛:只检查“骷髅 + 拳头 + 两行居中”,不读字,用来决定要不要启动攻击读取。
设置
CPU、2 核、低优先级,与另一个回放并行运行。整帧路由对照约 40 秒一帧,因 CPU 限制只跑了 9+4 帧就停止。
结果
9 次没读出的实时读取
| 媒体秒 | 实时结果 | 实际原因(目视) | 局部重读 |
|---|---|---|---|
| 565.7 | 被拒 | 整帧 OCR 漏了击杀行 | 补出 1 / 38-47(50%) |
| 1060.7 | 被拒 | 4 块牌(范围法术),两行被并成一串 | 补出 2 块;另 2 块未读(一块两遍不一致,一块伤害行连到背景、不居中) |
| 1113.2 | 被拒 | 骷髅被读进数字成 $2 |
补出 2 / 179-240 |
| 709.2 | 读了但无数字对 | 漏了短横,宽度检查拒绝 | 补出 10-15 / 884-1326 |
| 671.7 | 读了但无数字对 | 1188-1782 短横粘连 |
仍未读(两遍不一致),正确保持未知 |
| 661.7、919.2、934.2、943.7 | 被拒 | 画面上没有预览牌:线索打在白色生物身体上 | 门槛不触发,仍被拒,无假数字对 |
7 次“被拒”中 3 次是真预览(全部补回,其中一次补回 2/4 块),4 次是线索误报(本来就该拒)。补出的 5 个读数,以及 719.2 秒额外补出的 33-50 / 407-611(90%),都与原图目视一致。
已接受的 45 次实时读取
局部重读对同一块牌给出 37 个读数,36 个与实时读数相同;唯一不同的是 719.2 秒:实时读成 4-67 / 431-647(100%),其中 “7” 是背后数量牌的数字混了进来,局部读出 4-6,与画面一致。提议的补丁只补整帧 OCR 没覆盖的牌、不改已接受的读数,所以已接受读数不变。
全场 2 fps 扫描(最坏情况:不排除覆盖层、无版面门槛)
- 时间线标为攻击预览的 304 个采样中 210 个读出预览;其余 1,559 个采样里读出 19 个——逐一目视都是真预览牌(时间线区间边界漏标),没有假数字对。
- 54 种不同读数各目视一张:只有 659.0 秒
39-48 / 11881782错(短横粘连),已被“单值 ≤5 位”挡下;其余与画面一致。 - 被检查挡下、保持未知:字符没读出 80、图标淡化或被遮挡 6、不居中 1、长数字 1。多是行范围连到白色背景(如狮鹫翅膀),保守但不出错值。
- 发现门槛:在 1,559 个非标注采样上触发 23 次,目视 23 次画面上都有完整预览牌;在 304 个标注预览采样上触发 241 次。
耗时(CPU)
- 掩码 + 图标定位:中位 0.027 秒(p95 0.035 秒);发现门槛中位 0.020–0.025 秒。
- 读字:每块牌 2 行 × 2 遍,中位 0.97 秒;四块牌的范围法术 2.85 秒。GPU 耗时未测。
补丁冒烟测试与应用
在内存中载入提议的模块,整帧 OCR 用“完成但没有文字”的替身:5 个时刻补出与上表相同的预览,2 个误报时刻无预览;14 个输出全部通过 App 的严格校验器。之后由主会话审阅并原样应用:新私有模块、攻击读取的可选参数、路由器在整帧 OCR 没有数字对时用发现门槛选攻击任务。“单值最多 5 位”另外加到原有检查的最后一步(新原因:范围短横丢失),整帧 OCR 预览也受它约束;在已保存的几次端到端回放读数上,只会去掉已知的 39-48 / 11881782 一个。
失败与负结果
- 1060.7 秒四块牌中 2 块、671.7 秒一块仍未读出。
- 顺带发现两个生产错读(不在补丁范围):658.2 秒实时接受了
39-48 / 11881782(宽度检查放过),719.2 秒的4-67。前者后来被“≤5 位”规则覆盖;后者属于整帧 OCR 路径,本补丁不影响。 - 整帧路由对照因 CPU 限制没有跑完。
局限
- 只有一段训练录像,阈值(居中窗口、5 位)也在它上面定,没有独立来源检验。
- 读数核对是模型目视,不是人工审核。
- 自动模式下门槛触发会让战场读取变成“只读 HUD”(与整帧 OCR 触发时相同);门槛只在这段录像的真预览牌上触发过,未在其他录像验证。
- 背后数量牌的白色数字可能并入击杀行;居中检查挡下了扫描中的两例,但整帧 OCR 路径不受影响。
- CPU 上每块牌约 1 秒,多块牌更慢;App 端到端未测。
结论与下一步
“先找图标、再局部读字”能补回整帧 OCR 漏掉的真预览,同时对线索误报和背景干扰保持保守,在这段录像上没有产生假数字对,因此已接入生产。下一步是在其他录像上验证门槛和阈值,并测 GPU 与 App 端到端耗时。
Comments