深夜仓库里散落着一千张会发光的纸片,每张纸片都写着一组三维坐标,代表激光雷达从周围物体上弹回来的信号。这些纸片没有行列、没有顺序,也不均匀——这就是点云。想从里面找出藏着的车辆和行人,必须先给它们建立秩序。VoxelNet 像一位认真细致的整理员,搬来立体书架:把仓库切成成千上万个等大的小格子,纸片按坐标扫进格子;PointPillars 则像另一位麻利的整理员,他竖起一排排贯穿屋顶的竖档文件柜,纸片只按地面 XY 位置进档,高度则作为备注写在纸片上。一个精细但笨重,一个轻快但略粗。这篇文章会用这个仓库隐喻,带你弄懂两种经典方案的结构差异、速度与精度的权衡,以及工程上该如何选型。

岗位关联

学完这个对比,你可以在机器人 3D 感知项目里快速判断“要精度优先”还是“要速度与易部署优先”,直接为点云检测方案选型提供决策依据。

目录
  1. 可视化演示
  2. 点云与检测任务
  3. VoxelNet架构
  4. PointPillars架构
  5. 核心差异对比
  6. 性能与精度权衡
  7. 工程落地与选型
  8. AI 应用场景
  9. Python 演示
  10. 常见误区
  11. 面试题

可视化演示

动态演示VoxelNet与Point的核心机制,通过源头/管道/节点/终端四种模式展示关键概念与交互流程。

本节配有交互动效(进入视口后自动加载,约 3KB)。

VoxelNet与Point:D目标检 3D目标检测问题与点云挑战 VoxelNet体素化网络架构 核心机制可视化 VoxelNet与Point整体架构与关键组件

点云与检测任务

回到深夜仓库:激光雷达每秒钟发出几十万条激光束,碰到物体后反射回来,形成一堆带坐标的“纸星”。纸星之间没有顺序,同一面墙可能收到几千颗,远处的物体却只有几颗。3D 目标检测的任务,就是在这堆纸星里找出“哪里有车、哪里有人、哪里有自行车”,并画一个立体的方框把它框住。

点云的每个点通常由 \((x,y,z,r)\) 构成,其中 \(r\) 是反射强度。它与图片最大的不同是:图片有规整的像素矩阵,点云却没有行列顺序。点云天然稀疏,距离越远越疏。如果直接把原始点云塞给全连接网络,网络不知道哪些点属于同一个物体;必须先做离散化或结构化。这一步的选择,直接决定了后面模型的速度和精度。

3D 检测框不是普通的 2D 矩形,而是带朝向的立体框。一辆停在斜方向的车,如果不标注朝向,两个矩形框虽然重合,却无法描述车头指向哪里。因此,业界通常用 7 个数字来表示一个框:

就像整理仓库前先确认要找什么:如果只想找兔子的大概位置,一个大筐就够;但自动驾驶需要知道车头朝向,才能预测它会不会撞上来。检测框就是这张清单,后面的体素或柱体结构化方式,都是在为这张清单服务。

Box=(x,y,z,l,w,h,θ)\displaystyle \text{Box}=(x, y, z, l, w, h, \theta)
  1. 中心坐标检测框的几何中心在三维空间中的位置,由三个数字组成。
    center=(x,y,z)\text{center}=(x, y, z)
  2. 长宽高物体在三维空间中占据的包围盒尺寸。
    size=(l,w,h)\text{size}=(l, w, h)
  3. 朝向角物体在地面平面上的旋转角度,使框贴合车辆的实际方向。
    θ∈(−π,π]\theta \in (-\pi, \pi]
  4. 完整表示这七个数字合起来,就是一个可旋转的 3D 检测框。
    Box=(x,y,z,l,w,h,θ)\text{Box}=(x, y, z, l, w, h, \theta)

VoxelNet架构

VoxelNet 选择把仓库从地面到天空切成固定大小的小格子,像立体书架一样。每一格的宽、深、高都是预先定好的,散落的纸星按照三维坐标被扫进对应格子里。如果某个格子一颗星都没有,就让它空着,但书架本身依然存在。这种以三维立方体为单位组织数据的方式,就是“体素化”。

体素化之后,原始点云变成稀疏的三维网格。VoxelNet 引入 VFE(Voxel Feature Encoding)层来处理每个非空体素:先把每个点的坐标、反射率与它相对体素中心的偏移拼在一起;再通过一个 MLP 生成高维特征;最后在体素内部做最大值池化,形成这个格子的代表特征。最大值池化会保留最显著响应,而不是简单平均,因此对局部几何更敏感。

所有非空体素特征会组成一个四维张量,进入 3D 卷积中间层,让邻近体素交换信息。之后接一个区域提议网络(RPN)输出检测框。3D 卷积能捕捉局部几何关系,但也是主要性能瓶颈:三维空间里的邻居数量比二维多得多,计算量自然更大。立体书架的好处是细致,坏处是空书架也占地方。

vk=max⁡i∈Vk(MLP([pi;pi−ck]))\displaystyle \mathbf{v}_k=\max_{i \in \mathcal{V}_k}\left(\mathrm{MLP}\left(\left[\mathbf{p}_i; \mathbf{p}_i-\mathbf{c}_k\right]\right)\right)
  1. 点特征第 \(i\) 个激光点包含坐标和反射率,是体素处理的基本单位。
    pi=(xi,yi,zi,ri)\mathbf{p}_i = (x_i, y_i, z_i, r_i)
  2. 中心偏移用点的坐标减去第 \(k\) 个体素的中心,得到局部位置关系。
    oi=pi−ck\mathbf{o}_i = \mathbf{p}_i - \mathbf{c}_k
  3. 特征变换把原始点和偏移拼成一个向量,送入 MLP 学习更高层特征。
    ei=MLP([pi;oi])\mathbf{e}_i = \mathrm{MLP}([\mathbf{p}_i; \mathbf{o}_i])
  4. 最大池化对一个体素内所有点做最大值池化,得到该体素的代表特征。
    vk=max⁡i∈Vkei\mathbf{v}_k = \max_{i \in \mathcal{V}_k} \mathbf{e}_i

PointPillars架构

PointPillars 换了一种整理思路:它把仓库改成竖档文件柜,每个档案格从地面一直通到天花板,只按 XY 坐标决定纸星进哪个竖档,高度不单独开格子,而是作为备注写进纸星里。这种“柱体”划分大幅减少了格子总数,是 PointPillars 速度优势的根本来源。

每个柱体内的点不会直接被丢弃,而是构造一个 9 维特征向量:包含原始坐标 \(x,y,z\)、反射率 \(r\)、到柱体中心的三维距离,以及到所在 XY 栅格中心的偏移。这个丰富的特征让网络即使不做 Z 方向切分,也能感知垂直结构。然后使用 PointNet 对柱体内所有点做特征编码,再取最大值池化,得到柱体级别的代表特征。

得到每个柱体的特征后,PointPillars 会按 XY 坐标把这些特征散布到一个二维网格上,形成一张“伪图像”。伪图像仍然保留高度和反射率信息,但组织方式变成了规则的二维图像,后续可以直接使用成熟的 2D 卷积检测网络。竖档文件柜舍弃了 Z 方向切分,却没有丢掉垂直信息,这正是它又快又不明显掉精度的关键。

ek=max⁡i∈PkPointNet((xi,yi,zi,ri,xi−xc,yi−yc,zi−zc,xi−xp,yi−yp))\displaystyle \mathbf{e}_k = \max_{i \in \mathcal{P}_k} \mathrm{PointNet}\left((x_i,y_i,z_i,r_i,x_i-x_c,y_i-y_c,z_i-z_c,x_i-x_p,y_i-y_p)\right)
  1. 原始点信息先保留每个点的三维坐标和反射率。
    (xi,yi,zi,ri)(x_i, y_i, z_i, r_i)
  2. 柱体中心偏移计算点到它所在柱体中心的三维距离。
    (xi−xc,yi−yc,zi−zc)(x_i-x_c, y_i-y_c, z_i-z_c)
  3. 栅格中心偏移计算点到 XY 网格中心的二维偏移,帮助定位点在该柱体中的相对位置。
    (xi−xp,yi−yp)(x_i-x_p, y_i-y_p)
  4. PointNet 编码把上述信息拼成 9 维向量,用 PointNet 对每个点做非线性变换。
    PointNet(⋅)\mathrm{PointNet}(\cdot)
  5. 最大池化在柱体内部做最大值池化,得到这个竖档的代表特征。
    ek=max⁡i∈Pk(⋅)\mathbf{e}_k = \max_{i \in \mathcal{P}_k}(\cdot)

