Last active
May 15, 2019 09:28
-
-
Save seenitall/622a5dd016ee36910485108010874699 to your computer and use it in GitHub Desktop.
Polygon interpolation functions in numpy
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import numpy as np | |
import cv2 | |
import math | |
import torch | |
###### POLYGON INTERPOLATION FUNCTIONS NUMPY ###### | |
def segments(poly): | |
"""A sequence of (x,y) numeric coordinates pairs """ | |
return zip(poly, poly[1:] + [poly[0]]) | |
def perimeter(poly): | |
"""A sequence of (x,y) numeric coordinates pairs """ | |
return abs(sum(math.hypot(x0-x1, y0-y1) for ((x0, y0), (x1, y1)) in segments(poly))) | |
def average_int_distance(poly): | |
return abs(np.mean([math.hypot(x0-x1, y0-y1) for ((x0, y0), (x1, y1)) in segments(poly)])) | |
def median_int_distance(poly): | |
return abs(np.median([math.hypot(x0-x1, y0-y1) for ((x0, y0), (x1, y1)) in segments(poly)])) | |
def quantile_int_distance(poly, quantile): | |
return abs(np.quantile([math.hypot(x0-x1, y0-y1) for ((x0, y0), (x1, y1)) in segments(poly)], quantile)) | |
def n_int_distance_above_quantile(poly, int_quantile_dist): | |
total = sum((math.hypot(x0-x1, y0-y1) > int_quantile_dist) for ((x0, y0), (x1, y1)) in segments(poly)) | |
return total | |
def interpolate_polygon(polygon, K, device): | |
""" | |
interpolation in Pytorch: https://github.com/pytorch/pytorch/issues/1552 | |
https://gist.github.com/peteflorence/a1da2c759ca1ac2b74af9a83f69ce20e | |
""" | |
if len(polygon) > K: | |
"""randomly select K points""" | |
random_ix = np.sort(np.random.randint(len(polygon), size=K)) | |
new_points = [polygon[i] for i in random_ix] | |
assert len(new_points) == K | |
return new_points | |
if not isinstance(polygon, list): | |
lpol = polygon.tolist() | |
n_points_per_int = (K - len(lpol)) / len(lpol) | |
remaining_points = (K - len(lpol)) % len(lpol) | |
quantile = 1 - math.modf(n_points_per_int)[0] | |
new_points = [] | |
per = perimeter(lpol) | |
try: | |
int_quantile_dist = quantile_int_distance(lpol, quantile) | |
except: | |
print(math.modf(n_points_per_int), len(lpol), polygon) | |
n_above_quantile = n_int_distance_above_quantile(lpol, int_quantile_dist) | |
if n_above_quantile > remaining_points: | |
n_above_quantile = remaining_points | |
n_to_dist = remaining_points // n_above_quantile if n_above_quantile > 0 else 0 | |
for _, (p0, p1) in enumerate(zip(lpol, lpol[1::] + lpol[:1])): | |
n_points = n_points_per_int | |
dist = math.hypot(p0[0] - p1[0], p0[1] - p1[1]) # math.sqrt((x0-x1)**2 + (y0-y1)**2) | |
if dist > int_quantile_dist and remaining_points > 0: | |
n_points += n_to_dist | |
remaining_points -= n_to_dist | |
deltas = np.sort(np.random.random_sample(size=int(n_points))) | |
x_points = [p0[0] + i * (p1[0] - p0[0]) for i in deltas] | |
y_points = np.interp(x_points, [p0[0], p1[0]], [p0[1], p1[1]]) | |
new_points.append(p0) | |
for x, y in zip(x_points, y_points): | |
new_points.append([x, y]) | |
assert len(new_points) <= K, (len(new_points), len(lpol), polygon) | |
pad_len = K - len(new_points) | |
last_point = new_points[-1] if len(new_points) > 0 else 0. | |
new_points = np.pad(new_points, ((0, pad_len), (0, 0)), mode='constant', constant_values=((0,last_point),(0,0))) | |
else: | |
lpol = polygon | |
new_points = [[0., 0.]] * K | |
new_points = np.array(new_points) | |
return new_points |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment