摘要
在《英雄无敌:上古纪元》的战斗里,玩家可以打开一个生物的属性面板,看到攻击、防御、伤害、士气、幸运、先攻、速度等数值。这个面板是半透明的:后面战场上的东西会透过来,其中就包括其他兵堆脚下显示数量的小牌子(下称数量牌)上的数字。
OCR(光学字符识别,把图片里的字读成文字)在这种画面上会把背景里的小数字和前景的大数字拼在一起。前一轮发现了三处真实误读:
| 正确值 | 被读成 |
|---|---|
| 攻击 32 | 432 |
| 攻击 17 | 9517 |
| 幸运 1 | 71 |
本实验利用一个几何事实:前景属性数字字形更大、共用一条较低的底边,背景数量牌数字更小、位置更高。据此重新给每个属性数字取一个更紧的文字框,再用原来的读字流程复核。最终方案只复核已经读出的候选,三处错误全部纠正,原本正确和原本未知的字段都不受影响。另一个更激进的方案——用新框直接替换全部读数——虽然账面正确数更高,但引入了新的错误,被否决。
要回答的问题
- 能否在不降低 OCR 阈值、不限制数值范围、不查兵种目录的前提下,排除背景数量牌数字的干扰?
- 新方法会不会把原本正确的值改坏,或者把看不全的数字读成完整数字?
为什么不能用那些“捷径”:降低阈值会放进更多垃圾;“攻击不该超过某个值”是对游戏数值的猜测;查目录或借邻近帧会把推断冒充成观察。
数据与来源
- 训练来源:上一轮已精标的 87 张训练图(原图及其邻近帧),覆盖所有自动请求的攻击/防御/伤害/士气/幸运/先攻/速度格,而不只是那三处错误。
- 验证:新跑 210 张训练/校准完整原图、45 张邻域原图,最后对 71 张最新开发图跑一次。最新组是 10 月 5 日一个已暴露来源组里的 5 个对局,不是独立盲测。
- 保留低质量和“该位置不存在”的对照样本;更早冻结的测试来源不读取。
- 只验证了 2560×1440。
方法
几何提案:在登记好的属性行里找连通的字形块。前景大字形共享较低的底边,大多数背景数字更小、更高。保留负号和完整的多位数字;几何上含糊或贴着边界的一律拒绝提案。提案只返回框和诊断像素,不返回数值。
读字:把新框交给现有的读字器,原图和放大 3 倍两种尺度各读一遍,要求两遍对整个数字串严格一致。绝不从 OCR 结果里挑一个子串,也不推测数值范围。
两种使用方式(先在训练集上比较,再决定):
- 全替换:凡有新提案的格子,都用新框的读数替换原读数。
- 只复核已接受的候选:只对原本已经读出值的格子做一次复核;新框两种尺度都强一致且完整时可以改值;弱读、冲突、符号变化则保留原值并记录诊断。原本未知或被局部拒收的格子一律不动。
设置
- 实验入口是显式开关
--stat-foreground,不加就是上一版行为;不改模型权重、默认配置、App 或下游模块。 - 训练组上决定方案后才动用校准组和最新组;最新组只跑一次,不在最新组上调规则。
结果
训练组上的方案比较
455 个已请求的属性格中,340 个得到几何提案,115 个拒绝提案。
| 方案 | 正确 | 已标误读 | 新问题 | 决定 |
|---|---|---|---|---|
| 原读数 | 344 | 3 | — | 基线 |
| 全替换 | 353 | 1 | 3 个被鼠标遮住的残缺数字被读成完整的“1”;与死亡横幅重叠的 41 被读成 4 | 否决 |
| 只复核已有候选 | 纠正 3 处,原正确值无损失 | 0(这三处) | 没有把不可判的数字提升为值 | 采用 |
全部 13 个变化的原图上下文、原裁图和新裁图都看过像素(模型目视核对,不是独立人工审核)。关键教训:新框“看起来干净”并不证明里面的数字完整、没被遮挡,所以不能用它去恢复原本未知的字段。
完整原图验证
326 张图中唯一的值变化就是那 3 处纠正,全部在上一轮新增的训练精标范围里。因此更早一轮较窄分母上的成绩完全没变:
| 原声明范围 | 正确/分母 | 误读 | 拒判 | 漏读 | 声明字段整帧全对 |
|---|---|---|---|---|---|
| 训练 | 927/934 | 0 | 5 | 2 | 70/77 |
| 校准 | 280/280 | 0 | 0 | 0 | 24/24 |
| 最新 | 356/363 | 0 | 7 | 0 | 22/27 |
在上一轮建立的“完整局部 11 格”范围上:
| 范围 | 正确 | 误读 | 拒判 | 漏读 | 不可判、保持未知 | 不存在的位置没有误请求 |
|---|---|---|---|---|---|---|
| 42 张训练图、428 个可读格 | 384→387 | 3→0 | 21 | 20 | 34 | 0 |
| 45 张邻域图、266 个可读格 | 188 | 0 | 24 | 54 | 75 | 154 |
完整局部正确率分别是 90.42% 和 70.68%,仍未达到 95%。42 张图里那 3 个被接受的背景错误已清除,但不等于整个系统没有错误。
回归与速度
326 张图的 3,907 个原始数值观察都保留;3,347 个非目标或未知字段逐项一致;528 次前景复核只产生 3 处值变化;界面、身份、空槽、场景和日志输出深度比较一致;读取失败 0 次。
| 原图范围 | 热启动 p95(秒) | 最大(秒) |
|---|---|---|
| 训练 165 张 | 1.320 | 1.583 |
| 校准 45 张 | 1.362 | 1.445 |
| 最新 71 张 | 0.999 | 1.126 |
计时从解码文件到写出 JSON,包含新增复核,不含 App 截图和显示;依赖模型常驻预热(最新组冷启动界面 2.753 秒、OCR 5.103 秒)。与上一版的耗时差异属于波动,不称为优化。
失败与负结果
- 全替换方案失败:账面上正确数从 344 升到 353,但新增了把残缺数字读完整、把 41 读成 4 的错误。只展示三处背景错误被修好而隐藏这些新错误,是不诚实的。
- 最新组里上一轮新增的一个拒判(正确的数量 7/15 被拒)仍然保留。英雄士气 9/11、幸运 8/11、生物数量 14/16,都不到逐字段 95%。
- 全模块测试 7226 通过、2 个与之前相同的导入顺序失败、6 跳过,没有为了全绿删除或反复重跑。
局限
- 同一个 OCR 模型的多视图只算一个证据来源,不提供校准概率。
- 最新组是 5 个对局、1 个已暴露来源组,不能据此完成“十个独立来源”验收。
- 只在 2560×1440 上验证。
结论与下一步
“只复核、不扩张”的前景字形复核安全地消除了这一类背景数字拼接错误。但现在更大的损失来自覆盖率而不是这类错误:从保存的结果里已定位 8 张训练图、74 个可读字段漏读——其中 7 张根本没有面板提案,1 张面板得分 0.951 但下边界偏离固定模板,整个面板没被请求。下一轮优先复用已有的面板定位和文字锚点补上这个入口,保留局部可读的过渡帧和无面板负例,在训练来源上证明定位和字段完整性后再复测。
Comments