核心差异对比

如果把体素和柱体看成两种整理账本:VoxelNet 的账本按三维格子逐层记账,PointPillars 的账本只按 XY 柜台记账,Z 信息作为备注写在每张纸星上。两者本质区别不在于“谁更先进”,而在于中间表示从 3D 张量变成 2D 伪图像后,整个网络的计算模式发生了变化。

VoxelNet 需要维护 \(N_x \times N_y \times N_z\) 个潜在体素,即使只对非空体素做计算,检索和稀疏处理依然复杂;PointPillars 最多只有 \(N_x \times N_y\) 个柱体。假设 Z 方向被切成 \(N_z\) 层,那么柱体表示在格子数量上会少一个数量级:

这两种方式在特征编码上也不同:VoxelNet 用 VFE 加 3D 卷积,适合直接学习三维局部结构;PointPillars 用 PointNet 加 2D 卷积,先压缩再检测。计算复杂度的差异最终表现为:体素方案需要更多算力换精度,柱体方案用更轻量的网络换取实时性。

NPNV=NxNyNxNyNz=1Nz\displaystyle \frac{N_P}{N_V} = \frac{N_x N_y}{N_x N_y N_z} = \frac{1}{N_z}
  1. 体素总数三维体素把空间切成 X、Y、Z 三个方向上的立方体,总数为三者乘积。
    NV=Nx×Ny×NzN_V = N_x \times N_y \times N_z
  2. 柱体总数柱体只在 XY 平面划分,没有 Z 方向切分,因此总数少乘一个 \(N_z\)。
    NP=Nx×NyN_P = N_x \times N_y
  3. 比值柱体数量是体素数量的 \(1/N_z\),Z 分层越多,节省越明显。
    NPNV=1Nz\frac{N_P}{N_V} = \frac{1}{N_z}

性能与精度权衡

立体书架精细,竖档文件柜迅速。VoxelNet 对空间分层更细,能更好地区分上下重叠的物体;PointPillars 走鸟瞰图路线,丢失了精细的高度切分,但换来了速度和更稳定的训练过程。两者在 KITTI 等公开数据集上的表现也印证了这种权衡。

在相同条件下,PointPillars 的推理速度通常比 VoxelNet 快数倍到十余倍,显存占用也更低。精度上,PointPillars 的车体检测 AP 往往比 VoxelNet 低两到四个百分点,但很多工业场景中这个差距可以接受,尤其是当传感器线数较低、点云稀疏时,体素方案的优势并不明显。

| 对比维度 | VoxelNet | PointPillars |

| --- | --- | --- |

| 中间表示 | 稀疏三维体素 | 柱体伪图像 |

| 主要卷积 | 3D 卷积 | 2D 卷积 |

| 相对速度 | 慢 | 快 |

| 小目标/遮挡精度 | 较高 | 略低 |

| 显存占用 | 高 | 低 |

| 部署优化难度 | 高 | 低 |

但速度与精度的权衡不是固定的。稀疏卷积、TensorRT、FP16 和专用算子都能同时优化两者。PointPillars 在低算力平台上更容易达到实时;VoxelNet 经过工程优化后也能改善,但投入的精力更大。选型不是问哪个绝对好,而是问你的仓库需要几点前清点完:夜间巡逻要求 30Hz 响应,就选竖档;离线制图愿意多等 0.1 秒,就选精细书架。

工程落地与选型

工程落地首先要看生态。PointPillars 因为生成的是伪图像,可以直接复用 2D 检测领域的成熟优化:TensorRT、FP16、NPP 库、CUDA 核都有现成方案;VoxelNet 需要自定义 3D 卷积算子,算子优化高度依赖框架和硬件厂商支持,部署成本明显更高。

在机器人场景中,算力通常是 Jetson 这类嵌入式平台,点云密度有限,PointPillars 往往成为默认第一版方案。如果场景需要识别密集重叠的行人与自行车,并且允许更高功耗,VoxelNet 或混合方案会更合适。选型建议如下:

