Example #1
0
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
Example #2
0
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()
Example #3
0
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()
Example #4
0
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)
Example #7
0
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
Example #8
0
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)
Example #9
0
 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"])
Example #10
0
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)
Example #11
0
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
Example #12
0
        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()
Example #13
0
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
Example #14
0
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)
Example #15
0
    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"])
Example #16
0
    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
Example #20
0
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
Example #21
0
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
Example #22
0
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
Example #23
0
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)
Example #24
0
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")
Example #25
0
    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])
Example #26
0
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)
Example #27
0
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
Example #29
0
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