跳转到内容
新建笔记

G2L-Net:从局部点云到物体位姿

G2L-Net 是 Chen 等人在 CVPR 2020 提出的 RGB-D 位姿估计方法。它先用图像缩小搜索范围,再从点云中依次估计平移和旋转。本页保留原笔记的八张图,按数据如何流动重新解释方法,并单独说明公开代码与论文图示的差别。

1. 输入、输出与三个阶段

跳转到“1. 输入、输出与三个阶段”

对已知刚性物体,目标是求物体系到相机系的变换:

pc=Rpo+t,R∈SO(3),t∈R3.\boldsymbol p_c=\mathbf R\boldsymbol p_o+\boldsymbol t, \qquad \mathbf R\in SO(3),\quad\boldsymbol t\in\mathbb R^3.

输入包括对齐的 RGB-D、相机内参,以及物体模型和类别信息。模型、深度、关键点与平移标签的长度单位必须统一。这里的“全局到局部”表示逐步缩小空间并消除平移,不表示可以省略模型或相机标定。

G2L-Net 依次进行图像全局定位、点云平移定位和嵌入向量特征旋转定位

原论文整体流程图。图中的 “+” 表示特征拼接;数学中的坐标修正则是数值相加,两者要分开读。

阶段输入与工作输出
全局定位从 RGB 检测类别与目标位置,利用深度构造球形候选区域较小的候选点云
平移定位分割前景,预测可见点均值到物体原点的修正前景点、平移估计
旋转定位从移除平移的点云学习逐点嵌入特征关键点坐标表示,经刚体拟合得到旋转

2. 全局定位:为什么使用三维球形区域

跳转到“2. 全局定位:为什么使用三维球形区域”

二维检测框沿视线延伸后形成截锥区域。它限制了图像中的范围,但沿深度方向仍可能包含较多背景。

论文使用类别概率图峰值的像素位置及对应深度,将其反投影为三维球心 c\boldsymbol c。若已校正畸变且深度为光轴方向的 zz:

c=zK−1[u,v,1]T.\boldsymbol c=z\mathbf K^{-1}[u,v,1]^\mathsf T.

以物体模型直径 DD 为半径,候选点集合是:

S={xi:∥xi−c∥2≤D}.\mathcal S=\{\boldsymbol x_i:\|\boldsymbol x_i-\boldsymbol c\|_2\le D\}.

这里按论文使用 DD,不是 D/2D/2。球心来自检测与深度,并不保证落在物体几何中心;这个选择为定位误差和可见表面点的位置留出范围。

G2L-Net 全局定位分支:RGB 检测和深度反投影共同给出三维候选区域

原流程图的局部展开,保留以对照全局定位阶段的数据来源。

二维框形成的截锥区域与三维球形提议区域比较

球形区域进一步限制深度方向的搜索,但仍可能含背景,也可能因错误深度或检测位置偏差漏掉目标。后续网络需要处理候选区域质量,而不能假定第一步已经得到完整物体点云。

3. 平移定位:残差必须是三维向量

跳转到“3. 平移定位:残差必须是三维向量”

设分割后的可见前景点为 {xi}i=1N\{\boldsymbol x_i\}_{i=1}^{N},均值为:

xˉ=1N∑i=1Nxi.\bar{\boldsymbol x}=\frac1N\sum_{i=1}^{N}\boldsymbol x_i.

可见点均值通常不等于物体坐标原点在相机系中的位置:遮挡、单侧可见表面和采样密度都会改变均值。因此网络学习一个带方向的平移残差:

Δtgt=tgt−xˉ,t^=xˉ+Δt^.\Delta\boldsymbol t_{\mathrm{gt}} =\boldsymbol t_{\mathrm{gt}}-\bar{\boldsymbol x}, \qquad \widehat{\boldsymbol t} =\bar{\boldsymbol x}+\widehat{\Delta\boldsymbol t}.

