예제 #1
0
def plot_particle_3d(particle, environment, cameras=None, placed_cameras=None, view_time=0.0, figure_number=0,
                     opt_options=CameraPlacementOptions(), reevaluate_state=False):
    """
    Plots cameras and environment in 3D
    :param particle: particle to be plotted (np.array)
    :param environment: Environment class instance
    :param cameras: a list of Camera objects corresponding to the cameras which have already been placed in an
        environment
    :param placed_cameras: PlacedCameras class instance containing already placed cameras
    :param view_time: how long the plot should be visible
    :param figure_number: figure number on which to draw environment
    :param opt_options: optimization options
    :param reevaluate_state: whether or not to re-evaluate the camera state using the particle input (defaults to false)
    :return: none
    """
    figure = plt.figure(figure_number)
    plt.clf()
    ax = Axes3D(figure)

    # cameras should already have correct state following particle evaluation. only re-evaluate if needed
    if reevaluate_state:
        cameras = convert_particle_to_state(environment, particle, cameras, opt_options)

    draw_room_3d(environment=environment, cameras=cameras, placed_cameras=placed_cameras, fill_alpha=0.1, ax=ax)

    ax.elev = 15
    ax.azim = -140

    # ax.elev = 54
    # ax.azim = -70

    if view_time > 0:
        plt.pause(view_time)  # block for view_time seconds
    elif view_time < 0:
        plt.show()  # block until closed
    else:
        plt.waitforbuttonpress()  # block until any button is pressed
예제 #2
0
def initialize_opt_options():
    np.random.seed(round(time.time()))

    # loading configuration
    config = configparser.ConfigParser()
    rospack = rospkg.RosPack()
    config.read(rospack.get_path("perch_placement") + "/src/config/opt.ini")

    # extract configuration values
    env_conf = config['ENVIRONMENT']
    mesh_env = env_conf.getboolean('mesh_env')
    world_frame = np.asarray(np.matrix(env_conf['world_frame'])).squeeze()
    angle_threshold = env_conf.getfloat('angle_threshold')
    dist_threshold = env_conf.getfloat('dist_threshold')
    min_room_height = env_conf.getfloat('min_room_height')
    erosion_raster_density = env_conf.getint('erosion_raster_density')
    min_obstacle_radius = env_conf.getfloat('min_obstacle_radius')
    nearest_neighbor_restriction = env_conf.getboolean('enable_nearest_neighbor_restriction')
    target_volume_height = env_conf.getfloat('target_volume_height')

    cam_conf = config['CAMERA']
    variable_pan = cam_conf.getboolean('variable_pan')
    variable_tilt = cam_conf.getboolean('variable_tilt')
    variable_zoom = cam_conf.getboolean('variable_zoom')

    drone_conf = config['DRONE']
    perch_on_ceiling = drone_conf.getboolean('perch_on_ceiling')
    perch_on_walls = drone_conf.getboolean('perch_on_walls')
    land_on_floor = drone_conf.getboolean('land_on_floor')
    perch_on_intermediate_angles = drone_conf.getboolean('perch_on_intermediate_angles')
    min_perch_window = np.asarray(np.matrix(drone_conf['min_perch_window'])).squeeze()
    perch_window_shape = drone_conf['perch_window_shape']
    min_recovery_height = drone_conf.getfloat('min_recovery_height')

    variable_height = drone_conf.getboolean('variable_height')

    search_env = config['SEARCH']
    angle_mode = search_env['angle_mode']
    target_deviation = np.asarray(np.matrix(search_env['target_deviation'])).squeeze()
    min_vertices = search_env.getint('min_vertices')
    individual_surface_opt = search_env.getboolean('individual_surface_opt')
    map_to_flat_surface = search_env.getboolean('map_to_flat_surface')
    minimum_score_deviation = search_env.getfloat('minimum_score_deviation')
    minimum_particle_deviation = search_env.getfloat('minimum_particle_deviation')
    inside_out_search = search_env.getboolean('inside_out_search')

    if individual_surface_opt:
        surface_number = 0  # placeholder for now. will modify in loop below
    else:
        surface_number = -1

    vary_position_over_face = search_env.getboolean('vary_position_over_face')
    noise_resistant_particles = search_env.getint('noise_resistant_particles')
    noise_resistant_sample_size = search_env.getint('noise_resistant_sample_size')
    N_points = search_env.getint('N_points')

    # Optimizer Options:
    optimization_options = CameraPlacementOptions(variable_pan=variable_pan, variable_tilt=variable_tilt,
                                                  variable_zoom=variable_zoom, perch_on_ceiling=perch_on_ceiling,
                                                  perch_on_intermediate_angles=perch_on_intermediate_angles,
                                                  perch_on_walls=perch_on_walls, land_on_floor=land_on_floor,
                                                  variable_height=variable_height, mesh_env=mesh_env,
                                                  angle_mode=angle_mode, angle_threshold=angle_threshold,
                                                  dist_threshold=dist_threshold, min_room_height=min_room_height,
                                                  target_deviation=target_deviation, min_perch_window=min_perch_window,
                                                  vary_position_over_face=vary_position_over_face,
                                                  erosion_raster_density=erosion_raster_density,
                                                  min_obstacle_radius=min_obstacle_radius,
                                                  nearest_neighbor_restriction=nearest_neighbor_restriction,
                                                  target_volume_height=target_volume_height,
                                                  world_frame=world_frame, min_vertices=min_vertices,
                                                  surface_number=surface_number,
                                                  map_to_flat_surface=map_to_flat_surface,
                                                  perch_window_shape=perch_window_shape,
                                                  min_recovery_height=min_recovery_height,
                                                  minimum_score_deviation=minimum_score_deviation,
                                                  minimum_particle_deviation=minimum_particle_deviation,
                                                  inside_out_search=inside_out_search,
                                                  noise_resistant_particles=noise_resistant_particles,
                                                  noise_resistant_sample_size=noise_resistant_sample_size,
                                                  n_points=N_points)

    return optimization_options
