TT Lab
博客

한국어 English 日本語 中文

开始
博客

博客

自动判定:从发球到胜者,以及如何区分热身、练习与比赛

状态:草案(2026-10-26),已反映实测结果。 规则读取自 2026-10-25 的仓库代码(ttscore/, backend/static/tt/play/),数字是我们通过公开比赛视频亲自测算的值(日期和条件见各个表格)。使用手机拍摄的实际乒乓球馆视频的准确度尚未实测,因为目前还没有带标签的视频。 编写规则:以实测数据为基础,未能测算的部分标记为“未实测”。

目录

1. 自动判定是“建议”,而非记分牌

首先明确立场。摄像头记分牌真正的得分是第 2 篇中看到的 人输入并修正的历史记录。自动判定只是向该历史记录逐个提出诸如“本回合 A 得分,原因:出界,置信度 0.83”之类的 建议,只有被确认的建议才会成为历史记录中的得分栏(backend/static/tt/play/lib/camauto.mjs 前言“记分牌只有一个”)。因此,即使自动判定出错,也无需与人修正的历史记录单独匹配。

本文将跟随球坐标传入的那一刻起到芯片变成得分的全过程。

  1. 球坐标 → 事件(弹地·网球·出界·结束)
  2. 事件 → 裁判状态机 → 对打胜者
  3. 对打成组、死球、重新同步
  4. “需要确认” 判断
  5. 芯片与自动反映、人与机器的分工
  6. 在这中间穿插着 将热身·练习与比赛区分开的装置

。第 4 篇将介绍球坐标是如何生成的,前一系列的 第 5 篇则探讨了该引擎从 66.9% 提升到 93.1% 的历史。本文是 当前运行中规则的全貌。

2. 从球坐标到事件

工作线程仅保留最近 2.5 秒的球坐标(EventFeed, KEEP_S=2.5),每当有新样本输入时,便填补短暂的空白(3 个样本或以下)并重新提取事件(ttscore/events.py 的 detect_events)。由于是实时运行,无法预知未来,因此采用的是 不断重新读取最近区间的方式。

弹地:同时满足五个条件

只有在 同时 满足以下条件时才会判定为弹地。

条件 内容 原因
V 字形 画面 y 先增大(下降)后减小(上升) 弹跳球的基本形态
乒乓球台带内 乒乓球台顶面矩形内。每条边有 8px 的余量,末端边在平面上延伸到 0.15m 以外 弹地瞬间球中心比接触点高一个半径(20mm),映射到平面上会有偏移
间隔 与上一次弹地间隔 0.12 秒以上 避免重复计算同一次弹地
保持横向 前后横向移动都达到 2px 以上且方向相反则丢弃 在球台弹地的球会继续前进,击中球拍的球会返回。击球也会画出 V 字
丢弃网前 V 字 网 x ±2% 以内且击中网 ±2 帧以内的 V 字会被丢弃 挂网球的晃动

如果是从末端拍摄的画面(摄像头在端线后),则会多看一项。沿长度方向的速度必须达到 0.3m/s 以上。因为在末端画面中,画面 y 混合了高度和距离,容易产生假 V 字。

弹地的一侧(L·R)基于平面

弹地落在哪位选手的一侧,不是由画面的左侧或右侧决定的,而是通过 球台平面坐标来决定的。利用球台的四个顶点构建画面到平面(2.74m × 1.525m)的单应性矩阵(第 4 篇),将球接触点的坐标转换到平面上,并通过长度方向坐标 u 的正负来确定一侧(ttscore/table.py 的 ball_side)。这样一来,无论是从侧面拍还是从末端拍,公式都是一样的。如果矩形扭曲得无法被识别为矩形(可能是顶点弄错了),则会退回到旧规则,即基于网 x 基准线的左侧或右侧。因为扭曲矩形的平面变换会倾斜网线并颠倒两侧。

平面投影 仅在球接触球台的瞬间 准确。如果将空中的球投影到平面上,穿过摄像机中球的直线会与平面相交,球越高,偏移越远。因此,平面坐标仅用于判断弹地的一侧,空中区间的判断则单独进行。

横向速度:判定的关键

每次弹地都伴随着长度方向的横向速度。弹地后 vx,紧邻前 vx_in,单位是 台长/秒。由于它是除以球台长度而不是像素得到的值,因此与摄像机距离和分辨率无关。这一个数字在下一节的裁判中用于区分发球、回球和假弹地。

网球、出界、结束

置信度

