mirror of
https://github.com/SikongJueluo/Mini-Nav.git
synced 2026-07-13 04:25:32 +08:00
refactor(sync): improve topdown rendering and make justfile adapt to windows
This commit is contained in:
25
.justfile
25
.justfile
@@ -1,17 +1,20 @@
|
|||||||
|
remote_root := "ial-gpu-workstation-1:/home/ial-pangyg/docker-workspace/projects/mini-nav"
|
||||||
|
rsync_flags := "-avLh --progress --stats --itemize-changes"
|
||||||
|
upload_excludes := "--exclude=.jj/ --exclude=.git/ --exclude=.devenv/ --exclude=.direnv/ --exclude=deps/ --exclude=outputs/ --exclude=data/versioned_data/ --exclude=datasets/"
|
||||||
|
|
||||||
upload:
|
upload:
|
||||||
rsync -avLh --progress --stats --itemize-changes \
|
if command -v cygpath >/dev/null 2>&1 || test -n "${MSYSTEM:-}" || test -n "${CYGWIN:-}"; then \
|
||||||
--exclude='.jj/' \
|
env MSYS2_ARG_CONV_EXCL='*' rsync {{ rsync_flags }} {{ upload_excludes }} . {{ remote_root }}/; \
|
||||||
--exclude='.git/' \
|
else \
|
||||||
--exclude='.devenv/' \
|
rsync {{ rsync_flags }} {{ upload_excludes }} . {{ remote_root }}/; \
|
||||||
--exclude='.direnv/' \
|
fi
|
||||||
--exclude='deps/' \
|
|
||||||
--exclude='outputs/' \
|
|
||||||
--exclude='data/versioned_data/' \
|
|
||||||
. ial-gpu-workstation-1:/home/ial-pangyg/docker-workspace/projects/mini-nav/
|
|
||||||
|
|
||||||
download:
|
download:
|
||||||
rsync -avLh --progress --stats --itemize-changes \
|
if command -v cygpath >/dev/null 2>&1 || test -n "${MSYSTEM:-}" || test -n "${CYGWIN:-}"; then \
|
||||||
ial-gpu-workstation-1:/home/ial-pangyg/docker-workspace/projects/mini-nav/outputs .
|
env MSYS2_ARG_CONV_EXCL='*' rsync {{ rsync_flags }} {{ remote_root }}/outputs .; \
|
||||||
|
else \
|
||||||
|
rsync {{ rsync_flags }} {{ remote_root }}/outputs .; \
|
||||||
|
fi
|
||||||
|
|
||||||
sync-pkgs:
|
sync-pkgs:
|
||||||
# micromamba env create -f ./environment.yml
|
# micromamba env create -f ./environment.yml
|
||||||
|
|||||||
@@ -1,9 +1,13 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from dataclasses import dataclass, field
|
from dataclasses import dataclass, field
|
||||||
from importlib import import_module
|
|
||||||
from typing import Any, Sequence
|
from typing import Any, Sequence
|
||||||
|
|
||||||
|
import numpy as np
|
||||||
|
from matplotlib.backends.backend_agg import FigureCanvasAgg
|
||||||
|
from matplotlib.figure import Figure
|
||||||
|
from PIL import Image
|
||||||
|
|
||||||
|
|
||||||
@dataclass(frozen=True)
|
@dataclass(frozen=True)
|
||||||
class TopDownSceneElements:
|
class TopDownSceneElements:
|
||||||
@@ -28,10 +32,26 @@ def render_topdown_scene_map(
|
|||||||
elements: TopDownSceneElements,
|
elements: TopDownSceneElements,
|
||||||
meters_per_pixel: float,
|
meters_per_pixel: float,
|
||||||
style: TopDownRenderStyle | None = None,
|
style: TopDownRenderStyle | None = None,
|
||||||
maps_module: Any | None = None,
|
) -> Image.Image:
|
||||||
plt_module: Any | None = None,
|
"""Render a top-down scene map as a PIL Image.
|
||||||
use_matplotlib: bool = True,
|
|
||||||
) -> Any:
|
Uses matplotlib Agg backend (non-interactive) to draw room markers and
|
||||||
|
labels on the habitat top-down occupancy map, then returns the result
|
||||||
|
as a PIL Image.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
pathfinder: Habitat pathfinder instance.
|
||||||
|
elements: Scene elements containing room nodes to annotate.
|
||||||
|
meters_per_pixel: Resolution for the top-down map.
|
||||||
|
style: Visual style configuration.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
PIL.Image.Image: Rendered top-down map with annotations.
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
ValueError: If room_nodes is empty or meters_per_pixel <= 0.
|
||||||
|
NotImplementedError: If object_nodes or edges are provided.
|
||||||
|
"""
|
||||||
if not elements.room_nodes:
|
if not elements.room_nodes:
|
||||||
raise ValueError("room_nodes must not be empty")
|
raise ValueError("room_nodes must not be empty")
|
||||||
|
|
||||||
@@ -47,37 +67,33 @@ def render_topdown_scene_map(
|
|||||||
if style is None:
|
if style is None:
|
||||||
style = TopDownRenderStyle()
|
style = TopDownRenderStyle()
|
||||||
|
|
||||||
if maps_module is None:
|
# Import habitat maps internally — treated as required dependency.
|
||||||
maps_module = import_module("habitat.utils.visualizations.maps")
|
from habitat.utils.visualizations import maps
|
||||||
|
|
||||||
|
# Generate raw top-down occupancy map.
|
||||||
map_height = float(elements.room_nodes[0].center[1])
|
map_height = float(elements.room_nodes[0].center[1])
|
||||||
top_down_map = maps_module.get_topdown_map(
|
top_down_map = maps.get_topdown_map(
|
||||||
pathfinder,
|
pathfinder,
|
||||||
height=map_height,
|
height=map_height,
|
||||||
meters_per_pixel=meters_per_pixel,
|
meters_per_pixel=meters_per_pixel,
|
||||||
)
|
)
|
||||||
|
|
||||||
if not use_matplotlib:
|
# Render with matplotlib Agg backend (no GUI required).
|
||||||
return top_down_map
|
fig = Figure(figsize=style.figure_size)
|
||||||
|
_ = FigureCanvasAgg(fig)
|
||||||
if plt_module is None:
|
ax = fig.add_subplot(111)
|
||||||
try:
|
ax.imshow(top_down_map, cmap=style.map_cmap)
|
||||||
plt_module = import_module("matplotlib.pyplot")
|
|
||||||
except ImportError:
|
|
||||||
return top_down_map
|
|
||||||
|
|
||||||
plt_module.figure(figsize=style.figure_size)
|
|
||||||
plt_module.imshow(top_down_map, cmap=style.map_cmap)
|
|
||||||
|
|
||||||
|
# Annotate room positions and labels.
|
||||||
for room_node in elements.room_nodes:
|
for room_node in elements.room_nodes:
|
||||||
grid_y, grid_x = maps_module.to_grid(
|
grid_y, grid_x = maps.to_grid(
|
||||||
float(room_node.center[2]),
|
float(room_node.center[2]),
|
||||||
float(room_node.center[0]),
|
float(room_node.center[0]),
|
||||||
top_down_map.shape,
|
top_down_map.shape,
|
||||||
pathfinder=pathfinder,
|
pathfinder=pathfinder,
|
||||||
)
|
)
|
||||||
plt_module.scatter(grid_x, grid_y, c=style.room_color, s=style.room_marker_size)
|
ax.scatter(grid_x, grid_y, c=style.room_color, s=style.room_marker_size)
|
||||||
plt_module.text(
|
ax.text(
|
||||||
grid_x + style.room_label_offset,
|
grid_x + style.room_label_offset,
|
||||||
grid_y + style.room_label_offset,
|
grid_y + style.room_label_offset,
|
||||||
room_node.room_id,
|
room_node.room_id,
|
||||||
@@ -85,7 +101,12 @@ def render_topdown_scene_map(
|
|||||||
fontsize=8,
|
fontsize=8,
|
||||||
)
|
)
|
||||||
|
|
||||||
plt_module.title(style.title)
|
ax.set_title(style.title)
|
||||||
plt_module.axis("off")
|
ax.axis("off")
|
||||||
plt_module.show()
|
fig.canvas.draw()
|
||||||
return top_down_map
|
|
||||||
|
# Extract RGB pixels from the Agg canvas buffer.
|
||||||
|
rgba = np.asarray(fig.canvas.buffer_rgba(), dtype=np.uint8)
|
||||||
|
rgb = rgba[..., :3].copy()
|
||||||
|
|
||||||
|
return Image.fromarray(rgb)
|
||||||
|
|||||||
@@ -107,21 +107,18 @@ def habitat_setup(HabitatSimulatorConfig, RoomNode, create_habitat_simulator, np
|
|||||||
def render_topdown(
|
def render_topdown(
|
||||||
TopDownSceneElements,
|
TopDownSceneElements,
|
||||||
meters_per_pixel,
|
meters_per_pixel,
|
||||||
|
mo,
|
||||||
render_topdown_scene_map,
|
render_topdown_scene_map,
|
||||||
room_nodes,
|
room_nodes,
|
||||||
sim,
|
sim,
|
||||||
):
|
):
|
||||||
from habitat.utils.visualizations import maps
|
image = render_topdown_scene_map(
|
||||||
from matplotlib import pyplot as plt
|
|
||||||
|
|
||||||
render_topdown_scene_map(
|
|
||||||
pathfinder=sim.pathfinder,
|
pathfinder=sim.pathfinder,
|
||||||
elements=TopDownSceneElements(room_nodes=room_nodes),
|
elements=TopDownSceneElements(room_nodes=room_nodes),
|
||||||
meters_per_pixel=meters_per_pixel,
|
meters_per_pixel=meters_per_pixel,
|
||||||
maps_module=maps,
|
|
||||||
plt_module=plt,
|
|
||||||
)
|
)
|
||||||
return
|
mo.image(image)
|
||||||
|
return (image,)
|
||||||
|
|
||||||
|
|
||||||
@app.cell
|
@app.cell
|
||||||
|
|||||||
Reference in New Issue
Block a user