def main(): images = options['input'].split(',') output = options['output'] count = len(images) msg = _('Do not forget to set region properly to cover all images.') gscript.warning(msg) offset = 0 offsets = [] parms = {} for n, img in enumerate(images): offsets.append(offset) parms['image%d' % (n + 1)] = img parms['offset%d' % (n + 1)] = offset offset += get_limit(img) + 1 gscript.message(_("Mosaicing %d images...") % count) gscript.mapcalc("$output = " + make_expression(1, count), output=output, **parms) # modify the color table: p = gscript.feed_command('r.colors', map=output, rules='-') for img, offset in zip(images, offsets): print(img, offset) copy_colors(p.stdin, img, offset) p.stdin.close() p.wait() gscript.message(_("Done. Raster map <%s> created.") % output) # write cmd history: gscript.raster_history(output)
def main(): options, unused = gscript.parser() input = options['input'] red = options['red'] green = options['green'] blue = options['blue'] if not gscript.find_file(input)['file']: gscript.fatal(_("Raster map <%s> not found") % input) expressions = [] maps = [] if red: expressions.append('%s = r#${input}' % red) maps.append(red) if green: expressions.append('%s = g#${input}' % green) maps.append(green) if blue: expressions.append('%s = b#${input}' % blue) maps.append(blue) expr = ';'.join(expressions) gscript.mapcalc(expr, input=input) for name in maps: gscript.run_command('r.colors', map=name, color='grey255') gscript.raster_history(name)
def _import_file(self, filename, module, args): mapname = self._map_name(filename) gs.message(_('Processing <{}>...').format(mapname)) if module == 'r.import': args['resolution_value'] = self._raster_resolution(filename) try: gs.run_command(module, input=filename, output=mapname, **args) gs.raster_history(mapname) except CalledModuleError as e: pass # error already printed
def main(): name = options['output'] type = options['type'] dip = float(options['dip']) az = float(options['azimuth']) ea = float(options['easting']) no = float(options['northing']) el = float(options['elevation']) # reg = gscript.region() ### test input values ### if abs(dip) >= 90: gscript.fatal(_("dip must be between -90 and 90.")) if az < 0 or az >= 360: gscript.fatal(_("azimuth must be between 0 and 360")) # now the actual algorithm az_r = math.radians(-az) sinaz = math.sin(az_r) cosaz = math.cos(az_r) dip_r = math.radians(-dip) tandip = math.tan(dip_r) kx = sinaz * tandip ky = cosaz * tandip kz = el - ea * sinaz * tandip - no * cosaz * tandip if type == "CELL": round = "round" dtype = "int" elif type == "FCELL": round = "" dtype = "float" else: round = "" dtype = "double" gscript.mapcalc("$name = $type($round(x() * $kx + y() * $ky + $kz))", name=name, type=dtype, round=round, kx=kx, ky=ky, kz=kz) gscript.run_command('r.support', map=name, history='') gscript.raster_history(name) gscript.message(_("Done.")) t = string.Template("Raster map <$name> generated by r.plane " "at point $ea E, $no N, elevation $el with dip = $dip" " degrees and aspect = $az degrees ccw from north.") gscript.message(t.substitute(name=name, ea=ea, no=no, el=el, dip=dip, az=az))
def main(): global temp_dist, temp_val input = options['input'] output = options['output'] radius = float(options['radius']) metric = options['metric'] old = options['old'] new = options['new'] mapunits = flags['m'] tmp = str(os.getpid()) temp_dist = "r.grow.tmp.%s.dist" % tmp if new == '': temp_val = "r.grow.tmp.%s.val" % tmp new = temp_val else: temp_val = None if old == '': old = input if not mapunits: kv = grass.region() scale = math.sqrt(float(kv['nsres']) * float(kv['ewres'])) radius *= scale if metric == 'euclidean': metric = 'squared' radius = radius * radius # check if input file exists if not grass.find_file(input)['file']: grass.fatal(_("Raster map <%s> not found") % input) try: grass.run_command('r.grow.distance', input=input, metric=metric, distance=temp_dist, value=temp_val) except CalledModuleError: grass.fatal(_("Growing failed. Removing temporary maps.")) grass.mapcalc( "$output = if(!isnull($input),$old,if($dist < $radius,$new,null()))", output=output, input=input, radius=radius, old=old, new=new, dist=temp_dist) grass.run_command('r.colors', map=output, raster=input) # write cmd history: grass.raster_history(output)
def __import_file(self, filename, module, args): mapname = os.path.splitext(os.path.basename(filename))[0] gs.message(_('Processing <{}>...').format(mapname)) if module == 'r.import': args['resolution_value'] = self.__raster_resolution(filename) try: gs.run_command(module, input=filename, output=mapname, **args) gs.raster_history(mapname) except CalledModuleError as e: pass
def main(): red = options["red"] green = options["green"] blue = options["blue"] brightness = options["strength"] full = flags["f"] preserve = flags["p"] reset = flags["r"] # 90 or 98? MAX value controls brightness # think of percent (0-100), must be positive or 0 # must be more than "2" ? if full: for i in [red, green, blue]: grass.run_command("r.colors", map=i, color="grey") sys.exit(0) if reset: for i in [red, green, blue]: grass.run_command("r.colors", map=i, color="grey255") sys.exit(0) if not preserve: for i in [red, green, blue]: grass.message(_("Processing <%s>...") % i) v0 = get_percentile(i, 2) v1 = get_percentile(i, brightness) grass.debug("<%s>: min=%f max=%f" % (i, v0, v1)) set_colors(i, v0, v1) else: all_max = 0 all_min = 999999 for i in [red, green, blue]: grass.message(_("Processing <%s>...") % i) v0 = get_percentile(i, 2) v1 = get_percentile(i, brightness) grass.debug("<%s>: min=%f max=%f" % (i, v0, v1)) all_min = min(all_min, v0) all_max = max(all_max, v1) grass.debug("all_min=%f all_max=%f" % (all_min, all_max)) for i in [red, green, blue]: set_colors(i, v0, v1) # write cmd history: mapset = grass.gisenv()["MAPSET"] for i in [red, green, blue]: if grass.find_file(i)["mapset"] == mapset: grass.raster_history(i)
def main(): name = options["output"] type = options["type"] dip = float(options["dip"]) az = float(options["azimuth"]) ea = float(options["easting"]) no = float(options["northing"]) el = float(options["elevation"]) reg = grass.region() ### test input values ### if abs(dip) >= 90: grass.fatal(_("dip must be between -90 and 90.")) if az < 0 or az >= 360: grass.fatal(_("azimuth must be between 0 and 360")) ### now the actual algorithm az_r = math.radians(-az) sinaz = math.sin(az_r) cosaz = math.cos(az_r) dip_r = math.radians(-dip) tandip = math.tan(dip_r) kx = sinaz * tandip ky = cosaz * tandip kz = el - ea * sinaz * tandip - no * cosaz * tandip if type == "int": round = "round" else: round = "" grass.mapcalc( "$name = $type($round(x() * $kx + y() * $ky + $kz))", name=name, type=type, round=round, kx=kx, ky=ky, kz=kz ) grass.raster_history(name) grass.message(_("Done.")) t = string.Template( "Raster map <$name> generated by r.plane " + "at point $ea E, $no N, elevation $el with dip = $dip degrees and " + "aspect = $az degrees ccw from north." ) grass.message(t.substitute(name=name, ea=ea, no=no, el=el, dip=dip, az=az))
def _import_file(self, filename, module, args): mapname = self._map_name(filename) gs.message(_('Processing <{}>...').format(mapname)) if module == 'r.import': args['resolution_value'] = self._raster_resolution(filename) try: gs.run_command(module, input=filename, output=mapname, **args) if gs.raster_info(mapname)['datatype'] in ('FCELL', 'DCELL'): gs.message('Rounding to integer after reprojection') gs.use_temp_region() gs.run_command('g.region', raster=mapname) gs.run_command('r.mapcalc', quiet=True, expression='tmp_%s = round(%s)' % (mapname, mapname)) gs.run_command('g.rename', quiet=True, overwrite=True, raster='tmp_%s,%s' % (mapname, mapname)) gs.del_temp_region() gs.raster_history(mapname) except CalledModuleError as e: pass # error already printed
def main(): input = options['input'] output = options['output_prefix'] if not grass.find_file(input)['file']: grass.fatal(_("Raster map <%s> not found") % input) if not output: output = input expr = ';'.join(["${output}.r = r#${input}", "${output}.g = g#${input}", "${output}.b = b#${input}"]) grass.mapcalc(expr, input = input, output = output) for ch in ['r', 'g', 'b']: name = "%s.%s" % (output, ch) grass.run_command('r.colors', map = name, color = 'grey255') grass.raster_history(name)
def main(): input = options['input'] output = options['output_prefix'] if not grass.find_file(input)['file']: grass.fatal(_("Raster map <%s> not found") % input) if not output: output = input.split('@')[0] expr = ';'.join(["${output}.r = r#${input}", "${output}.g = g#${input}", "${output}.b = b#${input}"]) grass.mapcalc(expr, input = input, output = output) for ch in ['r', 'g', 'b']: name = "%s.%s" % (output, ch) grass.run_command('r.colors', map = name, color = 'grey255') grass.raster_history(name)
def import_aster(proj, srcfile, tempfile, band): #run gdalwarp with selected options (must be in $PATH) #to translate aster image to geotiff grass.message(_("Georeferencing aster image ...")) grass.debug("gdalwarp -t_srs %s %s %s" % (proj, srcfile, tempfile)) if platform.system() == "Darwin": cmd = ["arch", "-i386", "gdalwarp", "-t_srs", proj, srcfile, tempfile ] else: cmd = ["gdalwarp", "-t_srs", proj, srcfile, tempfile ] p = grass.call(cmd) if p != 0: #check to see if gdalwarp executed properly return #import geotiff to GRASS grass.message(_("Importing into GRASS ...")) outfile = "%s.%s" % (output, band) grass.run_command("r.in.gdal", input = tempfile, output = outfile) # write cmd history grass.raster_history(outfile)
def import_aster(proj, srcfile, tempfile, band): #run gdalwarp with selected options (must be in $PATH) #to translate aster image to geotiff grass.message(_("Georeferencing aster image ...")) grass.debug("gdalwarp -t_srs %s %s %s" % (proj, srcfile, tempfile)) if platform.system() == "Darwin": cmd = ["arch", "-i386", "gdalwarp", "-t_srs", proj, srcfile, tempfile] else: cmd = ["gdalwarp", "-t_srs", proj, srcfile, tempfile] p = grass.call(cmd) if p != 0: #check to see if gdalwarp executed properly return #import geotiff to GRASS grass.message(_("Importing into GRASS ...")) outfile = "%s.%s" % (output, band) grass.run_command("r.in.gdal", input=tempfile, output=outfile) # write cmd history grass.raster_history(outfile)
def main(): images = options['input'].split(',') output = options['output'] count = len(images) grass.warning( _('Do not forget to set region properly to cover all images.')) offset = 0 offsets = [] parms = {} for n, img in enumerate(images): offsets.append(offset) parms['image%d' % (n + 1)] = img parms['offset%d' % (n + 1)] = offset offset += get_limit(img) + 1 grass.message(_("Mosaicing %d images...") % count) grass.mapcalc("$output = " + make_expression(1, count), output=output, **parms) #modify the color table: p = grass.feed_command('r.colors', map=output, rules='-') for img, offset in zip(images, offsets): print img, offset copy_colors(p.stdin, img, offset) p.stdin.close() p.wait() grass.message(_("Done. Raster map <%s> created.") % output) # write cmd history: grass.raster_history(output)
def main(): global usermask, mapset, tmp_rmaps, tmp_vmaps input = options['input'] output = options['output'] tension = options['tension'] smooth = options['smooth'] method = options['method'] edge = int(options['edge']) segmax = int(options['segmax']) npmin = int(options['npmin']) lambda_ = float(options['lambda']) memory = options['memory'] quiet = True # FIXME mapset = grass.gisenv()['MAPSET'] unique = str(os.getpid()) # Shouldn't we use temp name? prefix = 'r_fillnulls_%s_' % unique failed_list = list( ) # a list of failed holes. Caused by issues with v.surf.rst. Connected with #1813 # check if input file exists if not grass.find_file(input)['file']: grass.fatal(_("Raster map <%s> not found") % input) # save original region reg_org = grass.region() # check if a MASK is already present # and remove it to not interfere with NULL lookup part # as we don't fill MASKed parts! if grass.find_file('MASK', mapset=mapset)['file']: usermask = "usermask_mask." + unique grass.message(_("A user raster mask (MASK) is present. Saving it...")) grass.run_command('g.rename', quiet=quiet, raster=('MASK', usermask)) # check if method is rst to use v.surf.rst if method == 'rst': # idea: filter all NULLS and grow that area(s) by 3 pixel, then # interpolate from these surrounding 3 pixel edge filling = prefix + 'filled' grass.use_temp_region() grass.run_command('g.region', align=input, quiet=quiet) region = grass.region() ns_res = region['nsres'] ew_res = region['ewres'] grass.message(_("Using RST interpolation...")) grass.message(_("Locating and isolating NULL areas...")) # creating binary (0/1) map if usermask: grass.message(_("Skipping masked raster parts")) grass.mapcalc( "$tmp1 = if(isnull(\"$input\") && !($mask == 0 || isnull($mask)),1,null())", tmp1=prefix + 'nulls', input=input, mask=usermask) else: grass.mapcalc("$tmp1 = if(isnull(\"$input\"),1,null())", tmp1=prefix + 'nulls', input=input) tmp_rmaps.append(prefix + 'nulls') # restoring user's mask, if present # to ignore MASKed original values if usermask: grass.message(_("Restoring user mask (MASK)...")) try: grass.run_command('g.rename', quiet=quiet, raster=(usermask, 'MASK')) except CalledModuleError: grass.warning(_("Failed to restore user MASK!")) usermask = None # grow identified holes by X pixels grass.message(_("Growing NULL areas")) tmp_rmaps.append(prefix + 'grown') try: grass.run_command('r.grow', input=prefix + 'nulls', radius=edge + 0.01, old=1, new=1, out=prefix + 'grown', quiet=quiet) except CalledModuleError: grass.fatal( _("abandoned. Removing temporary map, restoring " "user mask if needed:")) # assign unique IDs to each hole or hole system (holes closer than edge distance) grass.message(_("Assigning IDs to NULL areas")) tmp_rmaps.append(prefix + 'clumped') try: grass.run_command('r.clump', input=prefix + 'grown', output=prefix + 'clumped', quiet=quiet) except CalledModuleError: grass.fatal( _("abandoned. Removing temporary map, restoring " "user mask if needed:")) # get a list of unique hole cat's grass.mapcalc("$out = if(isnull($inp), null(), $clumped)", out=prefix + 'holes', inp=prefix + 'nulls', clumped=prefix + 'clumped') tmp_rmaps.append(prefix + 'holes') # use new IDs to identify holes try: grass.run_command('r.to.vect', flags='v', input=prefix + 'holes', output=prefix + 'holes', type='area', quiet=quiet) except: grass.fatal( _("abandoned. Removing temporary maps, restoring " "user mask if needed:")) tmp_vmaps.append(prefix + 'holes') # get a list of unique hole cat's cats_file_name = grass.tempfile(False) grass.run_command('v.db.select', flags='c', map=prefix + 'holes', columns='cat', file=cats_file_name, quiet=quiet) cat_list = list() cats_file = open(cats_file_name) for line in cats_file: cat_list.append(line.rstrip('\n')) cats_file.close() os.remove(cats_file_name) if len(cat_list) < 1: grass.fatal(_("Input map has no holes. Check region settings.")) # GTC Hole is NULL area in a raster map grass.message(_("Processing %d map holes") % len(cat_list)) first = True hole_n = 1 for cat in cat_list: holename = prefix + 'hole_' + cat # GTC Hole is a NULL area in a raster map grass.message(_("Filling hole %s of %s") % (hole_n, len(cat_list))) hole_n = hole_n + 1 # cut out only CAT hole for processing try: grass.run_command('v.extract', input=prefix + 'holes', output=holename + '_pol', cats=cat, quiet=quiet) except CalledModuleError: grass.fatal( _("abandoned. Removing temporary maps, restoring " "user mask if needed:")) tmp_vmaps.append(holename + '_pol') # zoom to specific hole with a buffer of two cells around the hole to # remove rest of data try: grass.run_command('g.region', vector=holename + '_pol', align=input, w='w-%d' % (edge * 2 * ew_res), e='e+%d' % (edge * 2 * ew_res), n='n+%d' % (edge * 2 * ns_res), s='s-%d' % (edge * 2 * ns_res), quiet=quiet) except CalledModuleError: grass.fatal( _("abandoned. Removing temporary maps, restoring " "user mask if needed:")) # remove temporary map to not overfill disk try: grass.run_command('g.remove', flags='fb', type='vector', name=holename + '_pol', quiet=quiet) except CalledModuleError: grass.fatal( _("abandoned. Removing temporary maps, restoring " "user mask if needed:")) tmp_vmaps.remove(holename + '_pol') # copy only data around hole grass.mapcalc("$out = if($inp == $catn, $inp, null())", out=holename, inp=prefix + 'holes', catn=cat) tmp_rmaps.append(holename) # If here loop is split into two, next part of loop can be run in parallel # (except final result patching) # Downside - on large maps such approach causes large disk usage # grow hole border to get it's edge area tmp_rmaps.append(holename + '_grown') try: grass.run_command('r.grow', input=holename, radius=edge + 0.01, old=-1, out=holename + '_grown', quiet=quiet) except CalledModuleError: grass.fatal( _("abandoned. Removing temporary map, restoring " "user mask if needed:")) # no idea why r.grow old=-1 doesn't replace existing values with NULL grass.mapcalc("$out = if($inp == -1, null(), \"$dem\")", out=holename + '_edges', inp=holename + '_grown', dem=input) tmp_rmaps.append(holename + '_edges') # convert to points for interpolation tmp_vmaps.append(holename) try: grass.run_command('r.to.vect', input=holename + '_edges', output=holename, type='point', flags='z', quiet=quiet) except CalledModuleError: grass.fatal( _("abandoned. Removing temporary maps, restoring " "user mask if needed:")) # count number of points to control segmax parameter for interpolation: pointsnumber = grass.vector_info_topo(map=holename)['points'] grass.verbose(_("Interpolating %d points") % pointsnumber) if pointsnumber < 2: grass.verbose(_("No points to interpolate")) failed_list.append(holename) continue # Avoid v.surf.rst warnings if pointsnumber < segmax: use_npmin = pointsnumber use_segmax = pointsnumber * 2 else: use_npmin = npmin use_segmax = segmax # launch v.surf.rst tmp_rmaps.append(holename + '_dem') try: grass.run_command('v.surf.rst', quiet=quiet, input=holename, elev=holename + '_dem', tension=tension, smooth=smooth, segmax=use_segmax, npmin=use_npmin) except CalledModuleError: # GTC Hole is NULL area in a raster map grass.fatal(_("Failed to fill hole %s") % cat) # v.surf.rst sometimes fails with exit code 0 # related bug #1813 if not grass.find_file(holename + '_dem')['file']: try: tmp_rmaps.remove(holename) tmp_rmaps.remove(holename + '_grown') tmp_rmaps.remove(holename + '_edges') tmp_rmaps.remove(holename + '_dem') tmp_vmaps.remove(holename) except: pass grass.warning( _("Filling has failed silently. Leaving temporary maps " "with prefix <%s> for debugging.") % holename) failed_list.append(holename) continue # append hole result to interpolated version later used to patch into original DEM if first: tmp_rmaps.append(filling) grass.run_command('g.region', align=input, raster=holename + '_dem', quiet=quiet) grass.mapcalc("$out = if(isnull($inp), null(), $dem)", out=filling, inp=holename, dem=holename + '_dem') first = False else: tmp_rmaps.append(filling + '_tmp') grass.run_command('g.region', align=input, raster=(filling, holename + '_dem'), quiet=quiet) grass.mapcalc( "$out = if(isnull($inp), if(isnull($fill), null(), $fill), $dem)", out=filling + '_tmp', inp=holename, dem=holename + '_dem', fill=filling) try: grass.run_command('g.rename', raster=(filling + '_tmp', filling), overwrite=True, quiet=quiet) except CalledModuleError: grass.fatal( _("abandoned. Removing temporary maps, restoring user " "mask if needed:")) # this map has been removed. No need for later cleanup. tmp_rmaps.remove(filling + '_tmp') # remove temporary maps to not overfill disk try: tmp_rmaps.remove(holename) tmp_rmaps.remove(holename + '_grown') tmp_rmaps.remove(holename + '_edges') tmp_rmaps.remove(holename + '_dem') except: pass try: grass.run_command('g.remove', quiet=quiet, flags='fb', type='raster', name=(holename, holename + '_grown', holename + '_edges', holename + '_dem')) except CalledModuleError: grass.fatal( _("abandoned. Removing temporary maps, restoring " "user mask if needed:")) try: tmp_vmaps.remove(holename) except: pass try: grass.run_command('g.remove', quiet=quiet, flags='fb', type='vector', name=holename) except CalledModuleError: grass.fatal( _("abandoned. Removing temporary maps, restoring user mask if needed:" )) # check if method is different from rst to use r.resamp.bspline if method != 'rst': grass.message(_("Using %s bspline interpolation") % method) # clone current region grass.use_temp_region() grass.run_command('g.region', align=input) reg = grass.region() # launch r.resamp.bspline tmp_rmaps.append(prefix + 'filled') # If there are no NULL cells, r.resamp.bslpine call # will end with an error although for our needs it's fine # Only problem - this state must be read from stderr new_env = dict(os.environ) new_env['LC_ALL'] = 'C' if usermask: try: p = grass.core.start_command('r.resamp.bspline', input=input, mask=usermask, output=prefix + 'filled', method=method, ew_step=3 * reg['ewres'], ns_step=3 * reg['nsres'], lambda_=lambda_, memory=memory, flags='n', stderr=subprocess.PIPE, env=new_env) stderr = grass.decode(p.communicate()[1]) if "No NULL cells found" in stderr: grass.run_command('g.copy', raster='%s,%sfilled' % (input, prefix), overwrite=True) p.returncode = 0 grass.warning( _("Input map <%s> has no holes. Copying to output without modification." ) % (input, )) except CalledModuleError as e: grass.fatal( _("Failure during bspline interpolation. Error message: %s" ) % stderr) else: try: p = grass.core.start_command('r.resamp.bspline', input=input, output=prefix + 'filled', method=method, ew_step=3 * reg['ewres'], ns_step=3 * reg['nsres'], lambda_=lambda_, memory=memory, flags='n', stderr=subprocess.PIPE, env=new_env) stderr = grass.decode(p.communicate()[1]) if "No NULL cells found" in stderr: grass.run_command('g.copy', raster='%s,%sfilled' % (input, prefix), overwrite=True) p.returncode = 0 grass.warning( _("Input map <%s> has no holes. Copying to output without modification." ) % (input, )) except CalledModuleError as e: grass.fatal( _("Failure during bspline interpolation. Error message: %s" ) % stderr) # restoring user's mask, if present: if usermask: grass.message(_("Restoring user mask (MASK)...")) try: grass.run_command('g.rename', quiet=quiet, raster=(usermask, 'MASK')) except CalledModuleError: grass.warning(_("Failed to restore user MASK!")) usermask = None # set region to original extents, align to input grass.run_command('g.region', n=reg_org['n'], s=reg_org['s'], e=reg_org['e'], w=reg_org['w'], align=input) # patch orig and fill map grass.message(_("Patching fill data into NULL areas...")) # we can use --o here as g.parser already checks on startup grass.run_command('r.patch', input=(input, prefix + 'filled'), output=output, overwrite=True) # restore the real region grass.del_temp_region() grass.message(_("Filled raster map is: %s") % output) # write cmd history: grass.raster_history(output) if len(failed_list) > 0: grass.warning( _("Following holes where not filled. Temporary maps with are left " "in place to allow examination of unfilled holes")) outlist = failed_list[0] for hole in failed_list[1:]: outlist = ', ' + outlist grass.message(outlist) grass.message(_("Done."))
def main(): if not hasNumPy: grass.fatal(_("Required dependency NumPy not found. Exiting.")) sharpen = options['method'] # sharpening algorithm ms1 = options['blue'] # blue channel ms2 = options['green'] # green channel ms3 = options['red'] # red channel pan = options['pan'] # high res pan channel out = options['output'] # prefix for output RGB maps bladjust = flags['l'] # adjust blue channel sproc = flags['s'] # serial processing outb = grass.core.find_file('%s_blue' % out) outg = grass.core.find_file('%s_green' % out) outr = grass.core.find_file('%s_red' % out) if (outb['name'] != '' or outg['name'] != '' or outr['name'] != '') and not grass.overwrite(): grass.warning(_('Maps with selected output prefix names already exist.' ' Delete them or use overwrite flag')) return pid = str(os.getpid()) # get PAN resolution: kv = grass.raster_info(map=pan) nsres = kv['nsres'] ewres = kv['ewres'] panres = (nsres + ewres) / 2 # clone current region grass.use_temp_region() grass.run_command('g.region', res=panres, align=pan) grass.message(_("Performing pan sharpening with hi res pan image: %f" % panres)) if sharpen == "brovey": grass.verbose(_("Using Brovey algorithm")) # pan/intensity histogram matching using linear regression outname = 'tmp%s_pan1' % pid panmatch1 = matchhist(pan, ms1, outname) outname = 'tmp%s_pan2' % pid panmatch2 = matchhist(pan, ms2, outname) outname = 'tmp%s_pan3' % pid panmatch3 = matchhist(pan, ms3, outname) outr = '%s_red' % out outg = '%s_green' % out outb = '%s_blue' % out # calculate brovey transformation grass.message(_("Calculating Brovey transformation...")) if sproc: # serial processing e = '''eval(k = "$ms1" + "$ms2" + "$ms3") "$outr" = 1.0 * "$ms3" * "$panmatch3" / k "$outg" = 1.0 * "$ms2" * "$panmatch2" / k "$outb" = 1.0 * "$ms1" * "$panmatch1" / k''' grass.mapcalc(e, outr=outr, outg=outg, outb=outb, panmatch1=panmatch1, panmatch2=panmatch2, panmatch3=panmatch3, ms1=ms1, ms2=ms2, ms3=ms3, overwrite=True) else: # parallel processing pb = grass.mapcalc_start('%s_blue = (1.0 * %s * %s) / (%s + %s + %s)' % (out, ms1, panmatch1, ms1, ms2, ms3), overwrite=True) pg = grass.mapcalc_start('%s_green = (1.0 * %s * %s) / (%s + %s + %s)' % (out, ms2, panmatch2, ms1, ms2, ms3), overwrite=True) pr = grass.mapcalc_start('%s_red = (1.0 * %s * %s) / (%s + %s + %s)' % (out, ms3, panmatch3, ms1, ms2, ms3), overwrite=True) pb.wait() pg.wait() pr.wait() # Cleanup grass.run_command('g.remove', flags='f', quiet=True, type='raster', name='%s,%s,%s' % (panmatch1, panmatch2, panmatch3)) elif sharpen == "ihs": grass.verbose(_("Using IHS<->RGB algorithm")) # transform RGB channels into IHS color space grass.message(_("Transforming to IHS color space...")) grass.run_command('i.rgb.his', overwrite=True, red=ms3, green=ms2, blue=ms1, hue="tmp%s_hue" % pid, intensity="tmp%s_int" % pid, saturation="tmp%s_sat" % pid) # pan/intensity histogram matching using linear regression target = "tmp%s_int" % pid outname = "tmp%s_pan_int" % pid panmatch = matchhist(pan, target, outname) # substitute pan for intensity channel and transform back to RGB color space grass.message(_("Transforming back to RGB color space and sharpening...")) grass.run_command('i.his.rgb', overwrite=True, hue="tmp%s_hue" % pid, intensity="%s" % panmatch, saturation="tmp%s_sat" % pid, red="%s_red" % out, green="%s_green" % out, blue="%s_blue" % out) # Cleanup grass.run_command('g.remove', flags='f', quiet=True, type='raster', name=panmatch) elif sharpen == "pca": grass.verbose(_("Using PCA/inverse PCA algorithm")) grass.message(_("Creating PCA images and calculating eigenvectors...")) # initial PCA with RGB channels pca_out = grass.read_command('i.pca', quiet=True, rescale='0,0', input='%s,%s,%s' % (ms1, ms2, ms3), output='tmp%s.pca' % pid) if len(pca_out) < 1: grass.fatal(_("Input has no data. Check region settings.")) b1evect = [] b2evect = [] b3evect = [] for l in pca_out.replace('(', ',').replace(')', ',').splitlines(): b1evect.append(float(l.split(',')[1])) b2evect.append(float(l.split(',')[2])) b3evect.append(float(l.split(',')[3])) # inverse PCA with hi res pan channel substituted for principal component 1 pca1 = 'tmp%s.pca.1' % pid pca2 = 'tmp%s.pca.2' % pid pca3 = 'tmp%s.pca.3' % pid b1evect1 = b1evect[0] b1evect2 = b1evect[1] b1evect3 = b1evect[2] b2evect1 = b2evect[0] b2evect2 = b2evect[1] b2evect3 = b2evect[2] b3evect1 = b3evect[0] b3evect2 = b3evect[1] b3evect3 = b3evect[2] outname = 'tmp%s_pan' % pid panmatch = matchhist(pan, ms1, outname) grass.message(_("Performing inverse PCA ...")) stats1 = grass.parse_command("r.univar", map=ms1, flags='g', parse=(grass.parse_key_val, {'sep': '='})) stats2 = grass.parse_command("r.univar", map=ms2, flags='g', parse=(grass.parse_key_val, {'sep': '='})) stats3 = grass.parse_command("r.univar", map=ms3, flags='g', parse=(grass.parse_key_val, {'sep': '='})) b1mean = float(stats1['mean']) b2mean = float(stats2['mean']) b3mean = float(stats3['mean']) if sproc: # serial processing e = '''eval(k = "$ms1" + "$ms2" + "$ms3") "$outr" = 1.0 * "$ms3" * "$panmatch3" / k "$outg" = 1.0 * "$ms2" * "$panmatch2" / k "$outb" = 1.0* "$ms1" * "$panmatch1" / k''' outr = '%s_red' % out outg = '%s_green' % out outb = '%s_blue' % out cmd1 = "$outb = (1.0 * $panmatch * $b1evect1) + ($pca2 * $b2evect1) + ($pca3 * $b3evect1) + $b1mean" cmd2 = "$outg = (1.0 * $panmatch * $b1evect2) + ($pca2 * $b2evect1) + ($pca3 * $b3evect2) + $b2mean" cmd3 = "$outr = (1.0 * $panmatch * $b1evect3) + ($pca2 * $b2evect3) + ($pca3 * $b3evect3) + $b3mean" cmd = '\n'.join([cmd1, cmd2, cmd3]) grass.mapcalc(cmd, outb=outb, outg=outg, outr=outr, panmatch=panmatch, pca2=pca2, pca3=pca3, b1evect1=b1evect1, b2evect1=b2evect1, b3evect1=b3evect1, b1evect2=b1evect2, b2evect2=b2evect2, b3evect2=b3evect2, b1evect3=b1evect3, b2evect3=b2evect3, b3evect3=b3evect3, b1mean=b1mean, b2mean=b2mean, b3mean=b3mean, overwrite=True) else: # parallel processing pb = grass.mapcalc_start('%s_blue = (%s * %f) + (%s * %f) + (%s * %f) + %f' % (out, panmatch, b1evect1, pca2, b2evect1, pca3, b3evect1, b1mean), overwrite=True) pg = grass.mapcalc_start('%s_green = (%s * %f) + (%s * %f) + (%s * %f) + %f' % (out, panmatch, b1evect2, pca2, b2evect2, pca3, b3evect2, b2mean), overwrite=True) pr = grass.mapcalc_start('%s_red = (%s * %f) + (%s * %f) + (%s * ''%f) + %f' % (out, panmatch, b1evect3, pca2, b2evect3, pca3, b3evect3, b3mean), overwrite=True) pr.wait() pg.wait() pb.wait() # Cleanup grass.run_command('g.remove', flags='f', quiet=True, type="raster", pattern='tmp%s*,%s' % (pid, panmatch)) # Could add other sharpening algorithms here, e.g. wavelet transformation grass.message(_("Assigning grey equalized color tables to output images...")) # equalized grey scales give best contrast for ch in ['red', 'green', 'blue']: grass.run_command('r.colors', quiet=True, map="%s_%s" % (out, ch), flags="e", color='grey') # Landsat too blue-ish because panchromatic band less sensitive to blue # light, so output blue channed can be modified if bladjust: grass.message(_("Adjusting blue channel color table...")) rules = grass.tempfile() colors = open(rules, 'w') colors.write('5 0 0 0\n20 200 200 200\n40 230 230 230\n67 255 255 255 \n') colors.close() grass.run_command('r.colors', map="%s_blue" % out, rules=rules) os.remove(rules) # output notice grass.verbose(_("The following pan-sharpened output maps have been generated:")) for ch in ['red', 'green', 'blue']: grass.verbose(_("%s_%s") % (out, ch)) grass.verbose(_("To visualize output, run: g.region -p raster=%s_red" % out)) grass.verbose(_("d.rgb r=%s_red g=%s_green b=%s_blue" % (out, out, out))) grass.verbose(_("If desired, combine channels into a single RGB map with 'r.composite'.")) grass.verbose(_("Channel colors can be rebalanced using i.colors.enhance.")) # write cmd history: for ch in ['red', 'green', 'blue']: grass.raster_history("%s_%s" % (out, ch)) # create a group with the three output grass.run_command('i.group', group=out, input="{n}_red,{n}_blue,{n}_green".format(n=out)) # Cleanup grass.run_command('g.remove', flags="f", type="raster", pattern="tmp%s*" % pid, quiet=True)
def main(): global nuldev, tmp nuldev = open(os.devnull, "w") tmp = "v_tin_to_rast_%d" % os.getpid() input = options["input"] output = options["output"] # initialize GRASS library G_gisinit("") # check if vector map exists mapset = G_find_vector2(input, "") if not mapset: grass.fatal("Vector map <%s> not found" % input) # define map structure map_info = pointer(Map_info()) # set vector topology to level 2 Vect_set_open_level(2) # opens the vector map Vect_open_old(map_info, input, mapset) Vect_maptype_info(map_info, input, mapset) # check if vector map is 3D if Vect_is_3d(map_info): grass.message("Vector map <%s> is 3D" % input) else: grass.fatal("Vector map <%s> is not 3D" % input) # allocation of the output buffer using the values of the current region window = pointer(Cell_head()) G_get_window(window) nrows = window.contents.rows ncols = window.contents.cols xref = window.contents.west yref = window.contents.south xres = window.contents.ew_res yres = window.contents.ns_res outrast = [] for i in range(nrows): outrast[i:] = [Rast_allocate_d_buf()] # create new raster outfd = Rast_open_new(output, DCELL_TYPE) if outfd < 0: grass.fatal("Impossible to create a raster <%s>" % output) # insert null values in cells grass.message(_("Step 1/4: Inserting null values in cells...")) for i in range(nrows): Rast_set_d_null_value(outrast[i], ncols) G_percent(i, nrows, 2) ##### main work ##### grass.message(_("Step 2/4: TIN preprocessing...")) z = c_double() G_percent(0, nrows, 2) Vect_tin_get_z(map_info, xref, yref, byref(z), None, None) grass.message(_("Step 3/4: Converting TIN to raster...")) for i in range(nrows): for j in range(ncols): x = xref + j * xres y = yref + i * yres Vect_tin_get_z(map_info, x, y, byref(z), None, None) outrast[i][j] = z G_percent(i, nrows, 2) grass.message(_("Step 4/4: Writing raster map...")) for i in range(nrows - 1, -1, -1): Rast_put_d_row(outfd, outrast[i]) G_percent(nrows - i, nrows, 2) # clear buffer for i in range(nrows): G_free(outrast[i]) # close raster Rast_close(outfd) # close vector Vect_close(map_info) # cut output raster to TIN vertical range vtop = grass.read_command("v.info", flags="g", map=input).rsplit()[4].split("=")[1] vbottom = (grass.read_command("v.info", flags="g", map=input).rsplit()[5].split("=")[1]) tmp = "v_tin_to_rast_%d" % os.getpid() grass.mapcalc( "$tmp = if($vbottom < $output && $output < $vtop, $output, null())", tmp=tmp, output=output, vbottom=vbottom, vtop=vtop, quiet=True, stderr=nuldev, ) grass.parse_command("g.rename", rast=(tmp, output), quiet=True, stderr=nuldev) # write cmd history: grass.run_command( "r.support", map=output, title="%s" % output, history="", description="generated by v.tin.to.rast", ) grass.raster_history(output) grass.message(_("Done."))
def main(): global vrtfile, tmpfile infile = options['input'] rast = options['output'] also = flags['a'] #### check for gdalinfo (just to check if installation is complete) if not grass.find_program('gdalinfo', '--help'): grass.fatal( _("'gdalinfo' not found, install GDAL tools first (http://www.gdal.org)" )) pid = str(os.getpid()) tmpfile = grass.tempfile() ################### let's go spotdir = os.path.dirname(infile) spotname = grass.basename(infile, 'hdf') if rast: name = rast else: name = spotname if not grass.overwrite() and grass.find_file(name)['file']: grass.fatal(_("<%s> already exists. Aborting.") % name) # still a ZIP file? (is this portable?? see the r.in.srtm script for ideas) if infile.lower().endswith('.zip'): grass.fatal(_("Please extract %s before import.") % infile) try: p = grass.Popen(['file', '-ib', infile], stdout=grass.PIPE) s = p.communicate()[0] if s == "application/x-zip": grass.fatal(_("Please extract %s before import.") % infile) except: pass ### create VRT header for NDVI projfile = os.path.join(spotdir, "0001_LOG.TXT") vrtfile = tmpfile + '.vrt' # first process the NDVI: grass.try_remove(vrtfile) create_VRT_file(projfile, vrtfile, infile) ## let's import the NDVI map... grass.message(_("Importing SPOT VGT NDVI map...")) if grass.run_command('r.in.gdal', input=vrtfile, output=name) != 0: grass.fatal(_("An error occurred. Stop.")) grass.message(_("Imported SPOT VEGETATION NDVI map <%s>.") % name) ################# ## http://www.vgt.vito.be/faq/FAQS/faq19.html # What is the relation between the digital number and the real NDVI ? # Real NDVI =coefficient a * Digital Number + coefficient b # = a * DN +b # # Coefficient a = 0.004 # Coefficient b = -0.1 # clone current region # switch to a temporary region grass.use_temp_region() grass.run_command('g.region', rast=name, quiet=True) grass.message(_("Remapping digital numbers to NDVI...")) tmpname = "%s_%s" % (name, pid) grass.mapcalc("$tmpname = 0.004 * $name - 0.1", tmpname=tmpname, name=name) grass.run_command('g.remove', flags='f', type='rast', pattern=name, quiet=True) grass.run_command('g.rename', rast=(tmpname, name), quiet=True) # write cmd history: grass.raster_history(name) #apply color table: grass.run_command('r.colors', map=name, color='ndvi', quiet=True) ########################## # second, optionally process the SM quality map: #SM Status Map # http://nieuw.vgt.vito.be/faq/FAQS/faq22.html #Data about # Bit NR 7: Radiometric quality for B0 coded as 0 if bad and 1 if good # Bit NR 6: Radiometric quality for B2 coded as 0 if bad and 1 if good # Bit NR 5: Radiometric quality for B3 coded as 0 if bad and 1 if good # Bit NR 4: Radiometric quality for MIR coded as 0 if bad and 1 if good # Bit NR 3: land code 1 or water code 0 # Bit NR 2: ice/snow code 1 , code 0 if there is no ice/snow # Bit NR 1: 0 0 1 1 # Bit NR 0: 0 1 0 1 # clear shadow uncertain cloud # #Note: # pos 7 6 5 4 3 2 1 0 (bit position) # 128 64 32 16 8 4 2 1 (values for 8 bit) # # # Bit 4-7 should be 1: their sum is 240 # Bit 3 land code, should be 1, sum up to 248 along with higher bits # Bit 2 ice/snow code # Bit 0-1 should be 0 # # A good map threshold: >= 248 if also: grass.message(_("Importing SPOT VGT NDVI quality map...")) grass.try_remove(vrtfile) qname = spotname.replace('NDV', 'SM') qfile = os.path.join(spotdir, qname) create_VRT_file(projfile, vrtfile, qfile) ## let's import the SM quality map... smfile = name + '.sm' if grass.run_command('r.in.gdal', input=vrtfile, output=smfile) != 0: grass.fatal(_("An error occurred. Stop.")) # some of the possible values: rules = [ r + '\n' for r in [ '8 50 50 50', '11 70 70 70', '12 90 90 90', '60 grey', '155 blue', '232 violet', '235 red', '236 brown', '248 orange', '251 yellow', '252 green' ] ] grass.write_command('r.colors', map=smfile, rules='-', stdin=rules) grass.message( _("Imported SPOT VEGETATION SM quality map <%s>.") % smfile) grass.message( _("Note: A snow map can be extracted by category 252 (d.rast %s cat=252)" ) % smfile) grass.message("") grass.message(_("Filtering NDVI map by Status Map quality layer...")) filtfile = "%s_filt" % name grass.mapcalc( "$filtfile = if($smfile % 4 == 3 || ($smfile / 16) % 16 == 0, null(), $name)", filtfile=filtfile, smfile=smfile, name=name) grass.run_command('r.colors', map=filtfile, color='ndvi', quiet=True) grass.message(_("Filtered SPOT VEGETATION NDVI map <%s>.") % filtfile) # write cmd history: grass.raster_history(smfile) grass.raster_history(filtfile) grass.message(_("Done."))
def main(): global temp_dist, temp_src input = options["input"] output = options["output"] distances = options["distances"] units = options["units"] zero = flags["z"] tmp = str(os.getpid()) temp_dist = "r.buffer.tmp.%s.dist" % tmp temp_src = "r.buffer.tmp.%s.src" % tmp # check if input file exists if not grass.find_file(input)["file"]: grass.fatal(_("Raster map <%s> not found") % input) scale = scales[units] distances = distances.split(",") distances1 = [scale * float(d) for d in distances] distances2 = [d * d for d in distances1] s = grass.read_command("g.proj", flags="j") kv = grass.parse_key_val(s) if kv["+proj"] == "longlat": metric = "geodesic" else: metric = "squared" grass.run_command("r.grow.distance", input=input, metric=metric, distance=temp_dist, flags="m") if zero: exp = "$temp_src = if($input == 0,null(),1)" else: exp = "$temp_src = if(isnull($input),null(),1)" grass.message(_("Extracting buffers (1/2)...")) grass.mapcalc(exp, temp_src=temp_src, input=input) exp = "$output = if(!isnull($input),$input,%s)" if metric == "squared": for n, dist2 in enumerate(distances2): exp %= "if($dist <= %f,%d,%%s)" % (dist2, n + 2) else: for n, dist2 in enumerate(distances1): exp %= "if($dist <= %f,%d,%%s)" % (dist2, n + 2) exp %= "null()" grass.message(_("Extracting buffers (2/2)...")) grass.mapcalc(exp, output=output, input=temp_src, dist=temp_dist) p = grass.feed_command("r.category", map=output, separator=":", rules="-") msg = "1:distances calculated from these locations\n" p.stdin.write(encode(msg)) d0 = "0" for n, d in enumerate(distances): msg = "%d:%s-%s %s\n" % (n + 2, d0, d, units) p.stdin.write(encode(msg)) d0 = d p.stdin.close() p.wait() grass.run_command("r.colors", map=output, color="rainbow") # write cmd history: grass.raster_history(output)
def main(): options, flags = grass.parser() elevation_input = options['input'] pca_shade_output = options['output'] altitude = float(options['altitude']) number_of_azimuths = int(options['nazimuths']) z_exaggeration = float(options['zscale']) scale = float(options['scale']) units = options['units'] shades_basename = options['shades_basename'] pca_basename = pca_basename_user = options['pca_shades_basename'] nprocs = int(options['nprocs']) full_circle = 360 # let's use floats here and leave the consequences to the user smallest_angle = float(full_circle) / number_of_azimuths azimuths = list(frange(0, full_circle, smallest_angle)) if not shades_basename: shades_basename = create_tmp_map_name('shade') MREMOVE.append(shades_basename) if not pca_basename: pca_basename = pca_shade_output + '_pca' pca_maps = [ pca_basename + '.' + str(i) for i in range(1, number_of_azimuths + 1) ] if not pca_basename_user: REMOVE.extend(pca_maps) # here we check all the posible if not grass.overwrite(): check_map_names(shades_basename, grass.gisenv()['MAPSET'], suffixes=azimuths) check_map_names(pca_basename, grass.gisenv()['MAPSET'], suffixes=range(1, number_of_azimuths)) grass.info(_("Running r.relief in a loop...")) count = 0 # Parallel processing proc_list = [] proc_count = 0 suffixes = [] all_suffixes = [] core.percent(0, number_of_azimuths, 1) for azimuth in azimuths: count += 1 core.percent(count, number_of_azimuths, 10) suffix = '_' + str(azimuth) proc_list.append( Process(target=run_r_shaded_relief, args=(elevation_input, shades_basename, altitude, azimuth, z_exaggeration, scale, units, suffix))) proc_list[proc_count].start() proc_count += 1 suffixes.append(suffix) all_suffixes.append(suffix) if proc_count == nprocs or proc_count == number_of_azimuths \ or count == number_of_azimuths: proc_count = 0 exitcodes = 0 for proc in proc_list: proc.join() exitcodes += proc.exitcode if exitcodes != 0: core.fatal(_("Error during r.relief computation")) # Empty process list proc_list = [] suffixes = [] # FIXME: how percent really works? # core.percent(1, 1, 1) shade_maps = [shades_basename + suf for suf in all_suffixes] grass.info(_("Running r.pca...")) # not quiet=True to get percents grass.run_command('i.pca', input=shade_maps, output=pca_basename, overwrite=core.overwrite()) grass.info( _("Creating RGB composite from " "PC1 (red), PC2 (green), PC3 (blue) ...")) grass.run_command('r.composite', red=pca_maps[0], green=pca_maps[1], blue=pca_maps[2], output=pca_shade_output, overwrite=core.overwrite(), quiet=True) grass.raster_history(pca_shade_output) if pca_basename_user: set_color_table(pca_maps, map_=shade_maps[0])
def main(): # split input images all_images = options['input'] images = all_images.split(',') # number of images n_images = len(images) # database path dbopt = options['database'] # output suffix suffix = options['suffix'] # output mosaic map mosaic = options['output'] output_names = [] # name for average table table_ave = "t%s_average" % suffix # increment of one the maximum value for a correct use of range function max_value = int(options['max']) + 1 # if the db path is the default one if dbopt.find('$GISDBASE/$LOCATION_NAME/$MAPSET') == 0: dbopt_split = dbopt.split('/')[-1] env = grass.gisenv() path = os.path.join(env['GISDBASE'], env['LOCATION_NAME'], env['MAPSET']) dbpath = os.path.join(path, dbopt_split) else: if os.access(os.path.dirname(dbopt), os.W_OK): path = os.path.dirname(dbopt) dbpath = dbopt else: grass.fatal( _("Folder to write database files does not" + " exist or is not writeable")) # connect to the db db = sqlite3.connect(dbpath) curs = db.cursor() grass.message(_("Calculating Cumulative Distribution Functions ...")) # number of pixels per value, summarized for all images numPixelValue = list(range(0, max_value)) for n in range(0, max_value): numPixelValue[n] = 0 # cumulative histogram for each value and each image cumulHistoValue = list(range(0, max_value)) # set up temp region only once grass.use_temp_region() # for each image for i in images: iname = i.split('@')[0] # drop table if exist query_drop = "DROP TABLE if exists \"t%s\"" % iname curs.execute(query_drop) # create table query_create = "CREATE TABLE \"t%s\" (grey_value integer,pixel_frequency " % iname query_create += "integer, cumulative_histogram integer, cdf real)" curs.execute(query_create) index_create = "CREATE UNIQUE INDEX \"t%s_grey_value\" ON \"t%s\" (grey_value) " % ( iname, iname) curs.execute(index_create) # set the region on the raster grass.run_command('g.region', raster=i) # calculate statistics stats_out = grass.pipe_command('r.stats', flags='cin', input=i, separator=':') stats = stats_out.communicate()[0].decode('utf-8').split('\n')[:-1] stats_dict = dict(s.split(':', 1) for s in stats) cdf = 0 curs.execute("BEGIN") # for each number in the range for n in range(0, max_value): # try to insert the values otherwise insert 0 try: val = int(stats_dict[str(n)]) cdf += val numPixelValue[n] += val insert = "INSERT INTO \"t%s\" VALUES (%i, %i, %i, 0.000000)" % ( iname, n, val, cdf) curs.execute(insert) except: insert = "INSERT INTO \"t%s\" VALUES (%i, 0, %i, 0.000000)" % ( iname, n, cdf) curs.execute(insert) # save cumulative_histogram for the second loop cumulHistoValue[n] = cdf curs.execute("COMMIT") db.commit() # number of pixel is the cdf value numPixel = cdf # for each number in the range # cdf is updated using the number of non-null pixels for the current image curs.execute("BEGIN") for n in range(0, max_value): # select value for cumulative_histogram for the range number """ select_ch = "SELECT cumulative_histogram FROM \"t%s\" WHERE " % iname select_ch += "(grey_value=%i)" % n result = curs.execute(select_ch) val = result.fetchone()[0] """ val = cumulHistoValue[n] # update cdf with new value if val != 0 and numPixel != 0: update_cdf = round(float(val) / float(numPixel), 6) update_cdf = "UPDATE \"t%s\" SET cdf=%s WHERE (grey_value=%i)" % ( iname, update_cdf, n) curs.execute(update_cdf) curs.execute("COMMIT") db.commit() db.commit() pixelTot = 0 # get total number of pixels divided by number of images # for each number in the range for n in range(0, max_value): """ numPixel = 0 # for each image for i in images: iname = i.split('@')[0] pixel_freq = "SELECT pixel_frequency FROM \"t%s\" WHERE (grey_value=%i)" % ( iname, n) result = curs.execute(pixel_freq) val = result.fetchone()[0] numPixel += val """ # calculate number of pixel divide by number of images div = (int(numPixelValue[n] / n_images)) pixelTot += div # drop average table query_drop = "DROP TABLE if exists %s" % table_ave curs.execute(query_drop) # create average table query_create = "CREATE TABLE %s (grey_value integer,average " % table_ave query_create += "integer, cumulative_histogram integer, cdf real)" curs.execute(query_create) index_create = "CREATE UNIQUE INDEX \"%s_grey_value\" ON \"%s\" (grey_value) " % ( table_ave, table_ave) curs.execute(index_create) cHist = 0 # for each number in the range curs.execute("BEGIN") for n in range(0, max_value): tot = 0 """ # for each image for i in images: iname = i.split('@')[0] # select pixel frequency pixel_freq = "SELECT pixel_frequency FROM \"t%s\" WHERE (grey_value=%i)" % ( iname, n) result = curs.execute(pixel_freq) val = result.fetchone()[0] tot += val """ tot = numPixelValue[n] # calculate new value of pixel_frequency average = (tot / n_images) cHist = cHist + int(average) # insert new values into average table if cHist != 0 and pixelTot != 0: cdf = float(cHist) / float(pixelTot) insert = "INSERT INTO %s VALUES (%i, %i, %i, %s)" % ( table_ave, n, int(average), cHist, cdf) curs.execute(insert) curs.execute("COMMIT") db.commit() # for each image grass.message(_("Reclassifying bands based on average histogram...")) for i in images: iname = i.split('@')[0] grass.run_command('g.region', raster=i) # write average rules file outfile = open(grass.tempfile(), 'w') new_grey = 0 for n in range(0, max_value): select_newgrey = "SELECT b.grey_value FROM \"t%s\" as a, " % iname select_newgrey += "%s as b WHERE a.grey_value=%i " % (table_ave, n) \ + "ORDER BY abs(a.cdf-b.cdf) LIMIT 1" # write line with old and new value try: result_new = curs.execute(select_newgrey) new_grey = result_new.fetchone()[0] out_line = "%d = %d\n" % (n, new_grey) outfile.write(out_line) except: out_line = "%d = %d\n" % (n, new_grey) outfile.write(out_line) outfile.close() outname = '%s.%s' % (iname, suffix) # check if a output map already exists result = grass.core.find_file(outname, element='cell') if result['fullname'] and grass.overwrite(): grass.run_command('g.remove', flags='f', type='raster', name=outname) grass.run_command('r.reclass', input=i, out=outname, rules=outfile.name) elif result['fullname'] and not grass.overwrite(): grass.warning( _("Raster map %s already exists and will not be overwritten" % i)) else: grass.run_command('r.reclass', input=i, out=outname, rules=outfile.name) output_names.append(outname) # remove the rules file grass.try_remove(outfile.name) # write cmd history: grass.raster_history(outname) db.commit() db.close() if mosaic: grass.message(_("Processing mosaic <%s>..." % mosaic)) grass.run_command('g.region', raster=all_images) grass.run_command('r.patch', input=output_names, output=mosaic)
def main(): global nuldev, tmp nuldev = file(os.devnull, "w") tmp = "v_tin_to_rast_%d" % os.getpid() input = options["input"] output = options["output"] # initialize GRASS library G_gisinit("") # check if vector map exists mapset = G_find_vector2(input, "") if not mapset: grass.fatal("Vector map <%s> not found" % input) # define map structure map_info = pointer(Map_info()) # set vector topology to level 2 Vect_set_open_level(2) # opens the vector map Vect_open_old(map_info, input, mapset) Vect_maptype_info(map_info, input, mapset) # check if vector map is 3D if Vect_is_3d(map_info): grass.message("Vector map <%s> is 3D" % input) else: grass.fatal("Vector map <%s> is not 3D" % input) # allocation of the output buffer using the values of the current region window = pointer(Cell_head()) G_get_window(window) nrows = window.contents.rows ncols = window.contents.cols xref = window.contents.west yref = window.contents.south xres = window.contents.ew_res yres = window.contents.ns_res outrast = [] for i in range(nrows): outrast[i:] = [Rast_allocate_d_buf()] # create new raster outfd = Rast_open_new(output, DCELL_TYPE) if outfd < 0: grass.fatal("Impossible to create a raster <%s>" % output) # insert null values in cells grass.message(_("Step 1/4: Inserting null values in cells...")) for i in range(nrows): Rast_set_d_null_value(outrast[i], ncols) G_percent(i, nrows, 2) ##### main work ##### grass.message(_("Step 2/4: TIN preprocessing...")) z = c_double() G_percent(0, nrows, 2) Vect_tin_get_z(map_info, xref, yref, byref(z), None, None) grass.message(_("Step 3/4: Converting TIN to raster...")) for i in range(nrows): for j in range(ncols): x = xref + j * xres y = yref + i * yres Vect_tin_get_z(map_info, x, y, byref(z), None, None) outrast[i][j] = z G_percent(i, nrows, 2) grass.message(_("Step 4/4: Writing raster map...")) for i in range(nrows - 1, -1, -1): Rast_put_d_row(outfd, outrast[i]) G_percent(nrows - i, nrows, 2) # clear buffer for i in range(nrows): G_free(outrast[i]) # close raster Rast_close(outfd) # close vector Vect_close(map_info) # cut output raster to TIN vertical range vtop = grass.read_command("v.info", flags="g", map=input).rsplit()[4].split("=")[1] vbottom = grass.read_command("v.info", flags="g", map=input).rsplit()[5].split("=")[1] tmp = "v_tin_to_rast_%d" % os.getpid() grass.mapcalc( "$tmp = if($vbottom < $output && $output < $vtop, $output, null())", tmp=tmp, output=output, vbottom=vbottom, vtop=vtop, quiet=True, stderr=nuldev, ) grass.parse_command("g.rename", rast=(tmp, output), quiet=True, stderr=nuldev) # write cmd history: grass.run_command( "r.support", map=output, title="%s" % output, history="", description="generated by v.tin.to.rast" ) grass.raster_history(output) grass.message(_("Done."))
def main(): global tile, tmpdir, in_temp in_temp = False input = options['input'] output = options['output'] one = flags['1'] #are we in LatLong location? s = grass.read_command("g.proj", flags='j') kv = grass.parse_key_val(s) if kv['+proj'] != 'longlat': grass.fatal(_("This module only operates in LatLong locations")) # use these from now on: infile = input while infile[-4:].lower() in ['.hgt', '.zip']: infile = infile[:-4] (fdir, tile) = os.path.split(infile) if not output: tileout = tile else: tileout = output zipfile = infile + ".hgt.zip" hgtfile = os.path.join(fdir, tile[:7] + ".hgt") if os.path.isfile(zipfile): #### check if we have unzip if not grass.find_program('unzip'): grass.fatal(_('The "unzip" program is required, please install it first')) # really a ZIP file? # make it quiet in a safe way (just in case -qq isn't portable) tenv = os.environ.copy() tenv['UNZIP'] = '-qq' if grass.call(['unzip', '-t', zipfile], env = tenv) != 0: grass.fatal(_("'%s' does not appear to be a valid zip file.") % zipfile) is_zip = True elif os.path.isfile(hgtfile): # try and see if it's already unzipped is_zip = False else: grass.fatal(_("File '%s' or '%s' not found") % (zipfile, hgtfile)) #make a temporary directory tmpdir = grass.tempfile() grass.try_remove(tmpdir) os.mkdir(tmpdir) if is_zip: shutil.copyfile(zipfile, os.path.join(tmpdir, tile + ".hgt.zip")) else: shutil.copyfile(hgtfile, os.path.join(tmpdir, tile + ".hgt")) #change to temporary directory os.chdir(tmpdir) in_temp = True zipfile = tile + ".hgt.zip" hgtfile = tile[:7] + ".hgt" bilfile = tile + ".bil" if is_zip: #unzip & rename data file: grass.message(_("Extracting '%s'...") % infile) if grass.call(['unzip', zipfile], env = tenv) != 0: grass.fatal(_("Unable to unzip file.")) grass.message(_("Converting input file to BIL...")) os.rename(hgtfile, bilfile) north = tile[0] ll_latitude = int(tile[1:3]) east = tile[3] ll_longitude = int(tile[4:7]) # are we on the southern hemisphere? If yes, make LATITUDE negative. if north == "S": ll_latitude *= -1 # are we west of Greenwich? If yes, make LONGITUDE negative. if east == "W": ll_longitude *= -1 # Calculate Upper Left from Lower Left ulxmap = "%.1f" % ll_longitude # SRTM90 tile size is 1 deg: ulymap = "%.1f" % (ll_latitude + 1) if not one: tmpl = tmpl3sec else: grass.message(_("Attempting to import 1-arcsec data.")) tmpl = tmpl1sec header = tmpl % (ulxmap, ulymap) hdrfile = tile + '.hdr' outf = file(hdrfile, 'w') outf.write(header) outf.close() #create prj file: To be precise, we would need EGS96! But who really cares... prjfile = tile + '.prj' outf = file(prjfile, 'w') outf.write(proj) outf.close() try: grass.run_command('r.in.gdal', input=bilfile, out=tileout) except: grass.fatal(_("Unable to import data")) # nice color table grass.run_command('r.colors', map = tileout, color = 'srtm') # write cmd history: grass.raster_history(tileout) grass.message(_("Done: generated map ") + tileout) grass.message(_("(Note: Holes in the data can be closed with 'r.fillnulls' using splines)"))
def main(): global tmp landsat = flags['l'] quickbird = flags['q'] spot = flags['s'] ms1 = options['ms1'] ms2 = options['ms2'] ms3 = options['ms3'] pan = options['pan'] out = options['output_prefix'] tmp = str(os.getpid()) if not landsat and not quickbird and not spot: grass.fatal(_("Please select a flag to specify the satellite sensor")) #get PAN resolution: kv = grass.raster_info(map = pan) nsres = kv['nsres'] ewres = kv['ewres'] panres = (nsres + ewres) / 2 # clone current region grass.use_temp_region() grass.verbose("Using resolution from PAN: %f" % panres) grass.run_command('g.region', flags = 'a', res = panres) grass.verbose("Performing Brovey transformation...") # The formula was originally developed for LANDSAT-TM5 and SPOT, # but it also works well with LANDSAT-TM7 # LANDSAT formula: # r.mapcalc "brov.red=1. * tm.5 / (tm.2 + tm.4 + tm.5) * etmpan" # r.mapcalc "brov.green=1. * tm.4 /(tm.2 + tm.4 + tm.5) * etmpan" # r.mapcalc "brov.blue=1. * tm.2 / (tm.2 + tm.4 + tm.5) * etmpan" # # SPOT formula: # r.mapcalc "brov.red= 1. * spot.ms.3 / (spot.ms.1 + spot.ms.2 + spot.ms.3) * spot.p" # r.mapcalc "brov.green=1. * spot.ms.2 / (spot.ms.1 + spot.ms.2 + spot.ms.3) * spot.p" # r.mapcalc "brov.blue= 1. * spot.ms.1 / (spot.ms.1 + spot.ms.2 + spot.ms.3) * spot.p" # note: for RGB composite then revert brov.red and brov.green! grass.message(_("Calculating %s.{red,green,blue}: ...") % out) e = '''eval(k = float("$pan") / ("$ms1" + "$ms2" + "$ms3")) "$out.red" = "$ms3" * k "$out.green" = "$ms2" * k "$out.blue" = "$ms1" * k''' grass.mapcalc(e, out = out, pan = pan, ms1 = ms1, ms2 = ms2, ms3 = ms3) # Maybe? #r.colors $GIS_OPT_OUTPUTPREFIX.red col=grey #r.colors $GIS_OPT_OUTPUTPREFIX.green col=grey #r.colors $GIS_OPT_OUTPUTPREFIX.blue col=grey #to blue-ish, therefore we modify #r.colors $GIS_OPT_OUTPUTPREFIX.blue col=rules << EOF #5 0 0 0 #20 200 200 200 #40 230 230 230 #67 255 255 255 #EOF if spot: #apect table is nice for SPOT: grass.message(_("Assigning color tables for SPOT...")) for ch in ['red', 'green', 'blue']: grass.run_command('r.colors', map = "%s.%s" % (out, ch), col = 'aspect') grass.message(_("Fixing output names...")) for s, d in [('green','tmp'),('red','green'),('tmp','red')]: src = "%s.%s" % (out, s) dst = "%s.%s" % (out, d) grass.run_command('g.rename', rast = (src, dst), quiet = True) else: #aspect table is nice for LANDSAT and QuickBird: grass.message(_("Assigning color tables for LANDSAT or QuickBird...")) for ch in ['red', 'green', 'blue']: grass.run_command('r.colors', map = "%s.%s" % (out, ch), col = 'aspect') grass.message(_("Following pan-sharpened output maps have been generated:")) for ch in ['red', 'green', 'blue']: grass.message(_("%s.%s") % (out, ch)) grass.verbose("To visualize output, run:") grass.verbose("g.region -p rast=%s.red" % out) grass.verbose("d.rgb r=%s.red g=%s.green b=%s.blue" % (out, out, out)) grass.verbose("If desired, combine channels with 'r.composite' to a single map.") # write cmd history: for ch in ['red', 'green', 'blue']: grass.raster_history("%s.%s" % (out, ch))
def main(): global tmp landsat = flags['l'] quickbird = flags['q'] spot = flags['s'] ms1 = options['ms1'] ms2 = options['ms2'] ms3 = options['ms3'] pan = options['pan'] out = options['output_prefix'] tmp = str(os.getpid()) if not landsat and not quickbird and not spot: grass.fatal(_("Please select a flag to specify the satellite sensor")) # get PAN resolution: kv = grass.raster_info(map=pan) nsres = kv['nsres'] ewres = kv['ewres'] panres = (nsres + ewres) / 2 # clone current region grass.use_temp_region() grass.verbose("Using resolution from PAN: %f" % panres) grass.run_command('g.region', flags='a', res=panres) grass.verbose("Performing Brovey transformation...") # The formula was originally developed for LANDSAT-TM5 and SPOT, # but it also works well with LANDSAT-TM7 # LANDSAT formula: # r.mapcalc "brov.red=1. * tm.5 / (tm.2 + tm.4 + tm.5) * etmpan" # r.mapcalc "brov.green=1. * tm.4 /(tm.2 + tm.4 + tm.5) * etmpan" # r.mapcalc "brov.blue=1. * tm.2 / (tm.2 + tm.4 + tm.5) * etmpan" # # SPOT formula: # r.mapcalc "brov.red= 1. * spot.ms.3 / (spot.ms.1 + spot.ms.2 + spot.ms.3) * spot.p" # r.mapcalc "brov.green=1. * spot.ms.2 / (spot.ms.1 + spot.ms.2 + spot.ms.3) * spot.p" # r.mapcalc "brov.blue= 1. * spot.ms.1 / (spot.ms.1 + spot.ms.2 + spot.ms.3) * spot.p" # note: for RGB composite then revert brov.red and brov.green! grass.message(_("Calculating %s.{red,green,blue}: ...") % out) e = '''eval(k = float("$pan") / ("$ms1" + "$ms2" + "$ms3")) "$out.red" = "$ms3" * k "$out.green" = "$ms2" * k "$out.blue" = "$ms1" * k''' grass.mapcalc(e, out=out, pan=pan, ms1=ms1, ms2=ms2, ms3=ms3) # Maybe? # r.colors $GIS_OPT_OUTPUTPREFIX.red col=grey # r.colors $GIS_OPT_OUTPUTPREFIX.green col=grey # r.colors $GIS_OPT_OUTPUTPREFIX.blue col=grey # to blue-ish, therefore we modify # r.colors $GIS_OPT_OUTPUTPREFIX.blue col=rules << EOF # 5 0 0 0 # 20 200 200 200 # 40 230 230 230 # 67 255 255 255 # EOF if spot: # aspect table is nice for SPOT: grass.message(_("Assigning color tables for SPOT...")) for ch in ['red', 'green', 'blue']: grass.run_command('r.colors', map="%s.%s" % (out, ch), col='aspect') grass.message(_("Fixing output names...")) for s, d in [('green', 'tmp'), ('red', 'green'), ('tmp', 'red')]: src = "%s.%s" % (out, s) dst = "%s.%s" % (out, d) grass.run_command('g.rename', raster=(src, dst), quiet=True) else: # aspect table is nice for LANDSAT and QuickBird: grass.message(_("Assigning color tables for LANDSAT or QuickBird...")) for ch in ['red', 'green', 'blue']: grass.run_command('r.colors', map="%s.%s" % (out, ch), col='aspect') grass.message( _("Following pan-sharpened output maps have been generated:")) for ch in ['red', 'green', 'blue']: grass.message(_("%s.%s") % (out, ch)) grass.verbose("To visualize output, run:") grass.verbose("g.region -p raster=%s.red" % out) grass.verbose("d.rgb r=%s.red g=%s.green b=%s.blue" % (out, out, out)) grass.verbose( "If desired, combine channels with 'r.composite' to a single map.") # write cmd history: for ch in ['red', 'green', 'blue']: grass.raster_history("%s.%s" % (out, ch))
def main(): red = options['red'] green = options['green'] blue = options['blue'] brightness = options['strength'] full = flags['f'] preserve = flags['p'] reset = flags['r'] global do_mp if flags['s']: do_mp = False # 90 or 98? MAX value controls brightness # think of percent (0-100), must be positive or 0 # must be more than "2" ? if full: for i in [red, green, blue]: grass.run_command('r.colors', map = i, color = 'grey', quiet = True) sys.exit(0) if reset: for i in [red, green, blue]: grass.run_command('r.colors', map = i, color = 'grey255', quiet = True) sys.exit(0) if not preserve: if do_mp: grass.message(_("Processing...")) # set up jobs and launch them proc = {} conn = {} for i in [red, green, blue]: conn[i] = mp.Pipe() proc[i] = mp.Process(target = get_percentile_mp, args = (i, ['2', brightness], conn[i],)) proc[i].start() grass.percent(1, 2, 1) # collect results and wait for jobs to finish for i in [red, green, blue]: output_pipe, input_pipe = conn[i] (v0, v1) = input_pipe.recv() grass.debug('parent (%s) (%.1f, %.1f)' % (i, v0, v1)) input_pipe.close() proc[i].join() set_colors(i, v0, v1) grass.percent(1, 1, 1) else: for i in [red, green, blue]: grass.message(_("Processing...")) (v0, v1) = get_percentile(i, ['2', brightness]) grass.debug("<%s>: min=%f max=%f" % (i, v0, v1)) set_colors(i, v0, v1) else: all_max = 0 all_min = 999999 if do_mp: grass.message(_("Processing...")) # set up jobs and launch jobs proc = {} conn = {} for i in [red, green, blue]: conn[i] = mp.Pipe() proc[i] = mp.Process(target = get_percentile_mp, args = (i, ['2', brightness], conn[i],)) proc[i].start() grass.percent(1, 2, 1) # collect results and wait for jobs to finish for i in [red, green, blue]: output_pipe, input_pipe = conn[i] (v0, v1) = input_pipe.recv() grass.debug('parent (%s) (%.1f, %.1f)' % (i, v0, v1)) input_pipe.close() proc[i].join() all_min = min(all_min, v0) all_max = max(all_max, v1) grass.percent(1, 1, 1) else: for i in [red, green, blue]: grass.message(_("Processing...")) (v0, v1) = get_percentile(i, ['2', brightness]) grass.debug("<%s>: min=%f max=%f" % (i, v0, v1)) all_min = min(all_min, v0) all_max = max(all_max, v1) grass.debug("all_min=%f all_max=%f" % (all_min, all_max)) for i in [red, green, blue]: set_colors(i, all_min, all_max) # write cmd history: mapset = grass.gisenv()['MAPSET'] for i in [red, green, blue]: if grass.find_file(i)['mapset'] == mapset: grass.raster_history(i)
def main(): global vecttmp, tmp1, usermask, mapset input = options['input'] output = options['output'] tension = options['tension'] smooth = options['smooth'] mapset = grass.gisenv()['MAPSET'] unique = str(os.getpid()) #check if input file exists if not grass.find_file(input)['file']: grass.fatal(_("<%s> does not exist.") % input) # check if a MASK is already present: usermask = "usermask_mask." + unique if grass.find_file('MASK', mapset = mapset)['file']: grass.message(_("A user raster mask (MASK) is present. Saving it...")) grass.run_command('g.rename', quiet = True, rast = ('MASK',usermask)) #make a mask of NULL cells tmp1 = "r_fillnulls_" + unique # idea: filter all NULLS and grow that area(s) by 3 pixel, then # interpolate from these surrounding 3 pixel edge grass.message(_("Locating and isolating NULL areas...")) #creating 0/1 map: grass.mapcalc("$tmp1 = if(isnull($input),1,null())", tmp1 = tmp1, input = input) #generate a ring: # the buffer is set to three times the map resolution so you get nominally # three points around the edge. This way you interpolate into the hole with # a trained slope & curvature at the edges, otherwise you just get a flat plane. # With just a single row of cells around the hole you often get gaps # around the edges when distance > mean (.5 of the time? diagonals? worse # when ewres!=nsres). # r.buffer broken in trunk for latlon, disabled #reg = grass.region() #res = (float(reg['nsres']) + float(reg['ewres'])) * 3 / 2 #if grass.run_command('r.buffer', input = tmp1, distances = res, out = tmp1 + '.buf') != 0: # much easier way: use r.grow with radius=3.01 if grass.run_command('r.grow', input = tmp1, radius = 3.01, old = 1, new = 2, out = tmp1 + '.buf') != 0: grass.fatal(_("abandoned. Removing temporary map, restoring user mask if needed:")) grass.mapcalc("MASK=if($tmp1.buf==2,1,null())", tmp1 = tmp1) # now we only see the outlines of the NULL areas if looking at INPUT. # Use this outline (raster border) for interpolating the fill data: vecttmp = "vecttmp_fillnulls_" + unique grass.message(_("Creating interpolation points...")) if grass.run_command('r.to.vect', input = input, output = vecttmp, feature = 'point'): grass.fatal(_("abandoned. Removing temporary maps, restoring user mask if needed:")) # count number of points to control segmax parameter for interpolation: pointsnumber = grass.vector_info_topo(map = vecttmp)['points'] grass.message(_("Interpolating %d points") % pointsnumber) if pointsnumber < 2: grass.fatal(_("Not sufficient points to interpolate. Maybe no hole(s) to fill in the current map region?")) grass.message(_("Note: The following warnings may be ignored.")) # remove internal MASK first -- WHY???? MN 10/2005 grass.run_command('g.remove', quiet = True, rast = 'MASK') if grass.find_file(usermask, mapset = mapset)['file']: grass.message(_("Using user mask while interpolating")) maskmap = usermask else: maskmap = None segmax = 600 if pointsnumber > segmax: grass.message(_("Using segmentation for interpolation...")) segmax = None else: grass.message(_("Using no segmentation for interpolation as not needed...")) grass.run_command('v.surf.rst', input = vecttmp, elev = tmp1 + '_filled', zcol = 'value', tension = tension, smooth = smooth, maskmap = maskmap, segmax = segmax) grass.message(_("Note: Above warnings may be ignored.")) # restoring user's mask, if present: if grass.find_file(usermask, mapset = mapset)['file']: grass.message(_("Restoring user mask (MASK)...")) grass.run_command('g.rename', quiet = True, rast = (usermask, 'MASK')) # patch orig and fill map grass.message(_("Patching fill data into NULL areas...")) # we can use --o here as g.parser already checks on startup grass.run_command('r.patch', input = (input,tmp1 + '_filled'), output = output, overwrite = True) grass.message(_("Filled raster map is: %s") % output) # write cmd history: grass.raster_history(output) grass.message(_("Done."))
def main(): atexit.register(cleanup) options, flags = gscript.parser() elevation_input = options["input"] local_relief_output = options["output"] neighborhood_size = int(options["neighborhood_size"]) save_intermediates = flags["i"] bspline = flags["v"] # when bspline == False, r.fillnulls is used shaded_local_relief_output = options["shaded_output"] # constants fill_method = "bicubic" # color table changed from difference to grey to histogram equalized-grey # It does make more sense to use that since many archaeologists use the same # color scheme for magnetometry and gpr data. color_table = options["color_table"] if color_table: user_color_table = True else: user_color_table = False rcolors_flags = "e" if flags["f"]: rcolors_flags = "" if flags["g"]: rcolors_flags += "g" if flags["n"]: rcolors_flags += "n" if save_intermediates: def local_create(name): """create_persistent_map_name with hard-coded first argument""" basename = local_relief_output.split("@")[0] return create_persistent_map_name(basename=basename, name=name) create_map_name = local_create else: create_map_name = create_tmp_map_name smooth_elevation = create_map_name("smooth_elevation") subtracted_smooth_elevation = create_map_name( "subtracted_smooth_elevation") vector_contours = create_map_name("vector_contours") raster_contours_with_values = create_map_name( "raster_contours_with_values") purged_elevation = create_map_name("purged_elevation") if bspline: contour_points = create_map_name("contour_points") else: raster_contours = create_map_name("raster_contours") if shaded_local_relief_output: relief_shade = create_map_name("relief_shade") # if saving intermediates, keep only 1 contour layer if save_intermediates: if not bspline: RREMOVE.append(raster_contours) VREMOVE.append(vector_contours) else: RREMOVE.append(smooth_elevation) RREMOVE.append(subtracted_smooth_elevation) VREMOVE.append(vector_contours) RREMOVE.append(purged_elevation) if bspline: VREMOVE.append(contour_points) else: RREMOVE.append(raster_contours) RREMOVE.append(raster_contours_with_values) # check even for the temporary maps # (although, in ideal world, we should always fail if some of them exists) if not gcore.overwrite(): check_map_name(smooth_elevation, gscript.gisenv()["MAPSET"], "cell") check_map_name(subtracted_smooth_elevation, gscript.gisenv()["MAPSET"], "cell") check_map_name(vector_contours, gscript.gisenv()["MAPSET"], "vect") check_map_name(raster_contours_with_values, gscript.gisenv()["MAPSET"], "cell") check_map_name(purged_elevation, gscript.gisenv()["MAPSET"], "cell") if bspline: check_map_name(contour_points, gscript.gisenv()["MAPSET"], "vect") else: check_map_name(raster_contours, gscript.gisenv()["MAPSET"], "cell") # algorithm according to Hesse 2010 (LiDAR-derived Local Relief Models) # step 1 (point cloud to digital elevation model) omitted # step 2 gscript.info(_("Smoothing using r.neighbors...")) gscript.run_command( "r.neighbors", input=elevation_input, output=smooth_elevation, size=neighborhood_size, overwrite=gcore.overwrite(), ) # step 3 gscript.info(_("Subtracting smoothed from original elevation...")) gscript.mapcalc("{c} = {a} - {b}".format( c=subtracted_smooth_elevation, a=elevation_input, b=smooth_elevation, overwrite=gcore.overwrite(), )) # step 4 gscript.info(_("Finding zero contours in elevation difference map...")) gscript.run_command( "r.contour", input=subtracted_smooth_elevation, output=vector_contours, levels=[0], overwrite=gcore.overwrite(), ) # Diverge here if using bspline interpolation # step 5 gscript.info( _("Extracting z value from the elevation" " for difference zero contours...")) if bspline: # Extract points from vector contours gscript.run_command( "v.to.points", _input=vector_contours, llayer="1", _type="line", output=contour_points, dmax="10", overwrite=gcore.overwrite(), ) # Extract original dem elevations at point locations gscript.run_command( "v.what.rast", _map=contour_points, raster=elevation_input, layer="2", column="along", ) # Get mean distance between points to optimize spline interpolation mean_dist = gscript.parse_command( "v.surf.bspline", flags="e", _input=contour_points, raster_output=purged_elevation, layer="2", column="along", method=fill_method, ) spline_step = round(float(mean_dist.keys()[0].split(" ")[-1])) * 2 gscript.info( _("Interpolating purged surface using a spline step value" " of {s}".format(s=spline_step))) gscript.run_command( "v.surf.bspline", _input=contour_points, raster_output=purged_elevation, layer="2", column="along", method=fill_method, overwrite=gcore.overwrite(), ) else: gscript.run_command( "v.to.rast", input=vector_contours, output=raster_contours, type="line", use="val", value=1, overwrite=gcore.overwrite(), ) gscript.mapcalc("{c} = {a} * {b}".format( c=raster_contours_with_values, a=raster_contours, b=elevation_input, overwrite=gcore.overwrite(), )) gscript.info( _("Interpolating elevation between" " difference zero contours...")) gscript.run_command( "r.fillnulls", input=raster_contours_with_values, output=purged_elevation, method=fill_method, overwrite=gcore.overwrite(), ) # step 6 gscript.info(_("Subtracting purged from original elevation...")) gscript.mapcalc("{c} = {a} - {b}".format( c=local_relief_output, a=elevation_input, b=purged_elevation, overwrite=gcore.overwrite(), )) gscript.raster_history(local_relief_output) # set color tables if save_intermediates: # same color table as input gscript.run_command("r.colors", map=smooth_elevation, raster=elevation_input, quiet=True) gscript.run_command("r.colors", map=purged_elevation, raster=elevation_input, quiet=True) # has only one color if not bspline: gscript.run_command( "r.colors", map=raster_contours_with_values, raster=elevation_input, quiet=True, ) # same color table as output gscript.run_command("r.colors", map=subtracted_smooth_elevation, color=color_table, quiet=True) if shaded_local_relief_output: if not user_color_table: color_table = "difference" gscript.run_command( "r.colors", flags=rcolors_flags, map=local_relief_output, color=color_table, quiet=True, ) # r.relief could run in parallel to the main computation, # but it is probably fast in comparison to the rest. # In theory, r.skyview and first component from r.shaded.pca # can be added as well, but let's leave this to the user. gscript.run_command("r.relief", input=elevation_input, output=relief_shade) gscript.run_command( "r.shade", shade=relief_shade, color=local_relief_output, output=shaded_local_relief_output, ) if not user_color_table: color_table = "grey" gscript.run_command( "r.colors", flags=rcolors_flags, map=local_relief_output, color=color_table, quiet=True, ) gscript.raster_history(shaded_local_relief_output) else: if not user_color_table: color_table = "grey" gscript.run_command( "r.colors", flags=rcolors_flags, map=local_relief_output, color=color_table, quiet=True, )
def main(): red = options["red"] green = options["green"] blue = options["blue"] brightness = options["strength"] full = flags["f"] preserve = flags["p"] reset = flags["r"] global do_mp if flags["s"]: do_mp = False check = True for m in [red, green, blue]: ex = gscript.find_file(m) if ex["name"] == "": check = False gscript.warning("Raster map <{}> not found ".format(m)) if not check: gscript.fatal("At least one of the input raster map was not found") # 90 or 98? MAX value controls brightness # think of percent (0-100), must be positive or 0 # must be more than "2" ? if full: for i in [red, green, blue]: gscript.run_command("r.colors", map=i, color="grey", quiet=True) sys.exit(0) if reset: for i in [red, green, blue]: gscript.run_command("r.colors", map=i, color="grey255", quiet=True) sys.exit(0) if not preserve: if do_mp: gscript.message(_("Processing...")) # set up jobs and launch them proc = {} conn = {} for i in [red, green, blue]: conn[i] = mp.Pipe() proc[i] = mp.Process( target=get_percentile_mp, args=( i, ["2", brightness], conn[i], ), ) proc[i].start() gscript.percent(1, 2, 1) # collect results and wait for jobs to finish for i in [red, green, blue]: output_pipe, input_pipe = conn[i] (v0, v1) = input_pipe.recv() gscript.debug("parent (%s) (%.1f, %.1f)" % (i, v0, v1)) input_pipe.close() proc[i].join() set_colors(i, v0, v1) gscript.percent(1, 1, 1) else: for i in [red, green, blue]: gscript.message(_("Processing...")) (v0, v1) = get_percentile(i, ["2", brightness]) gscript.debug("<%s>: min=%f max=%f" % (i, v0, v1)) set_colors(i, v0, v1) else: all_max = 0 all_min = 999999 if do_mp: gscript.message(_("Processing...")) # set up jobs and launch jobs proc = {} conn = {} for i in [red, green, blue]: conn[i] = mp.Pipe() proc[i] = mp.Process( target=get_percentile_mp, args=( i, ["2", brightness], conn[i], ), ) proc[i].start() gscript.percent(1, 2, 1) # collect results and wait for jobs to finish for i in [red, green, blue]: output_pipe, input_pipe = conn[i] (v0, v1) = input_pipe.recv() gscript.debug("parent (%s) (%.1f, %.1f)" % (i, v0, v1)) input_pipe.close() proc[i].join() all_min = min(all_min, v0) all_max = max(all_max, v1) gscript.percent(1, 1, 1) else: for i in [red, green, blue]: gscript.message(_("Processing...")) (v0, v1) = get_percentile(i, ["2", brightness]) gscript.debug("<%s>: min=%f max=%f" % (i, v0, v1)) all_min = min(all_min, v0) all_max = max(all_max, v1) gscript.debug("all_min=%f all_max=%f" % (all_min, all_max)) for i in [red, green, blue]: set_colors(i, all_min, all_max) # write cmd history: mapset = gscript.gisenv()["MAPSET"] for i in [red, green, blue]: if gscript.find_file(i)["mapset"] == mapset: gscript.raster_history(i)
def main(): input = options['input'] output = options['output'] altitude = options['altitude'] azimuth = options['azimuth'] zmult = options['zmult'] scale = float(options['scale']) units = options['units'] verbose_level = os.getenv('GRASS_VERBOSE') if verbose_level is None: verbose_level = 2 if not grass.find_file(input)['file']: grass.fatal(_("Raster map <%s> not found") % input) if input == output: grass.fatal(_("Input elevation map and output relief map must have different names")) # LatLong locations only: if units == 'meters': # scale=111120 scale *= 1852 * 60 # LatLong locations only: if units == 'feet': # scale=364567.2 scale *= 6076.12 * 60 #correct azimuth to East (GRASS convention): # this seems to be backwards, but in fact it works so leave it. az = float(azimuth) - 90 t = string.Template( r'''eval( \ x=($zmult*$input[-1,-1] + 2*$zmult*$input[0,-1] + $zmult*$input[1,-1] - \ $zmult*$input[-1,1] - 2*$zmult*$input[0,1] - $zmult*$input[1,1])/(8.*ewres()*$scale), \ y=($zmult*$input[-1,-1] + 2*$zmult*$input[-1,0] + $zmult*$input[-1,1] - \ $zmult*$input[1,-1] - 2*$zmult*$input[1,0] - $zmult*$input[1,1])/(8.*nsres()*$scale), \ slope=90.-atan(sqrt(x*x + y*y)), \ a=round(atan(x,y)), \ a=if(isnull(a),1,a), \ aspect=if(x!=0||y!=0,if(a,a,360.)), \ cang = sin($altitude)*sin(slope) + cos($altitude)*cos(slope) * cos($az-aspect) \ ) $output = if(isnull(cang), null(), 100.*cang)''') expr = t.substitute(altitude = altitude, az = az, input = input, output = output, scale = scale, zmult = zmult) p = grass.feed_command('r.mapcalc') p.stdin.write(expr) p.stdin.close() if p.wait() != 0: grass.fatal(_("In calculation, script aborted.")) if verbose_level < 3: grass.run_command('r.colors', map = output, color = 'grey', quiet = True) else: grass.run_command('r.colors', map = output, color = 'grey') # record metadata grass.run_command('r.support', map = output, title = 'Shaded relief of "%s"' % input, history = '') grass.run_command('r.support', map = output, history = "r.shaded.relief settings:") t = string.Template("altitude=$altitude azimuth=$azimuth zmult=$zmult scale=$scale") parms = dict(altitude = altitude, azimuth = azimuth, zmult = zmult, scale = options['scale']) grass.run_command('r.support', map = output, history = t.substitute(parms)) if units: grass.run_command('r.support', map = output, history = " units=%s (adjusted scale=%s)" % (units, scale)) # write cmd history: grass.raster_history(output)
def main(options, flags): # options and flags into variables ipl = options['input'] raster_exists(ipl) opl = options['output'] # size option backwards compatibility with window if not options['size'] and not options['window']: gs.fatal(_("Required parameter <%s> not set") % 'size') if options['size']: wz = int(options['size']) if options['window']: gs.warning(_("The window option is deprecated, use the option" " size instead")) wz = int(options['window']) if options['size'] and options['size'] != '3' and options['window']: gs.warning(_("When the obsolete window option is used, the" " new size option is ignored")) if wz % 2 == 0: gs.fatal(_("Please provide an odd number for the moving" " window size, not %d") % wz) # user wants pf or pff user_pf = options['pf'] user_pff = options['pff'] # backwards compatibility if flags['t']: gs.warning(_("The -t flag is deprecated, use pf and pff options" " instead")) if not user_pf and not user_pff and flags['t']: user_pf = opl + '_pf' user_pff = opl + '_pff' elif flags['t']: gs.warning(_("When pf or pff option is used, the -t flag" " is ignored")) flag_r = flags['r'] flag_s = flags['s'] clip_output = flags['a'] # set to current input map region if requested by the user # default is (and should be) the current region # we could use tmp region for this but if the flag is there # it makes sense to use it from now on (but we should reconsider) if flag_r: gs.message(_("Setting region to input map...")) gs.run_command('g.region', raster=ipl, quiet=True) # check if map values are limited to 1 and 0 input_info = gs.raster_info(ipl) # we know what we are doing only when input is integer if input_info['datatype'] != 'CELL': gs.fatal(_("The input raster map must have type CELL" " (integer)")) # for integer, we just need to text min and max if input_info['min'] != 0 or input_info['max'] != 1: gs.fatal(_("The input raster map must be a binary raster," " i.e. it should contain only values 0 and 1" " (now the minimum is %d and maximum is %d)") % (input_info['min'], input_info['max'])) # computing pf values # let forested pixels be x and number of all pixels in moving window # be y, then pf=x/y" gs.info(_("Step 1: Computing Pf values...")) # generate grid with pixel-value=number of forest-pixels in window # generate grid with pixel-value=number of pixels in moving window: tmpA2 = tmpname('tmpA01_') tmpC3 = tmpname('tmpA02_') gs.run_command("r.neighbors", quiet=True, input=ipl, output=[tmpA2, tmpC3], method=["sum", "count"], size=wz) # create pf map if user_pf: pf = user_pf else: pf = tmpname('tmpA03_') mapcalc("$pf = if( $ipl >=0, float($tmpA2) / float($tmpC3))", ipl=ipl, pf=pf, tmpA2=tmpA2, tmpC3=tmpC3) # computing pff values # Considering pairs of pixels in cardinal directions in # a 3x3 window, the total number of adjacent pixel pairs is 12. # Assuming that x pairs include at least one forested pixel, and # y of those pairs are forest-forest pairs, so pff equals y/x. gs.info(_("Step 2: Computing Pff values...")) # create copy of forest map and convert NULL to 0 (if any) tmpC4 = tmpname('tmpA04_') gs.run_command("g.copy", raster=[ipl, tmpC4], quiet=True) gs.run_command("r.null", map=tmpC4, null=0, quiet=True) # window dimensions max_index = int((wz - 1) / 2) # number of 'forest-forest' pairs expr1 = pairs_expression(map_name=tmpC4, max_index=max_index, combine_op='&') # number of 'nonforest-forest' pairs expr2 = pairs_expression(map_name=tmpC4, max_index=max_index, combine_op='|') # create pff map if user_pff: pff = user_pff else: pff = tmpname('tmpA07_') # potentially this can be split and parallelized mapcalc("$pff = if($ipl >= 0, float($tmpl4) / float($tmpl5))", ipl=ipl, tmpl4=expr1, tmpl5=expr2, pff=pff) # computing fragmentation index # (a b) name, condition # where a is a number used by Riitters et al. in ERRATUM (2) # and b is a number used in the sh script by Sambale and Sylla # b also defines 0 for non-forested which is consistent with input # (1 3) edge, if Pf > 0.6 and Pf - Pff < 0 # (2 6) undetermined, if Pf > 0.6 and Pf = Pff # (3 4) perforated, if Pf > 0.6 and Pf - Pff > 0 # (4 5) interior, if Pf = 1.0 # (5 1) patch, if Pf < 0.4 # (6 2) transitional, if 0.4 < Pf < 0.6 gs.info(_("Step 3: Computing fragmentation index...")) if clip_output: indexfin2 = tmpname('tmpA16_') else: indexfin2 = opl mapcalc( "eval(" "dpf = $pf - $pff," # individual classes "patch = if($pf < 0.4, 1, 0)," "transitional = if($pf >= 0.4 && $pf < 0.6, 2, 0)," "edge = if($pf >= 0.6 && dpf<0,3,0)," "perforated = if($pf > 0.6 && $pf < 1 && dpf > 0, 4, 0)," "interior = if($pf == 1, 5, 0)," "undetermined = if($pf > 0.6 && $pf < 1 && dpf == 0, 6, 0)," # null is considered as non-forest and we need to do it before + "patch = if(isnull(patch), 0, patch)," "transitional = if(isnull(transitional), 0, transitional)," "edge = if(isnull(edge), 0, edge)," "perforated = if(isnull(perforated), 0, perforated)," "interior = if(isnull(interior), 0, interior)," "undetermined = if(isnull(undetermined), 0, undetermined)," # combine classes (they don't overlap) # more readable than nested ifs from the ifs above "all = patch + transitional + edge + perforated + interior" " + undetermined" ")\n" # mask result by non-forest (according to the input) # removes the nonsense data created in the non-forested areas "$out = all * $binary_forest", out=indexfin2, binary_forest=ipl, pf=pf, pff=pff) # shrink the region if clip_output: gs.use_temp_region() reginfo = gs.parse_command("g.region", flags="gp") nscor = max_index * float(reginfo['nsres']) ewcor = max_index * float(reginfo['ewres']) gs.run_command("g.region", n=float(reginfo['n']) - nscor, s=float(reginfo['s']) + nscor, e=float(reginfo['e']) - ewcor, w=float(reginfo['w']) + ewcor, quiet=True) mapcalc("$opl = $if3", opl=opl, if3=indexfin2, quiet=True) # create categories # TODO: parametrize classes (also in r.mapcalc, r.colors and desc)? # TODO: translatable labels? labels = LABELS gs.write_command("r.category", quiet=True, map=opl, rules='-', stdin=labels, separator='space') # create color table colors = COLORS_SAMBALE gs.write_command("r.colors", map=opl, rules='-', stdin=colors, quiet=True) # write metadata for main layer gs.run_command("r.support", map=opl, title="Forest fragmentation", source1="Based on %s" % ipl, description="Forest fragmentation index (6 classes)") gs.raster_history(opl) # write metadata for intermediate layers if user_pf: # pf layer gs.run_command("r.support", map=pf, title="Proportion forested", units="Proportion", source1="Based on %s" % ipl, description="Proportion of pixels in the moving" " window that is forested") gs.raster_history(pf) if user_pff: # pff layer unused, tmphist = tempfile.mkstemp() text_file = open(tmphist, "w") long_description = """\ Proportion of all adjacent (cardinal directions only) pixel pairs that include at least one forest pixel for which both pixels are forested. It thus (roughly) estimates the conditional probability that, given a pixel of forest, its neighbor is also forest. """ text_file.write(long_description) text_file.close() gs.run_command("r.support", map=pff, title="Conditional probability neighboring cell" " is forest", units="Proportion", source1="Based on %s" % ipl, description="Probability neighbor of forest cell" " is forest", loadhistory=tmphist) gs.raster_history(pff) os.remove(tmphist) # report fragmentation index and names of layers created if flag_s: gs.run_command("r.report", map=opl, units=["h", "p"], flags="n", page_width=50, quiet=True) gs.info(_("The following layers were created")) gs.info(_("The fragmentation index: %s") % opl) if user_pf: gs.info(_("The proportion forested (Pf): %s") % pf) if user_pff: gs.info(_("The proportion forested pixel pairs (Pff): %s") % pff)
def main(): global usermask, mapset, tmp_rmaps, tmp_vmaps input = options['input'] output = options['output'] tension = options['tension'] smooth = options['smooth'] method = options['method'] edge = int(options['edge']) segmax = int(options['segmax']) npmin = int(options['npmin']) quiet = True # FIXME mapset = grass.gisenv()['MAPSET'] unique = str(os.getpid()) # Shouldn't we use temp name? prefix = 'r_fillnulls_%s_' % unique failed_list = list() # a list of failed holes. Caused by issues with v.surf.rst. Connected with #1813 #check if input file exists if not grass.find_file(input)['file']: grass.fatal(_("Raster map <%s> not found") % input) # save original region reg_org = grass.region() # check if a MASK is already present # and remove it to not interfere with NULL lookup part # as we don't fill MASKed parts! if grass.find_file('MASK', mapset = mapset)['file']: usermask = "usermask_mask." + unique grass.message(_("A user raster mask (MASK) is present. Saving it...")) grass.run_command('g.rename', quiet = quiet, rast = ('MASK',usermask)) #check if method is rst to use v.surf.rst if method == 'rst': # idea: filter all NULLS and grow that area(s) by 3 pixel, then # interpolate from these surrounding 3 pixel edge filling = prefix + 'filled' grass.use_temp_region() grass.run_command('g.region', align = input, quiet = quiet) region = grass.region() ns_res = region['nsres'] ew_res = region['ewres'] grass.message(_("Using RST interpolation...")) grass.message(_("Locating and isolating NULL areas...")) # creating binary (0/1) map if usermask: grass.message(_("Skipping masked raster parts")) grass.mapcalc("$tmp1 = if(isnull($input) && !($mask == 0 || isnull($mask)),1,null())", tmp1 = prefix + 'nulls', input = input, mask = usermask) else: grass.mapcalc("$tmp1 = if(isnull($input),1,null())", tmp1 = prefix + 'nulls', input = input) tmp_rmaps.append(prefix + 'nulls') # restoring user's mask, if present # to ignore MASKed original values if usermask: grass.message(_("Restoring user mask (MASK)...")) if grass.run_command('g.rename', quiet = quiet, rast = (usermask, 'MASK')) != 0: grass.warning(_("Failed to restore user MASK!")) usermask = None # grow identified holes by X pixels grass.message(_("Growing NULL areas")) tmp_rmaps.append(prefix + 'grown') if grass.run_command('r.grow', input = prefix + 'nulls', radius = edge + 0.01, old = 1, new = 1, out = prefix + 'grown', quiet = quiet) != 0: grass.fatal(_("abandoned. Removing temporary map, restoring user mask if needed:")) # assign unique IDs to each hole or hole system (holes closer than edge distance) grass.message(_("Assigning IDs to NULL areas")) tmp_rmaps.append(prefix + 'clumped') if grass.run_command('r.clump', input = prefix + 'grown', output = prefix + 'clumped', quiet = quiet) != 0: grass.fatal(_("abandoned. Removing temporary map, restoring user mask if needed:")) # get a list of unique hole cat's grass.mapcalc("$out = if(isnull($inp), null(), $clumped)", out = prefix + 'holes', inp = prefix + 'nulls', clumped = prefix + 'clumped') tmp_rmaps.append(prefix + 'holes') # use new IDs to identify holes if grass.run_command('r.to.vect', flags = 'v', input = prefix + 'holes', output = prefix + 'holes', type = 'area', quiet = quiet) != 0: grass.fatal(_("abandoned. Removing temporary maps, restoring user mask if needed:")) tmp_vmaps.append(prefix + 'holes') # get a list of unique hole cat's cats_file_name = grass.tempfile(False) grass.run_command('v.db.select', flags = 'c', map = prefix + 'holes', columns = 'cat', file = cats_file_name, quiet = quiet) cat_list = list() cats_file = file(cats_file_name) for line in cats_file: cat_list.append(line.rstrip('\n')) cats_file.close() os.remove(cats_file_name) if len(cat_list) < 1: grass.fatal(_("Input map has no holes. Check region settings.")) # GTC Hole is NULL area in a raster map grass.message(_("Processing %d map holes") % len(cat_list)) first = True hole_n = 1 for cat in cat_list: holename = prefix + 'hole_' + cat # GTC Hole is a NULL area in a raster map grass.message(_("Filling hole %s of %s") % (hole_n, len(cat_list))) hole_n = hole_n + 1 # cut out only CAT hole for processing if grass.run_command('v.extract', input = prefix + 'holes', output = holename + '_pol', cats = cat, quiet = quiet) != 0: grass.fatal(_("abandoned. Removing temporary maps, restoring user mask if needed:")) tmp_vmaps.append(holename + '_pol') # zoom to specific hole with a buffer of two cells around the hole to remove rest of data if grass.run_command('g.region', vect = holename + '_pol', align = input, w = 'w-%d' % (edge * 2 * ew_res), e = 'e+%d' % (edge * 2 * ew_res), n = 'n+%d' % (edge * 2 * ns_res), s = 's-%d' % (edge * 2 * ns_res), quiet = quiet) != 0: grass.fatal(_("abandoned. Removing temporary maps, restoring user mask if needed:")) # remove temporary map to not overfill disk if grass.run_command('g.remove', flags = 'fb', type = 'vect', pattern = holename + '_pol', quiet = quiet) != 0: grass.fatal(_("abandoned. Removing temporary maps, restoring user mask if needed:")) tmp_vmaps.remove(holename + '_pol') # copy only data around hole grass.mapcalc("$out = if($inp == $catn, $inp, null())", out = holename, inp = prefix + 'holes', catn = cat) tmp_rmaps.append(holename) # If here loop is split into two, next part of loop can be run in parallel # (except final result patching) # Downside - on large maps such approach causes large disk usage # grow hole border to get it's edge area tmp_rmaps.append(holename + '_grown') if grass.run_command('r.grow', input = holename, radius = edge + 0.01, old = -1, out = holename + '_grown', quiet = quiet) != 0: grass.fatal(_("abandoned. Removing temporary map, restoring user mask if needed:")) # no idea why r.grow old=-1 doesn't replace existing values with NULL grass.mapcalc("$out = if($inp == -1, null(), $dem)", out = holename + '_edges', inp = holename + '_grown', dem = input) tmp_rmaps.append(holename + '_edges') # convert to points for interpolation tmp_vmaps.append(holename) if grass.run_command('r.to.vect', input = holename + '_edges', output = holename, type = 'point', flags = 'z', quiet = quiet) != 0: grass.fatal(_("abandoned. Removing temporary maps, restoring user mask if needed:")) # count number of points to control segmax parameter for interpolation: pointsnumber = grass.vector_info_topo(map = holename)['points'] grass.verbose(_("Interpolating %d points") % pointsnumber) if pointsnumber < 2: grass.verbose(_("No points to interpolate")) failed_list.append(holename) continue # Avoid v.surf.rst warnings if pointsnumber < segmax: npmin = pointsnumber + 1 segmax = pointsnumber # launch v.surf.rst tmp_rmaps.append(holename + '_dem') if grass.run_command('v.surf.rst', quiet = quiet, input = holename, elev = holename + '_dem', tension = tension, smooth = smooth, segmax = segmax, npmin = npmin) != 0: # GTC Hole is NULL area in a raster map grass.fatal(_("Failed to fill hole %s") % cat) # v.surf.rst sometimes fails with exit code 0 # related bug #1813 if not grass.find_file(holename + '_dem')['file']: try: tmp_rmaps.remove(holename) tmp_rmaps.remove(holename + '_grown') tmp_rmaps.remove(holename + '_edges') tmp_rmaps.remove(holename + '_dem') tmp_vmaps.remove(holename) except: pass grass.warning(_("Filling has failed silently. Leaving temporary maps with prefix <%s> for debugging.") % holename) failed_list.append(holename) continue # append hole result to interpolated version later used to patch into original DEM if first: tmp_rmaps.append(filling) grass.run_command('g.region', align = input, rast = holename + '_dem', quiet = quiet) grass.mapcalc("$out = if(isnull($inp), null(), $dem)", out = filling, inp = holename, dem = holename + '_dem') first = False else: tmp_rmaps.append(filling + '_tmp') grass.run_command('g.region', align = input, rast = (filling, holename + '_dem'), quiet = quiet) grass.mapcalc("$out = if(isnull($inp), if(isnull($fill), null(), $fill), $dem)", out = filling + '_tmp', inp = holename, dem = holename + '_dem', fill = filling) if grass.run_command('g.rename', rast = (filling + '_tmp', filling), overwrite = True, quiet = quiet) != 0: grass.fatal(_("abandoned. Removing temporary maps, restoring user mask if needed:")) tmp_rmaps.remove(filling + '_tmp') # this map has been removed. No need for later cleanup. # remove temporary maps to not overfill disk try: tmp_rmaps.remove(holename) tmp_rmaps.remove(holename + '_grown') tmp_rmaps.remove(holename + '_edges') tmp_rmaps.remove(holename + '_dem') except: pass if grass.run_command('g.remove', quiet = quiet, flags = 'fb', type = 'rast', pattern = (holename, holename + '_grown', holename + '_edges', holename + '_dem')) != 0: grass.fatal(_("abandoned. Removing temporary maps, restoring user mask if needed:")) try: tmp_vmaps.remove(holename) except: pass if grass.run_command('g.remove', quiet = quiet, flags = 'fb', type = 'vect', pattern = holename) != 0: grass.fatal(_("abandoned. Removing temporary maps, restoring user mask if needed:")) #check if method is different from rst to use r.resamp.bspline if method != 'rst': grass.message(_("Using %s bspline interpolation") % method) # clone current region grass.use_temp_region() grass.run_command('g.region', align = input) reg = grass.region() # launch r.resamp.bspline tmp_rmaps.append(prefix + 'filled') if usermask: grass.run_command('r.resamp.bspline', input = input, mask = usermask, output = prefix + 'filled', method = method, ew_step = 3 * reg['ewres'], ns_step = 3 * reg['nsres'], _lambda = 0.01, flags = 'n') else: grass.run_command('r.resamp.bspline', input = input, output = prefix + 'filled', method = method, ew_step = 3 * reg['ewres'], ns_step = 3 * reg['nsres'], _lambda = 0.01, flags = 'n') # restoring user's mask, if present: if usermask: grass.message(_("Restoring user mask (MASK)...")) if grass.run_command('g.rename', quiet = quiet, rast = (usermask, 'MASK')) != 0: grass.warning(_("Failed to restore user MASK!")) usermask = None # set region to original extents, align to input grass.run_command('g.region', n = reg_org['n'], s = reg_org['s'], e = reg_org['e'], w = reg_org['w'], align = input) # patch orig and fill map grass.message(_("Patching fill data into NULL areas...")) # we can use --o here as g.parser already checks on startup grass.run_command('r.patch', input = (input,prefix + 'filled'), output = output, overwrite = True) # restore the real region grass.del_temp_region() grass.message(_("Filled raster map is: %s") % output) # write cmd history: grass.raster_history(output) if len(failed_list) > 0: grass.warning(_("Following holes where not filled. Temporary maps with are left in place to allow examination of unfilled holes")) outlist = failed_list[0] for hole in failed_list[1:]: outlist = ', ' + outlist grass.message(outlist) grass.message(_("Done."))
def main(): if not hasNumPy: grass.fatal(_("Required dependency NumPy not found. Exiting.")) sharpen = options['method'] # sharpening algorithm ms1_orig = options['blue'] # blue channel ms2_orig = options['green'] # green channel ms3_orig = options['red'] # red channel pan_orig = options['pan'] # high res pan channel out = options['output'] # prefix for output RGB maps bits = options['bitdepth'] # bit depth of image channels bladjust = flags['l'] # adjust blue channel sproc = flags['s'] # serial processing rescale = flags[ 'r'] # rescale to spread pixel values to entire 0-255 range # Checking bit depth bits = float(bits) if bits < 2 or bits > 30: grass.warning(_("Bit depth is outside acceptable range")) return outb = grass.core.find_file('%s_blue' % out) outg = grass.core.find_file('%s_green' % out) outr = grass.core.find_file('%s_red' % out) if (outb['name'] != '' or outg['name'] != '' or outr['name'] != '') and not grass.overwrite(): grass.warning( _('Maps with selected output prefix names already exist.' ' Delete them or use overwrite flag')) return pid = str(os.getpid()) # convert input image channels to 8 bit for processing ms1 = 'tmp%s_ms1' % pid ms2 = 'tmp%s_ms2' % pid ms3 = 'tmp%s_ms3' % pid pan = 'tmp%s_pan' % pid if rescale == False: if bits == 8: grass.message(_("Using 8bit image channels")) if sproc: # serial processing grass.run_command('g.copy', raster='%s,%s' % (ms1_orig, ms1), quiet=True, overwrite=True) grass.run_command('g.copy', raster='%s,%s' % (ms2_orig, ms2), quiet=True, overwrite=True) grass.run_command('g.copy', raster='%s,%s' % (ms3_orig, ms3), quiet=True, overwrite=True) grass.run_command('g.copy', raster='%s,%s' % (pan_orig, pan), quiet=True, overwrite=True) else: # parallel processing pb = grass.start_command('g.copy', raster='%s,%s' % (ms1_orig, ms1), quiet=True, overwrite=True) pg = grass.start_command('g.copy', raster='%s,%s' % (ms2_orig, ms2), quiet=True, overwrite=True) pr = grass.start_command('g.copy', raster='%s,%s' % (ms3_orig, ms3), quiet=True, overwrite=True) pp = grass.start_command('g.copy', raster='%s,%s' % (pan_orig, pan), quiet=True, overwrite=True) pb.wait() pg.wait() pr.wait() pp.wait() else: grass.message(_("Converting image chanels to 8bit for processing")) maxval = pow(2, bits) - 1 if sproc: # serial processing grass.run_command('r.rescale', input=ms1_orig, from_='0,%f' % maxval, output=ms1, to='0,255', quiet=True, overwrite=True) grass.run_command('r.rescale', input=ms2_orig, from_='0,%f' % maxval, output=ms2, to='0,255', quiet=True, overwrite=True) grass.run_command('r.rescale', input=ms3_orig, from_='0,%f' % maxval, output=ms3, to='0,255', quiet=True, overwrite=True) grass.run_command('r.rescale', input=pan_orig, from_='0,%f' % maxval, output=pan, to='0,255', quiet=True, overwrite=True) else: # parallel processing pb = grass.start_command('r.rescale', input=ms1_orig, from_='0,%f' % maxval, output=ms1, to='0,255', quiet=True, overwrite=True) pg = grass.start_command('r.rescale', input=ms2_orig, from_='0,%f' % maxval, output=ms2, to='0,255', quiet=True, overwrite=True) pr = grass.start_command('r.rescale', input=ms3_orig, from_='0,%f' % maxval, output=ms3, to='0,255', quiet=True, overwrite=True) pp = grass.start_command('r.rescale', input=pan_orig, from_='0,%f' % maxval, output=pan, to='0,255', quiet=True, overwrite=True) pb.wait() pg.wait() pr.wait() pp.wait() else: grass.message(_("Rescaling image chanels to 8bit for processing")) min_ms1 = int(grass.raster_info(ms1_orig)['min']) max_ms1 = int(grass.raster_info(ms1_orig)['max']) min_ms2 = int(grass.raster_info(ms2_orig)['min']) max_ms2 = int(grass.raster_info(ms2_orig)['max']) min_ms3 = int(grass.raster_info(ms3_orig)['min']) max_ms3 = int(grass.raster_info(ms3_orig)['max']) min_pan = int(grass.raster_info(pan_orig)['min']) max_pan = int(grass.raster_info(pan_orig)['max']) maxval = pow(2, bits) - 1 if sproc: # serial processing grass.run_command('r.rescale', input=ms1_orig, from_='%f,%f' % (min_ms1, max_ms1), output=ms1, to='0,255', quiet=True, overwrite=True) grass.run_command('r.rescale', input=ms2_orig, from_='%f,%f' % (min_ms2, max_ms2), output=ms2, to='0,255', quiet=True, overwrite=True) grass.run_command('r.rescale', input=ms3_orig, from_='%f,%f' % (min_ms3, max_ms3), output=ms3, to='0,255', quiet=True, overwrite=True) grass.run_command('r.rescale', input=pan_orig, from_='%f,%f' % (min_pan, max_pan), output=pan, to='0,255', quiet=True, overwrite=True) else: # parallel processing pb = grass.start_command('r.rescale', input=ms1_orig, from_='%f,%f' % (min_ms1, max_ms1), output=ms1, to='0,255', quiet=True, overwrite=True) pg = grass.start_command('r.rescale', input=ms2_orig, from_='%f,%f' % (min_ms2, max_ms2), output=ms2, to='0,255', quiet=True, overwrite=True) pr = grass.start_command('r.rescale', input=ms3_orig, from_='%f,%f' % (min_ms3, max_ms3), output=ms3, to='0,255', quiet=True, overwrite=True) pp = grass.start_command('r.rescale', input=pan_orig, from_='%f,%f' % (min_pan, max_pan), output=pan, to='0,255', quiet=True, overwrite=True) pb.wait() pg.wait() pr.wait() pp.wait() # get PAN resolution: kv = grass.raster_info(map=pan) nsres = kv['nsres'] ewres = kv['ewres'] panres = (nsres + ewres) / 2 # clone current region grass.use_temp_region() grass.run_command('g.region', res=panres, align=pan) # Select sharpening method grass.message( _("Performing pan sharpening with hi res pan image: %f" % panres)) if sharpen == "brovey": brovey(pan, ms1, ms2, ms3, out, pid, sproc) elif sharpen == "ihs": ihs(pan, ms1, ms2, ms3, out, pid, sproc) elif sharpen == "pca": pca(pan, ms1, ms2, ms3, out, pid, sproc) # Could add other sharpening algorithms here, e.g. wavelet transformation grass.message( _("Assigning grey equalized color tables to output images...")) # equalized grey scales give best contrast grass.message(_("setting pan-sharpened channels to equalized grey scale")) for ch in ['red', 'green', 'blue']: grass.run_command('r.colors', quiet=True, map="%s_%s" % (out, ch), flags="e", color='grey') # Landsat too blue-ish because panchromatic band less sensitive to blue # light, so output blue channed can be modified if bladjust: grass.message(_("Adjusting blue channel color table...")) blue_colors = ['0 0 0 0\n5% 0 0 0\n67% 255 255 255\n100% 255 255 255'] # these previous colors are way too blue for landsat # blue_colors = ['0 0 0 0\n10% 0 0 0\n20% 200 200 200\n40% 230 230 230\n67% 255 255 255\n100% 255 255 255'] bc = grass.feed_command('r.colors', quiet=True, map="%s_blue" % out, rules="-") bc.stdin.write('\n'.join(blue_colors)) bc.stdin.close() # output notice grass.verbose( _("The following pan-sharpened output maps have been generated:")) for ch in ['red', 'green', 'blue']: grass.verbose(_("%s_%s") % (out, ch)) grass.verbose( _("To visualize output, run: g.region -p raster=%s_red" % out)) grass.verbose(_("d.rgb r=%s_red g=%s_green b=%s_blue" % (out, out, out))) grass.verbose( _("If desired, combine channels into a single RGB map with 'r.composite'." )) grass.verbose( _("Channel colors can be rebalanced using i.colors.enhance.")) # write cmd history: for ch in ['red', 'green', 'blue']: grass.raster_history("%s_%s" % (out, ch)) # create a group with the three outputs #grass.run_command('i.group', group=out, # input="{n}_red,{n}_blue,{n}_green".format(n=out)) # Cleanup grass.message(_("cleaning up temp files")) try: grass.run_command('g.remove', flags="f", type="raster", pattern="tmp%s*" % pid, quiet=True) except: ""
def main(): global vrtfile, tmpfile infile = options['input'] rast = options['output'] also = flags['a'] #### check for gdalinfo (just to check if installation is complete) if not grass.find_program('gdalinfo', '--help'): grass.fatal(_("'gdalinfo' not found, install GDAL tools first (http://www.gdal.org)")) pid = str(os.getpid()) tmpfile = grass.tempfile() ################### let's go spotdir = os.path.dirname(infile) spotname = grass.basename(infile, 'hdf') if rast: name = rast else: name = spotname if not grass.overwrite() and grass.find_file(name)['file']: grass.fatal(_("<%s> already exists. Aborting.") % name) # still a ZIP file? (is this portable?? see the r.in.srtm script for ideas) if infile.lower().endswith('.zip'): grass.fatal(_("Please extract %s before import.") % infile) try: p = grass.Popen(['file', '-ib', infile], stdout = grass.PIPE) s = p.communicate()[0] if s == "application/x-zip": grass.fatal(_("Please extract %s before import.") % infile) except: pass ### create VRT header for NDVI projfile = os.path.join(spotdir, "0001_LOG.TXT") vrtfile = tmpfile + '.vrt' # first process the NDVI: grass.try_remove(vrtfile) create_VRT_file(projfile, vrtfile, infile) ## let's import the NDVI map... grass.message(_("Importing SPOT VGT NDVI map...")) try: grass.run_command('r.in.gdal', input=vrtfile, output=name) except CalledModuleError: grass.fatal(_("An error occurred. Stop.")) grass.message(_("Imported SPOT VEGETATION NDVI map <%s>.") % name) ################# ## http://www.vgt.vito.be/faq/FAQS/faq19.html # What is the relation between the digital number and the real NDVI ? # Real NDVI =coefficient a * Digital Number + coefficient b # = a * DN +b # # Coefficient a = 0.004 # Coefficient b = -0.1 # clone current region # switch to a temporary region grass.use_temp_region() grass.run_command('g.region', raster = name, quiet = True) grass.message(_("Remapping digital numbers to NDVI...")) tmpname = "%s_%s" % (name, pid) grass.mapcalc("$tmpname = 0.004 * $name - 0.1", tmpname = tmpname, name = name) grass.run_command('g.remove', type = 'raster', name = name, quiet = True, flags = 'f') grass.run_command('g.rename', raster = (tmpname, name), quiet = True) # write cmd history: grass.raster_history(name) #apply color table: grass.run_command('r.colors', map = name, color = 'ndvi', quiet = True) ########################## # second, optionally process the SM quality map: #SM Status Map # http://nieuw.vgt.vito.be/faq/FAQS/faq22.html #Data about # Bit NR 7: Radiometric quality for B0 coded as 0 if bad and 1 if good # Bit NR 6: Radiometric quality for B2 coded as 0 if bad and 1 if good # Bit NR 5: Radiometric quality for B3 coded as 0 if bad and 1 if good # Bit NR 4: Radiometric quality for MIR coded as 0 if bad and 1 if good # Bit NR 3: land code 1 or water code 0 # Bit NR 2: ice/snow code 1 , code 0 if there is no ice/snow # Bit NR 1: 0 0 1 1 # Bit NR 0: 0 1 0 1 # clear shadow uncertain cloud # #Note: # pos 7 6 5 4 3 2 1 0 (bit position) # 128 64 32 16 8 4 2 1 (values for 8 bit) # # # Bit 4-7 should be 1: their sum is 240 # Bit 3 land code, should be 1, sum up to 248 along with higher bits # Bit 2 ice/snow code # Bit 0-1 should be 0 # # A good map threshold: >= 248 if also: grass.message(_("Importing SPOT VGT NDVI quality map...")) grass.try_remove(vrtfile) qname = spotname.replace('NDV','SM') qfile = os.path.join(spotdir, qname) create_VRT_file(projfile, vrtfile, qfile) ## let's import the SM quality map... smfile = name + '.sm' try: grass.run_command('r.in.gdal', input=vrtfile, output=smfile) except CalledModuleError: grass.fatal(_("An error occurred. Stop.")) # some of the possible values: rules = [r + '\n' for r in [ '8 50 50 50', '11 70 70 70', '12 90 90 90', '60 grey', '155 blue', '232 violet', '235 red', '236 brown', '248 orange', '251 yellow', '252 green' ]] grass.write_command('r.colors', map = smfile, rules = '-', stdin = rules) grass.message(_("Imported SPOT VEGETATION SM quality map <%s>.") % smfile) grass.message(_("Note: A snow map can be extracted by category 252 (d.rast %s cat=252)") % smfile) grass.message("") grass.message(_("Filtering NDVI map by Status Map quality layer...")) filtfile = "%s_filt" % name grass.mapcalc("$filtfile = if($smfile % 4 == 3 || ($smfile / 16) % 16 == 0, null(), $name)", filtfile = filtfile, smfile = smfile, name = name) grass.run_command('r.colors', map = filtfile, color = 'ndvi', quiet = True) grass.message(_("Filtered SPOT VEGETATION NDVI map <%s>.") % filtfile) # write cmd history: grass.raster_history(smfile) grass.raster_history(filtfile) grass.message(_("Done."))
def main(): # Hard-coded parameters needed for USGS datasets usgs_product_dict = { "ned": { 'product': 'National Elevation Dataset (NED)', 'dataset': { 'ned1sec': (1. / 3600, 30, 100), 'ned13sec': (1. / 3600 / 3, 10, 30), 'ned19sec': (1. / 3600 / 9, 3, 10) }, 'subset': {}, 'extent': [ '1 x 1 degree', '15 x 15 minute' ], 'format': 'IMG', 'extension': 'img', 'zip': True, 'srs': 'wgs84', 'srs_proj4': "+proj=longlat +ellps=GRS80 +datum=NAD83 +nodefs", 'interpolation': 'bilinear', 'url_split': '/' }, "nlcd": { 'product': 'National Land Cover Database (NLCD)', 'dataset': { 'National Land Cover Database (NLCD) - 2001': (1. / 3600, 30, 100), 'National Land Cover Database (NLCD) - 2006': (1. / 3600, 30, 100), 'National Land Cover Database (NLCD) - 2011': (1. / 3600, 30, 100) }, 'subset': { 'Percent Developed Imperviousness', 'Percent Tree Canopy', 'Land Cover' }, 'extent': ['3 x 3 degree'], 'format': 'GeoTIFF', 'extension': 'tif', 'zip': True, 'srs': 'wgs84', 'srs_proj4': "+proj=longlat +ellps=GRS80 +datum=NAD83 +nodefs", 'interpolation': 'nearest', 'url_split': '/' }, "naip": { 'product': 'USDA National Agriculture Imagery Program (NAIP)', 'dataset': { 'Imagery - 1 meter (NAIP)': (1. / 3600 / 27, 1, 3)}, 'subset': {}, 'extent': [ '3.75 x 3.75 minute', ], 'format': 'JPEG2000', 'extension': 'jp2', 'zip': False, 'srs': 'wgs84', 'srs_proj4': "+proj=longlat +ellps=GRS80 +datum=NAD83 +nodefs", 'interpolation': 'nearest', 'url_split': '/' }, "lidar": { 'product': 'Lidar Point Cloud (LPC)', 'dataset': { 'Lidar Point Cloud (LPC)': (1. / 3600 / 9, 3, 10)}, 'subset': {}, 'extent': [''], 'format': 'LAS,LAZ', 'extension': 'las,laz', 'zip': True, 'srs': '', 'srs_proj4': "+proj=longlat +ellps=GRS80 +datum=NAD83 +nodefs", 'interpolation': 'nearest', 'url_split': '/' } } # Set GRASS GUI options and flags to python variables gui_product = options['product'] # Variable assigned from USGS product dictionary nav_string = usgs_product_dict[gui_product] product = nav_string['product'] product_format = nav_string['format'] product_extensions = tuple(nav_string['extension'].split(',')) product_is_zip = nav_string['zip'] product_srs = nav_string['srs'] product_proj4 = nav_string['srs_proj4'] product_interpolation = nav_string['interpolation'] product_url_split = nav_string['url_split'] product_extent = nav_string['extent'] gui_subset = None # Parameter assignments for each dataset if gui_product == 'ned': gui_dataset = options['ned_dataset'] ned_api_name = '' if options['ned_dataset'] == 'ned1sec': ned_data_abbrv = 'ned_1arc_' ned_api_name = '1 arc-second' if options['ned_dataset'] == 'ned13sec': ned_data_abbrv = 'ned_13arc_' ned_api_name = '1/3 arc-second' if options['ned_dataset'] == 'ned19sec': ned_data_abbrv = 'ned_19arc_' ned_api_name = '1/9 arc-second' product_tag = product + " " + ned_api_name if gui_product == 'nlcd': gui_dataset = options['nlcd_dataset'] if options['nlcd_dataset'] == 'nlcd2001': gui_dataset = 'National Land Cover Database (NLCD) - 2001' if options['nlcd_dataset'] == 'nlcd2006': gui_dataset = 'National Land Cover Database (NLCD) - 2006' if options['nlcd_dataset'] == 'nlcd2011': gui_dataset = 'National Land Cover Database (NLCD) - 2011' if options['nlcd_subset'] == 'landcover': gui_subset = 'Land Cover' if options['nlcd_subset'] == 'impervious': gui_subset = 'Percent Developed Imperviousness' if options['nlcd_subset'] == 'canopy': gui_subset = 'Percent Tree Canopy' product_tag = gui_dataset if gui_product == 'naip': gui_dataset = 'Imagery - 1 meter (NAIP)' product_tag = nav_string['product'] has_pdal = gscript.find_program(pgm='v.in.pdal') if gui_product == 'lidar': gui_dataset = 'Lidar Point Cloud (LPC)' product_tag = nav_string['product'] if not has_pdal: gscript.warning(_("Module v.in.pdal is missing," " any downloaded data will not be processed.")) # Assigning further parameters from GUI gui_output_layer = options['output_name'] gui_resampling_method = options['resampling_method'] gui_i_flag = flags['i'] gui_k_flag = flags['k'] work_dir = options['output_directory'] memory = options['memory'] nprocs = options['nprocs'] preserve_extracted_files = gui_k_flag use_existing_extracted_files = True preserve_imported_tiles = gui_k_flag use_existing_imported_tiles = True if not os.path.isdir(work_dir): gscript.fatal(_("Directory <{}> does not exist." " Please create it.").format(work_dir)) # Returns current units try: proj = gscript.parse_command('g.proj', flags='g') if gscript.locn_is_latlong(): product_resolution = nav_string['dataset'][gui_dataset][0] elif float(proj['meters']) == 1: product_resolution = nav_string['dataset'][gui_dataset][1] else: # we assume feet product_resolution = nav_string['dataset'][gui_dataset][2] except TypeError: product_resolution = False if gui_product == 'lidar' and options['resolution']: product_resolution = float(options['resolution']) if gui_resampling_method == 'default': gui_resampling_method = nav_string['interpolation'] gscript.verbose(_("The default resampling method for product {product} is {res}").format(product=gui_product, res=product_interpolation)) # Get coordinates for current GRASS computational region and convert to USGS SRS gregion = gscript.region() wgs84 = '+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs' min_coords = gscript.read_command('m.proj', coordinates=(gregion['w'], gregion['s']), proj_out=wgs84, separator='comma', flags='d') max_coords = gscript.read_command('m.proj', coordinates=(gregion['e'], gregion['n']), proj_out=wgs84, separator='comma', flags='d') min_list = min_coords.split(',')[:2] max_list = max_coords.split(',')[:2] list_bbox = min_list + max_list str_bbox = ",".join((str(coord) for coord in list_bbox)) # Format variables for TNM API call gui_prod_str = str(product_tag) datasets = quote_plus(gui_prod_str) prod_format = quote_plus(product_format) prod_extent = quote_plus(product_extent[0]) # Create TNM API URL base_TNM = "https://viewer.nationalmap.gov/tnmaccess/api/products?" datasets_TNM = "datasets={0}".format(datasets) bbox_TNM = "&bbox={0}".format(str_bbox) prod_format_TNM = "&prodFormats={0}".format(prod_format) TNM_API_URL = base_TNM + datasets_TNM + bbox_TNM + prod_format_TNM if gui_product == 'nlcd': TNM_API_URL += "&prodExtents={0}".format(prod_extent) gscript.verbose("TNM API Query URL:\t{0}".format(TNM_API_URL)) # Query TNM API try_again_messge = _("Possibly, the query has timed out. Check network configuration and try again.") try: TNM_API_GET = urlopen(TNM_API_URL, timeout=12) except HTTPError as error: gscript.fatal(_( "HTTP(S) error from USGS TNM API:" " {code}: {reason} ({instructions})").format( reason=error.reason, code=error.code, instructions=try_again_messge)) except (URLError, OSError, IOError) as error: # Catching also SSLError and potentially others which are # subclasses of IOError in Python 2 and of OSError in Python 3. gscript.fatal(_( "Error accessing USGS TNM API: {error} ({instructions})").format( error=error, instructions=try_again_messge)) # Parse return JSON object from API query try: return_JSON = json.load(TNM_API_GET) if return_JSON['errors']: TNM_API_error = return_JSON['errors'] api_error_msg = "TNM API Error - {0}".format(str(TNM_API_error)) gscript.fatal(api_error_msg) if gui_product == 'lidar' and options['title_filter']: return_JSON['items'] = [item for item in return_JSON['items'] if options['title_filter'] in item['title']] return_JSON['total'] = len(return_JSON['items']) except: gscript.fatal(_("Unable to load USGS JSON object.")) # Functions down_list() and exist_list() used to determine # existing files and those that need to be downloaded. def down_list(): dwnld_url.append(TNM_file_URL) dwnld_size.append(TNM_file_size) TNM_file_titles.append(TNM_file_title) if product_is_zip: extract_zip_list.append(local_zip_path) if f['datasets'][0] not in dataset_name: if len(dataset_name) <= 1: dataset_name.append(str(f['datasets'][0])) def exist_list(): exist_TNM_titles.append(TNM_file_title) exist_dwnld_url.append(TNM_file_URL) if product_is_zip: exist_zip_list.append(local_zip_path) extract_zip_list.append(local_zip_path) else: exist_tile_list.append(local_tile_path) # Assign needed parameters from returned JSON tile_API_count = int(return_JSON['total']) tiles_needed_count = 0 size_diff_tolerance = 5 exist_dwnld_size = 0 if tile_API_count > 0: dwnld_size = [] dwnld_url = [] dataset_name = [] TNM_file_titles = [] exist_dwnld_url = [] exist_TNM_titles = [] exist_zip_list = [] exist_tile_list = [] extract_zip_list = [] # for each file returned, assign variables to needed parameters for f in return_JSON['items']: TNM_file_title = f['title'] TNM_file_URL = str(f['downloadURL']) TNM_file_size = int(f['sizeInBytes']) TNM_file_name = TNM_file_URL.split(product_url_split)[-1] if gui_product == 'ned': local_file_path = os.path.join(work_dir, ned_data_abbrv + TNM_file_name) local_zip_path = os.path.join(work_dir, ned_data_abbrv + TNM_file_name) local_tile_path = os.path.join(work_dir, ned_data_abbrv + TNM_file_name) else: local_file_path = os.path.join(work_dir, TNM_file_name) local_zip_path = os.path.join(work_dir, TNM_file_name) local_tile_path = os.path.join(work_dir, TNM_file_name) file_exists = os.path.exists(local_file_path) file_complete = None # if file exists, but is incomplete, remove file and redownload if file_exists: existing_local_file_size = os.path.getsize(local_file_path) # if local file is incomplete if abs(existing_local_file_size - TNM_file_size) > size_diff_tolerance: # add file to cleanup list cleanup_list.append(local_file_path) # NLCD API query returns subsets that cannot be filtered before # results are returned. gui_subset is used to filter results. if not gui_subset: tiles_needed_count += 1 down_list() else: if gui_subset in TNM_file_title: tiles_needed_count += 1 down_list() else: continue else: if not gui_subset: tiles_needed_count += 1 exist_list() exist_dwnld_size += TNM_file_size else: if gui_subset in TNM_file_title: tiles_needed_count += 1 exist_list() exist_dwnld_size += TNM_file_size else: continue else: if not gui_subset: tiles_needed_count += 1 down_list() else: if gui_subset in TNM_file_title: tiles_needed_count += 1 down_list() continue # return fatal error if API query returns no results for GUI input elif tile_API_count == 0: gscript.fatal(_("TNM API ERROR or Zero tiles available for given input parameters.")) # number of files to be downloaded file_download_count = len(dwnld_url) # remove existing files from download lists for t in exist_TNM_titles: if t in TNM_file_titles: TNM_file_titles.remove(t) for url in exist_dwnld_url: if url in dwnld_url: dwnld_url.remove(url) # messages to user about status of files to be kept, removed, or downloaded if exist_zip_list: exist_msg = _("\n{0} of {1} files/archive(s) exist locally and will be used by module.").format(len(exist_zip_list), tiles_needed_count) gscript.message(exist_msg) # TODO: fix this way of reporting and merge it with the one in use if exist_tile_list: exist_msg = _("\n{0} of {1} files/archive(s) exist locally and will be used by module.").format(len(exist_tile_list), tiles_needed_count) gscript.message(exist_msg) # TODO: simply continue with whatever is needed to be done in this case if cleanup_list: cleanup_msg = _("\n{0} existing incomplete file(s) detected and removed. Run module again.").format(len(cleanup_list)) gscript.fatal(cleanup_msg) # formats JSON size from bites into needed units for combined file size if dwnld_size: total_size = sum(dwnld_size) len_total_size = len(str(total_size)) if 6 < len_total_size < 10: total_size_float = total_size * 1e-6 total_size_str = str("{0:.2f}".format(total_size_float) + " MB") if len_total_size >= 10: total_size_float = total_size * 1e-9 total_size_str = str("{0:.2f}".format(total_size_float) + " GB") else: total_size_str = '0' # Prints 'none' if all tiles available locally if TNM_file_titles: TNM_file_titles_info = "\n".join(TNM_file_titles) else: TNM_file_titles_info = 'none' # Formatted return for 'i' flag if file_download_count <= 0: data_info = "USGS file(s) to download: NONE" if gui_product == 'nlcd': if tile_API_count != file_download_count: if tiles_needed_count == 0: nlcd_unavailable = "NLCD {0} data unavailable for input parameters".format(gui_subset) gscript.fatal(nlcd_unavailable) else: data_info = ( "USGS file(s) to download:", "-------------------------", "Total download size:\t{size}", "Tile count:\t{count}", "USGS SRS:\t{srs}", "USGS tile titles:\n{tile}", "-------------------------", ) data_info = '\n'.join(data_info).format(size=total_size_str, count=file_download_count, srs=product_srs, tile=TNM_file_titles_info) print(data_info) if gui_i_flag: gscript.info(_("To download USGS data, remove <i> flag, and rerun r.in.usgs.")) sys.exit() # USGS data download process if file_download_count <= 0: gscript.message(_("Extracting existing USGS Data...")) else: gscript.message(_("Downloading USGS Data...")) TNM_count = len(dwnld_url) download_count = 0 local_tile_path_list = [] local_zip_path_list = [] patch_names = [] # Download files for url in dwnld_url: # create file name by splitting name from returned url # add file name to local download directory if gui_product == 'ned': file_name = ned_data_abbrv + url.split(product_url_split)[-1] local_file_path = os.path.join(work_dir, file_name) else: file_name = url.split(product_url_split)[-1] local_file_path = os.path.join(work_dir, file_name) try: # download files in chunks rather than write complete files to memory dwnld_req = urlopen(url, timeout=12) download_bytes = int(dwnld_req.info()['Content-Length']) CHUNK = 16 * 1024 with open(local_file_path, "wb+") as local_file: count = 0 steps = int(download_bytes / CHUNK) + 1 while True: chunk = dwnld_req.read(CHUNK) gscript.percent(count, steps, 10) count += 1 if not chunk: break local_file.write(chunk) gscript.percent(1, 1, 1) local_file.close() download_count += 1 # determine if file is a zip archive or another format if product_is_zip: local_zip_path_list.append(local_file_path) else: local_tile_path_list.append(local_file_path) file_complete = "Download {0} of {1}: COMPLETE".format( download_count, TNM_count) gscript.info(file_complete) except URLError: gscript.fatal(_("USGS download request has timed out. Network or formatting error.")) except StandardError: cleanup_list.append(local_file_path) if download_count: file_failed = "Download {0} of {1}: FAILED".format( download_count, TNM_count) gscript.fatal(file_failed) # sets already downloaded zip files or tiles to be extracted or imported # our pre-stats for extraction are broken, collecting stats during used_existing_extracted_tiles_num = 0 removed_extracted_tiles_num = 0 old_extracted_tiles_num = 0 extracted_tiles_num = 0 if exist_zip_list: for z in exist_zip_list: local_zip_path_list.append(z) if exist_tile_list: for t in exist_tile_list: local_tile_path_list.append(t) if product_is_zip: if file_download_count == 0: pass else: gscript.message("Extracting data...") # for each zip archive, extract needed file files_to_process = len(local_zip_path_list) for i, z in enumerate(local_zip_path_list): # TODO: measure only for the files being unzipped gscript.percent(i, files_to_process, 10) # Extract tiles from ZIP archives try: with zipfile.ZipFile(z, "r") as read_zip: for f in read_zip.namelist(): if f.lower().endswith(product_extensions): extracted_tile = os.path.join(work_dir, str(f)) remove_and_extract = True if os.path.exists(extracted_tile): if use_existing_extracted_files: # if the downloaded file is newer # than the extracted on, we extract if os.path.getmtime(extracted_tile) < os.path.getmtime(z): remove_and_extract = True old_extracted_tiles_num += 1 else: remove_and_extract = False used_existing_extracted_tiles_num += 1 else: remove_and_extract = True if remove_and_extract: removed_extracted_tiles_num += 1 os.remove(extracted_tile) if remove_and_extract: extracted_tiles_num += 1 read_zip.extract(f, work_dir) if os.path.exists(extracted_tile): local_tile_path_list.append(extracted_tile) if not preserve_extracted_files: cleanup_list.append(extracted_tile) except IOError as error: cleanup_list.append(extracted_tile) gscript.fatal(_( "Unable to locate or extract IMG file '{filename}'" " from ZIP archive '{zipname}': {error}").format( filename=extracted_tile, zipname=z, error=error)) gscript.percent(1, 1, 1) # TODO: do this before the extraction begins gscript.verbose(_("Extracted {extracted} new tiles and" " used {used} existing tiles").format( used=used_existing_extracted_tiles_num, extracted=extracted_tiles_num )) if old_extracted_tiles_num: gscript.verbose(_("Found {removed} existing tiles older" " than the corresponding downloaded archive").format( removed=old_extracted_tiles_num )) if removed_extracted_tiles_num: gscript.verbose(_("Removed {removed} existing tiles").format( removed=removed_extracted_tiles_num )) if gui_product == 'lidar' and not has_pdal: gscript.fatal(_("Module v.in.pdal is missing," " cannot process downloaded data.")) # operations for extracted or complete files available locally # We are looking only for the existing maps in the current mapset, # but theoretically we could be getting them from other mapsets # on search path or from the whole location. User may also want to # store the individual tiles in a separate mapset. # The big assumption here is naming of the maps (it is a smaller # for the files in a dedicated download directory). used_existing_imported_tiles_num = 0 imported_tiles_num = 0 mapset = get_current_mapset() files_to_import = len(local_tile_path_list) process_list = [] process_id_list = [] process_count = 0 num_tiles = len(local_tile_path_list) with Manager() as manager: results = manager.dict() for i, t in enumerate(local_tile_path_list): # create variables for use in GRASS GIS import process LT_file_name = os.path.basename(t) LT_layer_name = os.path.splitext(LT_file_name)[0] # we are removing the files if requested even if we don't use them # do not remove by default with NAIP, there are no zip files if gui_product != 'naip' and not preserve_extracted_files: cleanup_list.append(t) # TODO: unlike the files, we don't compare date with input if use_existing_imported_tiles and map_exists("raster", LT_layer_name, mapset): patch_names.append(LT_layer_name) used_existing_imported_tiles_num += 1 else: in_info = _("Importing and reprojecting {name}" " ({count} out of {total})...").format( name=LT_file_name, count=i + 1, total=files_to_import) gscript.info(in_info) process_count += 1 if gui_product != 'lidar': process = Process( name="Import-{}-{}-{}".format(process_count, i, LT_layer_name), target=run_file_import, kwargs=dict( identifier=i, results=results, input=t, output=LT_layer_name, resolution='value', resolution_value=product_resolution, extent="region", resample=product_interpolation, memory=memory )) else: srs = options['input_srs'] process = Process( name="Import-{}-{}-{}".format(process_count, i, LT_layer_name), target=run_lidar_import, kwargs=dict( identifier=i, results=results, input=t, output=LT_layer_name, input_srs=srs if srs else None )) process.start() process_list.append(process) process_id_list.append(i) # Wait for processes to finish when we reached the max number # of processes. if process_count == nprocs or i == num_tiles - 1: exitcodes = 0 for process in process_list: process.join() exitcodes += process.exitcode if exitcodes != 0: if nprocs > 1: gscript.fatal(_("Parallel import and reprojection failed." " Try running with nprocs=1.")) else: gscript.fatal(_("Import and reprojection step failed.")) for identifier in process_id_list: if "errors" in results[identifier]: gscript.warning(results[identifier]["errors"]) else: patch_names.append(results[identifier]["output"]) imported_tiles_num += 1 # Empty the process list process_list = [] process_id_list = [] process_count = 0 # no process should be left now assert not process_list assert not process_id_list assert not process_count gscript.verbose(_("Imported {imported} new tiles and" " used {used} existing tiles").format( used=used_existing_imported_tiles_num, imported=imported_tiles_num )) # if control variables match and multiple files need to be patched, # check product resolution, run r.patch # v.surf.rst lidar params rst_params = dict(tension=25, smooth=0.1, npmin=100) # Check that downloaded files match expected count completed_tiles_count = len(local_tile_path_list) if completed_tiles_count == tiles_needed_count: if len(patch_names) > 1: try: gscript.use_temp_region() # set the resolution if product_resolution: gscript.run_command('g.region', res=product_resolution, flags='a') if gui_product == 'naip': for i in ('1', '2', '3', '4'): patch_names_i = [name + '.' + i for name in patch_names] output = gui_output_layer + '.' + i gscript.run_command('r.patch', input=patch_names_i, output=output) gscript.raster_history(output) elif gui_product == 'lidar': gscript.run_command('v.patch', flags='nzb', input=patch_names, output=gui_output_layer) gscript.run_command('v.surf.rst', input=gui_output_layer, elevation=gui_output_layer, nprocs=nprocs, **rst_params) else: gscript.run_command('r.patch', input=patch_names, output=gui_output_layer) gscript.raster_history(gui_output_layer) gscript.del_temp_region() out_info = ("Patched composite layer '{0}' added").format(gui_output_layer) gscript.verbose(out_info) # Remove files if not -k flag if not preserve_imported_tiles: if gui_product == 'naip': for i in ('1', '2', '3', '4'): patch_names_i = [name + '.' + i for name in patch_names] gscript.run_command('g.remove', type='raster', name=patch_names_i, flags='f') elif gui_product == 'lidar': gscript.run_command('g.remove', type='vector', name=patch_names + [gui_output_layer], flags='f') else: gscript.run_command('g.remove', type='raster', name=patch_names, flags='f') except CalledModuleError: gscript.fatal("Unable to patch tiles.") temp_down_count = _( "{0} of {1} tiles successfully imported and patched").format( completed_tiles_count, tiles_needed_count) gscript.info(temp_down_count) elif len(patch_names) == 1: if gui_product == 'naip': for i in ('1', '2', '3', '4'): gscript.run_command('g.rename', raster=(patch_names[0] + '.' + i, gui_output_layer + '.' + i)) elif gui_product == 'lidar': if product_resolution: gscript.run_command('g.region', res=product_resolution, flags='a') gscript.run_command('v.surf.rst', input=patch_names[0], elevation=gui_output_layer, nprocs=nprocs, **rst_params) if not preserve_imported_tiles: gscript.run_command('g.remove', type='vector', name=patch_names[0], flags='f') else: gscript.run_command('g.rename', raster=(patch_names[0], gui_output_layer)) temp_down_count = _("Tile successfully imported") gscript.info(temp_down_count) else: gscript.fatal(_("No tiles imported successfully. Nothing to patch.")) else: gscript.fatal(_( "Error in getting or importing the data (see above). Please retry.")) # Keep source files if 'k' flag active if gui_k_flag: src_msg = ("<k> flag selected: Source tiles remain in '{0}'").format(work_dir) gscript.info(src_msg) # set appropriate color table if gui_product == 'ned': gscript.run_command('r.colors', map=gui_output_layer, color='elevation') # composite NAIP if gui_product == 'naip': gscript.use_temp_region() gscript.run_command('g.region', raster=gui_output_layer + '.1') gscript.run_command('r.composite', red=gui_output_layer + '.1', green=gui_output_layer + '.2', blue=gui_output_layer + '.3', output=gui_output_layer) gscript.raster_history(gui_output_layer) gscript.del_temp_region()
def main(): red = options['red'] green = options['green'] blue = options['blue'] brightness = options['strength'] full = flags['f'] preserve = flags['p'] reset = flags['r'] global do_mp if flags['s']: do_mp = False # 90 or 98? MAX value controls brightness # think of percent (0-100), must be positive or 0 # must be more than "2" ? if full: for i in [red, green, blue]: gscript.run_command('r.colors', map=i, color='grey', quiet=True) sys.exit(0) if reset: for i in [red, green, blue]: gscript.run_command('r.colors', map=i, color='grey255', quiet=True) sys.exit(0) if not preserve: if do_mp: gscript.message(_("Processing...")) # set up jobs and launch them proc = {} conn = {} for i in [red, green, blue]: conn[i] = mp.Pipe() proc[i] = mp.Process(target=get_percentile_mp, args=( i, ['2', brightness], conn[i], )) proc[i].start() gscript.percent(1, 2, 1) # collect results and wait for jobs to finish for i in [red, green, blue]: output_pipe, input_pipe = conn[i] (v0, v1) = input_pipe.recv() gscript.debug('parent (%s) (%.1f, %.1f)' % (i, v0, v1)) input_pipe.close() proc[i].join() set_colors(i, v0, v1) gscript.percent(1, 1, 1) else: for i in [red, green, blue]: gscript.message(_("Processing...")) (v0, v1) = get_percentile(i, ['2', brightness]) gscript.debug("<%s>: min=%f max=%f" % (i, v0, v1)) set_colors(i, v0, v1) else: all_max = 0 all_min = 999999 if do_mp: gscript.message(_("Processing...")) # set up jobs and launch jobs proc = {} conn = {} for i in [red, green, blue]: conn[i] = mp.Pipe() proc[i] = mp.Process(target=get_percentile_mp, args=( i, ['2', brightness], conn[i], )) proc[i].start() gscript.percent(1, 2, 1) # collect results and wait for jobs to finish for i in [red, green, blue]: output_pipe, input_pipe = conn[i] (v0, v1) = input_pipe.recv() gscript.debug('parent (%s) (%.1f, %.1f)' % (i, v0, v1)) input_pipe.close() proc[i].join() all_min = min(all_min, v0) all_max = max(all_max, v1) gscript.percent(1, 1, 1) else: for i in [red, green, blue]: gscript.message(_("Processing...")) (v0, v1) = get_percentile(i, ['2', brightness]) gscript.debug("<%s>: min=%f max=%f" % (i, v0, v1)) all_min = min(all_min, v0) all_max = max(all_max, v1) gscript.debug("all_min=%f all_max=%f" % (all_min, all_max)) for i in [red, green, blue]: set_colors(i, all_min, all_max) # write cmd history: mapset = gscript.gisenv()['MAPSET'] for i in [red, green, blue]: if gscript.find_file(i)['mapset'] == mapset: gscript.raster_history(i)
def main(): global temp_dist, temp_val input = options['input'] output = options['output'] radius = float(options['radius']) metric = options['metric'] old = options['old'] new = options['new'] mapunits = flags['m'] tmp = str(os.getpid()) temp_dist = "r.grow.tmp.%s.dist" % tmp shrink = False if radius < 0.0: shrink = True radius = -radius if new == '' and shrink == False: temp_val = "r.grow.tmp.%s.val" % tmp new = temp_val else: temp_val = None if old == '': old = input if not mapunits: kv = grass.region() scale = math.sqrt(float(kv['nsres']) * float(kv['ewres'])) radius *= scale if metric == 'euclidean': metric = 'squared' radius = radius * radius # check if input file exists if not grass.find_file(input)['file']: grass.fatal(_("Raster map <%s> not found") % input) if shrink == False: try: grass.run_command('r.grow.distance', input=input, metric=metric, distance=temp_dist, value=temp_val) except CalledModuleError: grass.fatal(_("Growing failed. Removing temporary maps.")) grass.mapcalc( "$output = if(!isnull($input),$old,if($dist < $radius,$new,null()))", output=output, input=input, radius=radius, old=old, new=new, dist=temp_dist) else: # shrink try: grass.run_command('r.grow.distance', input=input, metric=metric, distance=temp_dist, value=temp_val, flags='n') except CalledModuleError: grass.fatal(_("Shrinking failed. Removing temporary maps.")) grass.mapcalc( "$output = if($dist < $radius,null(),$old)", output=output, radius=radius, old=old, dist=temp_dist) grass.run_command('r.colors', map=output, raster=input) # write cmd history: grass.raster_history(output)
def main(): name = options["output"] type = options["type"] dip = float(options["dip"]) az = float(options["azimuth"]) try: ea = float(options["easting"]) no = float(options["northing"]) except ValueError: try: ea = float(gscript.utils.float_or_dms(options["easting"])) no = float(gscript.utils.float_or_dms(options["northing"])) except Exception: gscript.fatal(_("Input coordinates seems to be invalid")) el = float(options["elevation"]) # reg = gscript.region() # Test input values if abs(dip) >= 90: gscript.fatal(_("dip must be between -90 and 90.")) if az < 0 or az >= 360: gscript.fatal(_("azimuth must be between 0 and 360")) # now the actual algorithm az_r = math.radians(-az) sinaz = math.sin(az_r) cosaz = math.cos(az_r) dip_r = math.radians(-dip) tandip = math.tan(dip_r) kx = sinaz * tandip ky = cosaz * tandip kz = el - ea * sinaz * tandip - no * cosaz * tandip if type == "CELL": round = "round" dtype = "int" elif type == "FCELL": round = "" dtype = "float" else: round = "" dtype = "double" gscript.mapcalc( "$name = $type($round(x() * $kx + y() * $ky + $kz))", name=name, type=dtype, round=round, kx=kx, ky=ky, kz=kz, ) gscript.run_command("r.support", map=name, history="") gscript.raster_history(name) gscript.message(_("Done.")) t = string.Template("Raster map <$name> generated by r.plane " "at point $ea E, $no N, elevation $el with dip = $dip" " degrees and aspect = $az degrees ccw from north.") gscript.message( t.substitute(name=name, ea=ea, no=no, el=el, dip=dip, az=az))
def main(): global temp_dist, temp_src input = options['input'] output = options['output'] distances = options['distances'] units = options['units'] zero = flags['z'] tmp = str(os.getpid()) temp_dist = "r.buffer.tmp.%s.dist" % tmp temp_src = "r.buffer.tmp.%s.src" % tmp # check if input file exists if not grass.find_file(input)['file']: grass.fatal(_("Raster map <%s> not found") % input) scale = scales[units] distances = distances.split(',') distances1 = [scale * float(d) for d in distances] distances2 = [d * d for d in distances1] s = grass.read_command("g.proj", flags='j') kv = grass.parse_key_val(s) if kv['+proj'] == 'longlat': metric = 'geodesic' else: metric = 'squared' grass.run_command('r.grow.distance', input=input, metric=metric, distance=temp_dist, flags='m') if zero: exp = "$temp_src = if($input == 0,null(),1)" else: exp = "$temp_src = if(isnull($input),null(),1)" grass.message(_("Extracting buffers (1/2)...")) grass.mapcalc(exp, temp_src=temp_src, input=input) exp = "$output = if(!isnull($input),$input,%s)" if metric == 'squared': for n, dist2 in enumerate(distances2): exp %= "if($dist <= %f,%d,%%s)" % (dist2, n + 2) else: for n, dist2 in enumerate(distances1): exp %= "if($dist <= %f,%d,%%s)" % (dist2, n + 2) exp %= "null()" grass.message(_("Extracting buffers (2/2)...")) grass.mapcalc(exp, output=output, input=temp_src, dist=temp_dist) p = grass.feed_command('r.category', map=output, separator=':', rules='-') msg = "1:distances calculated from these locations\n" p.stdin.write(encode(msg)) d0 = "0" for n, d in enumerate(distances): msg = "%d:%s-%s %s\n" % (n + 2, d0, d, units) p.stdin.write(encode(msg)) d0 = d p.stdin.close() p.wait() grass.run_command('r.colors', map=output, color='rainbow') # write cmd history: grass.raster_history(output)
def main(): options, flags = gs.parser() simulated = options["simulated"] original = options["original"] reference = options["reference"] kappa = options["kappa"] kappasimulation = options["kappasimulation"] quantity_disagreement = options["quantity_disagreement"] allocation_disagreement = options["allocation_disagreement"] quantity_disagreement_basename = options["quantity_disagreement_basename"] allocation_disagreement_basename = options[ "allocation_disagreement_basename"] input_region = options["region"] nprocs = int(options["nprocs"]) current = gs.region() region = gs.parse_command("g.region", flags="pug", region=input_region) regions = [] for row in range(int(region["rows"])): for col in range(int(region["cols"])): s = float(region["s"]) + row * float(region["nsres"]) n = float(region["s"]) + (row + 1) * float(region["nsres"]) w = float(region["w"]) + col * float(region["ewres"]) e = float(region["w"]) + (col + 1) * float(region["ewres"]) regions.append({ "n": n, "s": s, "w": w, "e": e, "nsres": float(current["nsres"]), "ewres": float(current["ewres"]), }) results = [] params = [] for each in regions: if original: params.append({ "region": each, "simulated": simulated, "reference": reference, "original": original, }) else: params.append({ "region": each, "simulated": simulated, "reference": reference }) with Pool(processes=nprocs) as pool: results = pool.map_async(compute, params).get() outputs = {} if kappa: outputs["kappa"] = {"name": kappa, "param": "kappa", "inp": ""} if kappasimulation: outputs["kappasim"] = { "name": kappasimulation, "param": "kappasimulation", "inp": "", } if quantity_disagreement: outputs["quantity_disagreement"] = { "name": quantity_disagreement, "param": "total_quantity", "inp": "", } if allocation_disagreement: outputs["allocation_disagreement"] = { "name": allocation_disagreement, "param": "total_allocation", "inp": "", } env = os.environ.copy() env["GRASS_REGION"] = gs.region_env(region=input_region) for r in results: for key in r.keys(): if allocation_disagreement_basename and "allocation_class_" in key: cl = key.replace("allocation_class_", "") if cl not in outputs: outputs[cl] = { "name": allocation_disagreement_basename + "_" + cl, "param": key, "inp": "", } if quantity_disagreement_basename and "quantity_class_" in key: cl = key.replace("quantity_class_", "") if cl not in outputs: outputs[cl] = { "name": quantity_disagreement_basename + "_" + cl, "param": key, "inp": "", } for k in outputs: if outputs[k]["param"] in r and r[outputs[k]["param"]] is not None: outputs[k][ "inp"] += f"{r['e']},{r['n']},{r[outputs[k]['param']]}\n" for k in outputs: gs.write_command( "r.in.xyz", input="-", stdin=outputs[k]["inp"], output=outputs[k]["name"], method="mean", separator="comma", env=env, quiet=True, ) gs.raster_history(outputs[k]["name"])
def main(): global temp_dist, temp_src input = options['input'] output = options['output'] distances = options['distances'] units = options['units'] zero = flags['z'] tmp = str(os.getpid()) temp_dist = "r.buffer.tmp.%s.dist" % tmp temp_src = "r.buffer.tmp.%s.src" % tmp #check if input file exists if not grass.find_file(input)['file']: grass.fatal(_("<%s> does not exist.") % input) scale = scales[units] distances = distances.split(',') distances1 = [scale * float(d) for d in distances] distances2 = [d * d for d in distances1] s = grass.read_command("g.proj", flags='j') kv = grass.parse_key_val(s) if kv['+proj'] == 'longlat': metric = 'geodesic' else: metric = 'squared' grass.run_command('r.grow.distance', input = input, metric = metric, distance = temp_dist) if zero: exp = "$temp_src = if($input == 0,null(),1)" else: exp = "$temp_src = if(isnull($input),null(),1)" grass.message(_("Extracting buffers (1/2)...")) grass.mapcalc(exp, temp_src = temp_src, input = input) exp = "$output = if(!isnull($input),$input,%s)" for n, dist2 in enumerate(distances2): exp %= "if($dist <= %f,%d,%%s)" % (dist2,n + 2) exp %= "null()" grass.message(_("Extracting buffers (2/2)...")) grass.mapcalc(exp, output = output, input = temp_src, dist = temp_dist) p = grass.feed_command('r.category', map = output, rules = '-') p.stdin.write("1:distances calculated from these locations\n") d0 = "0" for n, d in enumerate(distances): p.stdin.write("%d:%s-%s %s\n" % (n + 2, d0, d, units)) d0 = d p.stdin.close() p.wait() grass.run_command('r.colors', map = output, color = 'rainbow') # write cmd history: grass.raster_history(output)
def main(): global tile, tmpdir, in_temp in_temp = False # to support SRTM water body swbd = False input = options["input"] output = options["output"] one = flags["1"] # are we in LatLong location? s = grass.read_command("g.proj", flags="j") kv = grass.parse_key_val(s) if "+proj" not in kv.keys() or kv["+proj"] != "longlat": grass.fatal(_("This module only operates in LatLong locations")) # use these from now on: infile = input while infile[-4:].lower() in [".hgt", ".zip", ".raw"]: infile = infile[:-4] (fdir, tile) = os.path.split(infile) if not output: tileout = tile else: tileout = output if ".hgt" in input: suff = ".hgt" else: suff = ".raw" swbd = True zipfile = "{im}{su}.zip".format(im=infile, su=suff) hgtfile = "{im}{su}".format(im=infile, su=suff) if os.path.isfile(zipfile): # really a ZIP file? if not zfile.is_zipfile(zipfile): grass.fatal(_("'%s' does not appear to be a valid zip file.") % zipfile) is_zip = True elif os.path.isfile(hgtfile): # try and see if it's already unzipped is_zip = False else: grass.fatal(_("File '%s' or '%s' not found") % (zipfile, hgtfile)) # make a temporary directory tmpdir = grass.tempfile() grass.try_remove(tmpdir) os.mkdir(tmpdir) if is_zip: shutil.copyfile( zipfile, os.path.join(tmpdir, "{im}{su}.zip".format(im=tile, su=suff)) ) else: shutil.copyfile( hgtfile, os.path.join(tmpdir, "{im}{su}".format(im=tile[:7], su=suff)) ) # change to temporary directory os.chdir(tmpdir) in_temp = True zipfile = "{im}{su}.zip".format(im=tile, su=suff) hgtfile = "{im}{su}".format(im=tile[:7], su=suff) bilfile = tile + ".bil" if is_zip: # unzip & rename data file: grass.message(_("Extracting '%s'...") % infile) try: zf = zfile.ZipFile(zipfile) zf.extractall() except: grass.fatal(_("Unable to unzip file.")) grass.message(_("Converting input file to BIL...")) os.rename(hgtfile, bilfile) north = tile[0] ll_latitude = int(tile[1:3]) east = tile[3] ll_longitude = int(tile[4:7]) # are we on the southern hemisphere? If yes, make LATITUDE negative. if north == "S": ll_latitude *= -1 # are we west of Greenwich? If yes, make LONGITUDE negative. if east == "W": ll_longitude *= -1 # Calculate Upper Left from Lower Left ulxmap = "%.1f" % ll_longitude # SRTM90 tile size is 1 deg: ulymap = "%.1f" % (ll_latitude + 1) if not one: tmpl = tmpl3sec elif swbd: grass.message(_("Attempting to import 1-arcsec SWBD data")) tmpl = swbd1sec else: grass.message(_("Attempting to import 1-arcsec data")) tmpl = tmpl1sec header = tmpl % (ulxmap, ulymap) hdrfile = tile + ".hdr" outf = open(hdrfile, "w") outf.write(header) outf.close() # create prj file: To be precise, we would need EGS96! But who really cares... prjfile = tile + ".prj" outf = open(prjfile, "w") outf.write(proj) outf.close() try: grass.run_command("r.in.gdal", input=bilfile, out=tileout) except: grass.fatal(_("Unable to import data")) # nice color table if not swbd: grass.run_command("r.colors", map=tileout, color="srtm") # write cmd history: grass.raster_history(tileout) grass.message(_("Done: generated map ") + tileout) grass.message( _("(Note: Holes in the data can be closed with 'r.fillnulls' using splines)") )
def main(): global temp_dist, temp_val input = options['input'] radius = float(options['radius']) metric = options['metric'] old = options['old'] new = options['new'] mapunits = flags['m'] tmp = str(os.getpid()) temp_dist = "r.grow.tmp.%s.dist" % tmp shrink = False if radius < 0.0: shrink = True radius = -radius if new == '' and not shrink: temp_val = "r.grow.tmp.%s.val" % tmp new = '"%s"' % temp_val else: temp_val = None if old == '': old = '"%s"' % input if not mapunits: kv = grass.region() scale = math.sqrt(float(kv['nsres']) * float(kv['ewres'])) radius *= scale if metric == 'euclidean': metric = 'squared' radius = radius * radius # check if input file exists if not grass.find_file(input)['file']: grass.fatal(_("Raster map <%s> not found") % input) # Workaround for r.mapcalc bug #3475 # Mapcalc will fail if output is a fully qualified map name out_name = options['output'].split('@') if len(out_name) == 2: if out_name[1] != grass.gisenv()['MAPSET']: grass.fatal(_("Output can be written only to the current mapset")) output = out_name[0] else: output = out_name[0] if not shrink: try: grass.run_command('r.grow.distance', input=input, metric=metric, distance=temp_dist, value=temp_val) except CalledModuleError: grass.fatal(_("Growing failed. Removing temporary maps.")) grass.mapcalc( '$output = if(!isnull("$input"),$old,if($dist < $radius,$new,null()))', output=output, input=input, radius=radius, old=old, new=new, dist=temp_dist) else: # shrink try: grass.run_command('r.grow.distance', input=input, metric=metric, distance=temp_dist, value=temp_val, flags='n') except CalledModuleError: grass.fatal(_("Shrinking failed. Removing temporary maps.")) grass.mapcalc( "$output = if(isnull($dist), $old, if($dist < $radius,null(),$old))", output=output, radius=radius, old=old, dist=temp_dist) grass.run_command('r.colors', map=output, raster=input) # write cmd history: grass.raster_history(output)
def main(): """Do the main work""" # set numpy printing options np.set_printoptions(formatter={"float": lambda x: "{0:0.2f}".format(x)}) # ========================================================================== # Input data # ========================================================================== # Required r_output = options["output"] r_dsm = options["input"] dsm_type = grass.parse_command("r.info", map=r_dsm, flags="g")["datatype"] # Test if DSM exist gfile_dsm = grass.find_file(name=r_dsm, element="cell") if not gfile_dsm["file"]: grass.fatal("Raster map <{}> not found".format(r_dsm)) # Exposure settings v_source = options["sampling_points"] r_source = options["source"] source_cat = options["sourcecat"] r_weights = options["weights"] # test if source vector map exist and contains points if v_source: gfile_vsource = grass.find_file(name=v_source, element="vector") if not gfile_vsource["file"]: grass.fatal("Vector map <{}> not found".format(v_source)) if not grass.vector.vector_info_topo(v_source, layer=1)["points"] > 0: grass.fatal("Vector map <{}> does not contain any points.".format( v_source)) if r_source: gfile_rsource = grass.find_file(name=r_source, element="cell") if not gfile_rsource["file"]: grass.fatal("Raster map <{}> not found".format(r_source)) # if source_cat is set, check that r_source is CELL source_datatype = grass.parse_command("r.info", map=r_source, flags="g")["datatype"] if source_cat != "*" and source_datatype != "CELL": grass.fatal( "The raster map <%s> must be integer (CELL type) in order to \ use the 'sourcecat' parameter" % r_source) if r_weights: gfile_weights = grass.find_file(name=r_weights, element="cell") if not gfile_weights["file"]: grass.fatal("Raster map <{}> not found".format(r_weights)) # Viewshed settings range_inp = float(options["range"]) v_elevation = float(options["observer_elevation"]) b_1 = float(options["b1_distance"]) pfunction = options["function"] refr_coeff = float(options["refraction_coeff"]) flagstring = "" if flags["r"]: flagstring += "r" if flags["c"]: flagstring += "c" # test values if v_elevation < 0.0: grass.fatal("Observer elevation must be larger than or equal to 0.0.") if range_inp <= 0.0 and range_inp != -1: grass.fatal("Exposure range must be larger than 0.0.") if pfunction == "Fuzzy_viewshed" and range_inp == -1: grass.fatal("Exposure range cannot be \ infinity for fuzzy viewshed approch.") if pfunction == "Fuzzy_viewshed" and b_1 > range_inp: grass.fatal("Exposure range must be larger than radius around \ the viewpoint where clarity is perfect.") # Sampling settings source_sample_density = float(options["sample_density"]) seed = options["seed"] if not seed: # if seed is not set, set it to process number seed = os.getpid() # Optional cores = int(options["nprocs"]) memory = int(options["memory"]) # ========================================================================== # Region settings # ========================================================================== # check that location is not in lat/long if grass.locn_is_latlong(): grass.fatal("The analysis is not available for lat/long coordinates.") # get comp. region parameters reg = Region() # check that NSRES equals EWRES if abs(reg.ewres - reg.nsres) > 1e-6: grass.fatal("Variable north-south and east-west 2D grid resolution \ is not supported") # adjust exposure range as a multiplicate of region resolution # if infinite, set exposure range to the max of region size if range_inp != -1: multiplicate = math.floor(range_inp / reg.nsres) exp_range = multiplicate * reg.nsres else: range_inf = max(reg.north - reg.south, reg.east - reg.west) multiplicate = math.floor(range_inf / reg.nsres) exp_range = multiplicate * reg.nsres if RasterRow("MASK", Mapset().name).exist(): grass.warning("Current MASK is temporarily renamed.") unset_mask() # ========================================================================== # Random sample exposure source with target points T # ========================================================================== if v_source: # go for using input vector map as sampling points v_source_sample = v_source grass.verbose("Using sampling points from input vector map") else: # go for sampling # min. distance between samples set to half of region resolution # (issue in r.random.cells) sample_distance = reg.nsres / 2 v_source_sample = sample_raster_with_points( r_source, source_cat, source_sample_density, sample_distance, "{}_rand_pts_vect".format(TEMPNAME), seed, ) # ========================================================================== # Get coordinates and attributes of target points T # ========================================================================== # Prepare a list of maps to extract attributes from # DSM values attr_map_list = [r_dsm] if pfunction in ["Solid_angle", "Visual_magnitude"]: grass.verbose("Precomputing parameter maps...") # Precompute values A, B, C, D for solid angle function # using moving window [row, col] if pfunction == "Solid_angle": r_a_z = "{}_A_z".format(TEMPNAME) r_b_z = "{}_B_z".format(TEMPNAME) r_c_z = "{}_C_z".format(TEMPNAME) r_d_z = "{}_D_z".format(TEMPNAME) expr = ";".join([ "$outmap_A = ($inmap[0, 0] + \ $inmap[0, -1] + \ $inmap[1, -1] + \ $inmap[1, 0]) / 4", "$outmap_B = ($inmap[-1, 0] + \ $inmap[-1, -1] + \ $inmap[0, -1] + \ $inmap[0, 0]) / 4", "$outmap_C = ($inmap[-1, 1] + \ $inmap[-1, 0] + \ $inmap[0, 0] + \ $inmap[0, 1]) / 4", "$outmap_D = ($inmap[0, 1] + \ $inmap[0, 0] + \ $inmap[1, 0] + \ $inmap[1, 1]) / 4", ]) grass.mapcalc( expr, inmap=r_dsm, outmap_A=r_a_z, outmap_B=r_b_z, outmap_C=r_c_z, outmap_D=r_d_z, overwrite=True, quiet=grass.verbosity() <= 1, ) attr_map_list.extend([r_a_z, r_b_z, r_c_z, r_d_z]) # Precompute values slopes in e-w direction, n-s direction # as atan(dz/dx) (e-w direction), atan(dz/dy) (n-s direction) # using moving window [row, col] elif pfunction == "Visual_magnitude": r_slope_ew = "{}_slope_ew".format(TEMPNAME) r_slope_ns = "{}_slope_ns".format(TEMPNAME) expr = ";".join([ "$outmap_ew = atan((sqrt(2) * $inmap[-1, 1] + \ 2 * $inmap[0, 1] + \ sqrt(2) * $inmap[1, 1] - \ sqrt(2) * $inmap[-1, -1] - \ 2 * $inmap[0, -1] - \ sqrt(2) * $inmap[1, -1]) / \ (8 * $w_ew))", "$outmap_ns = atan((sqrt(2) * $inmap[-1, -1] + \ 2 * $inmap[-1, 0] + \ sqrt(2) * $inmap[-1, 1] - \ sqrt(2) * $inmap[1, -1] - \ 2 * $inmap[1, 0] - \ sqrt(2) * $inmap[1, 1]) / \ (8 * $w_ns))", ]) grass.mapcalc( expr, inmap=r_dsm, outmap_ew=r_slope_ew, outmap_ns=r_slope_ns, w_ew=reg.ewres, w_ns=reg.nsres, overwrite=True, quiet=grass.verbosity() <= 1, ) attr_map_list.extend([r_slope_ew, r_slope_ns]) # Use viewshed weights if provided if r_weights: attr_map_list.append(r_weights) # Extract attribute values target_pts_grass = grass.read_command( "r.what", flags="v", map=attr_map_list, points=v_source_sample, separator="|", null_value="*", quiet=True, ) # columns to use depending on parametrization function usecols = list(range(0, 4 + len(attr_map_list))) usecols.remove(3) # skip 3rd column - site_name # convert coordinates and attributes of target points T to numpy array target_pts_np = txt2numpy( target_pts_grass, sep="|", names=None, null_value="*", usecols=usecols, structured=False, ) # if one point only - 0D array which cannot be used in iteration if target_pts_np.ndim == 1: target_pts_np = target_pts_np.reshape(1, -1) target_pts_np = target_pts_np[~np.isnan(target_pts_np).any(axis=1)] no_points = target_pts_np.shape[0] # if viewshed weights not set by flag - set weight to 1 for all pts if not r_weights: weights_np = np.ones((no_points, 1)) target_pts_np = np.hstack((target_pts_np, weights_np)) grass.debug("target_pts_np: {}".format(target_pts_np)) # ========================================================================== # Calculate weighted parametrised cummulative viewshed # by iterating over target points T # ========================================================================== grass.verbose("Calculating partial viewsheds...") # Parametrisation function if pfunction == "Solid_angle": parametrise_viewshed = solid_angle_reverse elif pfunction == "Distance_decay": parametrise_viewshed = distance_decay_reverse elif pfunction == "Fuzzy_viewshed": parametrise_viewshed = fuzzy_viewshed_reverse elif pfunction == "Visual_magnitude": parametrise_viewshed = visual_magnitude_reverse else: parametrise_viewshed = binary # Collect variables that will be used in do_it_all() into a dictionary global_vars = { "region": reg, "range": exp_range, "param_viewshed": parametrise_viewshed, "observer_elevation": v_elevation, "b_1": b_1, "memory": memory, "refr_coeff": refr_coeff, "flagstring": flagstring, "r_dsm": r_dsm, "dsm_type": dsm_type, "cores": cores, "tempname": TEMPNAME, } # Split target points to chunks for each core target_pnts = np.array_split(target_pts_np, cores) # Combine each chunk with dictionary combo = list(zip(itertools.repeat(global_vars), target_pnts)) # Calculate partial cummulative viewshed with Pool(cores) as pool: np_sum = pool.starmap(do_it_all, combo) pool.close() pool.join() # We should probably use nansum here? all_nan = np.all(np.isnan(np_sum), axis=0) np_sum = np.nansum(np_sum, axis=0, dtype=np.single) np_sum[all_nan] = np.nan grass.verbose("Writing final result and cleaning up...") # Restore original computational region reg.read() reg.set_current() reg.set_raster_region() # Convert numpy array of cummulative viewshed to raster numpy2raster(np_sum, mtype="FCELL", rastname=r_output, overwrite=True) # Remove temporary files and reset mask if needed cleanup() # Set raster history to output raster grass.raster_history(r_output, overwrite=True) grass.run_command( "r.support", overwrite=True, map=r_output, title="Visual exposure index as {}".format(pfunction.replace("_", " ")), description="generated by r.viewshed.exposure", units="Index value", quiet=True, )
def import_cloud_masks(self, area_threshold, prob_threshold, output, shadows, reproject): try: if os.environ["GRASS_OVERWRITE"] == "1": overwrite = True except Exception as e: overwrite = False # Import cloud masks for L2A products files_L2A = self._filter("MSK_CLDPRB_20m.jp2") for f in files_L2A: safe_dir = os.path.dirname(f).split(os.path.sep)[-4] items = safe_dir.split("_") # Define names of final & temporary maps map_name = "_".join([items[5], items[2], "MSK", "CLOUDS"]) clouds_imported = "_".join([items[5], items[2], "cloudprob"]) clouds_selected = "_".join([items[5], items[2], "clouds_selected"]) shadows_imported = "_".join([items[5], items[2], "shadows"]) shadows_selected = "_".join( [items[5], items[2], "shadows_selected"]) mask_selected = "_".join([items[5], items[2], "mask_selected"]) mask_cleaned = "_".join([items[5], items[2], "mask_cleaned"]) self._map_list.extend([ clouds_imported, clouds_selected, shadows_imported, shadows_selected, mask_selected, mask_cleaned, ]) # check if mask alrady exist if gs.find_file(name=map_name, element=output)["file"] and not overwrite: gs.message( _("option <output>: <{}> exists. To overwrite, use the --overwrite flag" .format(map_name))) continue try: # Import & Threshold cloud probability layer gs.message( _("Importing cloud mask for {}").format("_".join( [items[5], items[2]]))) if reproject: self._args["resolution_value"] = self._raster_resolution(f) self._args["resample"] = "bilinear" gs.run_command("r.import", input=f, output=clouds_imported, **self._args) else: gs.run_command("r.in.gdal", input=f, output=clouds_imported, **self._args) gs.use_temp_region() gs.run_command("g.region", raster=clouds_imported) gs.mapcalc( f"{clouds_selected} = if({clouds_imported} >= {prob_threshold}, 1, 0)" ) gs.del_temp_region() # Add shadow mask if shadows: try: shadow_file = self._filter("_".join( [items[5], items[2], "SCL_20m.jp2"])) if reproject: self._args[ "resolution_value"] = self._raster_resolution( shadow_file[0]) self._args["resample"] = "nearest" gs.run_command( "r.import", input=shadow_file, output=shadows_imported, **self._args, ) else: gs.run_command( "r.in.gdal", input=shadow_file, output=shadows_imported, **self._args, ) gs.use_temp_region() gs.run_command("g.region", raster=shadows_imported) gs.mapcalc( f"{shadows_selected} = if({shadows_imported} == 3, 2, 0)" ) gs.mapcalc( f"{mask_selected} = max({shadows_selected},{clouds_selected})" ) gs.del_temp_region() except Exception as e: gs.warning( _("Unable to import shadows for {}. Error: {}"). format("_".join([items[5], items[2]]), e)) else: gs.run_command("g.rename", quiet=True, raster=(clouds_selected, mask_selected)) gs.use_temp_region() gs.run_command("g.region", raster=mask_selected) # Cleaning small patches try: gs.run_command( "r.reclass.area", input=mask_selected, output=mask_cleaned, value=area_threshold, mode="greater", ) except Exception as e: pass # error already printed # Extract & Label clouds (and shadows) gs.run_command("r.null", map=mask_cleaned, setnull="0") labels = ["1:clouds", "2:shadows"] labelling = gs.feed_command("r.category", map=mask_cleaned, separator=":", rules="-") labelling.stdin.write("\n".join(labels).encode()) labelling.stdin.close() labelling.wait() info_stats = gs.parse_command("r.stats", input=mask_cleaned, flags="p") # Create final cloud (and shadow) mask & display areal statistics if output == "vector": gs.run_command( "r.to.vect", input=mask_cleaned, output=map_name, type="area", flags="s", ) colours = ["1 230:230:230", "2 60:60:60"] colourise = gs.feed_command( "v.colors", map=map_name, use="attr", column="value", rules="-", quiet=True, ) colourise.stdin.write("\n".join(colours).encode()) colourise.stdin.close() colourise.wait() gs.vector_history(map_name) else: gs.run_command("g.rename", quiet=True, raster=(mask_cleaned, map_name)) colours = ["1 230:230:230", "2 60:60:60"] colourise = gs.feed_command("r.colors", map=map_name, rules="-", quiet=True) colourise.stdin.write("\n".join(colours).encode()) colourise.stdin.close() colourise.wait() gs.raster_history(map_name) gs.message( _("Areal proportion of masked clouds:{}").format( [key.split()[1] for key in info_stats][0])) if shadows: if len(info_stats) > 2: gs.message( _("Areal proportion of masked shadows:{}").format( [key.split()[1] for key in info_stats][1])) else: gs.message(_("Areal proportion of masked shadows:0%")) gs.del_temp_region() except Exception as e: gs.del_temp_region() gs.warning( _("Unable to import cloud mask for {}. Error: {}").format( "_".join([items[5], items[2]]), e)) # Import of simplified cloud masks for Level-1C products all_files = self._filter("MSK_CLOUDS_B00.gml") files_L1C = [] for f in all_files: safe_dir = os.path.dirname(f).split(os.path.sep)[-4] if safe_dir not in [ os.path.dirname(file).split(os.path.sep)[-4] for file in files_L2A ]: files_L1C.append(f) if len(files_L1C) > 0: from osgeo import ogr for f in files_L1C: safe_dir = os.path.dirname(f).split(os.path.sep)[-4] items = safe_dir.split("_") # Define names of final & temporary maps map_name = "_".join([items[5], items[2], "MSK", "CLOUDS"]) clouds_imported = "_".join( [items[5], items[2], "clouds_imported"]) mask_cleaned = "_".join([items[5], items[2], "mask_cleaned"]) self._map_list.extend([clouds_imported, mask_cleaned]) # check if mask alrady exist if (gs.find_file(name=map_name, element=output)["file"] and not overwrite): gs.fatal( _("option <output>: <{}> exists. To overwrite, use the --overwrite flag" .format(map_name))) continue # check if any OGR layer dsn = ogr.Open(f) layer_count = dsn.GetLayerCount() dsn.Destroy() if layer_count < 1: gs.info( "No clouds layer found in <{}>. Import skipped".format( f)) continue # Import cloud layer try: gs.message( _("Importing cloud mask for {}").format("_".join( [items[5], items[2]]))) gs.run_command( "v.import", input=f, output=clouds_imported, extent=options["extent"], flags="o" if flags["o"] else None, quiet=True, ) gs.use_temp_region() gs.run_command("g.region", vector=clouds_imported) # Cleaning small patches gs.run_command( "v.clean", input=clouds_imported, output=mask_cleaned, tool="rmarea", threshold=area_threshold, ) # Calculating info stats gs.run_command("v.db.addcolumn", map=mask_cleaned, columns="value_num INT") gs.run_command("v.db.update", map=mask_cleaned, column="value_num", value=1) gs.run_command( "v.to.rast", input=mask_cleaned, output=mask_cleaned, use="attr", attribute_column="value_num", quiet=True, ) info_stats = gs.parse_command("r.stats", input=mask_cleaned, flags="p") # Create final cloud mask output if output == "vector": gs.run_command("g.rename", quiet=True, vector=(mask_cleaned, map_name)) colours = ["1 230:230:230"] colourise = gs.feed_command( "v.colors", map=map_name, use="attr", column="value_num", rules="-", quiet=True, ) colourise.stdin.write("\n".join(colours).encode()) colourise.stdin.close() colourise.wait() gs.vector_history(map_name) else: gs.run_command("g.rename", quiet=True, raster=(mask_cleaned, map_name)) colours = ["1 230:230:230"] colourise = gs.feed_command("r.colors", map=map_name, rules="-", quiet=True) colourise.stdin.write("\n".join(colours).encode()) colourise.stdin.close() colourise.wait() gs.raster_history(map_name) # Display messages & statistics if shadows: gs.warning( _("Level1 product: No shadow mask for {}").format( "_".join([items[5], items[2]]))) gs.message( _("Areal proportion of masked clouds:{}").format( [key.split()[1] for key in info_stats][0])) gs.del_temp_region() except Exception as e: gs.del_temp_region() gs.warning( _("Unable to import cloud mask for {}. Error: {}"). format("_".join([items[5], items[2]]), e))
def main(): global tile, tmpdir, in_temp in_temp = False input = options['input'] output = options['output'] one = flags['1'] # are we in LatLong location? s = grass.read_command("g.proj", flags='j') kv = grass.parse_key_val(s) if kv['+proj'] != 'longlat': grass.fatal(_("This module only operates in LatLong locations")) # use these from now on: infile = input while infile[-4:].lower() in ['.hgt', '.zip']: infile = infile[:-4] (fdir, tile) = os.path.split(infile) if not output: tileout = tile else: tileout = output zipfile = infile + ".hgt.zip" hgtfile = os.path.join(fdir, tile[:7] + ".hgt") if os.path.isfile(zipfile): # check if we have unzip if not grass.find_program('unzip'): grass.fatal( _('The "unzip" program is required, please install it first')) # really a ZIP file? # make it quiet in a safe way (just in case -qq isn't portable) tenv = os.environ.copy() tenv['UNZIP'] = '-qq' if grass.call(['unzip', '-t', zipfile], env=tenv) != 0: grass.fatal( _("'%s' does not appear to be a valid zip file.") % zipfile) is_zip = True elif os.path.isfile(hgtfile): # try and see if it's already unzipped is_zip = False else: grass.fatal(_("File '%s' or '%s' not found") % (zipfile, hgtfile)) # make a temporary directory tmpdir = grass.tempfile() grass.try_remove(tmpdir) os.mkdir(tmpdir) if is_zip: shutil.copyfile(zipfile, os.path.join(tmpdir, tile + ".hgt.zip")) else: shutil.copyfile(hgtfile, os.path.join(tmpdir, tile + ".hgt")) # change to temporary directory os.chdir(tmpdir) in_temp = True zipfile = tile + ".hgt.zip" hgtfile = tile[:7] + ".hgt" bilfile = tile + ".bil" if is_zip: # unzip & rename data file: grass.message(_("Extracting '%s'...") % infile) if grass.call(['unzip', zipfile], env=tenv) != 0: grass.fatal(_("Unable to unzip file.")) grass.message(_("Converting input file to BIL...")) os.rename(hgtfile, bilfile) north = tile[0] ll_latitude = int(tile[1:3]) east = tile[3] ll_longitude = int(tile[4:7]) # are we on the southern hemisphere? If yes, make LATITUDE negative. if north == "S": ll_latitude *= -1 # are we west of Greenwich? If yes, make LONGITUDE negative. if east == "W": ll_longitude *= -1 # Calculate Upper Left from Lower Left ulxmap = "%.1f" % ll_longitude # SRTM90 tile size is 1 deg: ulymap = "%.1f" % (ll_latitude + 1) if not one: tmpl = tmpl3sec else: grass.message(_("Attempting to import 1-arcsec data.")) tmpl = tmpl1sec header = tmpl % (ulxmap, ulymap) hdrfile = tile + '.hdr' outf = file(hdrfile, 'w') outf.write(header) outf.close() # create prj file: To be precise, we would need EGS96! But who really cares... prjfile = tile + '.prj' outf = file(prjfile, 'w') outf.write(proj) outf.close() try: grass.run_command('r.in.gdal', input=bilfile, out=tileout) except: grass.fatal(_("Unable to import data")) # nice color table grass.run_command('r.colors', map=tileout, color='srtm') # write cmd history: grass.raster_history(tileout) grass.message(_("Done: generated map ") + tileout) grass.message( _("(Note: Holes in the data can be closed with 'r.fillnulls' using splines)" ))