PointNet++通过递归局部划分和特征提取,解决PointNet在捕获点云局部特征上的不足。它使用最远点采样进行区域划分,通过Set Abstraction模块进行采样、分组和特征提取,并引入MSG和MRG解决点云密度不均衡问题,增强网络的鲁棒性。实验表明,PointNet++在稀疏点云处理和多尺度特征融合方面表现出色。
参考笔记:
[5分钟点云学习] #02 PointNet 开山之作_哔哩哔哩_bilibili(必看)
[5分钟点云学习] #03 PointNet++ 竟然是图结构?!_哔哩哔哩_bilibili(必看)
深度学习3D网络---PointNet++ - 半夜打老虎 - 博客园
PointNet系列论文阅读与理解_pointnet论文-CSDN博客
(CVPR) PointNet++ 深度层次特征学习度量空间中的点集 详细解读 - 附代码-CSDN博客
目录
1.唐宇迪简述
1.1PointNet存在的问题
(1)没有考虑点与点之间的关系进行局部特征融合,要不自己,要么一个整体(全局最大池化)
(2)PointNet++ 版本要从局部入手,多利用局部特征
(3)整体思想不变,只不过在特征提取处使用类似图卷积的方式来整合特征。
1.2PointNet++的基本出发点
(1)基于半径来选择局部区域。类似得到很多个簇
(2)针对得到的每个局部区域进行特征提取(卷积),对每个局部区域进行特征提取使用的是PointNet
(3)要解决的问题:如何选择区域(簇中心点的选择)
先利用最远点采样方法选出所有中心点,然后依据中心点和半径大小划分出区域。
(4)簇的半径大小如何定义,每个簇中选择多少个样本点
如上图所示,首先从样本中划分出多个区域,然后在每个区域中进行局部特征融合,融合出一个特征向量出来。即每个中心点对应的局部区域都要融合出一个特征向量出来。
1.3流程
(1)Sample Layer:使用最远点采样方法,采出每一个点云样本的所有中心点
例如样本有 1024 个点,要选择 128 个中心点,则使用最远点采样方法下采样出 128 个中心点。文中提到相比于随机采样,这种方法能更好的的覆盖整个点集。具体选择多少个中心点,数量怎么确定,是由人来指定的
(2)Group Layer:为(1)得到的每一个中心点确定好局部区域。这里有 2 个变量:
- R:作为点的邻域半径
- K:每个局部区域中点的最多数量
即对于每个中心点,在其邻域半径 R 内找 K 个邻居点。如下图,红色点为中心点:
PS:
a. 在官方源码中,如果某个中心点的邻居点数量 < K,则需要对局部区域内的某个点作复制,使得该中心点的邻居点数量达到 K
b. 在官方源码中,如果某个中心点的邻居点数量 > K,则按索引号的大小优先选择前 K 个
下图是 Group Layer(分组)的示例流程图
(3)PointNet Layer:对各组使用 PointNet 进行局部特征融合
2.两者的主要不同
(1)考虑到 PointNet 特征提取时只考虑单点,不能很好的表示局部结构 ==> PointNet++引入了sampling & grouping,考虑局部邻域特征
(2)PointNet中global feature全局特征直接由max pool得到,容易造成信息丢失 ==> PointNet++采用层级结构,可以有效的依据不同的感受野大小来提取不同区域的局部
(3)PointNet中采用T-Net来保证点云特征旋转的不变性 ==> PointNet++采用局部相对坐标进行特征提取,剔除了T-Net网络。这里采用局部相对的坐标的意思是每个中心点对应的局部区域里的所有点都会对相对于中心点进行平移操作。在代码中是如下实现的
'''
grouped_xyz shape:(B,S,N,C)=(批次,中心点数量,局部区域中点的个数,xyz坐标)
new_xyz.view shape:(B,S,1,C)=(批次,中心点数量,1,xyz坐标),这里会用到广播机制
最后 grouped_xyz_norm的shape:[批量大小,中心数量,局部区域中点的个数,归一化后的xyz坐标]
'''
grouped_xyz_norm = grouped_xyz - new_xyz.view(B, S, 1, C)
(4)针对稀疏点云导致样本不均匀问题,PointNet未做处理 ==> PointNet++提出多尺度方法MSG和多层级方法MRG来解决样本不均匀问题。源码只实现了MSG。
(5)对于分割网络来讲,PointNet直接整合global feature和local embedding特征 ==> PointNet++采用Encoder - Decoder结构,特征通过skip link concatenation进行连接
3.PointNet++网络结构
PointNet++网络结构如图所示,主要包含set abstraction(SA)块,分割网络中上采样的插值操作(interpolate),其中SA由Sampling Layer,Grouping Layer和PointNet Layer构成,接下来依次对其进行介绍。
Sample Layer | 对输入点使用最远点采样,在这些点中选出若干个中心点; |
Grouping Layer |
利用上一步得到的中心点将点集划分成若干个区域; |
PointNet Layer | 对上述得到的每个区域作局部特征提取,变成特征向量。 |
3.1 Sample Layer
3.1.1 作用
考虑到点云数量通常较大且数量不一致,PointNet++采用最远点采样,从原始个点云中选取
个点作为中心点
- 数据变化
比如结构图中输入是点云信息,其中N表示点云个数,d表示坐标维度(通常为(x, y, z)3维),c表示其他特征(如颜色、法线等),经过sampling layer后变成
,其中
3.1.2 相关代码
#最远点采样,npoint为采样点数量,xyz为点集
def farthest_point_sample(xyz, npoint):
"""
Input:
xyz: pointcloud data, [B, N, 3]=[批量,总点数,xyz坐标]
npoint: number of samples
Return:
centroids: sampled pointcloud index, [B, npoint],表示每个样本中,以npoint个点作为采样点,存放每次批次中作为采样点的索引
"""
device = xyz.device
B, N, C = xyz.shape#批量,点云个数,3
centroids = torch.zeros(B, npoint, dtype=torch.long).to(device)#shape:(B,npoint),用来存放采样点的索引
distance = torch.ones(B, N).to(device) * 1e10#存放每个点到已选择采样点的最小距离,shape:(B,N)
farthest = torch.randint(0, N, (B,), dtype=torch.long).to(device)#从每个场景中随机选取一个点作