每个事件都附带置信度。 conf = min(검출 신뢰도, 공백 신뢰도) ,空白置信度为 1 − 놓친 프레임 / (fps × 0.25초) 。如果在前方丢失球超过 0.25 秒,则为 0。这意味着期间可能漏掉了一次弹地,因此不可信。检测置信度也单独(det_conf)记载,用于发球的第一下弹地。

3. 裁判:不看“谁击球”

서브 대기 서브 시작만 받는다 직행 서버 쪽 바운드를 못 봄 서브 진행 네트 닿음 = 렛 후보 랠리 기대하는 쪽만 들고 간다 (받아야 할 쪽 S) 넘겨주기·튀기기 손에 든 공은 버리고 기다림 서버 쪽 바운드 네트 쪽 ≥ 0.7 리시버 쪽, 서버 쪽에서 온 방향 ≥ 0.7 리시버 쪽 바운드 1초 안 서버 쪽에 리턴 기대한 쪽 바운드 → 반대쪽을 기대 또·끝: 서버 득점 S 쪽 선수가 못 받음 서브 실패 판정 → 점수판의 득점 같은 쪽에 또 바운드 → 투 바운드 · 밖으로 → 아웃 아무 일 없이 끝 → 못 받음 · 서브 실패 → 리시버 득점 렛 → 점수 없음 0.25초 안 같은 쪽 두 바운드와 렛은 다음 이벤트까지 미룸 「누가 쳤나」는 보지 않는다. 바운드 순서와 가로 속도(테이블 길이/초)만 본다.
图:裁判状态机:从等待发球到发球进行·直达、对打、结束

裁判(ttscore/referee.py 的 RallyReferee)的核心思想在前言的第一行:st. 谁击球不是从视频中直接看到的,而是从弹地顺序推断出来的。 如果球在 S 侧弹地,接下来 S 侧的选手必须将其击打并落入对方一侧一次。如果未能做到(在同一侧再次弹地、未弹地直接飞出、无事发生直接结束),则 S 侧选手失利。唯独发球是个例外,球必须在发球方一侧弹地一次,然后在接发球方一侧弹地一次。

接触球拍是视频中最难找的事件。球被球拍遮挡、模糊、并融入选手身体。此设计在没有该事件的情况下也能计分。代价也很明显。如果漏掉一次弹地,或者夹杂了一次假弹地,“轮到谁击球”就会彻底错位。因此,以下大部分规则都是 过滤假弹地和对打外之球的装置。

状态有四个。 serve0(等待发球)→ serve1(发球进行)或 direct(直达)→ rally(对打)→ done(结束)。

等待发球:只接收发球的开始

在对打与对打之间,球也有很多运动。去捡球、传给对手、发球前在自己这侧弹几下、手里的球晃动。如果这些被捕获为事件,就会凭空产生得分。实际上,在将整场比赛输入引擎的第一盘中,49 个判定中有 20 个不是对打(传球 13 个,发球前在自己这侧弹 5 个等,2026-10-11, docs/tt/PERFORMANCE.md 2.6).

因此,在等待发球状态下, 只接收看起来像发球开始的球 。

# ttscore/referee.py _start() 에서 줄임
f = self._forward(ev, self.server, serve=True)    # 서버 쪽에서 네트 쪽으로 가는 가로 속도(바운드 앞뒤 중 큰 쪽)
if ev.side == self.server:
    if f is not None and f < SERVE_MIN_VX:        # 0.7 테이블 길이/초
        return False                               # 서브가 아니다 — 버리고 계속 기다린다
    self.phase = "serve1"
    return True
if f is not None and f >= TOWARD_NET_VX:          # 리시버 쪽에, 서버 쪽에서 날아온 방향으로 떨어진 공
    self.phase, self.expect = "direct", self.server
    self.conf = min(self.conf, AMBIGUOUS_CONF)     # 0.5 — 서버 쪽 바운드를 못 봤으니 확인 필요
    return True
return False

条件有两个。 落在记分牌已知的发球方一侧,且, 朝网的方向移动达到 0.7 台长/秒以上 。其余的球会被丢弃,也不会扣减置信度。数字 0.7 的依据是实测(公开比赛 12 场,2026-10-11)。

不接收记分牌发球方对侧“看起来像发球”开始的球。 如果接发球方向发球方抛球,球会从接发球方一侧向网的方向弹起并落在发球方一侧。形状与发球相同,但方向相反。将两侧都作为发球接收的变体,使 5 场比赛的假判定从 3 个增加到了 16 个。

