点云处理——基于数据索引的方法
Octree guided CNN using spherical kernels (CVPR2019)
KdNet
在这些方法中,点特征是沿着树从叶节点到根节点分层学习的。根节点的特征代表了整个点云的特征。
代表1: Octree guided CNN using spherical kernels (CVPR2019)
核心思想:利用八叉树将点云规格化,这个八叉树类似于体素化,区别在于不含点的体素不再8等分。至于划分几层,看各自需求。利用这种结构从叶节点逐层抽取特征至根节点,以获取整个点云的特征,并用于分类。八叉树还可以用来压缩点云,提高存储、计算和检索的效率。
与OctNet的区别:OctNet对点云进行体素化,并以3D体素的方式处理点云,而本文提出的球形卷积核没有这样的约束。其次,本文能够用单个深八叉树学习点云表示,而OctNet使用3个浅树的混合。
核心操作:球卷积
具体过程如下:
- 以某点(想提取特征的点)为中心,构造一个球坐标系;
- 等分球坐标三个参数:半径r,角度
和
,形成三维bin,中心点(球坐标原点不属于任何一个bin;
- 为每个bin分配一个矩阵参数
;
- 计算点的激活值:线性变换+激活
网络结构:
- 对输入点云进行nomalizaiton;
- 对每个点使用 pointwise convolution 进行特征变换;
- 为每个点指定半径找邻居(knn),r =[0.1,0.2,0.4,0.8],然后执行以下操作:
把找到的邻居点投影到对应的球卷积核上,卷积更新每个点的特征;
做两次球卷积操作和一次coaserning采样操作,降低点云密度;
对邻居点特征做max pooling,得到中心点特征;
对所有中心点特征进行reduce max,得到当前点云密度下的全局特征。
- 将球卷积核的半径改的很大,保证每个点的邻居都能包括其它所有点,并将每个点的邻居都投影到球上进行一次球卷积(调整维度,并激活);
- 将这些中心点进行全连,即reduce max出整个点云特征;
- 将之前不同密度下的点云全局特征与最后一层的点云全局特征拼接,作为最终的全局特征;
- 2个全连接+一个分类。
代表2: Kd-Net
构图
Kd树是一种多维二叉树,每次在一个维度上二分,直到所有的点别分完。
KdNet用KD树来构图,在方差最大的那个维度上,以该维度的中值作为划分节点。与其他方法一样,Kd-Net也将所有点云都事先进行归一化,归一化范围为。DGCNN中的KNN操作如果使用kd-tree树查找,k临近点变成1个临近点,就变成了Kd-Net。
from sklearn.neighbors import KDTree
//data: numpy array
kdt = KDTree(data,leaf_size=2)
//最近邻搜索
dist, ind = kdt.query([point], k=1)
// knn
dist, inds = kdt.query ([point], k=n)
// r 搜索
indices = kdt.query_radius([point], r=0.2)
特征提取
构完图之后,就是利用Kd-Net进行点云特征提取,从叶节点到根节点逐层提取特征并聚合。
过程很简单:
- 首先叶节点是输入点云,维度为k,由输入点云的维度确定;
- 两两卷积聚合,根据构图时的划分维度,从下面三组参数中选一组进行计算,
是划分维度,
,
是i点的两个子节点,
和
是第i层的学习参数,
是激活函数RELU;
- 特别的,如果同一层在构图的过程中划分维度相同,那么它们在这一层共享卷积参数,也就是说,在每一层,每个划分维度都有自己的一套参数,用同一维度划分的共享一套参数。
分类
对于分类来说,就是两两聚合,直到根节点,根节点的维度等于类别数;
分割
对于分割来说,则还要继续从根节点向后传播,类似U-Net,在encoder-decoder结构的基础之上加入了shortcut,避免一些信息的损失。
x2上采样点数,并将前面的特征concat过来,注意这里是分别进行卷积,再concat,重复操作直到点数与原始点云一致。w,b是后半段网络的权重和偏置,s,t是跳跃连接的权重和偏置。