-
Notifications
You must be signed in to change notification settings - Fork 1
/
voxelgrid.py
119 lines (83 loc) · 3.77 KB
/
voxelgrid.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
# HAKUNA MATATA
"""
VoxelGrid Class
"""
import numpy as np
from matplotlib import pyplot as plt
#from ..plot import plot_voxelgrid
class VoxelGrid(object):
def __init__(self, points, x_y_z=[1, 1, 1], bb_cuboid=True, build=True):
"""
Parameters
----------
points: (N,3) ndarray
The point cloud from wich we want to construct the VoxelGrid.
Where N is the number of points in the point cloud and the second
dimension represents the x, y and z coordinates of each point.
x_y_z: list
The segments in wich each axis will be divided.
x_y_z[0]: x axis
x_y_z[1]: y axis
x_y_z[2]: z axis
bb_cuboid(Optional): bool
If True(Default):
The bounding box of the point cloud will be adjusted
in order to have all the dimensions of equal lenght.
If False:
The bounding box is allowed to have dimensions of different sizes.
"""
self.points = points
xyzmin = np.min(points, axis=0) - 0.001
xyzmax = np.max(points, axis=0) + 0.001
if bb_cuboid:
#: adjust to obtain a minimum bounding box with all sides of equal lenght
diff = max(xyzmax-xyzmin) - (xyzmax-xyzmin)
xyzmin = xyzmin - diff / 2
xyzmax = xyzmax + diff / 2
self.xyzmin = xyzmin
self.xyzmax = xyzmax
segments = []
shape = []
for i in range(3):
# note the +1 in num
if type(x_y_z[i]) is not int:
raise TypeError("x_y_z[{}] must be int".format(i))
s, step = np.linspace(xyzmin[i], xyzmax[i], num=(x_y_z[i] + 1), retstep=True)
segments.append(s)
shape.append(step)
self.segments = segments
self.shape = shape
self.n_voxels = x_y_z[0] * x_y_z[1] * x_y_z[2]
self.n_x = x_y_z[0]
self.n_y = x_y_z[1]
self.n_z = x_y_z[2]
self.id = "{},{},{}-{}".format(x_y_z[0], x_y_z[1], x_y_z[2], bb_cuboid)
if build:
self.build()
def build(self):
structure = np.zeros((len(self.points), 4), dtype=int)
structure[:,0] = np.searchsorted(self.segments[0], self.points[:,0]) - 1
structure[:,1] = np.searchsorted(self.segments[1], self.points[:,1]) - 1
structure[:,2] = np.searchsorted(self.segments[2], self.points[:,2]) - 1
# i = ((y * n_x) + x) + (z * (n_x * n_y))
structure[:,3] = ((structure[:,1] * self.n_x) + structure[:,0]) + (structure[:,2] * (self.n_x * self.n_y))
self.structure = structure
vector = np.zeros(self.n_voxels)
count = np.bincount(self.structure[:,3])
vector[:len(count)] = count
self.vector = vector.reshape(self.n_z, self.n_y, self.n_x)
def plot(self, d=2, cmap="Oranges", axis=False):
if d == 2:
fig, axes= plt.subplots(int(np.ceil(self.n_z / 4)), 4, figsize=(8,8))
plt.tight_layout()
for i,ax in enumerate(axes.flat):
if i >= len(self.vector):
break
im = ax.imshow(self.vector[i], cmap=cmap, interpolation="none")
ax.set_title("Level " + str(i))
fig.subplots_adjust(right=0.8)
cbar_ax = fig.add_axes([0.85, 0.15, 0.05, 0.7])
cbar = fig.colorbar(im, cax=cbar_ax)
cbar.set_label('NUMBER OF POINTS IN VOXEL')
elif d == 3:
return plot_voxelgrid(self, cmap=cmap, axis=axis)