摘要

战场上每个兵堆脚下有一块数量牌,显示这一堆还剩多少只。实时分析用相邻两次读到的数量之差推算减员,所以“多读一位数”会造成严重的假变化。在一局实时对局(10 月 14 日 23:58)的 3 分钟真值检查中,判官的数量牌在两张截图(约 632 秒和 707 秒)上被读成 126,画面上是 26。真值是模型看图核对(MODEL_VISUAL_CHECKED),不是用户审核,因此本文只报计数。

复现发现:牌框没问题,牌内白色数字墨迹只有“2”和“6”两段;判官的链锤是灰色,在“2”左边,没有一个像素达到白色。但 OCR 两遍(原图/3 倍)都读成 126,分数都 ≥0.80,现有接受规则只看“两遍文字一致 + 分数够”,于是接受了 126。

本实验加了一个最小检查:OCR 文字的每一位必须能按顺序落在牌内的白色笔画段上,放不下就把数量置为未知(不改成别的数)。回归中实时截图的 2 处错读变为未知,没有正确读数受损。但独立审查后决定不合入。

要回答的问题

  • 126 是怎么产生的?
  • 能否用一个不训练模型的像素检查,挡住“多读一位”的错误,同时不伤害正确读数?

数据与来源

  • 问题帧:实时对局的两张原生截图(以及标注段外另一张同样读成 126 的截图)。
  • 回归数据:
    • 该实时局全部 58 张原生截图,510 个牌读数,其中标注段(598–782 秒)内 16 张有真值;
    • 行动条标注集的两段录像共 200 张原生截图、1175 个牌读数(真值取行动条上同色卡的数量,行动条不一定列出所有兵堆);
    • 实时 2 帧/秒的原尺寸 JPG 帧 368 张、3805 个读数(有压缩,只作附加检查)。
  • 没有打开冻结或留出来源。

方法

白色笔画检查:

  1. 在牌框内(上下各去 2 行)找白色像素列(亮度 V≥225、饱和度 S≤60),按空列切成“墨迹段”。
  2. OCR 文字的每一位要能按顺序落在自己的一段或几段上(一位数字可以断成几段,例如被遮住的 6);多出来的段允许(雪地、高光)。
  3. 一段里容纳几位数字,只在这段够宽时允许。各数字白墨宽度的 5% 分位数(0:8、1:2、2:6、3:6、4:7、5:6、6:8、7:7、8:7、9:8 列,加 1 列间隔)由 1339 个“段数 = 位数”的一致读数标定。
  4. 放不下 → 原因“数字没有白色墨迹支撑”,数量置为未知。牌上完全没有白墨(被盖住或变暗)→ 不判断,保持原读数。

检查同时应用于全图扫描的牌和“补找牌”(probe:对被置未知的牌再找一次)的读数;之后仍可按原规则由行动条同色同兵种的唯一卡补数量。没有改变公开数据结构或 App 校验。

设置

每帧用生产路径读一遍所有牌并保存裁剪,再在同样像素上分别算旧/新结果。真值只按“颜色 + 数量”判。

结果

组 帧 牌读数 旧:对 / 错 / 未知 / 无真值 新:对 / 错 / 未知 / 无真值 改动:修正→未知 / 改坏→未知 / 无标签→未知
实时原生截图 58 510 158 / 2 / 17 / 333 158 / 0 / 20 / 332 2 / 0 / 1
行动条标注集原生截图 200 1175 在行动条 976 / 不在行动条 123 / 63 / 13 同左 0 / 0 / 0
实时 2 帧/秒 JPG 368 3805 3776 / 3 / 26 / 0 同左 0 / 0 / 0
  • 实时截图的 3 处改动都是同一块判官牌的 126(两张有真值 26,一张在标注段外、模型看图也是 26)。没有一个原本正确的读数变成未知或别的数。
  • JPG 帧中这块牌 270 次读数:269 次两遍一致读成 26(全部保留),1 次不一致;126 只在原生 PNG 上出现。剩余 3 个旧错不是“多一位”,检查不管。
  • 修改后的端到端:两张问题截图都输出“数量未知”;其中一张的补找又读到 126,被同一检查拒绝。这两张的行动条没有读,所以无法补数,保持未知。

失败与负结果

独立审查确认三个问题,决定不合入:

  1. 换一个错数:数量被扣下后,补找会再读这块牌;链锤挡住“6”时确实会读成“2”,这个“2”能通过墨迹检查,以补找结果填回——成为另一个错数。行动条同色身份补数同理。
  2. 余量太小:拒绝 126 只靠一列亮度 224 对阈值 225 的余量;这块牌被拦下主要因为墨迹段恰好窄,并不是可靠地识别出多出的“1”。
  3. 端到端不完整:端到端检查用的是假的身体读取器,没有走到身体身份和行动条补数。

此外:白墨宽度常数与回归用的是同一批数据,不是独立检验;“少一位”(如 26 读成 2)的错误不在检查范围,行动条标注集里有 28 个“少一位”样式的不一致没有逐个核对;另一个公开的数量牌读取入口没有改,仍会给出 126。

由于状态估计(SE)已经把这两次 126 列为可疑读数、不计入减员,冒险合入不值得。补丁原样保存,结果作为不确定结论保留。

局限

  • 真值是模型目视核对,不是人工审核;问题只出现在一块牌上。
  • 14 项新测试和 97 项相关测试通过(一次新测试因断言写错失败,改的是测试断言而非代码),只证明行为。

结论与下一步

根因明确:OCR 把灰色链锤当成“1”,而接受规则只看文字和分数、不看像素。但“白色笔画宽度”这个检查过于脆弱,且会通过补找把错误换成另一个错数。如果以后再做:被扣下的牌不再补找、不再用同色身份补数;改用与相邻时刻读数或行动条同色同兵种数量的一致性来拒绝,而不是依赖墨迹宽度。