added some visualization tools for lidar pointclouds

This commit is contained in:
Jan Kowalczyk
2024-04-19 13:38:09 +02:00
parent 0907c89cce
commit 0ee3bc82b5
4 changed files with 395 additions and 0 deletions

140
tools/render2d.py Normal file
View File

@@ -0,0 +1,140 @@
from configargparse import ArgParser, YAMLConfigFileParser, ArgumentDefaultsRawHelpFormatter
from sys import exit
from pathlib import Path
from pointcloudset import Dataset
from rich.progress import track
from pandas import DataFrame
from PIL import Image
import matplotlib.pyplot as plt
from util import (
load_dataset_from_bag,
existing_file,
create_video_from_images,
calculate_average_frame_rate,
get_colormap_with_special_missing_color,
)
def create_2d_projection(
df: DataFrame,
output_file_path: Path,
tmp_file_path: Path,
colormap_name: str,
missing_data_color: str,
reverse_colormap: bool,
):
fig, ax = plt.subplots(figsize=(20.48, 5.12))
ax.imshow(
df,
cmap=get_colormap_with_special_missing_color(colormap_name, missing_data_color, reverse_colormap),
aspect="auto",
)
ax.axis("off")
fig.subplots_adjust(left=0, right=1, top=1, bottom=0)
plt.savefig(tmp_file_path, dpi=100, bbox_inches="tight", pad_inches=0)
plt.close()
img = Image.open(tmp_file_path)
img_resized = img.resize((2048, 512), Image.LANCZOS)
img_resized.save(output_file_path)
def render_2d_images(
dataset: Dataset,
output_images_path: Path,
image_pattern_prefix: str,
tmp_files_path: Path,
colormap_name: str,
missing_data_color: str,
reverse_colormap: bool,
) -> list[Path]:
rendered_images = []
for i, pc in track(enumerate(dataset, 1), description="Rendering images...", total=len(dataset)):
pc.data["horizontal_position"] = pc.data["original_id"] % 2048
image_data = pc.data.pivot(index="ring", columns="horizontal_position", values="range")
normalized_data = (image_data - image_data.min().min()) / (image_data.max().max() - image_data.min().min())
image_path = create_2d_projection(
normalized_data,
output_images_path / f"{image_pattern_prefix}_frame_{i:04d}.png",
tmp_files_path / "tmp.png",
colormap_name,
missing_data_color,
reverse_colormap,
)
rendered_images.append(image_path)
return rendered_images
def main() -> int:
parser = ArgParser(
config_file_parser_class=YAMLConfigFileParser,
default_config_files=["render2d_config.yaml"],
formatter_class=ArgumentDefaultsRawHelpFormatter,
description="Render a 2d projection of a point cloud",
)
parser.add_argument("--render-config-file", is_config_file=True, help="yaml config file path")
parser.add_argument("--input-bag-path", required=True, type=existing_file, help="path to bag file")
parser.add_argument(
"--tmp-files-path", default=Path("./tmp"), type=Path, help="path temporary files will be written to"
)
parser.add_argument(
"--output-images", type=bool, default=True, help="if rendered frames should be outputted as images"
)
parser.add_argument(
"--output-images-path", default=Path("./output"), type=Path, help="path rendered frames should be written to"
)
parser.add_argument(
"--output-video", type=bool, default=True, help="if rendered frames should be outputted as a video"
)
parser.add_argument(
"--output-video-path",
default=Path("./output/2d_render.mp4"),
type=Path,
help="path rendered video should be written to",
)
parser.add_argument("--output-images-prefix", default="2d_render", type=str, help="filename prefix for output")
parser.add_argument("--colormap-name", default="viridis", type=str, help="name of matplotlib colormap to be used")
parser.add_argument(
"--missing-data-color", default="black", type=str, help="name of color to be used for missing data"
)
parser.add_argument("--reverse-colormap", default=True, type=bool, help="if colormap should be reversed")
args = parser.parse_args()
if args.output_images:
args.output_images_path.mkdir(parents=True, exist_ok=True)
args.tmp_files_path = args.output_images_path
else:
args.tmp_files_path.mkdir(parents=True, exist_ok=True)
if args.output_video:
args.output_video_path.parent.mkdir(parents=True, exist_ok=True)
dataset = load_dataset_from_bag(args.input_bag_path)
images = render_2d_images(
dataset,
args.tmp_files_path,
args.output_images_prefix,
args.tmp_files_path,
args.colormap_name,
args.missing_data_color,
args.reverse_colormap,
)
if args.output_video:
input_images_pattern = f"{args.tmp_files_path / args.output_images_prefix}_frame_%04d.png"
create_video_from_images(input_images_pattern, args.output_video_path, calculate_average_frame_rate(dataset))
if not args.output_images:
for image in images:
image.unlink()
return 0
if __name__ == "__main__":
exit(main())