状态:草案(2026-10-13),已引入实测数据。 本文中的准确率和时间均为作者亲自测量,表格中均附上了测量日期和条件。论文中的数值单独标注为“论文”,未能测量的则记为“未实测”。由于研究仍在进行中,数字可能会发生变化。编写规则:以实测数据为基础,未能测量的标注为“未实测”。
目录
1. TT Score 旨在解决的问题
如果在球桌旁用三脚架立起一部手机,屏幕上的记分牌就会在每个回合自动为比分加分。如果判定存疑,则会弹出“需要确认”,由人工点击一次进行修正。修正后的记录将成为下一步训练的数据。
说起来简单,但要让机器完成一次加分,必须明确以下所有信息:
- 球在屏幕的什么位置。直径 4 厘米、快时时速超过 100 公里的球在每一帧中位于何处。
- 球桌在屏幕的什么位置。为了判断球是否触台、触碰了哪半边球桌,需要获取球桌的四个角。
- 发生了什么事。需要从球的轨迹中提取出“弹击(Bounce)”、“擦网(Net)”、“出界(Out)”、“回合结束(End of rally)”等事件。
- 因此是谁赢了。必须根据乒乓球规则对事件的先后顺序进行比对,从而确定胜者及原因。
本系列文章将逐一剖析回答这四个问题的模型与规则。本文即是整体的架构指南。
2. 四层分层架构图
| 层 | 职责 | 使用技术 | 运行位置与耗时 |
|---|---|---|---|
| 第 1 层:识别 | 从视频帧中寻找球的坐标、球桌的角 | 球:BlurBall。球桌:人工点击、SAM 2.1。辅助:姿态(RTMPose、MediaPipe)、声音(实验中) | 服务器 GPU,寻球窗口每个 10.5ms |
| 第 2 层:事件 | 从球的轨迹中提取弹击、擦网、出界、结束事件 | 手写规则(events.py) |
CPU,每个样本 0.1–0.4ms |
| 第 3 层:裁判 | 根据事件顺序确定回合胜者及原因 | 乒乓球规则(referee.py, rules.py) |
同 CPU 进程 |
| 第 4 层:延迟确认 | 仅由人工(未来也将引入视觉语言模型)重新查看存疑的回合 | 人工点击一次 | 异步,不阻塞比分更新 |
为什么要进行分层
最重要的原因是 判定规则必须比模型更先做到准确无误。无论球的坐标多么精确,如果错误地移植了诸如“发球时必须在己方落一次、对方落一次”之类的规则,比分就会出错。因此,第 2 层和第 3 层与模型解耦,作为 纯 Python 函数独立存在。在没有视频的情况下,仅通过合成轨迹和事件就能测试所有规则,即便将寻球模型替换为其他模型,裁判逻辑也无需更改。
第二个原因是 为了隔离故障点。如果端到端只有一个大型模型来接收视频并输出比分,当出现错误时,我们将无从得知是未能寻到球,还是错误应用了规则。通过分层,我们可以将相同的评分运行在“模型找到的球”、“标准答案球”、“标准答案弹击”这三个输入上,从而测量出误差究竟产生于哪一层。第 5 章将通过这种方法证明:“剩余的大部分误差并非产生于寻球,而是产生于事件提取”。
第三个原因是 开源许可与成本。每一层都可以选择最小的工具。寻球只需一个 149 万参数的模型,而裁判则完全不需要 GPU。
各层中选择了什么、去除了什么
| 位置 | 选择项 | 选择理由 | 去除项及理由 |
|---|---|---|---|
| 球 | BlurBall(代码 MIT,149 万参数) | 采用对模糊球的 中心打标签的方式,契合 60fps 下的长时间拖尾,在五个对比模型中单独性能最好(第 2 章) | TrackNetV2·MonoTrack·WASB 单独使用:召回率低至 0.71–0.96。组合使用虽然在暗光视频中有优势,但需要双倍的 GPU 时间 |
| 球桌 | 人工点击四次,实验中采用 SAM 2.1 tiny(Apache-2.0,3890 万参数) | 摄像机是固定的,因此比赛开始时只需进行一次。人工点击直接作为提示词(第 3 章) | YOLO 系列分割模型:AGPL 条款。SAM 3:独立许可证,需要批准访问权重,拥有 8.48 亿参数 |
| 姿态与球拍 | RTMPose(Apache-2.0)、MediaPipe Pose(代码 Apache-2.0) | 已在教练画面中使用。比分判定中仅作为“需要确认”的信号(第 4 章) | 利用姿态信息剔除弹击会导致胜者准确率下降 1.1–5.5%p |
| 声音 | 未接入引擎 | 在干净的录音中可以区分 99% 的球台声音,但在实际训练场的录音中效果未经证实(第 6 章) | — |
| 延迟确认 | 目前由人工负责 | 将修改比分的权限交予人工 | 将视觉语言模型用于判定:基本每秒处理一张图,因此输入中不包含弹击瞬间(第 8 章) |
3. 时间预算:16.7ms 与 1.5 秒
实时记分牌面临两个时间限制。
- 帧预算。 60fps 的视频每隔 16.7ms 就会产生一个新帧。如果无法在此期间完成处理,就会发生掉帧。如果是 30fps,则是 33.3ms。
- 判定预算。 这是指回合结束后,等待比分更新的最长容忍时间。目标设定在 1.5 秒以内。
单帧的实际耗时
| 部分 | 耗时(预热后的中位数) | 条件 |
|---|---|---|
| 寻球,实时(每新帧处理最近 3 张图的窗口) | 10.5ms(fp32),8.0ms(fp16) | 2026-10-12,服务器 GPU(24GB 级别)处于闲置状态,预热 30 次后进行 200 次 × 3 轮的中位数 |
| 寻球,录像回放(不重叠的 3 张图窗口,8 个窗口打包) | 每帧 3.42ms(1 个窗口),2.81ms(8 个窗口打包) | 2026-10-11,同 GPU。单个窗口同时处理 3 帧,因此每帧的值约为窗口耗时的三分之一 |
| 寻球,当与其他任务共享显卡时 | 单个窗口 40–46ms | 2026-10-11,同时运行 1 个语音合成和 2–3 个分割实验时 |
| 事件 + 裁判(对最近 2.5 秒的每个样本重新运行) | 每个样本 0.118ms(中位数),0.422ms(95 分位) | 2026-10-13,笔记本 CPU,32 万个样本 |
两行寻球耗时相差三倍的原因是实时设计的核心所在。BlurBall 接收 3 个帧并输出 3 张热力图。录像回放只需按不重叠的方式每 3 张图滑动窗口即可,而实时处理则要求每当新帧到来时,都用“包含刚刚到达的帧在内的最近 3 张图”重新运行窗口,并且只使用最后一张热力图。这是一种以三倍的 GPU 工作量为代价,将延迟控制在单帧间隔之内的取舍。如果使用中间的热力图,虽然可以同时看到前后帧,但必须多等待一帧,而在实测中,这两种方式的寻球差异在 1%p 以内(约 300 帧样本)。
总结来说,在空闲显卡上,单个会话消耗了 60fps 预算的大约 63%(10.5 / 16.7ms)。如果将显卡与其他任务共享,单个窗口的耗时将超过 40ms,不要说 60fps,连 30fps 都无法维持。因此,操作逻辑是 不排队等待积压的窗口,直接丢弃。 只保留一个待运行的窗口位置,如果 GPU 跟不上,新窗口就会覆盖该位置。因为一旦排队,延迟就会无休止地增长。在 2026-10-11 的测量中,处理速度落后于 30fps 的部分(发送帧的 22–28%)被丢弃了,延迟也并未因此增加。
当前的实时演示中,浏览器发送的是经由 512×288 缩减后的 JPEG(画质 0.7,实测 12–18KB),发送间隔为 30fps。因为如果发送原图,带宽成本会超过 10 倍,服务器用于缩图的工作量也会激增。在开发环境中,从浏览器发送到收到响应的中位数为 65ms,90 分位为 84ms。经过实际互联网的生产网络由于路由不同,目前处于未实测状态。
判定所需耗时
事件层采用的规则是:“如果在最后一次弹击后的 1.5 秒内没有新的弹击,则回合结束”。1.5 秒这个数值包含了 12 场实际比赛中 98% 的回合内弹击间隔(1,087 个中的 1,066 个)。不过,这是最慢的路径。如果球落出球桌,就会先触发“出界”;如果球在屏幕中消失,就会先触发“无球”结束。
2026-10-13 通过实际部署路径(下文第 4 节)测得的判定延迟如下。判定延迟是指产生判定结果的事件出现的时间,减去人工标注的回合结束标签时间的差值。
| 范围 | 判定延迟中位数 | 90% | 1.5 秒以内占比 |
|---|---|---|---|
| 实际比赛 12 场,275 个回合 | 0.16 秒 | 1.23 秒 | 98.9% |
| 其中测试赛 7 场,57 个回合 | 0.39 秒 | 1.32 秒 | 100% |
以上仅为算法等待的时间,不包含计算时间和网络时间。
4. 层间流动的数据
一旦进行分层,层与层之间的“契约”就变得至关重要。实际流转的数据如下:
| 边界 | 数据格式 | 备注 |
|---|---|---|
| 浏览器 → 第 1 层 | 512×288 JPEG、序号、拍摄时间戳(ms) | 超过 120KB 则丢弃 |
| 第 1 层 → 第 2 层 | 每帧 (t, x, y, conf) |
若无球则 x·y 为空。同时输出拖尾长度与角度,但目前的引擎尚未使用 |
| 球桌 → 第 2、3 层 | 四个角 → 屏幕坐标系到球桌平面坐标系的变换 | 比赛开始时一次性获取 |
| 第 2 层 → 第 3 层 | Event(t, kind, side, conf, vx, vx_in) |
kind 为 bounce·net·out·end。vx 为弹击后瞬间沿球桌长度方向的速度(球桌长度/秒) |
| 第 3 层 → 记分牌 | PointCall(winner_side, reason, confidence, t) |
winner_side 为空则为擦网重赛(Let)。置信度低于 0.6 则需要确认 |
有两点引人注目。首先,第 2 层 仅接收球的坐标 。视频像素不会越过第 1 层。其次,弹击事件中携带了“横向速度”。裁判利用这个数值来区分“像发球那样朝向网的球”和“将球击回给对手的球”。这单一数字大幅减少了实际比赛中的误判比分(第 5 章)。
5. 当前进展:2026-10-13 基准线
本评估使用公开数据集 OpenTTGames 中的 12 场实际比赛(5 场用于训练,7 场用于测试),以及在其基础上标注了回合结束原因的 Extended OpenTTGames 标签。测试对象为 275 个已知发球方的回合,核心指标为 回合胜者准确率。
| 路径 | 胜者正确 | 错误且无需确认 | 需要确认 | 无判定 |
|---|---|---|---|---|
| 录像评分(看完整个回合后判定) | 91.3% (251/275) | 13 | 108 | 3 |
| 发布的实时路径(每帧重新运行最近 2.5 秒) | 90.2% (248/275) | 15 | 129 | 2 |
| 仅限 7 场测试比赛,发布路径 | 87.7% (50/57) | 6 | 26 | 1 |
条件:球坐标直接使用 BlurBall 预训练权重(无微调),球台边缘从数据集的分割掩码中获取,引擎版本为 2026-10-13。仅在笔记本电脑 CPU 上重新运行了引擎。
在解读这些数字时,需要注意以下四个前提条件:
- 即使是同一引擎,表现也会因路径而异。 在画面清晰的视频中,录像评分和实时路径的差异仅为 3 个回合;但在黑暗或模糊的条件下,两种路径的排名会发生反转。因此,后续的所有实验都会同时记录这两种路径。
- 这是基于训练样本的分数。 规则引擎在调整时参考了这 12 场比赛。这 7 场测试比赛也是如此,因此该准确率会比在从未见过的视频上的表现更为乐观。
- 局限于单一体育馆和单一角度。 OpenTTGames 是在单个球场用固定侧面摄像机以 120fps 拍摄的(使用时降至 60fps)。手机拍摄、社区乒乓球馆的灯光以及其他角度的表现尚未进行实测。由于 BlurBall 的 26 个训练视频列表未公开,因此不确定是否与 OpenTTGames 重合。
- 边缘改变,数字就会改变。 使用 2026-10-12 通过 SAM 2.1 获取的边缘进行的录像评分为 93.1%(256/275)。由于该边缘文件已不复存在,基准线重新设定为数据集掩码边缘。边缘质量对分数的具体影响将在第 3 篇和第 5 篇中讨论。
6. 未来方向
剩余的误差大部分并非源于找球,而是源于 事件提取(第 5 篇)。因此,下一阶段的关注点与其说是“更好地寻找球的模型”,不如说是“区分弹跳与击球、过滤掉规则上不允许的顺序的信号”。2026-10-13 的模型研究包含三行权限结构。以下是研究与设计,效果尚未测量(正在进行中)。
- 感知。 分别为每个信号输出概率和“健康度”(0–1,当前信号是否可信)。对于球,常态化使用 BlurBall,仅在遮挡或黑暗情况下开启第二个球模型。加入球拍与姿态、声音(onset + 表面分类,优先进行同步和健康度判定)以及球台平面。
- 事件 → 裁判。 将当前的规则判定替换为将乒乓球回合顺序作为允许转移的 带约束的 Viterbi 解码。如果最佳路径与第二佳路径的分数差很小,则判定为“需要确认”(第 5 篇第 5 节)。
- 慢速确认。 仅将需要确认的回合剪辑发送给视觉-语言模型进行交叉验证,若与裁判结果不一致则进行标记(第 8 篇)。
同一研究选出的五个候选方案包括:引入规则语法的带约束 Viterbi、精细事件定位模型(如 AdaSpot)、声音表面分类与声音-视频同步、5 点球拍(RacketVision)以及抗遮挡球追踪(TOTNet)。我们将逐一使用相同的基准线(第 5 节)和相同的两条路径进行重新测量,并将其补充到本系列中。
7. 系列导览
| 篇 | 探讨内容 |
|---|---|
| 第 2 篇 寻球 | TrackNet → WASB → BlurBall。热图回归、多帧输入、模糊中的标注、HRNet |
| 第 3 篇 寻球台 | SAM 2.1、EfficientTAM、SAM 3。提示分割、记忆注意力、从掩码获取四个边缘与单应性 |
| 第 4 篇 姿态与球拍 | RTMPose (SimCC)、MediaPipe、RacketVision 的 5 点球拍 |
| 第 5 篇 事件与裁判 | 从轨迹中提取弹跳与击球的规则、裁判引擎、准确率从 66.9% 提升的历程、3D 极值规则与带约束的 Viterbi |
| 第 6 篇 声音 | onset 检测与表面分类。实际录音中无效的消极结果 |
| 第 7 篇 数据集 | 亲自统计 OpenTTGames、Extended、T3Set、TT Sounds、RacketVision、LATTE-MV 的表格与陷阱 |
| 第 8 篇 视觉-语言模型 | 为什么不将判定交由其处理 |
乒乓简言。 找准球和评好分是两码事。本系列将通过数字来追踪这两者之间的鸿沟。
参考
- 本系列的的代码路径以 TT Score 引擎文件夹为准。
ttscore/代表裁判引擎(纯 Python),live/代表实时工作线程,batch/代表录像视频工作线程,experiments/代表实验代码。 - 测量原始数据与方法:代码库
docs/tt/PERFORMANCE.md2.1·2.9.8、实时演示设计文档第 9 节、实验台账 E00 (2026-10-13)。 - OpenTTGames: https://lab.osai.ai/ (CC BY-NC-SA 4.0)
- Extended OpenTTGames: https://arxiv.org/abs/2512.19327, https://github.com/moamal01/table_tennis_data (CC BY-NC-SA 4.0)
- BlurBall: https://arxiv.org/abs/2509.18387, https://github.com/cogsys-tuebingen/BlurBall (代码遵循 MIT)