def find_tile_overlap(indir, ref): """ Find overlapping areas (polygons) between a reference (ref) and target rasters. Polygons are written to disk indir : strg Full path to the directory containing all raster files ref : strg Filename of the reference raster. Filenames are expected to have the following format: tileName_date.tif, e.g. 'T20MPA_20200729.tif' """ rfiles = [rfile for rfile in os.listdir(indir) if rfile.endswith('.tif') and rfile != ref] outdir = os.path.join(indir, 'overlaps') if not os.path.exists(outdir): os.makedirs(outdir) with ExitStack() as stack_files: src_ref = stack_files.enter_context(rasterio.open(os.path.join(indir, ref))) srcs = [stack_files.enter_context(rasterio.open(os.path.join(indir, f))) for f in rfiles] poly_ref = box(*src_ref.bounds) for idx, src in enumerate(srcs, start=1): print("") print(f"Check overlap between {src_ref.files[0]} and {src.files[0]}") poly = box(*src.bounds) intersect = poly_ref.intersection(poly) try: arr, meta = rst.load_raster_from_poly(src, intersect) meta.update({ "interleave": "band"}) arr_ref, meta_ref = rst.load_raster_from_poly(src_ref, intersect) meta_ref.update({ "interleave": "band"}) print(f"Overlap found, getting arrays from polygon: {idx}") except ValueError: print(f"No overlap found for poly: {idx}") continue else: tile_ref = src_ref.files[0].split("/")[-1].split("_")[0] tile_target = src.files[0].split("/")[-1].split("_")[0] fname_ref = "_".join([f"poly_{idx}", tile_ref]) + ".tif" fname_target = "_".join([f"poly_{idx}", tile_target]) + ".tif" rst.write_array_as_raster(arr, meta, os.path.join(outdir, fname_target)) rst.write_array_as_raster(arr_ref, meta_ref, os.path.join(outdir, fname_ref))
def make_raster_stack(): with ExitStack() as stack_files: # use SCL file to create a cloud-mask array ras_scl = stack_files.enter_context(rasterio.open(s20.get_fpaths('SCL_20m')[0])) arr_scl, meta_scl = rst.load_raster_from_poly(ras_scl, poly) arr_mask, _ = rst.mask_vals(arr_scl, meta_scl, [3,7,8,9,10]) # collect all relevant bands ras10 = [stack_files.enter_context(rasterio.open(fp)) for fp in s10.get_fpaths( 'B08_10m')] ras20 = [stack_files.enter_context(rasterio.open(fp)) for fp in s20.get_fpaths('B02_20m', 'B03_20m', 'B04_20m', 'B05_20m', 'B06_20m', 'B07_20m', 'B8A_20m', 'B11_20m', 'B12_20m')] ras_collect = ras10+ras20 with ExitStack() as stack_action: rstack = Rstack() for idx_ras, src in enumerate(ras_collect): if int(src.res[0]) == 10: # resample to 20 m logger.info(f"Resampling: {src.files[0]} to 20 m resolution") arr_r, meta = rst.load_resample(src, 0.5) src = stack_action.enter_context(rst.to_src(arr_r, meta)) arr, meta = rst.load_raster_from_poly(src, poly) arr_masked = rst.apply_mask(arr, arr_mask.mask, fill_value=9999) src = stack_action.enter_context(rst.to_src(arr_masked, meta)) logger.info(f"Add raster with resulution: {src.res} to the stack") rstack.add_item(src) # calc indexes indexes_to_calc = OrderedDict([("calc_ndvi", [rstack.items[3], rstack.items[0]]), ("calc_nbr", [rstack.items[0], rstack.items[9]]), ("calc_bsi", [rstack.items[1], rstack.items[3], rstack.items[0], rstack.items[9]]), ("calc_ndwi", [rstack.items[2], rstack.items[0]])]) indexes = Indexes(metadata=rstack.items[0].profile) for idx,vals in indexes_to_calc.items(): arr_idx, meta_idx = getattr(indexes, idx)(*vals) arr_idx_masked = rst.apply_mask(arr_idx, arr_mask.mask, fill_value=9999) src_idx = stack_action.enter_context(rst.to_src(arr_idx_masked, meta_idx)) rstack.add_item(src_idx) # final bands order of the stack rstack.set_metadata_param('interleave', 'band') order = [1, 2, 3, 4, 5, 6, 0, 7, 8, 9, 10, 11, 12, 13] rstack.reorder_items(order) fname = "_".join([s20.get_tile_number("B02_20m"), s20.get_datetake("B02_20m")])+"_stack.tif" fpath = rst.write_raster(rstack.items, rstack.metadata_collect, os.path.join(OUTDIR, fname)) return fpath
def find_total_overlaps(indir): fpaths = [os.path.join(indir, rfile) for rfile in os.listdir(indir) if rfile.endswith('.tif')] with ExitStack() as stack_files: srcs = [stack_files.enter_context(rasterio.open(fp)) for fp in fpaths] polys = [box(*src.bounds) for src in srcs] intersects = [] for poly, poly_front in ut.gen_current_front_pairs(polys): if poly.intersects(poly_front) and poly.intersection(poly_front) not in intersects: intersects.append(poly.intersection(poly_front)) print(intersects) # save a polygon #gdf1 = gpd.GeoDataFrame({"geometry": intersects}, crs=f"EPSG:{srcs[0].crs.to_epsg()}") #gdf1.to_file(os.path.join(BASEDIR, "overlap_polygon")) for src in srcs: print("") print(f"Run for raster: {src.files[0]} ..") for idx, intersect in enumerate(intersects, start=1): try: arr, meta = rst.load_raster_from_poly(src, intersect) print(f"Overlap found, getting arr from poly: {idx}") except ValueError: print(f"No overlap found for poly: {idx}") continue else: fname = "_".join([f"poly_{idx}", str(arr.shape[1]), str(arr.shape[2])]) + ".tif" print(fname) print(arr.shape) meta.update({ "interleave": "band"}) outdir = os.path.join(indir, src.files[0].split("/")[-1].split("_")[1]) if not os.path.exists(outdir): os.makedirs(outdir) rst.write_array_as_raster(arr, meta, os.path.join(outdir, fname))
def stack_sent2_bands(indir, bands, outdir, resolution=10, mask=False, window=None, polygon=None, indexes=None, fname=None): """ Create a stack of sentinel 2 bands with defined spacial resolution ********** params --------- indir : strg full path to the IMG_DATA folder. This directory is expected to have the standard sent2 structure, i.e. three subdirerctories: R10m, R20m and R60m bands : list Bands that should be included into the stack, e.g. 'B02_10m' or 'B05_20m' outdir : strg full path to the output directory resolution : int final resolution of all the bands of the stack mask : numpy boolean mask arr window : rasterio.windows.Window Define a final extent of the stack polygon : GEOJson-like dict e.g. { 'type': 'Polygon', 'coordinates': [[(),(),(),()]] } Define a final extent of the stack fnam: strg Name of the output raster stack; e.g. my_stack.tif indexes: OrderDict """ s10 = Sentinel2(os.path.join(indir, 'R10m')) s20 = Sentinel2(os.path.join(indir, 'R20m')) if window is not None and polygon is not None: raise ValueError("Cannot choose both window and polygon params!") with ExitStack() as stack_files: fpaths = [] for band in bands: try: fpaths.append(s10.get_fpath(band)) except KeyError: try: fpaths.append(s20.get_fpath(band)) except KeyError: raise ValueError(f"Cannot find band: '{band}'. Please provide valid band name.") srcs = [stack_files.enter_context(rasterio.open(fp)) for fp in fpaths] band_src_map = dict(zip(bands, srcs)) with ExitStack() as stack_action: rstack = Rstack() for band, src in band_src_map.items(): print(f'Band {band} to be processed..') if int(src.res[0]) != resolution: # resample to match res param print(f'Band: {band} will be resampled to {resolution} m resolution..') scale_factor = src.res[0] / resolution arr, meta = rst.load_resample(src, scale_factor) src = stack_action.enter_context(rst.to_src(arr, meta)) if window: print(f'Selected a window: {window} as AOI') arr, meta = rst.load_window(src, window) src = stack_action.enter_context(rst.to_src(arr, meta)) if polygon: print(f"Selected a polygon as AOI") arr, meta = rst.load_raster_from_poly(src, polygon) src = stack_action.enter_context(rst.to_src(arr, meta)) if np.any(mask): print(f"Selected a mask for band {band}") # check that mask and array are the same dimension arr, meta = rst.load(src) assert mask.shape == arr.shape, 'Array and mask must the have same shape' arr = rst.apply_mask(arr, mask, fill_value=9999) src = stack_action.enter_context(rst.to_src(arr, meta)) band_src_map[band] = src # update the mapping rstack.add_item(src) if indexes: print(f'Compute indexes: {indexes.keys()} and add them to the stack') to_calc = Indexes(metadata=rstack.items[0].profile) for idx,vals in indexes.items(): try: vals = [band_src_map[v] for v in vals] except KeyError: raise ValueError(f"One or more bands: '{vals}' were not defined as part of the stack.") try: arr_idx, meta_idx = getattr(to_calc, idx)(*vals) except AttributeError: raise ValueError(f"'{idx}' is not a valid Index method") arr_idx, meta_idx = getattr(to_calc, idx)(*vals) src_idx = stack_action.enter_context(rst.to_src(arr_idx, meta_idx)) band_src_map[idx] = src_idx # update the mapping rstack.add_item(src_idx) rstack.set_metadata_param('interleave', 'band') print(band_src_map.keys()) if not fname: fname = '_'.join([s10.get_tile_number('B02_10m'), s10.get_datetake('B02_10m')])+'.tif' if not os.path.exists(outdir): os.makedirs(outdir) fpath = rst.write_raster(rstack.items, rstack.metadata_collect, os.path.join(outdir, fname)) return fpath
if __name__ == "__main__": # Globals OUTDIR = "" # change me BASEDIR = "" # change me (Full path to IMG_DATA) DATA10 = "R10m/" DATA20 = "R20m/" POINTS_FP = "" # change me s10 = Sentinel2(os.path.join(BASEDIR, DATA10)) s20 = Sentinel2(os.path.join(BASEDIR, DATA20)) gdf = gpd.read_file(POINTS_FP) poly = box(*list(gdf.total_bounds)) with rasterio.open(s20.get_fpaths('TCI_20m')[0]) as ras_tci: # get the AOI over TCI and save to disk arr_tci, meta_tci = rst.load_raster_from_poly(ras_tci, poly) fname_tci = "_".join([s20.get_tile_number("TCI_20m"), s20.get_datetake("TCI_20m")])+"_AOI.tif" rst.write_array_as_raster(arr_tci, meta_tci, os.path.join(OUTDIR, fname_tci)) fp = make_raster_stack() X, y = extract_Xy(fp) for run in range(1, 31): logger.info("") logger.info(f"Start run {run}") clf = train_RandomForestClf(X, y, estimators=200) with rasterio.open(fp) as src: fname_cls = "_".join([os.path.basename(fp).split(".")[0], "classification_map_" , str(run) +".json"])
for poly, poly_front in ut.gen_current_front_pairs(polys): if poly.intersects(poly_front) and poly.intersection( poly_front) not in intersects: intersects.append(poly.intersection(poly_front)) print(intersects) # save a polygon #gdf1 = gpd.GeoDataFrame({"geometry": intersects}, crs=f"EPSG:{srcs[0].crs.to_epsg()}") #gdf1.to_file(os.path.join(BASEDIR, "overlap_polygon")) for src in srcs: print("") print(f"Run for raster: {src.files[0]} ..") for idx, intersect in enumerate(intersects, start=1): try: arr, meta = rst.load_raster_from_poly(src, intersect) print(f"Overlap found, getting arr from poly: {idx}") except ValueError: print(f"No overlap found for poly: {idx}") continue else: fname = "_".join([ os.path.dirname( src.files[0]).split("/")[-1].split("_")[0], f"poly_{idx}", str(arr.shape[1]), str(arr.shape[2]) ]) + ".tif" print(fname) print(arr.shape) meta.update({"interleave": "band"})