Skip to content

如何标注视频目标跟踪

借助模型辅助的掩码传播在整段视频中跟踪一个对象,诚实地处理遮挡,并用容差扫描来衡量时间一致性。

跟踪标注意味着在多帧之间标注同一个对象,而昂贵的部分不是第一份掩码,而是随后的数百份。 模型辅助的传播能消除其中大部分工作——前提是模型对"何时跟丢了"足够诚实。

工作流程

  1. 在某一帧上给对象画掩码。
  2. 向前传播。每个结果都会作为关键帧出现。
  3. 逐帧查看关键帧,在掩码漂移处做修正。修正某一帧会从该点起重新锚定整条轨迹。
yaml
annotation_schemes:
  - annotation_type: video_annotation
    name: tracks
    description: "Draw the object once, then press Track forward."
    source_field: video_url
    mode: tracking
    labels:
      - {name: subject, color: "#d1495b"}
    tracking_options:
      interpolation: linear
      auto_advance_frames: 5
    video_fps: 12
    frame_stepping: true

遇到遮挡应当什么都不返回

在标注闭环中,传播模型最有用的一项性质,就是当对象被遮挡时它会拒答,返回一个空帧而不是它的最佳猜测。

在被遮挡的帧上给出一个看似合理却错误的掩码,比留空更糟:标注者得先注意到它、判定它是错的、再把它删掉。而空帧可以被立刻读作"这里看不到该对象",这同时也正是正确的标签。

SAM 2 做到了这一点,而正是它的记忆模块让传播能够跨越遮挡继续成立,而不是在遮挡的另一侧把对象跟丢。对照已知基准实测,逐帧 IoU 在整个序列上稳定在 0.974 至 0.979,没有衰减。

保持不变 vs. 混合插值

在关键帧之间的帧上,掩码要么是保持不变的(沿用上一个关键帧),要么是混合插值出来的。保持不变是诚实的选择,并且被保持的帧应当在视觉上标出。

混合出来的掩码看起来更平滑,而它错得没人看得出来。如果下游确实需要插值后的几何,请在导出时插值——在那里它是一次被声明过的变换——而不要在界面里插值,那里它是隐形的。

多边形插值比看上去更难

在两个多边形关键帧之间插值,会在两个地方让朴素实现出错:

  • 两个关键帧可能顶点数不同
  • 标注者可能是从形状上不同的起点开始描的。

弧长重采样加旋转对齐能同时处理这两点。没有它,插值出来的多边形可能在关键帧之间翻转成自交形状。

传播应当在哪里运行

如果模型带有记忆模块,就应当在服务端。它的开销按帧计而非按提示计,而在浏览器标签页中跑上一百帧视频模型,意味着界面要冻结好几分钟。逐帧重新提示的浏览器内延续是另一种更轻的东西——它有用,但不是同一种能力,在你自己的文档中也值得不要混为一谈。

衡量一致性

两位标注者不会为同一个事件边界选中同一帧,因此时间一致性取决于匹配容差。请报告扫描曲线,而不是单一阈值:

  • 在 2 秒下高、在 0.25 秒下低:他们认同发生了某个事件,但对具体时点看法不一。通常是规范问题。
  • 两者都低:他们对事件是否发生本身存在分歧。

至于掩码本身,请按帧使用掩码一致性那一套机制。

一个值得在你自己的工具中排查的缺陷

HTML 视频报告的 currentTime 被截断到小数点后六位。用朴素的"乘法加下取整"把它换算成帧索引,会在每次跳转之后产生一帧偏差:12 fps 视频的第 14 帧会被读成第 13 帧。

在 2.8 之前,这个问题在 Potato 中是真实存在的,且影响每一位标注者、每一段视频。如果你手上有来自任何工具的按帧索引的视频标注,都值得拿一个已知帧来核验一下。

延伸阅读