跳转到内容
新建笔记

NOCS:类别级物体位姿、规范坐标与尺寸估计

NOCS(Normalized Object Coordinate Space,CVPR 2019)把类别内的不同物体放到一个共同的规范坐标空间,再让网络预测图像像素在该空间中的位置。它的关键不是记住某个测试物体的 CAD 模型,而是建立**“像素 → 规范三维坐标 → 相机三维坐标”**的对应关系。

这篇笔记重点区分三个容易混淆的概念:已知类别中的未见实例、统一缩放与长宽高、网络坐标预测与后续几何配准。

1. 类别级任务究竟允许知道什么

跳转到“1. 类别级任务究竟允许知道什么”

实例级位姿估计通常已知目标物体的精确模型和尺寸;类别级任务则希望处理已知类别中的新实例,例如训练见过一些杯子,测试面对另一只杯子。

已知条件在 NOCS 中的作用
已知物体类别及该类别的训练样本学习形状与规范方向的共性
训练用模型、标注和合成数据生成 NOCS 监督与训练图像
测试图像及与 RGB 对齐的深度提供外观和相机坐标系中的度量几何
测试物体的精确 CAD 模型推理不要求事先提供

因此,“不需要测试实例的 CAD”不能写成“训练也不使用三维模型”。论文使用 ShapeNetCore 模型生成训练数据,并提供真实 RGB-D 数据。网络输出也不是完整、无误差的 CAD 重建:它主要预测可见像素对应的规范表面坐标。

NOCS 的经典实验覆盖 bottle、bowl、camera、can、laptop、mug 六类。已知类别中的新实例,与训练完全没见过的新类别,是不同的泛化问题。

设一个物体在统一规范方向下的轴对齐包围盒中心为 c\mathbf c,三轴边长为

d=[dxdydz]T,ℓ=∥d∥2.\mathbf d= \begin{bmatrix}d_x&d_y&d_z\end{bmatrix}^{\mathsf T}, \qquad \ell=\|\mathbf d\|_2.

NOCS 使用同一个尺度归一化三个坐标轴:

q=Xo−cℓ+121.\mathbf q=\frac{\mathbf X_o-\mathbf c}{\ell} +\frac12\mathbf1.

归一化后,紧包围盒的对角线长度为 1,中心在 (0.5,0.5,0.5)(0.5,0.5,0.5),并位于单位立方体内。各轴边长为 d/ℓ\mathbf d/\ell,通常不是三个 1。

例如,尺寸为 60×80×100 mm60\times80\times100\ \mathrm{mm} 的物体,对角线约为 141.42 mm141.42\ \mathrm{mm},归一化边长约为 (0.424,0.566,0.707)(0.424,0.566,0.707)。如果分别把三个轴拉伸到 [0,1][0,1],物体的长宽高比例就消失了;这不是论文的统一缩放定义。

规范方向还需在类别内一致。例如“上方”和“正面”必须有一致标注,不能对每个物体随意旋转。轴对称物体的某些方向不可辨识,则需要在监督和评价时处理等价旋转。

3. NOCS 图不是普通彩色照片

跳转到“3. NOCS 图不是普通彩色照片”

对物体表面点赋予坐标 q=(qx,qy,qz)\mathbf q=(q_x,q_y,q_z),可以把三个坐标分量映射到 RGB 通道进行显示。这些颜色编码的是几何位置,并非物体真实材质。

训练时,真实或合成 RGB 图像作为输入;同一像素位置的 NOCS 坐标作为监督。不能把“渲染坐标颜色图”直接理解成“用坐标颜色图代替真实 RGB 训练”。

论文基于 Mask R-CNN,增加规范坐标预测分支。其 CNN 只使用 RGB;深度在后面的配准阶段参与计算。对于每个检测实例,网络给出类别、实例掩码和 NOCS 图。

flowchart TB
A["RGB 图像"] --> B["类别、掩码与 NOCS"]
B --> C["筛选同一像素对应"]
D["已对齐深度与内参"] --> C
C --> E["三维相似变换拟合"]
E --> F["旋转、平移与尺寸"]

坐标头既可回归连续坐标,也可将每个坐标轴离散为若干区间做分类。论文比较后采用 32 个区间的方案;类别通道和坐标区间是两套不同的索引,不能混为“32 个物体类别”。

4. 一个像素怎样产生一对三维坐标

跳转到“4. 一个像素怎样产生一对三维坐标”

采用列向量,设像素横坐标为 uu、纵坐标为 vv,相机内参为

K=[fx0cx0fycy001].K= \begin{bmatrix} f_x&0&c_x\\ 0&f_y&c_y\\ 0&0&1 \end{bmatrix}.

对于已去畸变、深度已对齐到 RGB 的像素,若 zz 表示沿相机光轴的深度,则

Xc=zK−1[uv1]=[(u−cx)z/fx(v−cy)z/fyz].\mathbf X_c= zK^{-1} \begin{bmatrix}u\\v\\1\end{bmatrix} = \begin{bmatrix} (u-c_x)z/f_x\\ (v-c_y)z/f_y\\ z \end{bmatrix}.

