摘要
这款回合制战斗游戏的屏幕顶部有一条行动条:按行动顺序排列的卡片,每张卡显示一个兵堆(同种生物的一组单位)的兵种、阵营颜色(红/蓝)和数量;回合之间有分隔标记,第一张卡就是当前行动的单位。实时分析时,项目在每次行动结束后读一次行动条,用相邻两次读数的数量差来推算减员(伤亡),因此每个数字都很关键。
本实验为两段录像建立逐卡标注集,并逐字段对照生产读取器。标注是 AI 助手的“模型目视核对”(MODEL_VISUAL_CHECKED),不是用户审核(REVIEWED),所以下文只报逐字段计数,不写“准确率”。
主要发现:兵种、颜色、回合组在两段录像上没有一个错。数量是唯一的问题:在后半场残兵只剩个位数时,读取器把一只麒麟的“9”读成“79”5 次(左侧鬃毛纹理被读成“7”),还有大量单个细数字未读;另有一例英雄窗口挡住数字下半部分,读取器却读出了“2”(实际 24),这会被减员推算当成一次假减员。
要回答的问题
- 行动条读取器的兵种、颜色、回合组、数量各字段表现如何?
- 错误和未读集中在哪里,对减员推算有什么风险?
数据与来源
| 录像 | 角色 | 时刻数 | 读取结果来源 |
|---|---|---|---|
| 一段训练录像(10 月 10 日 16:57,前 23 分钟) | 开发集 | 83 | App 离线回放时保存的每次行动条读取 |
| 另一段录像(10 月 10 日 01:39) | 独立检验 | 117 | 本实验用生产读取器新读 |
没有打开冻结或留出录像。
选帧:开发录像直接用 App 回放中的每一次读取作为一个时刻(83 个,含 4 个拒读)。独立录像还没有 App 回放会话,于是在 2 帧/秒的帧库里找“行动条静止”的时刻(2 秒内相邻帧行动条区域变化超过 40 灰度的像素都少于 0.2%),每个静止段取中间一帧;与上一个时刻只差 ≤1 个卡位,或相隔不到 3 秒,就去掉。原计划“每 15–20 秒一个”只得到 67 个不同状态,所以改为“每个静止段一个”,得到 117 个。已知损失:英雄施法只改一个卡位数量时会被当成同一状态丢掉。
标注:每张卡标位置、回合组(0 = 第一个分隔前,1 = 分隔后,依次类推)、兵种、颜色、数量;被挡住的数量写“未知”并注明原因。每段录像先做一张兵种对照表(每个兵种多张卡片样本与游戏资料库图标并排),全部与图标一致。开发录像是对着读取器的值核对的;独立录像前 13 个时刻同样,后 104 个时刻在读取器运行之前盲标。自查:同一时刻同一堆在不同回合组的数量一致;数量随时间只减不增(少数回升来自复活/再生,核对图上清楚)。
| 录像 | 时刻 | 有行动条 | 卡片 | 回合组 0 / 1 / ≥2 | 数量未知 |
|---|---|---|---|---|---|
| 开发 | 83 | 79 | 980 | 719 / 261 / 0 | 0 |
| 独立 | 117 | 117 | 1368 | 562 / 529 / 277 | 8(英雄窗口挡住) |
方法
逐卡、逐字段比较标注与读取器输出,分为正确、错误、未读(读取器拒绝给值)、漏检(卡没找到)、未知。读取器只读回合组 0 和 1;独立录像后半场残兵少时,行动条同时显示 3–5 个回合,回合组 ≥2 的 277 张卡记为“范围外”,逐个看过都是前面已出现的同一堆、数量相同,不丢信息。
设置
独立录像的读取在一个限核的“重任务名额”包装器下用 CPU 运行,同时机器上还有两段 App 离线回放和其他任务在跑。
结果
两段录像的行动条有无全部判对(开发录像 4 个无行动条的时刻正确拒读),卡片数全部与标注相同,没有漏卡或多卡。同一堆在两个回合组的两张卡数量不一致:读取器 0 次。
开发录像:
| 字段 | 正确 | 错误 | 未读 |
|---|---|---|---|
| 兵种 | 980 | 0 | 0 |
| 颜色 | 980 | 0 | 0 |
| 数量 | 970 | 0 | 10 |
| 回合组 | 980 | 0 | 0 |
独立录像(范围内 1091 张卡):
| 字段 | 正确 | 错误 | 未读 | 未知 | 挡住却读出值 |
|---|---|---|---|---|---|
| 兵种 | 1091 | 0 | 0 | 0 | 0 |
| 颜色 | 1091 | 0 | 0 | 0 | 0 |
| 数量 | 1010 | 5 | 68 | 7 | 1 |
| 回合组 | 1091 | 0 | 0 | 0 | 0 |
按标注方式拆分:盲标的 104 个时刻、932 张卡中,兵种/颜色/回合组全对;数量 861 对、5 错、66 未读。读取器给出的值里,与盲标不同的只有这 5 个数量;逐张放大原生帧看过,卡上清楚是“9”,是读取器错,不是标注错。所以盲标部分没有发现“标注跟着读取器走”的偏差——但两者都同意的值仍只是模型目视。
耗时:开发录像(App 回放进程内记录)读到行动条的 79 次中位 2.22 秒、p95 3.07 秒、最大 3.69 秒。独立录像在限核和抢核条件下热读中位 63.9 秒、p95 93.4 秒,不能当作生产耗时;剖析显示一帧中整帧文字检测约 32 秒、行动卡身份排序约 40 秒,并发现包装器总把几个任务挤在同 4 个逻辑核上。另外,行动条请求每帧都跑一次整帧文字检测,是否必要值得再看。
失败与负结果
错例共 84 条(开发录像未读 10;独立录像读错 5、未读 68、挡住却读出值 1),兵种、颜色、回合组一个都没有。
- “9”读成“79”(风险最高):一只蓝方麒麟后半场只剩 9 只。读取器两次 OCR 都读成“79”且分数够时就输出 79(5 次,两次 OCR 分数约 0.80–0.93)。这只麒麟在范围内共 49 张卡:读对 6、读错 5、未读 38(两次读法 9/79 不一致 28 次,79/79 但分数不够 10 次)。影响:减员时间线会看到 9→79→9 的“回升”。说明读取器没有检查数字宽度和位置——“9”只占一位宽。
- 单个细数字未读:全是单个窄数字压在金色或亮色生物图案上。例如一只红方织光者的“1”在约 115 秒内连续 12 个时刻都未读,最后一只的数量只能靠前后推断;开发录像中巫妖“1”连续 7 次未读,最后一只巫妖的死亡时刻因此不确定。同样的“1”在其他时刻能读出,并非完全读不了。
- 被挡住却读出值:我方英雄窗口盖住行动条第 3–6 张卡的下半部分,第 3 张只露出“24”中“2”的顶部,读取器读成 2。按减员算法,这就是一次 24→2 的假减员。同一帧其他被挡的卡和另一个时刻被挡的卡,读取器正确地没给值。建议:数量框与英雄窗口等会盖住行动条的窗口重叠时直接不读。
局限
- 标注只是模型目视核对,没有用户审核;开发录像的核对对着读取器值进行,可能有跟随偏差。
- 读错和大部分未读集中在少数几堆残兵的个位数字上,计数受它们停留多久影响很大,不能当作对所有数字的估计。
- 独立录像的选帧是“静止段”而不是 App 实际的“行动结束后”时刻,其中 34 个时刻有法术书、生物面板等叠加层,比 App 实际读的时刻更难。
- 只有两段录像、两场战斗,兵种组合有限;没有同名兵种同时出现在双方的情况。
- 11 项单元测试覆盖选帧去重、解析、打分逻辑,不代表识别准确率。
结论与下一步
行动条的兵种、颜色、回合组在这两段录像上已经很可靠;数量是唯一短板,而且错误模式很具体:个位数字被背景纹理“补”成两位数、细窄数字分数不够、被窗口挡住仍给值。这三类都直接威胁基于数量差的减员推算。下一步应加入数字宽度/位置检查、遮挡时拒读,并请用户在审核页上逐卡确认,把模型目视标注升级为人工审核。
Comments