TT Lab
博客

한국어 English 日本語 中文

开始
博客

博客

寻找球:从 TrackNet 到 WASB、BlurBall —— 热力图、多帧、模糊的中心

状态:草稿(2026-10-13),已反映实测结果。 我们的数值是 2026-10-11 至 12 在服务器 GPU(24GB 级别)上,直接加载 BlurBall 预训练权重且不经微调测得的值。论文数值单独标记为“论文”。引用的源码标注了 commit 并在简短化后引用。 编写规则:以实测数据为准,未测得的数据标记为“未实测”。

目录

1. 难点所在

乒乓球的直径为 4cm。在侧面拍摄、能看到整个球台的 1080p 实验室视频(TT3D)中,测量得到的球直径在中心为 11–12px,为了输入模型而缩放到 512×288 时,就只剩下大约 3px 了。此外,它的速度极快。以 70km/h(约 20m/s)飞行的球在 1/120 秒的曝光时间内会移动 17cm,在 1/60 秒内会移动 33cm。这意味着会留下 模糊轨迹。不仅如此,运动员的手和球拍会遮挡球,天花板的荧光灯和白色的鞋子也看起来很像球。

因此,如果直接使用通用的目标检测器(寻找人或汽车的边界框检测器),效果往往不好。该领域有专门寻找球类的谱系,TT Score 使用的 BlurBall 正是这一谱系的顶峰。

2. 直觉:不猜坐标,绘制地图

找球模型不会直接输出“球在 (x, y)”这样的两个数字。相反,它会绘制一张与输入尺寸相同的黑白图像,即 热力图。这是一张用 0–1 为每个像素涂上“此处是球的概率”的地图。标签也是在球的位置画出一个小型高斯山丘的地图,并与每个像素进行比较。

这样做有三个原因。

  1. 按像素学习位置误差。 如果只猜两个坐标,代表“错得有多离谱”的信号只有两个数字,而地图上的数万个像素各自都能提供学习信号。目标越小,这种差异就越明显。
  2. “无球”状态更自然。 如果整张地图都很暗,就说明没有球。坐标回归在没有球的时候也会指向某个地方。
  3. 可能存在多个候选。 如果球和荧光灯都被涂得很亮,可以把两者都留作候选,然后在后面挑选能连成轨迹的那一个。

第二个思路是 同时输入多个帧。只看单张图,根本分不清白色的点是球还是荧光灯。连续看 3 张图就能区分什么是运动的、什么是静止的。这就像人在视频中比在静态截图中更容易找到球一样。

입력: 연속 3프레임(RGB) → 9채널 288×512 t−2, t−1, t HRNet 계열 몸통(149만 파라미터) 원래 해상도 1/8 해상도 갈래를 나란히 두고 계속 섞는다 출력: 히트맵 3장(0–1, 프레임마다 한 장) 실시간은 마지막 장만 쓴다 후처리: 0.5 로 자르기 → 이어진 덩어리 찾기 위치 = 히트맵 값으로 가중한 중심, 신뢰도 = 값의 합 덩어리 주축 길이·각도 = 번짐의 길이·방향 라벨을 어디에 찍나 — 번진 공 하나 끝점(최신 위치) 가운데(BlurBall) 노출 시간 동안 공이 지나간 자국 끝점은 셔터가 닫히는 순간에 달려 흔들리고, 가운데는 노출의 중간 시각이라 일정하다
图:输入连续 3 帧以获得 3 张热力图并缩减为块的过程,以及模糊球的标签位置

3. 谱系:TrackNet → TTNet → TrackNetV2 → WASB → BlurBall

TrackNet(2019):热力图与多帧

这是为了在网球转播中寻找球而提出的模型(arXiv 1907.03698)。它使用 VGG-16 的前 13 层提取特征,并通过反卷积将其放大,从而生成 640×360 的热力图。它对比了输入单张的方案(Model I)和输入连续 3 张的方案(Model II),其精度和召回率从 95.7% / 89.6% 提升到了 99.8% / 96.6%(论文,将同一场比赛按 7:3 划分进行评估)。这是首次用数字展示多帧效果的案例。

解码很简单。通过在 128(0–255 之间)处对热力图进行阈值处理以将其转换为黑白图像,并使用圆检测(Hough)来寻找圆, 只有在精确匹配到一个时 ,才将其中心输出为球。在同一篇论文中,未混淆比赛的 10 折交叉验证的召回率为 75.7%。这已经暴露出该领域反复出现的教训:在一个比赛中表现良好的模型,在从未见过的比赛中性能会显著下降。

标签规则也值得记住。TrackNet 在球发生模糊时,会在痕迹的**最新位置(最前端)**打上点。而 BlurBall 正是对这一规则提出了质疑。

TTNet(2020):乒乓球、120fps 以及 OpenTTGames

