raster2seq / util /poly_ops.py
anas
Initial deployment of Raster2Seq floor plan vectorization API
fadb92b
Raw
History Blame Contribute Delete
3.3 kB
"""
Utilities for polygon manipulation.
"""
import numpy as np
import torch
def is_clockwise(points):
"""Check whether a sequence of points is clockwise ordered"""
# points is a list of 2d points.
assert len(points) > 0
s = 0.0
for p1, p2 in zip(points, points[1:] + [points[0]]):
s += (p2[0] - p1[0]) * (p2[1] + p1[1])
return s > 0.0
def resort_corners(corners):
"""Resort a sequence of corners so that the first corner starts
from upper-left and counterclockwise ordered in image
"""
corners = corners.reshape(-1, 2)
x_y_square_sum = corners[:, 0] ** 2 + corners[:, 1] ** 2
start_corner_idx = np.argmin(x_y_square_sum)
corners_sorted = np.concatenate([corners[start_corner_idx:], corners[:start_corner_idx]])
## sort points clockwise (counterclockwise in image)
if not is_clockwise(corners_sorted[:, :2].tolist()):
corners_sorted[1:] = np.flip(corners_sorted[1:], 0)
return corners_sorted.reshape(-1)
def get_all_order_corners(corners):
"""Get all possible permutation of a polygon"""
length = int(len(corners) / 2)
all_corners = torch.stack([corners.roll(i * 2) for i in range(length)])
return all_corners
def pad_gt_polys(gt_instances, num_queries_per_poly, image_size, drop_rate, device=None):
"""Pad the ground truth polygons so that they have a uniform length"""
thr_length = num_queries_per_poly * 2
room_targets = []
# padding ground truth on-fly
for gt_inst in gt_instances:
room_dict = {}
room_corners = []
corner_labels = []
corner_lengths = []
for i, poly in enumerate(gt_inst.gt_masks.polygons):
corners = torch.from_numpy(poly[0]).to(device)
corners = torch.clip(corners, 0, image_size - 1) / (image_size - 1)
# automatically skip the polygon if it is too long
if len(corners) > thr_length:
continue
corner_lengths.append(len(corners))
corners_pad = torch.zeros(num_queries_per_poly * 2, device=device)
corners_pad[: len(corners)] = corners
labels = torch.ones(int(len(corners) / 2), dtype=torch.int64).to(device)
labels_pad = torch.zeros(num_queries_per_poly, device=device)
labels_pad[: len(labels)] = labels
room_corners.append(corners_pad)
corner_labels.append(labels_pad)
room_classes = gt_inst.gt_classes
if drop_rate > 0.0:
keep_indices = np.where(np.random.rand(len(room_corners)) >= drop_rate)[0].tolist()
if len(keep_indices) > 0: # Only apply drop if we have something left
room_corners = [room_corners[i] for i in keep_indices]
corner_labels = [corner_labels[i] for i in keep_indices]
corner_lengths = [corner_lengths[i] for i in keep_indices]
room_classes = gt_inst.gt_classes[keep_indices]
room_dict = {
"coords": torch.stack(room_corners).to(device),
"labels": torch.stack(corner_labels).to(device),
"lengths": torch.tensor(corner_lengths, device=device),
"room_labels": room_classes.to(device),
}
room_targets.append(room_dict)
return room_targets