1
1
import os
2
2
3
3
import cv2
4
+ import mmengine
4
5
import numpy as np
5
6
import open3d as o3d
6
7
@@ -39,13 +40,16 @@ def __init__(self, dataset, dir, scene, classes, color_selector, start_idx,
39
40
self .vis .register_key_callback (262 , self .draw_next ) # Right Arrow
40
41
self .vis .register_key_callback (ord ('D' ), self .draw_next )
41
42
self .vis .register_key_callback (ord ('N' ), self .draw_next )
43
+ self .vis .register_key_callback (256 , self .close )
42
44
43
45
def begin (self ):
44
46
"""Some preparations before starting the rendering."""
45
47
print ('Press N/D/Right Arrow to draw next frame.' )
46
48
print ('Press Q to close the window and quit.' )
47
- print ('Please wait for a few seconds after rendering some frames,' ,
48
- 'or the program may crash.' )
49
+ print ("When you've rendered a lot of frames, the exit can become" ,
50
+ 'very slow because the program needs time to free up space.' )
51
+ print ('You can also press Esc to close window immediately,' ,
52
+ 'which may result in a segmentation fault.' )
49
53
s = self .scene ['sample_idx' ].split ('/' )
50
54
self .occupied = np .zeros ((len (self .scene ['instances' ]), ), dtype = bool )
51
55
if len (s ) == 2 :
@@ -115,9 +119,12 @@ def draw_next(self, vis):
115
119
pc .colors = o3d .utility .Vector3dVector (colors [::self .downsample ])
116
120
vis .add_geometry (pc )
117
121
if self .camera is not None :
118
- vis .remove_geometry (self .camera )
119
- self .camera = draw_camera (extrinsic )
120
- vis .add_geometry (self .camera )
122
+ cam_points = draw_camera (extrinsic , return_points = True )
123
+ self .camera .points = cam_points
124
+ vis .update_geometry (self .camera )
125
+ else :
126
+ self .camera = draw_camera (extrinsic )
127
+ vis .add_geometry (self .camera )
121
128
122
129
for ins_idx in img ['visible_instance_ids' ]:
123
130
if self .occupied [ins_idx ]:
@@ -135,3 +142,174 @@ def draw_next(self, vis):
135
142
vis .update_renderer ()
136
143
vis .poll_events ()
137
144
vis .run ()
145
+
146
+ def close (self , vis ):
147
+ """Close the visualizer.
148
+
149
+ Args:
150
+ vis (open3d.visualization.VisualizerWithKeyCallback): Visualizer.
151
+ """
152
+ vis .clear_geometries ()
153
+ vis .destroy_window ()
154
+ vis .close ()
155
+
156
+
157
+ class ContinuousOccupancyDrawer :
158
+ """Visualization tool for Continuous Occupancy Prediction task.
159
+
160
+ This class serves as the API for visualizing Continuous 3D Object
161
+ Detection task.
162
+
163
+ Args:
164
+ dataset (str): Name of composed raw dataset, one of
165
+ scannet/3rscan/matterport3d.
166
+ dir (str): Root path of the dataset.
167
+ scene (dict): Annotation of the selected scene.
168
+ classes (list): Class information.
169
+ color_selector (ColorMap): ColorMap for visualization.
170
+ start_idx (int) : Index of the frame which the task starts.
171
+ """
172
+
173
+ def __init__ (self , dataset , dir , scene , classes , color_selector ,
174
+ start_idx ):
175
+ self .dir = dir
176
+ self .dataset = dataset
177
+ self .scene = scene
178
+ self .classes = classes
179
+ self .color_selector = color_selector
180
+ self .idx = start_idx
181
+ self .camera = None
182
+
183
+ if dataset == 'matterport3d' :
184
+ _ , building , region = scene ['sample_idx' ].split ('/' )
185
+ else :
186
+ _ , region = scene ['sample_idx' ].split ('/' )
187
+
188
+ if dataset == 'scannet' :
189
+ self .occ_path = os .path .join (self .dir , 'scans' , region ,
190
+ 'occupancy' , 'occupancy.npy' )
191
+ self .mask_path = os .path .join (self .dir , 'scans' , region ,
192
+ 'occupancy' , 'visible_occupancy.pkl' )
193
+ elif dataset == '3rscan' :
194
+ self .occ_path = os .path .join (self .dir , region , 'occupancy' ,
195
+ 'occupancy.npy' )
196
+ self .mask_path = os .path .join (self .dir , region , 'occupancy' ,
197
+ 'visible_occupancy.pkl' )
198
+ elif dataset == 'matterport3d' :
199
+ self .occ_path = os .path .join (self .dir , building , 'occupancy' ,
200
+ f'occupancy_{ region } .npy' )
201
+ self .mask_path = os .path .join (self .dir , building , 'occupancy' ,
202
+ f'visible_occupancy_{ region } .pkl' )
203
+ else :
204
+ raise NotImplementedError
205
+
206
+ self .occupied = np .zeros ((len (self .scene ['instances' ]), ), dtype = bool )
207
+ self .vis = o3d .visualization .VisualizerWithKeyCallback ()
208
+ self .vis .register_key_callback (262 , self .draw_next ) # Right Arrow
209
+ self .vis .register_key_callback (ord ('D' ), self .draw_next )
210
+ self .vis .register_key_callback (ord ('N' ), self .draw_next )
211
+ self .vis .register_key_callback (256 , self .close )
212
+
213
+ def begin (self ):
214
+ """Some preparations before starting the rendering."""
215
+ print ('Press N/D/Right Arrow to draw next frame.' )
216
+ print ('Press Q to close the window and quit.' )
217
+ print ("When you've rendered a lot of frames, the exit can become" ,
218
+ 'very slow because the program needs time to free up space.' )
219
+ print ('You can also press Esc to close window immediately,' ,
220
+ 'which may result in a segmentation fault.' )
221
+ self .gt = np .load (self .occ_path )
222
+ self .mask = mmengine .load (self .mask_path )
223
+
224
+ point_cloud_range = [- 3.2 , - 3.2 , - 1.28 + 0.5 , 3.2 , 3.2 , 1.28 + 0.5 ]
225
+ occ_size = [40 , 40 , 16 ]
226
+ self .grid_size = 0.16
227
+
228
+ self .points = np .zeros ((self .gt .shape [0 ], 6 ), dtype = float )
229
+ self .gird_id = np .ones (occ_size , dtype = int ) * - 1
230
+ self .visible_mask = np .zeros ((self .gt .shape [0 ], ), dtype = bool )
231
+ for i in range (self .gt .shape [0 ]):
232
+ x , y , z , label_id = self .gt [i ]
233
+ self .gird_id [x , y , z ] = i
234
+ label_id = int (label_id )
235
+ if label_id == 0 :
236
+ label = 'object'
237
+ else :
238
+ label = self .classes [label_id - 1 ]
239
+ color = self .color_selector .get_color (label )
240
+ color = [x / 255.0 for x in color ]
241
+ self .points [i ][:3 ] = [
242
+ x * self .grid_size + point_cloud_range [0 ] + self .grid_size / 2 ,
243
+ y * self .grid_size + point_cloud_range [1 ] + self .grid_size / 2 ,
244
+ z * self .grid_size + point_cloud_range [2 ] + self .grid_size / 2
245
+ ]
246
+ self .points [i ][3 :] = color
247
+
248
+ pcd = o3d .geometry .PointCloud ()
249
+ pcd .points = o3d .utility .Vector3dVector (self .points [:, :3 ])
250
+ pcd .colors = o3d .utility .Vector3dVector (self .points [:, 3 :])
251
+ voxel_grid = o3d .geometry .VoxelGrid .create_from_point_cloud (
252
+ pcd , voxel_size = self .grid_size )
253
+ frame = o3d .geometry .TriangleMesh .create_coordinate_frame ()
254
+ self .vis .create_window ()
255
+ self .vis .add_geometry (voxel_grid )
256
+ self .vis .add_geometry (frame )
257
+ ctr = self .vis .get_view_control ()
258
+ self .view_param = ctr .convert_to_pinhole_camera_parameters ()
259
+ self .voxel_grid = voxel_grid
260
+ self .draw_next (self .vis )
261
+
262
+ def draw_next (self , vis ):
263
+ """Render the next frame.
264
+
265
+ Args:
266
+ vis (open3d.visualization.VisualizerWithKeyCallback): Visualizer.
267
+ """
268
+ if self .idx >= len (self .scene ['images' ]):
269
+ print ('No more images' )
270
+ return
271
+
272
+ img = self .scene ['images' ][self .idx ]
273
+ extrinsic = self .scene ['axis_align_matrix' ] @ img ['cam2global' ]
274
+
275
+ mask = self .mask [self .idx ]['visible_occupancy' ]
276
+ visible_ids = np .unique (self .gird_id [mask ])
277
+ visible_ids = visible_ids [visible_ids >= 0 ]
278
+ self .visible_mask [visible_ids ] = True
279
+ pcd = o3d .geometry .PointCloud ()
280
+ pcd .points = o3d .utility .Vector3dVector (
281
+ self .points [self .visible_mask ][:, :3 ])
282
+ pcd .colors = o3d .utility .Vector3dVector (
283
+ self .points [self .visible_mask ][:, 3 :])
284
+ voxel_grid = o3d .geometry .VoxelGrid .create_from_point_cloud (
285
+ pcd , voxel_size = self .grid_size )
286
+
287
+ if self .camera is not None :
288
+ cam_points = draw_camera (extrinsic , return_points = True )
289
+ self .camera .points = cam_points
290
+ vis .update_geometry (self .camera )
291
+ else :
292
+ self .camera = draw_camera (extrinsic )
293
+ vis .add_geometry (self .camera )
294
+
295
+ self .voxel_grid .clear ()
296
+ vis .update_geometry (self .voxel_grid )
297
+ vis .remove_geometry (self .voxel_grid )
298
+ vis .add_geometry (voxel_grid )
299
+ self .voxel_grid = voxel_grid
300
+ self .idx += 1
301
+ ctr = vis .get_view_control ()
302
+ ctr .convert_from_pinhole_camera_parameters (self .view_param )
303
+ vis .update_renderer ()
304
+ vis .poll_events ()
305
+ vis .run ()
306
+
307
+ def close (self , vis ):
308
+ """Close the visualizer.
309
+
310
+ Args:
311
+ vis (open3d.visualization.VisualizerWithKeyCallback): Visualizer.
312
+ """
313
+ vis .clear_geometries ()
314
+ vis .destroy_window ()
315
+ vis .close ()
0 commit comments