G2L-Net 是 Chen 等人在 CVPR 2020 提出的 RGB-D 位姿估计方法。它先用图像缩小搜索范围,再从点云中依次估计平移和旋转。本页保留原笔记的八张图,按数据如何流动重新解释方法,并单独说明公开代码与论文图示的差别。
1. 输入、输出与三个阶段
跳转到“1. 输入、输出与三个阶段”对已知刚性物体,目标是求物体系到相机系的变换:
输入包括对齐的 RGB-D、相机内参,以及物体模型和类别信息。模型、深度、关键点与平移标签的长度单位必须统一。这里的“全局到局部”表示逐步缩小空间并消除平移,不表示可以省略模型或相机标定。

原论文整体流程图。图中的 “+” 表示特征拼接;数学中的坐标修正则是数值相加,两者要分开读。
| 阶段 | 输入与工作 | 输出 |
|---|---|---|
| 全局定位 | 从 RGB 检测类别与目标位置,利用深度构造球形候选区域 | 较小的候选点云 |
| 平移定位 | 分割前景,预测可见点均值到物体原点的修正 | 前景点、平移估计 |
| 旋转定位 | 从移除平移的点云学习逐点嵌入特征 | 关键点坐标表示,经刚体拟合得到旋转 |
2. 全局定位:为什么使用三维球形区域
跳转到“2. 全局定位:为什么使用三维球形区域”二维检测框沿视线延伸后形成截锥区域。它限制了图像中的范围,但沿深度方向仍可能包含较多背景。
论文使用类别概率图峰值的像素位置及对应深度,将其反投影为三维球心 。若已校正畸变且深度为光轴方向的 :
以物体模型直径 为半径,候选点集合是:
这里按论文使用 ,不是 。球心来自检测与深度,并不保证落在物体几何中心;这个选择为定位误差和可见表面点的位置留出范围。

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

球形区域进一步限制深度方向的搜索,但仍可能含背景,也可能因错误深度或检测位置偏差漏掉目标。后续网络需要处理候选区域质量,而不能假定第一步已经得到完整物体点云。
3. 平移定位:残差必须是三维向量
跳转到“3. 平移定位:残差必须是三维向量”设分割后的可见前景点为 ,均值为:
可见点均值通常不等于物体坐标原点在相机系中的位置:遮挡、单侧可见表面和采样密度都会改变均值。因此网络学习一个带方向的平移残差:
原笔记把残差写成 。这是一个标量距离,丢失方向,不能单独恢复三维平移。上式的符号来自发布代码的数据增强标签和推理相加方式,见 data_augment与推理流程。
旋转分支接收移除估计平移后的点:
若平移估计准确,则 。点云仍带有未知旋转;论文称它为局部规范空间,不能理解成已经恢复完整物体坐标系。
例如均值为 m,而物体原点平移为 m,正确残差为 m。它的长度约为 0.0548 m,但这个长度无法告诉我们应该沿哪一方向修正。
4. 逐点嵌入向量特征在学习什么
跳转到“4. 逐点嵌入向量特征在学习什么”4.1 视角改变会改变可见点云
跳转到“4.1 视角改变会改变可见点云”
原笔记的多视点示意图。它帮助说明可见表面随视角变化;“四个视点覆盖任意物体全部表面”不是普遍成立的几何结论,凹陷、自遮挡与外部遮挡均可破坏这一假设。
只把点云压成一个全局向量,可能丢掉部分局部方向信息。G2L-Net 使用逐点方向预测作为学习任务,使中间特征携带“这个可见点朝向模型关键点的方向”。
4.2 关键点与单位方向
跳转到“4.2 关键点与单位方向”模型中预先选定 个关键点 。本节定义监督标签时使用 ,与前节推理时减去估计平移的点云区分开。在移除真实平移的相机轴向坐标中,关键点为 。对于不与关键点重合的点:
这是一条从观测点指向关键点的单位方向,不包含距离。它与 FFB6D 发布实现的“观测点减关键点”三维偏移在符号、长度信息和用途上均不同。
若两点重合,分母为零,方向没有定义。生成标签时应显式处理或屏蔽这类样本,不能把零向量称作单位向量。

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

包围盒角点容易定义,即使不在物体表面也可作为已知几何参照。FPS 重视模型点之间的空间分布。两种选择改变学习目标和几何条件,应与网络输出维度、顺序及训练权重对应。
4.3 把损失函数与最优化操作分开写
跳转到“4.3 把损失函数与最优化操作分开写”令输入点集为 ,其中 。方向预测为 ,一个清楚的均方误差定义是:
训练再通过 优化包含多个任务的总损失。不能一边写 ,一边把 塞进它的定义中而不说明最优值的含义;集合 与点数 也不是同一对象。
只有当预测与真值都归一化为单位向量时,才有:
若网络直接输出未归一化的三个数,误差还会受预测长度影响,不能直接等同于角度误差。上式的求和归约用于解释概念;发布代码的 MSELoss 还对坐标维取平均,各任务权重与其尺度配套。
5. 旋转预测:论文图与发布实现分别读
跳转到“5. 旋转预测:论文图与发布实现分别读”
论文图 5 中,A 提供方向监督以训练嵌入特征,B 预测旋转的关键点坐标表示,C 学习坐标修正。图注明确说 A 不部署到推理阶段。
需要区别的是,本页核对的公开版本仍在演示推理中计算 box_pred,并将它与中间特征拼接后输入旋转预测器。仓库 README 也说明发布代码经过调整。因此“论文 A 只用于训练”与“当前发布实现使用 A 的输出”分别对应两个版本,不能揉成一个流程。见固定版本 README和演示推理实现。
5.1 用关键点坐标表示旋转
跳转到“5.1 用关键点坐标表示旋转”直接输出九个数并不自动满足旋转矩阵的正交性与行列式约束。所核对实现输出八个三维关键点,共 24 个坐标,再利用模型关键点与预测关键点之间的对应关系求刚体拟合,取出旋转。
具体 SVD 推导、行列式修正与可运行 CPU 函数见 FFB6D 笔记的刚体拟合部分。两篇使用同一种几何工具,并不表示它们的网络结构或关键点生成方式相同。
5.2 “旋转残差”落实为关键点坐标修正
跳转到“5.2 “旋转残差”落实为关键点坐标修正”用 表示第一次拟合得到的旋转。发布代码先旋转模型关键点,再叠加残差分支给出的三维坐标修正:
接着对 与 再做一次刚体拟合,提取最终旋转 ;最终平移仍采用前面的 。
训练代码让修正后的坐标与目标关键点坐标计算均方误差,并对第一次拟合所得坐标使用 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_meantranslation_recovered = visible_mean + translation_residualnp.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-Net | FFB6D |
|---|---|---|
| 如何使用 RGB-D | RGB 先定位,点云完成后续平移与旋转估计 | 图像与点云在多层特征中双向融合 |
| 逐点预测的几何含义 | 指向关键点的单位方向,服务于嵌入特征学习 | 带长度的关键点与中心偏移,用于投票 |
| 最后如何约束旋转 | 由关键点坐标表示进行刚体拟合 | 由聚合后的关键点对应进行刚体拟合 |
| 阅读实现时最易混淆处 | 论文的训练辅助头与发布推理不同 | SIFT-FPS 论文与 ORB-FPS 发布配置不同 |
原论文:CVPR 2020 出版页、作者 arXiv 版本。代码核对固定于 DC1991/G2L_Net 的 bc6e34a5 提交。
原笔记来源:CSDN 原文,首次发布于 2022-10-17。八张原图均保留;坐标推导、版本区别和 NumPy 示例为本页的学习补充。