예제 #3
0
def convert_particle_to_angle(particle_angle, wall_normal, camera, environment, axis=2,
                              opt_options=CameraPlacementOptions(), target_center=False):
    """
    Converts a particle weight into a pan or tilt angle

    :param particle_angle: particle weight, on range [0, 1]
    :param wall_normal: normal direction of the surface on which the camera is placed
    :param camera: Camera instance
    :param environment: Environment Class instance containing the environment in which to place cameras
    :param axis: 0 (roll, not used) 1 (tilt/pitch axis), or 2 (pan/yaw axis)
    :param opt_options: used to specify the optimization options which impact how particles are mapped to angles.
     Relevant options include:
     angle_mode
        "TOWARDS_TARGET" - the camera is always pointed to within some angular variation (currently +/- 15 deg) of the
        target centroid
        "WALL_LIMITED" - the camera is always pointed within the internal 180 degrees of the surface which it is
        perching on. i.e. [-90, 90]
        "FOV_LIMITED" - the camera is always pointed within the range of angles which the FOV first contacts the surface
        which it is perching on.
        (i.e. [-90+FOV/2, 90-FOV/2])
        "GIMBAL_LIMITED" - the intersection of the FOV_LIMITED range and the camera's specified gimbal limits
        "GIMBAL_LIMITED_TARGETING" - this mode attempts to point TOWARDS_TARGET, but still conforms with gimbal limits
        All other opt result in a 0 to 360 value to be specified
     target_deviation - a 2d array or list containing the maximum allowable angular deviation away from the centroid of
     the target region
    :param target_center: bool. if true, disregard the particle and point either with 0 gimbal offset (for WALL, FOV, or
     GIMBAL limited options), directly towards the target center, for TOWARDS_TARGET, or as close to target center as
     possible for GIMBAL_LIMITED_TARGETING
    :return: converted angle to assign to camera
    """

    # extract euler angles from 0-direction of camera at surface
    eul = vec2eul(np.dot(camera.camera_rotation, wall_normal))
    norm_offset = eul[axis]  # uses standard convention; eul[0] = roll, eul[1] = pitch/tilt, eul[2] = pan/yaw
    angle_mode = opt_options.angle_mode
    target_deviation = opt_options.target_deviation

    if target_center:
        particle_angle = 0.5

    if angle_mode == "WALL_LIMITED":
        # recenter to -90 to 90 about edge normal
        angle = (particle_angle * 360 - 180) / 2 + norm_offset

    elif angle_mode == "FOV_LIMITED":
        # recenter about edge normal between -(90-fov/2) and (90-fov/2)
        angle = ((particle_angle * 360 - 180) / 2) * ((180 - camera.fov[1-axis]) / 180) + norm_offset
        # using 1-axis b/c FOV is listed as PAN (Horizontal) then TILT (vertical)
        # while you could consider adding different cases for corner points where the view is more or less than 180 deg,
        # it doesn't seem worth the complexity. A camera cannot perch on a corner and wouldn't benefit from increased
        # FOV. A drone also can't perch too near an inner corner, limiting the need for consideration over inner corner
        # occlusions.

    elif angle_mode == "GIMBAL_LIMITED":
        min_angle = np.min([90-camera.fov[1-axis]/2, camera.gimbal_limit[axis-1]])
        angle = (particle_angle * 2 * min_angle - min_angle) + norm_offset

    elif angle_mode == "TOWARDS_TARGET":
        # restrict to +/- X degrees about the center of the target region
        # find vector between camera location and target centroid
        vec_dir = np.array([environment.target_centroid[0] - camera.pose[0],
                            environment.target_centroid[1] - camera.pose[1],
                            environment.target_centroid[2] - camera.pose[2]])

        vec_dir = vec_dir / dist(vec_dir, np.zeros(3))  # normalize to get unit vector
        eul = vec2eul(vec_dir)  # convert to euler angles. use pitch for tilt, use yaw for pan

        angle = (particle_angle * target_deviation[axis-1] - target_deviation[axis-1]/2) + eul[axis]

    elif angle_mode == "GIMBAL_LIMITED_TARGETING":
        # point towards target center, if allowed by gimbal limits. else get as close as possible
        # find vector between camera location and target centroid
        vec_dir = np.array([environment.target_centroid[0] - camera.pose[0],
                            environment.target_centroid[1] - camera.pose[1],
                            environment.target_centroid[2] - camera.pose[2]])

        vec_dir = vec_dir / dist(vec_dir, np.zeros(3))  # normalize to get unit vector
        eul = vec2eul(vec_dir)  # convert to euler angles. use pitch for tilt, use yaw for pan

        # simplify notation a bit here... t=target direction, n=normal direction, g=gimbal limit, d=target deviation
        t = eul[axis]
        n = norm_offset
        g = camera.gimbal_limit[axis-1]
        d = target_deviation[axis-1]

        # min angular distance  between normal and target directions
        delta_angle = min_ang_dist(t, n)

        if np.abs(delta_angle) < g + d:
            # set of deviations about target direction intersects set of angles within gimbal limit, about the normal
            # direction. In this case, want the union of the two sets

            if target_center:  # disregard particle and try to get as close as possible to target direction
                if np.abs(delta_angle) < g:
                    return t  # target is within gimbal limits; aim at target
                else:  # return closest gimbal bound to target
                    if np.abs(min_ang_dist(t, n+g)) < np.abs(min_ang_dist(t, n-g)):
                        return n+g
                    else:
                        return n-g

            bounds = np.array([n + max(-g, delta_angle - d),
                               n + min(g, delta_angle + d)])  # upper and lower bound of resultant set

            # select point within set
            set_range = bounds[1]-bounds[0]
            angle = (particle_angle * set_range) + bounds[0]

        else:
            # target is not within gimbal limits. set angular range as the
            ubd = min_ang_dist(t, n+g)
            lbd = min_ang_dist(t, n-g)
            if np.abs(ubd) < np.abs(lbd):
                angle = n+g
            else:
                angle = n+g

    else:
        # angle_mode == "NO_LIMIT":
        # recenter to -180 to 180
        angle = (particle_angle * 360 - 180)

    return angle
