-
Notifications
You must be signed in to change notification settings - Fork 31
/
Copy path21.ndds_export.py
411 lines (333 loc) · 13.8 KB
/
21.ndds_export.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
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
import nvisii
import numpy as np
opt = lambda : None
opt.spp = 100
opt.width = 500
opt.height = 500
opt.out = "21_ndds_export.png"
# # # # # # # # # # # # # # # # # # # # # # # # #
# Function to add cuboid information to an object using
def add_cuboid(name, debug=False):
"""
Add cuboid children to the transform tree to a given object for exporting
:param name: string name of the nvisii entity to add a cuboid
:param debug: bool - add sphere on the nvisii entity to make sure the
cuboid is located at the right place.
:return: return a list of cuboid in canonical space of the object.
"""
obj = nvisii.entity.get(name)
min_obj = obj.get_mesh().get_min_aabb_corner()
max_obj = obj.get_mesh().get_max_aabb_corner()
centroid_obj = obj.get_mesh().get_aabb_center()
cuboid = [
nvisii.vec3(max_obj[0], max_obj[1], max_obj[2]),
nvisii.vec3(min_obj[0], max_obj[1], max_obj[2]),
nvisii.vec3(max_obj[0], min_obj[1], max_obj[2]),
nvisii.vec3(max_obj[0], max_obj[1], min_obj[2]),
nvisii.vec3(min_obj[0], min_obj[1], max_obj[2]),
nvisii.vec3(max_obj[0], min_obj[1], min_obj[2]),
nvisii.vec3(min_obj[0], max_obj[1], min_obj[2]),
nvisii.vec3(min_obj[0], min_obj[1], min_obj[2]),
nvisii.vec3(centroid_obj[0], centroid_obj[1], centroid_obj[2]),
]
# change the ids to be like ndds / DOPE
cuboid = [ cuboid[2],cuboid[0],cuboid[3],
cuboid[5],cuboid[4],cuboid[1],
cuboid[6],cuboid[7],cuboid[-1]]
cuboid.append(nvisii.vec3(centroid_obj[0], centroid_obj[1], centroid_obj[2]))
for i_p, p in enumerate(cuboid):
child_transform = nvisii.transform.create(f"{name}_cuboid_{i_p}")
child_transform.set_position(p)
child_transform.set_scale(nvisii.vec3(0.3))
child_transform.set_parent(obj.get_transform())
if debug:
nvisii.entity.create(
name = f"{name}_cuboid_{i_p}",
mesh = nvisii.mesh.create_sphere(f"{name}_cuboid_{i_p}"),
transform = child_transform,
material = nvisii.material.create(f"{name}_cuboid_{i_p}")
)
for i_v, v in enumerate(cuboid):
cuboid[i_v]=[v[0], v[1], v[2]]
return cuboid
def get_cuboid_image_space(obj_id, camera_name = 'camera'):
"""
reproject the 3d points into the image space for a given object.
It assumes you already added the cuboid to the object
:obj_id: string for the name of the object of interest
:camera_name: string representing the camera name in nvisii
:return: cubdoid + centroid projected to the image, values [0..1]
"""
cam_matrix = nvisii.entity.get(camera_name).get_transform().get_world_to_local_matrix()
cam_proj_matrix = nvisii.entity.get(camera_name).get_camera().get_projection()
points = []
points_cam = []
for i_t in range(9):
trans = nvisii.transform.get(f"{obj_id}_cuboid_{i_t}")
mat_trans = trans.get_local_to_world_matrix()
pos_m = nvisii.vec4(
mat_trans[3][0],
mat_trans[3][1],
mat_trans[3][2],
1)
p_cam = cam_matrix * pos_m
p_image = cam_proj_matrix * (cam_matrix * pos_m)
p_image = nvisii.vec2(p_image) / p_image.w
p_image = p_image * nvisii.vec2(1,-1)
p_image = (p_image + nvisii.vec2(1,1)) * 0.5
points.append([p_image[0],p_image[1]])
points_cam.append([p_cam[0],p_cam[1],p_cam[2]])
return points, points_cam
# function to export meta data about the scene and about the objects
# of interest. Everything gets saved into a json file.
def export_to_ndds_file(
filename = "tmp.json", #this has to include path as well
obj_names = [], # this is a list of ids to load and export
height = 500,
width = 500,
camera_name = 'camera',
camera_struct = None,
visibility_percentage = False,
):
"""
Method that exports the meta data like NDDS. This includes all the scene information in one
scene.
:filename: string for the json file you want to export, you have to include the extension
:obj_names: [string] each entry is a nvisii entity that has the cuboids attached to, these
are the objects that are going to be exported.
:height: int height of the image size
:width: int width of the image size
:camera_name: string for the camera name nvisii entity
:camera_struct: dictionary of the camera look at information. Expecting the following
entries: 'at','eye','up'. All three has to be floating arrays of three entries.
This is an optional export.
:visibility_percentage: bool if you want to export the visibility percentage of the object.
Careful this can be costly on a scene with a lot of objects.
:return nothing:
"""
import simplejson as json
# assume we only use the view camera
cam_matrix = nvisii.entity.get(camera_name).get_transform().get_world_to_local_matrix()
cam_matrix_export = []
for row in cam_matrix:
cam_matrix_export.append([row[0],row[1],row[2],row[3]])
cam_world_location = nvisii.entity.get(camera_name).get_transform().get_position()
cam_world_quaternion = nvisii.entity.get(camera_name).get_transform().get_rotation()
# cam_world_quaternion = nvisii.quat_cast(cam_matrix)
cam_intrinsics = nvisii.entity.get(camera_name).get_camera().get_intrinsic_matrix(width, height)
if camera_struct is None:
camera_struct = {
'at': [0,0,0,],
'eye': [0,0,0,],
'up': [0,0,0,]
}
dict_out = {
"camera_data" : {
"width" : width,
'height' : height,
'camera_look_at':
{
'at': [
camera_struct['at'][0],
camera_struct['at'][1],
camera_struct['at'][2],
],
'eye': [
camera_struct['eye'][0],
camera_struct['eye'][1],
camera_struct['eye'][2],
],
'up': [
camera_struct['up'][0],
camera_struct['up'][1],
camera_struct['up'][2],
]
},
'camera_view_matrix':cam_matrix_export,
'location_world':
[
cam_world_location[0],
cam_world_location[1],
cam_world_location[2],
],
'quaternion_world_xyzw':[
cam_world_quaternion[0],
cam_world_quaternion[1],
cam_world_quaternion[2],
cam_world_quaternion[3],
],
'intrinsics':{
'fx':cam_intrinsics[0][0],
'fy':cam_intrinsics[1][1],
'cx':cam_intrinsics[2][0],
'cy':cam_intrinsics[2][1]
}
},
"objects" : []
}
# Segmentation id to export
id_keys_map = nvisii.entity.get_name_to_id_map()
for obj_name in obj_names:
projected_keypoints, _ = get_cuboid_image_space(obj_name, camera_name=camera_name)
# put them in the image space.
for i_p, p in enumerate(projected_keypoints):
projected_keypoints[i_p] = [p[0]*width, p[1]*height]
# Get the location and rotation of the object in the camera frame
trans = nvisii.transform.get(obj_name)
quaternion_xyzw = nvisii.inverse(cam_world_quaternion) * trans.get_rotation()
object_world = nvisii.vec4(
trans.get_position()[0],
trans.get_position()[1],
trans.get_position()[2],
1
)
pos_camera_frame = cam_matrix * object_world
#check if the object is visible
visibility = -1
bounding_box = [-1,-1,-1,-1]
segmentation_mask = nvisii.render_data(
width=int(width),
height=int(height),
start_frame=0,
frame_count=1,
bounce=int(0),
options="entity_id",
)
segmentation_mask = np.array(segmentation_mask).reshape(width,height,4)[:,:,0]
if visibility_percentage == True and int(id_keys_map [obj_name]) in np.unique(segmentation_mask.astype(int)):
transforms_to_keep = {}
for name in id_keys_map.keys():
if 'camera' in name.lower() or obj_name in name:
continue
trans_to_keep = nvisii.entity.get(name).get_transform()
transforms_to_keep[name]=trans_to_keep
nvisii.entity.get(name).clear_transform()
# Percentage visibility through full segmentation mask.
segmentation_unique_mask = nvisii.render_data(
width=int(width),
height=int(height),
start_frame=0,
frame_count=1,
bounce=int(0),
options="entity_id",
)
segmentation_unique_mask = np.array(segmentation_unique_mask).reshape(width,height,4)[:,:,0]
values_segmentation = np.where(segmentation_mask == int(id_keys_map[obj_name]))[0]
values_segmentation_full = np.where(segmentation_unique_mask == int(id_keys_map[obj_name]))[0]
visibility = len(values_segmentation)/float(len(values_segmentation_full))
# set back the objects from remove
for entity_name in transforms_to_keep.keys():
nvisii.entity.get(entity_name).set_transform(transforms_to_keep[entity_name])
else:
if int(id_keys_map[obj_name]) in np.unique(segmentation_mask.astype(int)):
#
visibility = 1
y,x = np.where(segmentation_mask == int(id_keys_map[obj_name]))
bounding_box = [int(min(x)),int(max(x)),height-int(max(y)),height-int(min(y))]
else:
visibility = 0
# Final export
dict_out['objects'].append({
'class':obj_name.split('_')[0],
'name':obj_name,
'provenance':'nvisii',
# TODO check the location
'location': [
pos_camera_frame[0],
pos_camera_frame[1],
pos_camera_frame[2]
],
'quaternion_xyzw':[
quaternion_xyzw[0],
quaternion_xyzw[1],
quaternion_xyzw[2],
quaternion_xyzw[3],
],
'quaternion_xyzw_world':[
trans.get_rotation()[0],
trans.get_rotation()[1],
trans.get_rotation()[2],
trans.get_rotation()[3]
],
'projected_cuboid': projected_keypoints[0:8],
'projected_cuboid_centroid': projected_keypoints[8],
'segmentation_id':id_keys_map[obj_name],
'visibility_image':visibility,
'bounding_box': {
'top_left':[
bounding_box[0],
bounding_box[2],
],
'bottom_right':[
bounding_box[1],
bounding_box[3],
],
},
})
with open(filename, 'w+') as fp:
json.dump(dict_out, fp, indent=4, sort_keys=True)
# # # # # # # # # # # # # # # # # # # # # # # # #
nvisii.initialize(headless=True, verbose=True)
nvisii.enable_denoiser()
camera = nvisii.entity.create(
name = "camera",
transform = nvisii.transform.create("camera"),
camera = nvisii.camera.create(
name = "camera",
aspect = float(opt.width)/float(opt.height)
)
)
# # # # # # # # # # # # # # # # # # # # # # # # #
# lets store the camera look at information so we can export it
camera_struct_look_at = {
'at':[0,0.1,0.1],
'up':[0,0,1],
'eye':[1,0.7,0.2]
}
# # # # # # # # # # # # # # # # # # # # # # # # #
camera.get_transform().look_at(
at = camera_struct_look_at['at'],
up = camera_struct_look_at['up'],
eye = camera_struct_look_at['eye']
)
nvisii.set_camera_entity(camera)
nvisii.set_dome_light_sky(sun_position = (10, 10, 1), saturation = 2)
nvisii.set_dome_light_exposure(1)
mesh = nvisii.mesh.create_from_file("obj", "./content/dragon/dragon.obj")
obj_entity = nvisii.entity.create(
name="obj_entity",
mesh = mesh,
transform = nvisii.transform.create("obj_entity"),
material = nvisii.material.create("obj_entity")
)
# # # # # # # # # # # # # # # # # # # # # # # # #
# Lets add the cuboid to the object we want to export
add_cuboid("obj_entity")
# lets keep track of the entities we want to export
entities_to_export = ["obj_entity"]
# lets set the obj_entity up
obj_entity.get_transform().set_rotation(
(0.7071, 0, 0, 0.7071)
)
obj_entity.get_material().set_base_color(
(0.9,0.12,0.08)
)
obj_entity.get_material().set_roughness(0.7)
obj_entity.get_material().set_specular(1)
obj_entity.get_material().set_sheen(1)
# # # # # # # # # # # # # # # # # # # # # # # # #
nvisii.render_to_file(
width=opt.width,
height=opt.height,
samples_per_pixel=opt.spp,
file_path=opt.out
)
export_to_ndds_file(
filename = opt.out.replace('png','json'),
obj_names = entities_to_export,
width=opt.width,
height=opt.height,
camera_struct = camera_struct_look_at
)
# let's clean up GPU resources
nvisii.deinitialize()