def remove_random_object(scene_struct, blender_objects, camera): #objects = scene_struct['objects'] #positions = [obj.location for obj in blender_objects] num_objs = len(blender_objects) n_rand = int(random.uniform(0, 1) * num_objs) print("object chosen: ", str(n_rand), " of ", str(num_objs)) utils.delete_object(blender_objects[n_rand]) scene_struct['objects'].pop(n_rand) blender_objects.pop(n_rand) return blender_objects, scene_struct
async def delete_mptcp_proxy(data_store, amqp, node_id): mptcp_proxy = utils.delete_object(data_store, amqp, node_id, utils.KEY_MPTCP_PROXY) mptcp_proxy.status = "Deleting" mptcp_proxy.deleting = True data_store.save(mptcp_proxy) await send_delete_proxy(data_store, amqp, mptcp_proxy) raise web.HTTPAccepted()
async def delete_l2_tunnel(data_store, amqp, node_id): l2_tunnel = utils.delete_object(data_store, amqp, node_id, utils.KEY_L2_TUNNEL) l2_tunnel.status = "Deleting" l2_tunnel.deleting = True data_store.save(l2_tunnel) await send_delete_tunnel(data_store, amqp, l2_tunnel) raise web.HTTPAccepted()
async def delete_expansion(data_store, amqp, node_id): expansion = utils.delete_object(data_store, amqp, node_id, utils.KEY_EXPANSION) expansion.status = "Deleting" expansion.deleting = True data_store.save(expansion) await send_delete_expansion(data_store, amqp, expansion) raise web.HTTPAccepted()
async def delete_vpn_connection(data_store, amqp, node_id): vpn_connection = utils.delete_object(data_store, amqp, node_id, utils.KEY_CONNECTION) vpn_connection.status = "Deleting" vpn_connection.deleting = True data_store.save(vpn_connection) await send_delete_connection(data_store, amqp, vpn_connection) raise web.HTTPAccepted()
def purge(blender_objects, blender_texts, view_struct, num_objects, args, cams): # If any of the objects are fully occluded then start over; delete all # objects from the scene and place them all again. __builtin__.print('Some objects are occluded; replacing objects') for obj in blender_objects: utils.delete_object(obj) for text in blender_texts: utils.delete_object(text) for obj in bpy.context.scene.objects: if "Text" in obj.name: utils.delete_object(obj) return add_random_objects(view_struct, num_objects, args, cams)
def render_scene( args, num_objects=5, output_index=0, output_split='none', output_image='render.png', output_scene='render.json', output_blendfile='render.blend', ): # Load the main blendfile bpy.ops.wm.open_mainfile(filepath=args.base_scene_blendfile) # Load materials utils.load_materials(args.material_dir) # Set render arguments so we can get pixel coordinates later. # We use functionality specific to the CYCLES renderer so BLENDER_RENDER # cannot be used. render_args = bpy.context.scene.render render_args.engine = "CYCLES" render_args.filepath = output_image render_args.resolution_x = args.width render_args.resolution_y = args.height render_args.resolution_percentage = 100 render_args.tile_x = args.render_tile_size render_args.tile_y = args.render_tile_size if args.use_gpu == 1: # Blender changed the API for enabling CUDA at some point if bpy.app.version < (2, 78, 0): bpy.context.user_preferences.system.compute_device_type = 'CUDA' bpy.context.user_preferences.system.compute_device = 'CUDA_0' else: cycles_prefs = bpy.context.user_preferences.addons[ 'cycles'].preferences cycles_prefs.compute_device_type = 'CUDA' # Some CYCLES-specific stuff bpy.data.worlds['World'].cycles.sample_as_light = True bpy.context.scene.cycles.blur_glossy = 2.0 bpy.context.scene.cycles.samples = args.render_num_samples bpy.context.scene.cycles.transparent_min_bounces = args.render_min_bounces bpy.context.scene.cycles.transparent_max_bounces = args.render_max_bounces if args.use_gpu == 1: bpy.context.scene.cycles.device = 'GPU' # This will give ground-truth information about the scene and its objects scene_struct = { 'split': output_split, 'image_index': output_index, 'image_filename': os.path.basename(output_image), 'objects': [], 'directions': {}, } # Put a plane on the ground so we can compute cardinal directions bpy.ops.mesh.primitive_plane_add(radius=5) plane = bpy.context.object def rand(L): return 2.0 * L * (random.random() - 0.5) # Add random jitter to camera position if args.camera_jitter > 0: for i in range(3): bpy.data.objects['Camera'].location[i] += rand(args.camera_jitter) # Figure out the left, up, and behind directions along the plane and record # them in the scene structure camera = bpy.data.objects['Camera'] plane_normal = plane.data.vertices[0].normal cam_behind = camera.matrix_world.to_quaternion() * Vector((0, 0, -1)) cam_left = camera.matrix_world.to_quaternion() * Vector((-1, 0, 0)) cam_up = camera.matrix_world.to_quaternion() * Vector((0, 1, 0)) plane_behind = (cam_behind - cam_behind.project(plane_normal)).normalized() plane_left = (cam_left - cam_left.project(plane_normal)).normalized() plane_up = cam_up.project(plane_normal).normalized() # Delete the plane; we only used it for normals anyway. The base scene file # contains the actual ground plane. utils.delete_object(plane) # Save all six axis-aligned directions in the scene struct scene_struct['directions']['behind'] = tuple(plane_behind) scene_struct['directions']['front'] = tuple(-plane_behind) scene_struct['directions']['left'] = tuple(plane_left) scene_struct['directions']['right'] = tuple(-plane_left) scene_struct['directions']['above'] = tuple(plane_up) scene_struct['directions']['below'] = tuple(-plane_up) # Add random jitter to lamp positions if args.key_light_jitter > 0: for i in range(3): bpy.data.objects['Lamp_Key'].location[i] += rand( args.key_light_jitter) if args.back_light_jitter > 0: for i in range(3): bpy.data.objects['Lamp_Back'].location[i] += rand( args.back_light_jitter) if args.fill_light_jitter > 0: for i in range(3): bpy.data.objects['Lamp_Fill'].location[i] += rand( args.fill_light_jitter) # Now make some random objects objects, blender_objects = add_random_objects(scene_struct, num_objects, args, camera) # Render the scene and dump the scene data structure scene_struct['objects'] = objects scene_struct['relationships'] = compute_all_relationships(scene_struct) while True: try: if args.save_blendfiles != 1: bpy.ops.render.render(write_still=True) break except Exception as e: print(e) with open(output_scene, 'w') as f: json.dump(scene_struct, f, indent=2) if args.save_blendfiles == 1: bpy.ops.wm.save_as_mainfile(filepath=output_blendfile) with open(output_blendfile, 'rb') as f_in, gzip.open(output_blendfile + '.gz', 'wb', compresslevel=1) as f_out: shutil.copyfileobj(f_in, f_out) os.remove(output_blendfile) return
def setup_scene( args, num_objects=5, output_index=0, output_split='none', output_image='render.png', output_scene='render_json', ): # This will give ground-truth information about the scene and its objects scene_struct = { 'split': output_split, 'image_index': output_index, 'image_filename': os.path.basename(output_image), 'objects': [], 'directions': {}, } # Put a plane on the ground so we can compute cardinal directions bpy.ops.mesh.primitive_plane_add(radius=5) plane = bpy.context.object # Add random jitter to camera position # if args.camera_jitter > 0: # for i in range(3): # bpy.data.objects['Camera'].location[i] += rand(args.camera_jitter) # Figure out the left, up, and behind directions along the plane and record camera = bpy.data.objects['Camera'] plane_normal = plane.data.vertices[0].normal cam_behind = camera.matrix_world.to_quaternion() * Vector((0, 0, -1)) cam_left = camera.matrix_world.to_quaternion() * Vector((-1, 0, 0)) cam_up = camera.matrix_world.to_quaternion() * Vector((0, 1, 0)) plane_behind = (cam_behind - cam_behind.project(plane_normal)).normalized() plane_left = (cam_left - cam_left.project(plane_normal)).normalized() plane_up = cam_up.project(plane_normal).normalized() # Save all six axis-aligned directions in the scene struct scene_struct['directions']['behind'] = tuple(plane_behind) scene_struct['directions']['front'] = tuple(-plane_behind) scene_struct['directions']['left'] = tuple(plane_left) scene_struct['directions']['right'] = tuple(-plane_left) scene_struct['directions']['above'] = tuple(plane_up) scene_struct['directions']['below'] = tuple(-plane_up) # Delete the plane; we only used it for normals anyway. The base scene file # contains the actual ground plane. utils.delete_object(plane) # Add random jitter to lamp positions if args.key_light_jitter > 0: for i in range(3): bpy.data.objects['Lamp_Key'].location[i] += rand( args.key_light_jitter) if args.back_light_jitter > 0: for i in range(3): bpy.data.objects['Lamp_Back'].location[i] += rand( args.back_light_jitter) if args.fill_light_jitter > 0: for i in range(3): bpy.data.objects['Lamp_Fill'].location[i] += rand( args.fill_light_jitter) # objects = cup_game(scene_struct, num_objects, args, camera) objects, blender_objects = add_random_objects(scene_struct, num_objects, args, camera) record = MovementRecord(blender_objects, args.num_frames) actions.random_objects_movements(objects, blender_objects, args, args.num_frames, args.min_dist, record, max_motions=args.max_motions) # Render the scene and dump the scene data structure scene_struct['objects'] = objects scene_struct['relationships'] = compute_all_relationships(scene_struct) scene_struct['movements'] = record.get_dict() with open(output_scene, 'w') as f: json.dump(scene_struct, f, indent=2)
def tearDownClass(cls): logging.info("Start Teardown") for stream in cls.streams_to_create: for record in cls.new_objects[stream]: delete_object(stream, record["id"])
def render_scene( args, num_objects=5, output_index=0, output_split='none', output_image='render.png', output_scene='render_json', output_blendfile=None, ): # Load the main blendfile bpy.ops.wm.open_mainfile(filepath=args.base_scene_blendfile) # Load materials utils.load_materials(args.material_dir) # Set render arguments so we can get pixel coordinates later. # We use functionality specific to the CYCLES renderer so BLENDER_RENDER # cannot be used. render_args = bpy.context.scene.render render_args.engine = "CYCLES" render_args.filepath = output_image render_args.resolution_x = args.width render_args.resolution_y = args.height render_args.resolution_percentage = 100 render_args.tile_x = args.render_tile_size render_args.tile_y = args.render_tile_size if args.use_gpu == 1: # Blender changed the API for enabling CUDA at some point if bpy.app.version < (2, 78, 0): bpy.context.user_preferences.system.compute_device_type = 'CUDA' bpy.context.user_preferences.system.compute_device = 'CUDA_0' else: cycles_prefs = bpy.context.user_preferences.addons[ 'cycles'].preferences cycles_prefs.compute_device_type = 'CUDA' # Some CYCLES-specific stuff bpy.data.worlds['World'].cycles.sample_as_light = True bpy.context.scene.cycles.blur_glossy = 2.0 bpy.context.scene.cycles.samples = args.render_num_samples bpy.context.scene.cycles.transparent_min_bounces = args.render_min_bounces bpy.context.scene.cycles.transparent_max_bounces = args.render_max_bounces if args.use_gpu == 1: bpy.context.scene.cycles.device = 'GPU' # This will give ground-truth information about the scene and its objects scene_struct = { 'split': output_split, 'image_index': output_index, 'image_filename': os.path.basename(output_image), 'objects': [], 'directions': {}, } # Put a plane on the ground so we can compute cardinal directions bpy.ops.mesh.primitive_plane_add(radius=5) plane = bpy.context.object def rand(L): return 2.0 * L * (random.random() - 0.5) # Add random jitter to camera position if args.camera_jitter > 0: for i in range(3): bpy.data.objects['Camera'].location[i] += rand(args.camera_jitter) # Figure out the left, up, and behind directions along the plane and record # them in the scene structure camera = bpy.data.objects['Camera'] plane_normal = plane.data.vertices[0].normal cam_behind = camera.matrix_world.to_quaternion() * Vector((0, 0, -1)) cam_left = camera.matrix_world.to_quaternion() * Vector((-1, 0, 0)) cam_up = camera.matrix_world.to_quaternion() * Vector((0, 1, 0)) plane_behind = (cam_behind - cam_behind.project(plane_normal)).normalized() plane_left = (cam_left - cam_left.project(plane_normal)).normalized() plane_up = cam_up.project(plane_normal).normalized() # Delete the plane; we only used it for normals anyway. The base scene file # contains the actual ground plane. utils.delete_object(plane) # Save all six axis-aligned directions in the scene struct scene_struct['directions']['behind'] = tuple(plane_behind) scene_struct['directions']['front'] = tuple(-plane_behind) scene_struct['directions']['left'] = tuple(plane_left) scene_struct['directions']['right'] = tuple(-plane_left) scene_struct['directions']['above'] = tuple(plane_up) scene_struct['directions']['below'] = tuple(-plane_up) # Add random jitter to lamp positions if args.key_light_jitter > 0: for i in range(3): bpy.data.objects['Lamp_Key'].location[i] += rand( args.key_light_jitter) if args.back_light_jitter > 0: for i in range(3): bpy.data.objects['Lamp_Back'].location[i] += rand( args.back_light_jitter) if args.fill_light_jitter > 0: for i in range(3): bpy.data.objects['Lamp_Fill'].location[i] += rand( args.fill_light_jitter) # Now make some random objects objects, blender_objects = add_random_objects(scene_struct, num_objects, args, camera) ## Added (Start) # instance id is stored as 32 bit float # if there are N objects, then id 0 ~ N - 1 is randomly assigned to each # assign id to each object for i, o in enumerate(blender_objects): o.pass_index = i # add new node for composition bpy.context.scene.use_nodes = True tree = bpy.context.scene.node_tree bpy.context.scene.render.layers["RenderLayer"].use_pass_object_index = True node = tree.nodes.new(type="CompositorNodeOutputFile") node.base_path = '../output/images' node.format.file_format = 'OPEN_EXR' # for instance segmentation node.file_slots[0].path = 'inst' tree.links.new(tree.nodes["Render Layers"].outputs['IndexOB'], node.inputs[0]) # for rendered image node.layer_slots.new('Image') node.file_slots[1].path = 'rgb' node.file_slots[1].use_node_format = False node.file_slots[1].format.file_format = 'PNG' tree.links.new(tree.nodes["Render Layers"].outputs['Image'], node.inputs[1]) ## Added (end) # Render the scene and dump the scene data structure scene_struct['objects'] = objects scene_struct['relationships'] = compute_all_relationships(scene_struct) while True: try: # bpy.ops.render.render(write_still=True) bpy.ops.render.render() break except Exception as e: print(e) with open(output_scene, 'w') as f: json.dump(scene_struct, f, indent=2) if output_blendfile is not None: bpy.ops.wm.save_as_mainfile(filepath=output_blendfile)
def add_random_objects(scene_struct, num_objects, args, inp, img_config, camera): """ Add random objects to the current blender scene """ # Load the property file with open(args.properties_json, 'r') as f: properties = json.load(f) color_name_to_rgba = {} for name, rgb in properties['colors'].items(): rgba = [float(c) / 255.0 for c in rgb] + [1.0] color_name_to_rgba[name] = rgba material_mapping = [(v, k) for k, v in properties['materials'].items()] object_mapping = [(v, k) for k, v in properties['shapes'].items()] size_mapping = list(properties['sizes'].items()) shape_color_combos = None if args.shape_color_combos_json is not None: with open(args.shape_color_combos_json, 'r') as f: shape_color_combos = list(json.load(f).items()) positions = [] objects = [] blender_objects = [] for i in range(num_objects): # Choose a random size user_obj = img_config.objects[i] size_name = user_obj['size'] assert size_name in properties[ 'sizes'], "Size not defined in properties.json" r = properties['sizes'][size_name] # size_name, r = random.choice(size_mapping) # Try to place the object, ensuring that we don't intersect any existing # objects and that we are more than the desired margin away from all existing # objects along all cardinal directions. num_tries = 0 while True: # If we try and fail to place an object too many times, then delete all # the objects in the scene and start over. num_tries += 1 if num_tries > args.max_retries: for obj in blender_objects: utils.delete_object(obj) print("Failed to place objects") print(dists_good, margins_good) sys.exit( "Failed to place objects. Check `user_config.py` for image {image_index}, object {i}" .format(image_index=image_index, i=i)) dy = lambda: random.uniform(-0.45, 0.45) clamp = lambda x: min(2.95, max(-2.95, x)) x = clamp(user_obj['x']) y = clamp(user_obj['y']) z = user_obj['z'] # Check to make sure the new object is further than min_dist from all # other objects, and further than margin along the four cardinal directions dists_good = True margins_good = True for (xx, yy, rr) in positions: dx, dy = x - xx, y - yy dist = math.sqrt(dx * dx + dy * dy) if dist - r - rr < args.min_dist: dists_good = False break for direction_name in ['left', 'right', 'front', 'behind']: direction_vec = scene_struct['directions'][direction_name] assert direction_vec[2] == 0 margin = dx * direction_vec[0] + dy * direction_vec[1] if 0 < margin < args.margin: print(margin, args.margin, direction_name) print('BROKEN MARGIN!') margins_good = False break if not margins_good: break if dists_good and margins_good: break # Choose random color and shape if shape_color_combos is None: # obj_name, obj_name_out = random.choice(object_mapping) # color_name, rgba = random.choice(list(color_name_to_rgba.items())) obj_name_out = user_obj['shape'] color_name = user_obj['color'] assert obj_name_out in properties[ 'shapes'], "Shape not defined in properties.json" assert color_name in color_name_to_rgba, "Color not defined in properties.json" obj_name = properties['shapes'][obj_name_out] rgba = color_name_to_rgba[color_name] else: obj_name_out, color_choices = random.choice(shape_color_combos) color_name = random.choice(color_choices) obj_name = [k for k, v in object_mapping if v == obj_name_out][0] rgba = color_name_to_rgba[color_name] # For cube, adjust the size a bit if obj_name == 'Cube': r /= math.sqrt(2) # Choose random orientation for the object. theta = user_obj[ 'orientation'] if 'orientation' in user_obj else 360.0 * random.random( ) # Actually add the object to the scene utils.add_object(args.shape_dir, obj_name, r, (x, y, z), theta=theta) obj = bpy.context.object blender_objects.append(obj) positions.append((x, y, r)) # Attach a random material # mat_name, mat_name_out = random.choice(material_mapping) mat_name_out = user_obj['material'] assert mat_name_out in properties[ 'materials'], "Material not defined in properties.json" mat_name = properties['materials'][mat_name_out] utils.add_material(mat_name, Color=rgba) # Record data about the object in the scene data structure pixel_coords = utils.get_camera_coords(camera, obj.location) objects.append({ 'shape': obj_name_out, 'size': size_name, 'material': mat_name_out, '3d_coords': tuple(obj.location), 'rotation': theta, 'pixel_coords': pixel_coords, 'color': color_name, }) # Check that all objects are at least partially visible in the rendered image all_visible = check_visibility(blender_objects, args.min_pixels_per_object) if not all_visible: # If any of the objects are fully occluded then start over; delete all # objects from the scene and place them all again. print('Some objects are occluded; replacing objects') for obj in blender_objects: utils.delete_object(obj) return add_random_objects(scene_struct, num_objects, args, inp, img_config, camera) return objects, blender_objects
utils.move_hand(0) utils.move_arm_neutral() except: rospy.logerr('fail to grasp') sys.exit() try: utils.move_hand(1) time.sleep(2) utils.move_hand(0) utils.move_arm_init() except: rospy.logerr('fail to move') sys.exit() try: utils.move_base_goal(0.85, 4.0, 180) except: rospy.logerr('fail to move') sys.exit() try: utils.delete_object("e_lego_duplo") utils.move_base_goal(0, 0, 0) except: print("first_state") sys.exit()
def add_random_objects(scene_struct, num_objects, args, camera, init_positions, sizes=[], inout=False): """ Add random objects to the current blender scene """ # Load the property file print(init_positions) color_name_to_rgba = {} with open(args.properties_json, 'r') as f: properties = json.load(f) for name, rgb in properties['colors'].items(): rgba = [float(c) / 255.0 for c in rgb] + [1.0] color_name_to_rgba[name] = rgba material_mapping = [(v, k) for k, v in properties['materials'].items()] object_mapping = [(v, k) for k, v in properties['shapes'].items()] size_mapping = list(properties['sizes'].items()) shape_color_combos = None if args.shape_color_combos_json is not None: with open(args.shape_color_combos_json, 'r') as f: shape_color_combos = list(json.load(f).items()) positions = [] objects = [] blender_objects = [] for i in range(num_objects): if len(sizes) == 1 and i != 0: # Choose a random size size_name, r = random.choice(size_mapping) else: size_name, r = sizes[i] x, y, z = init_positions[i] # Choose random color and shape if shape_color_combos is None: obj_name, obj_name_out = random.choice(object_mapping) color_name, rgba = random.choice(list(color_name_to_rgba.items())) if inout and i == 0: obj_name, obj_name_out = ('Tray', 'tray') color_name, rgba = ('gray', [0.5, 0.5, 0.5, 1]) # elif i == 0: # obj_name, obj_name_out = ('SmoothCube_v2', 'cube') # color_name, rgba = ('red', [0.67, 0.13, 0.13, 1]) # elif i == 1: # obj_name, obj_name_out = ('SmoothCube_v2', 'cube') # color_name, rgba = ('blue', color_name_to_rgba['blue']) # elif i == 2: # obj_name, obj_name_out = ('SmoothCylinder', 'cylinder') # color_name, rgba = ('green', color_name_to_rgba['green']) else: obj_name_out, color_choices = random.choice(shape_color_combos) color_name = random.choice(color_choices) obj_name = [k for k, v in object_mapping if v == obj_name_out][0] rgba = color_name_to_rgba[color_name] # For cube, adjust the size a bit if obj_name == 'Cube': r /= math.sqrt(2) theta = 0 # Actually add the object to the scene utils.add_object(args.shape_dir, obj_name, r, (x, y, z), theta=theta) obj = bpy.context.object blender_objects.append(obj) positions.append((x, y, z, r)) # Attach a random material mat_name, mat_name_out = random.choice(material_mapping) if i == 0 or i == 1: mat_name = "Rubber" elif i == 2: mat_name = "MyMetal" utils.add_material(mat_name, Color=rgba) # Record data about the object in the scene data structure pixel_coords = utils.get_camera_coords(camera, obj.location) objects.append({ 'shape': obj_name_out, 'size': size_name, 'material': mat_name_out, '3d_coords': tuple(obj.location), 'r' : r, 'rotation': theta, 'pixel_coords': pixel_coords, 'color': color_name, }) # Check that all objects are at least partially visible in the rendered image all_visible = check_visibility(blender_objects, objects, args.min_pixels_per_object) if not all_visible: # If any of the objects are fully occluded then start over; delete all # objects from the scene and place them all again. print('Some objects are occluded; replacing objects') for obj in blender_objects: utils.delete_object(obj) return add_random_objects(scene_struct, num_objects, args, camera, init_positions + np.random.uniform(low=-0.05, high=0.05, size=(np.array(init_positions).shape)), sizes=sizes, inout=inout) return objects, blender_objects
def render_scene(args, num_objects=5, num_images=0, output_split='none', image_template='render.png', scene_template='render_json', arr_template='arr', output_blendfile=None, directions={1: 'no', 2: 'no', 3: 'no', 4: 'no', 5: 'no', 6: 'no'} ): for object_name in bpy.data.objects.keys(): if 'Sphere' in object_name or\ 'Cylinder' in object_name or\ 'Cube' in object_name or\ 'Duck' in object_name or\ 'Peg' in object_name or\ 'Disk' in object_name or\ 'Bowl' in object_name: utils.delete_object_by_name(object_name) # Load materials utils.load_materials(args.material_dir) # Set render arguments so we can get pixel coordinates later. # We use functionality specific to the CYCLES renderer so BLENDER_RENDER # cannot be used. render_args = bpy.context.scene.render render_args.engine = "CYCLES" render_args.resolution_x = args.width render_args.resolution_y = args.height render_args.resolution_percentage = 100 render_args.tile_x = args.render_tile_size render_args.tile_y = args.render_tile_size if args.use_gpu == 1: # Blender changed the API for enabling CUDA at some point if bpy.app.version < (2, 78, 0): bpy.context.user_preferences.system.compute_device_type = 'CUDA' bpy.context.user_preferences.system.compute_device = 'CUDA_0' else: cycles_prefs = bpy.context.user_preferences.addons['cycles'].preferences cycles_prefs.compute_device_type = 'CUDA' # Some CYCLES-specific stuff bpy.data.worlds['World'].cycles.sample_as_light = True bpy.context.scene.cycles.blur_glossy = 2.0 bpy.context.scene.cycles.samples = args.render_num_samples bpy.context.scene.cycles.transparent_min_bounces = args.render_min_bounces bpy.context.scene.cycles.transparent_max_bounces = args.render_max_bounces if args.use_gpu == 1: bpy.context.scene.cycles.device = 'GPU' # This will give ground-truth information about the scene and its objects scene_struct = { 'split': output_split, 'objects': [], 'directions': {}, } # Put a plane on the ground so we can compute cardinal directions bpy.ops.mesh.primitive_plane_add(radius=5) plane = bpy.context.object def rand(L): return 2.0 * L * (random.random() - 0.5) # Add random jitter to camera position if args.camera_jitter > 0: for i in range(3): bpy.data.objects['Camera'].location[i] += rand(args.camera_jitter) # Figure out the left, up, and behind directions along the plane and record # them in the scene structure camera = bpy.data.objects['Camera'] plane_normal = plane.data.vertices[0].normal cam_behind = camera.matrix_world.to_quaternion() * Vector((0, 0, -1)) cam_left = camera.matrix_world.to_quaternion() * Vector((-1, 0, 0)) cam_up = camera.matrix_world.to_quaternion() * Vector((0, 1, 0)) plane_behind = (cam_behind - cam_behind.project(plane_normal)).normalized() plane_left = (cam_left - cam_left.project(plane_normal)).normalized() plane_up = cam_up.project(plane_normal).normalized() # Delete the plane; we only used it for normals anyway. The base scene file # contains the actual ground plane. utils.delete_object(plane) # Save all six axis-aligned directions in the scene struct scene_struct['directions']['behind'] = tuple(plane_behind) scene_struct['directions']['front'] = tuple(-plane_behind) scene_struct['directions']['left'] = tuple(plane_left) scene_struct['directions']['right'] = tuple(-plane_left) scene_struct['directions']['above'] = tuple(plane_up) scene_struct['directions']['below'] = tuple(-plane_up) # Add random jitter to lamp positions if args.key_light_jitter > 0: for i in range(3): bpy.data.objects['Lamp_Key'].location[i] += rand(args.key_light_jitter) if args.back_light_jitter > 0: for i in range(3): bpy.data.objects['Lamp_Back'].location[i] += rand(args.back_light_jitter) if args.fill_light_jitter > 0: for i in range(3): bpy.data.objects['Lamp_Fill'].location[i] += rand(args.fill_light_jitter) objects = [] blender_objects = [] direction_vec = [] traj = [] for scene_idx in range(num_images): image_path = image_template % (scene_idx + args.start_idx) render_args.filepath = image_path scene_path = scene_template % (scene_idx + args.start_idx) arr_path = arr_template % (scene_idx + args.start_idx) if scene_idx == 0: init_positions = [] # ref_obj_loc = np.array([0, -1, 0]) ref_obj_loc = np.array([0, 0, 0]) init_positions.append(ref_obj_loc) sizes = [('large', 0.6)] # sizes = [('small', 0.3)] inout=False for obj_idx in range(1, args.max_objects): init_position = [] for axis, movement in directions.items(): # X if axis == 1: if movement != ['no']: if movement[0] == 'front': init_position.append(-3) else: init_position.append(2) else: tmp = random.choice(np.linspace(-2, 2, 10, endpoint=True)) while np.array([abs(tmp - posit[1]) < args.margin for posit in init_positions]).any(): tmp = random.choice(np.linspace(-2, 2, 10, endpoint=True)) init_position.append(tmp) # Y if axis == 0: if movement != ['no']: if movement[0] == 'left': init_position.append(-2) else: init_position.append(2) else: tmp = random.choice(np.linspace(-2, 2, 10, endpoint=True)) while np.array([abs(tmp - posit[0]) < args.margin for posit in init_positions]).any(): tmp = random.choice(np.linspace(-2, 2, 10, endpoint=True)) init_position.append(tmp) # Z if axis == 2: if movement != ['no']: if movement[0] == 'below': init_position.append(0) else: init_position.append(2) else: tmp = random.choice(np.linspace(0, 2, 10, endpoint=True)) # while np.array([abs(tmp - posit[2]) < args.margin for posit in init_positions]).any(): while abs(tmp - init_positions[0][2]) < args.margin: tmp = random.choice(np.linspace(0, 2, 10, endpoint=True)) init_position.append(tmp) # CLOSE/FAR close_far_thresh = 3 if axis == 3: if movement != ['no']: far_sample = [] close_sample = [] while far_sample == [] or \ np.linalg.norm(far_sample - ref_obj_loc) < close_far_thresh or \ np.array([np.linalg.norm(far_sample - posit) < args.min_dist for posit in init_positions]).any(): x = random.choice(np.linspace(-2, 2, 10, endpoint=True)) y = random.choice(np.linspace(-2, 2, 10, endpoint=True)) z = random.choice(np.linspace(0.6, 2, 10, endpoint=True)) far_sample = np.array([x, y, z]) while close_sample == [] or \ np.linalg.norm(close_sample - ref_obj_loc) > close_far_thresh or \ np.linalg.norm(close_sample - ref_obj_loc) < 1: x = random.choice(np.linspace(-2, 2, 10, endpoint=True)) y = random.choice(np.linspace(-2, 2, 10, endpoint=True)) z = random.choice(np.linspace(0.6, 2, 10, endpoint=True)) close_sample = np.array([x, y, z]) if movement[0] == 'far': init_position = far_sample else: init_position = close_sample else: pass # ON/OFF close_far_thresh = 1 if axis == 4: if movement != ['no']: # size_mapping = [('small', 0.35), ('large', 0.7)] size_mapping = [('small', 0.5)] off_sample = [] on_sample = [] while off_sample == [] or \ np.linalg.norm(off_sample - ref_obj_loc) < close_far_thresh or \ np.array([np.linalg.norm(off_sample - posit) < args.min_dist for posit in init_positions]).any(): x = random.choice(np.linspace(-2, 2, 10, endpoint=True)) y = random.choice(np.linspace(-2, 2, 10, endpoint=True)) # z = random.choice(np.linspace(0.6, 2, 10, endpoint=True)) z = 0 off_sample = np.array([x, y, z]) x = init_positions[-1][0] + random.uniform(-0.2, 0.2) y = init_positions[-1][1] + random.uniform(-0.2, 0.2) size_name, r = random.choice(size_mapping) sizes.append((size_name, r)) z = init_positions[-1][2] + sizes[-1][1] * 2 on_sample = np.array([x, y, z]) if movement[0] == 'off': init_position = off_sample else: init_position = on_sample else: pass # IN/OUT close_far_thresh = 1 if axis == 5: if movement != ['no']: inout = True out_sample = [] in_sample = [] while out_sample == [] or \ np.linalg.norm(out_sample - ref_obj_loc) < close_far_thresh or \ np.array([np.linalg.norm(out_sample - posit) < args.min_dist for posit in init_positions]).any(): x = random.choice(np.linspace(-2, 2, 10, endpoint=True)) # y = random.choice(np.linspace(-2, 2, 10, endpoint=True)) y = -3 + random.uniform(-0.2, 0.2) # z = random.choice(np.linspace(0.6, 2, 10, endpoint=True)) z = 0 out_sample = np.array([x, y, z]) # if obj_idx == 1: # offset = -1 # else: # offset = 1 offsets = [[-1, -1], [-1, 1], [1, -1], [1, 1]] # x = init_positions[0][0] + offset # y = init_positions[0][1] + random.choice(np.linspace(-0.2, 0.2, 2, endpoint=True)) x, y = offsets[obj_idx - 1] x += random.uniform(-0.1, 0.1) y += random.uniform(-0.1, 0.1) sizes.append(('small', 0.3)) z = init_positions[0][2] in_sample = np.array([x, y, z]) if movement[0] == 'out': init_position = out_sample else: init_position = in_sample else: pass init_positions.append(init_position) # FACILITATE STACKING if directions[4][0] != 'no' and directions[4][0] == 'on': init_positions = init_positions[:1] + init_positions[1:][::-1] print(init_positions) # Now make some random objects objects, blender_objects = add_random_objects(scene_struct, num_objects, args, camera, \ init_positions, sizes=sizes, inout=inout) init_positions = [] for obj in blender_objects: init_positions.append(np.array(obj.location)) final_positions = [] ref_obj_loc = init_positions[0] final_positions.append(ref_obj_loc) curvy = False for obj_idx in range(1, args.max_objects): final_position = [] for axis, movement in directions.items(): # X if axis == 1: if movement != ['no']: if movement[0] == 'front': final_position.append(2) else: final_position.append(-3) else: final_position.append(np.array(blender_objects[obj_idx].location[1])) # Y if axis == 0: if movement != ['no']: if movement[0] == 'left': final_position.append(2) else: final_position.append(-2) else: final_position.append(np.array(blender_objects[obj_idx].location[0])) # Z if axis == 2: if movement != ['no']: if movement[0] == 'below': final_position.append(2) else: final_position.append(objects[obj]['r']) else: final_position.append(np.array(blender_objects[obj_idx].location[2])) # CLOSE/FAR close_far_thresh = 3 if axis == 3: if movement != ['no']: far_sample = [] close_sample = [] while far_sample == [] or \ np.linalg.norm(far_sample - ref_obj_loc) < close_far_thresh or \ np.array([np.linalg.norm(far_sample - posit) < args.min_dist for posit in final_positions]).any(): x = random.choice(np.linspace(-2, 2, 10, endpoint=True)) y = random.choice(np.linspace(-2, 2, 10, endpoint=True)) z = random.choice(np.linspace(0.6, 2, 10, endpoint=True)) far_sample = np.array([x, y, z]) while close_sample == [] or \ np.linalg.norm(close_sample - ref_obj_loc) > close_far_thresh or \ np.linalg.norm(close_sample - ref_obj_loc) < 1 or \ np.array([np.linalg.norm(close_sample - posit) < args.min_dist for posit in final_positions]).any(): x = random.choice(np.linspace(-2, 2, 10, endpoint=True)) y = random.choice(np.linspace(-2, 2, 10, endpoint=True)) z = random.choice(np.linspace(0.6, 2, 10, endpoint=True)) close_sample = np.array([x, y, z]) if movement[0] == 'far': final_position = close_sample else: final_position = far_sample else: pass # ON/OFF close_far_thresh = 1 if axis == 4: if movement != ['no']: curvy = True off_sample = [] on_sample = [] while off_sample == [] or \ np.linalg.norm(off_sample - ref_obj_loc) < close_far_thresh or \ np.array([np.linalg.norm(off_sample - posit) < args.min_dist for posit in final_positions]).any(): x = random.choice(np.linspace(-2, 2, 10, endpoint=True)) y = random.choice(np.linspace(-2, 2, 10, endpoint=True)) # z = random.choice(np.linspace(0.6, 2, 10, endpoint=True)) z = 0 off_sample = np.array([x, y, z]) x = final_positions[-1][0] + random.uniform(-0.2, 0.2) y = final_positions[-1][1] + random.uniform(-0.2, 0.2) r_prev = objects[obj_idx-1]['r'] r = objects[obj_idx]['r'] z = final_positions[-1][2] + r_prev + r on_sample = np.array([x, y, z]) if movement[0] == 'off': final_position = on_sample else: final_position = off_sample else: pass # IN/OUT close_far_thresh = 1 if axis == 5: if movement != ['no']: curvy = True out_sample = [] in_sample = [] while out_sample == [] or \ np.linalg.norm(out_sample - ref_obj_loc) < close_far_thresh or \ np.array([np.linalg.norm(out_sample - posit) < args.min_dist for posit in final_positions]).any(): x = random.choice(np.linspace(-2, 2, 10, endpoint=True)) # y = random.choice(np.linspace(-2, 2, 10, endpoint=True)) y = -3 + random.uniform(-0.2, 0.2) # z = random.choice(np.linspace(0.6, 2, 10, endpoint=True)) z = 0 out_sample = np.array([x, y, z]) # if obj_idx == 1: # offset = -1 # else: # offset = 1 # x = final_positions[0][0] + offset # y = final_positions[0][1] + random.choice(np.linspace(-0.2, 0.2, 2, endpoint=True)) #offsets = [[-1, -1], [-1, 1], [1, -1], [1, 1]] offsets = [[-0.5, -0.5], [-0.5, 0.5], [0.5, -0.5], [0.5, 0.5]] x, y = offsets[obj_idx - 1] # x, y = [0, 0] x += random.uniform(-0.1, 0.1) y += random.uniform(-0.1, 0.1) r = objects[obj_idx]['r'] z = final_positions[0][2] + r in_sample = np.array([x, y, z]) if movement[0] == 'out': final_position = in_sample else: final_position = out_sample else: pass final_positions.append(final_position) traj = calculate_trajectory(init_positions, final_positions, args, curvy=curvy) else: move_obj_idx, pos = traj[scene_idx-1] move_object(blender_objects[move_obj_idx], pos) pixel_coords = utils.get_camera_coords(camera, blender_objects[move_obj_idx].location) objects[move_obj_idx]['pixel_coords'] = pixel_coords # <Vector (-1.6002, -1.5445, 1.9500)> objects[move_obj_idx]['3d_coords'] = list(blender_objects[move_obj_idx].location) # <Euler (x=0.0000, y=0.0000, z=139.0579), order='XYZ'> objects[move_obj_idx]['rotation'] = blender_objects[move_obj_idx].rotation_euler[2] ### get b_box box_dict = get_b_box.main(bpy.context, blender_objects) for _id in box_dict: objects[_id]['bbox'] = box_dict[_id] # Render the scene and dump the scene data structure scene_struct['objects'] = objects scene_struct['relationships'] = compute_all_relationships(scene_struct) tree = bpy.context.scene.node_tree links = tree.links rl = tree.nodes['Render Layers'] v = tree.nodes['Viewer'] links.new(rl.outputs[0], v.inputs[0]) while True: try: bpy.ops.render.render(write_still=True) break except Exception as e: print(e) links.remove(links[0]) # get viewer pixels rgb_pixels = bpy.data.images['Viewer Node'].pixels rgb_pixels = np.array(rgb_pixels[:]) rgb_pixels = np.power(rgb_pixels, 1/2.2) rgb_pixels[rgb_pixels > 1] = 1 rgb_pixels = rgb_pixels.reshape(args.height, args.width, 4)[...,:3] links.new(rl.outputs[2], v.inputs[0]) render_shadeless(blender_objects, lights_off=False) links.remove(links[0]) # get viewer pixels depth_pixels = bpy.data.images['Viewer Node'].pixels depth_pixels = np.array(depth_pixels[:]) depth_pixels = depth_pixels.reshape(args.height, args.width, 4)[...,0, None] links.new(rl.outputs[0], v.inputs[0]) render_shadeless(blender_objects) links.remove(links[0]) # get viewer pixels mask_pixels = bpy.data.images['Viewer Node'].pixels mask_pixels = np.array(mask_pixels[:]) mask_pixels = mask_pixels.reshape(args.height, args.width, 4)[...,:3] pixels = np.concatenate((rgb_pixels, depth_pixels, mask_pixels), axis=2) pixels = np.flipud(pixels) utils.save_arr(pixels, arr_path) with open(scene_path, 'w') as f: json.dump(scene_struct, f, indent=2)
def do_test(self, conn_id): """ Verify that the sync only sent records to the target for selected streams Create a new object for each stream Verify that the second sync includes at least one create for each stream Verify that the created record was picked up on the second sync """ streams_to_create = { "balance_transactions", # should be created implicity with a create in the payouts or charges streams "charges", "coupons", "customers", "invoice_items", "invoice_line_items", # this is created implicity by invoices, it just creates another invoice TODO get this outa here "invoices", # this will create an invoice_item "payouts", "plans", "products", "subscription_items", "subscriptions", # this will create a new plan and payment method } missing_streams_to_create = { "disputes", # can be created by simulating a dispute transaction with a specific card number # no way to create directly, see: https://stripe.com/docs/testing#disputes "payout_transactions", # BUG (https://stitchdata.atlassian.net/browse/SUP-1294) # depends on payouts and transactions "transfers", # needs an account that we can transfer to, not sure # how to set up a test account we can use to create a transfer } our_catalogs = get_catalogs(conn_id, streams_to_create) self.select_all_streams_and_fields(conn_id, our_catalogs, select_all_fields=True) # Run a sync job using orchestrator first_sync_record_count = self.run_sync(conn_id) # verify that the sync only sent records to the target for selected streams (catalogs) self.assertEqual(set(first_sync_record_count.keys()), streams_to_create) # Get the set of records from a first sync first_sync_records = runner.get_records_from_target_output() first_sync_created, _ = self.split_records_into_created_and_updated( first_sync_records) new_objects = { stream: create_object(stream) for stream in streams_to_create.difference( {"balance_transactions"}) } # Run a second sync job using orchestrator second_sync_record_count = self.run_sync(conn_id) # Get the set of records from a second sync second_sync_records = runner.get_records_from_target_output() second_sync_created, _ = self.split_records_into_created_and_updated( second_sync_records) # # THIS MAKES AN ASSUMPTION THAT CHILD STREAMS DO NOT NEED TESTING. # # ADJUST IF NECESSARY for stream in streams_to_create.difference(self.child_streams()): with self.subTest(stream=stream): second_sync_created_objects = second_sync_created.get( stream, {}).get("messages", []) # verify that you get at least one new record on the second sync self.assertGreaterEqual( len(second_sync_created_objects), 1, msg="second sync didn't have created objects", ) if stream == "balance_transactions": sources = [ record.get("data", {}).get("source") for record in second_sync_created_objects ] self.assertTrue(new_objects['payouts']['id'] in sources) self.assertTrue(new_objects['charges']['id'] in sources) continue # verify the new object is in the list of created objects # from the second sync self.assertTrue( any(new_objects[stream]["id"] == record.get("data", {}).get("id") for record in second_sync_created_objects)) if stream in streams_to_create: delete_object(stream, new_objects[stream]["id"])
def test_run(self): """ Verify that the sync only sent records to the target for selected streams Update metadata[test] with a random number for each stream with event updates Verify that the second sync includes at least one update for each stream Verify that the second sync includes less records than the first sync Verify that the updated metadata was picked up on the second sync PREREQUISITE For EACH stream that gets updates through events stream, there's at least 1 row of data """ conn_id = connections.ensure_connection(self) event_update_streams = { # "balance_transactions" # Cannot be directly updated "charges", "coupons", "customers", # "disputes", # Cannot create directly with api "invoice_items", # "invoice_line_items", # Can't be updated via api "invoices", # "payout_transactions", # See bug in create_test "payouts", "plans", "products", # "subscription_items", # BUG_9916 | https://jira.talendforge.org/browse/TDL-9916 "subscriptions", # "transfers", # Cannot be updated directly via api } found_catalogs = self.run_and_verify_check_mode(conn_id) our_catalogs = [catalog for catalog in found_catalogs if catalog.get('tap_stream_id') in event_update_streams] self.select_all_streams_and_fields( conn_id, our_catalogs, select_all_fields=True ) # Ensure each stream under test has data to start new_objects = { stream: create_object(stream) for stream in event_update_streams } # Some streams will be updated implicitly streams_to_update = event_update_streams.difference({ "invoice_line_items", "subscription_items", }) # Run a sync job using orchestrator first_sync_record_count = self.run_and_verify_sync(conn_id) # verify that the sync only sent records to the target for selected streams (catalogs) self.assertEqual(set(first_sync_record_count.keys()), event_update_streams) # Get the set of records from a first sync first_sync_records = runner.get_records_from_target_output() first_sync_created, _ = self.split_records_into_created_and_updated( first_sync_records ) updated = {} # holds id for updated objects in each stream for stream in streams_to_update: # There needs to be some test data for each stream, otherwise this will break self.assertGreater(len(first_sync_created[stream]["messages"]), 0, msg='We did not get any new records from ' 'the first sync for {}'.format(stream)) record = first_sync_created[stream]["messages"][0]["data"] # We need to make sure the data actually changes, otherwise no event update # will get created update_object(stream, record["id"]) updated[stream] = record["id"] # Run a second sync job using orchestrator second_sync_record_count = self.run_and_verify_sync(conn_id) # Get the set of records from a second sync second_sync_records = runner.get_records_from_target_output() _, second_sync_updated = self.split_records_into_created_and_updated( second_sync_records ) # # THIS MAKES AN ASSUMPTION THAT CHILD STREAMS DO NOT NEED TESTING. # # ADJUST IF NECESSARY for stream in event_update_streams.difference(self.child_streams()): with self.subTest(stream=stream): # verify that there is more than 1 record of data - setup necessary self.assertGreater( first_sync_record_count.get(stream, 0), 1, msg="Data isn't set up to be able to test event updates", ) # verify that you get at least one updated record on the second sync self.assertGreaterEqual( len(second_sync_updated.get(stream, {}).get("messages", [])), 1, msg="second syc didn't have updates", ) # verify that you get less data the 2nd time around since only updates # should be picked up self.assertLess( second_sync_record_count.get(stream, 0), first_sync_record_count.get(stream, 0), msg="second syc had the same or more records", ) # verify all the updated records in the 2nd sync are different from # the first run first_data = next( record["data"] for record in first_sync_created.get(stream, {}).get("messages", []) if record.get("data", {}).get("id") == updated[stream] ) second_data = next( record["data"] for record in second_sync_updated.get(stream, {}).get( "messages", [] ) if record.get("data", {}).get("id") == updated[stream] ) # verify the updated timestamp is greater in the second sync self.assertGreater( second_data["updated"], first_data["updated"], "updated timestamp for second sync is not greater than first sync", ) # verify the metadata[test] value actually changed self.assertNotEqual( second_data["metadata"].get("test_value", 0), first_data["metadata"].get("test_value", 0), "the test metadata should be different", ) if stream in new_objects: delete_object(stream, new_objects[stream]["id"])
def render_scene(args, num_objects=5, output_index=0, output_split='none', output_image='render.png', output_scene='render_json', output_blendfile=None, img_template='image%d.png'): bpy.ops.wm.open_mainfile(filepath=args.base_scene_blendfile) # Load materials utils.load_materials(args.material_dir) # node_path = '/home/bozidar/uni/prac/repos/clevr-dataset-gen/image_generation/data/NodeGroupMulti4.blend' node_path = '/home/bozidar/uni/prac/repos/clevr-dataset-gen/image_generation/data/NodeGroup.blend' with bpy.data.libraries.load(node_path) as (data_from, data_to): data_to.objects = data_from.objects data_to.materials = data_from.materials data_to.node_groups = data_from.node_groups node_mat = data_to.materials[0] node_group_elems = data_to.node_groups[0].nodes[ "ColorRamp"].color_ramp.elements # for i in segm_colors: # print(list(i.color)) # Set render arguments so we can get pixel coordinates later. # We use functionality specific to the CYCLES renderer so BLENDER_RENDER # cannot be used. render_args = bpy.context.scene.render render_args.engine = "CYCLES" render_args.filepath = output_image render_args.resolution_x = args.width render_args.resolution_y = args.height render_args.resolution_percentage = 100 render_args.tile_x = args.render_tile_size render_args.tile_y = args.render_tile_size if args.use_gpu == 1: # Blender changed the API for enabling CUDA at some point if bpy.app.version < (2, 78, 0): bpy.context.user_preferences.system.compute_device_type = 'CUDA' bpy.context.user_preferences.system.compute_device = 'CUDA_0' else: cycles_prefs = bpy.context.user_preferences.addons[ 'cycles'].preferences cycles_prefs.compute_device_type = 'CUDA' # Some CYCLES-specific stuff bpy.data.worlds['World'].cycles.sample_as_light = True bpy.context.scene.cycles.blur_glossy = 2.0 bpy.context.scene.cycles.samples = args.render_num_samples bpy.context.scene.cycles.transparent_min_bounces = args.render_min_bounces bpy.context.scene.cycles.transparent_max_bounces = args.render_max_bounces if args.use_gpu == 1: bpy.context.scene.cycles.device = 'GPU' # This will give ground-truth information about the scene and its objects scene_struct = { 'split': output_split, 'image_index': output_index, 'image_filename': os.path.basename(output_image), 'objects': [], 'directions': {}, } # Put a plane on the ground so we can compute cardinal directions if bpy.app.version < (2, 80, 0): bpy.ops.mesh.primitive_plane_add(radius=5) else: bpy.ops.mesh.primitive_plane_add(size=5) plane = bpy.context.object def rand(L): return 2.0 * L * (random.random() - 0.5) # Add random jitter to camera position if args.camera_jitter > 0: for i in range(3): bpy.data.objects['Camera'].location[i] += rand(args.camera_jitter) # Figure out the left, up, and behind directions along the plane and record # them in the scene structure camera = bpy.data.objects['Camera'] plane_normal = plane.data.vertices[0].normal if bpy.app.version < (2, 80, 0): cam_behind = camera.matrix_world.to_quaternion() * Vector((0, 0, -1)) cam_left = camera.matrix_world.to_quaternion() * Vector((-1, 0, 0)) cam_up = camera.matrix_world.to_quaternion() * Vector((0, 1, 0)) else: cam_behind = camera.matrix_world.to_quaternion() @ Vector((0, 0, -1)) cam_left = camera.matrix_world.to_quaternion() @ Vector((-1, 0, 0)) cam_up = camera.matrix_world.to_quaternion() @ Vector((0, 1, 0)) plane_behind = (cam_behind - cam_behind.project(plane_normal)).normalized() plane_left = (cam_left - cam_left.project(plane_normal)).normalized() plane_up = cam_up.project(plane_normal).normalized() # Delete the plane; we only used it for normals anyway. The base scene file # contains the actual ground plane. utils.delete_object(plane) # Save all six axis-aligned directions in the scene struct scene_struct['directions']['behind'] = tuple(plane_behind) scene_struct['directions']['front'] = tuple(-plane_behind) scene_struct['directions']['left'] = tuple(plane_left) scene_struct['directions']['right'] = tuple(-plane_left) scene_struct['directions']['above'] = tuple(plane_up) scene_struct['directions']['below'] = tuple(-plane_up) # Add random jitter to lamp positions if args.key_light_jitter > 0: for i in range(3): bpy.data.objects['Lamp_Key'].location[i] += rand( args.key_light_jitter) if args.back_light_jitter > 0: for i in range(3): bpy.data.objects['Lamp_Back'].location[i] += rand( args.back_light_jitter) if args.fill_light_jitter > 0: for i in range(3): bpy.data.objects['Lamp_Fill'].location[i] += rand( args.fill_light_jitter) # Now make some random objects objects, blender_objects = add_random_objects(scene_struct, num_objects, args, camera) # Segmentation materials and colors n = len(objects) node_mat.node_tree.nodes['Group'].inputs[1].default_value = n segm_mat = [] segm_color = [] for i in range(n + 1): node_mat.node_tree.nodes['Group'].inputs[0].default_value = i segm_mat.append(node_mat.copy()) segm_color.append(list(node_group_elems[i].color)) print(segm_mat) print(segm_color) angles = [-50, 90] steps = 5 for i, a in enumerate(np.linspace(*angles, steps)): # position = bpy.data.objects['Lamp_Key'].location # r = R.from_euler(axis, a, degrees=True).as_matrix() r = mathutils.Euler((0.0, math.radians(a), 0.0), 'XYZ') # r = mathutils.Euler((math.radians(30), math.radians(a), 0.0), 'XYZ') # bpy.data.objects['Lamp_Back'].location.rotate(r) # bpy.data.objects['Area'].location.rotate(r) bpy.data.objects['Area'].rotation_euler = r scene_struct['image_index'] = output_index * steps + i render_args.filepath = img_template % (output_index * steps + i) # bpy.data.objects['Sphere_0'].select = True # obj = bpy.context.selected_objects # for obj in bpy.context.selected_objects: # obj.select = False # bpy.context.scene.objects.active = None # bpy.context.scene.objects.active = bpy.data.objects['Ground'] print('---------------------------') print(objects) print('---------------------------') print(bpy.data.objects.items()) print('---------------------------') # exit() # Render the scene and dump the scene data structure scene_struct['objects'] = objects scene_struct['relationships'] = compute_all_relationships(scene_struct) while True: try: bpy.ops.render.render(write_still=True) break except Exception as e: print(e) with open(output_scene, 'w') as f: json.dump(scene_struct, f, indent=2) if output_blendfile is not None: print('===============================>', output_blendfile) bpy.ops.wm.save_as_mainfile(filepath=output_blendfile) # segm rendering s = render_args.filepath ind = s.rindex('.') render_args.filepath = s[:ind] + '_segm' + s[ind:] prev_mat = [] bpy.data.objects['Ground'].data.materials.clear() bpy.data.objects['Ground'].data.materials.append(segm_mat[0]) for i in range(n): prev_mat.append(bpy.data.objects[i - n].data.materials[0]) scene_name = bpy.data.objects[i - n].name index = -1 for obj in objects: if obj['scene_name'] == scene_name: index = obj['index'] obj['segm_color'] = segm_color[obj['index'] + 1] bpy.data.objects[i - n].data.materials.clear() bpy.data.objects[i - n].data.materials.append(segm_mat[index + 1]) while True: try: bpy.ops.render.render(write_still=True) break except Exception as e: print(e) bpy.data.objects['Ground'].data.materials.clear() for i in range(n): bpy.data.objects[i - n].data.materials.clear() bpy.data.objects[i - n].data.materials.append(prev_mat[i])
def render_scene(args, output_index=0, output_split='none', output_image='render.png', output_scene='render_json', output_blendfile=None, idx=-1): # Load the main blendfile bpy.ops.wm.open_mainfile(filepath=args.base_scene_blendfile) # Load materials utils.load_materials(args.material_dir) # Set render arguments so we can get pixel coordinates later. # We use functionality specific to the CYCLES renderer so BLENDER_RENDER # cannot be used. render_args = bpy.context.scene.render render_args.engine = "CYCLES" render_args.filepath = output_image render_args.resolution_x = args.width render_args.resolution_y = args.height render_args.resolution_percentage = 100 render_args.tile_x = args.render_tile_size render_args.tile_y = args.render_tile_size if args.use_gpu == 1: # Blender changed the API for enabling CUDA at some point if bpy.app.version < (2, 78, 0): bpy.context.user_preferences.system.compute_device_type = 'CUDA' bpy.context.user_preferences.system.compute_device = 'CUDA_0' else: cycles_prefs = bpy.context.user_preferences.addons[ 'cycles'].preferences cycles_prefs.compute_device_type = 'CUDA' # Some CYCLES-specific stuff bpy.data.worlds['World'].cycles.sample_as_light = True bpy.context.scene.cycles.blur_glossy = 2.0 bpy.context.scene.cycles.samples = args.render_num_samples bpy.context.scene.cycles.transparent_min_bounces = args.render_min_bounces bpy.context.scene.cycles.transparent_max_bounces = args.render_max_bounces if args.use_gpu == 1: bpy.context.scene.cycles.device = 'GPU' # This will give ground-truth information about the scene and its objects scene_struct = { 'split': output_split, 'image_index': output_index, 'image_filename': os.path.basename(output_image), 'objects': [], 'directions': {}, } # Put a plane on the ground so we can compute cardinal directions bpy.ops.mesh.primitive_plane_add(radius=5) plane = bpy.context.object def rand(L): return 2.0 * L * (random.random() - 0.5) # Add random jitter to camera position if args.camera_jitter > 0: for i in range(3): bpy.data.objects['Camera'].location[i] += rand(args.camera_jitter) # Figure out the left, up, and behind directions along the plane and record # them in the scene structure camera = bpy.data.objects['Camera'] plane_normal = plane.data.vertices[0].normal cam_behind = camera.matrix_world.to_quaternion() * Vector((0, 0, -1)) cam_left = camera.matrix_world.to_quaternion() * Vector((-1, 0, 0)) cam_up = camera.matrix_world.to_quaternion() * Vector((0, 1, 0)) plane_behind = (cam_behind - cam_behind.project(plane_normal)).normalized() plane_left = (cam_left - cam_left.project(plane_normal)).normalized() plane_up = cam_up.project(plane_normal).normalized() # Delete the plane; we only used it for normals anyway. The base scene file # contains the actual ground plane. utils.delete_object(plane) # Save all six axis-aligned directions in the scene struct scene_struct['directions']['behind'] = tuple(plane_behind) scene_struct['directions']['front'] = tuple(-plane_behind) scene_struct['directions']['left'] = tuple(plane_left) scene_struct['directions']['right'] = tuple(-plane_left) scene_struct['directions']['above'] = tuple(plane_up) scene_struct['directions']['below'] = tuple(-plane_up) # Add random jitter to lamp positions if args.key_light_jitter > 0: for i in range(3): bpy.data.objects['Lamp_Key'].location[i] += rand( args.key_light_jitter) if args.back_light_jitter > 0: for i in range(3): bpy.data.objects['Lamp_Back'].location[i] += rand( args.back_light_jitter) if args.fill_light_jitter > 0: for i in range(3): bpy.data.objects['Lamp_Fill'].location[i] += rand( args.fill_light_jitter) # Now make some random objects objects, blender_objects = add_random_objects(scene_struct, args, camera, idx) for i in range(len(objects)): objects[i]['idx'] = i + 1 ### get b_box box_dict = get_b_box.main(bpy.context, blender_objects) def build_rendermask_graph(num_obj): # switch on nodes bpy.context.scene.use_nodes = True tree = bpy.context.scene.node_tree links = tree.links # clear default nodes for n in tree.nodes: tree.nodes.remove(n) # create input render layer node rl = tree.nodes.new('CompositorNodeRLayers') rl.location = 185, 285 scene = bpy.context.scene nodes = scene.node_tree.nodes render_layers = nodes['Render Layers'] ofile_nodes = [ nodes.new("CompositorNodeOutputFile") for _ in range(num_obj) ] for _i, of_node in enumerate(ofile_nodes): of_node.base_path = "./tmp_graph_output/indexob{}_{}".format( _i, idx) idmask_list = [ nodes.new("CompositorNodeIDMask") for _ in range(num_obj) ] for _i, o_node in enumerate(idmask_list): o_node.index = _i + 1 bpy.data.scenes['Scene'].render.layers[ 'RenderLayer'].use_pass_object_index = True for _i in range(num_obj): scene.node_tree.links.new(render_layers.outputs['IndexOB'], idmask_list[_i].inputs[0]) scene.node_tree.links.new(idmask_list[_i].outputs[0], ofile_nodes[_i].inputs['Image']) def get_diff_obj_points(): obj_index = dict() index = 0 for obj in blender_objects: index += 1 obj.pass_index = index obj_index[obj.name] = index return index index = get_diff_obj_points() build_rendermask_graph(index) # Render the scene and dump the scene data structure scene_struct['objects'] = objects scene_struct['relationships'] = compute_all_relationships(scene_struct) while True: try: bpy.ops.render.render(write_still=True) break except Exception as e: print(e) #save_as_json cmd = ['python', './restore_img2json.py', str(index), str(idx)] res = subprocess.Popen(cmd, stdout=subprocess.PIPE) res.wait() print('res: ', res.returncode) if res.returncode != 0: print(" os.wait:exit status != 0\n") result = res.stdout.read() print("after read: {}".format(result)) raise Exception('error in img2json') obj_mask = json.load(open('/tmp/obj_mask_{}.json'.format(idx))) _path = '/tmp/obj_mask_{}.json'.format(idx) os.system('rm ' + _path) scene_struct['obj_mask'] = obj_mask scene_struct['obj_bbox'] = box_dict with open(output_scene, 'w') as f: json.dump(scene_struct, f, indent=2) if output_blendfile is not None: bpy.ops.wm.save_as_mainfile(filepath=output_blendfile)
def add_random_objects(scene_struct, num_objects, args, camera, gen_list): """ Add random objects to the current blender scene """ # Load the property file with open(args.properties_json, 'r') as f: properties = json.load(f) color_name_to_rgba = {} for name, rgb in properties['colors'].items(): rgba = [float(c) / 255.0 for c in rgb] + [1.0] color_name_to_rgba[name] = rgba material_mapping = [(v, k) for k, v in properties['materials'].items()] object_mapping = [(v, k) for k, v in properties['shapes'].items()] size_mapping = list(properties['sizes'].items()) shape_color_combos = None if args.shape_color_combos_json is not None: with open(args.shape_color_combos_json, 'r') as f: shape_color_combos = list(json.load(f).items()) positions = [] objects = [] blender_objects = [] assert num_objects == 1, "Only Generate Single" gen_config = gen_list.split('.') gen_config = [k.split('_') for k in gen_config] for i in range(num_objects): # Choose a random size size_name, r = random.choice(size_mapping) # Try to place the object, ensuring that we don't intersect any existing # objects and that we are more than the desired margin away from all existing # objects along all cardinal directions. num_tries = 0 while True: # If we try and fail to place an object too many times, then delete all # the objects in the scene and start over. num_tries += 1 if num_tries > args.max_retries: for obj in blender_objects: utils.delete_object(obj) return add_random_objects(scene_struct, num_objects, args, camera, gen_list) # if i == 0: # x = random.uniform(-2.5, -0.3) # else: # x = random.uniform(0.3, 2.5) x = random.uniform(-1.5, 1.5) # x = random.uniform(-3, 3) y = x #random.uniform(-0.2, 0.2)#random.uniform(-3, 3) rn = random.uniform(0.5 * (np.abs(x) - 0.3) - 2.1, 0.1) y += rn x -= rn # Check to make sure the new object is further than min_dist from all # other objects, and further than margin along the four cardinal directions dists_good = True margins_good = True for (xx, yy, rr) in positions: dx, dy = x - xx, y - yy dist = math.sqrt(dx * dx + dy * dy) if dist - r - rr < args.min_dist: dists_good = False break for direction_name in ['left', 'right', 'front', 'behind']: direction_vec = scene_struct['directions'][direction_name] assert direction_vec[2] == 0 margin = dx * direction_vec[0] + dy * direction_vec[1] if 0 < margin < args.margin: print(margin, args.margin, direction_name) print('BROKEN MARGIN!') margins_good = False break if not margins_good: break if dists_good and margins_good: break # Choose random color and shape if shape_color_combos is None: obj_name, obj_name_out = random.choice(object_mapping) color_name, rgba = random.choice(list(color_name_to_rgba.items())) else: obj_name_out, color_choices = random.choice(shape_color_combos) color_name = random.choice(color_choices) obj_name = [k for k, v in object_mapping if v == obj_name_out][0] rgba = color_name_to_rgba[color_name] # print (obj_name, obj_name_out, color_name, rgba) # abc color_name = gen_config[i][0] obj_name = properties['shapes'][gen_config[i][1]] obj_name_out = gen_config[i][1] rgba = color_name_to_rgba[color_name] print(color_name, obj_name) # abc # For cube, adjust the size a bit if obj_name == 'cube': assert False r /= math.sqrt(2) # Choose random orientation for the object. theta = 45. #360.0 * random.random() if obj_name == 'Trunk': theta = 134. # Actually add the object to the scene utils.add_object(args.shape_dir, obj_name, r, (x, y), theta=theta) obj = bpy.context.object blender_objects.append(obj) positions.append((x, y, r)) # Attach a random material mat_name, mat_name_out = random.choice(material_mapping) utils.add_material(mat_name, Color=rgba) # Record data about the object in the scene data structure pixel_coords = utils.get_camera_coords(camera, obj.location) objects.append({ 'shape': obj_name_out, 'size': size_name, 'material': mat_name_out, '3d_coords': tuple(obj.location), 'rotation': theta, 'pixel_coords': pixel_coords, 'color': color_name, }) # Check that all objects are at least partially visible in the rendered image all_visible = check_visibility(blender_objects, args.min_pixels_per_object) if not all_visible: # If any of the objects are fully occluded then start over; delete all # objects from the scene and place them all again. print('Some objects are occluded; replacing objects') for obj in blender_objects: utils.delete_object(obj) return add_random_objects(scene_struct, num_objects, args, camera, gen_list) return objects, blender_objects
def add_random_objects(scene_struct, num_objects, args, camera): """ Add random objects to the current blender scene """ # Load the property file with open(args.properties_json, 'r') as f: properties = json.load(f) color_name_to_rgba = {} for name, rgb in properties['colors'].items(): rgba = [float(c) / 255.0 for c in rgb] + [1.0] color_name_to_rgba[name] = rgba material_mapping = [(v, k) for k, v in properties['materials'].items()] object_mapping = [(v, k) for k, v in properties['shapes'].items()] size_mapping = list(properties['sizes'].items()) shape_color_combos = None if args.shape_color_combos_json is not None: with open(args.shape_color_combos_json, 'r') as f: shape_color_combos = list(json.load(f).items()) positions = [] objects = [] blender_objects = [] if balanced_num_shapes_flag: chosen_objects = [ object_mapping[j] for j in range(NUM_SHAPES) for _ in range(num_objects[j]) ] range_num = sum(num_objects) else: range_num = num_objects for i in range(range_num): # Choose a random size size_name, r = random.choice(size_mapping) # Try to place the object, ensuring that we don't intersect any existing # objects and that we are more than the desired margin away from all existing # objects along all cardinal directions. num_tries = 0 while True: # If we try and fail to place an object too many times, then delete all # the objects in the scene and start over. num_tries += 1 if num_tries > args.max_retries: for obj in blender_objects: utils.delete_object(obj) return add_random_objects(scene_struct, num_objects, args, camera) x = random.uniform(-3, 3) y = random.uniform(-3, 3) # Check to make sure the new object is further than min_dist from all # other objects, and further than margin along the four cardinal directions dists_good = True margins_good = True for (xx, yy, rr) in positions: dx, dy = x - xx, y - yy dist = math.sqrt(dx * dx + dy * dy) if dist - r - rr < args.min_dist: dists_good = False break for direction_name in ['left', 'right', 'front', 'behind']: direction_vec = scene_struct['directions'][direction_name] assert direction_vec[2] == 0 margin = dx * direction_vec[0] + dy * direction_vec[1] if 0 < margin < args.margin: print(margin, args.margin, direction_name) print('BROKEN MARGIN!') margins_good = False break if not margins_good: break if dists_good and margins_good: break # Choose random color and shape if shape_color_combos is None: # Need to change this line to just choose one of the pre-chosen shapes. # obj_name, obj_name_out = random.choice(object_mapping) # Here, obj_name_out is "cube", "sphere", or "cylinder" if balanced_num_shapes_flag: obj_name, obj_name_out = chosen_objects[i] else: obj_name, obj_name_out = random.choice(object_mapping) color_name, rgba = random.choice(list(color_name_to_rgba.items())) else: obj_name_out, color_choices = random.choice(shape_color_combos) color_name = random.choice(color_choices) obj_name = [k for k, v in object_mapping if v == obj_name_out][0] rgba = color_name_to_rgba[color_name] # Get a random material mat_name, mat_name_out = random.choice(material_mapping) # Here, check if any of the chosen properties are disallowed. # If so, then keep randomly selecting again until no pair is disallowed. # Unfortunately, this will remove any guarantees about the distribution of labels. while obj_has_conflict(size_name, obj_name_out, mat_name_out, color_name): size_name, r = random.choice(size_mapping) obj_name, obj_name_out = random.choice(object_mapping) mat_name, mat_name_out = random.choice(material_mapping) color_name, rgba = random.choice(list(color_name_to_rgba.items())) # For cube, adjust the size a bit if obj_name == 'Cube': r /= math.sqrt(2) # Choose random orientation for the object. theta = 360.0 * random.random() # Actually add the object to the scene utils.add_object(args.shape_dir, obj_name, r, (x, y), theta=theta) obj = bpy.context.object blender_objects.append(obj) positions.append((x, y, r)) # Attach the chosen material and color. utils.add_material(mat_name, Color=rgba) # Record data about the object in the scene data structure pixel_coords = utils.get_camera_coords(camera, obj.location) objects.append({ 'shape': obj_name_out, 'size': size_name, 'material': mat_name_out, '3d_coords': tuple(obj.location), 'rotation': theta, 'pixel_coords': pixel_coords, 'color': color_name, }) # Check that all objects are at least partially visible in the rendered image all_visible = check_visibility(blender_objects, args.min_pixels_per_object) if not all_visible: # If any of the objects are fully occluded then start over; delete all # objects from the scene and place them all again. print('Some objects are occluded; replacing objects') for obj in blender_objects: utils.delete_object(obj) return add_random_objects(scene_struct, num_objects, args, camera) return objects, blender_objects
def add_random_objects(scene_struct, num_objects, args, camera, attempts=0): """ Add random objects to the current blender scene """ if attempts > 10: print ("Tried 10 times to place {} objects and failed. Giving up hope and moving on.".format(num_objects)) return None, None # Load the property file with open(args.properties_json, 'r') as f: properties = json.load(f) color_name_to_rgba = {} for name, rgb in properties['colors'].items(): rgba = [float(c) / 255.0 for c in rgb] + [1.0] color_name_to_rgba[name] = rgba material_mapping = [(v, k) for k, v in properties['materials'].items()] object_mapping = [(v, k) for k, v in properties['shapes'].items()] size_mapping = list(properties['sizes'].items()) num_objects = [["duck",args.num_ducks],["sphere",args.num_balls]] objects_to_place = [] for obj_name, num in num_objects: for i in range(num): objects_to_place.append(obj_name) shape_color_combos = None if args.shape_color_combos_json is not None: with open(args.shape_color_combos_json, 'r') as f: shape_color_combos = list(json.load(f).items()) positions = [] objects = [] blender_objects = [] x_range = [-2.5,2.5] y_range = [-2.5,2.5] corners = [[x_range[0], y_range[0]], [x_range[0], y_range[1]], [x_range[1], y_range[0]], [x_range[1], y_range[1]],] i=-1 while len(objects_to_place) > 0: i+=1 #for i in range(num_objects): # Choose a random size size_name, r = random.choice(size_mapping) # Try to place the object, ensuring that we don't intersect any existing # objects and that we are more than the desired margin away from all existing # objects along all cardinal directions. num_tries = 0 while True: # If we try and fail to place an object too many times, then delete all # the objects in the scene and start over. num_tries += 1 if num_tries > args.max_retries: for obj in blender_objects: utils.delete_object(obj) return add_random_objects(scene_struct, num_objects, args, camera, attempts=attempts+1) #x = corners[i][0] #y = corners[i][1] #print (x, y, "POSITION") x = random.uniform(*x_range) y = random.uniform(*y_range) # Check to make sure the new object is further than min_dist from all # other objects, and further than margin along the four cardinal directions dists_good = True margins_good = True for (xx, yy, rr) in positions: dx, dy = x - xx, y - yy dist = math.sqrt(dx * dx + dy * dy) if dist - r - rr < args.min_dist: dists_good = False break for direction_name in ['left', 'right', 'front', 'behind']: direction_vec = scene_struct['directions'][direction_name] assert direction_vec[2] == 0 margin = dx * direction_vec[0] + dy * direction_vec[1] if 0 < margin < args.margin: print(margin, args.margin, direction_name) print('BROKEN MARGIN!') margins_good = False break if not margins_good: break if dists_good and margins_good: break # Choose random color and shape if shape_color_combos is None: obj_name_out = objects_to_place.pop() #obj_name = object_mapping[obj_name_out] obj_name = properties["shapes"][obj_name_out] #obj_name, obj_name_out = random.choice(object_mapping) color_name, rgba = random.choice(list(color_name_to_rgba.items())) else: obj_name_out, color_choices = random.choice(shape_color_combos) color_name = random.choice(color_choices) obj_name = [k for k, v in object_mapping if v == obj_name_out][0] rgba = color_name_to_rgba[color_name] r *= args.width / 256. / 1.2 zshift=0.0 # For cube, adjust the size a bit if obj_name == 'Cube': r /= math.sqrt(2) if obj_name=="Sphere": zshift = -0.25*r if obj_name == 'Rubber Duck': r /= math.sqrt(2) zshift=-1.15 # Choose random orientation for the object. theta = 360.0 * random.random() # Actually add the object to the scene utils.add_object(args.shape_dir, obj_name, r, (x, y), theta=theta, zshift=zshift) obj = bpy.context.object blender_objects.append(obj) positions.append((x, y, r)) # Attach a random material if obj_name != 'Rubber Duck': mat_name, mat_name_out = random.choice(material_mapping) utils.add_material(mat_name, Color=rgba) # Record data about the object in the scene data structure pixel_coords = utils.get_camera_coords(camera, obj.location) objects.append({ 'shape': obj_name_out, 'size': size_name, #'material': mat_name_out, '3d_coords': tuple(obj.location), 'rotation': theta, 'pixel_coords': pixel_coords, 'color': color_name, }) # Check that all objects are at least partially visible in the rendered image all_visible = check_visibility(blender_objects, args.min_pixels_per_object*(args.width/256)**2) if not all_visible: # If any of the objects are fully occluded then start over; delete all # objects from the scene and place them all again. print('Some objects are occluded; replacing objects') for obj in blender_objects: utils.delete_object(obj) return add_random_objects(scene_struct, num_objects, args, camera, attempts=attempts+1) return objects, blender_objects
def add_random_objects(scene_struct, num_objects, args, camera): """ Add random objects to the current blender scene """ # Load the property file with open(args.properties_json, 'r') as f: properties = json.load(f) color_name_to_rgba = {} for name, rgb in properties['colors'].items(): rgba = [float(c) / 255.0 for c in rgb] + [1.0] color_name_to_rgba[name] = rgba material_mapping = [(v, k) for k, v in properties['materials'].items()] object_mapping = [(v, k) for k, v in properties['shapes'].items()] size_mapping = list(properties['sizes'].items()) shape_color_combos = None if args.shape_color_combos_json is not None: with open(args.shape_color_combos_json, 'r') as f: shape_color_combos = list(json.load(f).items()) positions = [] objects = [] blender_objects = [] for i in range(num_objects): # Choose a random size size_name, r = random.choice(size_mapping) # Try to place the object, ensuring that we don't intersect any existing # objects and that we are more than the desired margin away from all existing # objects along all cardinal directions. num_tries = 0 while True: # If we try and fail to place an object too many times, then delete all # the objects in the scene and start over. num_tries += 1 if num_tries > args.max_retries: for obj in blender_objects: utils.delete_object(obj) return add_random_objects(scene_struct, num_objects, args, camera) x = random.uniform(-2.5, 2.5) y = random.uniform(-2.5, 2.5) # Check to make sure the new object is further than min_dist from all # other objects, and further than margin along the four cardinal directions dists_good = True margins_good = True for (xx, yy, rr) in positions: dx, dy = x - xx, y - yy dist = math.sqrt(dx * dx + dy * dy) if dist <= 0.5 and random.random() <= 0.5: x = xx y = yy dx, dy = x - xx, y - yy dist = math.sqrt(dx * dx + dy * dy) if dist >= 0.1 and dist - r - rr < args.min_dist: dists_good = False break for direction_name in [ 'left', 'right', 'front', 'behind', 'above', 'below' ]: direction_vec = scene_struct['directions'][direction_name] # assert direction_vec[2] == 0 margin = dx * direction_vec[0] + dy * direction_vec[1] if dist >= 0.1 and 0 < margin < args.margin: print(dist, margin, args.margin, direction_name) print('BROKEN MARGIN!') margins_good = False break if not margins_good: break num, z = height(objects, (x, y)) if dists_good and margins_good and num <= 2: break # Choose random color and shape if shape_color_combos is None: obj_name, obj_name_out = random.choice(object_mapping) color_name, rgba = random.choice(list(color_name_to_rgba.items())) else: obj_name_out, color_choices = random.choice(shape_color_combos) color_name = random.choice(color_choices) obj_name = [k for k, v in object_mapping if v == obj_name_out][0] rgba = color_name_to_rgba[color_name] # For cube, adjust the size a bit if obj_name == 'Cube': r /= math.sqrt(2) # Choose random orientation for the object. theta = 360.0 * random.random() # Actually add the object to the scene utils.add_object(args.shape_dir, obj_name, r, (x, y, z + r), theta=theta) obj = bpy.context.object blender_objects.append(obj) positions.append((x, y, z + r)) # Attach a random material mat_name, mat_name_out = random.choice(material_mapping) utils.add_material(mat_name, Color=rgba) # Record data about the object in the scene data structure pixel_coords = utils.get_camera_coords(camera, obj.location) import numpy as np bobj = bpy.context.object loc = np.array(bobj.location) dim = np.array(bobj.dimensions) half = dim / 2 corners = [] corners.append(loc + half * [1, 1, 1]) corners.append(loc + half * [1, 1, -1]) corners.append(loc + half * [1, -1, 1]) corners.append(loc + half * [1, -1, -1]) corners.append(loc + half * [-1, 1, 1]) corners.append(loc + half * [-1, 1, -1]) corners.append(loc + half * [-1, -1, 1]) corners.append(loc + half * [-1, -1, -1]) import mathutils corners_camera_coords = np.array([ utils.get_camera_coords(camera, mathutils.Vector(tuple(corner))) for corner in corners ]) xmax = np.amax(corners_camera_coords[:, 0]) ymax = np.amax(corners_camera_coords[:, 1]) xmin = np.amin(corners_camera_coords[:, 0]) ymin = np.amin(corners_camera_coords[:, 1]) objects.append({ 'shape': obj_name_out, 'r': r, 'size': size_name, 'material': mat_name_out, '3d_coords': tuple(obj.location), 'rotation': theta, 'pixel_coords': pixel_coords, 'color': color_name, 'xmin': xmin, 'ymin': ymin, 'xmax': xmax, 'ymax': ymax }) # Check that all objects are at least partially visible in the rendered image all_visible = check_visibility(blender_objects, args.min_pixels_per_object) if not all_visible: # If any of the objects are fully occluded then start over; delete all # objects from the scene and place them all again. print('Some objects are occluded; replacing objects') for obj in blender_objects: utils.delete_object(obj) return add_random_objects(scene_struct, num_objects, args, camera) for obj in objects: print(obj['shape'], obj['color']) return objects, blender_objects
def render_scene( args, num_objects=5, output_index=0, output_split='none', output_image_dir='../output/images/', output_image='render.png', output_scene='render.json', output_blendfile=None, ): # Load the main blendfile bpy.ops.wm.open_mainfile(filepath=args.base_scene_blendfile) # Load materials utils.load_materials(args.material_dir) # Set render arguments so we can get pixel coordinates later. # We use functionality specific to the CYCLES renderer so BLENDER_RENDER # cannot be used. render_args = bpy.context.scene.render render_args.engine = "CYCLES" render_args.filepath = output_image render_args.resolution_x = args.width render_args.resolution_y = args.height render_args.resolution_percentage = 100 render_args.tile_x = args.render_tile_size render_args.tile_y = args.render_tile_size if args.use_gpu == 1: # Blender changed the API for enabling CUDA at some point print(bpy.app.version) if bpy.app.version < (2, 78, 0): bpy.context.user_preferences.system.compute_device_type = 'CUDA' bpy.context.user_preferences.system.compute_device = 'CUDA_0' else: print(bpy.context.preferences.addons['cycles']) cycles_prefs = bpy.context.preferences.addons['cycles'].preferences cuda_devices, opencl_devices = cycles_prefs.get_devices() cycles_prefs.compute_device_type = 'CUDA' # Some CYCLES-specific stuff bpy.data.worlds['World'].cycles.sample_as_light = True bpy.context.scene.cycles.blur_glossy = 2.0 bpy.context.scene.cycles.samples = args.render_num_samples bpy.context.scene.cycles.transparent_min_bounces = args.render_min_bounces bpy.context.scene.cycles.transparent_max_bounces = args.render_max_bounces if args.use_gpu == 1: bpy.context.scene.cycles.device = 'GPU' # This will give ground-truth information about the scene and its objects scene_struct = { 'split': output_split, 'image_index': output_index, 'image_filename': os.path.basename(output_image), 'objects': [], 'directions': {}, } # Put a plane on the ground so we can compute cardinal directions if bpy.app.version <= (2, 79, 0): bpy.ops.mesh.primitive_plane_add(radius=5) else: bpy.ops.mesh.primitive_plane_add(size=5) plane = bpy.context.object def rand(L): return 2.0 * L * (random.random() - 0.5) # Add random jitter to camera position # if args.camera_jitter > 0: # for i in range(3): # bpy.data.objects['Camera'].location[i] += rand(args.camera_jitter) # Figure out the left, up, and behind directions along the plane and record # them in the scene structure camera = bpy.data.objects['Camera'] print('Camera location', camera.location) print('Camera matrix world', camera.matrix_world) plane_normal = plane.data.vertices[0].normal if bpy.app.version <= (2, 79, 0): cam_behind = camera.matrix_world.to_quaternion() * Vector((0, 0, -1)) cam_left = camera.matrix_world.to_quaternion() * Vector((-1, 0, 0)) cam_up = camera.matrix_world.to_quaternion() * Vector((0, 1, 0)) else: cam_behind = camera.matrix_world.to_quaternion() @ Vector((0, 0, -1)) cam_left = camera.matrix_world.to_quaternion() @ Vector((-1, 0, 0)) cam_up = camera.matrix_world.to_quaternion() @ Vector((0, 1, 0)) # cam_behind = Vector((0, 0, 0)) # cam_behind[0] = - camera.matrix_world[0][2] # cam_behind[1] = - camera.matrix_world[1][2] # cam_behind[2] = - camera.matrix_world[2][2] # cam_left = Vector((0, 0, 0)) # cam_left[0] = - camera.matrix_world[0][0] # cam_left[1] = - camera.matrix_world[1][0] # cam_left[2] = - camera.matrix_world[2][0] # cam_up = Vector((0, 0, 0)) # cam_up[0] = camera.matrix_world[0][1] # cam_up[1] = camera.matrix_world[1][1] # cam_up[2] = camera.matrix_world[2][1] plane_behind = (cam_behind - cam_behind.project(plane_normal)).normalized() plane_left = (cam_left - cam_left.project(plane_normal)).normalized() plane_up = cam_up.project(plane_normal).normalized() # Delete the plane; we only used it for normals anyway. The base scene file # contains the actual ground plane. utils.delete_object(plane) # Save all six axis-aligned directions in the scene struct scene_struct['directions']['behind'] = tuple(plane_behind) scene_struct['directions']['front'] = tuple(-plane_behind) scene_struct['directions']['left'] = tuple(plane_left) scene_struct['directions']['right'] = tuple(-plane_left) scene_struct['directions']['above'] = tuple(plane_up) scene_struct['directions']['below'] = tuple(-plane_up) # Add random jitter to lamp positions if args.key_light_jitter > 0: for i in range(3): bpy.data.objects['Lamp_Key'].location[i] += rand( args.key_light_jitter) if args.back_light_jitter > 0: for i in range(3): bpy.data.objects['Lamp_Back'].location[i] += rand( args.back_light_jitter) if args.fill_light_jitter > 0: for i in range(3): bpy.data.objects['Lamp_Fill'].location[i] += rand( args.fill_light_jitter) # Now make some random objects objects, blender_objects = add_random_objects(scene_struct, num_objects, args, camera) # # Choose pose to render from # centers = [obj['3d_coords'] for obj in objects] # objects_centroid = np.mean(np.array(centers), axis=0) poses = utils.sample_poses(args.imgs_per_scene, 10) # Check visibility here and if one object not visible in either view then sample 2 new poses # for i in range(args.imgs_per_scene): # for j in range(4): # for k in range(4): # bpy.data.objects['Camera'].matrix_world[j][k] = poses[i][j, k] # all_visible = check_visibility(blender_objects, args.min_pixels_per_object) # print('all visible', all_visible) # break # Render object masks # print(bpy.context.scene.view_layers.values()) bpy.context.scene.use_nodes = True bpy.context.scene.view_layers["RenderLayer"].use_pass_object_index = True for i, obj in enumerate(bpy.context.scene.objects): obj.pass_index = i # bpy.ops.node.add_node(type="CompositorNodeOutputFile", use_transform=True) # bpy.data.scenes["Scene"].node_tree.nodes["File Output.00{}".format(i+1)].base_path = output_masks_dir print(bpy.context.object.pass_index) # Render the scene and dump the scene data structure for i in range(args.imgs_per_scene): render_args.filepath = output_image_dir + 's{}v{}.png'.format( output_index, i) for j in range(4): for k in range(4): bpy.data.objects['Camera'].matrix_world[j][k] = poses[i][j, k] while True: try: bpy.ops.render.render(write_still=True) break except Exception as e: print(e) if output_blendfile is not None: bpy.ops.wm.save_as_mainfile(filepath=output_blendfile) scene_struct['objects'] = objects scene_struct['relationships'] = compute_all_relationships(scene_struct) scene_struct['poses'] = [pose.tolist() for pose in poses] with open(output_scene, 'w') as f: json.dump(scene_struct, f, indent=2)
os.environ['AWS_SHARED_CREDENTIALS_FILE'] = p.credential_name os.environ['AWS_PROFILE'] = p.credential_name os.environ['AWS_DEFAULT_REGION'] = p.location s3 = boto3.resource('s3') try: s3.create_bucket(Bucket=p.data_bucket, CreateBucketConfiguration={'LocationConstraint': p.location}) except ClientError: print("Data Bucket Already Created") u.upload_object(p.data_bucket, p.template_name, p.template_name) u.upload_zip_object(p.data_bucket, 'lambda_function.py', 'lambda_function.zip', 'lambda_function.zip') client = boto3.client('cloudformation') status = u.stack_status(p.stack_name) if status == 'ROLLBACK_COMPLETE' or status == 'ROLLBACK_FAILED' or status == 'UPDATE_ROLLBACK_COMPLETE' or status == \ 'DELETE_FAILED': u.delete_object(p.names["source_bucket"]) u.delete_object(p.names["dest_bucket"]) client.delete_stack(StackName=p.stack_name) while u.stack_status('stack') == 'DELETE_IN_PROGRESS': time.sleep(1) print("stack deleted") u.create_stack(p.stack_name, p.names["template_url"], p.names["source_bucket"], p.names["dest_bucket"]) print("stack created") elif status == 'CREATE_COMPLETE' or status == 'UPDATE_COMPLETE' : u.update_stack(p.stack_name, p.names["template_url"], p.names["source_bucket"], p.names["dest_bucket"]) print("stack updated") else: u.create_stack(p.stack_name, p.names["template_url"], p.names["source_bucket"], p.names["dest_bucket"]) print("stack created")
def do_test(self, conn_id): """Test we get a lot of data back based on the start date configured in base""" # Select all streams and all fields within streams found_catalogs = menagerie.get_catalogs(conn_id) incremental_streams = { key for key, value in self.expected_replication_method().items() if value == self.INCREMENTAL } # IF THERE ARE STREAMS THAT SHOULD NOT BE TESTED # REPLACE THE EMPTY SET BELOW WITH THOSE STREAMS untested_streams = self.child_streams().union( {'disputes', 'events', 'transfers', 'payout_transactions'}) our_catalogs = get_catalogs( conn_id, incremental_streams.difference(untested_streams)) self.select_all_streams_and_fields(conn_id, our_catalogs, select_all_fields=True) # Create a record for each stream under test prior to the first sync new_objects = { stream: create_object(stream) for stream in incremental_streams.difference(untested_streams) } # Run a sync job using orchestrator first_sync_record_count = self.run_sync(conn_id) first_total_records = reduce(lambda a, b: a + b, first_sync_record_count.values()) # Count actual rows synced first_sync_records = runner.get_records_from_target_output() # set the start date for a new connection based off bookmarks largest value first_max_bookmarks = self.max_bookmarks_by_stream(first_sync_records) bookmark_list = [ next(iter(book.values())) for stream, book in first_max_bookmarks.items() ] bookmark_dates = [] for bookmark in bookmark_list: try: bookmark_dates.append(parse(bookmark)) except (ValueError, OverflowError, TypeError): pass if not bookmark_dates: # THERE WERE NO BOOKMARKS THAT ARE DATES. # REMOVE CODE TO FIND A START DATE AND ENTER ONE MANUALLY raise ValueError # largest_bookmark = reduce(lambda a, b: a if a > b else b, bookmark_dates) # self.start_date = self.local_to_utc(largest_bookmark).strftime(self.START_DATE_FORMAT) self.start_date = dt.strftime(dt.today() - timedelta(days=1), self.START_DATE_FORMAT) # create a new connection with the new start_date conn_id = self.create_connection(original_properties=False) # Select all streams and all fields within streams found_catalogs = menagerie.get_catalogs(conn_id) our_catalogs = [ catalog for catalog in found_catalogs if catalog.get('tap_stream_id') in incremental_streams.difference( untested_streams) ] self.select_all_streams_and_fields(conn_id, our_catalogs, select_all_fields=True) # TODO remove the updates, this is unnecessary. Verify with Harvest # Update a record for each stream under test prior to the 2nd sync first_sync_created, _ = self.split_records_into_created_and_updated( first_sync_records) updated = {} # holds id for updated objects in each stream for stream in new_objects: # There needs to be some test data for each stream, otherwise this will break record = first_sync_created[stream]["messages"][0]["data"] update_object(stream, record["id"]) updated[stream] = record["id"] # Run a sync job using orchestrator second_sync_record_count = self.run_sync(conn_id) # tap-stripe uses events for updates, so these need filtered to validate bookmark second_sync_records = runner.get_records_from_target_output() second_sync_created, second_sync_updated = self.split_records_into_created_and_updated( second_sync_records) second_total_records = reduce(lambda a, b: a + b, second_sync_record_count.values(), 0) # Only examine bookmarks for "created" objects, not updates second_min_bookmarks = self.min_bookmarks_by_stream( second_sync_created) # verify that at least one record synced and less records synced than the 1st connection self.assertGreater(second_total_records, 0) self.assertLess(first_total_records, second_total_records) # validate that all newly created records are greater than the start_date for stream in incremental_streams.difference(untested_streams): with self.subTest(stream=stream): # verify that each stream has less records in the first sync than the second self.assertGreater( second_sync_record_count.get(stream, 0), first_sync_record_count.get(stream, 0), msg="first had more records, start_date usage not verified" ) # verify all data from 2nd sync >= start_date target_mark = second_min_bookmarks.get(stream, {"mark": None}) target_value = next(iter( target_mark.values())) # there should be only one if target_value: # it's okay if there isn't target data for a stream try: target_value = self.local_to_utc(parse(target_value)) expected_value = self.local_to_utc( parse(self.start_date)) # verify that the minimum bookmark sent to the target for the second sync # is greater than or equal to the start date self.assertGreaterEqual(target_value, expected_value) except (OverflowError, ValueError, TypeError): print("bookmarks cannot be converted to dates, " "can't test start_date for {}".format(stream)) if stream in updated: delete_object(stream, updated[stream])
def render_scene(args, num_objects=5, output_index=0, output_split='none', output_image='render.png', output_scene='render_json', output_masks=None, output_blendfile=None, ): # Load the main blendfile bpy.ops.wm.open_mainfile(filepath=args.base_scene_blendfile) # Load materials utils.load_materials(args.material_dir) # Set render arguments so we can get pixel coordinates later. # We use functionality specific to the CYCLES renderer so BLENDER_RENDER # cannot be used. render_args = bpy.context.scene.render render_args.engine = "CYCLES" render_args.filepath = output_image render_args.resolution_x = args.width render_args.resolution_y = args.height render_args.resolution_percentage = 100 render_args.tile_x = args.render_tile_size render_args.tile_y = args.render_tile_size if args.use_gpu == 1: # Blender changed the API for enabling CUDA at some point if bpy.app.version < (2, 78, 0): bpy.context.user_preferences.system.compute_device_type = 'CUDA' bpy.context.user_preferences.system.compute_device = 'CUDA_0' else: cycles_prefs = bpy.context.user_preferences.addons['cycles'].preferences cycles_prefs.compute_device_type = 'CUDA' # Some CYCLES-specific stuff bpy.data.worlds['World'].cycles.sample_as_light = True bpy.context.scene.cycles.blur_glossy = 2.0 bpy.context.scene.cycles.samples = args.render_num_samples bpy.context.scene.cycles.transparent_min_bounces = args.render_min_bounces bpy.context.scene.cycles.transparent_max_bounces = args.render_max_bounces if args.use_gpu == 1: bpy.context.scene.cycles.device = 'GPU' if args.output_depth: # Following is based on stanford-shapenet-renderer bpy.context.scene.use_nodes = True tree = bpy.context.scene.node_tree render_layers = tree.nodes.new('CompositorNodeRLayers') depth_file_output = tree.nodes.new(type="CompositorNodeOutputFile") depth_file_output.label = 'Depth Output' depth_file_output.file_slots[0].path = '../../' + output_image + '_depth' map = tree.nodes.new(type="CompositorNodeNormalize") # thus, most distant points have pixel intensity of one, and nearest zero tree.links.new(render_layers.outputs['Depth'], map.inputs[0]) tree.links.new(map.outputs[0], depth_file_output.inputs[0]) # This will give ground-truth information about the scene and its objects scene_struct = { 'split': output_split, 'image_index': output_index, 'image_filename': os.path.basename(output_image), 'objects': [], 'directions': {}, } # Put a plane on the ground so we can compute cardinal directions bpy.ops.mesh.primitive_plane_add(radius=5) plane = bpy.context.object def rand(L): return 2.0 * L * (random.random() - 0.5) # Add random jitter to camera position if args.camera_jitter > 0: for i in range(3): bpy.data.objects['Camera'].location[i] += rand(args.camera_jitter) # Figure out the left, up, and behind directions along the plane and record # them in the scene structure camera = bpy.data.objects['Camera'] plane_normal = plane.data.vertices[0].normal cam_behind = camera.matrix_world.to_quaternion() * Vector((0, 0, -1)) cam_left = camera.matrix_world.to_quaternion() * Vector((-1, 0, 0)) cam_up = camera.matrix_world.to_quaternion() * Vector((0, 1, 0)) plane_behind = (cam_behind - cam_behind.project(plane_normal)).normalized() plane_left = (cam_left - cam_left.project(plane_normal)).normalized() plane_up = cam_up.project(plane_normal).normalized() # Delete the plane; we only used it for normals anyway. The base scene file # contains the actual ground plane. utils.delete_object(plane) # Save all six axis-aligned directions in the scene struct scene_struct['directions']['behind'] = tuple(plane_behind) scene_struct['directions']['front'] = tuple(-plane_behind) scene_struct['directions']['left'] = tuple(plane_left) scene_struct['directions']['right'] = tuple(-plane_left) scene_struct['directions']['above'] = tuple(plane_up) scene_struct['directions']['below'] = tuple(-plane_up) # Add random jitter to lamp positions if args.key_light_jitter > 0: for i in range(3): bpy.data.objects['Lamp_Key'].location[i] += rand(args.key_light_jitter) if args.back_light_jitter > 0: for i in range(3): bpy.data.objects['Lamp_Back'].location[i] += rand(args.back_light_jitter) if args.fill_light_jitter > 0: for i in range(3): bpy.data.objects['Lamp_Fill'].location[i] += rand(args.fill_light_jitter) # Now make some random objects objects, blender_objects = add_random_objects(scene_struct, num_objects, args, camera) if args.no_background: # This must come after add_random_objects, as that also changes the ground layer utils.set_layer(bpy.data.objects['Ground'], 2) else: # Note that in base_scene, the ground has no material (hence uses blender's default) bpy.data.materials.new(name='Ground_Material') ground_mat = bpy.data.materials['Ground_Material'] background_intensity = args.background_intensities[random.randrange(len(args.background_intensities))] ground_mat.diffuse_color = [background_intensity] * 3 bpy.data.objects['Ground'].data.materials.append(ground_mat) # Render the scene and dump the scene data structure scene_struct['objects'] = objects scene_struct['relationships'] = compute_all_relationships(scene_struct) while True: try: bpy.ops.render.render(write_still=True) break except Exception as e: print(e) if args.crop: maybe_crop(output_image) if args.output_depth: raise NotImplementedError if output_masks is not None: render_masks(blender_objects, output_masks) with open(output_scene, 'w') as f: json.dump(scene_struct, f, indent=2) if output_blendfile is not None: bpy.ops.wm.save_as_mainfile(filepath=output_blendfile)
def add_random_objects(scene_struct, num_objects, args, camera): """ Add random objects to the current blender scene """ # Load the property file with open(args.properties_json, 'r') as f: properties = json.load(f) color_name_to_rgba = {} for name, rgb in properties['colors'].items(): rgba = [float(c) / 255.0 for c in rgb] + [1.0] color_name_to_rgba[name] = rgba material_mapping = [(v, k) for k, v in properties['materials'].items()] object_mapping = [(v, k) for k, v in properties['shapes'].items()] size_mapping = list(properties['sizes'].items()) shape_color_combos = None if args.shape_color_combos_json is not None: with open(args.shape_color_combos_json, 'r') as f: shape_color_combos = list(json.load(f).items()) positions = [] objects = [] blender_objects = [] for i in range(num_objects): if i == 0: # first element is the small shiny gold "snitch"! size_name, r = "small", 0.3 # slightly larger than small obj_name, obj_name_out = 'Spl', 'spl' color_name = "gold" rgba = [1.0, 0.843, 0.0, 1.0] mat_name, mat_name_out = "MyMetal", "metal" elif i == 1: # second element is a medium cone size_name, r = "medium", 0.5 obj_name, obj_name_out = 'Cone', 'cone' color_name, rgba = random.choice(list(color_name_to_rgba.items())) mat_name, mat_name_out = random.choice(material_mapping) elif i == 2: # third element is a large cone size_name, r = "large", 0.75 obj_name, obj_name_out = 'Cone', 'cone' color_name, rgba = random.choice(list(color_name_to_rgba.items())) mat_name, mat_name_out = random.choice(material_mapping) else: # Choose a random size size_name, r = random.choice(size_mapping) # Choose random color and shape if shape_color_combos is None: obj_name, obj_name_out = random.choice(object_mapping) color_name, rgba = random.choice( list(color_name_to_rgba.items())) else: obj_name_out, color_choices = random.choice(shape_color_combos) color_name = random.choice(color_choices) obj_name = [k for k, v in object_mapping if v == obj_name_out][0] rgba = color_name_to_rgba[color_name] # Choose a random material mat_name, mat_name_out = random.choice(material_mapping) # Try to place the object, ensuring that we don't intersect any # existing objects and that we are more than the desired margin away # from all existing objects along all cardinal directions. num_tries = 0 while True: # If we try and fail to place an object too many times, then # delete all the objects in the scene and start over. num_tries += 1 if num_tries > args.max_retries: for obj in blender_objects: utils.delete_object(obj) return add_random_objects(scene_struct, num_objects, args, camera) x = random.uniform(-3, 3) y = random.uniform(-3, 3) # Check to make sure the new object is further than min_dist from # all other objects, and further than margin along the four # cardinal directions dists_good = True margins_good = True for (xx, yy, rr) in positions: dx, dy = x - xx, y - yy dist = math.sqrt(dx * dx + dy * dy) if dist - r - rr < args.min_dist: dists_good = False break for direction_name in ['left', 'right', 'front', 'behind']: direction_vec = scene_struct['directions'][direction_name] assert direction_vec[2] == 0 margin = dx * direction_vec[0] + dy * direction_vec[1] if 0 < margin < args.margin: logging.debug('{} {} {}'.format( margin, args.margin, direction_name)) logging.debug('BROKEN MARGIN!') margins_good = False break if not margins_good: break if dists_good and margins_good: break # For cube, adjust the size a bit if obj_name == 'Cube': r /= math.sqrt(2) # Choose random orientation for the object. # theta = 360.0 * random.random() theta = 2 * np.pi * random.random() # Actually add the object to the scene utils.add_object(args.shape_dir, obj_name, r, (x, y), theta=theta) obj = bpy.context.object blender_objects.append(obj) positions.append((x, y, r)) # Actually add material utils.add_material(mat_name, Color=rgba) # get bbox corners in world coord bbox_corners_world = np.array([ obj.matrix_world * Vector(corner) for corner in obj.bound_box ]) # 8 x 3 array T = np.average(bbox_corners_world, axis=0) # len-3, xyz coord in world system # try to create lrt l = [obj.dimensions.x, obj.dimensions.y, obj.dimensions.z] # R = eul2rot((0, 0, theta), degrees=True) # lx, ly, lz = l # xs = np.array([-lx/2., -lx/2., -lx/2., -lx/2., lx/2., lx/2., lx/2., lx/2.])[None, :] # 1 x 8 # ys = np.array([-ly/2., -ly/2., ly/2., ly/2., -ly/2., -ly/2., ly/2., ly/2.])[None, :] # zs = np.array([-lz/2., lz/2., -lz/2., lz/2., -lz/2., lz/2., -lz/2., lz/2.])[None, :] # xyzs_obj = np.concatenate([xs, ys, zs], axis=0) # 3 x 8 # xyzs_world = np.dot(R, xyzs) + T[:, None] # Record data about the object in the scene data structure pixel_coords = utils.get_camera_coords(camera, obj.location) objects.append({ 'shape': obj_name_out, 'size': size_name, 'sized': r, 'material': mat_name_out, '3d_coords': tuple(obj.location), '3d_bbox': bbox_corners_world.tolist(), '3d_size': l, '3d_bbox_center': T.tolist(), 'rotation': theta, 'pixel_coords': pixel_coords, 'color': color_name, 'instance': obj.name, }) return objects, blender_objects
def render_semantic_change( args, default_config, output_index=0, output_split='none', output_image='render.png', output_scene='render_json', output_blendfile=None, change_type='random', ): # Load the main blendfile bpy.ops.wm.open_mainfile(filepath=args.base_scene_blendfile) # Load materials utils.load_materials(args.material_dir) # Set render arguments so we can get pixel coordinates later. # We use functionality specific to the CYCLES renderer so BLENDER_RENDER # cannot be used. render_args = bpy.context.scene.render render_args.engine = "CYCLES" render_args.filepath = output_image render_args.resolution_x = args.width render_args.resolution_y = args.height render_args.resolution_percentage = 100 render_args.tile_x = args.render_tile_size render_args.tile_y = args.render_tile_size if args.use_gpu == 1: # Blender changed the API for enabling CUDA at some point if bpy.app.version < (2, 78, 0): bpy.context.user_preferences.system.compute_device_type = 'CUDA' bpy.context.user_preferences.system.compute_device = 'CUDA_0' else: cycles_prefs = bpy.context.user_preferences.addons[ 'cycles'].preferences cycles_prefs.compute_device_type = 'CUDA' # Some CYCLES-specific stuff bpy.data.worlds['World'].cycles.sample_as_light = True bpy.context.scene.cycles.blur_glossy = 2.0 bpy.context.scene.cycles.samples = args.render_num_samples bpy.context.scene.cycles.transparent_min_bounces = args.render_min_bounces bpy.context.scene.cycles.transparent_max_bounces = args.render_max_bounces if args.use_gpu == 1: bpy.context.scene.cycles.device = 'GPU' # This will give ground-truth information about the scene and its objects scene_struct = { 'split': output_split, 'image_index': output_index, 'image_filename': os.path.basename(output_image), 'objects': [], 'directions': {}, } # Put a plane on the ground so we can compute cardinal directions bpy.ops.mesh.primitive_plane_add(radius=5) plane = bpy.context.object def rand(L): return 2.0 * L * (random.random() - 0.5) # Randomly gitter camera from the default location #default_camera = default_config['camera'] default_camera_jitters = default_config['camera_jitters'] if args.camera_jitter > 0: for i in range(3): rand_camera_jitter = rand(args.camera_jitter) bpy.data.objects['Camera'].location[i] += ( default_camera_jitters[i] + rand_camera_jitter) # Figure out the left, up, and behind directions along the plane and record # them in the scene structure camera = bpy.data.objects['Camera'] plane_normal = plane.data.vertices[0].normal cam_behind = camera.matrix_world.to_quaternion() * Vector((0, 0, -1)) cam_left = camera.matrix_world.to_quaternion() * Vector((-1, 0, 0)) cam_up = camera.matrix_world.to_quaternion() * Vector((0, 1, 0)) plane_behind = (cam_behind - cam_behind.project(plane_normal)).normalized() plane_left = (cam_left - cam_left.project(plane_normal)).normalized() plane_up = cam_up.project(plane_normal).normalized() # Delete the plane; we only used it for normals anyway. The base scene file # contains the actual ground plane. utils.delete_object(plane) # Save all six axis-aligned directions in the scene struct scene_struct['directions']['behind'] = tuple(plane_behind) scene_struct['directions']['front'] = tuple(-plane_behind) scene_struct['directions']['left'] = tuple(plane_left) scene_struct['directions']['right'] = tuple(-plane_left) scene_struct['directions']['above'] = tuple(plane_up) scene_struct['directions']['below'] = tuple(-plane_up) # Use the same lamp light jitters default_key_jitters = default_config['key_light_jitters'] default_back_jitters = default_config['back_light_jitters'] default_fill_jitters = default_config['fill_light_jitters'] for i in range(3): bpy.data.objects['Lamp_Key'].location[i] += default_key_jitters[i] for i in range(3): bpy.data.objects['Lamp_Back'].location[i] += default_back_jitters[i] for i in range(3): bpy.data.objects['Lamp_Fill'].location[i] += default_fill_jitters[i] """ if args.key_light_jitter > 0: for i in range(3): rand_key_light_jitter = rand(args.key_light_jitter) bpy.data.objects['Lamp_Key'].location[i] += rand_key_light_jitter if args.back_light_jitter > 0: for i in range(3): rand_back_light_jitter = rand(args.back_light_jitter) bpy.data.objects['Lamp_Back'].location[i] += rand_back_light_jitter if args.fill_light_jitter > 0: for i in range(3): rand_fill_light_jitter = rand(args.fill_light_jitter) bpy.data.objects['Lamp_Fill'].location[i] += rand_fill_light_jitter """ # Now make some semantic changes to default objects default_objects = default_config['objects'] sc_objects, sc_blend_objects, success = \ apply_change(default_objects, scene_struct, args, camera, change_type) if not success: print( 'Could not semantically change the given scene for change type: %s' % change_type) return False # Render the scene and dump the scene data structure scene_struct['objects'] = sc_objects scene_struct['relationships'] = compute_all_relationships(scene_struct) while True: try: bpy.ops.render.render(write_still=True) break except Exception as e: print(e) with open(output_scene, 'w') as f: json.dump(scene_struct, f, indent=2) if output_blendfile is not None: bpy.ops.wm.save_as_mainfile(filepath=output_blendfile) return True
def add_random_objects(scene_struct, num_objects, args, camera): """ Add random objects to the current blender scene """ # Load the property file with open(args.properties_json, 'r') as f: properties = json.load(f) color_name_to_rgba = {} for name, rgb in properties['colors'].items(): rgba = [float(c) / 255.0 for c in rgb] + [1.0] color_name_to_rgba[name] = rgba material_mapping = [(v, k) for k, v in properties['materials'].items()] object_mapping = [(v, k) for k, v in properties['shapes'].items()] size_mapping = list(properties['sizes'].items()) shape_color_combos = None if args.shape_color_combos_json is not None: with open(args.shape_color_combos_json, 'r') as f: shape_color_combos = list(json.load(f).items()) positions = [] objects = [] blender_objects = [] for i in range(num_objects): # Choose a random size size_name, r = random.choice(size_mapping) # Try to place the object, ensuring that we don't intersect any existing # objects and that we are more than the desired margin away from all existing # objects along all cardinal directions. num_tries = 0 while True: # If we try and fail to place an object too many times, then delete all # the objects in the scene and start over. num_tries += 1 if num_tries > args.max_retries: for obj in blender_objects: utils.delete_object(obj) return add_random_objects(scene_struct, num_objects, args, camera) x = random.uniform(-3, 3) y = random.uniform(-3, 3) # Check to make sure the new object is further than min_dist from all # other objects, and further than margin along the four cardinal directions dists_good = True margins_good = True for (xx, yy, rr) in positions: dx, dy = x - xx, y - yy dist = math.sqrt(dx * dx + dy * dy) if dist - r - rr < args.min_dist: dists_good = False break for direction_name in ['left', 'right', 'front', 'behind']: direction_vec = scene_struct['directions'][direction_name] assert direction_vec[2] == 0 margin = dx * direction_vec[0] + dy * direction_vec[1] if 0 < margin < args.margin: print(margin, args.margin, direction_name) print('BROKEN MARGIN!') margins_good = False break if not margins_good: break if dists_good and margins_good: break # Choose random color and shape if shape_color_combos is None: obj_name, obj_name_out = random.choice(object_mapping) color_name, rgba = random.choice(list(color_name_to_rgba.items())) else: obj_name_out, color_choices = random.choice(shape_color_combos) color_name = random.choice(color_choices) obj_name = [k for k, v in object_mapping if v == obj_name_out][0] rgba = color_name_to_rgba[color_name] # For cube, adjust the size a bit if obj_name == 'Cube': r /= math.sqrt(2) # Choose random orientation for the object. theta = 360.0 * random.random() # Actually add the object to the scene utils.add_object(args.shape_dir, obj_name, r, (x, y), theta=theta) obj = bpy.context.object blender_objects.append(obj) positions.append((x, y, r)) # Attach a random material mat_name, mat_name_out = random.choice(material_mapping) utils.add_material(mat_name, Color=rgba) # Record data about the object in the scene data structure pixel_coords = utils.get_camera_coords(camera, obj.location) objects.append({ 'name': obj.name, 'shape': obj_name_out, 'size': size_name, 'material': mat_name_out, '3d_coords': tuple(obj.location), 'rotation': theta, 'pixel_coords': pixel_coords, 'color': color_name, }) # # Check that all objects are at least partially visible in the rendered image # all_visible = check_visibility(blender_objects, args.min_pixels_per_object, args.height, args.width, # args.crop_up, args.crop_down, args.crop_left, args.crop_right) # if not all_visible: # # If any of the objects are fully occluded then start over; delete all # # objects from the scene and place them all again. # print('Some objects are occluded; replacing objects') # for obj in blender_objects: # utils.delete_object(obj) # return add_random_objects(scene_struct, num_objects, args, camera) indices = [ n[0] for n in sorted(enumerate(objects), key=lambda x: x[1]['pixel_coords'][2], reverse=True) ] objects = [objects[idx] for idx in indices] blender_objects = [blender_objects[idx] for idx in indices] return objects, blender_objects
def apply_change(default_objects, scene_struct, args, camera, change_type): """ Apply changes to default objects to the current blender scene. """ # Load the property file with open(args.properties_json, 'r') as f: properties = json.load(f) color_name_to_rgba = {} for name, rgb in properties['colors'].items(): rgba = [float(c) / 255.0 for c in rgb] + [1.0] color_name_to_rgba[name] = rgba material_mapping = [(v, k) for k, v in properties['materials'].items()] object_mapping = [(v, k) for k, v in properties['shapes'].items()] size_mapping = list(properties['sizes'].items()) shape_color_combos = None if args.shape_color_combos_json is not None: with open(args.shape_color_combos_json, 'r') as f: shape_color_combos = list(json.load(f).items()) def render_object(obj): obj_name_out = obj['shape'] obj_name = [k for k, v in object_mapping if v == obj_name_out][0] color_name = obj['color'] rgba = color_name_to_rgba[color_name] size_name = obj['size'] r = [v for k, v in size_mapping if k == size_name][0] if obj_name == 'Cube': r /= math.sqrt(2) theta = obj['rotation'] mat_name_out = obj['material'] mat_name = [k for k, v in material_mapping if v == mat_name_out][0] x, y, z = obj['3d_coords'] position = (x, y, r) utils.add_object(args.shape_dir, obj_name, r, (x, y), theta=theta) new_blend_obj = bpy.context.object utils.add_material(mat_name, Color=rgba) new_pixel_coords = utils.get_camera_coords(camera, new_blend_obj.location) return new_blend_obj, position, new_pixel_coords def check_dist_margin(this_position, other_positions): # Check to make sure the new object is further than min_dist from all # other objects, and further than margin along the four cardinal directions dists_good = True margins_good = True x, y, r = this_position for (xx, yy, rr) in other_positions: dx, dy = x - xx, y - yy dist = math.sqrt(dx * dx + dy * dy) if dist - r - rr < args.min_dist: dists_good = False break for direction_name in ['left', 'right', 'front', 'behind']: direction_vec = scene_struct['directions'][direction_name] assert direction_vec[2] == 0 margin = dx * direction_vec[0] + dy * direction_vec[1] if 0 < margin < args.margin: print(margin, args.margin, direction_name) print('BROKEN MARGIN!') margins_good = False break if not margins_good: break return dists_good and margins_good curr_num_objects = len(default_objects) new_objects = [] if change_type == 'color': # Randomly pick an object and change its color. object_idx = random.randint(0, curr_num_objects - 1) for i, obj in enumerate(default_objects): new_obj = copy.deepcopy(obj) if i == object_idx: curr_color_name = new_obj['color'] while True: new_color_name, new_rgba = random.choice( list(color_name_to_rgba.items())) if new_color_name != curr_color_name: break new_obj['color'] = new_color_name new_objects.append(new_obj) elif change_type == 'material': # Randomly pick an object and change its material. object_idx = random.randint(0, curr_num_objects - 1) for i, obj in enumerate(default_objects): new_obj = copy.deepcopy(obj) if i == object_idx: curr_mat_name_out = new_obj['material'] curr_mat_name = [ k for k, v in material_mapping if v == curr_mat_name_out ][0] while True: new_mat_name, new_mat_name_out = random.choice( material_mapping) if new_mat_name != curr_mat_name: break new_obj['material'] = new_mat_name_out new_objects.append(new_obj) elif change_type == 'shape': # Randomly pick an object and change the shape. pass elif change_type == 'drop': # Randomly pick an object and delete from the scene. object_idx = random.randint(0, curr_num_objects - 1) for i, obj in enumerate(default_objects): new_obj = copy.deepcopy(obj) if i == object_idx: continue else: new_objects.append(new_obj) elif change_type == 'add': # Randomly add an object to the scene. # Need to check distance and margin # Randomly pick size new_size_name, new_r = random.choice(size_mapping) # Try to place the object, ensuring that we don't intersect any existing # objects and that we are more than the desired margin away from all existing # objects along all cardinal directions. other_positions = [] for i, obj in enumerate(default_objects): obj_name_out = obj['shape'] obj_name = [k for k, v in object_mapping if v == obj_name_out][0] size_name = obj['size'] r = [v for k, v in size_mapping if k == size_name][0] if obj_name == 'Cube': r /= math.sqrt(2) x, y, z = obj['3d_coords'] position = (x, y, r) other_positions.append(position) new_objects.append(copy.deepcopy(obj)) num_tries = 0 while True: # If we try and fail to place an object too many times, # reject the default image. num_tries += 1 if num_tries > args.max_retries: return None, None, False new_x = random.uniform(-3, 3) new_y = random.uniform(-3, 3) this_position = (new_x, new_y, new_r) success = check_dist_margin(this_position, other_positions) if success: break # Choose random color and shape if shape_color_combos is None: new_obj_name, new_obj_name_out = random.choice(object_mapping) new_color_name, new_rgba = random.choice( list(color_name_to_rgba.items())) else: new_obj_name_out, color_choices = random.choice(shape_color_combos) new_color_name = random.choice(color_choices) new_obj_name = [ k for k, v in object_mapping if v == new_obj_name_out ][0] new_rgba = color_name_to_rgba[new_color_name] # For cube, adjust the size a bit if new_obj_name == 'Cube': new_r /= math.sqrt(2) # Choose random orientation for the object. new_theta = 360.0 * random.random() # Attach a random material new_mat_name, new_mat_name_out = random.choice(material_mapping) new_objects.append({ 'shape': new_obj_name_out, 'size': new_size_name, 'material': new_mat_name_out, '3d_coords': (new_x, new_y, -1), 'rotation': new_theta, 'pixel_coords': None, 'color': new_color_name, }) elif change_type == 'switch': # Randomly pick two objects and switch locations. # Need to check distance and margin pass elif change_type == 'random': # Apply random changes from above. pass elif change_type == 'same': # Don't apply any change to the objects. for i, obj in enumerate(default_objects): new_obj = copy.deepcopy(obj) new_objects.append(new_obj) new_num_objects = len(new_objects) new_positions = [] new_blend_objects = [] for obj in new_objects: new_blend_object, new_position, new_pixel_coords = render_object(obj) new_blend_objects.append(new_blend_object) new_positions.append(new_position) obj['pixel_coords'] = new_pixel_coords # Check that all objects are at least partially visible in the rendered image all_visible = check_visibility(new_blend_objects, args.min_pixels_per_object) if not all_visible: # If any of the objects are fully occluded, delete all and skip this one. print('Some objects are occluded') for obj in new_blend_objects: utils.delete_object(obj) return None, None, False return new_objects, new_blend_objects, True