有一个例外。在接发球方一侧, 沿从发球方飞来的方向(远离网且达到 0.7 以上)落下的球。这可能是漏掉了发球方一侧弹地的发球,也可能是未在发球方一侧弹地的发球失误。这作为 direct(直达)状态接收,并将置信度降低至 0.5 发送至需要确认。发球的第一下弹地由于被抛球和球拍遮挡而经常漏掉。因此,在直达之后如果接发球方再次弹地或直接结束,根据开关(TTSCORE_DIRECT_MISS,开启)视为 接发球方未接住(发球方得分) 。因为在实际视频实验(院长 E27)中,“再次弹地”判定 60 个中有 48 个,“结束”判定 49 个中有 36 个是发球方得分。

发球进行:1 秒内到达接发球方

serve1 在此状态下等待接发球方一侧的弹地。

擦网球:推迟到下一个事件

发球期间触网且(net) 如果球在接球方一侧弹地,则记为候选擦网(let)。不会立即宣告擦网,而是 推迟到下一个事件。

最初会立即判定擦网,但在实时处理路径中(2026-10-13)两次重现了擦网判定后的“死球”规则(第 4 节)导致后续真实对局的所有弹地被全部抛弃、该对局得分消失的问题。推迟判定的方案修复了该问题,离线对局级别的结果并未改变。

对局:在交替的方向间

在对局中,只保留「expect下一个弹地应当落下的方向」。

# referee.py feed() 의 랠리 부분에서 줄임
f = self._forward(ev, ev.side)                 # 바운드 뒤 가로 속도
if f is not None and f >= TOWARD_NET_VX:       # 네트 쪽으로 가는 「바운드」 는 가짜 — 버린다
    return None
if ev.side == self.expect:                     # 기대한 쪽: 정상. 다음은 반대쪽
    self.expect = flip(self.expect)
    return None
if ev.t - prev_bounce_t < DOUBLE_BOUNCE_SURE_S:   # 0.25초 안의 같은 쪽 두 바운드 — 미룬다
    self.pending = ev
    return None
return self._call(flip(ev.side), "double_bounce", ev)   # 같은 쪽에 또: 그 쪽 선수가 진다

出界与结束:最后弹地一侧的运动员未能接住

判定的置信度

单个判定的置信度为该对局内事件置信度的 最小值。但发球第一跳按扣除空白期后的检测置信度(det_conf)计算。因为发球第一跳之前的空白期是由抛球和球拍遮挡造成的,期间不可能漏掉弹地。在扣除这一点之前,发球第一跳的 70% 置信度为 0,这也是“需要确认达 86%”的主要原因(PERFORMANCE 2.6)。

4. 对局打包:死球、胜者、重新同步

一个裁判负责一个对局。将对局首尾相连制作成记分牌的工作由 ttscore/analyze.py 的 LiveScorer 完成。

5. “需要确认”:四个分支

每个判定都可以附加“需要确认”标记。即保持判定不变,让人工看一眼。附加该标记的途径有四条。

分支 条件 原因(why)
① 校准回归 学习得到的逻辑回归给出的“判定错误的概率” > 0.0442(校准 v2)。关闭校准则使用旧规则“置信度 < 0.6” cal + 两个对结果推动最大的特征组合(球弱、漏球、长对局、结束不明、未看到发球、发球方不同、判定类型)
② 底线带 落点在底线边界 ±0.08m 以内 edge
③ 信号冲突与球弱 若球模型之间互相冲突,或者对局区间内检测到球的帧比例低于 0.5,则将置信度扣减至 0.59 conflict 等
④ 球台 对局正在重新寻找球台或跨越了丢失区间 table

此外,带有重新同步信号(resync)的判定也会在芯片中被单独询问。

为什么单一置信度不够

最初的规则是“若对局置信度 < 0.6 则需要确认”。在 2026-10-14 评估该置信度是否真的能区分错误时发现 它无法区分(院长 E20,保持实时路径不变,公开测试 7 场比赛 × 11 种退化条件,共 597 个判定)。置信度 0.0–0.1 区间的正确率为 0.86,0.9–1.0 区间也是 0.86,用于区分错误的 AUC 为 0.51(抛硬币)。因为在 30fps 的实时路径中,只要漏掉一次球,最小值就会跌到 0.6 以下。

