def frequencies(r, excludeNoData=True): """ Return frequencies table """ import numpy as np from osgeo import gdal from gasp.g.prop.img import get_nd if type(r).__name__ == 'str': img = gdal.Open(r) arr = img.ReadAsArray() elif type(r).__name__ == 'Dataset': img = r arr = img.ReadAsArray() else: img = None arr = r unique = list(np.unique(arr)) one_arr = arr.reshape(arr.shape[0] * arr.shape[1]) freq = np.bincount(one_arr) freq = freq[freq != 0] if excludeNoData: if type(r).__name__ == 'str' or type(r).__name__ == 'Dataset': ndval = get_nd(img) return {unique[i] : freq[i] for i in range(len(unique)) if unique[i] != ndval} else: return {unique[i] : freq[i] for i in range(len(unique))} else: return {unique[i] : freq[i] for i in range(len(unique))}
def resample_by_majority(refrst, valrst, out_rst): """ Resample valrst based on refrst: Get Majority value of valrst for each cell in refrst Useful when ref raster has cellsize greater than value raster. TODO: Valrst must be of int type """ import numpy as np from osgeo import gdal from gasp.g.prop.img import get_cell_size, get_nd from gasp.gt.torst import obj_to_rst # Data to Array if type(refrst) == gdal.Dataset: refsrc = refrst else: refsrc = gdal.Open(refrst) if type(valrst) == gdal.Dataset: valsrc = valrst else: valsrc = gdal.Open(valrst) refnum = refsrc.ReadAsArray() valnum = valsrc.ReadAsArray() # Get Ref shape ref_shape = refnum.shape # in a row, how many cells valnum are for each refnum cell refcs = int(get_cell_size(refsrc)[0]) valcs = int(get_cell_size(valsrc)[0]) dcell = int(refcs / valcs) # Valnum must be of int type # Create generalized/resampled raster resnum = np.zeros(ref_shape, dtype=valnum.dtype) for row in range(ref_shape[0]): for col in range(ref_shape[1]): resnum[row, col] = np.bincount( valnum[row*dcell:row*dcell+dcell, col*dcell : col*dcell+dcell].reshape(dcell*dcell) ).argmax() # Export out raster return obj_to_rst(resnum, out_rst, refsrc, noData=get_nd(valsrc))
def gdal_mapcalc(expression, exp_val_paths, outRaster, template_rst, outNodata=-99999): """ GDAL Raster Calculator TODO: Check if rasters dimensions are equal """ import numpy as np import os from osgeo import gdal, osr from gasp.gt.prop.ff import drv_name from py_expression_eval import Parser from gasp.g.prop.img import get_nd from gasp.gt.torst import obj_to_rst parser = Parser() EXPRESSION = parser.parse(expression) evalValue = {} noDatas = {} for x in EXPRESSION.variables(): img = gdal.Open(exp_val_paths[x]) arr = img.ReadAsArray().astype(float) evalValue[x] = arr noDatas[x] = get_nd(img) result = EXPRESSION.evaluate(evalValue) for v in noDatas: np.place(result, evalValue[v] == noDatas[v], outNodata) # Write output and return return obj_to_rst(result, outRaster, template_rst, noData=outNodata)
def get_nodata(r): """ Returns the value defining NoData in a Raster file API'S Available: * gdal; """ gisApi = 'gdal' if gisApi == 'gdal': from gasp.g.prop.img import get_nd from osgeo import gdal img = gdal.Open(r) ndVal = get_nd(img) else: raise ValueError('The api {} is not available'.format(gisApi)) return ndVal
def rcls_rst(inrst, rclsRules, outrst, api='gdal', maintain_ext=True): """ Reclassify a raster (categorical and floating points) if api == 'gdal rclsRules = { 1 : 99, 2 : 100 ... } or rclsRules = { (0, 8) : 1 (8, 16) : 2 '*' : 'NoData' } elif api == grass: rclsRules should be a path to a text file """ if api == 'gdal': import numpy as np import os from osgeo import gdal from gasp.gt.torst import obj_to_rst from gasp.g.fm import imgsrc_to_num from gasp.g.prop.img import get_nd if not os.path.exists(inrst): raise ValueError('File {} does not exist!'.format(inrst)) # Open Raster img = gdal.Open(inrst) # Raster to Array rst_num = imgsrc_to_num(img) nodataVal = get_nd(img) rcls_num = np.full(rst_num.shape, 255, dtype=np.uint8) # Change values for k in rclsRules: if rclsRules[k] == 'NoData': continue if type(k) == str: continue elif type(k) == tuple: q = (rst_num > k[0]) & (rst_num <= k[1]) else: q = rst_num == k np.place(rcls_num, q, rclsRules[k]) if '*' in rclsRules and rclsRules['*'] != 'NoData': np.place(rcls_num, rcls_num == 255, rclsRules['*']) if 'NoData' in rclsRules and rclsRules['NoData'] != 'NoData': np.place(rcls_num, rst_num == nodataVal, rclsRules['NoData']) if not maintain_ext: from gasp.g.nop.rshp import rshp_to_data left, cellx, z, top, c, celly = img.GetGeoTransform() clip_rcls, n_left, n_top = rshp_to_data(rcls_num, 255, left, cellx, top, celly) return obj_to_rst(clip_rcls, outrst, img, noData=255, geotrans=(n_left, cellx, z, n_top, c, celly)) else: return obj_to_rst(rcls_num, outrst, img, noData=255) elif api == "pygrass": from grass.pygrass.modules import Module r = Module('r.reclass', input=inrst, output=outrst, rules=rclsRules, overwrite=True, run_=False, quiet=True) r() else: raise ValueError(("API {} is not available").format(api))
def floatrst_to_intrst(in_rst, out_rst): """ Raster with float data to Raster with Integer Values """ import numpy as np from osgeo import gdal from gasp.g.prop.img import get_nd from gasp.gt.torst import obj_to_rst nds = { 'int8': -128, 'int16': -32768, 'int32': -2147483648, 'uint8': 255, 'uint16': 65535, 'uint32': 4294967295 } # Open Raster img = gdal.Open(in_rst) # Raster to Array rstnum = img.ReadAsArray() # Round data rstint = np.around(rstnum, decimals=0) # Get min and max tstmin = rstint.min() tstmax = rstint.max() try: nd = int(round(get_nd(img), 0)) except: nd = None if tstmin == nd: np.place(rstint, rstint == nd, np.nan) rstmin = rstint.min() rstmax = tstmax else: rstmin = tstmin if tstmax == nd: np.place(rstint, rstint == nd, np.nan) rstmax = rstint.max() else: rstmax = tstmax # Get dtype for output raster if rstmin < 0: if rstmin <= -128: if rstmin <= -32768: tmin = 'int32' else: tmin = 'int16' else: tmin = 'int8' else: tmin = 'u' if tmin == 'u': if rstmax >= 255: if rstmax >= 65535: tmax = 'uint32' else: tmax = 'uint16' else: tmax = 'uint8' else: if tmin == 'int8': if rstmax >= 127: if rstmax >= 32767: tmax = 'int32' else: tmax = 'int16' else: tmax = 'int8' elif tmin == 'int16': if rstmax >= 32767: tmax = 'int32' else: tmax = 'int16' else: tmax = 'int32' if tmax == 'int8': nt = np.int8 elif tmax == 'int16': nt = np.int16 elif tmax == 'int32': nt = np.int32 elif tmax == 'uint8': nt = np.uint8 elif tmax == 'uint16': nt = np.uint16 else: nt = np.uint32 # Get nodata for new raster new_nd = nds[tmax] # Place NoData value np.nan_to_num(rstint, copy=False, nan=new_nd) # Convert array type to integer rstint = rstint.astype(nt) # Export result to file and return return obj_to_rst(rstint, out_rst, img, noData=new_nd)