def tile(sceneid, tile_x, tile_y, tile_z, rgb=('04', '03', '02'), tilesize=256): """Create mercator tile from Sentinel-2 data. Attributes ---------- sceneid : str Sentinel-2 sceneid. tile_x : int Mercator tile X index. tile_y : int Mercator tile Y index. tile_z : int Mercator tile ZOOM level. rgb : tuple, str, optional (default: ('04', '03', '02')) Bands index for the RGB combination. tilesize : int, optional (default: 256) Output image size. Returns ------- data : numpy ndarray mask: numpy array """ if not isinstance(rgb, tuple): rgb = tuple((rgb, )) scene_params = utils.sentinel_parse_scene_id(sceneid) sentinel_address = '{}/{}'.format(SENTINEL_BUCKET, scene_params['key']) sentinel_preview = '{}/preview.jp2'.format(sentinel_address) with rasterio.open(sentinel_preview) as src: wgs_bounds = transform_bounds(*[src.crs, 'epsg:4326'] + list(src.bounds), densify_pts=21) if not utils.tile_exists(wgs_bounds, tile_z, tile_x, tile_y): raise TileOutsideBounds('Tile {}/{}/{} is outside image bounds'.format( tile_z, tile_x, tile_y)) mercator_tile = mercantile.Tile(x=tile_x, y=tile_y, z=tile_z) tile_bounds = mercantile.xy_bounds(mercator_tile) addresses = ['{}/B{}.jp2'.format(sentinel_address, band) for band in rgb] _tiler = partial(utils.tile_band_worker, bounds=tile_bounds, tilesize=tilesize, nodata=0) with futures.ThreadPoolExecutor(max_workers=3) as executor: data, masks = zip(*list(executor.map(_tiler, addresses))) mask = np.all(masks, axis=0).astype(np.uint8) * 255 return np.concatenate(data), mask
def test_tile_exists_valid(): """ Should work as expected (return true) """ tile = '7-36-50' tile_z, tile_x, tile_y = map(int, tile.split('-')) bounds = [-78.75, 34.30714385628803, -75.93749999999999, 36.59788913307021] assert utils.tile_exists(bounds, tile_z, tile_x, tile_y)
def tile(sceneid, tile_x, tile_y, tile_z, bands=("04", "03", "02"), tilesize=256): """ Create mercator tile from Sentinel-2 data. Attributes ---------- sceneid : str Sentinel-2 sceneid. tile_x : int Mercator tile X index. tile_y : int Mercator tile Y index. tile_z : int Mercator tile ZOOM level. bands : tuple, str, optional (default: ('04', '03', '02')) Bands index for the RGB combination. tilesize : int, optional (default: 256) Output image size. Returns ------- data : numpy ndarray mask: numpy array """ if not isinstance(bands, tuple): bands = tuple((bands,)) for band in bands: if band not in SENTINEL_BANDS: raise InvalidBandName("{} is not a valid Sentinel band name".format(band)) scene_params = _sentinel_parse_scene_id(sceneid) sentinel_address = "{}/{}".format(SENTINEL_BUCKET, scene_params["key"]) sentinel_preview = "{}/preview.jp2".format(sentinel_address) with rasterio.open(sentinel_preview) as src: wgs_bounds = transform_bounds( *[src.crs, "epsg:4326"] + list(src.bounds), densify_pts=21 ) if not utils.tile_exists(wgs_bounds, tile_z, tile_x, tile_y): raise TileOutsideBounds( "Tile {}/{}/{} is outside image bounds".format(tile_z, tile_x, tile_y) ) mercator_tile = mercantile.Tile(x=tile_x, y=tile_y, z=tile_z) tile_bounds = mercantile.xy_bounds(mercator_tile) addresses = ["{}/B{}.jp2".format(sentinel_address, band) for band in bands] _tiler = partial(utils.tile_read, bounds=tile_bounds, tilesize=tilesize, nodata=0) with futures.ThreadPoolExecutor(max_workers=MAX_THREADS) as executor: data, masks = zip(*list(executor.map(_tiler, addresses))) mask = np.all(masks, axis=0).astype(np.uint8) * 255 return np.concatenate(data), mask
def tile(address, tile_x, tile_y, tile_z, rgb=None, tilesize=256, nodata=None, alpha=None): """Create mercator tile from any images. Attributes ---------- address : str file url. tile_x : int Mercator tile X index. tile_y : int Mercator tile Y index. tile_z : int Mercator tile ZOOM level. rgb : tuple, int, optional (default: (1, 2, 3)) Bands index for the RGB combination. tilesize : int, optional (default: 256) Output image size. nodata: int or float, optional (defaults: None) alpha: int, optional (defaults: None) Force alphaband if not present in the dataset metadata Returns ------- data : numpy ndarray mask: numpy array """ with rasterio.open(address) as src: wgs_bounds = transform_bounds(*[src.crs, 'epsg:4326'] + list(src.bounds), densify_pts=21) nodata = nodata if nodata is not None else src.nodata if not rgb: rgb = src.indexes if not utils.tile_exists(wgs_bounds, tile_z, tile_x, tile_y): raise TileOutsideBounds('Tile {}/{}/{} is outside image bounds'.format( tile_z, tile_x, tile_y)) mercator_tile = mercantile.Tile(x=tile_x, y=tile_y, z=tile_z) tile_bounds = mercantile.xy_bounds(mercator_tile) return utils.tile_band_worker(address, tile_bounds, tilesize, indexes=rgb, nodata=nodata, alpha=alpha)
def tile(bucket, key, tile_x, tile_y, tile_z, rgb=(1, 2, 3), tilesize=256, prefix='s3:/'): """Create mercator tile from AWS hosted images and encodes it in base64. Attributes ---------- bucket : str AWS bucket's name. key : str AWS file's key. tile_x : int Mercator tile X index. tile_y : int Mercator tile Y index. tile_z : int Mercator tile ZOOM level. tileformat : str Image format to return (Accepted: "jpg" or "png") rgb : tuple, int, optional (default: (1, 2, 3)) Bands index for the RGB combination. tilesize : int, optional (default: 256) Output image size. Returns ------- out : numpy ndarray """ source_address = '{}/{}/{}'.format(prefix, bucket, key) with rasterio.open(source_address) as src: wgs_bounds = transform_bounds( *[src.crs, 'epsg:4326'] + list(src.bounds), densify_pts=21) nodata = src.nodata if not utils.tile_exists(wgs_bounds, tile_z, tile_x, tile_y): raise TileOutsideBounds( 'Tile {}/{}/{} is outside image bounds'.format( tile_z, tile_x, tile_y)) mercator_tile = mercantile.Tile(x=tile_x, y=tile_y, z=tile_z) tile_bounds = mercantile.xy_bounds(mercator_tile) w, s, e, n = tile_bounds out = utils.tile_band_worker(source_address, tile_bounds, tilesize, indexes=rgb, nodata=nodata) return out
def tile(address, tile_x, tile_y, tile_z, indexes=None, tilesize=256, nodata=None): """ Create mercator tile from any images. Attributes ---------- address : str file url. tile_x : int Mercator tile X index. tile_y : int Mercator tile Y index. tile_z : int Mercator tile ZOOM level. indexes : tuple, int, optional (default: (1, 2, 3)) Bands indexes for the RGB combination. tilesize : int, optional (default: 256) Output image size. nodata: int or float, optional Overwrite nodata value for mask creation. Returns ------- data : numpy ndarray mask: numpy array """ with rasterio.open(address) as src: wgs_bounds = transform_bounds(*[src.crs, 'epsg:4326'] + list(src.bounds), densify_pts=21) indexes = indexes if indexes is not None else src.indexes if not utils.tile_exists(wgs_bounds, tile_z, tile_x, tile_y): raise TileOutsideBounds( 'Tile {}/{}/{} is outside image bounds'.format( tile_z, tile_x, tile_y)) mercator_tile = mercantile.Tile(x=tile_x, y=tile_y, z=tile_z) tile_bounds = mercantile.xy_bounds(mercator_tile) return utils.tile_read(src, tile_bounds, tilesize, indexes=indexes, nodata=nodata)
def tile( src_dst: Union[DatasetReader, DatasetWriter, WarpedVRT], x: int, y: int, z: int, tilesize: int = 256, **kwargs, ) -> Tuple[numpy.ndarray, numpy.ndarray]: """ Read mercator tile from an image. Attributes ---------- src_dst : rasterio.io.DatasetReader rasterio.io.DatasetReader object x : int Mercator tile X index. y : int Mercator tile Y index. z : int Mercator tile ZOOM level. tilesize : int, optional Output tile size. Default is 256. kwargs : Any, optional Additional options to forward to part() Returns ------- data : numpy ndarray mask: numpy array """ bounds = transform_bounds(src_dst.crs, constants.WGS84_CRS, *src_dst.bounds, densify_pts=21) if not tile_exists(bounds, z, x, y): raise TileOutsideBounds(f"Tile {z}/{x}/{y} is outside image bounds") tile_bounds = mercantile.xy_bounds(mercantile.Tile(x=x, y=y, z=z)) return part( src_dst, tile_bounds, tilesize, tilesize, dst_crs=constants.WEB_MERCATOR_CRS, **kwargs, )
def _s1_tiler(src_path): with rasterio.open(src_path) as src_dst: with WarpedVRT( src_dst, src_crs=src_dst.gcps[1], src_transform=transform.from_gcps(src_dst.gcps[0]), src_nodata=0, ) as vrt_dst: if not utils.tile_exists(vrt_dst.bounds, tile_z, tile_x, tile_y): raise TileOutsideBounds( "Tile {}/{}/{} is outside image bounds".format( tile_z, tile_x, tile_y)) return utils._tile_read(vrt_dst, bounds=tile_bounds, tilesize=tilesize)
def tile_exists(self, x: int, y: int, z: int) -> bool: """ Check if the tile exist. Attributes ---------- x : int X tile map index. y : int y tile map index z : int Z tile map index Returns ------- bool """ return tile_exists(self._bounds, z, x, y)
def tile( stac: Dict, assets: Sequence[str], tile_x: int, tile_y: int, tile_z: int, tilesize: int = 256, **kwargs: Any, ) -> Tuple[numpy.ndarray, numpy.ndarray]: """ Create mercator tile from any images. Attributes ---------- stac : dict STAC item. assets : list Asset names. tile_x : int Mercator tile X index. tile_y : int Mercator tile Y index. tile_z : int Mercator tile ZOOM level. tilesize : int, optional (default: 256) Output image size. kwargs: dict, optional These will be passed to the 'rio_tiler.reader.tile' function. Returns ------- data : numpy ndarray mask: numpy array """ if isinstance(assets, str): assets = (assets, ) if not tile_exists(stac["bbox"], tile_z, tile_x, tile_y): raise TileOutsideBounds( f"Tile {tile_z}/{tile_x}/{tile_y} is outside item bounds") assets_url = _get_href(stac, assets) return reader.multi_tile(assets_url, tile_x, tile_y, tile_z, **kwargs)
def tile(address, tile_x, tile_y, tile_z, tilesize=256, **kwargs): """ Create mercator tile from any images. Attributes ---------- address : str file url. tile_x : int Mercator tile X index. tile_y : int Mercator tile Y index. tile_z : int Mercator tile ZOOM level. tilesize : int, optional (default: 256) Output image size. kwargs: dict, optional These will be passed to the 'rio_tiler.utils._tile_read' function. Returns ------- data : numpy ndarray mask: numpy array """ with rasterio.open(address) as src: bounds = transform_bounds(src.crs, "epsg:4326", *src.bounds, densify_pts=21) if not utils.tile_exists(bounds, tile_z, tile_x, tile_y): raise TileOutsideBounds( "Tile {}/{}/{} is outside image bounds".format( tile_z, tile_x, tile_y)) mercator_tile = mercantile.Tile(x=tile_x, y=tile_y, z=tile_z) tile_bounds = mercantile.xy_bounds(mercator_tile) return utils.tile_read(src, tile_bounds, tilesize, **kwargs)
def landsat8_tile(sceneid, tile_x, tile_y, tile_z, bands=("4", "3", "2"), tilesize=256, pan=False, percents="", **kwargs): """ Create mercator tile from Landsat-8 data. Attributes ---------- sceneid : str Landsat sceneid. For scenes after May 2017, sceneid have to be LANDSAT_PRODUCT_ID. tile_x : int Mercator tile X index. tile_y : int Mercator tile Y index. tile_z : int Mercator tile ZOOM level. bands : tuple, str, optional (default: ("4", "3", "2")) Bands index for the RGB combination. tilesize : int, optional (default: 256) Output image size. pan : boolean, optional (default: False) If True, apply pan-sharpening. kwargs: dict, optional These will be passed to the 'rio_tiler.utils._tile_read' function. Returns ------- data : numpy ndarray mask: numpy array """ if not isinstance(bands, tuple): bands = tuple((bands, )) for band in bands: if band not in LANDSAT_BANDS: raise InvalidBandName( "{} is not a valid Landsat band name".format(band)) scene_params = landsat8._landsat_parse_scene_id(sceneid) meta_data = landsat8._landsat_get_mtl(sceneid).get("L1_METADATA_FILE") landsat_address = "{}/{}".format(LANDSAT_BUCKET, scene_params["key"]) wgs_bounds = toa_utils._get_bounds_from_metadata( meta_data["PRODUCT_METADATA"]) addresses = ["{}_B{}.TIF".format(landsat_address, band) for band in bands] values = [] percents = percents.split(',') i = 0 for address in addresses: with rasterio.open(address) as src: if int(percents[i]) != 0 and int(percents[i + 1]) != 100: overviews = src.overviews(1) if len(overviews) > 0: d = src.read( out_shape=(1, int(src.height / overviews[len(overviews) - 1]), int(src.width / overviews[len(overviews) - 1]))) else: d = src.read() dflatten = numpy.array(d.flatten()) p_start, p_end = numpy.percentile(dflatten[dflatten > 0], (int(percents[i]), (int(percents[i + 1])))) values.append([p_start, p_end]) else: values.append([None, None]) i += 2 if not utils.tile_exists(wgs_bounds, tile_z, tile_x, tile_y): # raise TileOutsideBounds( # "Tile {}/{}/{} is outside image bounds".format(tile_z, tile_x, tile_y) # ) return None, None mercator_tile = mercantile.Tile(x=tile_x, y=tile_y, z=tile_z) tile_bounds = mercantile.xy_bounds(mercator_tile) def _tiler(band): address = "{}_B{}.TIF".format(landsat_address, band) if band == "QA": nodata = 1 else: nodata = 0 return utils.tile_read(address, bounds=tile_bounds, tilesize=tilesize, nodata=nodata, **kwargs) with futures.ThreadPoolExecutor(max_workers=MAX_THREADS) as executor: data, masks = zip(*list(executor.map(_tiler, bands))) mask = numpy.all(masks, axis=0).astype(numpy.uint8) * 255 new_data = list(data) has_modification = False for ds in range(0, len(new_data)): if values[ds][0] is not None and values[ds][1] is not None: has_modification = True new_data[ds] = rescale_intensity(new_data[ds], in_range=(values[ds][0], values[ds][1]), out_range=(0, 255)) if has_modification == True: data = numpy.array(new_data).astype(numpy.uint8) data = numpy.concatenate(data) if pan: pan_address = "{}_B8.TIF".format(landsat_address) matrix_pan, mask = utils.tile_read(pan_address, tile_bounds, tilesize, nodata=0) data = utils.pansharpening_brovey(data, matrix_pan, 0.2, matrix_pan.dtype) sun_elev = meta_data["IMAGE_ATTRIBUTES"]["SUN_ELEVATION"] for bdx, band in enumerate(bands): if band in ["1", "2", "3", "4", "5", "6", "7", "8", "9"]: # OLI multi_reflect = meta_data["RADIOMETRIC_RESCALING"].get( "REFLECTANCE_MULT_BAND_{}".format(band)) add_reflect = meta_data["RADIOMETRIC_RESCALING"].get( "REFLECTANCE_ADD_BAND_{}".format(band)) data[bdx] = 10000 * reflectance.reflectance( data[bdx], multi_reflect, add_reflect, sun_elev) elif band in ["10", "11"]: # TIRS multi_rad = meta_data["RADIOMETRIC_RESCALING"].get( "RADIANCE_MULT_BAND_{}".format(band)) add_rad = meta_data["RADIOMETRIC_RESCALING"].get( "RADIANCE_ADD_BAND_{}".format(band)) k1 = meta_data["TIRS_THERMAL_CONSTANTS"].get( "K1_CONSTANT_BAND_{}".format(band)) k2 = meta_data["TIRS_THERMAL_CONSTANTS"].get( "K2_CONSTANT_BAND_{}".format(band)) data[bdx] = brightness_temp.brightness_temp( data[bdx], multi_rad, add_rad, k1, k2) return data, mask
def test_tile_exists_valid(): """Should work as expected (return true).""" bounds = [-80, 34, -75, 40] # Contains assert utils.tile_exists(bounds, 7, 36, 50) # bounds contains tile bounds assert utils.tile_exists(bounds, 3, 2, 3) # tile bounds contains bounds # Intersects assert utils.tile_exists(bounds, 7, 35, 50) assert utils.tile_exists(bounds, 7, 37, 50) assert utils.tile_exists(bounds, 7, 36, 51) assert utils.tile_exists(bounds, 7, 37, 51) assert utils.tile_exists(bounds, 7, 35, 51) assert utils.tile_exists(bounds, 7, 35, 48) assert utils.tile_exists(bounds, 7, 37, 48) # Outside tiles assert not utils.tile_exists(bounds, 7, 36, 40) assert not utils.tile_exists(bounds, 7, 36, 60) assert not utils.tile_exists(bounds, 7, 25, 50) assert not utils.tile_exists(bounds, 7, 70, 50)
def tile(sceneid, tile_x, tile_y, tile_z, rgb=('04', '03', '02'), r_bds=(0, 16000), g_bds=(0, 16000), b_bds=(1, 16000), tilesize=256): """Create mercator tile from Sentinel-2 data and encodes it in base64. Attributes ---------- sceneid : str Sentinel-2 sceneid. tile_x : int Mercator tile X index. tile_y : int Mercator tile Y index. tile_z : int Mercator tile ZOOM level. rgb : tuple, int, optional (default: ('04', '03', '02')) Bands index for the RGB combination. r_bds : tuple, int, optional (default: (0, 16000)) First band (red) DN min and max values (DN * 10,000) used for the linear rescaling. g_bds : tuple, int, optional (default: (0, 16000)) Second band (green) DN min and max values (DN * 10,000) used for the linear rescaling. b_bds : tuple, int, optional (default: (0, 16000)) Third band (blue) DN min and max values (DN * 10,000) used for the linear rescaling. tilesize : int, optional (default: 256) Output image size. Returns ------- out : numpy ndarray (type: uint8) """ scene_params = utils.sentinel_parse_scene_id(sceneid) sentinel_address = '{}/{}'.format(SENTINEL_BUCKET, scene_params['key']) sentinel_preview = '{}/preview.jp2'.format(sentinel_address) with rasterio.open(sentinel_preview) as src: wgs_bounds = transform_bounds( *[src.crs, 'epsg:4326'] + list(src.bounds), densify_pts=21) if not utils.tile_exists(wgs_bounds, tile_z, tile_x, tile_y): raise TileOutsideBounds('Tile {}/{}/{} is outside image bounds'.format( tile_z, tile_x, tile_y)) mercator_tile = mercantile.Tile(x=tile_x, y=tile_y, z=tile_z) tile_bounds = mercantile.xy_bounds(mercator_tile) # define a list of bands Min and Max Values (form input) histo_cuts = dict(zip(rgb, [r_bds, g_bds, b_bds])) addresses = ['{}/B{}.jp2'.format(sentinel_address, band) for band in rgb] _tiler = partial(utils.tile_band_worker, bounds=tile_bounds, tilesize=tilesize) with futures.ThreadPoolExecutor(max_workers=3) as executor: out = np.stack(executor.map(_tiler, addresses)) for bdx, band in enumerate(rgb): # Rescale Intensity to byte (1->255) with 0 being NoData out[bdx] = np.where( out[bdx] > 0, utils.linear_rescale(out[bdx], in_range=histo_cuts.get(band), out_range=[1, 255]), 0) return out.astype(np.uint8)
def tile(sceneid, tile_x, tile_y, tile_z, bands=("4", "3", "2"), tilesize=256, pan=False, **kwargs): """ Create mercator tile from Landsat-8 data. Attributes ---------- sceneid : str Landsat sceneid. For scenes after May 2017, sceneid have to be LANDSAT_PRODUCT_ID. tile_x : int Mercator tile X index. tile_y : int Mercator tile Y index. tile_z : int Mercator tile ZOOM level. bands : tuple, str, optional (default: ("4", "3", "2")) Bands index for the RGB combination. tilesize : int, optional (default: 256) Output image size. pan : boolean, optional (default: False) If True, apply pan-sharpening. kwargs: dict, optional These will be passed to the 'rio_tiler.utils._tile_read' function. Returns ------- data : numpy ndarray mask: numpy array """ if not isinstance(bands, tuple): bands = tuple((bands, )) for band in bands: if band not in LANDSAT_BANDS: raise InvalidBandName( "{} is not a valid Landsat band name".format(band)) scene_params = _landsat_parse_scene_id(sceneid) meta_data = _landsat_get_mtl(sceneid).get("L1_METADATA_FILE") landsat_address = "{}/{}".format(LANDSAT_BUCKET, scene_params["key"]) wgs_bounds = toa_utils._get_bounds_from_metadata( meta_data["PRODUCT_METADATA"]) if not utils.tile_exists(wgs_bounds, tile_z, tile_x, tile_y): raise TileOutsideBounds("Tile {}/{}/{} is outside image bounds".format( tile_z, tile_x, tile_y)) mercator_tile = mercantile.Tile(x=tile_x, y=tile_y, z=tile_z) tile_bounds = mercantile.xy_bounds(mercator_tile) def _tiler(band): address = "{}_B{}.TIF".format(landsat_address, band) if band == "QA": nodata = 1 else: nodata = 0 return utils.tile_read(address, bounds=tile_bounds, tilesize=tilesize, nodata=nodata, **kwargs) with futures.ThreadPoolExecutor(max_workers=MAX_THREADS) as executor: data, masks = zip(*list(executor.map(_tiler, bands))) data = np.concatenate(data) mask = np.all(masks, axis=0).astype(np.uint8) * 255 if pan: pan_address = "{}_B8.TIF".format(landsat_address) matrix_pan, mask = utils.tile_read(pan_address, tile_bounds, tilesize, nodata=0) data = utils.pansharpening_brovey(data, matrix_pan, 0.2, matrix_pan.dtype) sun_elev = meta_data["IMAGE_ATTRIBUTES"]["SUN_ELEVATION"] for bdx, band in enumerate(bands): if band in ["1", "2", "3", "4", "5", "6", "7", "8", "9"]: # OLI multi_reflect = meta_data["RADIOMETRIC_RESCALING"].get( "REFLECTANCE_MULT_BAND_{}".format(band)) add_reflect = meta_data["RADIOMETRIC_RESCALING"].get( "REFLECTANCE_ADD_BAND_{}".format(band)) data[bdx] = 10000 * reflectance.reflectance( data[bdx], multi_reflect, add_reflect, sun_elev) elif band in ["10", "11"]: # TIRS multi_rad = meta_data["RADIOMETRIC_RESCALING"].get( "RADIANCE_MULT_BAND_{}".format(band)) add_rad = meta_data["RADIOMETRIC_RESCALING"].get( "RADIANCE_ADD_BAND_{}".format(band)) k1 = meta_data["TIRS_THERMAL_CONSTANTS"].get( "K1_CONSTANT_BAND_{}".format(band)) k2 = meta_data["TIRS_THERMAL_CONSTANTS"].get( "K2_CONSTANT_BAND_{}".format(band)) data[bdx] = brightness_temp.brightness_temp( data[bdx], multi_rad, add_rad, k1, k2) return data, mask
def tile(sceneid, tile_x, tile_y, tile_z, bands=None, tilesize=256): """ Create mercator tile from CBERS data. Attributes ---------- sceneid : str CBERS sceneid. tile_x : int Mercator tile X index. tile_y : int Mercator tile Y index. tile_z : int Mercator tile ZOOM level. bands : tuple, int, optional (default: None) Bands index for the RGB combination. If None uses default defined for the instrument tilesize : int, optional (default: 256) Output image size. Returns ------- data : numpy ndarray mask: numpy array """ scene_params = utils.cbers_parse_scene_id(sceneid) if not bands: bands = scene_params["rgb"] if not isinstance(bands, tuple): bands = tuple((bands, )) cbers_address = "{}/{}".format(CBERS_BUCKET, scene_params["key"]) with rasterio.open("{}/{}_BAND{}.tif".format( cbers_address, sceneid, scene_params["reference_band"])) as src: wgs_bounds = transform_bounds(*[src.crs, "epsg:4326"] + list(src.bounds), densify_pts=21) if not utils.tile_exists(wgs_bounds, tile_z, tile_x, tile_y): raise TileOutsideBounds("Tile {}/{}/{} is outside image bounds".format( tile_z, tile_x, tile_y)) mercator_tile = mercantile.Tile(x=tile_x, y=tile_y, z=tile_z) tile_bounds = mercantile.xy_bounds(mercator_tile) addresses = [ "{}/{}_BAND{}.tif".format(cbers_address, sceneid, band) for band in bands ] _tiler = partial(utils.tile_read, bounds=tile_bounds, tilesize=tilesize, nodata=0) with futures.ThreadPoolExecutor(max_workers=3) as executor: data, masks = zip(*list(executor.map(_tiler, addresses))) mask = np.all(masks, axis=0).astype(np.uint8) * 255 return np.concatenate(data), mask
def tile( sceneid: str, tile_x: int, tile_y: int, tile_z: int, bands: Union[Sequence[str], str] = ("04", "03", "02"), tilesize: int = 256, **kwargs: Dict, ) -> Tuple[numpy.ndarray, numpy.ndarray]: """ Create mercator tile from Sentinel-2 data. Attributes ---------- sceneid : str Sentinel-2 sceneid. tile_x : int Mercator tile X index. tile_y : int Mercator tile Y index. tile_z : int Mercator tile ZOOM level. bands : tuple, str, optional (default: ('04', '03', '02')) Bands index for the RGB combination. tilesize : int, optional (default: 256) Output image size. kwargs: dict, optional These will be passed to the 'rio_tiler.utils._tile_read' function. Returns ------- data : numpy ndarray mask: numpy array """ if isinstance(bands, str): bands = (bands, ) scene_params = sentinel2_parser(sceneid) for band in bands: if band not in scene_params["valid_bands"]: raise InvalidBandName( "{} is not a valid Sentinel band name".format(band)) sentinel_prefix = "{scheme}://{bucket}/{prefix}".format(**scene_params) preview_file = os.path.join(sentinel_prefix, scene_params["preview_file"]) with rasterio.open(preview_file) as src: bounds = transform_bounds(src.crs, constants.WGS84_CRS, *src.bounds, densify_pts=21) if not tile_exists(bounds, tile_z, tile_x, tile_y): raise TileOutsideBounds( "Tile {}/{}/{} is outside image bounds".format( tile_z, tile_x, tile_y)) if scene_params["processingLevel"] == "L2A": bands = [_l2_prefixed_band(b) for b in bands] else: bands = ["B{}".format(b) for b in bands] addresses = [f"{sentinel_prefix}/{band}.jp2" for band in bands] return reader.multi_tile(addresses, tile_x, tile_y, tile_z, tilesize=tilesize, nodata=0)
def tile( sceneid: str, tile_x: int, tile_y: int, tile_z: int, bands: Union[Sequence[str], str] = ["4", "3", "2"], tilesize: int = 256, pan: bool = False, **kwargs: Any, ) -> Tuple[numpy.ndarray, numpy.ndarray]: """ Create mercator tile from Landsat-8 data. Attributes ---------- sceneid : str Landsat sceneid. For scenes after May 2017, sceneid have to be LANDSAT_PRODUCT_ID. tile_x : int Mercator tile X index. tile_y : int Mercator tile Y index. tile_z : int Mercator tile ZOOM level. bands : tuple, str, optional (default: ("4", "3", "2")) Bands index for the RGB combination. tilesize : int, optional (default: 256) Output image size. pan : boolean, optional (default: False) If True, apply pan-sharpening. kwargs: dict, optional These will be passed to the 'rio_tiler.utils._tile_read' function. Returns ------- data : numpy ndarray mask: numpy array """ if isinstance(bands, str): bands = (bands,) for band in bands: if band not in LANDSAT_BANDS: raise InvalidBandName("{} is not a valid Landsat band name".format(band)) scene_params = landsat_parser(sceneid) meta: Dict = _landsat_get_mtl(sceneid)["L1_METADATA_FILE"] landsat_prefix = "{scheme}://{bucket}/{prefix}/{scene}".format(**scene_params) bounds = toa_utils._get_bounds_from_metadata(meta["PRODUCT_METADATA"]) if not tile_exists(bounds, tile_z, tile_x, tile_y): raise TileOutsideBounds( "Tile {}/{}/{} is outside image bounds".format(tile_z, tile_x, tile_y) ) def worker(band: str): asset = f"{landsat_prefix}_B{band}.TIF" if band == "QA": nodata = 1 resamp = "nearest" else: nodata = 0 resamp = "bilinear" with rasterio.open(asset) as src_dst: tile, mask = reader.tile( src_dst, tile_x, tile_y, tile_z, tilesize=tilesize, nodata=nodata, resampling_method=resamp, ) return tile, mask with futures.ThreadPoolExecutor(max_workers=constants.MAX_THREADS) as executor: data, masks = zip(*list(executor.map(worker, bands))) data = numpy.concatenate(data) mask = numpy.all(masks, axis=0).astype(numpy.uint8) * 255 if pan: pan_data, mask = worker("8") data = pansharpening_brovey(data, pan_data, 0.2, pan_data.dtype) if bands[0] != "QA" or len(bands) != 1: for bdx, band in enumerate(bands): data[bdx] = _convert(data[bdx], band, meta) return data, mask
def sentinel2_tile(sceneid, tile_x, tile_y, tile_z, bands=("04", "03", "02"), tilesize=256, percents='', **kwargs): """ Create mercator tile from Sentinel-2 data. Attributes ---------- sceneid : str Sentinel-2 sceneid. tile_x : int Mercator tile X index. tile_y : int Mercator tile Y index. tile_z : int Mercator tile ZOOM level. bands : tuple, str, optional (default: ('04', '03', '02')) Bands index for the RGB combination. tilesize : int, optional (default: 256) Output image size. kwargs: dict, optional These will be passed to the 'rio_tiler.utils._tile_read' function. Returns ------- data : numpy ndarray mask: numpy array """ if not isinstance(bands, tuple): bands = tuple((bands, )) for band in bands: if band not in SENTINEL_BANDS: raise InvalidBandName( "{} is not a valid Sentinel band name".format(band)) scene_params = sentinel2._sentinel_parse_scene_id(sceneid) sentinel_address = "{}/{}".format(SENTINEL_BUCKET, scene_params["key"]) addresses = ["{}/B{}.jp2".format(sentinel_address, band) for band in bands] values = [] percents = percents.split(',') i = 0 for address in addresses: with rasterio.open(address) as src: bounds = warp.transform_bounds(src.crs, "epsg:4326", *src.bounds, densify_pts=21) if int(percents[i]) != 0 and int(percents[i + 1]) != 100: overviews = src.overviews(1) if len(overviews) > 0: d = src.read( out_shape=(1, int(src.height / overviews[len(overviews) - 1]), int(src.width / overviews[len(overviews) - 1]))) else: d = src.read() dflatten_full = numpy.array(d.flatten()) dflatten = dflatten_full[dflatten_full > 0] p_start, p_end = numpy.percentile(dflatten, (int(percents[i]), (int(percents[i + 1])))) values.append([p_start, p_end]) else: values.append([None, None]) i += 2 if not utils.tile_exists(bounds, tile_z, tile_x, tile_y): # raise TileOutsideBounds( # "Tile {}/{}/{} is outside image bounds".format(tile_z, tile_x, tile_y) # ) return None, None mercator_tile = mercantile.Tile(x=tile_x, y=tile_y, z=tile_z) tile_bounds = mercantile.xy_bounds(mercator_tile) _tiler = partial(utils.tile_read, bounds=tile_bounds, tilesize=tilesize, nodata=0, **kwargs) with futures.ThreadPoolExecutor(max_workers=MAX_THREADS) as executor: data, masks = zip(*list(executor.map(_tiler, addresses))) mask = numpy.all(masks, axis=0).astype(numpy.uint8) * 255 new_data = list(data) has_modification = False for ds in range(0, len(new_data)): if values[ds][0] is not None and values[ds][1] is not None: has_modification = True new_data[ds] = rescale_intensity(new_data[ds], in_range=(values[ds][0], values[ds][1]), out_range=(0, 255)) if has_modification == True: data = numpy.array(new_data).astype(numpy.uint8) return numpy.concatenate(data), mask
def tile( sceneid: str, tile_x: int, tile_y: int, tile_z: int, bands: Union[Sequence[str], str] = None, tilesize: int = 256, **kwargs: Dict, ) -> Tuple[numpy.ndarray, numpy.ndarray]: """ Create mercator tile from CBERS data. Attributes ---------- sceneid : str CBERS sceneid. tile_x : int Mercator tile X index. tile_y : int Mercator tile Y index. tile_z : int Mercator tile ZOOM level. bands : tuple or list or str, optional Bands index for the RGB combination. If None uses default defined for the instrument tilesize : int, optional Output image size. Default is 256 kwargs: dict, optional These will be passed to the 'rio_tiler.reader.tile' function. Returns ------- data : numpy ndarray mask: numpy array """ if isinstance(bands, str): bands = (bands, ) scene_params = cbers_parser(sceneid) if not bands: bands = scene_params["rgb"] for band in bands: if band not in scene_params["bands"]: raise InvalidBandName( "{} is not a valid band name for {} CBERS instrument".format( band, scene_params["instrument"])) cbers_prefix = "{scheme}://{bucket}/{prefix}/{scene}".format( **scene_params) with rasterio.open("{}_BAND{}.tif".format( cbers_prefix, scene_params["reference_band"])) as src_dst: bounds = transform_bounds(src_dst.crs, constants.WGS84_CRS, *src_dst.bounds, densify_pts=21) if not tile_exists(bounds, tile_z, tile_x, tile_y): raise TileOutsideBounds("Tile {}/{}/{} is outside image bounds".format( tile_z, tile_x, tile_y)) addresses = [f"{cbers_prefix}_BAND{band}.tif" for band in bands] return reader.multi_tile(addresses, tile_x, tile_y, tile_z, tilesize=tilesize, nodata=0)
def tile(sceneid, tile_x, tile_y, tile_z, bands=("4", "3", "2"), tilesize=256, pan=False): """ Create mercator tile from Landsat-8 data. Attributes ---------- sceneid : str Landsat sceneid. For scenes after May 2017, sceneid have to be LANDSAT_PRODUCT_ID. tile_x : int Mercator tile X index. tile_y : int Mercator tile Y index. tile_z : int Mercator tile ZOOM level. bands : tuple, str, optional (default: ("4", "3", "2")) Bands index for the RGB combination. tilesize : int, optional (default: 256) Output image size. pan : boolean, optional (default: False) If True, apply pan-sharpening. Returns ------- data : numpy ndarray mask: numpy array """ if not isinstance(bands, tuple): bands = tuple((bands, )) for band in bands: if band not in LANDSAT_BANDS: raise InvalidBandName( "{} is not a valid Landsat band name".format(band)) scene_params = _landsat_parse_scene_id(sceneid) meta_data = _landsat_get_mtl(sceneid).get("L1_METADATA_FILE") landsat_address = "{}/{}".format(LANDSAT_BUCKET, scene_params["key"]) wgs_bounds = toa_utils._get_bounds_from_metadata( meta_data["PRODUCT_METADATA"]) if not utils.tile_exists(wgs_bounds, tile_z, tile_x, tile_y): raise TileOutsideBounds("Tile {}/{}/{} is outside image bounds".format( tile_z, tile_x, tile_y)) mercator_tile = mercantile.Tile(x=tile_x, y=tile_y, z=tile_z) tile_bounds = mercantile.xy_bounds(mercator_tile) ms_tile_size = int(tilesize / 2) if pan else tilesize addresses = ["{}_B{}.TIF".format(landsat_address, band) for band in bands] _tiler = partial(utils.tile_read, bounds=tile_bounds, tilesize=ms_tile_size, nodata=0) with futures.ThreadPoolExecutor(max_workers=MAX_THREADS) as executor: data, masks = zip(*list(executor.map(_tiler, addresses))) data = np.concatenate(data) mask = np.all(masks, axis=0).astype(np.uint8) * 255 if pan: pan_address = "{}_B8.TIF".format(landsat_address) matrix_pan, mask = utils.tile_read(pan_address, tile_bounds, tilesize, nodata=0) w, s, e, n = tile_bounds pan_transform = transform.from_bounds(w, s, e, n, tilesize, tilesize) vis_transform = pan_transform * Affine.scale(2.0) data = pansharpen( data, vis_transform, matrix_pan, pan_transform, np.int16, "EPSG:3857", "EPSG:3857", 0.2, method="Brovey", src_nodata=0, ) sun_elev = meta_data["IMAGE_ATTRIBUTES"]["SUN_ELEVATION"] for bdx, band in enumerate(bands): if int(band) > 9: # TIRS multi_rad = meta_data["RADIOMETRIC_RESCALING"].get( "RADIANCE_MULT_BAND_{}".format(band)) add_rad = meta_data["RADIOMETRIC_RESCALING"].get( "RADIANCE_ADD_BAND_{}".format(band)) k1 = meta_data["TIRS_THERMAL_CONSTANTS"].get( "K1_CONSTANT_BAND_{}".format(band)) k2 = meta_data["TIRS_THERMAL_CONSTANTS"].get( "K2_CONSTANT_BAND_{}".format(band)) data[bdx] = brightness_temp.brightness_temp( data[bdx], multi_rad, add_rad, k1, k2) else: multi_reflect = meta_data["RADIOMETRIC_RESCALING"].get( "REFLECTANCE_MULT_BAND_{}".format(band)) add_reflect = meta_data["RADIOMETRIC_RESCALING"].get( "REFLECTANCE_ADD_BAND_{}".format(band)) data[bdx] = 10000 * reflectance.reflectance( data[bdx], multi_reflect, add_reflect, sun_elev) return data, mask
def tile(sceneid, tile_x, tile_y, tile_z, bands=("04", "03", "02"), tilesize=256, **kwargs): """ Create mercator tile from Sentinel-2 data. Attributes ---------- sceneid : str Sentinel-2 sceneid. tile_x : int Mercator tile X index. tile_y : int Mercator tile Y index. tile_z : int Mercator tile ZOOM level. bands : tuple, str, optional (default: ('04', '03', '02')) Bands index for the RGB combination. tilesize : int, optional (default: 256) Output image size. kwargs: dict, optional These will be passed to the 'rio_tiler.utils._tile_read' function. Returns ------- data : numpy ndarray mask: numpy array """ scene_params = _sentinel_parse_scene_id(sceneid) if not isinstance(bands, tuple): bands = tuple((bands, )) for band in bands: if band not in scene_params["valid_bands"]: raise InvalidBandName( "{} is not a valid Sentinel band name".format(band)) preview_file = os.path.join( scene_params["aws_bucket"], scene_params["aws_prefix"], scene_params["preview_file"], ) with rasterio.open(preview_file) as src: bounds = transform_bounds(src.crs, "epsg:4326", *src.bounds, densify_pts=21) if not utils.tile_exists(bounds, tile_z, tile_x, tile_y): raise TileOutsideBounds("Tile {}/{}/{} is outside image bounds".format( tile_z, tile_x, tile_y)) mercator_tile = mercantile.Tile(x=tile_x, y=tile_y, z=tile_z) tile_bounds = mercantile.xy_bounds(mercator_tile) path_prefix = os.path.join(scene_params["aws_bucket"], scene_params["aws_prefix"]) if scene_params["processingLevel"] == "L2A": bands = [_l2_prefixed_band(b) for b in bands] else: bands = ["B{}".format(b) for b in bands] def _read_tile(path): with rasterio.open(path) as src_dst: return utils.tile_read(src_dst, bounds=tile_bounds, tilesize=tilesize, nodata=0, **kwargs) addresses = ["{}/{}.jp2".format(path_prefix, band) for band in bands] with futures.ThreadPoolExecutor(max_workers=MAX_THREADS) as executor: data, masks = zip(*list(executor.map(_read_tile, addresses))) mask = np.all(masks, axis=0).astype(np.uint8) * 255 return np.concatenate(data), mask
def tile(sceneid, tile_x, tile_y, tile_z, rgb=(4, 3, 2), r_bds=(0, 16000), g_bds=(0, 16000), b_bds=(0, 16000), tilesize=256, pan=False): """Create mercator tile from Landsat-8 data and encodes it in base64. Attributes ---------- sceneid : str Landsat sceneid. For scenes after May 2017, sceneid have to be LANDSAT_PRODUCT_ID. tile_x : int Mercator tile X index. tile_y : int Mercator tile Y index. tile_z : int Mercator tile ZOOM level. rgb : tuple, int, optional (default: (4, 3, 2)) Bands index for the RGB combination. r_bds : tuple, int, optional (default: (0, 16000)) First band (red) DN min and max values (DN * 10,000) used for the linear rescaling. g_bds : tuple, int, optional (default: (0, 16000)) Second band (green) DN min and max values (DN * 10,000) used for the linear rescaling. b_bds : tuple, int, optional (default: (0, 16000)) Third band (blue) DN min and max values (DN * 10,000) used for the linear rescaling. tilesize : int, optional (default: 256) Output image size. pan : boolean, optional (default: False) If True, apply pan-sharpening. Returns ------- out : numpy ndarray (type: uint8) """ scene_params = utils.landsat_parse_scene_id(sceneid) meta_data = utils.landsat_get_mtl(sceneid).get('L1_METADATA_FILE') landsat_address = '{}/{}'.format(LANDSAT_BUCKET, scene_params['key']) wgs_bounds = toa_utils._get_bounds_from_metadata( meta_data['PRODUCT_METADATA']) if not utils.tile_exists(wgs_bounds, tile_z, tile_x, tile_y): raise TileOutsideBounds('Tile {}/{}/{} is outside image bounds'.format( tile_z, tile_x, tile_y)) mercator_tile = mercantile.Tile(x=tile_x, y=tile_y, z=tile_z) tile_bounds = mercantile.xy_bounds(mercator_tile) # define a list of bands Min and Max Values (from input) histo_cuts = dict(zip(rgb, [r_bds, g_bds, b_bds])) ms_tile_size = int(tilesize / 2) if pan else tilesize addresses = ['{}_B{}.TIF'.format(landsat_address, band) for band in rgb] _tiler = partial(utils.tile_band_worker, bounds=tile_bounds, tilesize=ms_tile_size) with futures.ThreadPoolExecutor(max_workers=3) as executor: out = np.stack(list(executor.map(_tiler, addresses))) if pan: pan_address = '{}_B8.TIF'.format(landsat_address) matrix_pan = utils.tile_band_worker(pan_address, tile_bounds, tilesize) w, s, e, n = tile_bounds pan_transform = transform.from_bounds(w, s, e, n, tilesize, tilesize) vis_transform = pan_transform * Affine.scale(2.) out = pansharpen(out, vis_transform, matrix_pan, pan_transform, np.int16, 'EPSG:3857', 'EPSG:3857', 0.2, method='Brovey', src_nodata=0) sun_elev = meta_data['IMAGE_ATTRIBUTES']['SUN_ELEVATION'] for bdx, band in enumerate(rgb): multi_reflect = meta_data['RADIOMETRIC_RESCALING'].get( 'REFLECTANCE_MULT_BAND_{}'.format(band)) add_reflect = meta_data['RADIOMETRIC_RESCALING'].get( 'REFLECTANCE_ADD_BAND_{}'.format(band)) out[bdx] = 10000 * reflectance.reflectance( out[bdx], multi_reflect, add_reflect, sun_elev, src_nodata=0) out[bdx] = np.where( out[bdx] > 0, utils.linear_rescale(out[bdx], in_range=histo_cuts.get(band), out_range=[1, 255]), 0) return out.astype(np.uint8)
def tile(sceneid, tile_x, tile_y, tile_z, rgb=(4, 3, 2), tilesize=256, pan=False): """Create mercator tile from Landsat-8 data. Attributes ---------- sceneid : str Landsat sceneid. For scenes after May 2017, sceneid have to be LANDSAT_PRODUCT_ID. tile_x : int Mercator tile X index. tile_y : int Mercator tile Y index. tile_z : int Mercator tile ZOOM level. rgb : tuple, int, optional (default: (4, 3, 2)) Bands index for the RGB combination. tilesize : int, optional (default: 256) Output image size. pan : boolean, optional (default: False) If True, apply pan-sharpening. Returns ------- data : numpy ndarray mask: numpy array """ if not isinstance(rgb, tuple): rgb = tuple((rgb, )) scene_params = utils.landsat_parse_scene_id(sceneid) meta_data = utils.landsat_get_mtl(sceneid).get('L1_METADATA_FILE') landsat_address = '{}/{}'.format(LANDSAT_BUCKET, scene_params['key']) wgs_bounds = toa_utils._get_bounds_from_metadata( meta_data['PRODUCT_METADATA']) if not utils.tile_exists(wgs_bounds, tile_z, tile_x, tile_y): raise TileOutsideBounds( 'Tile {}/{}/{} is outside image bounds'.format( tile_z, tile_x, tile_y)) mercator_tile = mercantile.Tile(x=tile_x, y=tile_y, z=tile_z) tile_bounds = mercantile.xy_bounds(mercator_tile) ms_tile_size = int(tilesize / 2) if pan else tilesize addresses = ['{}_B{}.TIF'.format(landsat_address, band) for band in rgb] _tiler = partial(utils.tile_band_worker, bounds=tile_bounds, tilesize=ms_tile_size, nodata=0) with futures.ThreadPoolExecutor(max_workers=3) as executor: data, masks = zip(*list(executor.map(_tiler, addresses))) data = np.concatenate(data) mask = np.all(masks, axis=0).astype(np.uint8) * 255 if pan: pan_address = '{}_B8.TIF'.format(landsat_address) matrix_pan, mask = utils.tile_band_worker(pan_address, tile_bounds, tilesize, nodata=0) w, s, e, n = tile_bounds pan_transform = transform.from_bounds(w, s, e, n, tilesize, tilesize) vis_transform = pan_transform * Affine.scale(2.) data = pansharpen(data, vis_transform, matrix_pan, pan_transform, np.int16, 'EPSG:3857', 'EPSG:3857', 0.2, method='Brovey', src_nodata=0) sun_elev = meta_data['IMAGE_ATTRIBUTES']['SUN_ELEVATION'] for bdx, band in enumerate(rgb): if int(band) > 9: # TIRS multi_rad = meta_data['RADIOMETRIC_RESCALING'].get( 'RADIANCE_MULT_BAND_{}'.format(band)) add_rad = meta_data['RADIOMETRIC_RESCALING'].get( 'RADIANCE_ADD_BAND_{}'.format(band)) k1 = meta_data['TIRS_THERMAL_CONSTANTS'].get( 'K1_CONSTANT_BAND_{}'.format(band)) k2 = meta_data['TIRS_THERMAL_CONSTANTS'].get( 'K2_CONSTANT_BAND_{}'.format(band)) data[bdx] = brightness_temp.brightness_temp( data[bdx], multi_rad, add_rad, k1, k2) else: multi_reflect = meta_data['RADIOMETRIC_RESCALING'].get( 'REFLECTANCE_MULT_BAND_{}'.format(band)) add_reflect = meta_data['RADIOMETRIC_RESCALING'].get( 'REFLECTANCE_ADD_BAND_{}'.format(band)) data[bdx] = 10000 * reflectance.reflectance( data[bdx], multi_reflect, add_reflect, sun_elev) return data, mask