Luuu / frame_field_learning /polygonize_utils.py
็™ฝ้นญๅ…ˆ็”Ÿ
init
abd2a81
from functools import partial
from collections import Iterable
import shapely.geometry
import shapely.ops
import shapely.affinity
import numpy as np
import cv2
import skimage.measure
from lydorn_utils import print_utils
def compute_init_contours(np_indicator, level):
assert isinstance(np_indicator, np.ndarray) and len(np_indicator.shape) == 2, "indicator should have shape (H, W)"
# Using marching squares
contours = skimage.measure.find_contours(np_indicator, level, fully_connected='low', positive_orientation='high')
# Using OpenCV:
# u, contours, _ = cv2.findContours((level < np_indicator).astype(np.uint8), cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)
# contours = [contour[:, 0, ::-1] for contour in contours]
# contours = [np.concatenate((contour, contour[0:1, :]), axis=0) for contour in contours]
# Using rasterio
# import rasterio.features
# shapes = rasterio.features.shapes((level < np_indicator).astype(np.uint8))
# contours = []
# for shape in shapes:
# for coords in shape[0]["coordinates"]:
# contours.append(np.array(coords)[:, ::-1] - 0.5)
# Simplify contours a tiny bit:
# contours = [skimage.measure.approximate_polygon(contour, tolerance=0.01) for contour in contours]
return contours
def compute_init_contours_batch(np_indicator_batch, level, pool=None):
post_process_partial = partial(compute_init_contours, level=level)
if pool is not None:
init_contours_batch = pool.map(post_process_partial, np_indicator_batch)
else:
init_contours_batch = list(map(post_process_partial, np_indicator_batch))
return init_contours_batch
def split_polylines_corner(polylines, corner_masks):
new_polylines = []
for polyline, corner_mask in zip(polylines, corner_masks):
splits, = np.where(corner_mask)
if len(splits) == 0:
new_polylines.append(polyline)
continue
slice_list = [(splits[i], splits[i+1] + 1) for i in range(len(splits) - 1)]
for s in slice_list:
new_polylines.append(polyline[s[0]:s[1]])
# Possibly add a merged polyline if start and end vertices are not corners (or endpoints of open polylines)
if ~corner_mask[0] and ~corner_mask[-1]: # In fact any of those conditon should be enough
new_polyline = np.concatenate([polyline[splits[-1]:], polyline[:splits[0] + 1]], axis=0)
new_polylines.append(new_polyline)
return new_polylines
def compute_geom_prob(geom, prob_map, output_debug=False):
assert len(prob_map.shape) == 2, "prob_map should have size (H, W), not {}".format(prob_map.shape)
if isinstance(geom, Iterable):
return [compute_geom_prob(_geom, prob_map, output_debug=output_debug) for _geom in geom]
elif isinstance(geom, shapely.geometry.Polygon):
# --- Cut with geom bounds:
minx, miny, maxx, maxy = geom.bounds
minx = int(minx)
miny = int(miny)
maxx = int(maxx) + 1
maxy = int(maxy) + 1
geom = shapely.affinity.translate(geom, xoff=-minx, yoff=-miny)
prob_map = prob_map[miny:maxy, minx:maxx]
# --- Rasterize TODO: better rasterization (or sampling) of polygon ?
raster = np.zeros(prob_map.shape, dtype=np.uint8)
exterior_array = np.round(np.array(geom.exterior.coords)).astype(np.int32)
interior_array_list = [np.round(np.array(interior.coords)).astype(np.int32) for interior in geom.interiors]
cv2.fillPoly(raster, [exterior_array], color=1)
cv2.fillPoly(raster, interior_array_list, color=0)
raster_sum = np.sum(raster)
if 0 < raster_sum:
polygon_prob = np.sum(raster * prob_map) / raster_sum
else:
polygon_prob = 0
if output_debug:
print_utils.print_warning("WARNING: empty polygon raster in polygonize_tracing.compute_polygon_prob().")
return polygon_prob
else:
raise NotImplementedError(f"Geometry of type {type(geom)} not implemented!")