def dem_to_aspect(src_raster, band=0, alg='Horn', trigonometric=False): """Calculate the aspect for the DEM. Parameters ---------- src_raster : Raster The dem used to calculate the aspect. band : int, optional, default: 0 source band number to use. alg : {'ZevenbergenThorne' or 'Horn'}, optional, default: Horn The literature suggests Zevenbergen & Thorne to be more suited to smooth landscapes, where Horn’s formula to perform better on rougher terrain. trigonometric: bool, optional, default: False whether to return trigonometric angle instead of azimuth. Thus 0deg means East, 90deg North, 180deg West, 270deg South. Returns ------- dst_raster: Raster Aspect calculated from the DEM. """ options = dict(band=band + 1, alg=alg, trigonometric=trigonometric, format='MEM') ds_src = src_raster.to_gdal_ds() ds = gdal.DEMProcessing('', ds_src, 'aspect', **options) dst_raster = tgp.read_gdal_ds(ds) return dst_raster
def dem_to_slope(src_raster, band=0, alg='Horn', slope_format='degree'): """Calculate the slope for the DEM. Parameters ---------- src_raster : Raster The dem used to calculate the slope. band : int, optional, default: 0 source band number to use. alg : {'ZevenbergenThorne' or 'Horn'}, optional, default: Horn The literature suggests Zevenbergen & Thorne to be more suited to smooth landscapes, where Horn’s formula to perform better on rougher terrain. slope_format: {"degree" or "percent"}, optional, default degree The format of the slope. Returns ------- dst_raster: Raster Slope calculated from the DEM. """ options = dict(band=band + 1, alg=alg, slopeFormat=slope_format, format='MEM') ds_src = src_raster.to_gdal_ds() ds = gdal.DEMProcessing('', ds_src, 'slope', **options) dst_raster = tgp.read_gdal_ds(ds) return dst_raster
def dem_to_hillshade(src_raster, band=0, alg='Horn', azimuth=315, altitude=45): """Calculate the hillshade for the DEM. Parameters ---------- src_raster : Raster The dem used to calculate the hillshade. band : int, optional, default: 0 source band number to use. alg : {'ZevenbergenThorne' or 'Horn'}, optional, default: Horn The literature suggests Zevenbergen & Thorne to be more suited to smooth landscapes, where Horn’s formula to perform better on rougher terrain. azimuth : int, optional, default 315 Azimuth of the light, in degrees. 0 if it comes from the top of the raster, 90 from the east, ... The default value, 315, should rarely be changed as it is the value generally used to generate shaded maps. altitude : int, optional, default 45 Altitude of the light, in degrees. 90 if the light comes from above the DEM, 0 if it is raking light. Returns ------- dst_raster: Raster Hillshade calculated from the DEM. """ options = dict(band=band + 1, alg=alg, azimuth=azimuth, altitude=altitude, format='MEM') ds_src = src_raster.to_gdal_ds() ds = gdal.DEMProcessing('', ds_src, 'hillshade', **options) dst_raster = tgp.read_gdal_ds(ds) return dst_raster
def remap_by_ref_raster(self, ref_raster): """remap the raster on to another canvas drew by referenced raster. Parameters ---------- ref_raster: Raster The referenced raster. The extent, projection and resolution will be used. Returns ------- dst_raster: Raster Remapped result. """ src_ds = self.to_gdal_ds() src_projection, src_gdaldtype = self.projection, self.gdaldtype ref_geo_transform, ref_projection = ref_raster.geo_transform, ref_raster.projection output_bounds = ref_raster.extent_for_gdal # minX, minY, maxX, maxY x_res, y_res = ref_geo_transform[1], ref_geo_transform[5] output_type = src_gdaldtype dst_ds = gdal.Warp('', src_ds, xRes=x_res, yRes=y_res, outputBounds=output_bounds, format='MEM', srcSRS=src_projection, dstSRS=ref_projection, outputType=output_type, resampleAlg='bilinear') dst_raster = tgp.read_gdal_ds(dst_ds) return dst_raster
def reproject(self, dst_crs='EPSG:4326', src_crs=None): """Reproject the raster data. Parameters ---------- dst_crs: str, optional, default: EPSG:4326 The target crs to transform the raster to. src_crs: str, optional The source crs to transform the raster from. If None, get the projection from src_raster. Returns ------- dst_raster: Raster Reprojected result. Examples -------- >>> import TronGisPy as tgp >>> src_raster_fp = tgp.get_testing_fp() >>> src_raster = tgp.read_raster(src_raster_fp) >>> print("project(before)", src_raster.projection) >>> dst_raster = src_raster.reproject(dst_crs='EPSG:4326', src_crs=None) >>> print("project(after)", tgp.wkt_to_epsg(dst_raster.projection)) """ src_ds = self.to_gdal_ds() if src_crs: dst_ds = gdal.Warp('', src_ds, srcSRS=src_crs, dstSRS=dst_crs, format='MEM') else: dst_ds = gdal.Warp('', src_ds, dstSRS=dst_crs, format='MEM') if dst_ds is None: try: src_crs = "EPSG:" + str(tgp.wkt_to_epsg(self.projection)) dst_ds = gdal.Warp('', src_ds, srcSRS=src_crs, dstSRS=dst_crs, format='MEM') assert dst_ds is not None, "Please provide src_crs since the raster does not contain valid crs information." print("Please provide src_crs to accelerate the process.") except: assert False, "Please provide src_crs since the raster does not contain crs information." dst_raster = tgp.read_gdal_ds(dst_ds) return dst_raster
def clip_raster_with_extent(src_raster, extent): """Clip raster with extent. Parameters ---------- src_raster: Raster Which raster data to be clipped. extent: tuple extent to clip the data with (xmin, ymin, xmax, ymax) format. Returns ------- dst_raster: Raster. Clipped result. Examples -------- >>> import geopandas as gpd >>> import TronGisPy as tgp >>> from TronGisPy import ShapeGrid >>> from matplotlib import pyplot as plt >>> from shapely.geometry import Polygon >>> src_raster_fp = tgp.get_testing_fp('satellite_tif') >>> src_raster = tgp.read_raster(src_raster_fp) >>> ext = xmin, ymin, xmax, ymax = [329454.39272725, 2746809.43272727, 331715.57090906, 2748190.90181818] >>> dst_raster = ShapeGrid.clip_raster_with_extent(src_raster, ext) >>> fig, (ax1, ax2) = plt.subplots(1, 2) # plot the result >>> src_raster.plot(ax=ax1) >>> ext_poly = [(xmin, ymin), (xmin, ymax), (xmax, ymax), (xmax, ymin)] >>> df_ext_poly = gpd.GeoDataFrame([Polygon(ext_poly)], columns=['geom'], geometry='geom') >>> df_ext_poly.boundary.plot(ax=ax1) >>> ax1.set_title('original image and clipper') >>> dst_raster.plot(ax=ax2) >>> ax2.set_title('clipped image') >>> plt.show() """ assert src_raster.geo_transform is not None, "src_raster.geo_transform should not be None" src_ds = src_raster.to_gdal_ds() dst_ds = gdal.Warp('', src_ds, format='MEM', outputBounds=extent, cropToCutline=True) dst_raster = tgp.read_gdal_ds(dst_ds) return dst_raster
def dem_to_roughness(src_raster, band=0): """Calculate the roughness for the DEM. Parameters ---------- src_raster : Raster The dem used to calculate the roughness. band : int, optional, default: 0 source band number to use. Returns ------- dst_raster: Raster roughness calculated from the DEM. """ options = dict(band=band + 1, format='MEM') ds_src = src_raster.to_gdal_ds() ds = gdal.DEMProcessing('', ds_src, 'Roughness', **options) dst_raster = tgp.read_gdal_ds(ds) return dst_raster
def dem_to_TPI(src_raster, band=0): """Calculate the topographic position index (TPI) for the DEM. Parameters ---------- src_raster : Raster The dem used to calculate the TPI. band : int, optional, default: 0 source band number to use. Returns ------- dst_raster: Raster TPI calculated from the DEM. """ options = dict(band=band + 1, format='MEM') ds_src = src_raster.to_gdal_ds() ds = gdal.DEMProcessing('', ds_src, 'TPI', **options) dst_raster = tgp.read_gdal_ds(ds) return dst_raster
def gdal_fillnodata(raster, band=0, no_data_value=999, max_distance=100, smoothing_iterations=0): """Interpolate values on specific cells (generally nan cell) using `gdal.FillNodata`. To be mentioned, this cannot accept zero in its data except its no_data_value is zero. Parameters ---------- raster: Raster The Raster object you want to fill the no_data_value. band: int, optional, default: 0 The band numnber of Raster object you want to fill the no_data_value which start from zero. no_data_value: int or float, optional, default: 999 The value to be filled with interpolated value. If no_data_value == None, use np.nan as no_data_value. max_distance: int, optional, default: 100 The cells within the max distance from no_data_value location will be calculated to fill the no_data_value. smoothing_iterations: int, optional, default: 0 The maximum limitation on loop. Returns ------- data_interp: ndarray. Interpolation result. Examples -------- >>> import numpy as np >>> import TronGisPy as tgp >>> from TronGisPy import Interpolation >>> from matplotlib import pyplot as plt >>> raster_fp = tgp.get_testing_fp('tif_forinterpolation') >>> raster = tgp.read_raster(raster_fp) >>> raster.data[np.isnan(raster.data)] = 999 >>> raster_interp = Interpolation.gdal_fillnodata(raster) >>> fig, (ax1, ax2) = plt.subplots(1,2) >>> raster.plot(ax=ax1) >>> raster_interp.plot(ax=ax2) >>> plt.show() """ # make dst_band ds_dst = raster.to_gdal_ds() dstband = ds_dst.GetRasterBand(band + 1) # make maskband raster_mask = raster.copy() raster_mask.data[raster_mask.data == no_data_value] = 0 raster_mask.data[raster_mask.data != 0] = 1 raster_mask.astype(bool) raster_mask.no_data_value = 0 ds_mask = raster_mask.to_gdal_ds() maskband = ds_mask.GetRasterBand(1) gdal.FillNodata(dstband, maskband, max_distance, smoothing_iterations) data_interp = tgp.read_gdal_ds(ds_dst) ds_dst = None ds_mask = None return data_interp
def refine_resolution(self, dst_resolution, resample_alg='near', extent=None, rotate=True): """Refine the resolution of the raster. Parameters ---------- dst_resolution: int Target Resolution. resample_alg: {'near', 'bilinear', 'cubic', 'cubicspline', 'lanczos', 'average', 'mode'}. ``near``: nearest neighbour resampling (default, fastest algorithm, worst interpolation quality). ``bilinear``: bilinear resampling. ``cubic``: cubic resampling. ``cubicspline``: cubic spline resampling. ``lanczos``: Lanczos windowed sinc resampling. ``average``: average resampling, computes the weighted average of all non-NODATA contributing pixels. ``mode``: mode resampling, selects the value which appears most often of all the sampled points. extent: tuple extent to clip the data with (xmin, ymin, xmax, ymax) format. rotate: bool If True, the function will rotate the raster and adds noData values around it to make a new rectangular image matrix if the rotation in Raster.geo_transform is not zero, else it will keep the original rotation angle of Raster.geo_transform. Gdal will rotate the image by default . Please refer to the issue https://gis.stackexchange.com/questions/256081/why-does-gdalwarp-rotate-the-data and https://github.com/OSGeo/gdal/issues/1601. Returns ------- dst_raster: Raster Refined result. Examples -------- >>> import numpy as np >>> import TronGisPy as tgp >>> from TronGisPy import ShapeGrid >>> from matplotlib import pyplot as plt >>> src_raster_fp = tgp.get_testing_fp('dem_process_path') >>> src_raster = tgp.read_raster(src_raster_fp) >>> src_raster.data[src_raster.data == -999] = np.nan >>> dst_raster = src_raster.refine_resolution(dst_resolution=10, resample_alg='bilinear') >>> fig, (ax1, ax2) = plt.subplots(1, 2) # plot the result >>> src_raster.plot(ax=ax1) >>> ax1.set_title('original dem ' + str(src_raster.shape)) >>> dst_raster.plot(ax=ax2) >>> ax2.set_title('refined image ' + str(dst_raster.shape)) >>> plt.show() """ src_ds = self.to_gdal_ds() if rotate: dst_ds = gdal.Warp('', src_ds, xRes=dst_resolution, yRes=dst_resolution, outputBounds=extent, format='MEM', resampleAlg=resample_alg) dst_raster = tgp.read_gdal_ds(dst_ds) else: assert extent is None, "you cannot set the extent when rotate == False" zoom_in = dst_resolution / self.pixel_size[0] dst_ds = gdal.Warp('', src_ds, xRes=zoom_in, yRes=zoom_in, format='MEM', resampleAlg=resample_alg, transformerOptions=[ 'SRC_METHOD=NO_GEOTRANSFORM', 'DST_METHOD=NO_GEOTRANSFORM' ]) dst_geo_transform = np.array(self.geo_transform) dst_geo_transform[[1, 2, 4, 5]] *= zoom_in dst_raster = tgp.read_gdal_ds(dst_ds) dst_raster.geo_transform = tuple(dst_geo_transform) dst_raster.projection = self.projection return dst_raster