1. 对延迟有硬指标,例如自动驾驶 30Hz 推理,优先 PointPillars。

2. 离线处理高密度点云,例如高精地图自动标注,选 VoxelNet。

3. 想要快速迭代验证算法,先用 PointPillars,后续再针对难点优化。

4. 需要同时完成 BEV 分割、路径规划等多任务,伪图像结构更方便共享特征。

最终,所有方案都要依靠数据闭环和评测指标验证。没有万能的仓库整理方式,只有适合当前货物、仓库高度和限时要求的方案。多做几次对照实验,比在纸面上争论“谁更强”更有价值。

AI 应用场景

自动驾驶实时感知

阶段:模型选型与推理部署

解决的问题:传统 2D 检测无法直接处理雷达点云,而 VoxelNet 的 3D 卷积在车规级计算平台上难以达到实时。PointPillars 先把点云变成竖档柱体,再散布成伪图像,用 2D 卷积完成检测,延迟低且部署链路成熟。

具体案例:某 Robotaxi 项目使用 32 线激光雷达,感知模块要求每帧 80ms 内输出车辆和行人框。工程师以 PointPillars 为骨干网络,搭配 TensorRT FP16,在 Orin 平台达到 25FPS,并将模型量化误差控制在 1% 以内。

低速物流 AGV 避障

阶段:模型训练与边缘部署

解决的问题:AGV 上算力有限,常见 16 线激光雷达点云稀疏,直接上 VoxelNet 容易出现大量空体素,浪费算力。PointPillars 只按 XY 分竖档,对稀疏点更稳定,也更符合室内低速场景的实时避障需求。

具体案例:一个工厂仓储 AGV 项目需要识别前方 5 米内的人、托盘和叉车。算法团队在 Jeston Orin Nano 上部署 PointPillars,达到 20FPS,误检率低于 2%,成功支撑了自动急停与绕障。

离线高精地图自动标注

阶段:离线数据处理与自动化标注

解决的问题:高精地图制图车使用 64 线激光雷达,点云密集、数据量大,不需要实时推理,却需要尽可能高的检测精度。VoxelNet 的三维体素和 3D 卷积能更好还原物体轮廓,适合离线批量生成候选框。

具体案例:某图商使用 VoxelNet 对城市道路点云自动标注路杆、路口和车辆,后期人工只修正边缘框,标注效率提升了约 60%,尤其改善了高层遮挡场景下的召回率。

Python 演示

python49 行
import numpy as np def voxel_encode(points, voxel_size=0.4, max_groups=64):    indices = np.floor(points[:, :3] / voxel_size).astype(int)    groups = {}    for i, idx in enumerate(indices):        key = tuple(idx)        if key in groups:            groups[key].append(points[i])        elif len(groups) < max_groups:            groups[key] = [points[i]]    feats = []    for pts in groups.values():        pts = np.array(pts)        center = pts[:, :3].mean(axis=0)        aug = np.hstack([pts, pts[:, :3] - center])        feats.append(aug.max(axis=0))    return np.array(feats) def pillar_encode(points, grid_size=0.4, max_groups=64):    xy_idx = np.floor(points[:, :2] / grid_size).astype(int)    groups = {}    for i, idx in enumerate(xy_idx):        key = tuple(idx)        if key in groups:            groups[key].append(points[i])        elif len(groups) < max_groups:            groups[key] = [points[i]]    feats = []    for pts in groups.values():        pts = np.array(pts)        center_xy = pts[:, :2].mean(axis=0)        center_xyz = np.append(center_xy, 0.0)        pfeat = np.hstack([pts, pts[:, :3] - center_xyz, pts[:, :2] - center_xy])        feats.append(pfeat.max(axis=0))    return np.array(feats) def main():    rng = np.random.default_rng(0)    points = rng.random((500, 4))    voxel_feats = voxel_encode(points)    pillar_feats = pillar_encode(points)    print("voxel groups:", voxel_feats.shape[0])    print("pillar groups:", pillar_feats.shape[0])    print("voxel feature dim:", voxel_feats.shape[1])    print("pillar feature dim:", pillar_feats.shape[1]) if __name__ == "__main__":    main()
目的:用小型随机点云模拟体素与柱体两种组织方式,直观看到柱体分组更少、特征维度更高,对应 PointPillars 计算更轻的特点。
  1. indices = np.floor(points[:, :3] / voxel_size).astype(int)用整数索引把连续空间切成体素格子。
  2. groups[key].append(points[i])同一格子的点聚到一起,天然处理无序点云。
  3. center = pts[:, :3].mean(axis=0)`; `aug = np.hstack([pts, pts[:, :3] - center])加入相对中心偏移,让特征带位置上下文。
  4. feats.append(aug.max(axis=0))最大池化,保留体素内最显著特征。
  5. xy_idx = np.floor(points[:, :2] / grid_size).astype(int)柱体只看 XY,所以 Z 不参与分组。
  6. pfeat = np.hstack([pts, pts[:, :3] - center_xyz, pts[:, :2] - center_xy])9 维柱体特征,高度仍保留在数值中。