예제 #4
0
def convert_particle_to_state(environment, particle, cameras, opt_options=CameraPlacementOptions(), debug=False):
    """
    Converts the weights of the particle into the state of the Camera to be evaluated

    :param environment: Environment Class instance containing the environment in which to place cameras
    :param particle: individual particle as np.array
    :param cameras: a list of Camera objects corresponding to the cameras which have already been placed in an
     environment
    :param opt_options: CameraPlacementOptions class containing opt opt
    :param debug: flag, if true print and draw relevant information.
    :return: list of cameras with updated state
    """

    n_cameras = len(cameras)
    ppc = opt_options.get_particle_size()  # particles per camera

    for i in range(n_cameras):

        particle_index = 0

        if opt_options.mesh_env:
            particle_index = 1  # 1D by default (to select face center on preselected surface)
            surf_index = -1
            if opt_options.surface_number < 0:
                particle_index += 1  # extra term required for surface selection

            elif 0 <= opt_options.surface_number < len(environment.perch_regions):
                surf_index = opt_options.surface_number
            else:
                print("ERROR: SURFACE ID TOO LARGE. THIS SHOULD NOT HAPPEN")
                cameras[i].pose *= np.nan
                break

            if opt_options.map_to_flat_surface:
                particle_index += 1
            elif opt_options.vary_position_over_face:
                particle_index += 2

            if opt_options.map_to_flat_surface:
                surf_point, cameras[i].wall_normal, on_ceiling, surf_id = \
                    environment.map_particle_to_flattened_surface(particle[i * ppc:i*ppc+particle_index],
                                                                surface_index=surf_index)
                if np.isnan(surf_point).any():
                    cameras[i].pose[:3] *= np.nan
                    break

            else:
                surf_point, cameras[i].wall_normal, on_ceiling, surf_id = \
                    environment.map_particle_to_surface(particle[i * ppc:i*ppc+particle_index],
                                                        surface_index=surf_index)

            R = rot3d_from_z_vec(cameras[i].wall_normal)
            cameras[i].pose[0:3] = surf_point + np.dot(R, cameras[i].camera_offset)

        else:  # DEPRECATED
            edge_perimeter = environment.perch_perimeter

            if opt_options.perch_on_ceiling:
                cameras[i].pose[0:3], cameras[i].wall_normal, on_ceiling = \
                    environment.map_particle_to_surface(particle=particle, start_index=i*ppc+particle_index)

                particle_index = particle_index + 3
            else:
                cameras[i].pose[0:2], cameras[i].wall_normal = \
                    map_line_to_edge(environment, particle[i*ppc + particle_index] * edge_perimeter)

                on_ceiling = False

            # vertical position is already covered by perch on ceiling if it is active. only include height
            if opt_options.variable_height and not opt_options.perch_on_ceiling:
                cameras[i].pose[2] = convert_particle_to_height(particle[i*ppc + particle_index], on_ceiling,
                                                                environment)
            else:
                cameras[i].pose[2] = 2  # constant height. typical ceiling is ~2.75m high; set in environment.max_height

        # Recall: the camera's axes are X=RIGHT, Y=DOWN, Z=FORWARD; (before was erroneously using X=fwd, Y=left, z=up)
        # therefore camera PAN is about Y, TILT is about X, ROLL is about Z
        if opt_options.variable_pan:
            cameras[i].pose[-2] = -convert_particle_to_angle(particle_angle=particle[i * ppc + particle_index],
                                                            wall_normal=cameras[i].wall_normal, camera=cameras[i],
                                                            axis=2, environment=environment, opt_options=opt_options)
            particle_index = particle_index + 1
        else:
            # passing 0.5 in as particle value and enabling target_center better respects angle mode (either point
            # normal to wall, or towards target) without adding search complexity
            cameras[i].pose[-2] = -convert_particle_to_angle(0.5, wall_normal=cameras[i].wall_normal,
                                                            camera=cameras[i], axis=2, environment=environment,
                                                            opt_options=opt_options, target_center=True)

        if opt_options.variable_tilt:
            cameras[i].pose[-3] = -convert_particle_to_angle(particle_angle=particle[i * ppc + particle_index],
                                                            wall_normal=cameras[i].wall_normal, camera=cameras[i],
                                                            axis=1, environment=environment, opt_options=opt_options)
            particle_index = particle_index + 1
        else:
            # passing 0.5 in as particle value and enabling target_center better respects angle mode (either point
            # normal to wall, or towards target) without adding search complexity
            cameras[i].pose[-3] = -convert_particle_to_angle(0.5, wall_normal=cameras[i].wall_normal,
                                                            camera=cameras[i], axis=1, environment=environment,
                                                            opt_options=opt_options, target_center=True)

        if opt_options.variable_zoom:
            cameras[i].fov = convert_particle_to_zoom(particle[i * ppc + particle_index], cameras[i])
            # particle_index = particle_index + 1  # re-add if more options are added in the future
        else:
            cameras[i].fov = cameras[i].base_fov

        # for the time being, never add any roll. Could consider adding roll as "noise"... might want noise resistance
        cameras[i].pose[-1] = 0

        cameras[i].surf_id = surf_id

        # if debug:
        #     print("Camera: " + str(i))
        #     print("Particle: " + str(particle[i*2:i*2+2]))
        #     print("FOV: " + str(cameras[i].fov[0]))
        #     print("Edge Normal Direction: " + str(cameras[i].wall_normal))
        #     print("Camera Pose: " + str(cameras[i].pose))

    return cameras
