@@ -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