摘要
最后一次行动之后,游戏会弹出结算页:标题“胜利”或“战败”,按钮“接受结果”,下面列出双方每个兵堆的卡片——生物头像、卡内的白色数字(开战数量),以及卡下橙红色的损失(如“-185”,前面有个小骷髅图标)。这是敌方军队和每堆总减员的战斗结束值,状态估计(SE)可以用它核对整局的减员时间线。
但 App 的关键帧服务(决定哪些画面值得读的程序)一直把它归为菜单直接跳过。本实验在 3 个训练结算页上找画面、写参考、做读取器原型并评估,提出生产接入补丁(10 月 15 日已接入)。所有数字都是模型读数和模型目视核对(MODEL_VISUAL_CHECKED),不是人工审核。
要回答的问题
结算页上每张卡的数量、损失和兵种能否可靠读出?App 如何知道结算页出现、应在哪一帧读?
数据与来源
只用训练来源:
| 录像 | 面板出现 | 停留约 | 标题 | 每边卡片 |
|---|---|---|---|---|
| 10 月 10 日 16:57 训练录像 | 1304.47 秒 | 2.0 秒 | 胜利 | 7 / 7 |
| 10 月 10 日 01:39 训练录像 | 1797.63 秒 | 1.3–1.6 秒 | 胜利 | 7 / 7 |
| 10 月 9 日 08:38 官方 AI 对局 | 759.19 秒 | 3.9 秒 | 战败 | 7 / 7 |
用固定条带(标题条 + 按钮行)与一张结算页做相关来查找,每段只有一个结算页。来源确定为训练的 3 个已保存 App 会话里没有结算页;来源不明的会话没有打开。共保存 38 张原生帧(面板出现前几帧、出现后最初 0.1 秒、闪白和稳定后若干帧)。
方法
画面特点(三局一致):
- 面板瞬间出现,没有淡入;左红旗、右蓝旗。每边第 1 行 4 张卡、第 2 行 3 张(只见过 7 对 7)。
- 出现后约 0.1 秒内:卡片是干净的生物头像和数量,还没有损失行。
- 然后每张有损失的卡闪白一下(每张 30–70 毫秒,顺序不定),之后才出现损失行。
- 之后很多卡上出现时强时弱的红色骷髅,盖住生物的脸。骷髅不等于全灭:16:57 局有两张带骷髅的卡损失小于数量(16/-8、18/-12)。
- 临时部队(如召唤的火焰幼虫)没有卡。
- 标题是录像玩家的结果,不指出哪边是自己。
参考:数量和损失在稳定帧原生裁图上逐个目视读;兵种用出现后第一帧的干净头像与知识库标准图标逐个比对,08:38 局还与同一录像的战斗日志对上。共 42 张卡:30 张损失等于数量(都带骷髅),8 张损失小于数量且无骷髅,2 张损失小于数量但带骷髅,2 张没有损失行。
读取器(提案模块 v1):
- 是不是结算页:标题框和按钮框各 OCR 两次(原图和 3 倍放大,都 ≥0.80 且一致),必须读到“胜利/战败”或“接受结果”。
- 找卡:在固定搜索区里,对每个候选位置计算卡片四条边被图像边缘覆盖的比例,取四边最小值 ≥0.80 的峰;再在 18 像素内精确重定位(原型曾在闪白的邻卡旁错位 14 像素)。
- 数量:合并卡中心 ±36 像素内的白色列段,左右各留 16 像素再 OCR,两次一致且只接受 1–4 位数字。留边太窄会丢掉开头的 1 或 2,太宽会把 7 读成 77。
- 损失:卡下橙红色列段,第一段是骷髅图标,从第二段(减号)开始 OCR,必须是“-数字”。没有损失行时,只有画面已稳定(有损失行、没有卡在闪白、搜索区没有大块白色)才记为 0,否则未知。损失大于数量时两者都不保留。
- 兵种:复用行动条卡片的标准头像匹配器,把卡片上部放大 1.10 倍后匹配;门槛沿用行动条的 0.80 / 0.03。闪白的卡不认。
- 哪一边是自己(owner)永远留空,由 App/SE 用其他证据决定。
设置
帧按读取器自己的“稳定”判断和出现后是否 ≥0.3 秒分组;稳定且 ≥0.3 秒的帧(12 帧、168 次卡片读数)才是 App 应该读的帧。OCR 在 CPU 上。
结果
提案模块 v1(每个输出都通过了严格格式校验):
| 字段 | 稳定帧(12 帧,168 张卡) | 出现后最初的帧(12 帧,168 张卡) |
|---|---|---|
| 是不是结算页 | 12/12;面板前 12 帧都判为非结算页 | 12/12 |
| 标题、旗子颜色 | 12/12、24/24 | 12/12、24/24 |
| 找到卡 | 168/168,无多余 | 120/168(48 张在闪白),1 张多余(数量损失都未知) |
| 数量 | 168 对,0 错 | 113 对,0 错,55 未读 |
| 损失 | 168 对,0 错(159 次读到数字,9 次是无损失行记 0) | 6 对,0 错,162 未读 |
| 兵种(门槛 0.80/0.03) | 23 对,0 错,145 未读 | 45 对,0 错,123 未读 |
| 兵种(实验门槛 0.60/0.06)* | 103 对,0 错,65 未读 | 109 对,0 错,59 未读 |
| 兵种第一名(不设门槛) | 133 对,35 错 | 110 对,10 错,48 未读 |
* 实验门槛是看过这三局干净帧的分数后定的,不是独立验证的工作点。
骷髅挡脸是兵种读不出的主要原因:原型评估中,稳定帧上不带骷髅的卡第一名 44/44 全对,带骷髅的卡第一名 89 对 35 错;出现后第一帧的干净头像第一名 104/104 全对。
App 能否知道结算页出现:把 38 帧按 App 方式缩小后交给生产的阶段判断,面板帧 26/26 场景名都是“胜利”(08:38 的战败也是——场景名只代表这种画面,不代表胜负),面板前 12 帧都是“战斗中”。因此 App 只需在看到这个场景名时发出结算页读取请求,不必改关键帧服务的判决。
耗时:CPU 上稳定帧中位约 24 秒(2 核、与其他进程并行),主要是约 56 次 OCR;非结算页约 1.6 秒。战斗已结束,不影响实时,但 App 必须在用户点“接受结果”之前把帧存下来。
失败与负结果
- 原型 v0 把“110”读成“11”(v1 改为合并卡中心附近所有白色段并精确定位后修好)。
- 原型 v0 判为“稳定”的 5 帧早期帧中有 3 帧其实还有卡在闪白——闪白的卡找不到边框,“没有卡在闪白”的检查失效。没有因此填错 0,但 v1 增加了“没有大块白色”的条件。
- 行动条的兵种门槛对结算卡太严(分数普遍 0.65–0.90);不设门槛又会错 35 张。
- 01:39 雪地背景透过面板,条带相关只有 0.65(16:57 是参考图所在局,不算独立)。
- 骷髅的含义没有弄清。
局限
只有 3 局、42 张不同的卡,数量和损失的 0 错不是准确率。只见过 7 对 7 的布局;升级形态头像相近的混淆样本太少;英雄身份没有读。
结论与下一步
数量和损失可以稳定读出,兵种的瓶颈是骷髅挡脸。接入方案:每次结算页最多读两次——面板出现的第一帧(干净头像认兵种)和至少 0.5 秒后的一帧(读数量和损失);SE 只用稳定且读成功的读数,按旗帜颜色分我方/敌方,有兵种时按兵种对应、没有时按开局数量对应,生成“开局数量减损失”的结束读数或列出不一致。10 月 15 日已按此接入生产;真实结算帧经生产路由的检查、App 端回放验证和界面显示当时尚未完成。
Comments