因此,引擎在判定瞬间利用已知的 19 个值训练了一个小型逻辑回归(ttscore/reviewcal.py)。包括置信度、检测置信度最小值、弹地平均置信度、弹地/事件数量、弱事件/空白事件数量、对局长度、最后是否为“结束”、是否观察到发球形态对、该侧是否与记分牌不同、判定原因等。计算时每个判定只需一次内积,因此没有实时开销。原理与训练将在第 4 篇中介绍。

判定 条件 未经确认即错误 (†) 需要确认 错误区分 AUC
置信度 < 0.6 测试 7 场比赛 × 11 种条件(597 个判定,E20) 26 395 0.51
校准 v1 相同 12 430 —
校准 v2(生产) 测试 7 场比赛 × 11 种条件(661 个判定,反映标签修正,E25) 20 → 8 450 → 497 0.71 → 0.73

v2 行中“→”前方是相同条件下的 v1。†v2 行包含了未经确认而放过的幽灵判定,因此不能与上方两行直接对比。校准选择阈值的方向是: 稍微增加需要确认的次数,但大幅减少人工盲目放过的错误回答 。阈值是在训练比赛单位的 5 折交叉验证中,以“需要确认次数不高于当前的前提下漏掉的错误最少”来确定的。

附加原因的理由也在实测中得到了验证。校准前原因处于空白状态,芯片无法说明需要确认什么(院长 E19-2)。现在,回归判定为需要确认的每一个判定,都会附带最多两个“将结果推向错误方向影响最大的特征”的人类语言词组发送出去。

底线带

球是击中底线(擦边)还是落在线外,是用单台相机最难区分的判定。如果落地点在底线边界 ±0.08m 以内,胜者保持不变,并发送至需要确认(TTSCORE_EDGE_REVIEW,院长 E34)。

6. 热身、练习与比赛的区分方法

① 휴대폰 화면 몸풀기: 득점 칸을 눌러도 점수 안 들어감 「경기 시작」 → 시작 시각을 이력에 적음 ② 자동 점수 모듈 기기 시계 → 프레임 시계(연결 순간 = 0) {type: score, on, start, server_side} ③ 웹 중계 로그인 · 몫 확인 뒤 그대로 전달 ④ 실시간 작업자 scorer.start(server_side, t) 지난 판정·구간을 잊고 새로 시작 ⑤ 엔진 시각 t 앞의 이벤트는 모두 버림 그 뒤에만 심판이 판정 이중 잠금: 시작 전에는 브라우저가 신호를 안 보내고 작업자도 판정하지 않는다(공 위치만 보냄). 서버 쪽은 점수판이 바뀔 때마다 따로 보낸다 — 사람이 고친 쪽이 이긴다.
图:“比赛开始”信号从手机屏幕到引擎的路径

引擎无法区分练习发球

乒乓球比赛以热身对局开始。双方互相对打几分钟,还会尝试练习发球。问题在于 练习发球与真实发球具有相同的形态。在发球方弹地一次,在接球方弹地一次,网前速度也与真实情况一致。

有实测案例。公开测试赛之一(test_4)在比赛开始 2.05 秒时拍到了赛前练习发球。从发球方到网侧为 4.2 台长/秒,球越过了球网。按照第 3 节的发球确认规则,无法将其与真实发球区分开。引擎将其当作第一分记下,而这一分导致整场比赛的发球轮次错位,该比赛的“对局后比分正确”在 21 个对局中为 0(PERFORMANCE 2.6)。

我们还评估了仅通过视频区分练习的方法。“丢弃记分牌第一发球方第一个完整发球之前的部分”(N1)以及“丢弃任意一侧第一个发球形态对之前的部分”(N2)。两者都没有改善(相比无信号引擎,5 场比赛的比分正确数 24 → 24,胜者 41 → 40,第 12 篇全篇无判定 18 → 21)。test_4 的真正第一球是一个挂网的发球失误,因此它不是“完整的发球”,并且两条规则都丢弃了真正的第一分。由于练习发球案例仅有 1 个,因此无法通过数据确定规则。 所以没有采用。

结论很简单: 比赛何时开始由人工告知。 这对运动员来说很简单,对机器来说几乎是不可能的任务。

“比赛开始”信号的传输路径

