MapLocNet / osm /raster.py
wangerniu
Commit message.
124ba77
# Copyright (c) Meta Platforms, Inc. and affiliates.
from typing import Dict, List
import cv2
import numpy as np
import torch
from utils.geo import BoundaryBox
from .data import MapArea, MapLine, MapNode
from .parser import Groups
class Canvas:
def __init__(self, bbox: BoundaryBox, ppm: float):
self.bbox = bbox
self.ppm = ppm
self.scaling = bbox.size * ppm
self.w, self.h = np.ceil(self.scaling).astype(int)
self.clear()
def clear(self):
self.raster = np.zeros((self.h, self.w), np.uint8)
def to_uv(self, xy: np.ndarray):
xy = self.bbox.normalize(xy)
xy[..., 1] = 1 - xy[..., 1]
s = self.scaling
if isinstance(xy, torch.Tensor):
s = torch.from_numpy(s).to(xy)
return xy * s - 0.5
def to_xy(self, uv: np.ndarray):
s = self.scaling
if isinstance(uv, torch.Tensor):
s = torch.from_numpy(s).to(uv)
xy = (uv + 0.5) / s
xy[..., 1] = 1 - xy[..., 1]
return self.bbox.unnormalize(xy)
def draw_polygon(self, xy: np.ndarray):
uv = self.to_uv(xy)
cv2.fillPoly(self.raster, uv[None].astype(np.int32), 255)
def draw_multipolygon(self, xys: List[np.ndarray]):
uvs = [self.to_uv(xy).round().astype(np.int32) for xy in xys]
cv2.fillPoly(self.raster, uvs, 255)
def draw_line(self, xy: np.ndarray, width: float = 1):
uv = self.to_uv(xy)
cv2.polylines(
self.raster, uv[None].round().astype(np.int32), False, 255, thickness=width
)
def draw_cell(self, xy: np.ndarray):
if not self.bbox.contains(xy):
return
uv = self.to_uv(xy)
self.raster[tuple(uv.round().astype(int).T[::-1])] = 255
def render_raster_masks(
nodes: List[MapNode],
lines: List[MapLine],
areas: List[MapArea],
canvas: Canvas,
) -> Dict[str, np.ndarray]:
all_groups = Groups.areas + Groups.ways + Groups.nodes
masks = {k: np.zeros((canvas.h, canvas.w), np.uint8) for k in all_groups}
for area in areas:
canvas.raster = masks[area.group]
outlines = area.outers + area.inners
canvas.draw_multipolygon(outlines)
if area.group == "building":
canvas.raster = masks["building_outline"]
for line in outlines:
canvas.draw_line(line)
for line in lines:
canvas.raster = masks[line.group]
canvas.draw_line(line.xy)
for node in nodes:
canvas.raster = masks[node.group]
canvas.draw_cell(node.xy)
return masks
def mask_to_idx(group2mask: Dict[str, np.ndarray], groups: List[str]) -> np.ndarray:
masks = np.stack([group2mask[k] for k in groups]) > 0
void = ~np.any(masks, 0)
idx = np.argmax(masks, 0)
idx = np.where(void, np.zeros_like(idx), idx + 1) # add background
return idx
def render_raster_map(masks: Dict[str, np.ndarray]) -> np.ndarray:
areas = mask_to_idx(masks, Groups.areas)
ways = mask_to_idx(masks, Groups.ways)
nodes = mask_to_idx(masks, Groups.nodes)
return np.stack([areas, ways, nodes])