常见误区

误区我觉得点云有坐标,把它填成一个固定大小的三维数组不就行了,把二维卷积改成三维卷积,就跟图像检测一样了。

正解点云不像图像每个像素都有值,大部分位置是空的。直接建稠密网格会浪费算力和显存,而且点云的点数、顺序不固定。需要先用体素或柱体这样的稀疏表示,再用 PointNet 或稀疏卷积聚合。好比不能要求仓库里每个书架格子都塞满纸星,只有非空格才值得读。

为何常见:学 2D 检测时习惯了规则像素,下意识把坐标离散化想象成填数组。

误区为了不漏掉小物体,我把体素设成 1 厘米,分辨率越高精度一定越高。

正解格子越小,空体素数量会指数增长,3D 卷积和显存开销都会爆炸,反而导致训练变慢甚至跑不起来。体素大小要与点云密度匹配,激光雷达点云通常使用几十厘米量级的体素,并配合稀疏化技术。

为何常见:直觉认为分辨率越高越好,忽略了稀疏性和算力约束。

误区柱子只按 XY 分组,高度信息完全丢了,所以它一定比 VoxelNet 差很多。

正解PointPillars 只是不按 Z 方向切格,但每个点仍然把 \(z\)、到柱体中心的三维偏移写进特征里,后续网络可以恢复高度。就像竖档文件柜不把文件按层分格,但每张纸上都写了层高备注。

为何常见:从示意图上看柱体是二维网格,容易被误读成丢失高度。

误区既然算力差了十几倍,检测精度肯定也差十个百分点,所以不能用在精确任务上。

正解在 KITTI 等基准上,PointPillars 与 VoxelNet 的 AP 差距通常只有几个点,经过数据增强和工程调优后差距还会缩小。速度收益主要来自去掉 Z 方向空体素和 3D 卷积,而不是粗暴丢信息。

为何常见:把速度与精度看成简单线性对立,忽略了特征编码保留了大量关键信息。

误区我选了 PointPillars,部署时应该能直接 20FPS 跑在 Jetson 上,不需要再调。

正解工程落地还要处理点云预处理、张量形状、TensorRT 算子支持、多雷达融合、后处理、类别不平衡等问题。选型只是第一步,PointPillars 的 2D 伪图像确实更容易复用成熟优化,但依然需要大量适配工作。

为何常见:算法工程师常低估部署优化成本,以为网络轻就一定快。

面试题

Q1. PointPillars 把点云划分成哪种单元?

单选题 · easy

  • A.三维立方体体素
  • B.垂直方向的柱体← 正确答案
  • C.二维灰度像素
  • D.完全无序的点列表

答案:B。PointPillars 只在 XY 平面划分柱体,Z 方向不单独切格,所有高度信息通过特征编码保留。A 是 VoxelNet 的做法,C 和 D 都不符合柱体化思路。

Q2. VoxelNet 在一个体素内聚合点特征时,主要使用哪个操作?

单选题 · easy

  • A.最大值池化← 正确答案
  • B.全局平均池化
  • C.随机采样
  • D.中值滤波

答案:A。VFE 层在 MLP 变换后使用最大值池化,保留体素内最显著的点特征。平均池化会稀释峰值响应,随机采样和信息丢失有关,中值滤波不是 VFE 的标准操作。

