Skip to content

Commit b5266ad

Browse files
authored
Merge pull request andyzeng#14 from kevinzakka/bugfix
Correctly works on gpu and cpu now
2 parents dcc7773 + 2ff469a commit b5266ad

File tree

2 files changed

+73
-18
lines changed

2 files changed

+73
-18
lines changed

demo.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,11 @@
5858
print("Average FPS: {:.2f}".format(fps))
5959

6060
# Get mesh from voxel volume and save to disk (can be viewed with Meshlab)
61-
print("Saving to mesh.ply...")
61+
print("Saving mesh to mesh.ply...")
6262
verts, faces, norms, colors = tsdf_vol.get_mesh()
63-
fusion.meshwrite("mesh.ply", verts, faces, norms, colors)
63+
fusion.meshwrite("mesh.ply", verts, faces, norms, colors)
64+
65+
# Get point cloud from voxel volume and save to disk (can be viewed with Meshlab)
66+
print("Saving point cloud to pc.ply...")
67+
point_cloud = tsdf_vol.get_point_cloud()
68+
fusion.pcwrite("pc.ply", point_cloud)

fusion.py

Lines changed: 66 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ def __init__(self, vol_bnds, voxel_size, use_gpu=True):
3434
self._vol_bnds = vol_bnds
3535
self._voxel_size = float(voxel_size)
3636
self._trunc_margin = 5 * self._voxel_size # truncation on SDF
37+
self._color_const = 256 * 256
3738

3839
# Adjust volume bounds and ensure C-order contiguous
3940
self._vol_dim = np.ceil((self._vol_bnds[:,1]-self._vol_bnds[:,0])/self._voxel_size).copy(order='C').astype(int)
@@ -158,10 +159,11 @@ def __init__(self, vol_bnds, voxel_size, use_gpu=True):
158159
range(self._vol_dim[2]),
159160
indexing='ij'
160161
)
161-
self.vox_coords = np.concatenate([xv.reshape(1,-1), yv.reshape(1,-1), zv.reshape(1,-1)], axis=0).astype(int).T
162-
163-
self.b_const = 256 * 256
164-
self.g_const = 256
162+
self.vox_coords = np.concatenate([
163+
xv.reshape(1,-1),
164+
yv.reshape(1,-1),
165+
zv.reshape(1,-1)
166+
], axis=0).astype(int).T
165167

166168
@staticmethod
167169
@njit(parallel=True)
@@ -217,7 +219,7 @@ def integrate(self, color_im, depth_im, cam_intr, cam_pose, obs_weight=1.):
217219

218220
# Fold RGB color image into a single channel image
219221
color_im = color_im.astype(np.float32)
220-
color_im = np.floor(color_im[...,2]*self.b_const + color_im[...,1]*self.g_const + color_im[...,0])
222+
color_im = np.floor(color_im[...,2]*self._color_const + color_im[...,1]*256 + color_im[...,0])
221223

222224
if self.gpu_mode: # GPU mode: integrate voxel volume (calls CUDA kernel)
223225
for gpu_loop_idx in range(self._n_gpu_loops):
@@ -278,24 +280,45 @@ def integrate(self, color_im, depth_im, cam_intr, cam_pose, obs_weight=1.):
278280

279281
# Integrate color
280282
old_color = self._color_vol_cpu[valid_vox_x, valid_vox_y, valid_vox_z]
281-
old_b = np.floor(old_color / self.b_const)
282-
old_g = np.floor((old_color-old_b*self.b_const)/self.g_const)
283-
old_r = old_color - old_b*self.b_const - old_g*self.g_const
283+
old_b = np.floor(old_color / self._color_const)
284+
old_g = np.floor((old_color-old_b*self._color_const)/256)
285+
old_r = old_color - old_b*self._color_const - old_g*256
284286
new_color = color_im[pix_y[valid_pts],pix_x[valid_pts]]
285-
new_b = np.floor(new_color / self.b_const)
286-
new_g = np.floor((new_color - new_b*self.b_const) /self.g_const)
287-
new_r = new_color - new_b*self.b_const - new_g*self.g_const
287+
new_b = np.floor(new_color / self._color_const)
288+
new_g = np.floor((new_color - new_b*self._color_const) /256)
289+
new_r = new_color - new_b*self._color_const - new_g*256
288290
new_b = np.minimum(255., np.round((w_old*old_b + new_b) / w_new))
289291
new_g = np.minimum(255., np.round((w_old*old_g + new_g) / w_new))
290292
new_r = np.minimum(255., np.round((w_old*old_r + new_r) / w_new))
291-
self._color_vol_cpu[valid_vox_x, valid_vox_y, valid_vox_z] = new_b*self.b_const + new_g*self.g_const + new_r
293+
self._color_vol_cpu[valid_vox_x, valid_vox_y, valid_vox_z] = new_b*self._color_const + new_g*256 + new_r
292294

