def _resample_raster(raster, out_file, factor): """ Resample raster Parameters ---------- raster: RasterBase raster to resample out_file: str output file to which to write new raster factor: int or float Resampling factor """ geo_transform = (raster.x_origin, raster.resolution[0] / factor, 0, raster.y_origin, 0, -raster.resolution[1] / factor) out_ds = _gdal_temp_dataset(out_file, raster._gdal_driver, raster._gdal_dataset.GetProjection(), raster.x_size * factor, raster.y_size * factor, raster.nb_band, geo_transform, raster.data_type, raster.no_data) for band in range(1, raster.nb_band + 1): gdal.RegenerateOverview(raster._gdal_dataset.GetRasterBand(band), out_ds.GetRasterBand(band), 'mode') # Close dataset out_ds = None
def _rasterize(raster_class, geodataframe, burn_values, attribute, gdal_driver, projection, x_size, y_size, nb_band, geo_transform, data_type, no_data, all_touched): """ Rasterize geographic layer Parameters ---------- raster_class: RasterBase Raster class to return geodataframe: geopandas.GeoDataFrame or gistools.layer.GeoLayer Geographic layer to be rasterized burn_values: None or list[float] or list[int] list of values to burn in each band, excusive with attribute attribute: str attribute in layer from which burn value must be retrieved gdal_driver projection x_size: int y_size: int nb_band: int geo_transform: tuple data_type no_data all_touched: bool Returns ------- """ with ShapeTempFile() as shp_file, \ RasterTempFile(gdal_driver.GetMetadata()['DMD_EXTENSION']) as out_file: geodataframe.to_file(shp_file.path, driver=ESRI_DRIVER) out_ds = _gdal_temp_dataset(out_file.path, gdal_driver, projection, x_size, y_size, nb_band, geo_transform, data_type, no_data) gdal.Rasterize(out_ds, shp_file.path, bands=[bd + 1 for bd in range(nb_band)], burnValues=burn_values, attribute=attribute, allTouched=all_touched) out_ds = None # Be careful with the temp file, make a pointer to be sure # the Python garbage collector does not destroy it ! raster = raster_class(out_file.path) raster._temp_file = out_file return raster
def _array_to_raster(raster_class, array, crs, bounds, gdal_driver, no_data): """ Convert array to (north up) raster Parameters ---------- array: numpy.ndarray crs: pyproj.CRS bounds: tuple Image boundaries as (xmin, ymin, xmax, ymax) gdal_driver: osgeo.gdal.Driver no_data Returns ------- """ if array.ndim == 2: nb_band = 1 x_size = array.shape[1] y_size = array.shape[0] else: nb_band = array.shape[0] x_size = array.shape[2] y_size = array.shape[1] xmin, ymin, xmax, ymax = bounds geo_transform = (xmin, (xmax - xmin) / x_size, 0, ymax, 0, -(ymax - ymin) / y_size) with RasterTempFile( gdal_driver.GetMetadata()['DMD_EXTENSION']) as out_file: out_ds = _gdal_temp_dataset( out_file.path, gdal_driver, crs.to_wkt(), x_size, y_size, nb_band, geo_transform, gdal_array.NumericTypeCodeToGDALTypeCode(array.dtype), no_data) if nb_band == 1: out_ds.GetRasterBand(nb_band).WriteArray(array) else: for band in range(nb_band): out_ds.GetRasterBand(band + 1).WriteArray(array[band, :, :]) # Close dataset out_ds = None raster = raster_class(out_file.path) raster._temp_file = out_file return raster
def _align_raster(in_raster, out_file, on_raster): """ Align raster on other raster """ out_ds = _gdal_temp_dataset(out_file, in_raster._gdal_driver, on_raster._gdal_dataset.GetProjection(), on_raster.x_size, on_raster.y_size, in_raster.nb_band, on_raster.geo_transform, in_raster.data_type, in_raster.no_data) gdal.Warp(out_ds, in_raster._gdal_dataset) # Close dataset out_ds = None
def _windowing(raster, out_file, function, band, window_size, method, data_type, no_data, chunk_size, nb_processes): """ Apply function in each moving or block window in raster Description ----------- Parameters ---------- """ window_generator = WindowGenerator(raster, band, window_size, method) out_ds = _gdal_temp_dataset(out_file, raster._gdal_driver, raster._gdal_dataset.GetProjection(), window_generator.x_size, window_generator.y_size, raster.nb_band, window_generator.geo_transform, data_type, no_data) y = 0 # chunk size cannot be 0 and cannot # be higher than height of window # generator (y_size). And it must be # a multiple of window generator width # (x_size) chunk_size = max(min(chunk_size // window_generator.x_size, window_generator.y_size) * window_generator.x_size, window_generator.x_size) for win_gen in tqdm(split_into_chunks(window_generator, chunk_size), total=len(window_generator)//chunk_size + int(len(window_generator) % chunk_size != 0), desc="Sliding window computation"): with mp.Pool(processes=nb_processes) as pool: output = np.asarray(list(pool.map(partial(_set_nan, function=function, no_data=raster.no_data), win_gen, chunksize=MP_CHUNK_SIZE))) output[np.isnan(output)] = no_data # Set number of rows to write to file n_rows = len(output) // window_generator.x_size # Write row to raster out_ds.GetRasterBand(band).WriteArray(np.reshape(output, (n_rows, window_generator.x_size)), 0, y) # Update row index y += n_rows # Close dataset out_ds = None
def _clip_raster_by_mask(raster, geodataframe, no_data, all_touched): """ Clip raster by mask from geographic layer Parameters ---------- raster: pyrasta.raster.RasterBase raster to clip geodataframe: geopandas.GeoDataFrame or gistools.layer.GeoLayer no_data: float or int No data value all_touched: bool if True, clip all pixels that are touched, otherwise clip if pixel's centroids are within boundaries Returns ------- RasterBase """ clip_raster = raster.clip(bounds=geodataframe.total_bounds) with ShapeTempFile() as shp_file, \ RasterTempFile(clip_raster._gdal_driver.GetMetadata()['DMD_EXTENSION']) as r_file: geodataframe.to_file(shp_file.path, driver=ESRI_DRIVER) out_ds = _gdal_temp_dataset(r_file.path, clip_raster._gdal_driver, clip_raster._gdal_dataset.GetProjection(), clip_raster.x_size, clip_raster.y_size, clip_raster.nb_band, clip_raster.geo_transform, clip_raster.data_type, clip_raster.no_data) gdal.Rasterize(out_ds, shp_file.path, burnValues=[1], allTouched=all_touched) out_ds = None return clip_raster.__class__.raster_calculation( [clip_raster, clip_raster.__class__(r_file.path)], lambda x, y: x * y, no_data=no_data, showprogressbar=False)
def _return_classification(raster, nb_classes, *args, **kwargs): with RasterTempFile(raster._gdal_driver.GetMetadata() ['DMD_EXTENSION']) as out_file: out_ds = _gdal_temp_dataset(out_file.path, raster._gdal_driver, raster._gdal_dataset.GetProjection(), raster.x_size, raster.y_size, 1, raster.geo_transform, gdal.GetDataTypeByName('Int16'), no_data=CLASSIFICATION_NO_DATA) labels = classification(raster, nb_classes, out_ds, *args, **kwargs) # Close dataset out_ds = None new_raster = raster.__class__(out_file.path) new_raster._temp_file = out_file return new_raster
def _padding(raster, out_file, pad_x, pad_y, pad_value): """ Add pad values around raster Description ----------- Parameters ---------- raster: RasterBase raster to pad out_file: str output file to which to write new raster pad_x: int x padding size (new width will therefore be RasterXSize + 2 * pad_x) pad_y: int y padding size (new height will therefore be RasterYSize + 2 * pad_y) pad_value: int or float value to set to pad area around raster Returns ------- """ geo_transform = (raster.x_origin - pad_x * raster.resolution[0], raster.resolution[0], 0, raster.y_origin + pad_y * raster.resolution[1], 0, -raster.resolution[1]) out_ds = _gdal_temp_dataset(out_file, raster._gdal_driver, raster._gdal_dataset.GetProjection(), raster.x_size + 2 * pad_x, raster.y_size + 2 * pad_y, raster.nb_band, geo_transform, raster.data_type, raster.no_data) for band in range(1, raster.nb_band + 1): out_ds.GetRasterBand(band).Fill(pad_value) gdal.Warp(out_ds, raster._gdal_dataset) # Close dataset out_ds = None
def _op(raster1, out_file, raster2, op_type): """ Basic arithmetic operations """ out_ds = _gdal_temp_dataset(out_file, raster1._gdal_driver, raster1._gdal_dataset.GetProjection(), raster1.x_size, raster1.y_size, raster1.nb_band, raster1.geo_transform, gdal.GetDataTypeByName('Float32'), raster1.no_data) for band in range(1, raster1.nb_band + 1): for window in get_block_windows(1000, raster1.x_size, raster1.y_size): array1 = raster1._gdal_dataset.GetRasterBand(band).ReadAsArray( *window).astype("float32") try: array2 = raster2._gdal_dataset.GetRasterBand(band).ReadAsArray( *window).astype("float32") except AttributeError: array2 = raster2 # If second input is not a raster but a scalar if op_type == "add": result = array1 + array2 elif op_type == "sub": result = array1 - array2 elif op_type == "mul": result = array1 * array2 elif op_type == "truediv": result = array1 / array2 else: result = None out_ds.GetRasterBand(band).WriteArray(result, window[0], window[1]) # Close dataset out_ds = None
def _raster_calculation(raster_class, sources, fhandle, window_size, gdal_driver, data_type, no_data, nb_processes, chunksize, description): """ Calculate raster expression """ if not hasattr(window_size, "__getitem__"): window_size = (window_size, window_size) master_raster = sources[0] window_gen = ([ src._gdal_dataset.ReadAsArray(*w).astype(GDAL_TO_NUMPY[data_type]) for src in sources ] for w in get_xy_block_windows(window_size, master_raster.x_size, master_raster.y_size)) width = int(master_raster.x_size / window_size[0]) + min( 1, master_raster.x_size % window_size[0]) height = int(master_raster.y_size / window_size[1]) + min( 1, master_raster.y_size % window_size[1]) with RasterTempFile( gdal_driver.GetMetadata()['DMD_EXTENSION']) as out_file: is_first_run = True y = 0 for win_gen in tqdm(split_into_chunks(window_gen, width), total=height, desc=description): with mp.Pool(processes=nb_processes) as pool: result = np.concatenate(list( pool.imap(fhandle, win_gen, chunksize=chunksize)), axis=1) if is_first_run: if result.ndim == 2: nb_band = 1 else: nb_band = result.shape[0] out_ds = _gdal_temp_dataset( out_file.path, gdal_driver, master_raster._gdal_dataset.GetProjection(), master_raster.x_size, master_raster.y_size, nb_band, master_raster.geo_transform, data_type, no_data) is_first_run = False if nb_band == 1: out_ds.GetRasterBand(1).WriteArray(result, 0, y) else: for band in range(nb_band): out_ds.GetRasterBand(band + 1).WriteArray( result[band, :, :], 0, y) y += window_size[1] # Close dataset out_ds = None return raster_class(out_file.path)