Spaces:
Running
Running
import re | |
import numpy as np | |
from itertools import groupby | |
from PIL import Image | |
import math | |
from math import ceil, floor | |
from skimage import draw | |
from random import sample | |
import base64 | |
from io import BytesIO | |
convert = lambda text: int(text) if text.isdigit() else text.lower() | |
natrual_key = lambda key: [convert(c) for c in re.split('([0-9]+)', key)] | |
def points_to_token_string(box, polygons): | |
polygon_strings = [] | |
for polygon in polygons: | |
polygon_string = " ".join([f"<bin_{int(p[0])}_{int(p[1])}>" for p in polygon]) | |
polygon_strings.append(polygon_string) | |
polygon_string = " <separator> ".join(polygon_strings) | |
box_string = " ".join([f"<bin_{int(p[0])}_{int(p[1])}>" for p in box]) | |
token_string = " ".join([box_string, polygon_string]) | |
token_type = [] | |
for token in token_string.split(" "): | |
if "bin" in token: | |
token_type.append(0) # 0 for coordinate tokens | |
else: | |
token_type.append(1) # 1 for separator tokens | |
return token_string, token_type | |
def resize_binary_mask(array, new_size): | |
image = Image.fromarray(array.astype(np.uint8) * 255) | |
image = image.resize(new_size) | |
return np.asarray(image).astype(np.bool_) | |
def close_contour(contour): | |
if not np.array_equal(contour[0], contour[-1]): | |
contour = np.vstack((contour, contour[0])) | |
return contour | |
def binary_mask_to_rle(binary_mask): | |
rle = {'counts': [], 'size': list(binary_mask.shape)} | |
counts = rle.get('counts') | |
for i, (value, elements) in enumerate(groupby(binary_mask.ravel(order='F'))): | |
if i == 0 and value == 1: | |
counts.append(0) | |
counts.append(len(list(elements))) | |
return rle | |
def revert_direction(poly): | |
poly = np.array(poly).reshape(int(len(poly) / 2), 2) | |
poly = poly[::-1, :] | |
return list(poly.flatten()) | |
def reorder_points(poly): | |
poly = np.array(poly) | |
xs = poly[::2] | |
ys = poly[1::2] | |
points = np.array(poly).reshape(int(len(poly) / 2), 2) | |
start = np.argmin(xs ** 2 + ys ** 2) # smallest distance to the origin | |
poly_reordered = np.concatenate([points[start:], points[:start]], 0) | |
return list(poly_reordered.flatten()) | |
def convert_pts(coeffs): | |
pts = [] | |
for i in range(len(coeffs) // 2): | |
pts.append([coeffs[2 * i + 1], coeffs[2 * i]]) # y, x | |
return np.array(pts, np.int32) | |
def get_mask_from_codes(codes, img_size): | |
masks = [np.zeros(img_size)] | |
for code in codes: | |
if len(code) > 0: | |
mask = draw.polygon2mask(img_size, convert_pts(code)) | |
mask = np.array(mask, np.uint8) | |
masks.append(mask) | |
mask = sum(masks) | |
mask = mask > 0 | |
return mask.astype(np.uint8) | |
def is_clockwise(poly): | |
n = len(poly) // 2 | |
xs = poly[::2] | |
xs.append(xs[0]) | |
ys = poly[1::2] | |
ys.append(ys[0]) | |
area = 0 | |
for i in range(n): | |
x1, y1 = xs[i], ys[i] | |
x2, y2 = xs[i + 1], ys[i + 1] | |
area += (x2 - x1) * (y2 + y1) | |
return area < 0 | |
def close_polygon_contour(poly): | |
poly = np.array(poly).reshape(int(len(poly) / 2), 2) | |
x1, y1 = poly[0] | |
x2, y2 = poly[-1] | |
if x1 != x2: | |
poly = np.concatenate([poly, [poly[0]]], 0) | |
return list(poly.flatten()) | |
def close_polygons_contour(polygons): | |
polygons_closed = [] | |
for polygon in polygons: | |
polygon_closed = close_polygon_contour(polygon) | |
polygons_closed.append(polygon_closed) | |
return polygons_closed | |
def image_to_base64(img, format): | |
output_buffer = BytesIO() | |
img.save(output_buffer, format=format) | |
byte_data = output_buffer.getvalue() | |
base64_str = base64.b64encode(byte_data) | |
base64_str = str(base64_str, encoding='utf-8') | |
return base64_str | |
def process_polygons(polygons, redirection=True, reorder=True, close=False): | |
polygons_processed = [] | |
for polygon in polygons: | |
if redirection and not is_clockwise(polygon): | |
polygon = revert_direction(polygon) | |
if reorder: | |
polygon = reorder_points(polygon) | |
if close: | |
polygon = close_polygon_contour(polygon) | |
polygons_processed.append(polygon) | |
polygons = sorted(polygons_processed, key=lambda x: (x[0] ** 2 + x[1] ** 2, x[0], x[1])) | |
return polygons | |
def string_to_polygons(pts_strings): | |
pts_strings = pts_strings.split(" ")[:-1] | |
polygons = [] | |
for pts_string in pts_strings: | |
polygon = pts_string.split(",") | |
polygon = [float(p) for p in polygon] | |
polygons.append(polygon) | |
return polygons | |
def downsample_polygon(polygon, ds_rate=25): | |
points = np.array(polygon).reshape(int(len(polygon) / 2), 2) | |
points = points[::ds_rate] | |
return list(points.flatten()) | |
def downsample_polygons(polygons, ds_rate=25): | |
polygons_ds = [] | |
for polygon in polygons: | |
polygons_ds.append(downsample_polygon(polygon, ds_rate)) | |
return polygons_ds | |
def check_length(polygons): | |
length = 0 | |
for polygon in polygons: | |
length += len(polygon) | |
return length | |
def approximate_polygon(poly, tolerance=2): | |
poly = np.array(poly).reshape(int(len(poly) / 2), 2) | |
new_poly = [poly[0]] | |
for i in range(1, len(poly)): | |
x1, y1 = new_poly[-1] | |
x2, y2 = poly[i] | |
dist = math.sqrt((x1 - x2) ** 2 + (y1 - y2) ** 2) | |
if dist > tolerance: | |
new_poly.append(poly[i]) | |
new_poly = np.array(new_poly) | |
return list(new_poly.flatten()) | |
def approximate_polygons(polys, tolerance=1.0, max_length=400): | |
tol = tolerance | |
while check_length(polys) > max_length: | |
polys_new = [] | |
for poly in polys: | |
polys_new.append(approximate_polygon(poly, tolerance=tol)) | |
polys = polys_new | |
tol += 2.0 | |
return polys | |
def random_int(low, high): | |
if low < high: | |
return np.random.randint(low, high) | |
else: | |
return max(low, high) | |
def interpolate_points(ps, pe): | |
xs, ys = ps | |
xe, ye = pe | |
points = [] | |
dx = xe - xs | |
dy = ye - ys | |
if dx != 0: | |
scale = dy / dx | |
if xe > xs: | |
x_interpolated = list(range(ceil(xs), floor(xe) + 1)) | |
else: | |
x_interpolated = list(range(floor(xs), ceil(xe) - 1, -1)) | |
for x in x_interpolated: | |
y = ys + (x - xs) * scale | |
points.append([x, y]) | |
if dy != 0: | |
scale = dx / dy | |
if ye > ys: | |
y_interpolated = list(range(ceil(ys), floor(ye) + 1)) | |
else: | |
y_interpolated = list(range(floor(ys), ceil(ye) - 1, -1)) | |
for y in y_interpolated: | |
x = xs + (y - ys) * scale | |
points.append([x, y]) | |
if xe > xs: | |
points = sorted(points, key=lambda x: x[0]) | |
else: | |
points = sorted(points, key=lambda x: -x[0]) | |
return points | |
def interpolate_polygon(polygon): | |
points = np.array(polygon).reshape(int(len(polygon) / 2), 2) | |
points_interpolated = [] | |
points_interpolated.append(points[0]) | |
for i in range(0, len(points) - 1): | |
points_i = interpolate_points(points[i], points[i + 1]) | |
points_interpolated += points_i | |
points_interpolated.append(points[i + 1]) | |
points_interpolated = prune_points(points_interpolated) | |
polygon_interpolated = np.array(points_interpolated) | |
return list(polygon_interpolated.flatten()) | |
def prune_points(points, th=0.1): | |
points_pruned = [points[0]] | |
for i in range(1, len(points)): | |
x1, y1 = points_pruned[-1] | |
x2, y2 = points[i] | |
dist = (x2 - x1) ** 2 + (y2 - y1) ** 2 | |
if dist > th: | |
points_pruned.append(points[i]) | |
return points_pruned | |
def interpolate_polygons(polygons): | |
polygons_i = [] | |
for polygon in polygons: | |
polygons_i.append(interpolate_polygon(polygon)) | |
return polygons_i | |
def sample_polygon(polygon, sample_rate=0.5): | |
points = np.array(polygon).reshape(int(len(polygon) / 2), 2) | |
k = int(len(points) * sample_rate) | |
index = sorted(sample(list(range(len(points))), k)) | |
points_sampled = points[index] | |
return list(np.array(points_sampled).flatten()) | |
def sample_polygons(polygons, max_length=400.0): | |
n = check_length(polygons) | |
k = max_length / n | |
polygons_s = [] | |
for polygon in polygons: | |
polygons_s.append(sample_polygon(polygon, k)) | |
return polygons_s | |
def polygons_to_string(polygons): | |
pts_strings = [] | |
for polygon in polygons: | |
pts_string = ','.join([str(num) for num in polygon]) | |
pts_string += " " # separator | |
pts_strings.append(pts_string) | |
pts_strings = "".join(pts_strings) | |
return pts_strings | |