293295
def get_volume(self):
294296
if self.gpu_mode:
295297
cuda.memcpy_dtoh(self._tsdf_vol_cpu, self._tsdf_vol_gpu)
296298
cuda.memcpy_dtoh(self._color_vol_cpu, self._color_vol_gpu)
297299
return self._tsdf_vol_cpu, self._color_vol_cpu
298300

301+
def get_point_cloud(self):
302+
"""Extract a point cloud from the voxel volume.
303+
"""
304+
tsdf_vol, color_vol = self.get_volume()
305+
306+
# Marching cubes
307+
verts = measure.marching_cubes_lewiner(tsdf_vol, level=0)[0]
308+
verts_ind = np.round(verts).astype(int)
309+
verts = verts*self._voxel_size + self._vol_origin
310+
311+
# Get vertex colors
312+
rgb_vals = color_vol[verts_ind[:, 0], verts_ind[:, 1], verts_ind[:, 2]]
313+
colors_b = np.floor(rgb_vals / self._color_const)
314+
colors_g = np.floor((rgb_vals - colors_b*self._color_const) / 256)
315+
colors_r = rgb_vals - colors_b*self._color_const - colors_g*256
316+
colors = np.floor(np.asarray([colors_r, colors_g, colors_b])).T
317+
colors = colors.astype(np.uint8)
318+
319+
pc = np.hstack([verts, colors])
320+
return pc
321+
299322
def get_mesh(self):
300323
"""Compute a mesh from the voxel volume using marching cubes.
301324
"""
@@ -308,9 +331,9 @@ def get_mesh(self):
308331

309332
# Get vertex colors
310333
rgb_vals = color_vol[verts_ind[:,0], verts_ind[:,1], verts_ind[:,2]]
311-
colors_b = np.floor(rgb_vals/self.b_const)
312-
colors_g = np.floor((rgb_vals-colors_b*self.b_const)/self.g_const)
313-
colors_r = rgb_vals-colors_b*self.b_const-colors_g*self.g_const
334+
colors_b = np.floor(rgb_vals/self._color_const)
335+
colors_g = np.floor((rgb_vals-colors_b*self._color_const)/256)
336+
colors_r = rgb_vals-colors_b*self._color_const-colors_g*256
314337
colors = np.floor(np.asarray([colors_r,colors_g,colors_b])).T
315338
colors = colors.astype(np.uint8)
316339
return verts, faces, norms, colors
@@ -372,4 +395,31 @@ def meshwrite(filename, verts, faces, norms, colors):
372395
for i in range(faces.shape[0]):
373396
ply_file.write("3 %d %d %d\n"%(faces[i,0], faces[i,1], faces[i,2]))
374397

375-
ply_file.close()
398+
ply_file.close()
399+
400+
401+
def pcwrite(filename, xyzrgb):
402+
"""Save a point cloud to a polygon .ply file.
403+
"""
404+
xyz = xyzrgb[:, :3]
405+
rgb = xyzrgb[:, 3:].astype(np.uint8)
406+
407+
# Write header
408+
ply_file = open(filename,'w')
409+
ply_file.write("ply\n")
410+
ply_file.write("format ascii 1.0\n")
411+
ply_file.write("element vertex %d\n"%(xyz.shape[0]))
412+
ply_file.write("property float x\n")
413+
ply_file.write("property float y\n")
414+
ply_file.write("property float z\n")
415+
ply_file.write("property uchar red\n")
416+
ply_file.write("property uchar green\n")
417+
ply_file.write("property uchar blue\n")
418+
ply_file.write("end_header\n")
419+
420+
# Write vertex list
421+
for i in range(xyz.shape[0]):
422+
ply_file.write("%f %f %f %d %d %d\n"%(
423+
xyz[i, 0], xyz[i, 1], xyz[i, 2],
424+
rgb[i, 0], rgb[i, 1], rgb[i, 2],
425+
))

0 commit comments

Comments
 (0)