Q3. 一个用于水平路面物体的 3D 检测框通常用几个参数表示?

单选题 · easy

  • A.5
  • B.6
  • C.7← 正确答案
  • D.9

答案:C。3D 检测框一般用中心坐标 \((x,y,z)\)、长宽高 \((l,w,h)\) 和朝向角 \(\theta\),共 7 个参数。5 或 6 个参数通常无法描述旋转框,9 维通常是 PointPillars 的点特征,不是框参数。

Q4. PointPillars 的伪图像是如何生成的?

单选题 · mid

  • A.柱体特征按 XY 坐标散布到二维网格← 正确答案
  • B.体素特征直接拼接成三维张量
  • C.激光点云按距离排序成图片
  • D.RPN 输出的边界框画成图像

答案:A。PointPillars 先把每个柱体编码成特征向量,再根据柱体所在的 XY 坐标把它们放到二维网格上,形成类似图像的伪图像。这个过程是特征散布,不是点云排序,也不是把检测框画出来。

Q5. 在相同条件下,下列哪个说法通常正确?

单选题 · mid

  • A.VoxelNet 推理速度低于 PointPillars← 正确答案
  • B.PointPillars 推理速度低于 VoxelNet
  • C.两者推理速度完全相同
  • D.两者都不能用于激光雷达

答案:A。VoxelNet 使用 3D 卷积和三维体素,计算量更大,通常在同等条件下比 PointPillars 慢。PointPillars 用伪图像和 2D 卷积,速度更快,因此 B 和 C 错误。

Q6. PointPillars 比 VoxelNet 轻量的原因包括?

多选题 · mid

  • A.没有 Z 方向体素划分← 正确答案
  • B.主要使用 2D 卷积← 正确答案
  • C.柱体特征可散布成伪图像← 正确答案
  • D.完全不用点云原始特征

答案:ABC。PointPillars 不做 Z 方向切格,减少空格数量;伪图像使后续卷积变成 2D,计算更高效。它没有丢掉点云原始特征,点的坐标、反射率和中心偏移仍然参与编码,因此 D 错误。

Q7. VFE 层把哪两部分特征拼接后再送入 MLP?

单选题 · mid

  • A.点特征与体素中心偏移← 正确答案
  • B.检测框与类别概率
  • C.伪图像与灰度图
  • D.时间戳与雷达 ID

答案:A。VFE 层拼接原始点特征和相对体素中心的偏移,使网络知道每个点在自己的格子里处于什么位置。检测框、伪图像和时间戳都出现得更晚,不属于 VFE 输入。

Q8. 在 16 线稀疏点云和低功耗 Jetson 平台上,通常优先选择哪个方案?

单选题 · hard

  • A.高分辨率 VoxelNet
  • B.PointPillars← 正确答案
  • C.纯 3D 卷积网络
  • D.先补点云再检测

答案:B。稀疏点云下,高分辨率体素会产生大量空体素,3D 卷积在低功耗平台上难以实时。PointPillars 的柱体结构对稀疏点更稳定,部署更轻量。补点云会引入伪信息,不是首选。

Q9. VoxelNet 在密集点云上的主要劣势包括?

多选题 · hard

  • A.体素数量巨大← 正确答案
  • B.3D 卷积计算开销高← 正确答案
  • C.显存占用偏高← 正确答案
  • D.无法输出三维朝向

答案:ABC。密集点云下,非空体素增多,三维网格规模变大,3D 卷积和显存开销也会上升。VoxelNet 完全可以输出带朝向的 3D 框,因此 D 错误。

Q10. 关于 VoxelNet 与 PointPillars 在 KITTI 上车体检测的对比,合理说法是?

单选题 · extreme

  • A.二者 AP 差距通常不大但速度量级不同← 正确答案
  • B.VoxelNet 的 AP 比 PointPillars 高约 30 个点
  • C.PointPillars 的速度比 VoxelNet 还慢
  • D.PointPillars 完全不检测车辆

答案:A。在同一数据集上,VoxelNet 的精度通常略高,但差距一般只有几个百分点,而 PointPillars 在速度上往往能快数倍到十余倍。高 30 个点、速度更慢或完全不检测车辆都不符合实际。