相机记分牌的热身状态(第 2 篇)正是接收该信号的门户。

  1. 画面。 开启相机即为热身状态(CamMatch.startedAt === null)。即使点击计分格也不会增加比分,而是会晃动“比赛开始”按钮。遥控器的开始键仅在热身期间有效。
  2. 开始。 点击“比赛开始”后, startMatch() 将比赛开始时间记入历史记录,并以 tt:match-start 事件发出 {type:'score', on:true, start, server_side} 。
  3. 对齐时钟。 自动计分画面(cam-auto.js)接收该信号并调用 scoreOn() ,将设备时钟(Date.now)记录的开始时间转换为 帧时钟(与操作人员连接的瞬间为 0)(startOffset)。因为操作人员不知道设备时钟,只知道附在帧上的时间。
  4. 操作人员。 经由网页直播,操作人员的会话调用 scorer.start(server_side, t) 并新建 LiveScorer 。遗忘过去的判定和区间,丢弃该时间之前的所有事件。
  5. 双重锁定。 若比赛尚未开始,浏览器不会发送此信号,且操作人员在收到信号前不会做出判定(仅发送球的位置和弹地显示)。浏览器端也不会将热身期间或比赛结束后到达的判定生成建议(autoProposal 为 null,代码注释“热身对局不是得分”)。

发球方也会随之调整。记分牌每次改变时(得分、撤销、人工修正发球权),都会将当前的发球方发送给操作人员,引擎借此校准下一局的发球方。 人工修正的发球方优先。

实测:单个信号的效果

在公开比赛期间,针对 0:0 开始、标签与规则相符的 5 场比赛(49 个回合),这是模拟由人工在第一记发球前瞬间按下「比赛开始」信号所测得的数值(2026-10-11,PERFORMANCE 2.7)。

指标(5场比赛 49个回合) 无信号 有信号
回合后得分(比分·局分)正确 27 / 49 36 / 49
胜者正确 44 / 49 45 / 49
非标签回合的判定(假得分) 3 2

test_4 从 0/21 上升到了 9/21。即使在第一记发球前 0.3、1、2、3 秒按下信号,结果也是一样的, 5秒前(在练习发球之前)按下则没有效果。因此,界面会引导用户在「热身结束、第一记发球之前」按下。

比赛中的「练习球」

即使比赛开始后,回合之间的球仍在继续运动。这由第 3、4 节的装置来过滤。

剩余局限

与记分牌无关的「练习」功能

这两个名字相似且容易混淆的功能与记分牌及自动判定 无关。

7. 芯片:人机职责分工

判定成为芯片的过程

작업자 판정 승자 쪽(L·R) · 이유 · 신뢰도 · 확인 필요와 사유 칩 — 그때의 왼쪽·오른쪽 선수로 바꿔 띄움 줄은 2개까지 · 최소 2.5초 보임 · 렛과 판정 없음은 안 띄움 칩에 답 맞음 선수 이름 무효 득점 칸을 누름 그 손이 칩의 답 (2점 막기) 답 없음 확실: 4초 뒤 확인 필요: 9초 뒤 그대로 넣음 이력(진짜 점수)에 득점 칸 맞음·같은 선수 → confirm · 다른 선수 → flip 무효 → 넣지 않음, void 시간이 지나 들어간 판정 → 고친 기록 남기지 않음 고친 기록은 영상 없이, 동의 표시와 함께 서버로
图:判定浮现为芯片并成为得分栏的路径与时间规则

当操作员发送判定时,浏览器会将其 以当时的左侧选手为准 进行转换并以芯片形式浮现。因为操作员是以原始视频的 L/R 为准叙述的,屏幕可能是镜像的,而且每局比赛座位都会互换。不提议擦网(Let)和无判定。

芯片上有四个按钮:「正确」、「(左侧选手)得分」、「(右侧选手)得分」、「无效」。

如果没有答复则直接录入

没有人会在每个回合都去按立在远处的手机。因此,如果没有答复,则直接录入(backend/static/tt/play/lib/scorestatus.mjs).

判定 等待答复的时间 依据
确信 4秒 —
需要确认 9秒 比人工查看芯片并答复的时间(约 2.5 秒 + 「请稍等」3 秒)更充裕,且在实际视频判定间隔(3.8–17.4 秒)之内

这条规则背后有段故事。2026-10-13 将公开比赛视频交由运营操作员测试时,摄像机记分牌在 50 秒内收到四个判定,比分却依然是 0:0。大多数判定都是“需要确认”,而屏幕在人工答复“需要确认”之前不会将其录入,直到下一个判定到来时便将其丢弃。并且它没有说明为什么没有录入。现在,“需要确认”也会在 9 秒后录入,如果在满 9 秒前有下一个判定到来,则会在那时录入之前的判定。

