def _get_quadrant_tiles(tile): """Return indicies of tiles at one higher zoom (in TMS tiling scheme)""" ul = (tile.tms[0] * 2, tile.tms[1] * 2) return [Tile.from_tms(ul[0], ul[1], tile.zoom + 1), # UL Tile.from_tms(ul[0], ul[1] + 1, tile.zoom + 1), # LL Tile.from_tms(ul[0] + 1, ul[1], tile.zoom + 1), # UR Tile.from_tms(ul[0] + 1, ul[1] + 1, tile.zoom + 1)] # LR
def get_tiles_bbox(tms_bbox: Tuple[int, int, int, int], zoom: int) -> Tuple[float, float, float, float]: # language=rst """ Returns bbox of geo coordinates for tiles from tms_bbox area :param tms_bbox: area of the tms coordinates in the form of: `(min_x, min_y, max_x, max_y)` :param zoom: :return: bbox of geo coordinates in the form: `(min_lat, min_lon, max_lat, max_lon)` """ points = Tile.from_tms(*tms_bbox[:2], zoom).bounds + Tile.from_tms(*tms_bbox[2:], zoom).bounds latitudes, longitudes = zip(*(p.latitude_longitude for p in points)) return min(latitudes), min(longitudes), max(latitudes), max(longitudes)
def test_finding_child_tiles(self): """Check if 4 correct child tiles can be found from a parent tile.""" parent_tile = Tile.from_tms(1412, 3520, 17) ground_truth = [ Tile.from_tms(x, y, z) for x, y, z in [(2825, 7041, 18), (2825, 7040, 18), (2824, 7041, 18), (2824, 7040, 18)] ] children_tiles = _get_quadrant_tiles(parent_tile) self.assertCountEqual(ground_truth, children_tiles)
def _merge_tiles(path: Union[Path, str], tiles_dir: Union[Path, str], tms_bbox: Tuple[int, int, int, int], zoom: int, tiles_format: ImageFormat) -> None: # language=rst """ Merge tiles from `tms_bbox` area from `tiles_dir` with `zoom` zoomlevel and `tiles_format` image format in image file with `path` without georeference :param path: :param tiles_dir: :param tms_bbox: area of the tms coordinates in the form of: `(min_x, min_y, max_x, max_y)` :param zoom: :param tiles_format: :return: """ min_x, min_y, max_x, max_y = tms_bbox rows = list() for y in range(max_y, min_y - 1, -1): row = list() for x in range(min_x, max_x + 1): tile_path = get_filename(Tile.from_tms(x, y, zoom), tiles_format, tiles_dir) row.append(cv2.imread(str(tile_path))) row_img = cv2.hconcat(row) rows.append(row_img) data = cv2.vconcat(rows) cv2.imwrite(path, data)
def test_assert_tms_y(tms_y, zoom): tms_x = 0 with pytest.raises(AssertionError) as assertion_info: _ = Tile.from_tms(tms_x=tms_x, tms_y=tms_y, zoom=zoom) assert 'TMS Y needs to be a value between 0 and (2^zoom) -1.' in str( assertion_info.value)
def test_georeference(): tile = Tile.from_tms(139423, 171197, 18) img_path = os.path.join(os.getcwd(), "test", "data", "18_139423_171197.tif") m = MarchingSquares.from_file(img_path) points = m.find_contour() geo_points = georeference(points, tile) p = geometry.Polygon(geo_points) print(p.wkt) assert p.wkt == "POLYGON ((11.46890044212341 48.1641425687818, 11.46890580654145 48.1641425687818, 11.46890580654145 48.16404238298088, 11.46879851818085 48.16404238298088, 11.46879851818085 48.16413899072083, 11.46890044212341 48.16413899072083, 11.46890044212341 48.1641425687818))"
def test_roundtrip(): zoom_level = 18 t = Tile.from_tms(139423, 171197, zoom_level) minx, maxy = t.bounds[0].pixels(zoom_level) maxx, miny = t.bounds[1].pixels(zoom_level) p = Point.from_pixel(maxx, maxy, zoom=zoom_level) mx, my = p.meters t2 = Tile.for_meters(mx, my, zoom_level) assert t.quad_tree == t2.quad_tree
def getTMSBBox(x, y, zoom): tile = Tile.from_tms(tms_x=x, tms_y=y, zoom=zoom) bounds = tile.bounds minLong = bounds[0].longitude minLat = bounds[0].latitude maxLong = bounds[1].longitude maxLat = bounds[1].latitude minLong, minLat = pointTo3857(minLong, minLat) maxLong, maxLat = pointTo3857(maxLong, maxLat) return np.array([minLong, maxLong, minLat, maxLat])
def test_predict(): weights_path = os.path.join(os.getcwd(), "model", "mask_rcnn_osm_0030.h5") assert os.path.isfile(weights_path) img_path = os.path.join(os.getcwd(), "test", "data", "18_139423_171197.tiff") p = Predictor(weights_path) polygon_points = p.predict_path(img_path=img_path, tile=Tile.from_tms(139423, 171197, 18)) for points in polygon_points: p = Polygon(points) print(p.wkt) assert 1 == 1
def get_tile_gen(bbox: Tuple[float, float, float, float], zoom: int) -> Generator[Tile, None, None]: # language=rst """ :param bbox: area of the geo coordinates in the form of: `(min_lat, min_lon, max_lat, max_lon)` :param zoom: :return: generator of tiles, which area intersects with bbox area """ min_x, min_y, max_x, max_y = get_bbox_in_tms(bbox, zoom) for x in range(min_x, max_x + 1): for y in range(min_y, max_y + 1): yield Tile.from_tms(x, y, zoom)
def get_tile_pyramid(top_tile_dict, max_zoom=18, ret_format='{z}-{x}-{y}'): """Get all children of a tile at a specific zoom. Parameters: ---------- top_tile_dict: dict Tile for which to get children down to some zoom level. 'x', 'y', 'z' should be defined keys corresponding to TMS coordinates. max_zoom: int Zoom at which to terminate file search ret_format: str Return format for strings Returns: ------- tile_inds: list of str All tiles at the specified zoom that underly the top tile """ # Initialize queue and add input tile stack = LifoQueue() stack.put( Tile.from_tms(top_tile_dict['x'], top_tile_dict['y'], top_tile_dict['z'])) # Depth-first search on tile indices desired_tiles = [] while not stack.empty(): # Pop the top tile in the stack temp_tile = stack.get() # Check if desired zoom has been reached if temp_tile.zoom >= max_zoom: # If at max zoom, save tile tile_dict = dict(x=temp_tile.tms[0], y=temp_tile.tms[1], z=temp_tile.zoom) desired_tiles.append(ret_format.format(**tile_dict)) # Otherwise, zoom in one increment, find children tiles, add to stack else: for rt in _get_quadrant_tiles(temp_tile): stack.put(rt) return desired_tiles
def open_tile(filename, outdir='./'): """ Open a tile image and assign projection and geotransform """ img = gippy.GeoImage(filename) z, x, y = map(int, img.basename().split('-')) tile = Tile.from_tms(tms_x=x, tms_y=y, zoom=z) img[0] = (img[0] == 255) fout = os.path.join(outdir, img.basename() + '.tif') geoimg = img.save(fout, options={'COMPRESS': 'DEFLATE'}) geoimg.set_srs('EPSG:3857') minpt = tile.bounds[0].meters maxpt = tile.bounds[1].meters affine = np.array( [ minpt[0], (maxpt[0]-minpt[0])/geoimg.xsize(), 0.0, abs(minpt[1]), 0.0, -(maxpt[1]-minpt[1])/geoimg.ysize() ]) geoimg.set_affine(affine) return geoimg
def x2bbox(xt_min, xt_max, yt_min, yt_max, zoom=19): south = 90.0 north = -90.0 east = -180.0 west = 180.0 for x in range(xt_min, xt_max + 1): for y in range(yt_min, yt_max + 1): tile = Tile.from_tms(tms_x=x, tms_y=y, zoom=zoom) b = tile.bounds for i in range(2): lat = b[i].latitude_longitude[0] lon = b[i].latitude_longitude[1] south = min(south, -lat) north = max(north, -lat) east = max(east, lon) west = min(west, lon) return east, west, north, south
def _tiles_from_bbox(bbox, zoom_level): """ * Returns all tiles for the specified bounding box """ if isinstance(bbox, dict): point_min = Point.from_latitude_longitude(latitude=bbox['tl'], longitude=bbox['tr']) point_max = Point.from_latitude_longitude(latitude=bbox['bl'], longitude=bbox['br']) elif isinstance(bbox, list): point_min = Point.from_latitude_longitude(latitude=bbox[1], longitude=bbox[0]) point_max = Point.from_latitude_longitude(latitude=bbox[3], longitude=bbox[2]) else: raise RuntimeError("bbox must bei either a dict or a list") tile_min = Tile.for_point(point_min, zoom_level) tile_max = Tile.for_point(point_max, zoom_level) tiles = [] for x in range(tile_min.tms_x, tile_max.tms_x + 1): for y in range(tile_min.tms_y, tile_max.tms_y + 1): tiles.append(Tile.from_tms(tms_x=x, tms_y=y, zoom=zoom_level)) return tiles
def test_tile_bounds(tms_x, tms_y, zoom, expected_min, expected_max): tile = Tile.from_tms(tms_x=tms_x, tms_y=tms_y, zoom=zoom) point_min, point_max = tile.bounds assert point_min.latitude_longitude == pytest.approx(expected_min, abs=0.1) assert point_max.latitude_longitude == pytest.approx(expected_max, abs=0.1)
def test_from_tms(tms, zoom): tms_x, tms_y = tms tile = Tile.from_tms(tms_x=tms_x, tms_y=tms_y, zoom=zoom) assert tile.tms == tms
def cog_windowed_read(image_path, tile_ind, chan_inds=(1, ), final_proj=None): """Get raster data from a cloud-optimized-geotiff using a tile's bounds. Parameters ---------- image_path: str COG file path as local file or path to remote image. tile_ind: dict or str Dictionary with keys `z`, `x`, `y` defined or str in `z-x-y` format. chan_inds: tuple of int Channel indicies to grab from COG. Usually, `(1)` for L and `(1, 2, 3)` for RGB. final_proj: str Output projection for data if a projection different from the COG is needed. Returns ------- window_data: np.ndarray Array containing data values requested in tile_ind. """ if isinstance(tile_ind, dict): tile = Tile.from_tms(tile_ind['x'], tile_ind['y'], tile_ind['z']) elif isinstance(tile_ind, str): z, x, y = [int(val) for val in tile_ind.split('-')] tile = Tile.from_tms(x, y, z) else: raise ValueError( 'Could not parse `tile_ind` as string or dict: {}'.format( tile_ind)) with rasterio.open(image_path) as cog_image: p1 = Proj({'init': 'epsg:4326'}) p2 = Proj(**cog_image.crs) # Convert tile lat/lon bounds to COG ref frame # (pygeotile bounds are (LL, UR)) window_bounds = dict() window_bounds['west'], window_bounds['north'] = \ transform(p1, p2, tile.bounds[0].longitude, tile.bounds[1].latitude) window_bounds['east'], window_bounds['south'] = \ transform(p1, p2, tile.bounds[1].longitude, tile.bounds[0].latitude) # Get image origin point and resolution from the COG tif_bounds = dict(north=cog_image.bounds.top, west=cog_image.bounds.left) x_res, y_res = cog_image.transform[0], cog_image.transform[4] # Calculate the pixel indices of the window top = int((window_bounds['north'] - tif_bounds['north']) / y_res) left = int((window_bounds['west'] - tif_bounds['west']) / x_res) bottom = int((window_bounds['south'] - tif_bounds['north']) / y_res) right = int((window_bounds['east'] - tif_bounds['west']) / x_res) window_pixels = ((top, bottom), (left, right)) # Access the pixels of TIF image # XXX Seems to force data to the output shape window_data = np.empty((len(chan_inds), 256, 256), cog_image.profile['dtype']) for ci in chan_inds: cog_image.read(ci, window=window_pixels, out=window_data[ci - 1], boundless=True) # If user wants a specific transform, do that now if final_proj is not None: profile = cog_image.profile dst_crs = crs.from_string(final_proj) # Calculate the ideal dimensions and transformation in the new crs # XXX Possible to define resolution here dst_affine, dst_width, dst_height = calculate_default_transform( cog_image.crs, dst_crs, 256, 256, left=left, bottom=bottom, right=right, top=top) profile.update({ 'crs': dst_crs, 'transform': dst_affine, 'affine': dst_affine, 'width': dst_width, 'height': dst_height }) # Create an array for the projected window window_data_proj = np.empty( (len(chan_inds), dst_height, dst_width), cog_image.profile['dtype']) reproject(source=window_data, src_crs=cog_image.crs, src_transform=cog_image.affine, destination=window_data_proj, dst_transform=dst_affine, dst_crs=dst_crs, resampling=Resampling.nearest) return np.moveaxis(window_data_proj, 0, -1) return np.moveaxis(window_data, 0, -1)
def test_no_assert_tms_y(tms_y, zoom): tms_x = 0 _ = Tile.from_tms(tms_x=tms_x, tms_y=tms_y, zoom=zoom) assert "No assertion raise :)"
from pygeotile.tile import Tile tms_x, tms_y, zoom = 134494, 329369, 19 tile = Tile.from_tms(tms_x=tms_x, tms_y=tms_y, zoom=19) # Tile Map Service (TMS) X Y and zoom print('QuadTree: ', tile.quad_tree) # QuadTree: 0302222310303211330 print('Google: ', tile.google) # Google: (134494, 194918)