Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support Author-namedspaced Thumbnails and Revamp building_map_generator #132

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 50 additions & 0 deletions building_map_tools/building_map_generator/_init_argparse.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import argparse

# Init overall parser and subparser
parser = argparse.ArgumentParser(
prog="building_map_generator",
description="Generate .world files, map models, and navigation maps"
"for running in Gazebo or Ignition!"
)
subparsers = parser.add_subparsers(help="Commands:", dest="command")

# Init shared parser
sim_parser = argparse.ArgumentParser(add_help=False)
sim_parser.add_argument("INPUT", type=str,
help="Input building.yaml file to process")
sim_parser.add_argument("OUTPUT_WORLD", type=str,
help="Name of the .world file to output")
sim_parser.add_argument("OUTPUT_MODEL_DIR", type=str,
help="Path to output the map model files")
sim_parser.add_argument("-o", "--options", type=str, nargs='*', default=[],
help="Generator options")

# Create subparsers for Gazebo, Ignition, and Nav generation
gazebo_parser = subparsers.add_parser(
'gazebo',
help='Generate .world file and map model.sdf for Gazebo',
parents=[sim_parser]
)
gazebo_parser.add_argument("-n", "--no_download", default=False,
const=True, action="store_const",
help="Do not download missing models from Fuel")
gazebo_parser.add_argument("-m", "--model_path", type=str,
help="Gazebo model path to check for models")
gazebo_parser.add_argument("-c", "--cache", type=str,
help="Path to pit_crew model cache")


ignition_parser = subparsers.add_parser(
'ignition',
help='Generate .world file and map model.sdf for Ignition',
parents=[sim_parser]
)

nav_parser = subparsers.add_parser(
'nav',
help='Generate nav map .yaml file',
)
nav_parser.add_argument("INPUT", type=str,
help="Input building.yaml file to process")
nav_parser.add_argument("OUTPUT_DIR", type=str,
help="Path to output the nav .yaml files")
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
#!/usr/bin/env python3

from building_map.generator import Generator
from building_map_generator._init_argparse import parser

import pit_crew
import logging
import sys

handler = logging.StreamHandler(sys.stdout)
handler.setFormatter(pit_crew.PitCrewFormatter())
logger = logging.getLogger()
logger.addHandler(handler)
logger.setLevel(logging.INFO)


def main():
args = parser.parse_args()
g = Generator()

if args.command == "gazebo":
# Construct model set
model_set = set()

if not args.no_download:
building = g.parse_editor_yaml(args.INPUT)

for _, level in building.levels.items():
for model in level.models:
model_set.add(model.model_name)

missing_models = pit_crew.get_missing_models(
model_set,
model_path=args.model_path,
cache_file_path=args.cache
)

for downloadable_model in missing_models['downloadable']:
model_name, author_name = downloadable_model

# TODO: For now it just picks the first author
# When model authors are put into the thumbnails, then we can
# use that instead
logger.info("\nDownloading %s by %s from Fuel"
% (model_name, author_name[0]))

pit_crew.download_model(model_name, author_name[0],
download_path=args.model_path)

logger.warning("\nUnavailable models (not in local or Fuel): %s"
% missing_models['missing'])

g.generate_gazebo_sdf(
args.INPUT,
args.OUTPUT_WORLD,
args.OUTPUT_MODEL_DIR,
args.options
)

if args.command == "ignition":
g.generate_ignition_sdf(
args.INPUT,
args.OUTPUT_WORLD,
args.OUTPUT_MODEL_DIR,
args.options
)

if args.command == "nav":
g.generate_nav(args.INPUT, args.OUTPUT_DIR)

if __name__ == "__main__":
main()
20 changes: 0 additions & 20 deletions building_map_tools/building_map_generators/building_map_gazebo.py

This file was deleted.

This file was deleted.

12 changes: 0 additions & 12 deletions building_map_tools/building_map_generators/building_map_nav.py

This file was deleted.

11 changes: 4 additions & 7 deletions building_map_tools/setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
'building_map',
'building_map.doors',
'building_map_server',
'building_map_generators',
'building_map_generator',
'pit_crew'],
py_modules=[],
data_files=[
Expand All @@ -23,7 +23,7 @@
),
(
'share/' + package_name + '/textures',
glob('building_map_generators/textures/*.png')
glob('building_map_generator/textures/*.png')
),
],
install_requires=['setuptools', 'shapely', 'pyyaml'],
Expand All @@ -47,11 +47,8 @@
'console_scripts': [
'building_map_server = '
'building_map_server.building_map_server:main',
'building_map_gazebo = '
'building_map_generators.building_map_gazebo:main',
'building_map_ignition = '
'building_map_generators.building_map_ignition:main',
'building_map_nav = building_map_generators.building_map_nav:main'
'building_map_generator = '
'building_map_generator.building_map_generator:main',
],
},
)
3 changes: 2 additions & 1 deletion test_maps/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,10 @@ foreach(path ${traffic_editor_paths})
set(output_model_dir ${output_dir}/models)

# first, generate the world
message("BUILDING WORLDFILE WITH COMMAND: ros2 run building_map_tools building_map_generator gazebo ${map_path} ${output_world_path} ${output_model_dir}")
add_custom_command(
OUTPUT ${output_world_path}
COMMAND ros2 run building_map_tools building_map_gazebo ${map_path} ${output_world_path} ${output_model_dir}
COMMAND ros2 run building_map_tools building_map_generator gazebo ${map_path} ${output_world_path} ${output_model_dir}
DEPENDS ${map_path}
)

