没接触过点云的人看到 3D 标注界面,第一反应通常是"不就是拉个盒子把东西框起来吗"。 这一页回答他。答案不在鼠标好不好用上。
一个 3D 框要回答的其实是这么一句话:
「这辆车,长 4.6 m,在 12 m 处,朝向偏 30°」
这句话里有两类信息。麻烦在于,它们各自只存在于一个传感器里。
| 信息 | 点云(LiDAR)能给吗 | 图像(相机)能给吗 |
|---|---|---|
| 语义:这是车还是箱子 | 几乎不能 | ✅ 一目了然 |
| 几何:多远、多大、怎么摆 | ✅ 精确 | ❌ 投影后深度丢了 |
两个"不能"都不是技术不够,是两种传感器的原理决定的。两个具体画面:
把一辆车和一堆堆叠的纸箱放进点云:
前视图里,两者都是【方块状的 L 形点】
你分不出哪个是车
把 12 m 外的真车和 3 m 外的玩具车放进图像:
它们的【像素大小可能差不多】
你分不出哪个更远
是任务本身要求两种证据同时在场。这也是为什么它的核心功能叫 2D↔3D 融合标注,而不是"点云标注加图像标注"两个互不相干的工具。
我们习惯了图像,容易以为点云只是分辨率低一点的照片。两者性质差很远:
| 图像 | 点云 | |
|---|---|---|
| 结构 | 规则网格 H×W,稠密 | N 个无序 3D 点,N 逐帧变化 |
| 密度 | 全图均匀 | 近密远疏,10 m 外的车可能只剩几个点 |
| 覆盖 | 每个像素都有值 | 只有被扫到的那一面 |
| 渲染 | 光栅化加贴图,GPU 天生擅长 | 点渲染、splatting,另一套管线 |
最后一行影响最大。一帧 LiDAR 从车顶打出去,只能扫到物体朝向传感器的那一侧。所以:
一辆车在点云里看起来是【"L 形"的两条边】
一个侧面加一个前面(或后面)
背面和顶面是【空的】
标注员真正在做的事,是看着两条边加一堆散点,在脑子里补出一个完整立方体,再把框摆上去。
2D 框:四个边界都有真实的像素证据
3D 框:有整整两个面【没有任何数据】
这解释了为什么远距离小目标只能靠几个聊胜于无的点硬猜,也解释了为什么必须靠图像帮忙定类别。
要让两种模态同时在场,唯一的办法是把点云投影到图像上。这一步就是后面几何篇要讲的内外参。 但这里藏着一个反直觉的性质。
极端情形:光轴上整条射线压成同一个像素,也就是主点。 沿深度方向移动 100 m,图像中心产生 0 px 变化。
这不是精度不够,是信息根本不存在。
把 3D 框沿视线方向推动 ΔZ,像素位移是:
Δu = u · ΔZ / Z
取 fx = 933、1920×1080、Z = 12 m、ΔZ = 1 m:
u = 0 正中心 → 0 px
u = 240 → 20 px
u = 480 → 40 px
u = 960 边缘 → 80 px
你在某个视角把框摆好了,转一下相机,发现它歪得离谱。 "转一下"的本质,是把原本在中心的目标挪到了边缘。 同一个深度误差从 0 px 变成 80 px,突然就现形了。
而"正对着驶离的前车"是最坏的情况:车身长度整个躺在视线方向上, 被透视压缩成接近零宽的一条边。把框沿视线推 2 m,屏幕上几乎纹丝不动。
更糟的是中心恰好是视野里目标最常出现的位置。误差最不可见的地方, 正好是最需要看清的地方。
搞清楚上面这些,就能理解为什么"3D 标注难用"经常被归错因。它其实是两个独立的问题:
| 本质 | 该谁来解 | |
|---|---|---|
| 跟手 | 鼠标只有 2 个自由度,要映射到世界的 3 个 | 交互设计 |
| 不飘 | 单视图的零空间不可观测 | 信息供给 |
只解决了跟手的工具,用户会遇到"手很顺,但转过去发现全歪了"。
跟手是纯交互问题,有成熟解法。核心一句:不要映射到世界坐标,要映射到屏幕平面。 因为你能看见、能判断的只有屏幕上的东西。
不飘没法靠手感解决,因为缺的不是精度,是信息。要么把自由度砍掉,要么换个视角,要么从别处补。
一个 3D 框有 9 个自由度。工业界的标准做法是在动手之前先砍掉大部分:
9 DOF:x, y, z, L, W, H, roll, pitch, yaw
−3 地面约束 物体立在地面上,z、roll、pitch 锁死
★ 一旦钉在地面上,"沿视线的歧义"就消失了
因为 射线 ∩ 地面 = 唯一交点
−3 尺寸先验 类别已知 → 车多大是已知的
−1 轨迹推朝向 车往哪开就朝哪
=2 只剩 (x, y) ★★★
而 (x, y) 在俯视图里完全跟手、完全可辨。也就是说,正确设计下, 人需要手工确定的,和拖一个 2D 框一样简单。
卡车会超载超高,车会停在坡道上,堆叠的箱子不贴地。 约束必须留手动解锁的逃生口,否则会强行产生错误真值。
主视图(相机视角):零空间 = 视线方向
BEV 俯视图 :零空间 = 垂直方向
两者零空间不同 → 任何 3D 配置至少会在其中一个视图里"看得出不对"
而剩下的 (x, y, yaw),恰好【在 BEV 里全部可辨且跟手】
不要让用户在信息不充分的视图里,做那个视图决定不了的操作。
人判断"框的 3D 位置对不对"很难,判断"框里有没有点"非常容易。 所以不要只给一个漂浮的线框,要同时给定量反馈:框内点云高亮、框外变暗,并显示框内点数。
于是如果框沿着视线滑出去了,框内点数会骤降,异常立刻显形,根本不需要转摄像头。
把不可观测的自由度,转成一个屏幕上可观测的标量。
这点很反直觉。加约束并没有消灭零空间,只是把它逼到了一个特定的位置。
以地面约束为例。相机高 h、目标地面距离 Z、俯角 θ:
Z = h / tanθ → |dZ/dθ| = h·(1 + (Z/h)²) ≈ Z²/h
深度误差随距离平方放大。取 h = 1.2 m、f = 933 px:
| 距离 Z | 1 像素误差对应的深度误差 | 放大倍数 |
|---|---|---|
| 12 m | 0.13 m | 121× |
| 50 m | 2.2 m | 2084× |
| 100 m | 8.9 m | 8334× |
所以"地面约束让人一次画准"只在近场成立。地平线恰好就是那条零空间: 视线与地面相切,θ 趋于 0,解发散。
自由空间里,零空间是每一条视线,到处都在。 加了地面约束,零空间收缩成地平线这一条线,但没消失。
这也正好对上自动驾驶的现实:难例本来就在远处。 最终解决它的是 LiDAR,直接给深度,不靠三角化。
绕【视线轴】旋转 → 轮廓变化极其微弱
绕另外两轴旋转 → 轮廓明显变形
所以自由空间里不可观测的方向不止一个,而是"沿视线平移"加"绕视线旋转"这一对。 这也是 6DoF 位姿标注比 3D 框难一个档次的直接原因。
如果这一页只留一句,是这句:
2D 标注:画错了 → 你看得见框歪了 → 有反馈 → 能自纠
3D 标注:零空间误差 → 屏幕上零变化 → 无反馈 → 不知道错,也不知道该去看
不是"一次画不准",而是"画完之后你无法验证自己准不准"。
普通误差是手抖,更小心就行。这个是信息不在场,再小心也没用。
1. 质检必须在与标注不同的视图里做。 标注时看不出来的错误,在同一视图里检查同样看不出来,那等于没查。
2. 单帧不可见,但群体统计可见。 框的深度分布和点云实际深度分布放一起,会出现系统性偏移。
3. 这就是 3D 标注的质检比 2D 难那么多的原因。 2D 的错帧挑出来给审核员看就行;3D 的错帧看起来完全正常。
上面讲的"地面约束"在自动驾驶里几乎总成立,换到具身操作就是常态失效的。
| 地面约束 | 尺寸先验 | 结果 | |
|---|---|---|---|
| 自动驾驶 | ✅ 几乎总成立,车在路上 | ✅ 类别先验很强 | 3D 框标注能半自动 |
| 具身操作 | ❌ 桌面、空中、任意姿态 | ❌ 任意物体、非刚性 | 自由空间是常态 |
所以在自动驾驶里能靠约束省掉的那部分工作量,到具身操作里得用别的手段补。 这是后面标注篇要展开的一条主线。
3D 标注难,难在信息被物理地劈成了两半,以及投影天生丢掉一个维度。 鼠标好不好用是另一个独立问题,两者都要解,但解不了对方。
最该记住的是那条静默性:错误在屏幕上没有反馈。 所以后面所有的设计,约束、多视图、点云反馈、质检流程,本质上都是在给这个不可观测的方向 硬造一个可观测的信号。