def cell_padding(input, output, radius=3): """Mitigates edge effect by growing an input raster map by radius cells Args ---- input, output : str Names of GRASS raster map for input, and padded output radius : int Radius in which to expand region and grow raster Returns ------- input_grown : str GRASS raster map which has been expanded by radius cells""" region = Region() g.region(n=region.north + (region.nsres * radius), s=region.south - (region.nsres * radius), w=region.west - (region.ewres * radius), e=region.east + (region.ewres * radius)) r.grow(input=input, output=output, radius=radius+1, quiet=True) return (region)
def cell_padding(input, output, radius=3): """Mitigates edge effect by growing an input raster map by radius cells Args ---- input, output : str Names of GRASS raster map for input, and padded output radius : int Radius in which to expand region and grow raster Returns ------- input_grown : str GRASS raster map which has been expanded by radius cells""" region = Region() g.region(n=region.north + (region.nsres * radius), s=region.south - (region.nsres * radius), w=region.west - (region.ewres * radius), e=region.east + (region.ewres * radius)) r.grow(input=input, output=output, radius=radius+1, quiet=True) return (region)
def cell_padding(input, output, radius=3): """Mitigates edge effect by growing an input raster map by radius cells Parameters ---------- input, output : str Names of GRASS raster map for input, and padded output. radius : int Radius in which to expand region and grow raster. Returns ------- input_grown : str GRASS raster map which has been expanded by radius cells """ g.region(grow=radius) r.grow(input=input, output=output, radius=radius, quiet=True) region = Region() return region
def main(): elevation = options['elevation'] slope = options['slope'] flat_thres = float(options['flat_thres']) curv_thres = float(options['curv_thres']) filter_size = int(options['filter_size']) counting_size = int(options['counting_size']) nclasses = int(options['classes']) texture = options['texture'] convexity = options['convexity'] concavity = options['concavity'] features = options['features'] # remove mapset from output name in case of overwriting existing map texture = texture.split('@')[0] convexity = convexity.split('@')[0] concavity = concavity.split('@')[0] features = features.split('@')[0] # store current region settings global current_reg current_reg = parse_key_val(g.region(flags='pg', stdout_=PIPE).outputs.stdout) del current_reg['projection'] del current_reg['zone'] del current_reg['cells'] # check for existing mask and backup if found global mask_test mask_test = gs.list_grouped( type='rast', pattern='MASK')[gs.gisenv()['MAPSET']] if mask_test: global original_mask original_mask = temp_map('tmp_original_mask') g.copy(raster=['MASK', original_mask]) # error checking if flat_thres < 0: gs.fatal('Parameter thres cannot be negative') if filter_size % 2 == 0 or counting_size % 2 == 0: gs.fatal( 'Filter or counting windows require an odd-numbered window size') if filter_size >= counting_size: gs.fatal( 'Filter size needs to be smaller than the counting window size') if features != '' and slope == '': gs.fatal('Need to supply a slope raster in order to produce the terrain classification') # Terrain Surface Texture ------------------------------------------------- # smooth the dem gs.message("Calculating terrain surface texture...") gs.message( "1. Smoothing input DEM with a {n}x{n} median filter...".format( n=filter_size)) filtered_dem = temp_map('tmp_filtered_dem') gs.run_command("r.neighbors", input = elevation, method = "median", size = filter_size, output = filtered_dem, flags='c', quiet=True) # extract the pits and peaks based on the threshold pitpeaks = temp_map('tmp_pitpeaks') gs.message("2. Extracting pits and peaks with difference > thres...") r.mapcalc(expression='{x} = if ( abs({dem}-{median})>{thres}, 1, 0)'.format( x=pitpeaks, dem=elevation, thres=flat_thres, median=filtered_dem), quiet=True) # calculate density of pits and peaks gs.message("3. Using resampling filter to create terrain texture...") window_radius = (counting_size-1)/2 y_radius = float(current_reg['ewres'])*window_radius x_radius = float(current_reg['nsres'])*window_radius resample = temp_map('tmp_density') r.resamp_filter(input=pitpeaks, output=resample, filter=['bartlett','gauss'], radius=[x_radius,y_radius], quiet=True) # convert to percentage gs.message("4. Converting to percentage...") r.mask(raster=elevation, overwrite=True, quiet=True) r.mapcalc(expression='{x} = float({y} * 100)'.format(x=texture, y=resample), quiet=True) r.mask(flags='r', quiet=True) r.colors(map=texture, color='haxby', quiet=True) # Terrain convexity/concavity --------------------------------------------- # surface curvature using lacplacian filter gs.message("Calculating terrain convexity and concavity...") gs.message("1. Calculating terrain curvature using laplacian filter...") # grow the map to remove border effects and run laplacian filter dem_grown = temp_map('tmp_elevation_grown') laplacian = temp_map('tmp_laplacian') g.region(n=float(current_reg['n']) + (float(current_reg['nsres']) * filter_size), s=float(current_reg['s']) - (float(current_reg['nsres']) * filter_size), w=float(current_reg['w']) - (float(current_reg['ewres']) * filter_size), e=float(current_reg['e']) + (float(current_reg['ewres']) * filter_size)) r.grow(input=elevation, output=dem_grown, radius=filter_size, quiet=True) r.mfilter( input=dem_grown, output=laplacian, filter=string_to_rules(laplacian_matrix(filter_size)), quiet=True) # extract convex and concave pixels gs.message("2. Extracting convexities and concavities...") convexities = temp_map('tmp_convexities') concavities = temp_map('tmp_concavities') r.mapcalc( expression='{x} = if({laplacian}>{thres}, 1, 0)'\ .format(x=convexities, laplacian=laplacian, thres=curv_thres), quiet=True) r.mapcalc( expression='{x} = if({laplacian}<-{thres}, 1, 0)'\ .format(x=concavities, laplacian=laplacian, thres=curv_thres), quiet=True) # calculate density of convexities and concavities gs.message("3. Using resampling filter to create surface convexity/concavity...") resample_convex = temp_map('tmp_convex') resample_concav = temp_map('tmp_concav') r.resamp_filter(input=convexities, output=resample_convex, filter=['bartlett','gauss'], radius=[x_radius,y_radius], quiet=True) r.resamp_filter(input=concavities, output=resample_concav, filter=['bartlett','gauss'], radius=[x_radius,y_radius], quiet=True) # convert to percentages gs.message("4. Converting to percentages...") g.region(**current_reg) r.mask(raster=elevation, overwrite=True, quiet=True) r.mapcalc(expression='{x} = float({y} * 100)'.format(x=convexity, y=resample_convex), quiet=True) r.mapcalc(expression='{x} = float({y} * 100)'.format(x=concavity, y=resample_concav), quiet=True) r.mask(flags='r', quiet=True) # set colors r.colors_stddev(map=convexity, quiet=True) r.colors_stddev(map=concavity, quiet=True) # Terrain classification Flowchart----------------------------------------- if features != '': gs.message("Performing terrain surface classification...") # level 1 produces classes 1 thru 8 # level 2 produces classes 5 thru 12 # level 3 produces classes 9 thru 16 if nclasses == 8: levels = 1 if nclasses == 12: levels = 2 if nclasses == 16: levels = 3 classif = [] for level in range(levels): # mask previous classes x:x+4 if level != 0: min_cla = (4*(level+1))-4 clf_msk = temp_map('tmp_clf_mask') rules = '1:{0}:1'.format(min_cla) r.recode( input=classif[level-1], output=clf_msk, rules=string_to_rules(rules), overwrite=True) r.mask(raster=clf_msk, flags='i', quiet=True, overwrite=True) # image statistics smean = r.univar( map=slope, flags='g', stdout_=PIPE).outputs.stdout.split(os.linesep) smean = [i for i in smean if i.startswith('mean=') is True][0].split('=')[1] cmean = r.univar( map=convexity, flags='g', stdout_=PIPE).outputs.stdout.split(os.linesep) cmean = [i for i in cmean if i.startswith('mean=') is True][0].split('=')[1] tmean = r.univar( map=texture, flags='g', stdout_=PIPE).outputs.stdout.split(os.linesep) tmean = [i for i in tmean if i.startswith('mean=') is True][0].split('=')[1] classif.append(temp_map('tmp_classes')) if level != 0: r.mask(flags='r', quiet=True) classification(level+1, slope, smean, texture, tmean, convexity, cmean, classif[level]) # combine decision trees merged = [] for level in range(0, levels): if level > 0: min_cla = (4*(level+1))-4 merged.append(temp_map('tmp_merged')) r.mapcalc( expression='{x} = if({a}>{min}, {b}, {a})'.format( x=merged[level], min=min_cla, a=merged[level-1], b=classif[level])) else: merged.append(classif[level]) g.rename(raster=[merged[-1], features], quiet=True) del TMP_RAST[-1] # Write metadata ---------------------------------------------------------- history = 'r.terrain.texture ' for key,val in options.iteritems(): history += key + '=' + str(val) + ' ' r.support(map=texture, title=texture, description='generated by r.terrain.texture', history=history) r.support(map=convexity, title=convexity, description='generated by r.terrain.texture', history=history) r.support(map=concavity, title=concavity, description='generated by r.terrain.texture', history=history) if features != '': r.support(map=features, title=features, description='generated by r.terrain.texture', history=history) # write color and category rules to tempfiles r.category( map=features, rules=string_to_rules(categories(nclasses)), separator='pipe') r.colors( map=features, rules=string_to_rules(colors(nclasses)), quiet=True) return 0