Expand Down
1 change: 1 addition & 0 deletions traffic_editor/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ ExternalProject_Add(thumbnails_repo

add_dependencies(traffic-editor thumbnails_repo)


install(
TARGETS traffic-editor
LIBRARY DESTINATION lib
Expand Down
12 changes: 6 additions & 6 deletions traffic_editor/thumbnail_generator/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ This is the pipeline for generating thumbnails to be used in `traffic_editor`.
* ROS Melodic
* Gazebo-9

Install all the other required packages,
Install all the other required packages, **and be sure to build all packages in the `traffic_editor` package**

```bash
sudo apt install \
Expand Down Expand Up @@ -39,7 +39,7 @@ Create a green screen world in `gazebo`, and start spawning models listed in you
./scripts/start_gazebo_screen.sh green

# start the spawning and photo-taking script in a second terminal
./scripts/top_view_generator.py -m test/model_list.yaml -o images/green
./scripts/top_view_generator.py test/model_list.yaml images/green
```

The orthogonal views of the models with a green screen will have been saved in the folder `images/green/`. Next, do the same with a white screen,
Expand All @@ -49,15 +49,15 @@ The orthogonal views of the models with a green screen will have been saved in t
./scripts/start_gazebo_screen.sh white

# in a second terminal
./scripts/top_view_generator.py -m test/model_list.yaml -o images/white
./scripts/top_view_generator.py test/model_list.yaml images/white
```

Similarly, the folder `images/white/` will have been populated when the script finishes.

The contours of the models are then extracted from the green-screened images using OpenCV to generate a transparency mask, used for cropping the white-background images, so that it stays centered and is as small as possible. This can be done by calling,

```bash
./scripts/crop.py -m test/model_list.yaml -g images/green -w images/white -o images/cropped
./scripts/crop.py test/model_list.yaml -o images/cropped -g images/green -w images/white
```

The generated thumbnails in `images/cropped` can then be added to `traffic_editor/thumbnails/images/`, while the model names need to be updated to `traffic_editor/thumbnails/model_list.yaml`.
Expand All @@ -67,13 +67,13 @@ The generated thumbnails in `images/cropped` can then be added to `traffic_edito
A new model list `.yaml` file can be generated using the utility script, where an optional blacklisted model names can be added, to avoid creating moving models or agents,

```bash
./scripts/generate_model_list.py -d MODEL_DIR -b test/model_blacklist.yaml -o test/output_model_list.yaml
./scripts/generate_model_list.py output_model_list.yaml -d MODEL_DIR -b test/model_blacklist.yaml
```

In the event that merging multiple model lists is required, a different utility script can be used,

```bash
./scripts/merge_model_lists.py -s test/model_list.yaml -d test/copied_model_list.yaml
./scripts/merge_model_lists.py test/merged_model_list.yaml -s test/extra_model_list.yaml
```

# Credits
Expand Down
52 changes: 39 additions & 13 deletions traffic_editor/thumbnail_generator/scripts/crop.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,30 +77,56 @@ def crop(green_img, white_img):
if __name__ == '__main__':
parser = argparse.ArgumentParser()
parser.add_argument(
'-m', '--model-list', default='../test/model_list.yaml',
help='Path of model_list.yaml')
'model_list', default='../test/model_list.yaml',
help='Path of model_list.yaml'
)
parser.add_argument(
'-g', '--green-img-dir', default='../images/green/',
help='Directory filled with green screened model images')
'-o', '--output_dir',
default='../images/cropped/',
help='Directory where the cropped output images will be saved'
)
parser.add_argument(
'-w', '--white-img-dir', default='../images/white/',
help='Directory f illed with white screened model images')
'-g', '--green-img-dir', default='../images/green/',
help='Directory filled with green screened model images'
)
parser.add_argument(
'-o', '--output-dir', default='../images/cropped/',
help='Directory where the cropped output images will be saved')
'-w', '--white-img-dir', default='../images/white/',
help='Directory filled with white screened model images'
)
args = parser.parse_args(sys.argv[1:])

with open(args.model_list) as f:
y = yaml.load(f)

dirs = [os.path.expanduser(args.output_dir),
os.path.expanduser(args.green_img_dir),
os.path.expanduser(args.white_img_dir)]

# Make dirs if they dont exist
for dir in dirs:
try:
os.makedirs(dir)
print("Made diretory: {}".format(dir))
except Exception:
pass

for model_name in y['models']:
green_img = cv2.imread(
os.path.join(args.green_img_dir, '{}.png'.format(model_name)))
white_img = cv2.imread(
os.path.join(args.white_img_dir, '{}.png'.format(model_name)))
green_img = cv2.imread(os.path.join(
os.path.expanduser(args.green_img_dir),
'{}.png'.format(model_name)
)
)
white_img = cv2.imread(os.path.join(
os.path.expanduser(args.white_img_dir),
'{}.png'.format(model_name)
)
)

output_filepath = os.path.join(
args.output_dir, '{}.png'.format(model_name))
os.path.expanduser(args.output_dir),
'{}.png'.format(model_name)
)

print('generating {}'.format(output_filepath))

white_img_cropped = crop(green_img, white_img)
Expand Down
Loading