예제 #5
0
def evaluate_particle(particle, environment, cameras, placed_cameras=PlacedCameras(),
                      opt_options=CameraPlacementOptions(), debug=False, vedo_plt=None, maximization=False):
    """
    This function evaluates a single particle using the heuristic function defined in evaluate_arrangement()

    :param particle: individual particle as np.array
    :param environment: Environment class instance
    :param cameras: a list of Camera objects corresponding to the cameras which have already been placed in an
     environment
    :param placed_cameras: PlacedCameras class instance
    :param opt_options: CameraPlacementOptions class containing opt opt
    :param debug: flag, if true print and draw relevant information.
    :return: score of particle
    """
    # convert particle into camera pose; evaluate edge normal at each camera position
    cameras = convert_particle_to_state(environment=environment, particle=particle, cameras=cameras,
                                        opt_options=opt_options, debug=debug)

    # plot particles to debug...
    # if debug:
    #     if environment.dimension == 2:
    #         plot_particle_2d(particle=np.squeeze(particle), environment=environment, cameras=cameras,
    #                          placed_cameras=placed_cameras, view_time=0.0001, figure_number=figure_number)
    #     else:
    # # if len(placed_cameras.cameras) > 0:
    # plot_particle_3d(particle=particle, environment=environment, cameras=cameras, placed_cameras=placed_cameras,
    #                  view_time=0.0001, figure_number=figure_number)

    score = evaluate_arrangement_covariance(environment=environment, cameras=cameras, placed_cameras=placed_cameras,
                                            debug=debug, maximization=maximization)

    if vedo_plt is not None:
        if len(placed_cameras.cameras) >= 10:
            geom_list = []
            for i in range(len(cameras)):
                pymesh_frustum = cameras[i].generate_discrete_camera_mesh(degrees_per_step=5, environment=environment)
                if len(pymesh_frustum.faces) > 0 and not np.isnan(pymesh_frustum.vertices).any():
                    pymesh_verts = pymesh_frustum.vertices.copy()
                    pymesh_verts.flags.writeable = True
                    pymesh_faces = pymesh_frustum.faces.copy()
                    pymesh_faces.flags.writeable = True
                    frustum = trimesh.Trimesh(vertices=pymesh_frustum.vertices.copy(),
                                              faces=pymesh_frustum.faces.copy())
                    vedo_frustum = vedo.mesh.Mesh(frustum)
                    vedo_frustum.alpha(0.2)
                    vedo_frustum.color("c")
                    quad_mesh = trimesh.load(
                        "/home/simon/catkin_ws/src/perch_placement/src/ui/models/white-red-black_quad2.ply")
                    R = rot3d_from_x_vec(cameras[i].wall_normal)
                    R2 = rot3d_from_rtp(np.array([0, -90, 0]))
                    R_aug = np.zeros([4, 4])
                    R_aug[:3, :3] = R.dot(R2)
                    R_aug[:3, -1] = cameras[i].pose[:3]
                    quad_mesh.vertices = trimesh.transform_points(quad_mesh.vertices, R_aug)
                    quad_mesh_vedo = vedo.mesh.Mesh(quad_mesh)
                    quad_mesh_vedo.cellIndividualColors(quad_mesh.visual.face_colors / 255, alphaPerCell=True)
                    geom_list.append(quad_mesh_vedo)
                    geom_list.append(vedo_frustum)

                    for actor in geom_list:
                        vedo_plt.add(actor)

                    # p_.camera_position = [
                    #     (R * np.cos(t), R * np.sin(t), z),
                    #     (c[0], c[1], c[2]),  # (-0.026929191045848594, 0.5783514020506139, 0.8268966663940324),
                    #     (0, 0, 1),
                    # ]
                    vedo_plt.camera.SetPosition(7*np.cos(-145*np.pi/180.0), 7*np.sin(-145*np.pi/180.0), 6.25)
                    vedo_plt.camera.SetFocalPoint(-0.026929191045848594, 0.5783514020506139, 0.9268966663940324)
                    vedo_plt.camera.SetViewUp(np.array([0, 0, 1]))
                    vedo_plt.camera.SetDistance(7.8)
                    vedo_plt.camera.SetClippingRange([0.25, 30])
                    vedo_plt.camera
                    vedo_plt.show(interactive=False, rate=30, resetcam=False, fullscreen=True)
                    time.sleep(0.5)
                    actors = vedo_plt.actors
                    for i in range(len(cameras)):
                        vedo_plt.remove(actors.pop())
                        vedo_plt.remove(actors.pop())

        # plot_particle_3d(particle=particle, environment=environment, cameras=cameras, placed_cameras=placed_cameras,
        #                  view_time=0.0001, figure_number=0)
    # print("Particle score: " + str(score) + "; Pose: " + str(cameras[0].pose))

    if debug:
        print(score)

    return score