同一像素处的网络预测为 q\mathbf q。将规范空间重新移到原点:

x=q−121,y=Xc.\mathbf x=\mathbf q-\frac12\mathbf1,\qquad \mathbf y=\mathbf X_c.

这样得到一对对应的三维点 (x,y)(\mathbf x,\mathbf y)。掩码内有效的多个像素产生两组有对应索引的点云。

这里有两个独立的信息来源:x\mathbf x 来自网络预测;y\mathbf y 来自深度反投影。深度本身不会生成 NOCS 坐标。 配准也不需要先猜测这两组点之间的最近邻关系,因为像素索引已经给出了对应关系。

实际筛选应剔除无效深度、非有限坐标和明显的掩码污染。RGB 与深度未标定对齐、裁剪后仍使用原内参、毫米和米混用,都会破坏对应关系。

5. 为什么拟合是七自由度,输出却有三个尺寸

跳转到“5. 为什么拟合是七自由度,输出却有三个尺寸”

对中心化后的 NOCS 点,拟合模型为

yi≈sRxi+t,s>0,R∈SO(3).\mathbf y_i \approx sR\mathbf x_i+\mathbf t, \qquad s>0,\quad R\in SO(3).

其中 RR 有 3 个自由度,t\mathbf t 有 3 个,统一尺度 ss 有 1 个。这是七自由度的相似变换,不是带三个独立缩放的仿射变换。

物体的三个尺寸通过规范空间中的形状范围与 ss 一起恢复。例如完整规范形状的边长为 e\mathbf e,则

d^=se.\hat{\mathbf d}=s\mathbf e.

三个尺寸通常不同,因为 e\mathbf e 已保留长宽高比例。它们并不要求配准算法独立拟合 sx,sy,szs_x,s_y,s_z。

对完整且中心正确的规范包围盒,可以用逐轴最大、最小值之差求 e\mathbf e。如果只有局部可见点,直接取范围会漏掉不可见极值;尺寸误差因此既受配准尺度影响,也受网络形状预测和可见范围影响。

6. 从最小二乘推导相似变换

跳转到“6. 从最小二乘推导相似变换”

下面给出独立的教学推导,便于核对坐标约定。目标为

min⁡s>0,  R∈SO(3),  t1N∑i=1N∥yi−sRxi−t∥22.\min_{s>0,\;R\in SO(3),\;\mathbf t} \frac1N\sum_{i=1}^N \|\mathbf y_i-sR\mathbf x_i-\mathbf t\|_2^2.

先计算均值 xˉ,yˉ\bar{\mathbf x},\bar{\mathbf y},以及中心化坐标 xi′,yi′\mathbf x'_i,\mathbf y'_i。平移满足

t=yˉ−sRxˉ.\mathbf t=\bar{\mathbf y}-sR\bar{\mathbf x}.

定义交叉协方差与源点方差:

C=1N∑iyi′xi′T,σx2=1N∑i∥xi′∥22.C=\frac1N\sum_i\mathbf y'_i{\mathbf x'_i}^{\mathsf T}, \qquad \sigma_x^2=\frac1N\sum_i\|\mathbf x'_i\|_2^2.

对 C=UΣVTC=U\Sigma V^{\mathsf T} 做奇异值分解,并设置

D=diag⁡(1,1,det⁡(UVT)).D=\operatorname{diag} \left(1,1,\det(UV^{\mathsf T})\right).

则在非退化且尺度为正的条件下,

R=UDVT,s=tr⁡(ΣD)σx2.R=UDV^{\mathsf T}, \qquad s=\frac{\operatorname{tr}(\Sigma D)}{\sigma_x^2}.

DD 用于排除镜像反射。源码若采用相反顺序的协方差,旋转公式中的转置也会改变;不能只复制一行 SVD 公式而忽略它前面的矩阵定义。

以下 NumPy 示例只实现已知对应、无外点的相似变换拟合,不包含 RANSAC,也不运行 NOCS 网络:

