从稀疏到完整:JS3C-Net如何用场景补全提升点云分割
从稀疏到完整:JS3C-Net如何用场景补全提升点云分割
🚗 自动驾驶入门系列第二篇 | 作者:小探
📅 发布时间:2026年6月10日
前言
上一篇我们介绍了LMSCNet——一个轻量级的3D语义补全网络。今天我们来看另一篇有趣的工作:JS3C-Net(Joint Semantic-Completion and Classification,联合分割补全和分类任务)。
这篇论文的核心思想非常巧妙:通过场景补全任务,让网络学习到"物体应该长什么样"的先验知识,然后用这些知识来提升点云分割的效果。
一、问题背景:为什么需要这篇论文?
1.1 单帧LiDAR点云的挑战
想象你用LiDAR扫描一辆车,只能得到车表面的点,车内部是空的。这就是单帧(single sweep)点云的特点:
单帧点云特点:
✓ 只包含物体表面点
✓ 点云非常稀疏(一辆车可能只有几十个点)
✗ 看不到被遮挡的部分
✗ 无法获取完整的3D结构
1.2 现有方法的局限
| 方法类型 | 问题 |
|---|---|
| 纯分割方法 | 只关注可见点,忽略上下文 |
| 纯补全方法 | 只预测占用,不区分语义 |
| 体素化方法 | 丢失点级精度 |
1.3 JS3C-Net的核心洞察
"分割"和"补全"是互补的任务!
- 分割需要知道"这是什么"
- 补全需要知道"这里应该有什么"
通过联合学习,网络可以学到更丰富的3D形状先验。
二、核心知识点:理解JS3C-Net的关键概念
2.1 什么是上下文形状先验(Contextual Shape Priors)?
形状先验:网络学习到的"物体应该长什么样"的知识。
例子:学习"车"的形状先验
- 车通常是长方体形状
- 车轮在底部四个角
- 车窗在上部
- 即使只看到车的一部分,也能推断出完整形状
2.2 点级特征 vs 体素级特征
JS3C-Net同时处理两种特征:
点级特征(Point-level):
├── 保留精确的点位置
├── 适合精细分割
└── 但缺乏上下文信息
体素级特征(Voxel-level):
├── 提供3D结构信息
├── 适合场景补全
└── 但损失点级精度
2.3 稀疏卷积(Sparse Convolution)
传统3D卷积在空区域也做计算,浪费算力。稀疏卷积只在有点的区域计算:
传统卷积:O(N³) 计算量
稀疏卷积:O(K) 计算量,K << N³
┌─────────────────┐
│ ■ ■ ■ ■ ■ ■ ■ ■ │ ■ = 有点(需要计算)
│ ■ □ □ □ □ □ □ ■ │ □ = 空(跳过计算)
│ ■ □ □ □ □ □ □ ■ │
│ ■ □ □ □ □ □ □ ■ │
│ ■ □ □ □ □ □ □ ■ │
│ ■ □ □ □ □ □ □ ■ │
│ ■ □ □ □ □ □ □ ■ │
│ ■ ■ ■ ■ ■ ■ ■ ■ │
└─────────────────┘
三、JS3C-Net架构详解
3.1 整体架构
输入:单帧LiDAR点云 [N, 4] (x, y, z, intensity)
↓
┌───────────────────────────────────────────┐
│ Sparse UNet 编码器 │
│ ┌─────────────────────────────────────┐ │
│ │ 稀疏3D卷积层 │ │
│ │ (3×3×3 kernel, stride=2) │ │
│ └─────────────────────────────────────┘ │
│ ↓ │
│ ┌─────────────────────────────────────┐ │
│ │ 稀疏残差块 │ │
│ │ (1×1×1 → 3×3×3 → 1×1×1) │ │
│ └─────────────────────────────────────┘ │
└───────────────────────────────────────────┘
↓
┌───────────────┬───────────────┐
│ 点级分支 │ 体素级分支 │
│ (Point Branch)│ (Voxel Branch)│
└───────┬───────┴───────┬───────┘
↓ ↓
┌───────────────┐ ┌───────────────┐
│ 点云分割 │ │ 场景补全 │
│ [N, 20] │ │ [H,W,D,20] │
└───────────────┘ └───────────────┘
↓ ↓
└───────┬───────┘
↓
联合优化损失
3.2 点级分支(Point Branch)
class PointBranch(nn.Module):
def __init__(self):
# MLP层
self.mlp = nn.Sequential(
nn.Linear(32, 64),
nn.BatchNorm1d(64),
nn.ReLU(),
nn.Linear(64, 128),
nn.BatchNorm1d(128),
nn.ReLU()
)
# 分类头
self.classifier = nn.Linear(128, num_classes)
def forward(self, point_features, voxel_features):
# 从体素特征中采样到点
sampled_features = trilinear_interpolation(
voxel_features, point_coords
)
# 融合点级和体素级特征
fused = torch.cat([point_features, sampled_features], dim=-1)
# MLP处理
output = self.mlp(fused)
# 分类
seg_pred = self.classifier(output)
return seg_pred
3.3 体素级分支(Voxel Branch)
class VoxelBranch(nn.Module):
def __init__(self):
# 解码器
self.decoder = nn.Sequential(
SparseConv3d(128, 64, 3, stride=1),
SparseConv3d(64, 32, 3, stride=1),
SparseConv3d(32, num_classes, 1, stride=1)
)
def forward(self, sparse_features):
# 上采样到原始分辨率
upsampled = sparse_to_dense(sparse_features)
# 预测占用和语义
occ_pred = self.decoder(upsampled)
return occ_pred
3.4 双线性插值聚合(Bilinear Interpolation Aggregation)
这是JS3C-Net的关键创新之一:
def trilinear_interpolation(voxel_features, point_coords):
"""
将体素特征插值到点位置
Args:
voxel_features: [B, C, H, W, D] 体素特征
point_coords: [N, 3] 点坐标 (归一化到[0,1])
Returns:
point_features: [N, C] 点特征
"""
# 找到每个点周围的8个角点
corners = get_8_corners(point_coords)
# 计算插值权重
weights = compute_bilinear_weights(point_coords, corners)
# 加权求和
point_features = sum(
voxel_features[corner] * weight
for corner, weight in zip(corners, weights)
)
return point_features
四、数据增强:Complete-and-Mask
4.1 传统数据增强的问题
传统增强方法:
- 随机旋转:改变视角,但不改变点云密度
- 随机缩放:改变大小,但不改变稀疏性
- 随机平移:改变位置,但不增加新点
问题:无法模拟更密集的点云
4.2 Complete-and-Mask 增强
JS3C-Net提出了一种新的数据增强方法:
Step 1: 补全(Complete)
├── 用场景补全网络预测完整的3D占用
├── 在占用区域采样新的点
└── 得到更密集的点云
Step 2: 遮挡(Mask)
├── 随机遮挡部分区域
├── 模拟遮挡情况
└── 训练网络预测被遮挡的部分
效果:增加训练数据的多样性,提升泛化能力
五、损失函数设计
5.1 多任务损失
def compute_loss(pred_seg, pred_occ, gt_seg, gt_occ):
"""
联合优化分割和补全任务
"""
# 分割损失:加权交叉熵 + Lovász损失
seg_loss = weighted_cross_entropy(pred_seg, gt_seg) + \
lovasz_softmax(pred_seg, gt_seg)
# 补全损失:加权交叉熵
occ_loss = weighted_cross_entropy(pred_occ, gt_occ)
# 总损失
total_loss = seg_loss + 0.5 * occ_loss
return total_loss
5.2 Lovász损失
为什么需要Lovász损失?
问题:IoU不可微,无法直接优化
解决:Lovász扩展,将IoU转化为可微损失
Lovász损失优势:
✓ 直接优化IoU指标
✓ 对类别不平衡更鲁棒
✓ 提升小物体的分割效果
六、实验结果分析
6.1 SemanticKITTI数据集性能
| 方法 | 分割mIoU | 补全mIoU | 速度 |
|---|---|---|---|
| Tang et al. | 52.2 | - | 90ms |
| MinkowskiNet | 63.0 | - | 70ms |
| JS3C-Net | 69.7 | 10.6 | 70ms |
6.2 消融实验
| 配置 | 分割mIoU | 提升 |
|---|---|---|
| 基线(仅分割) | 65.4 | - |
| + 补全任务 | 67.8 | +2.4 |
| + 双分支融合 | 68.9 | +1.1 |
| + Complete-and-Mask | 69.7 | +0.8 |
关键发现:
- 补全任务提升分割:+2.4% mIoU
- 双分支融合:+1.1% mIoU
- 数据增强:+0.8% mIoU
6.3 可视化结果
输入点云 预测分割 真实标签
● ●(车) ●(车)
●●● ●●●(车) ●●●(车)
●●●●● ●●●●●(车) ●●●●●(车)
● ●(路) ●(路)
七、代码实现要点
7.1 稀疏卷积实现
import torch
import torch.nn as nn
class SparseConv3d(nn.Module):
def __init__(self, in_channels, out_channels, kernel_size, stride=1):
super().__init__()
self.conv = nn.Conv3d(
in_channels, out_channels,
kernel_size, stride=stride,
padding=kernel_size//2
)
self.bn = nn.BatchNorm3d(out_channels)
self.relu = nn.ReLU(inplace=True)
def forward(self, x, coords):
# 只在有点的位置计算
dense = sparse_to_dense(x, coords)
out = self.conv(dense)
out = self.bn(out)
out = self.relu(out)
return dense_to_sparse(out, coords)
7.2 点级-体素级特征融合
def fuse_features(point_features, voxel_features, point_coords):
"""
融合点级和体素级特征
"""
# 体素特征插值到点位置
voxel_at_points = trilinear_interpolation(
voxel_features, point_coords
)
# 拼接特征
fused = torch.cat([point_features, voxel_at_points], dim=-1)
# MLP融合
fused = self.fusion_mlp(fused)
return fused
7.3 Complete-and-Mask增强
def complete_and_mask(point_cloud, occupancy_grid):
"""
Complete-and-Mask数据增强
"""
# Step 1: 从占用网格采样新点
completed_points = sample_from_occupancy(occupancy_grid)
# Step 2: 合并原始点云和补全点云
augmented = torch.cat([point_cloud, completed_points], dim=0)
# Step 3: 随机遮挡
mask = random_mask(augmented.shape[0], ratio=0.2)
augmented = augmented[mask]
return augmented
八、论文的核心启示
8.1 技术启示
| 启示 | 说明 |
|---|---|
| 任务互补 | 分割和补全可以互相促进 |
| 多尺度特征 | 点级+体素级特征更全面 |
| 数据增强 | Complete-and-Mask有效提升泛化 |
| 稀疏卷积 | 大幅提升计算效率 |
8.2 工程启示
- 联合训练更有效:多任务学习可以学到更丰富的特征
- 数据增强很重要:好的增强方法可以显著提升性能
- 稀疏卷积是关键:3D任务必须考虑计算效率
8.3 研究启示
- 任务设计:选择互补的任务进行联合学习
- 特征融合:不同粒度的特征可以互补
- 评估指标:同时关注分割和补全性能
九、与LMSCNet的对比
| 方面 | LMSCNet | JS3C-Net |
|---|---|---|
| 任务 | 仅场景补全 | 分割+补全 |
| 输入 | 体素化点云 | 原始点云 |
| 特征 | 体素级 | 点级+体素级 |
| 数据增强 | 标准增强 | Complete-and-Mask |
| 性能 | 15.3% mIoU | 69.7% mIoU |
| 速度 | 较慢 | 70ms |
十、关键概念速查表
| 概念 | 定义 | 重要性 |
|---|---|---|
| 上下文形状先验 | 网络学习到的物体形状知识 | ⭐⭐⭐⭐⭐ |
| 点级特征 | 保留点位置的特征 | ⭐⭐⭐⭐ |
| 体素级特征 | 3D网格结构的特征 | ⭐⭐⭐⭐ |
| 稀疏卷积 | 只在有点区域计算的卷积 | ⭐⭐⭐⭐⭐ |
| Complete-and-Mask | 补全+遮挡的数据增强 | ⭐⭐⭐⭐ |
| Lovász损失 | 可微的IoU损失 | ⭐⭐⭐ |
十一、总结与延伸
11.1 JS3C-Net的贡献
| 贡献 | 说明 |
|---|---|
| 联合学习框架 | 分割+补全互相促进 |
| 双分支架构 | 点级+体素级特征融合 |
| Complete-and-Mask | 新的数据增强方法 |
| 稀疏卷积优化 | 高效的3D特征提取 |
11.2 局限性
- 仅单帧:未利用时序信息
- 计算量:仍然较大(70ms/帧)
- 内存占用:稀疏卷积需要大量内存
11.3 后续研究方向
- 时序融合:利用多帧点云
- 更高效的架构:如MinkowskiNet
- 端到端训练:减少中间步骤
- 多模态融合:结合相机图像
十二、参考文献
- JS3C-Net: Sparse Single Sweep LiDAR Point Cloud Segmentation via Learning Contextual Shape Priors from Scene Completion (AAAI 2021)
- MinkowskiNet: 4D Spatio-Temporal ConvNets (CVPR 2020)
- SparseConv: 3D Sparse Convolutional Neural Networks (ICLR 2019)
- Lovász-Softmax: The Lovász-Softmax Loss (CVPR 2018)
下期预告
下一篇我们将介绍TPVFormer——一种基于三视角(Tri-Perspective View)的视觉中心3D占用感知方法,它如何用相机图像替代LiDAR实现3D理解?
关注我们,持续获取自动驾驶3D感知技术干货!
往期回顾:

浙公网安备 33010602011771号