原笔记把残差写成 ∥t−xˉ∥2\|\boldsymbol t-\bar{\boldsymbol x}\|_2。这是一个标量距离,丢失方向,不能单独恢复三维平移。上式的符号来自发布代码的数据增强标签和推理相加方式,见 data_augment与推理流程。

旋转分支接收移除估计平移后的点:

xi′=xi−t^.\boldsymbol x'_i=\boldsymbol x_i-\widehat{\boldsymbol t}.

若平移估计准确,则 xi′≈Rpo,i\boldsymbol x'_i\approx\mathbf R\boldsymbol p_{o,i}。点云仍带有未知旋转;论文称它为局部规范空间,不能理解成已经恢复完整物体坐标系。

例如均值为 (0.10,−0.03,0.85)(0.10,-0.03,0.85) m,而物体原点平移为 (0.12,−0.04,0.90)(0.12,-0.04,0.90) m,正确残差为 (0.02,−0.01,0.05)(0.02,-0.01,0.05) m。它的长度约为 0.0548 m,但这个长度无法告诉我们应该沿哪一方向修正。

4. 逐点嵌入向量特征在学习什么

跳转到“4. 逐点嵌入向量特征在学习什么”

4.1 视角改变会改变可见点云

跳转到“4.1 视角改变会改变可见点云”

多个视点观察三维物体时,可见表面区域随视角改变

原笔记的多视点示意图。它帮助说明可见表面随视角变化;“四个视点覆盖任意物体全部表面”不是普遍成立的几何结论,凹陷、自遮挡与外部遮挡均可破坏这一假设。

只把点云压成一个全局向量,可能丢掉部分局部方向信息。G2L-Net 使用逐点方向预测作为学习任务,使中间特征携带“这个可见点朝向模型关键点的方向”。

模型中预先选定 KK 个关键点 mk\boldsymbol m_k。本节定义监督标签时使用 xi′=xi−tgt\boldsymbol x'_i=\boldsymbol x_i-\boldsymbol t_{\mathrm{gt}},与前节推理时减去估计平移的点云区分开。在移除真实平移的相机轴向坐标中,关键点为 qk′=Rmk\boldsymbol q'_k=\mathbf R\boldsymbol m_k。对于不与关键点重合的点:

vik=qk′−xi′∥qk′−xi′∥2.\boldsymbol v_{ik} =\frac{\boldsymbol q'_k-\boldsymbol x'_i} {\|\boldsymbol q'_k-\boldsymbol x'_i\|_2}.

这是一条从观测点指向关键点的单位方向,不包含距离。它与 FFB6D 发布实现的“观测点减关键点”三维偏移在符号、长度信息和用途上均不同。

若两点重合,分母为零,方向没有定义。生成标签时应显式处理或屏蔽这类样本,不能把零向量称作单位向量。

逐点方向向量指向同一个绿色关键点,其他关键点用黑色标出

图中只展示一个关键点的方向场;使用多个关键点时,每个输入点对应多组方向监督。

模型包围盒八个角点与最远点采样关键点的比较

包围盒角点容易定义,即使不在物体表面也可作为已知几何参照。FPS 重视模型点之间的空间分布。两种选择改变学习目标和几何条件,应与网络输出维度、顺序及训练权重对应。

4.3 把损失函数与最优化操作分开写

跳转到“4.3 把损失函数与最优化操作分开写”