예제 #6
0
def evaluate_swarm(x, environment, cameras, placed_cameras=PlacedCameras(),
                   opt_options=CameraPlacementOptions(), debug=False, figure_number=0, vedo_plt=None,
                   maximization=False):
    """
    The main function used by PySwarms to evaluate particles corresponding with camera placement

    :param x: the list of particles returned by PySwarms for the current iteration
    :param environment: Environment Class instance containing the environment in which to place cameras
    :param cameras: list of cameras, in order of which they are placed
    :param placed_cameras: PlacedCameras class instance
    :param opt_options: CameraPlacementOptions class containing opt opt
    :param debug: flag, if true print and draw relevant information.
    :param figure_number: figure window number on which to plot placements
    :return: particle scores
    """
    particles = np.copy(x)
    n_particles = np.shape(particles)[0]  # extract swarm dimensions

    # pts_searched = 0
    # fitness_deviation = 0
    # max_fitness = np.finfo(float).max

    if not opt_options.continue_searching:
        # print("would stop here")
        return np.ones(n_particles)*np.finfo(float).max/2

    else:
        # Check particle variance
        if opt_options.minimum_particle_deviation is not None and opt_options.minimum_particle_deviation > 0:
            deviations = np.std(particles, axis=0)
            # print("Particle Deviations: " + str(deviations))
            if (deviations < opt_options.minimum_particle_deviation).all():
                # print("Ending search early. Particle deviation too low.")
                opt_options.continue_searching = False
                # print("Would stop here")
                return np.ones(n_particles)*np.finfo(float).max/2

        results = np.ones([n_particles, 1])*np.inf  # start with max possible score...

        # print("There are " + str(len(placed_cameras.cameras)) + "placed cameras")

        for p in range(n_particles):
            results[p] = evaluate_particle(particle=particles[p, :], environment=environment, cameras=cameras,
                                           placed_cameras=placed_cameras, opt_options=opt_options, debug=debug,
                                           vedo_plt=vedo_plt, maximization=maximization)

        # if opt_options.noise_resistant_particles > 0:
        #     n_top = min(opt_options.noise_resistant_particles, n_particles)
        #     top_particles = np.argpartition(np.squeeze(results), -n_top)[-n_top:]
        #     environment.noise_resistant_search = True
        #     for p in top_particles:
        #         results[p] = evaluate_particle(particle=particles[p, :], environment=environment, cameras=cameras,
        #                                        placed_cameras=placed_cameras, opt_options=opt_options, debug=debug,
        #                                        maximization=maximization)
        #     environment.noise_resistant_search = False

        if opt_options.log_performance:
            c = len(placed_cameras.cameras)
            i = opt_options.iteration
            j = opt_options.data_index + 1

            opt_options.search_time[i, c, j] = time.time()
            # opt_options.fitness_deviation[i, c, j] = np.nanstd(results)
            opt_options.best_fitness[i, c, j] = np.nanmin(results)
            opt_options.pts_searched[i, c, j] = n_particles

            opt_options.data_index += 1

        if debug:
            if environment.dimension == 2:
                plot_particles_in_2d_search_space(particles, figure_number)

        # if environment.opt_options.map_to_flat_surface:
        #     plot_particles_on_2D_surface(particles, surf=environment.perch_regions[environment.opt_options.surface_number],
        #                                  figure_num=1, view_time=0.1, persistent_points=False)

        # fig = plt.figure(1)
        # ax = Axes3D(fig)
        # plot_particles_on_3D_surface(particles, environment=environment, surf_id=environment.opt_options.surface_number,
        #                              ax=ax, view_time=0.1, persistent_points=False, ppc=opt_options.get_particle_size())

        if opt_options.minimum_score_deviation is not None and opt_options.minimum_score_deviation > 0:
            deviation = np.std(results)
            # print("Score Deviation: " + str(deviation))
            if (deviation < opt_options.minimum_score_deviation).all():
                opt_options.stagnant_loops += 1
                # print("Score variation too low... (# consecutive stagnant loops = " +
                #       str(opt_options.stagnant_loops) + ")")
                # print("Scores: " + str(results.reshape([-1])))
                if opt_options.stagnant_loops >= opt_options.max_stagnant_loop_count:
                    # print("Ending search early. Score deviation too low.")
                    opt_options.continue_searching = False
            else:
                opt_options.stagnant_loops = 0

        # return np.squeeze(results)
        return results.reshape([-1])