这是一个为了实时分析乒乓球比赛而开发的模型(arXiv 2004.09927),我们用于评估的 OpenTTGames 数据集正是与该论文一同公开的了。在 120fps 全高清视频中,将连续 9 帧堆叠成通道(输入 27 通道)。采用两阶段结构:先将整个画面缩小到 320×128 大致定位,再从原图中裁剪该区域进行精确查找。

输出很有趣。它不是 2D 热力图,而是 两个长度分别为 320 和 128 的 1D 向量(x 轴、y 轴)。将 2D 地图拆分为两个轴的 1D 分布可以减少计算量。第四篇中的 RTMPose (SimCC) 也采用了相同的思路。论文报告称:事件识别率 97.0%,球检测率 97.5%,整个流水线耗时 6.0ms(单张桌面级 GPU)(见论文)。在我们 60fps 的手机视频上尚未进行实测。

TrackNetV2 (2020):输入 3 帧,输出 3 帧

这是针对羽毛球改进的版本。通过将其更改为 U-Net 结构,采用 输入 3 帧并同时输出 3 张热力图的(MIMO) 方式,将速度从 2.7 FPS 提升至 31.8 FPS(见论文摘要)。其输入大小 288×512 和“输入 3 帧并输出 3 帧”的做法被后来的 WASB 和 BlurBall 直接继承。

WASB (2023):小型 HRNet 与连通域后处理

这是一个旨在广泛用于足球、网球、羽毛球、排球和篮球这五项运动的基准模型(BMVC 2023,arXiv 2311.05237,代码采用 MIT 协议)。乒乓球并不在那五项之中。其骨干网络是小型 HRNet(见下文第 4 节),拥有 150 万个参数。输入是 (B, 9, 288, 512),即 RGB 3 通道 × 3 帧,输出是经过 Sigmoid 的 3 张热力图。

后处理不使用 TrackNet 的圆检测,而是使用 连通域查找。以下是原代码库中的相关部分。

# nttcom/WASB-SBDT src/detectors/postprocessor.py @923462ca, 49–59행(MIT, NTT Communications)
if np.max(hm) > self._score_threshold:
    th, hm_th        = cv2.threshold(hm, self._score_threshold, 1, cv2.THRESH_BINARY)
    n_labels, labels = cv2.connectedComponents(hm_th.astype(np.uint8))
    for m in range(1,n_labels):
        ys, xs = np.where( labels==m )
        ws     = hm[ys, xs]
        if self._use_hm_weight:
            score  = ws.sum()
            x      = np.sum( np.array(xs) * ws ) / np.sum(ws)
            y      = np.sum( np.array(ys) * ws ) / np.sum(ws)

在 0.5 处进行截断,将每个连通域按热力图值加权得到的中心作为位置,并将值的 和作为分数。使用求和意味着大而深的连通域会胜出。论文中解释称,连接帧之间的追踪器会通过“位置 + 速度 + 加速度/2”来预测下一个位置,但公开的代码并没有使用预测,而是 在上一个位置 300px(基于原图)范围内的候选者中选择分数最高的一个。当论文与代码不一致时,以代码的实际动作为准。

BlurBall (2025–2026):模糊的中心

这是针对乒乓球对 WASB 进行修改后的模型(arXiv 2509.18387,CVPRW 2026,代码采用 MIT 协议)。改变的主要是 标签。

输入和输出的形状与 WASB 相同((B, 9, 288, 512) → 3 张热力图)。模糊的长度和角度不是通过单独的输出头,而是通过 热力图连通域的形状在后处理中读取。

# cogsys-tuebingen/BlurBall src/detectors/blurball_postprocessor.py @2f0f5496, 48–50·60–71행에서 줄임(MIT)
angle = 0.5 * np.arctan2(2 * moments["mu11"], moments["mu20"] - moments["mu02"])
mean, eigenvectors = cv2.PCACompute(coords.astype(np.float32), mean=None)
principal_axis = eigenvectors[0]                 # 가장 긴 축
projected = np.dot(coords - mean, principal_axis)
l = projected.max() - projected.min()            # 79행에서 l / 2 를 반길이로 저장

这里同样存在两个论文与代码的差异。论文解释说连通域的置信度是热力图的 平均值,但代码中和 WASB 一样是 求和。关于角度,论文通过主轴向量计算,而代码通过图像矩计算。

论文中的数值(自定义乒乓球测试集,288×512,桌面级 GPU)为 F1 96.52、79 FPS,这些数据经常被一起引用,但 这两个数字来自不同的设置。96.52 是以单帧为步长滑动的 1-step 推理,79 FPS 是以三帧为步长的 3-step 推理(3-step 的 F1 为 96.16)。论文表格中没有给出 1-step 的 FPS。

4. HRNet:完整保留分辨率

