From 7a85d9d38499ad59f32b4ce0245711546ca655dc Mon Sep 17 00:00:00 2001 From: "Daniel J. Hofmann" Date: Fri, 20 Jul 2018 12:16:15 +0200 Subject: [PATCH] Generalizes post-processing handlers across zoom levels, closes #51 --- robosat/features/parking.py | 14 ++++++++++---- robosat/tiles.py | 24 ++++++++++++++++++++++++ robosat/tools/features.py | 3 +++ 3 files changed, 37 insertions(+), 4 deletions(-) diff --git a/robosat/features/parking.py b/robosat/features/parking.py index ec01f014..cdce4086 100644 --- a/robosat/features/parking.py +++ b/robosat/features/parking.py @@ -5,20 +5,26 @@ import shapely.geometry +from robosat.tiles import meters_per_pixel from robosat.features.core import denoise, grow, contours, simplify, featurize, parents_in_hierarchy class ParkingHandler: - kernel_size_denoise = 20 - kernel_size_grow = 20 + kernel_size_denoise_m = 10 + kernel_size_grow_m = 10 simplify_threshold = 0.01 def __init__(self): self.features = [] def apply(self, tile, mask): - if tile.z != 18: - raise NotImplementedError("Parking lot post-processing thresholds are tuned for z18") + resolution = meters_per_pixel(tile, mask.shape[0]) + + kernel_size_denoise_px = round(self.kernel_size_denoise_m / resolution) + kernel_size_grow_px = round(self.kernel_size_grow_m / resolution) + + assert kernel_size_denoise_px >= 1, "denoising kernel is at least a single pixel in size" + assert kernel_size_grow_px >= 1, "growing kernel is at least a single pixel in size" # The post-processing pipeline removes noise and fills in smaller holes. We then # extract contours, simplify them and transform tile pixels into coordinates. diff --git a/robosat/tiles.py b/robosat/tiles.py index 24a09a1e..56b11d6b 100644 --- a/robosat/tiles.py +++ b/robosat/tiles.py @@ -8,6 +8,7 @@ See: https://wiki.openstreetmap.org/wiki/Slippy_map_tilenames """ +import math import csv import io import os @@ -16,6 +17,29 @@ import mercantile +def meters_per_pixel(tile, size): + """Returns the resolution for a tile. + + Args: + tile: the mercantile.tile to calculate the resolution for. + size: the size in pixels for this tile (e.g. 256). + + Returns: + The resolution in meters per pixel. + """ + + # https://wiki.openstreetmap.org/wiki/Slippy_map_tilenames#Resolution_and_Scale + + z = tile.z + lat = mercantile.ul(tile).lat + + radius = 6378137 + mpp = radius * 2 * math.pi / size + resolution = mpp * math.cos(math.radians(lat)) / (2 ** z) + + return resolution + + def pixel_to_location(tile, dx, dy): """Converts a pixel in a tile to a coordinate. diff --git a/robosat/tools/features.py b/robosat/tools/features.py index 062441ac..17750d1a 100644 --- a/robosat/tools/features.py +++ b/robosat/tools/features.py @@ -46,6 +46,9 @@ def main(args): image = np.array(Image.open(path).convert("P"), dtype=np.uint8) mask = (image == index).astype(np.uint8) + h, w = mask.shape[:2] + assert h == w + handler.apply(tile, mask) handler.save(args.out)