예제 #7
0
def ply_environment(file_path_prototype,
                    target_path_prototype=None,
                    cluster_env_path=None,
                    optimization_options=CameraPlacementOptions(),
                    reorient_mesh=False,
                    full_env_path=None,
                    N_points=50):  # , surface_number=-1):

    rospy.loginfo(rospy.get_caller_id() + " Importing mesh environment")
    t0 = time.time()

    if cluster_env_path is not None:
        cluster_env = import_ply(cluster_env_path,
                                 post_process=False,
                                 options=optimization_options,
                                 is_plane_mesh=False)

        if optimization_options.nearest_neighbor_restriction:
            # use color codes to identify unique clusters of faces
            colors, clusters, cluster_ids = np.unique(cluster_env.face_colors,
                                                      axis=0,
                                                      return_index=True,
                                                      return_inverse=True)

            # make a map between point IDs and faces
            point_face_map = [[] for i in range(cluster_env.num_points)]

            for f in range(cluster_env.num_faces):
                for i in range(3):
                    point_face_map[cluster_env.faces[f, i]].append(f)

            tree = KDTree(
                cluster_env.points)  # make tree with set of unique points

            kdt_data = KDTreeData(tree, colors, clusters, cluster_ids,
                                  cluster_env.points, cluster_env.faces,
                                  point_face_map)
        else:
            kdt_data = None

        t1 = time.time()
        print("Preprocessing the cluster environment takes: " + str(t1 - t0))
        t0 = time.time()

        # cluster_env_remeshed = pymesh.form_mesh(cluster_env.points, cluster_env.faces)
        # cluster_env_remeshed, _ = pymesh.split_long_edges(cluster_env_remeshed, optimization_options.dist_threshold)
        # cluster_env_remeshed = Mesh(cluster_env_remeshed.vertices, cluster_env_remeshed.faces,
        #                             options=optimization_options)  # TODO: REMOVE
        cluster_env_remeshed = copy.deepcopy(
            cluster_env)  # BANDAID SPEEDUP PRIOR TO PROPER REMOVAL.

        t1 = time.time()
        print("Remeshing the cluster environment takes: " + str(t1 - t0))
        t0 = time.time()
    else:
        cluster_env = None
        kdt_data = None
        cluster_env_remeshed = None

    surfaces = []
    surf_files = glob.glob(file_path_prototype + "*")
    # print("Surf Files:")
    # print(str(surf_files))
    for fp in range(len(surf_files)):
        # print("Processing: " + str(fp))
        mesh = import_ply(surf_files[fp],
                          post_process=False,
                          options=optimization_options,
                          kdt_data=kdt_data)
        if mesh.faces is None or mesh.points is None:
            print("PROBLEM!")
        if mesh.is_valid:
            surfaces.append(mesh)
        else:
            warnings.warn("Warning: mesh " + str(surf_files[fp]) +
                          " omitted due to invalid geometry.")
    if len(surfaces) == 0:
        surfaces = None

    t1 = time.time()
    print("Loading min area surfaces took: " + str(t1 - t0))
    t0 = time.time()

    if target_path_prototype is not None and target_path_prototype != "":
        surf_files = glob.glob(target_path_prototype)
        targets = []
        for fp in surf_files:
            # print("Processing: " + str(fp))
            mesh = import_ply(fp,
                              post_process=False,
                              options=optimization_options)
            if mesh.is_valid:
                targets.append(mesh)
            else:
                warnings.warn("Warning: mesh " + str(fp) +
                              " omitted due to invalid geometry.")
        if len(targets) > 0:
            target = targets[0]
            for t in range(len(targets)):
                if t != 0:
                    target += targets[t]
        else:
            target = None
    else:
        target = None

    t1 = time.time()
    print("Loading target mesh took: " + str(t1 - t0))
    t0 = time.time()

    if full_env_path is not None:
        full_env = import_ply(full_env_path, is_plane_mesh=False)
    else:
        full_env = None

    t1 = time.time()
    print("Loading the full mesh environment took: " + str(t1 - t0))

    env = MeshEnvironment(surfaces=surfaces,
                          n_points=N_points,
                          target=target,
                          obstacles=None,
                          clust_env=cluster_env,
                          full_env=full_env,
                          opt_options=optimization_options,
                          reorient_mesh=reorient_mesh,
                          cluster_env_remeshed=cluster_env_remeshed,
                          full_env_path=full_env_path,
                          clust_env_path=cluster_env_path)
    return env
