Source code for onstove.raster

import glob
import gzip

import fiona
import numpy as np

import rasterio
import rasterio.mask
from rasterio.merge import merge
from rasterio.warp import calculate_default_transform, reproject, Resampling
from rasterio.enums import Resampling as enumsResampling


[docs]def align_raster(raster_1, raster_2, method='nearest', compression='DEFLATE'): raster_1_meta = raster_1.meta raster_2_meta = raster_2.meta out_meta = raster_1_meta.copy() out_meta.update({ 'transform': raster_1_meta['transform'], 'crs': raster_1_meta['crs'], 'compress': compression, 'nodata': raster_2_meta['nodata'], 'dtype': raster_2_meta['dtype'] }) destination = np.full((raster_1_meta['height'], raster_1_meta['width']), raster_2_meta['nodata']) reproject( source=raster_2.data, destination=destination, src_transform=raster_2_meta['transform'], src_crs=raster_2_meta['crs'], src_nodata=raster_2_meta['nodata'], dst_transform=raster_1_meta['transform'], dst_crs=raster_1_meta['crs'], resampling=Resampling[method]) return destination, out_meta
# def interpolate(raster, max_search_distance=10): # with rasterio.open(raster) as src: # profile = src.profile # arr = src.read(1) # arr_filled = fillnodata(arr, mask=src.read_masks(1), max_search_distance=max_search_distance) # # with rasterio.open(raster, 'w', **profile) as dest: # dest.write_band(1, arr_filled)
[docs]def mask_raster(raster_path, mask_layer, output_file, nodata=0, compression='NONE', all_touched=False): if isinstance(mask_layer, str): with fiona.open(mask_layer, "r") as shapefile: shapes = [feature["geometry"] for feature in shapefile] crs = 'EPSG:4326' else: shapes = [mask_layer.dissolve().geometry.loc[0]] crs = mask_layer.crs if '.gz' in raster_path: with gzip.open(raster_path) as gzip_infile: with rasterio.open(gzip_infile) as src: out_image, out_transform = rasterio.mask.mask(src, shapes, crop=True, nodata=nodata, all_touched=all_touched) out_meta = src.meta else: with rasterio.open(raster_path) as src: out_image, out_transform = rasterio.mask.mask(src, shapes, crop=True, nodata=nodata, all_touched=all_touched) out_meta = src.meta out_meta.update({"driver": "GTiff", "height": out_image.shape[1], "width": out_image.shape[2], "transform": out_transform, 'compress': compression, 'nodata': nodata, "crs": crs}) with rasterio.open(output_file, "w", **out_meta) as dest: dest.write(out_image)
[docs]def reproject_raster(raster_path, dst_crs, cell_width=None, cell_height=None, method='nearest', compression='DEFLATE'): """ Resamples and/or reproject a raster layer. """ with rasterio.open(raster_path) as src: # Calculates the new transform, widht and height of # the reprojected layer transform, width, height = calculate_default_transform( src.crs, dst_crs, src.width, src.height, *src.bounds) # If a destination cell width and height was provided, then it # calculates the new boundaries, with, heigh and transform # depending on the new cell size. if cell_width and cell_height: bounds = rasterio.transform.array_bounds(height, width, transform) width = int(width * (transform[0] / cell_width)) height = int(height * (abs(transform[4]) / cell_height)) transform = rasterio.transform.from_origin(bounds[0], bounds[3], cell_width, cell_height) # Updates the metadata out_meta = src.meta.copy() out_meta.update({ 'crs': dst_crs, 'transform': transform, 'width': width, 'height': height, 'compress': compression }) # The layer is then reprojected/resampled # if output_file: # # if an output file path was provided, then the layer is saved # with rasterio.open(output_file, 'w', **out_meta) as dst: # for i in range(1, src.count + 1): # reproject( # source=rasterio.band(src, i), # destination=rasterio.band(dst, i), # src_transform=src.transform, # src_crs=src.crs, # dst_transform=transform, # dst_crs=dst_crs, # resampling=Resampling[method]) # else: # If not outputfile is provided, then a numpy array and the # metadata if returned destination = np.full((height, width), src.nodata) reproject( source=rasterio.band(src, 1), destination=destination, src_transform=src.transform, src_crs=src.crs, dst_transform=transform, dst_crs=dst_crs, resampling=Resampling[method]) return destination, out_meta
[docs]def sample_raster(path, gdf): with rasterio.open(path) as src: return [float(val) for val in src.sample([(x.coords.xy[0][0], x.coords.xy[1][0]) for x in gdf['geometry']])]
[docs]def merge_rasters(files_path, dst_crs, outpul_file): files = glob.glob(files_path) src_files_to_mosaic = [] for fp in files: src = rasterio.open(fp) src_files_to_mosaic.append(src) mosaic, out_trans = merge(src_files_to_mosaic) out_meta = src.meta.copy() out_meta.update({"driver": "GTiff", "height": mosaic[0].shape[0], "width": mosaic[0].shape[1], "transform": out_trans, "crs": dst_crs } ) with rasterio.open(outpul_file, "w", **out_meta) as dest: dest.write(mosaic[0], indexes=1)
[docs]def normalize(raster=None, limit=None, output_file=None, inverse=False, meta=None, buffer=False): if isinstance(raster, str): with rasterio.open(raster) as src: raster = src.read(1) nodata = src.nodata meta = src.meta else: raster = raster.copy() nodata = meta['nodata'] meta = meta if callable(limit): raster[~limit(raster)] = np.nan raster[raster == nodata] = np.nan min_value = np.nanmin(raster) max_value = np.nanmax(raster) raster = (raster - min_value) / (max_value - min_value) if inverse: if not buffer: raster[np.isnan(raster)] = 1 raster[raster < 0] = np.nan raster = 1 - raster else: if not buffer: raster[np.isnan(raster)] = 0 raster[raster < 0] = np.nan meta.update(nodata=np.nan, dtype='float32') if output_file: with rasterio.open(output_file, "w", **meta) as dest: dest.write(raster.astype('float32'), indexes=1) else: return raster, meta
[docs]def resample(raster_path, height, width, method='bilinear'): with rasterio.open(raster_path) as src: # resample data to target shape data = src.read( out_shape=( src.count, int(src.height * (abs(src.transform[4]) / height)), int(src.width * (abs(src.transform[0]) / width)) ), resampling=enumsResampling[method] ) # scale image transform transform = src.transform * src.transform.scale( (src.width / data.shape[-1]), (src.height / data.shape[-2]) ) return data, transform