令输入点集为 X={xi′}i=1N\mathcal X=\{\boldsymbol x'_i\}_{i=1}^N,其中 N=∣X∣N=|\mathcal X|。方向预测为 v^ik(θ)\widehat{\boldsymbol v}_{ik}(\theta),一个清楚的均方误差定义是:

Lvec(θ)=1KN∑k=1K∑i=1N∥v^ik(θ)−vik∥22.L_{\mathrm{vec}}(\theta) =\frac{1}{KN} \sum_{k=1}^{K}\sum_{i=1}^{N} \left\|\widehat{\boldsymbol v}_{ik}(\theta)-\boldsymbol v_{ik}\right\|_2^2.

训练再通过 min⁡θLtrain(θ)\min_\theta L_{\mathrm{train}}(\theta) 优化包含多个任务的总损失。不能一边写 L(θ)L(\theta),一边把 min⁡θ\min_\theta 塞进它的定义中而不说明最优值的含义;集合 X\mathcal X 与点数 ∣X∣|\mathcal X| 也不是同一对象。

只有当预测与真值都归一化为单位向量时,才有:

∥v^−v∥22=2−2cos⁡α.\|\widehat{\boldsymbol v}-\boldsymbol v\|_2^2 =2-2\cos\alpha.

若网络直接输出未归一化的三个数,误差还会受预测长度影响,不能直接等同于角度误差。上式的求和归约用于解释概念;发布代码的 MSELoss 还对坐标维取平均,各任务权重与其尺度配套。

5. 旋转预测:论文图与发布实现分别读

跳转到“5. 旋转预测:论文图与发布实现分别读”

旋转定位网络的方向监督分支 A、旋转表示分支 B 与残差分支 C

论文图 5 中,A 提供方向监督以训练嵌入特征,B 预测旋转的关键点坐标表示,C 学习坐标修正。图注明确说 A 不部署到推理阶段。

需要区别的是,本页核对的公开版本仍在演示推理中计算 box_pred,并将它与中间特征拼接后输入旋转预测器。仓库 README 也说明发布代码经过调整。因此“论文 A 只用于训练”与“当前发布实现使用 A 的输出”分别对应两个版本,不能揉成一个流程。见固定版本 README和演示推理实现。

5.1 用关键点坐标表示旋转

跳转到“5.1 用关键点坐标表示旋转”

直接输出九个数并不自动满足旋转矩阵的正交性与行列式约束。所核对实现输出八个三维关键点,共 24 个坐标,再利用模型关键点与预测关键点之间的对应关系求刚体拟合,取出旋转。

具体 SVD 推导、行列式修正与可运行 CPU 函数见 FFB6D 笔记的刚体拟合部分。两篇使用同一种几何工具,并不表示它们的网络结构或关键点生成方式相同。

5.2 “旋转残差”落实为关键点坐标修正

跳转到“5.2 “旋转残差”落实为关键点坐标修正”

用 R^0\widehat{\mathbf R}_0 表示第一次拟合得到的旋转。发布代码先旋转模型关键点,再叠加残差分支给出的三维坐标修正:

z^k=R^0mk+Δq^k.\widehat{\boldsymbol z}_k =\widehat{\mathbf R}_0\boldsymbol m_k +\widehat{\Delta\boldsymbol q}_k.

接着对 {mk}\{\boldsymbol m_k\} 与 {z^k}\{\widehat{\boldsymbol z}_k\} 再做一次刚体拟合,提取最终旋转 R^\widehat{\mathbf R};最终平移仍采用前面的 xˉ+Δt^\bar{\boldsymbol x}+\widehat{\Delta\boldsymbol t}。

训练代码让修正后的坐标与目标关键点坐标计算均方误差,并对第一次拟合所得坐标使用 detach。这里的修正是每个关键点的三维向量,不是把一个欧氏距离标量加到旋转矩阵上,也不是直接预测李代数中的旋转增量。

这套实现包含两次几何拟合。它没有因此成为 ICP 式反复迭代对齐,也不能据“残差分支同时预测”推断整个流程没有后续几何计算。对应实现见训练脚本。

6. 可运行的小例子:单位方向与平移残差

跳转到“6. 可运行的小例子:单位方向与平移残差”

以下例子独立于 G2L-Net 网络,只需要 NumPy。它检查方向长度、零距离掩码和带符号平移恢复。

import numpy as np
def directions_to_keypoints(points, keypoints, eps=1e-12):
points = np.asarray(points, dtype=np.float64)
keypoints = np.asarray(keypoints, dtype=np.float64)
if (points.ndim != 2 or points.shape[1:] != (3,)
or keypoints.ndim != 2 or keypoints.shape[1:] != (3,)
or len(points) == 0 or len(keypoints) == 0):
raise ValueError("需要非空的 N×3 点集和 K×3 关键点")
if not np.isfinite(points).all() or not np.isfinite(keypoints).all():
raise ValueError("坐标必须有限")
if not np.isfinite(eps) or eps <= 0:
raise ValueError("eps 必须为有限正数")
delta = keypoints[None, :, :] - points[:, None, :]
length = np.linalg.norm(delta, axis=-1, keepdims=True)
valid = length[..., 0] > eps
directions = np.divide(delta, length, out=np.zeros_like(delta),
where=valid[..., None])
return directions, valid # 无效位置为占位零值,不能当作单位向量
points = np.array([[0., 0., 0.], [1., 0., 0.]])
keypoints = np.array([[0., 0., 0.], [0., 1., 0.]])
directions, valid = directions_to_keypoints(points, keypoints)
assert valid.tolist() == [[False, True], [True, True]]
np.testing.assert_allclose(np.linalg.norm(directions[valid], axis=-1), 1.)
np.testing.assert_allclose(directions[1, 0], [-1., 0., 0.])
visible_mean = np.array([0.10, -0.03, 0.85])
translation_true = np.array([0.12, -0.04, 0.90])
translation_residual = translation_true - visible_mean
translation_recovered = visible_mean + translation_residual
np.testing.assert_allclose(translation_recovered, translation_true)
print(np.round(translation_residual, 6)) # [ 0.02 -0.01 0.05]

若把这个函数用于生成监督,损失也应使用相同有效掩码,并按有效方向对数归一化。本例的零值只是存储占位;把它加入普通单位方向 MSE 会改变目标。阈值 eps 还应与坐标单位和数据精度匹配。

本次运行了这个例子与刚体拟合的 CPU 验证;未运行原始 GPU 网络、训练或预训练推理。旧训练脚本的批量点索引也需要在复现时检查,不能仅凭静态阅读就承诺原环境在现代依赖下可以直接执行。

7. 如何读实验曲线与运行速度

跳转到“7. 如何读实验曲线与运行速度”

逐点嵌入特征、全局特征与旋转残差分支的原论文消融曲线

原论文图 9。左图研究训练视角数据比例与特征表示,采用真实检测框和随机物体点球心的简化设置;不能把它读成完整检测链路的结果。右图比较训练过程中旋转残差分支的作用,曲线反映论文对应数据、模型和评价设置。

论文报告约 23 FPS,条件是 i7-4930K、GTX 1080 Ti、640×480 图像下的单物体处理。这是论文报告值,不是本页测试结果。比较方法时应同时核对是否计入检测、点云处理、数据传输及几何拟合,以及物体数量和评价阈值。

可以用下面的对照把两种方法联系起来:

问题G2L-NetFFB6D
如何使用 RGB-DRGB 先定位,点云完成后续平移与旋转估计图像与点云在多层特征中双向融合
逐点预测的几何含义指向关键点的单位方向,服务于嵌入特征学习带长度的关键点与中心偏移,用于投票
最后如何约束旋转由关键点坐标表示进行刚体拟合由聚合后的关键点对应进行刚体拟合
阅读实现时最易混淆处论文的训练辅助头与发布推理不同SIFT-FPS 论文与 ORB-FPS 发布配置不同

原论文:CVPR 2020 出版页、作者 arXiv 版本。代码核对固定于 DC1991/G2L_Net 的 bc6e34a5 提交。

原笔记来源:CSDN 原文,首次发布于 2022-10-17。八张原图均保留;坐标推导、版本区别和 NumPy 示例为本页的学习补充。