WASB 和 BlurBall 的骨干网络属于 HRNet(CVPR 2019,arXiv 1902.09212)系列。普通的分类模型会将图像缩小到 1/2、1/4、… 1/32 来压缩“这是什么”。一个 3px 大小的球哪怕只缩小到 1/8,也会比单个像素还要小。即使再放大,位置也会变得模糊不清。

HRNet 自始至终保持原始分辨率的分支,同时在旁边逐个添加低分辨率分支并行运行,并在分支之间反复融合信息。 低分辨率分支负责“附近有人且有桌子”的宏观上下文,高分辨率分支则负责“精确到这个像素”。我们使用的配置是 4 个分支,通道数为 16、32、64、128,并且将初始主干(stem)的步长设为 1,直接将输入分辨率送入分支中(在我方代码的 "STEM": {"STRIDES": [1, 1]}).

5. 在我方代码中

模型代码(MIT)并未放入代码库中,而是存放在服务器的存储空间中读取。因为如果引入他人的代码,我们就必须跟着修改其副本。代码库中只有其周边部分(live/blurball.py, batch/model_blurball.py).

权重验证。 下载的权重在比对 sha256 后,仅以 torch.load(weights_only=True) 的方式读取。由于 PyTorch 检查点是 pickle 格式,因此可能会执行任意代码。如果比对错误或 weights_only 无法读取时将停止启动。

预处理。 RGB,512×288,使用 ImageNet 均值和标准差进行归一化。因为浏览器已经将图像缩小到 512×288,所以服务器不会更改大小。我曾因此吃过一次大亏。将解码后的数组仅通过 transpose 交换轴进行堆叠后,张量变成了 channels_last 布局,导致 cuDNN 走了一条与预热时不同的计算路径。预热后的第一个实际帧耗时 12.5秒 。 np.ascontiguousarray 修改了一行代码就解决了。

后处理。 为了找到与原始仓库相同的连通块,额外生成了一个用于屏幕显示的值。

# live/blurball.py blobs() 에서 줄임
_, th = cv2.threshold(hm, SCORE_T, 1, cv2.THRESH_BINARY)          # SCORE_T = 0.5
n, labels = cv2.connectedComponents(th.astype(np.uint8))
for m in range(1, n):
    ys, xs = np.where(labels == m); ws = hm[ys, xs]; sw = float(ws.sum())
    x, y = float((xs * ws).sum() / sw), float((ys * ws).sum() / sw)
    pts = np.stack([xs, ys], 1).astype(np.float64); pts -= pts.mean(0)
    vals, vecs = np.linalg.eigh(np.cov(pts.T))                     # 주축 = 번짐 방향
    pm = pts @ vecs[:, 1]; length = float(pm.max() - pm.min()) / 2.0
    out.append({"x": x, "y": y, "score": sw, "peak": float(ws.max()), "len": length, ...})

score(和)用于跟踪器选择候选时, peak(最大值,0–1)用于在屏幕上显示置信度。由于“和”会根据连通块的大小超过 1,因此不适合作为展示给人类看的值。与原始仓库不同,这里的角度是通过协方差的主轴计算得出的。

实时与录像的区别。 实时模式下,每个新帧都会滚动最近 3 张图像的窗口,并且 只使用最后的那个热力图 (OUT_INDEX = 2)。录像模式使用不重叠的 3 张图像窗口,使用全部三张图像。因此,实时模式每帧的 GPU 工作量是三倍(第 1 篇第 3 节)。

6. 实测:能找到多少

基准线(2026-10-11)

条件:OpenTTGames 测试 7 场比赛,仅使用原始 120fps 的偶数帧(60fps),仅使用带有标记的 3,483 帧,在 512×288 下与正确答案相差 5px 以内即视为正确。权重保持预训练时的状态。

指标 值
精确率 / 召回率 0.9817 / 0.9785
位置误差(RMSE) 0.594px(以 512 为基准),以原始 1920 为基准时为 2.23px
边界前后 ±2 帧的召回率 0.988
时间(单个窗口,录像模式) 每帧 3.42ms(293fps),8 个窗口组合 2.81ms
时间(单个窗口,实时模式,空卡) 10.5ms(fp32),8.0ms(fp16)
GPU 内存(torch 最大预留量) fp32 单个窗口 0.35GB,8 个 2.6GB,16 个 5.2GB。fp16 单个窗口 0.22GB
模型 权重 5.8MB,149 万个参数

弱点有三个。

球的状态 召回率
几乎静止的球(60fps 帧之间原始基准小于 10px) 0.790
与运动员重叠的球(与数据集中的人体掩码重叠) 0.863
极快的球(80px 以上) 0.855

静止的球大多是发球前拿在手里的球,对得分影响很小。重叠的球和极快的球才是真正痛点所在。

