3.3 PointNet layer( 二 )


: 对+以后的点云进行局部的全局特征提取
.3of
++是的延伸,在的基础上加入了多层次结构( ),使得网络能够在越来越大的区域上提供更高级别的特征 。
网络的每一组set主要包括3个部分: layer,layer andlayer 。
layer:主要是对输入点进行采样,在这些点中选出若干个中心点;
layer:是利用上一步得到的中心点将点集划分成若干个区域;
layer:是对上述得到的每个区域进行编码,变成特征向量
每一组提取层的输入是(N,(d+C)),其中N是输入点的数量,d是坐标维度,C是特征维度 。
输出是(N',(d+C^{'})),其中N'是输出点的数量,d是坐标维度不变,C'是新的特征维度 。下面详细介绍每一层的作用及实现过程 。
3. layer
使用 point (FPS)选择N'个点,至于为什么选择使用这种方法选择点,文中提到相比于随机采样,这种方法能更好的的覆盖整个点集 。具体选择多少个中心点,数量怎么确定,可以看做是超参数视数据规模来定 。
FPS算法原理为:
从点云中选取第一个点A作为查询点,从剩余点中,选取一个距离最远的点B;
以取出来的点A,B作为查询点,从剩余点中,取距离最远的点C 。此时,由于已经取出来的点的个数超过1需要同时考虑所有查询点(A,B) 。方法如下:
2.1 对于剩余点中的任意一个点P,计算该点P到已经选中的点集中所有点(A, B)的距离;取与点A和 B的距离中的最小值作为该点到已选点集的距离d;
2.2 计算出每个剩余点到点集的距离后,选取距离最大的那个点,即为点C3
3. 重复第2步,一直采样到N'个点为止 。
++较的主要改进是引入了局部特征的思想: 将整个大点云P分成有的小点云,分别利用对小点云进行特征提取 。(采样的目的)就是选出上述小点云的代表点(中心点),这里实现的方式采用的FPS( point ):
a. 有两个集合A = {}, B = P
b. 随机选择B中一个点x加入A, 并从B中删除点x
c. 计算B中每个点z到A中所有点的距离得到z_1, z_2, …, z_len(A), 选择min(z_1, z_2, …, z_len(A)记为点z到集合A的距离;
d. 从B中选择距离集合A最远的点y, 加入到集合A,并从B删除点y.
e. 重复c, d直到集合A中点的数量满足预先设定的阈值.
是不是和图论里的算法很类似,只不过算法求的是最短距离 。下面用一张二维图更直观的表示的目的: 左图表示输入点,右图表示使用FPS算法采样得到的中心点(红色倒三角形) 。这些中心点将用于接下来的group操作 。
的代码(fps算法)的代码如下, 部分是采用的向量化实现,而且在实现的时候有些技巧性;建议首先自己思考一下如何用代码实现上述fps算法:
input和分别是什么 ? Input: 点集xyz shape=(B, N, 3), 中心点的数量M; : M个中心点的坐标或索引, shape=(B, M, 3)或(B, M). 代码中返回的是索引值 。
如果不用for循环进行比较距离, 又该如何实现 ? 如果感觉不是很好写,看看下面的代码实现吧 。
如何实现点集中的点-点距离的向量化计算 ? 这里实现时遇到了一个坑, 当dist=0时,有可能会出现1e-8之类很小的值,但开根号也没有报错,所以比较好的方式是使用平方距离,或者使用torch.where过滤一下距离等于0的值 。
def farthest_point_sample(xyz, npoint):"""Input:xyz: pointcloud data, [B, N, 3]#B代表batch_sizenpoint: number of samplesReturn:centroids: sampled pointcloud index, [B, npoint, 3]"""device = xyz.deviceB, N, C = xyz.shapecentroids = torch.zeros(B, npoint, dtype=torch.long).to(device) # 采样点矩阵(B, npoint)distance = torch.ones(B, N).to(device) * 1e10# 采样点到所有点距离(B, N)farthest = torch.randint(0, N, (B,), dtype=torch.long).to(device) # 最远点,初试时随机选择一点点batch_indices = torch.arange(B, dtype=torch.long).to(device)# batch_size 数组for i in range(npoint):centroids[:, i] = farthest# 更新第i个最远点centroid = xyz[batch_indices, farthest, :].view(B, 1, 3) # 取出这个最远点的xyz坐标dist = torch.sum((xyz - centroid) ** 2, -1) # 计算点集中的所有点到这个最远点的欧式距离mask = dist