-
-
Notifications
You must be signed in to change notification settings - Fork 6.8k
/
Copy pathpoint_cloud_sampling.py
168 lines (142 loc) · 5.6 KB
/
point_cloud_sampling.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
"""
Point cloud sampling example codes. This code supports
- Voxel point sampling
- Farthest point sampling
- Poisson disk sampling
"""
import matplotlib.pyplot as plt
import numpy as np
import numpy.typing as npt
from collections import defaultdict
do_plot = True
def voxel_point_sampling(original_points: npt.NDArray, voxel_size: float):
"""
Voxel Point Sampling function.
This function sample N-dimensional points with voxel grid.
Points in a same voxel grid will be merged by mean operation for sampling.
Parameters
----------
original_points : (M, N) N-dimensional points for sampling.
The number of points is M.
voxel_size : voxel grid size
Returns
-------
sampled points (M', N)
"""
voxel_dict = defaultdict(list)
for i in range(original_points.shape[0]):
xyz = original_points[i, :]
xyz_index = tuple(xyz // voxel_size)
voxel_dict[xyz_index].append(xyz)
points = np.vstack([np.mean(v, axis=0) for v in voxel_dict.values()])
return points
def farthest_point_sampling(orig_points: npt.NDArray,
n_points: int, seed: int):
"""
Farthest point sampling function
This function sample N-dimensional points with the farthest point policy.
Parameters
----------
orig_points : (M, N) N-dimensional points for sampling.
The number of points is M.
n_points : number of points for sampling
seed : random seed number
Returns
-------
sampled points (n_points, N)
"""
rng = np.random.default_rng(seed)
n_orig_points = orig_points.shape[0]
first_point_id = rng.choice(range(n_orig_points))
min_distances = np.ones(n_orig_points) * float("inf")
selected_ids = [first_point_id]
while len(selected_ids) < n_points:
base_point = orig_points[selected_ids[-1], :]
distances = np.linalg.norm(orig_points[np.newaxis, :] - base_point,
axis=2).flatten()
min_distances = np.minimum(min_distances, distances)
distances_rank = np.argsort(-min_distances) # Farthest order
for i in distances_rank: # From the farthest point
if i not in selected_ids: # if not selected yes, select it
selected_ids.append(i)
break
return orig_points[selected_ids, :]
def poisson_disk_sampling(orig_points: npt.NDArray, n_points: int,
min_distance: float, seed: int, MAX_ITER=1000):
"""
Poisson disk sampling function
This function sample N-dimensional points randomly until the number of
points keeping minimum distance between selected points.
Parameters
----------
orig_points : (M, N) N-dimensional points for sampling.
The number of points is M.
n_points : number of points for sampling
min_distance : minimum distance between selected points.
seed : random seed number
MAX_ITER : Maximum number of iteration. Default is 1000.
Returns
-------
sampled points (n_points or less, N)
"""
rng = np.random.default_rng(seed)
selected_id = rng.choice(range(orig_points.shape[0]))
selected_ids = [selected_id]
loop = 0
while len(selected_ids) < n_points and loop <= MAX_ITER:
selected_id = rng.choice(range(orig_points.shape[0]))
base_point = orig_points[selected_id, :]
distances = np.linalg.norm(
orig_points[np.newaxis, selected_ids] - base_point,
axis=2).flatten()
if min(distances) >= min_distance:
selected_ids.append(selected_id)
loop += 1
if len(selected_ids) != n_points:
print("Could not find the specified number of points...")
return orig_points[selected_ids, :]
def plot_sampled_points(original_points, sampled_points, method_name):
fig = plt.figure()
ax = fig.add_subplot(projection='3d')
ax.scatter(original_points[:, 0], original_points[:, 1],
original_points[:, 2], marker=".", label="Original points")
ax.scatter(sampled_points[:, 0], sampled_points[:, 1],
sampled_points[:, 2], marker="o",
label="Filtered points")
plt.legend()
plt.title(method_name)
plt.axis("equal")
def main():
n_points = 1000
seed = 1234
rng = np.random.default_rng(seed)
x = rng.normal(0.0, 10.0, n_points)
y = rng.normal(0.0, 1.0, n_points)
z = rng.normal(0.0, 10.0, n_points)
original_points = np.vstack((x, y, z)).T
print(f"{original_points.shape=}")
print("Voxel point sampling")
voxel_size = 20.0
voxel_sampling_points = voxel_point_sampling(original_points, voxel_size)
print(f"{voxel_sampling_points.shape=}")
print("Farthest point sampling")
n_points = 20
farthest_sampling_points = farthest_point_sampling(original_points,
n_points, seed)
print(f"{farthest_sampling_points.shape=}")
print("Poisson disk sampling")
n_points = 20
min_distance = 10.0
poisson_disk_points = poisson_disk_sampling(original_points, n_points,
min_distance, seed)
print(f"{poisson_disk_points.shape=}")
if do_plot:
plot_sampled_points(original_points, voxel_sampling_points,
"Voxel point sampling")
plot_sampled_points(original_points, farthest_sampling_points,
"Farthest point sampling")
plot_sampled_points(original_points, poisson_disk_points,
"poisson disk sampling")
plt.show()
if __name__ == '__main__':
main()