0%

对顶点采样

简单介绍几种获取点云的采样方法

Random Sampling

从点云或mesh的顶点集直接随机抽样,获得点云。

这种最自然的想法的问题是:由于随机性,点的分布可能在某些局部是“一簇一簇”的。换言之,点的分布其实不够均匀。

Uniform Sampling

从mesh的各个面片上均匀抽取点。其方法为(假设为三角mesh):

  1. 估计总面积和各面片的面积,根据比例关系确定各个面片上究竟各需要采多少个点。
  2. 在一个三角形区域内均匀采样

Uniform Sampling in a Triangle

在三角形ΔABC\Delta ABC内均匀采样的一种错误方法

  1. 从[0,1]均匀分布中抽取三个值a,b,ca,b,c
  2. 归一化:a=a/(a+b+c),b=b/(a+b+c),c=c/(a+b+c)a'=a/(a+b+c),b'=b/(a+b+c),c'=c/(a+b+c)
  3. P=aA+bB+cCP=a'A+b'B+c'C

可以证明:这样得到的PP其实不是均匀分布,而是在三角形中心更加集中。

正确的方法是

  1. 先把ΔABC\Delta ABC转化为平行四边形ABDCABDC,其中DDAA关于BCBC所在直线的对称点。
  2. 从[0,1]均匀分布抽取2个值,并归一化得到a,ba',b'
  3. P=A+a(BA)+b(CA)P=A+a'(B-A)+b'(C-A),当PP不在ΔABC\Delta ABC中时,就使用其关于BCBC所在直线的对称点。

容易证明,此时抽出的点PP在平行四边形内是均匀分布的,因此对称后在三角形中还是均匀分布。

如下图所示,左图为错误方法,右图为正确方法(图源:Geography meets ML)。

image-20220830233827772

需要注意的是,均匀采样仍然带有随机性,因此采出来的点还是不太均匀。

Farthest Point Sampling

这是一种基于“最大化点之间距离”从而使点分布均匀的采样方法。当然,实际使用时采用的是迭代近似的方案。

首先需要定义点到点集(点云)的距离为点到点集中所有点距离中的最小值

  1. 先用Uniform Sampling等方法,得到一个初始点云UU,但UU的点数远多于目标点数(如10倍)
  2. S={}S=\{\}
  3. TT代表UU中各点到当前SS(点集)的距离表。初始化TT++\infin(由于一开始SS是空的)。
  4. 随机选择一个点PP
  5. PP放入SS中。如果SS的大小已经达到目标点数,则退出。
  6. 计算PP点到UU中所有点的距离,并将其与TT的对应各个距离值取较小值来更新TT
  7. 选择到SS距离最大的点PP,即TT中最大值所对应的点(由于已经在SS的点到SS的距离就是0,因此不会被重复选择)
  8. 返回第5步。

可以参考的简单代码实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import numpy as np
def FPS(ptcloud,count):
#省略了获取初始点云的过程
U = ptcloud
S = []
dist_to_S = np.full(len(U),np.inf) #即距离表T
newpt_idx = 0 #这里没随机选择,而是直接取了第一个点,效果应当差不多
for _ in range(count):
S.append(U[newpt_idx])
dist_offer = np.sum((U - U[newpt_idx])**2,axis=1)
dist_to_S = np.min(np.stack((dist_offer,dist_to_S)),axis=0)
#找新点
newpt_idx = np.argmax(dist_to_S)
return np.array(S)
#使用例
ptcloud_fps = FPS(ptcloud,4000)

复杂度

UU共有NN个点,目标点数为KK,则每次循环会执行O(N)O(N)次计算(更新距离表),因此总复杂度为O(NK)O(NK)

Voxel Sampling

即将空间栅格化,每个空间小格随机取一个点。可以分桶实现,于是复杂度为线性。

按:这种方法和图像采样问题有相似之处。

欢迎关注我的其它发布渠道