FPS
没有想到不按套路出牌的美团今早就撕了这个。
点云最远点采样,从一堆点集中选出一些点,使得他们尽可能地远离。这样采样出来的点能比较好的表征整个轮廓。在pointnet++中就用到过。
整体思路是:分别维护一个已选取和待选取的点云集合。先从点云集合中选出一个点,然后计算其余所有点到该点的距离,距离最大的那个点是下次要加入的点。当pick集合中有多个点时,距离的定义为到集合每个点距离中的最小距离。
关于距离的计算:维护一个distance列表,对于每次pick出来的点,去更新distance。可以利用前缀性质,不需要重新计算点到集合中所有点的距离了,而是选取原值和到新point的距离中的较小值,即dis = min(dis, newdis)。
关于第一个点的选取:一般用离点云重心最远的点作为初始点
import numpy as np
import matplotlib.pyplot as plt
# def compute_dis(points):
# ## points: N*3
# ## return -- distances: N*N
# points_dis = np.sum(np.power(points, 2), axis=1) # N
# distances = np.expand_dims(points_dis, axis=1).repeat(points.shape[0], axis=1) # N*N
# distances = distances + distances.T + 2 * np.dot(points, points.T)
# return distances
def plot(points, sample_points):
ax = plt.axes(projection='3d')
ax.scatter3D(points[:,0], points[:,1], points[:,2])
ax.scatter3D(sample_points[:,0], sample_points[:,1], sample_points[:,2], c='r', s=60, marker = '^')
plt.show()
def fps(points, k):
sample_points = np.zeros((k, 3))
## 用离重心最远的初始化
barycenter = np.sum(points, axis=0)/points.shape[0]
print(barycenter)
distance = np.full((points.shape[0]), np.nan)
point = barycenter
# # 随机初始化
# point = points[0]
# points = points[:-1,:]
# sample_points[0,:] = point
# distance = np.sum((points - point)**2, axis=1)
for i in range(k):
distance = np.minimum(distance, np.sum((points - point)**2, axis=1)) ## 前缀思想更新最小值
index = np.argmax(distance)
point = points[index]
sample_points[i,:] = point
mask = np.ones((points.shape[0]), dtype=bool)
mask[index] = False
points = points[mask]
distance = distance[mask]
return sample_points
np.random.seed(42)
points = np.random.randint(0, 5, size=(50, 3))
sample_points = fps(points, 10)
plot(points, sample_points)
print(points)
print(sample_points)
————————————————————————————————————————————
最远点采样(FPS)
三维点云处理05-FPS代码实现