摘要

在这款游戏的战场上,每堆生物脚下都有一块数量牌:一个小牌子,写着这堆兵还剩多少。读出数量牌能帮助推断双方兵力。之前的实验已经有能找牌、读数字的内部代码,但其他模块(例如状态估计 SE,把读到的观察累积成对局状态和对手构筑的推断)只能通过公开接口调用视觉模块。

本实验验收一个新增的公开单图入口:命令行 visible-quantity-plates --image … --read-literals,内部调用公开接口。做法非常保守:实现和配置先在 Git 中冻结、软件测试通过,然后对两张事先固定的原图各只调用一次,不重试。

两次调用都成功:每张图找到 7 块牌、做了 14 次实际读数,每块牌的几何、颜色证据和读数记录都与旧实验的导出逐项完全相同——包括一个已知的错误读数。这验证的是“接线没改变结果”,不是新的准确率。

要回答的问题

新的公开入口是否真的走公开接口、在真实原图上能正常完成,并且结果与已有的内部导出完全一致?

数据与来源

  • 两张事先固定的 2560×1440 原生截图(草地和雪地战场,来自之前实验的数据集)。
  • 已有的旧实验导出作为对照。
  • 只用缓存的 CPU 模型,不下载、不用 GPU。

方法

  • 冻结:协议文件固定两张原图、辅助代码元数据和 CPU 配置;实现提交只包含提供方的文件和改动,工作区里其他无关改动保留不提交,并记录差异。
  • 执行器对每张图调用一次真正的命令行 main(argv),记录确切参数、公开结果、计数、耗时、模型与来源元数据。
  • 防重跑:一个独占的“已开始”回执阻止再次运行;每张图在调用前写自己的独占“调用开始”回执,失败也算用掉唯一一次机会。
  • 执行器不解码图片、不导入私有辅助代码、不选新几何、不用标签预测、不复制媒体、不改运行时默认。
  • 调用之后,只读元数据的验证脚本比对保存的读数与旧导出,不再调用模型。

几何方法沿用旧的版本(基于暖色牌边与数字证据,不输入身体检测)。OCR 是 PP-OCRv6 中型识别模型,原尺寸和 3 倍放大各读一次,每次门槛 0.80——两次读数来自同一个模型,是相关的,不是独立投票。

设置

OpenCV 和预测器各 2 个线程,每批最多 8 个变体。

结果

原图 退出/状态 牌/读数 公开接口秒数 调用方秒数 输出字节
草地 350 秒 0 / CANDIDATES 7 / 14 7.266 7.282 5,477
雪地 360 秒 0 / CANDIDATES 7 / 14 4.531 4.531 5,482

每次公开调用做了一次原图解码、一次缓存 CPU 模型初始化、两批共 14 个实际读数。数量和字面阶段完成(但不保证找全);身体检测没有运行;单位关系为空;范围标为“当前画面,不是开局”。每块保留的牌,其原生几何、颜色证据和字面记录都与旧导出完全相同,包括原始分数。没有从文件名推断时间,也没有把任何候选升级成“当前军队真值”。

保留的难例:

  • 草地第 3 块牌:保留已知的错误候选 384,两次原始读数都是 384(分数 0.840 和 0.870)。“两次一致”不等于正确,也没有用参考标签修正。
  • 雪地第 3 块牌:两次读到 15,分数 0.894 和 0.710,因低分值为空。
  • 雪地第 7 块牌:两次读到 To,值为空,原因是不是数字。

只读元数据验证:通过。2 次公开调用、2 次解码、2 次初始化、14 块牌、28 次实际读数;原图、三个缓存模型文件、旧辅助代码和冻结的实现/配置元数据都没变。

软件验证:视觉模块全套 5,919 项通过;聚焦的提供方与兼容测试 234 项通过(含 28 个新的公开入口用例);另有一个不需要模型的“提供方 → SE”集成用例用合成临时图片通过。子进程测试覆盖了退出码、部分失败保留、来源变化拒绝、超过上限(65 块牌)整体拒绝、分批、只用缓存的 CPU 设置、原图不被修改等;四个 10 秒阻塞测试在注入的 1.5 秒预算下验证了子进程会被真正终止(这不是硬实时承诺)。

失败与负结果

  • 已知错误读数 384 被保留并输出为候选——两次同模型读数一致仍可能是错的。
  • 意见不一致和部分失败的处理只用软件测试验证,没有在真实图片上再调用。

局限

  • 只有两张已用过的原图,不是准确率评估。
  • 主线的独立验收、App 传输接入都是单独的后续步骤,本实验没有做;没有改 App、默认设置或会话。
  • 耗时包括冷启动,不是端到端 p95。

结论与下一步

公开入口接线正确:真实调用走公开接口完成,结果与旧导出逐字节一致,难例和错例都如实保留。下一步交给主线独立验收,之后才考虑让 App 通过这个入口传输数量牌读数;去重、更多图片的评估等都不在本次范围。