From 05dbf7220e8386eb2337502c4d4851fc8dce30cd Mon Sep 17 00:00:00 2001 From: danielgordon10 <danielgordon10@gmail.com> Date: Fri, 26 Apr 2019 16:03:27 -0700 Subject: [PATCH] Small changes to the topdown map interface to make plotting the agent easier (#76) * added conversion of matrix map to color picture * added example --- examples/shortest_path_follower_example.py | 69 ++++++++++++++++++---- habitat/tasks/nav/nav_task.py | 39 ++++++------ habitat/utils/visualizations/maps.py | 29 +++++++-- 3 files changed, 103 insertions(+), 34 deletions(-) diff --git a/examples/shortest_path_follower_example.py b/examples/shortest_path_follower_example.py index e6cd147d3..b3f8ca7b9 100644 --- a/examples/shortest_path_follower_example.py +++ b/examples/shortest_path_follower_example.py @@ -7,28 +7,69 @@ import os import shutil -import imageio - +import cv2 import habitat +import numpy as np from habitat.tasks.nav.shortest_path_follower import ShortestPathFollower +from habitat.utils.visualizations import maps +from habitat.utils.visualizations.utils import images_to_video IMAGE_DIR = os.path.join("examples", "images") if not os.path.exists(IMAGE_DIR): os.makedirs(IMAGE_DIR) +class SimpleRLEnv(habitat.RLEnv): + def get_reward_range(self): + return [-1, 1] + + def get_reward(self, observations): + return 0 + + def get_done(self, observations): + return self.habitat_env.episode_over + + def get_info(self, observations): + return self.habitat_env.get_metrics() + + +def draw_top_down_map(info, heading, output_size): + top_down_map = maps.colorize_topdown_map(info["top_down_map"]["map"]) + original_map_size = top_down_map.shape[:2] + map_scale = np.array( + (1, original_map_size[1] * 1.0 / original_map_size[0]) + ) + new_map_size = np.round(output_size * map_scale).astype(np.int32) + # OpenCV expects w, h but map size is in h, w + top_down_map = cv2.resize(top_down_map, (new_map_size[1], new_map_size[0])) + + map_agent_pos = info["top_down_map"]["agent_map_coord"] + map_agent_pos = np.round( + map_agent_pos * new_map_size / original_map_size + ).astype(np.int32) + top_down_map = maps.draw_agent( + top_down_map, + map_agent_pos, + heading - np.pi / 2, + agent_radius_px=top_down_map.shape[0] / 40, + ) + return top_down_map + + def shortest_path_example(mode): config = habitat.get_config(config_file="tasks/pointnav.yaml") - env = habitat.Env(config=config) + config.TASK.MEASUREMENTS.append("TOP_DOWN_MAP") + config.TASK.SENSORS.append("HEADING_SENSOR") + env = SimpleRLEnv(config=config) goal_radius = env.episodes[0].goals[0].radius if goal_radius is None: goal_radius = config.SIMULATOR.FORWARD_STEP_SIZE - follower = ShortestPathFollower(env.sim, goal_radius, False) + follower = ShortestPathFollower(env.habitat_env.sim, goal_radius, False) follower.mode = mode print("Environment creation successful") for episode in range(3): - observations = env.reset() + env.reset() dirname = os.path.join( IMAGE_DIR, "shortest_path_example", mode, "%02d" % episode ) @@ -36,16 +77,20 @@ def shortest_path_example(mode): shutil.rmtree(dirname) os.makedirs(dirname) print("Agent stepping around inside environment.") - count_steps = 0 - while not env.episode_over: + images = [] + while not env.habitat_env.episode_over: best_action = follower.get_next_action( - env.current_episode.goals[0].position + env.habitat_env.current_episode.goals[0].position ) - observations = env.step(best_action.value) - count_steps += 1 + observations, reward, done, info = env.step(best_action.value) im = observations["rgb"] - imageio.imsave(os.path.join(dirname, "%03d.jpg" % count_steps), im) - print("Episode finished after {} steps.".format(count_steps)) + top_down_map = draw_top_down_map( + info, observations["heading"], im.shape[0] + ) + output_im = np.concatenate((im, top_down_map), axis=1) + images.append(output_im) + images_to_video(images, dirname, "trajectory") + print("Episode finished") def main(): diff --git a/habitat/tasks/nav/nav_task.py b/habitat/tasks/nav/nav_task.py index e1b19731f..95fbda44e 100644 --- a/habitat/tasks/nav/nav_task.py +++ b/habitat/tasks/nav/nav_task.py @@ -547,7 +547,13 @@ class TopDownMap(habitat.Measure): + self._grid_delta, ] - self._metric = house_map + self._metric = { + "map": house_map, + "agent_map_coord": ( + map_agent_x - (self._ind_x_min - self._grid_delta), + map_agent_y - (self._ind_y_min - self._grid_delta), + ), + } def update_map(self, agent_position): a_x, a_y = maps.to_grid( @@ -558,24 +564,21 @@ class TopDownMap(habitat.Measure): self._map_resolution, ) # Don't draw over the source point - color = ( - min(self._step_count * 245 / self._config.MAX_EPISODE_STEPS, 245) - + 10 - if self._top_down_map[a_x, a_y] != maps.MAP_SOURCE_POINT_INDICATOR - else maps.MAP_SOURCE_POINT_INDICATOR - ) - color = int(color) + if self._top_down_map[a_x, a_y] != maps.MAP_SOURCE_POINT_INDICATOR: + color = 10 + min( + self._step_count * 245 // self._config.MAX_EPISODE_STEPS, 245 + ) - thickness = int( - np.round(self._map_resolution[0] * 2 / MAP_THICKNESS_SCALAR) - ) - cv2.line( - self._top_down_map, - self._previous_xy_location, - (a_y, a_x), - color, - thickness=thickness, - ) + thickness = int( + np.round(self._map_resolution[0] * 2 / MAP_THICKNESS_SCALAR) + ) + cv2.line( + self._top_down_map, + self._previous_xy_location, + (a_y, a_x), + color, + thickness=thickness, + ) self._previous_xy_location = (a_y, a_x) return self._top_down_map, a_x, a_y diff --git a/habitat/utils/visualizations/maps.py b/habitat/utils/visualizations/maps.py index 9dca6e248..c44302acd 100644 --- a/habitat/utils/visualizations/maps.py +++ b/habitat/utils/visualizations/maps.py @@ -4,12 +4,13 @@ # This source code is licensed under the MIT license found in the # LICENSE file in the root directory of this source tree. -import numpy as np +import os +from typing import List, Tuple, Optional + import cv2 import imageio +import numpy as np import scipy.ndimage -import os -from typing import List, Tuple, Optional from habitat.core.simulator import Simulator from habitat.utils.visualizations import utils @@ -32,6 +33,16 @@ MAP_BORDER_INDICATOR = 2 MAP_SOURCE_POINT_INDICATOR = 4 MAP_TARGET_POINT_INDICATOR = 6 +TOP_DOWN_MAP_COLORS = np.full((256, 3), 150, dtype=np.uint8) +TOP_DOWN_MAP_COLORS[10:] = cv2.applyColorMap( + np.arange(246, dtype=np.uint8), cv2.COLORMAP_JET +).squeeze(1)[:, ::-1] +TOP_DOWN_MAP_COLORS[MAP_INVALID_POINT] = [255, 255, 255] +TOP_DOWN_MAP_COLORS[MAP_VALID_POINT] = [150, 150, 150] +TOP_DOWN_MAP_COLORS[MAP_BORDER_INDICATOR] = [50, 50, 50] +TOP_DOWN_MAP_COLORS[MAP_SOURCE_POINT_INDICATOR] = [0, 0, 200] +TOP_DOWN_MAP_COLORS[MAP_TARGET_POINT_INDICATOR] = [200, 0, 0] + def draw_agent( image: np.ndarray, @@ -51,7 +62,7 @@ def draw_agent( # Rotate before resize to keep good resolution. rotated_agent = scipy.ndimage.interpolation.rotate( - AGENT_SPRITE, agent_rotation * -180 / np.pi + AGENT_SPRITE, agent_rotation * 180 / np.pi ) # Rescale because rotation may result in larger image than original, but # the agent sprite size should stay the same. @@ -312,3 +323,13 @@ def get_topdown_map( top_down_map[range_x[0] : range_x[1], range_y[0] : range_y[1]] ) return top_down_map + + +def colorize_topdown_map(top_down_map: np.ndarray) -> np.ndarray: + """Convert the top down map to RGB based on the indicator values. + Args: + top_down_map: A non-colored version of the map. + Returns: + A colored version of the top-down map. + """ + return TOP_DOWN_MAP_COLORS[top_down_map] -- GitLab