test_7 的精确率低至 0.882,但这并不是模型的问题。 这场比赛中有 104 处标记为“无球”,其中 41 处实际上能看到球(经目视确认 6 帧)。模型正确找到的球被判定为了“找到了原本不存在的球”。扣除这 41 处后,精确率为 0.9937。关于数据集的内容将在第 7 篇中详细介绍。

与其他模型对比(2026-10-11–12)

使用 BlurBall 作者公开的对比模型权重在相同条件下进行了测量。

模型 精确率 / 召回率 重叠的球 静止的球 极快的球
BlurBall(阈值 0.5) 0.982 / 0.979 0.863 0.790 0.855
BlurBall(阈值 0.3) 0.980 / 0.985 0.903 0.862 0.868
WASB,使用中心标签训练 0.985 / 0.964 0.879 0.707 0.855
WASB,使用端点标签训练 0.976 / 0.934 0.774 0.696 0.513
MonoTrack 0.983 / 0.949 0.798 0.646 0.829
TrackNetV2 0.992 / 0.822 0.669 0.398 0.566
ResTrackNetV2 0.993 / 0.712 0.532 0.160 0.237
BlurBall + WASB,通过热力图最大值合并(阈值 0.3) 0.980 / 0.989 0.935 0.895 0.882

有三点值得一读。

  1. 即使同为 WASB,使用中心标签训练的模型也比使用端点标签的模型更好。 在极快的球上为 0.855 对 0.513。这是模糊中心标签有效的直接证据(OpenTTGames 的标记更偏向中心也是原因之一)。
  2. 性能提升的大部分原因不是因为叠加了模型,而是因为调低了阈值。 即使单独使用 BlurBall,只要将阈值降至 0.3,召回率就会从 0.979 升至 0.985。叠加 WASB 带来的纯收益是召回率 +0.35%p。
  3. 在干净的视频中,寻找更多的球并没有提高分数。 在 7 场比赛 57 个多拍测试中,BlurBall 猜对胜者的次数为 53,阈值 0.3 为 52,两个模型结合也是 52。因为降低阈值也会增加虚假边界。

在恶劣条件下 (2026-10-11–12)

我们对同一个测试视频施加了决定性的退化进行测量(球检测召回率)。

条件 BlurBall 单独 BlurBall + WASB 结合 (0.3)
干净 0.979 0.989
黑暗 + 传感器噪声 0.685 0.820
低分辨率(缩小到 320×180 后放大) 0.898 0.957
长曝光(1/60 秒模糊) 0.841 0.869
球被遮挡(肤色椭圆) 0.842 0.868
形似球的干扰物 0.969 0.927
30fps 0.984 0.985

在昏暗的地方,结合两个模型有很大帮助(57个多拍测试中的胜者从 36 升至 45),但在形似球的干扰物面前,WASB 产生了大量虚假检测,情况反而变糟了。 不存在永远稳操胜券的组合。 而且结合后 GPU 时间翻倍(单窗口 10.5 → 20.0ms)。因此我们目前一直仅常态化运行 BlurBall,并正在试验“仅在球信号较弱时开启第二个模型”的方法(进行中)。

在 OpenTTGames 之外 (2026-10-11)

视频 精确率 / 召回率 错在哪里
OpenTTGames 测试(基准) 0.982 / 0.979 —
TT3D 实验室,侧面 50fps 0.929 / 0.860 错过的大多是发球前拿在手里的球
TT3D 实验室,斜向 60fps 0.894 / 0.820 20 个远距离错误中有 15 个是 天花板荧光灯. 除去画面上方的条纹,精确率为 0.956
LATTE-MV 国际比赛转播,30fps 640×360 0.815 / 0.722(一致度) 40 个不一致中有 25 个是指向了 同一模糊痕迹的另一端处的点

最后一行完美地展示了这篇文章的主题。LATTE-MV 的球坐标不是人工标注,而是其数据管道的追踪结果,并指向痕迹的一端。BlurBall 指向中心。被评判为“不同”的两者中有 62% 实际上是同一个球。如果标注规则不同,即使是同一个模型,评分也会不同。

7. 为什么选择 BlurBall,以及下一步

作为下一步,我们正在调查和实验抗遮挡模型(仅在遮挡帧开启的条件模型)以及使用手机视频的微调。结果出来后会补充到这篇文章中(进行中)。目前最大的课题是手机视频还没有人工标注的真值集。

Titi 的一言。 同样的 WASB 模型,通过教导它拍摄模糊球的“中心”而不是“边缘”,快球召回率从 0.51 提高到了 0.86。这就是一个标注约定的力量。

阅读更多原理。 完整保持热力图和分辨率的结构整理在 视觉模型阅读第 1、3 篇:U-Net 与 HRNet中,热力图损失与训练技巧整理在 第 4 篇:损失函数与训练技巧中,并附带了原始论文。

参考

登录后即可点赞

评论

还没有评论。

登录后即可发表评论