芯片队列最多为两个。当第三个判定到来时,将最旧的直接录入,且一旦浮现的芯片至少显示 2.5 秒。

答复的处理

答复 进入历史记录的栏目 修改记录
「正确」 得分(来源 auto) confirm
超时直接录入 得分(来源 auto) 不留记录(并非人工确认)
与判定相同的选手 得分(来源 auto) confirm
与判定不同的选手 得分(来源 tap) flip
「无效」 不录入 void

手势即为芯片的答复

最重要的一条规则是:首要规则是, 当芯片浮现时如果按下了得分栏,该手势即成为芯片的答复(handOverride)。如果是同一位选手则为正确,如果是不同选手则为修改。如果没有这条规则,人工会习惯性地按下手动记分,4 秒后自动判定也会录入,从而导致 一个回合得 2 分。

综上所述,职责划分如下。

人工 机器
确定比赛何时开始 确定(「比赛开始」) 丢弃该时间点之前的内容
谁在发球 可以修改,修改即获胜 从记分牌接收并使用,如果不一致则询问「发球正确吗?」
回合胜者 在芯片上答复或手动按下(手势即答复) 提出建议。如果没有答复,则在 4/9 秒后录入
模糊判定 查看 附加“需要确认”及原因
错误录入的分数 从历史记录中删除(第 2 篇) —

人工在芯片上的答复记录(修改记录)可能会保存在服务器中。视频不会被保存,仅导出同意用于训练的内容。该记录将去往何处以及至今如何使用将在第 6 篇中探讨。

8. 实测:目前准确度如何

所有行均是在公开比赛视频(OpenTTGames 测试 7 场比赛)中测得的数值。训练和阈值选择使用了其他比赛,测试比赛留到最后查看。不过,由于规则引擎本身是在 2026-10-11–12 观察测试比赛的过程中不断完善的,因此基于规则基准的测试分数是乐观的(负责人关于数据泄露的警告)。

测量 条件 结果
运营流程固定基准表 测试 7 场比赛 × 降级 11 种条件,标签 638,与运营相同的路径 + 弹跳过滤、校准 v2、直通规则(2026-10-16,负责人 E25·E27) 正确 508, 未经确认即错误 8,需要确认 497,幽灵球(无球时给出的得分)51,判定延迟 p90 1.32秒
摄像机记分牌从头到尾 将测试 7 场比赛的 851 秒以虚拟摄像机 30fps 流式传输至真实浏览器/操作员代码中,标签 58 个回合(2026-10-17,负责人 E35) 正确 47,错误 7,无判定 4,幽灵球 9, 未经确认即错误 0,需要确认 53/65
分条件公开视频 八种拍摄条件 27 个剪辑(2026-10-14–16,PERFORMANCE 2.16–2.17) 垂直竖立的手机视频中,能看到球的帧占 5%,判定为 0
手机拍摄的真实乒乓球馆 — 未实测(带标签的视频 0 部)

这两行说明了当前的特性: 未经确认即出错的情况很少见,但需要确认的情况很多。 在摄像机记分牌从头到尾的测试中,65 个判定中有 53 个需要确认。9 秒自动应用机制代替人工付出了代价,“减少需要确认的次数,同时不增加未经确认即出错的次数”便是下阶段的改进目标。

9. 总结

TT 的一句话。 热身发球和真实发球在我看来一模一样。所以请务必在第一记发球前瞬间按下「比赛开始」。那一次按键比十分还要重要。

参考文献

  1. International Table Tennis Federation. ITTF Statutes 2026, Chapter 2: The Laws of Table Tennis, §§2.10–2.15. https://db.ittf.com/document
  2. R. Voeikov, N. Falaleev, R. Baikulov. "TTNet: Real-time Temporal and Spatial Video Analysis of Table Tennis." CVPR Workshops, 2020. arXiv:2004.09927. 这是通过神经网络直接捕捉弹跳和网球的代表性先前研究,而我们的不同之处在于通过球轨迹规则提取事件。
  3. Extended OpenTTGames(回合结束原因·胜者标签)。arXiv:2512.19327。本文中的回合胜者标准答案。
  4. 我们的测量:仓库 docs/tt/PERFORMANCE.md 2.6·2.7·2.16·2.17,研究日志 E20·E25·E27·E34·E35。代码 ttscore/events.py·referee.py·analyze.py·reviewcal.py, backend/static/tt/play/lib/camauto.mjs·scorestatus.mjs.

延伸阅读

登录后即可点赞

评论

还没有评论。

登录后即可发表评论