极坐标 BEV 的表示方法:在 BEV 空间按照角度和半径两个维度进行划分,而非笛卡尔坐标系下的均匀矩形网格。自车近处高分辨率,远处低分辨率,契合相机近大远小的成像特点。
核心优势
非均匀网格划分与分辨率优化
极坐标 BEV 以 ego 为中心,沿角度和半径两个方向对空间进行划分。其中,角度方向通常采用固定步长,而径向方向则采用非均匀间隔。
- 角度划分:{\theta \in [-\pi, \pi)},以固定步长 {\Delta\theta} 划分为 {N = 2 \pi / \Delta\theta} 个扇区。
- 径向划分:{\rho \in [0, \rho_{max})} ,采用非均匀间隔 {\Delta\rho_i} ,其中 {i = 1, ..., M} 。
这种划分方式使近距离区域拥有更密集的网格,而随着距离增加,单个网格对应的物理面积逐渐增大,从而避免在远距离区域使用大量高分辨率网格。
高度估计替代深度估计
与直接对图像中的每个像素进行深度估计不同,部分极坐标 BEV 方法会直接在 Polar Grid 上估计空间表面的高度。
这种方式将问题从图像空间中的深度预测,转换为 BEV 空间中的表面几何估计。对于以地面和周围环境为主要关注对象的自动驾驶场景,这种表示方式能够直接围绕最终的 BEV 空间进行建模。
特征表示与相机成像特性匹配
相机具有明显的透视成像特性:相同方向上的物体会随着距离变化表现出不同的尺度,而位于不同方向上的区域则对应不同的相机视角。
极坐标网格以传感器为中心进行划分,径向方向对应距离变化,角度方向对应观察方向。这种空间划分方式与相机的射线传播关系更加一致,使不同距离和不同方向上的特征能够按照更符合几何关系的方式组织。
特别是对于 LiDAR 数据,极坐标划分还能够减少远距离区域的计算冗余,并在一定程度上适应点云近密远疏的分布特点。
PolarNet
PolarNet 是较早采用极坐标表示进行点云语义分割的方法,使用单模态 LiDAR 数据作为输入。
核心创新点包括以下三点:
极坐标点云投影和特征提取
PolarNet 将点云从笛卡尔坐标系转换到 {(\rho, \phi, z)} 极坐标表示,并按照径向、角度和高度进行网格划分。从俯视角度观察,{(\rho, \phi)} 两个维度形成环形网格结构。
由于极坐标网格的面积会随着半径增加而增大,这种非均匀划分方式能够在一定程度上适应 LiDAR 点云近密远疏的分布特性,使不同距离区域的网格点数分布更加均衡。
同时,论文通过实验发现,相比传统的笛卡尔坐标网格,同一个极坐标网格中的点具有更高概率属于同一种语义类别。
这一点也可以从 LiDAR 的工作方式理解。LiDAR 发射的激光本质上沿着射线传播,而 Polar Grid 的角度边界与这些射线方向天然对应。类似地,相机中的每个像素同样对应一条从相机中心出发的视线,因此极坐标表示与多种传感器的观测几何都具有较好的匹配关系。
# 笛卡尔坐标 → 极坐标变换
def cart2polar(input_xyz):
rho = np.sqrt(input_xyz[:, 0]**2 + input_xyz[:, 1]**2) # 距离
phi = np.arctan2(input_xyz[:, 1], input_xyz[:, 0]) # 角度
return np.stack((rho, phi, input_xyz[:, 2]), axis=1)
# 在 spherical_dataset 中:
xyz_pol = cart2polar(xyz) # 转换为极坐标
grid_ind = (np.floor((np.clip(xyz_pol, min_bound, max_bound) - min_bound) / intervals)).astype(np.int)
这段代码描述了点云从笛卡尔坐标系转换到极坐标系,并进一步映射到 Polar Grid 的过程。输入 input_xyz 为 {N \times 3} 的点云数据。
首先,通过 input_xyz[:, 0] 和 input_xyz[:, 1] 计算点在水平平面上到坐标中心的距离,即半径。
然后,通过 arctan2 计算对应的角度。
最终,每个点可以表示为:
PolarNet 使用 Simplified PointNet 网络提取每个网格单元中的点云特征。相比许多需要通过 KNN 构建局部邻域的 Point-Level 点云算法,这种基于网格的方式能够更直接地对点云进行序列化和特征提取,从而提高整体处理效率。
环卷积(Ring Convolution)
普通 2D 卷积通常会在边界使用 Zero Padding,这对于普通的矩形特征图没有问题。但是在极坐标表示中,角度维度具有周期性,例如 {0^\circ} 与 {360^\circ} 在物理空间中实际上是连续的。
因此,为了处理极坐标网格在角度维度上的周期性,需要在角度轴的两端进行 Circular Padding(循环填充),从而消除边界截断带来的影响。
代码如下:
class double_conv_circular(nn.Module):
'''(conv => BN => ReLU) * 2'''
def __init__(self, in_ch, out_ch, group_conv, dilation=1):
super(double_conv_circular, self).__init__()
# ... 初始化代码
def forward(self, x):
# 添加循环填充(环形填充)
x = F.pad(x, (1, 1, 0, 0), mode='circular')
x = self.conv1(x)
# 再次进行循环填充
x = F.pad(x, (1, 1, 0, 0), mode='circular')
x = self.conv2(x)
return x
虽然极坐标空间在物理意义上是一个圆形区域,但为了使用常规的 2D 卷积操作,特征最终仍然会被展开成矩形特征图。
对于一个 2D 特征,也可以说是一个 4D Tensor:
pad 函数中的 (1, 1, 0, 0) 参数可以理解为:
# F.pad(x, (left, right, top, bottom, front, back, ...))
# (最后维 最后维 倒数第 2 维 倒数第 2 维 ...)
F.pad(x, (1, 1, 0, 0), mode='circular')
│ │ │ │
│ │ │ └── Height 下方填充 0 行
│ │ └───── Height 上方填充 0 行
│ └──────── Width 右侧填充 1 列 ← 角度维度
└─────────── Width 左侧填充 1 列 ← 角度维度
给一个更直观的示例。假设极坐标特征被展开成 8 列,对应不同的角度区间:
原始 8 列(角度从左到右):
Col: 0 1 2 3 4 5 6 7
[A][B][C][D][E][F][G][H] ← φ ∈ [-π, π]
循环填充后:
Col: -1 0 1 2 3 4 5 6 7 8
[H][A][B][C][D][E][F][G][H][A]
└右端 └─────────────────┘ └左端
环绕到左 原始 8 列数据 环绕到右
含义:
- 左侧填充 [H] ← 原来最右侧的值,在角度上与 φ = -π 相邻
- 右侧填充 [A] ← 原来最左侧的值,在角度上与 φ = π 相邻
而径向方向则不具有这种周期性,因此仍然可以使用普通的 Zero Padding。
所以,Ring Convolution 本身仍然使用普通的卷积 Kernel,特殊之处主要在于 Padding 的方式:角度维度使用 Circular Padding,而其他维度仍然按照普通方式处理。
经过 U-Net 处理后,网络会对每个极坐标网格进行类别预测。由于 Polar Grid 的划分方式能够提高同一网格内点属于相同语义类别的概率,因此 PolarNet 可以在避免复杂 Point-Level 上采样解码的情况下完成点云语义分割。
PolarBEV
PolarBEV 是地平线提出的一种基于极坐标 BEV 表示的视觉感知方法,使用单模态多相机图像作为输入。
虽然输入数据从 LiDAR 变成了图像,但极坐标表示仍然具有明显优势。相机近大远小的透视关系、以 ego 为中心的观测射线,以及 Polar Grid 与空间方向之间的对应关系,都使得极坐标表示能够更自然地组织 BEV 空间中的视觉特征。
Rearrangement
首先,将 BEV 空间沿角度和半径方向进行栅格化,其中角度方向采用均匀划分,而径向方向采用非均匀划分。
随后,通过 Ring Conv 和 Circular Padding 处理角度维度上的周期性连接问题,并将 Polar Grid 中的特征重组成矩形特征图,从而方便后续直接使用 2D 卷积。
整体结构看起来与 PolarNet 比较相似,但由于输入数据模态不同,两者在特征构建方式上存在明显区别。
LiDAR 自身提供 3D 坐标,因此点可以直接根据空间位置分配到 Polar BEV Grid 中。而相机输入只有 2D 图像特征,需要先通过 Lift 过程建立图像特征与 BEV 空间之间的几何对应关系,然后才能将图像特征聚合到 Polar Grid 中。
Polar Embedding Decomposition
极坐标表示可以从径向和角度两个维度理解:
- 径向特性:描述不同距离上的空间位置和尺度变化。
- 角度特性:描述不同方向上的观察区域和视角关系。
因此,论文为每个 Polar Grid 预定义一个可学习的 Query Embedding,并将其分解为径向和角度两个部分:
- {q_i^{rad}} :半径相关的 Query。
- {q_i^{ang}} :角度相关的 Query。
最终,第 \text{i} 个 Polar Grid 的 Query 可以表示为:
通过这种分解方式,网络可以分别学习不同距离和不同方向上的空间特征,再将两部分信息组合为完整的 Polar Query,从而增强 BEV 特征的空间表达能力。
Iterative Surface Estimation
Lift 的过程并没有采用类似 LSS 的离散深度分布预测路线,而是采用基于几何对齐的逆向映射方法。具体实现机制为迭代表面估计(Iterative Surface Estimation)。
初始化时,网络会假设车辆周围存在一个 Hypothetical Plane,也就是一个初始的平坦地面。对于 Polar BEV Grid 中的每个网格 {(r, \theta, h)} ,初始高度设置为 0。
由于真实场景中的道路和周围环境并不是完全平坦的,因此网络会根据 Query Embedding 对每个网格的高度进行迭代更新:
其中:
- {h_i^t} :第 \text{t} 次迭代后,第 \text{i} 个网格的高度。
- {\Theta} :用于预测高度变化量的 MLP。
- {q_i^{t-1}} :上一次迭代的 Query Embedding。
- {h_i^{t-1}} :上一次迭代的高度值。
这是一个残差更新过程,模型预测的是高度变化量,而非直接预测最终高度。将预测的高度变化量加到上一次迭代的高度上,即可得到当前迭代的高度。
随后进行高度归一化:
然后从极坐标转换到笛卡尔坐标系:
接着构建齐次坐标:
其中,齐次坐标的作用是将空间坐标变换和投影统一表示为矩阵运算。
随后,将 {\mathbf{w}_i} 投影到第 \text{n} 个相机图像平面:
其中 {\mathbf{I}_n} 和 {\mathbf{E}_n} 分别表示第 \text{n} 个视角相机的内参和外参。
经过齐次坐标归一化后,可以得到图像上的像素坐标:
然后进行特征转换。这个过程实际上是一个多视角特征聚合过程,其中隐去了具体的特征采样操作。
此时,CNN 已经从多个相机视角中提取完 2D 特征 {F_n} 。然后根据 {p_{i,n}} ,也就是对应的像素坐标,从相应位置的图像特征图中采样,得到 {F_{i,n}} 。
最终进行特征聚合:
其中:
- {f_i} :BEV 视角下第 \text{i} 个网格的特征。
- {M_{i,n}} :二进制掩码,用于判断第 \text{i} 个 Polar Grid 是否能够被第 \text{n} 个相机观测到。
- {F_{i,n}} :投影位置对应的图像特征。
如果同一个 Polar Grid 对应的 3D 位置同时落在多个相机视野中,则可以聚合这些相机对应位置的图像特征。
Head
基于 FIERY 论文中的 Head,Loss Function 也采用相同的设计思路。
网络首先通过 Encoder-Decoder 结构进一步细化 BEV 特征,然后连接多个预测分支:
- Seg Score:预测每个位置的语义类别概率。
- Offset:预测每个像素指向所属实例中心的偏移量。
- Centerness:预测每个像素属于实例中心区域的概率。
对应代码如下:
self.segmentation_head = nn.Sequential(
nn.Conv2d(shared_out_channels, shared_out_channels, kernel_size=3, padding=(0, 1), bias=False),
nn.BatchNorm2d(shared_out_channels),
nn.ReLU(inplace=True),
nn.Conv2d(shared_out_channels, n_classes, kernel_size=1, padding=0),
)
self.instance_offset_head = nn.Sequential(
nn.Conv2d(shared_out_channels, shared_out_channels, kernel_size=3, padding=(0, 1), bias=False),
nn.BatchNorm2d(shared_out_channels),
nn.ReLU(inplace=True),
nn.Conv2d(shared_out_channels, 2, kernel_size=1, padding=0),
)
self.instance_center_head = nn.Sequential(
nn.Conv2d(shared_out_channels, shared_out_channels, kernel_size=3, padding=(0, 1), bias=False),
nn.BatchNorm2d(shared_out_channels),
nn.ReLU(inplace=True),
nn.Conv2d(shared_out_channels, 1, kernel_size=1, padding=0),
nn.Sigmoid(),
)
self.instance_future_head = nn.Sequential(
nn.Conv2d(shared_out_channels, shared_out_channels, kernel_size=3, padding=(0, 1), bias=False),
nn.BatchNorm2d(shared_out_channels),
nn.ReLU(inplace=True),
nn.Conv2d(shared_out_channels, 2, kernel_size=1, padding=0),
)
PolarFormer
PolarFormer 将极坐标 BEV 与 Transformer 结合,用于多相机 3D 目标检测。也是单模态的相机图像作为输入,执行 3D 检测任务。
Polar Cross-Attention
几何对齐:因为极坐标的定义方式与相机的透视成像几何具有较好的对应关系。模型利用相机的内外参完成 3D 到 2D 的几何投影,计算每个 Polar Query 在 2D 图像上对应的像素区域。
Sequence-to-Sequence 聚合:Polar Query 作为 Transformer 中的 Query,对应的 2D 图像特征作为 Key 和 Value。通过 Cross-Attention,每个 Polar Query 从与自身空间位置相关的图像区域中聚合视觉特征。
Multi-scale Polar FPN
在极坐标网格中,靠近相机的网格物理面积非常小,而远离相机的网格物理面积非常大。同样一辆汽车,在近处可能占据几十个网格,而在远处可能只占据少量网格。
为了缓解极坐标非均匀网格带来的尺度不均衡问题,PolarFormer 设计了类似 FPN 的多尺度特征结构。
通过不同尺度的 Polar Feature Map,网络能够同时保留高分辨率的空间细节,并利用低分辨率特征获得更大的感受野和更强的语义信息。
因此,Multi-scale Polar FPN 的核心目的并不是简单地按照近处或远处分别使用某一种固定分辨率,而是通过多尺度特征融合,使不同距离区域中的目标都能够获得更合适的特征表达。
Polar Head
极坐标 BEV 特征构建完成后,通过 Polar Head 预测 3D BBox 的类别、位置、尺寸和朝向。
目标的位置使用极坐标形式表示:
同时预测 3D BBox 的宽、高、长以及朝向角 {\theta} 。
最终,通过基础的三角函数关系,将目标中心从极坐标系转换回笛卡尔坐标系:
从而得到最终的 3D BBox 空间位置。
参考文章
[4] SuperZ-Liu/PolarBEV: The offical code of PolarBEV (CoRL2022).
[5] [2206.15398] PolarFormer: Multi-camera 3D Object Detection with Polar Transformer
评论