예제 #8
0
def environment_1(obstructions=True,
                  target="A",
                  dimension=2,
                  optimization_options=CameraPlacementOptions()):
    height = 2.75

    room_coords = np.array([[20, 10], [20, 20], [10, 20], [10, 15], [5, 15],
                            [5, 10]])

    ceiling_coords = room_coords
    perch_areas = np.array([[[5.5, 10], [10.75, 10]], [[13.5, 10], [18.75,
                                                                    10]],
                            [[20, 10.25], [20, 18.75]],
                            [[19.75, 20], [10.5, 20]],
                            [[10, 19.25], [10, 15.25]], [[7.5, 15], [5.25,
                                                                     15]],
                            [[5, 14.75], [5, 10.5]]])

    if target == "A":  # center of main room portion
        target_coords = np.array([[13, 14], [15, 14], [14, 16], [12, 17]])
    elif target == "B":  # center of side annex
        target_coords = np.array([[6, 12], [8, 12], [7, 14], [5.5, 14.5]])
    elif target == "C":  # hugging bottom right corner
        target_coords = np.array([[18, 10.5], [19.5, 11], [19, 11.5],
                                  [18.5, 12]])
    else:  # entire room is target
        target_coords = room_coords

    obstruction1 = np.array([[10, 9.98], [20.02, 9.98], [20.02, 20.02],
                             [9.98, 20.02], [9.98, 15.02], [4.98, 15.02],
                             [4.98, 9.98]])
    obstruction2 = np.array([[13, 12], [15, 12.5], [15, 13.], [13, 12.75]])
    obstruction3 = np.array([[13.25, 18], [14, 18], [14, 18.5], [13.25, 18.5]])

    if obstructions:
        obstruction_polygons = [obstruction1, obstruction2, obstruction3]
    else:
        obstruction_polygons = [obstruction1]  # room walls only

    using_o3d = False  #

    if dimension == 3:
        # IN 3D, DEFINE EVERYTHING AS OPEN3D POINT CLOUD
        ceiling_coords = add_z_axis(room_coords, height)
        target_coords = add_z_axis(target_coords, 0)
        # convert ceiling to point cloud
        if using_o3d:
            ceiling = o3d.geometry.PointCloud()
            ceiling.points = o3d.utility.Vector3dVector(ceiling_coords)
            ceiling_coords = ceiling

            ceiling_poly = convert_PointCloud_to_Mesh(ceiling_coords)
            # visualize_o3d(ceiling_coords)
            visualize_o3d(ceiling_poly)

            room_coords = convert_2D_poly_list_to_PointCloud(
                room_coords, height)
            perch_areas = convert_2D_poly_list_to_PointCloud(
                perch_areas, height)

            obstruction1 = convert_2D_poly_list_to_PointCloud(
                obstruction1, height)
            obstruction2 = convert_2D_poly_list_to_PointCloud(
                obstruction2, height)
            obstruction3 = convert_2D_poly_list_to_PointCloud(
                obstruction3, height)

        else:
            room_coords = convert_2D_Poly_to_3D_Walls(room_coords, height)

            pa = []
            for i in range(len(perch_areas)):
                pa.extend(
                    convert_2D_Poly_to_3D_Walls_PA_ONLY(
                        perch_areas[i, :, :], height))
            perch_areas = pa

            obstruction1 = convert_2D_Poly_to_3D_Walls(obstruction1, height)
            obstruction2 = convert_2D_Poly_to_3D_Walls(obstruction2, height)
            obstruction3 = convert_2D_Poly_to_3D_Walls(obstruction3, height)

        # compile all obstructions into a single list
        if obstructions:
            obstruction2.extend(obstruction3)
            obstruction1.extend(obstruction2)
            obstruction_polygons = obstruction1
        else:
            obstruction_polygons = obstruction1  # room walls only

    env = Environment(walls=room_coords,
                      n_points=100,
                      dimension=dimension,
                      target=target_coords,
                      obstacles=obstruction_polygons,
                      perch_regions=perch_areas,
                      opt_options=optimization_options,
                      ceiling=ceiling_coords)

    return env