import numpy as np
def fit_similarity(source, target):
"""Rows are 3D points; returns s, R, t with y = s * R @ x + t."""
x = np.asarray(source, dtype=np.float64)
y = np.asarray(target, dtype=np.float64)
if x.ndim != 2 or x.shape[1:] != (3,) or y.shape != x.shape:
raise ValueError("source and target must have the same (N, 3) shape")
if len(x) < 3 or not np.isfinite(x).all() or not np.isfinite(y).all():
raise ValueError("need at least three finite corresponding points")
xc, yc = x - x.mean(axis=0), y - y.mean(axis=0)
if np.linalg.matrix_rank(xc) < 2 or np.linalg.matrix_rank(yc) < 2:
raise ValueError("coincident or collinear points cannot fix 3D rotation")
covariance = yc.T @ xc / len(x)
if np.linalg.matrix_rank(covariance) < 2:
raise ValueError("degenerate cross-covariance")
u, singular, vt = np.linalg.svd(covariance)
diagonal = np.ones(3)
diagonal[-1] = 1.0 if np.linalg.det(u @ vt) >= 0 else -1.0
rotation = (u * diagonal) @ vt
variance = np.mean(np.sum(xc * xc, axis=1))
scale = np.dot(singular, diagonal) / variance
if not np.isfinite(scale) or scale <= 0:
raise ValueError("the fitted scale must be positive")
translation = y.mean(axis=0) - scale * (rotation @ x.mean(axis=0))
return scale, rotation, translation
source = np.array([[0., 0., 0.], [1., 0., 0.],
[0., 1., 0.], [0., 0., 1.]])
expected_r = np.array([[0., -1., 0.], [1., 0., 0.], [0., 0., 1.]])
target = 0.2 * (source @ expected_r.T) + [0.1, -0.2, 0.8]
s, r, t = fit_similarity(source, target)
np.testing.assert_allclose(s * (source @ r.T) + t, target, atol=1e-12)
np.testing.assert_allclose(r.T @ r, np.eye(3), atol=1e-12)
assert np.isclose(np.linalg.det(r), 1.0)

论文在拟合之外使用 RANSAC 去除外点。其作用是寻找相互一致的对应关系;RANSAC 阈值必须有明确单位,样本退化和内点不足也必须显式处理。

7. 对称性改变的是“哪些答案算等价”

跳转到“7. 对称性改变的是“哪些答案算等价””

轴对称物体绕对称轴旋转后,观测可能相同。强制它只能对应唯一规范角度,会让训练监督互相冲突。

一种表述是:给定允许的对称变换集合 S\mathcal S,对整个实例比较等价规范坐标目标,再选择损失最小的那个:

Lsym=min⁡S∈S1N∑iℓ ⁣(q^i, S(qi−121)+121).L_{\mathrm{sym}} = \min_{S\in\mathcal S} \frac1N\sum_i \ell\!\left( \hat{\mathbf q}_i,\, S(\mathbf q_i-\tfrac12\mathbf1)+\tfrac12\mathbf1 \right).

这个式子强调“整个实例使用同一个对称变换”。若对每个像素独立选不同的旋转,得到的坐标图可能不再对应一个刚体。对称性也必须进入评价协议;例如杯柄可见时的 mug,与杯柄不可见时的 mug,不一定具有相同的可辨识方向。

坐标损失小、三维包围盒重叠高、旋转误差小,是不同目标。论文分别报告检测/尺寸与旋转—平移指标,不能把一个指标的改进直接解释为所有几何误差都减小。

8. 阅读官方代码时的四个边界

跳转到“8. 阅读官方代码时的四个边界”

本节核对作者仓库固定提交 dd58dbf68feede04c3d7bbafeb9212af1a43422f。它是历史 TensorFlow/Keras 实现;以下为源码与局部数值检查,不代表已运行完整模型。

位置可确认的行为使用时需要注意
aligning.py::estimateSimilarityUmeyama返回三个相同的 Scales接口虽然是三元素数组,实际仍是统一尺度
utils.py::align将 NOCS 减去 0.5,使用同像素深度点配准bbox_scales 是规范尺寸范围,实际尺度还在变换矩阵中
utils.py::align规范范围使用 2 * max(abs(q - 0.5))相当于关于规范原点构造对称包围盒;不是任意局部点集的 max−min
backproject / align / dataset.py包含轴翻转、旋转转置、毫米到米换算及坐标图通道处理应核对整条坐标链,不能单独复制某个翻转或转置

另一个容易忽略的问题是:with_scale=True 时,返回矩阵左上角为尺度乘旋转,它不是纯粹的 SE(3)SE(3) 刚体矩阵。若要提取旋转,应先分离统一尺度,再检查正交性与行列式;不能直接用带尺度矩阵计算旋转角误差。

历史文件中用于残差评估的 OutTransform 与后续 align 重新构造矩阵采用了不同的旋转转置方式。复用前应先用已知旋转和尺度的点对测试“变换后是否回到目标点”,而不能根据函数名称认为行列向量约定已经一致。

9. 复现时先验证哪几件事

跳转到“9. 复现时先验证哪几件事”

先用人工构造的点对验证相似变换,再检查一张真实图像的 RGB—深度对齐。随后分别查看掩码、NOCS 图、三维对应残差、拟合尺度与包围盒尺寸。这些中间量能区分“分割错了”“规范方向错了”和“度量单位错了”。

  • 原论文:Wang 等,Normalized Object Coordinate Space for Category-Level 6D Object Pose and Size Estimation,CVPR 2019。
  • 作者项目页与固定版本代码:方法、数据和历史实现。
  • FFB6D 的刚体拟合:对比已知尺度下的三维关键点配准。
  • CSDN 原笔记:首次发布于 2022-08-30。本篇重新组织为研究阅读笔记,并补充独立推导与可执行几何示例。