def radiance_to_brightness_temperature(outname, radiance, temperature_expression): """ Convert Spectral Radiance to At-Satellite Brightness Temperature. For details see Landsat8 class. """ temperature_expression = replace_dummies( temperature_expression, instring=DUMMY_MAPCALC_STRING_RADIANCE, outstring=radiance) msg = "\n|i Converting spectral radiance to at-Satellite Temperature " if info: msg += "| Expression: " + str(temperature_expression) g.message(msg) temperature_equation = equation.format(result=outname, expression=temperature_expression) grass.mapcalc(temperature_equation, overwrite=True) if info: run('r.info', map=outname, flags='r') #run('r.univar', map=outname) del (temperature_expression) del (temperature_equation)
def main(): """ RichDEM depression filling """ # lazy import RICHDEM try: import richdem as rd except: g.message(flags='e', message=('RichDEM not detected. Install pip3 and ' + 'then type at the command prompt: ' + '"pip3 install richdem".')) _input = options['input'] _output = options['output'] _epsilon = options['epsilon'] _topology = options['topology'] if _epsilon == 'true': epsilon = True else: epsilon = False dem = garray.array() dem.read(_input, null=np.nan) rd_inout = rd.rdarray(dem, no_data=np.nan) rd.FillDepressions(dem=rd_inout, epsilon=epsilon, in_place=True, topology=_topology) dem[:] = rd_inout[:] dem.write(_output, overwrite=gscript.overwrite())
def radiance_to_brightness_temperature( outname, radiance, temperature_expression, quiet=False, ): """ Convert Spectral Radiance to At-Satellite Brightness Temperature. For details see Landsat8 class. """ temperature_expression = replace_dummies( temperature_expression, instring=DUMMY_MAPCALC_STRING_RADIANCE, outstring=radiance, ) msg = "\n|i Converting spectral radiance to at-Satellite Temperature " if not quiet: msg += "| Expression: " + str(temperature_expression) g.message(msg) temperature_equation = EQUATION.format(result=outname, expression=temperature_expression) grass.mapcalc(temperature_equation, overwrite=True) if not quiet: run("r.info", map=outname, flags="r")
def main(): g.message("Pocitam NDVI...") # nastavit region g.region(rast=options['tm4']) # vypocitat NDVI r.mapcalc('ndvi = float({y} - {x}) / ({y} + {x})'.format(x=options['tm3'], y=options['tm4']), overwrite=True) # r.reclass podporuje pouze datovy typ CELL r.mapcalc('temp1 = 100 * ndvi', overwrite=True) g.message("Reklasifikuji data...") # reklasifikovat data reclass_rules = """-100 thru 5 = 1 bez vegetace, vodni plochy 5 thru 35 = 2 plochy s minimalni vegetaci 35 thru 100 = 3 plochy pokryte vegetaci""" r.reclass(overwrite=True, rules='-', input='temp1', output='r_ndvi', stdin_=reclass_rules) # nastavit tabulku barev color_rules = """1 red 2 yellow 3 0 136 26""" r.colors(quiet=True, map='r_ndvi', rules='-', stdin_=color_rules) # vytiskout zakladni charakteristiku dat r.report(map='r_ndvi', units=['c', 'p', 'h'])
def determine_average_emissivity( outname, emissivity_output, landcover_map, avg_lse_expression, quiet=True, ): """ Produce an average emissivity map based on FROM-GLC map covering the region of interest. """ msg = ( '\n|i Determining average land surface emissivity based on a look-up table ' ) if not quiet: msg += ('| Expression:\n\n {exp}') msg = msg.format(exp=avg_lse_expression) g.message(msg) avg_lse_expression = replace_dummies( avg_lse_expression, instring=DUMMY_MAPCALC_STRING_FROM_GLC, outstring=landcover_map, ) avg_lse_equation = EQUATION.format( result=outname, expression=avg_lse_expression, ) grass.mapcalc(avg_lse_equation, overwrite=True) if not quiet: run('r.info', map=outname, flags='r') # save land surface emissivity map? if emissivity_output: run('g.rename', raster=(outname, emissivity_output))
def determine_delta_emissivity(outname, landcover_map, delta_lse_expression): """ Produce a delta emissivity map based on the FROM-GLC map covering the region of interest. """ msg = ('\n|i Determining delta land surface emissivity based on a ' 'look-up table ') if info: msg += ('| Expression:\n\n {exp}') msg = msg.format(exp=delta_lse_expression) g.message(msg) delta_lse_expression = replace_dummies( delta_lse_expression, instring=DUMMY_MAPCALC_STRING_FROM_GLC, outstring=landcover_map) delta_lse_equation = equation.format(result=outname, expression=delta_lse_expression) grass.mapcalc(delta_lse_equation, overwrite=True) if info: run('r.info', map=outname, flags='r') del (delta_lse_expression) del (delta_lse_equation) # save delta land surface emissivity map? if delta_emissivity_output: run('g.rename', raster=(outname, delta_emissivity_output))
def estimate_column_water_vapor(outname, ratio, cwv_expression): """ *** This function is NOT used. It was part of an initial step-by-step approach, while coding and testing. Kept for future plans!? *** """ msg = "\n|i Estimating atmospheric column water vapor " msg += '| Mapcalc expression: ' msg += cwv_expression g.message(msg) cwv_expression = replace_dummies(cwv_expression, instring=DUMMY_Rji, outstring=ratio) cwv_equation = equation.format(result=outname, expression=cwv_expression) grass.mapcalc(cwv_equation, overwrite=True) if info: run('r.info', map=outname, flags='r') # save Column Water Vapor map? if cwv_output: run('g.rename', raster=(outname, cwv_output))
def estimate_ratio_ji(outname, tmp_ti_mean, tmp_tj_mean, ratio_expression): """ *** This function is NOT used. It was part of an initial step-by-step approach, while coding and testing. Kept for future plans!? *** Estimate Ratio ji for the Column Water Vapor retrieval equation. """ msg = '\n |i Estimating ratio Rji...' msg += '\n' + ratio_expression g.message(msg) ratio_expression = replace_dummies(ratio_expression, in_ti=DUMMY_Ti_MEAN, out_ti=tmp_ti_mean, in_tj=DUMMY_Tj_MEAN, out_tj=tmp_tj_mean) ratio_equation = equation.format(result=outname, expression=ratio_expression) grass.mapcalc(ratio_equation, overwrite=True) if info: run('r.info', map=outname, flags='r')
def determine_delta_emissivity( outname, delta_emissivity_output, landcover_map, delta_lse_expression, quiet=True, ): """ Produce a delta emissivity map based on the FROM-GLC map covering the region of interest. """ msg = "\n|i Determining delta land surface emissivity based on a " "look-up table " if not quiet: msg += "| Expression:\n\n {exp}" msg = msg.format(exp=delta_lse_expression) g.message(msg) delta_lse_expression = replace_dummies( delta_lse_expression, instring=DUMMY_MAPCALC_STRING_FROM_GLC, outstring=landcover_map, ) delta_lse_equation = EQUATION.format(result=outname, expression=delta_lse_expression) grass.mapcalc(delta_lse_equation, overwrite=True) if not quiet: run("r.info", map=outname, flags="r") # save delta land surface emissivity map? if delta_emissivity_output: run("g.rename", raster=(outname, delta_emissivity_output))
def main(): """ RichDEM flat resolution: give a gentle slope """ # lazy import RICHDEM try: import richdem as rd except: g.message(flags='e', message=('RichDEM not detected. Install pip3 and ' + 'then type at the command prompt: ' + '"pip3 install richdem".')) _input = options['input'] _output = options['output'] # Check for overwrite _rasters = np.array(gscript.parse_command('g.list', type='raster').keys()) if (_rasters == _output).any(): g.message(flags='e', message="output would overwrite " + _output) dem = garray.array() dem.read(_input, null=np.nan) rd_input = rd.rdarray(dem, no_data=np.nan) rd_output = rd.ResolveFlats(rd_input) dem[:] = rd_output[:] dem.write(_output, overwrite=gscript.overwrite())
def extract_tgz(tgz): """ Decompress and unpack a .tgz file """ g.message(_('Extracting files from tar.gz file')) # open tar.gz file in read mode tar = tarfile.TarFile.open(name=tgz, mode='r') # get the scene's (base)name tgz_base = os.path.basename(tgz).split('.tar.gz')[0] # try to create a directory with the scene's (base)name # source: <http://stackoverflow.com/a/14364249/1172302> try: os.makedirs(tgz_base) # if something went wrong, raise an error except OSError: if not os.path.isdir(tgz_base): raise # extract files indide the scene directory tar.extractall(path=tgz_base)
def mask_clouds(qa_band, qa_pixel): """ ToDo: - a better, independent mechanism for QA. --> see also Landsat8 class. - support for multiple qa_pixel values (eg. input as a list of values) Create and apply a cloud mask based on the Quality Assessment Band (BQA.) Source: <http://landsat.usgs.gov/L8QualityAssessmentBand.php See also: http://courses.neteler.org/processing-landsat8-data-in-grass-gis-7/#Applying_the_Landsat_8_Quality_Assessment_%28QA%29_Band """ msg = ('\n|i Masking for pixel values <{qap}> ' 'in the Quality Assessment band.'.format(qap=qa_pixel)) g.message(msg) #tmp_cloudmask = tmp_map_name('cloudmask') #qabits_expression = 'if({band} == {pixel}, 1, null())'.format(band=qa_band, # pixel=qa_pixel) #cloud_masking_equation = equation.format(result=tmp_cloudmask, # expression=qabits_expression) #grass.mapcalc(cloud_masking_equation) r.mask(raster=qa_band, maskcats=qa_pixel, flags='i', overwrite=True)
def identify_product_collection(scene): """ Identify the collection and the validity of a Landsat scene product identifier by trying to match it against pre-defined regular expression templates. Parameters ---------- scene : A Landsat product identifier string template : A list of regular expression templates against which to validate the 'scene' string Returns ------- ... Raises ------ ... """ for template_key in LANDSAT_IDENTIFIERS['scene_template']: template = LANDSAT_IDENTIFIERS['scene_template'][template_key] try: # re.match(pattern, string, flags=0) if re.match(template, scene): return template_key except: g.message(_("No match"))
def main(): g.message("Pocitam NDVI...") # nastavit region g.region(rast=options['tm4']) # vypocitat NDVI r.mapcalc('ndvi = float({y} - {x}) / ({y} + {x})'.format(x=options['tm3'], y=options['tm4']), overwrite = True) # r.reclass podporuje pouze datovy typ CELL r.mapcalc('temp1 = 100 * ndvi', overwrite = True) g.message("Reklasifikuji data...") # reklasifikovat data reclass_rules = """-100 thru 5 = 1 bez vegetace, vodni plochy 5 thru 35 = 2 plochy s minimalni vegetaci 35 thru 100 = 3 plochy pokryte vegetaci""" r.reclass(overwrite = True, rules = '-', input = 'temp1', output = 'r_ndvi', stdin_ = reclass_rules) # nastavit tabulku barev color_rules = """1 red 2 yellow 3 0 136 26""" r.colors(quiet = True, map = 'r_ndvi', rules = '-', stdin_ = color_rules) # vytiskout zakladni charakteristiku dat r.report(map = 'r_ndvi', units = ['c', 'p', 'h'])
def main(): """ RichDEM depression breaching """ # lazy import RICHDEM try: import richdem as rd except: g.message( flags="e", message=("RichDEM not detected. Install pip3 and " + "then type at the command prompt: " + '"pip3 install richdem".'), ) _input = options["input"] _output = options["output"] _topology = options["topology"] dem = garray.array() dem.read(_input, null=np.nan) rd_inout = rd.rdarray(dem, no_data=np.nan) rd.BreachDepressions(dem=rd_inout, in_place=True, topology=_topology) dem[:] = rd_inout[:] dem.write(_output, overwrite=gscript.overwrite())
def determine_delta_emissivity(outname, landcover_map, delta_lse_expression): """ Produce a delta emissivity map based on the FROM-GLC map covering the region of interest. """ msg = ('\n|i Determining delta land surface emissivity based on a ' 'look-up table ') if info: msg += ('| Expression:\n\n {exp}') msg = msg.format(exp=delta_lse_expression) g.message(msg) delta_lse_expression = replace_dummies(delta_lse_expression, instring=DUMMY_MAPCALC_STRING_FROM_GLC, outstring=landcover_map) delta_lse_equation = equation.format(result=outname, expression=delta_lse_expression) grass.mapcalc(delta_lse_equation, overwrite=True) if info: run('r.info', map=outname, flags='r') del(delta_lse_expression) del(delta_lse_equation) # save delta land surface emissivity map? if delta_emissivity_output: run('g.rename', raster=(outname, delta_emissivity_output))
def main(): """ RichDEM flat resolution: give a gentle slope """ # lazy import RICHDEM try: import richdem as rd except: g.message( flags="e", message=("RichDEM not detected. Install pip3 and " + "then type at the command prompt: " + '"pip3 install richdem".'), ) _input = options["input"] _output = options["output"] _attribute = options["attribute"] _zscale = float(options["zscale"]) dem = garray.array() dem.read(_input, null=np.nan) rd_input = rd.rdarray(dem, no_data=np.nan) del dem rd_output = rd.TerrainAttribute(dem=rd_input, attrib=_attribute, zscale=_zscale) outarray = garray.array() outarray[:] = rd_output[:] outarray.write(_output, overwrite=gscript.overwrite())
def digital_numbers_to_radiance(outname, band, radiance_expression): """ Convert Digital Number values to TOA Radiance. For details, see in Landsat8 class. Zero (0) DNs set to NULL here (not via the class' function). """ if null: msg = "\n|i Setting zero (0) Digital Numbers in {band} to NULL" msg = msg.format(band=band) g.message(msg) run('r.null', map=band, setnull=0) msg = "\n|i Rescaling {band} digital numbers to spectral radiance " msg = msg.format(band=band) if info: msg += '| Expression: ' msg += radiance_expression g.message(msg) radiance_expression = replace_dummies(radiance_expression, instring=DUMMY_MAPCALC_STRING_DN, outstring=band) radiance_equation = equation.format(result=outname, expression=radiance_expression) grass.mapcalc(radiance_equation, overwrite=True) if info: run('r.info', map=outname, flags='r') #run('r.univar', map=outname) del(radiance_expression) del(radiance_equation)
def radiance_to_brightness_temperature(outname, radiance, temperature_expression): """ Convert Spectral Radiance to At-Satellite Brightness Temperature. For details see Landsat8 class. """ temperature_expression = replace_dummies(temperature_expression, instring=DUMMY_MAPCALC_STRING_RADIANCE, outstring=radiance) msg = "\n|i Converting spectral radiance to at-Satellite Temperature " if info: msg += "| Expression: " + str(temperature_expression) g.message(msg) temperature_equation = equation.format(result=outname, expression=temperature_expression) grass.mapcalc(temperature_equation, overwrite=True) if info: run('r.info', map=outname, flags='r') #run('r.univar', map=outname) del(temperature_expression) del(temperature_equation)
def digital_numbers_to_radiance(outname, band, radiance_expression): """ Convert Digital Number values to TOA Radiance. For details, see in Landsat8 class. Zero (0) DNs set to NULL here (not via the class' function). """ if null: msg = "\n|i Setting zero (0) Digital Numbers in {band} to NULL" msg = msg.format(band=band) g.message(msg) run('r.null', map=band, setnull=0) msg = "\n|i Rescaling {band} digital numbers to spectral radiance " msg = msg.format(band=band) if info: msg += '| Expression: ' msg += radiance_expression g.message(msg) radiance_expression = replace_dummies(radiance_expression, instring=DUMMY_MAPCALC_STRING_DN, outstring=band) radiance_equation = equation.format(result=outname, expression=radiance_expression) grass.mapcalc(radiance_equation, overwrite=True) if info: run('r.info', map=outname, flags='r') #run('r.univar', map=outname) del (radiance_expression) del (radiance_equation)
def estimate_lst(outname, t10, t11, avg_lse_map, delta_lse_map, cwv_map, lst_expression): """ Produce a Land Surface Temperature map based on a mapcalc expression returned from a SplitWindowLST object. Inputs are: - brightness temperature maps t10, t11 - column water vapor map - a temporary filename - a valid mapcalc expression """ msg = '\n|i Estimating land surface temperature ' if info: msg += "| Expression:\n" g.message(msg) if info: msg = lst_expression msg += '\n' print msg # replace the "dummy" string... if landcover_map: split_window_expression = replace_dummies(lst_expression, in_avg_lse=DUMMY_MAPCALC_STRING_AVG_LSE, out_avg_lse=avg_lse_map, in_delta_lse=DUMMY_MAPCALC_STRING_DELTA_LSE, out_delta_lse=delta_lse_map, in_cwv=DUMMY_MAPCALC_STRING_CWV, out_cwv=cwv_map, in_ti=DUMMY_MAPCALC_STRING_T10, out_ti=t10, in_tj=DUMMY_MAPCALC_STRING_T11, out_tj=t11) elif emissivity_class: split_window_expression = replace_dummies(lst_expression, in_cwv=DUMMY_MAPCALC_STRING_CWV, out_cwv=cwv_map, in_ti=DUMMY_MAPCALC_STRING_T10, out_ti=t10, in_tj=DUMMY_MAPCALC_STRING_T11, out_tj=t11) # Convert to Celsius? if celsius: split_window_expression = '({swe}) - 273.15'.format(swe=split_window_expression) split_window_equation = equation.format(result=outname, expression=split_window_expression) else: split_window_equation = equation.format(result=outname, expression=split_window_expression) grass.mapcalc(split_window_equation, overwrite=True) if info: run('r.info', map=outname, flags='r') del(split_window_expression) del(split_window_equation)
def estimate_lst(outname, t10, t11, avg_lse_map, delta_lse_map, cwv_map, lst_expression): """ Produce a Land Surface Temperature map based on a mapcalc expression returned from a SplitWindowLST object. Inputs are: - brightness temperature maps t10, t11 - column water vapor map - a temporary filename - a valid mapcalc expression """ msg = '\n|i Estimating land surface temperature ' if info: msg += "| Expression:\n" g.message(msg) if info: msg = lst_expression msg += '\n' print(msg) # replace the "dummy" string... if landcover_map: split_window_expression = replace_dummies(lst_expression, in_avg_lse=DUMMY_MAPCALC_STRING_AVG_LSE, out_avg_lse=avg_lse_map, in_delta_lse=DUMMY_MAPCALC_STRING_DELTA_LSE, out_delta_lse=delta_lse_map, in_cwv=DUMMY_MAPCALC_STRING_CWV, out_cwv=cwv_map, in_ti=DUMMY_MAPCALC_STRING_T10, out_ti=t10, in_tj=DUMMY_MAPCALC_STRING_T11, out_tj=t11) elif emissivity_class: split_window_expression = replace_dummies(lst_expression, in_cwv=DUMMY_MAPCALC_STRING_CWV, out_cwv=cwv_map, in_ti=DUMMY_MAPCALC_STRING_T10, out_ti=t10, in_tj=DUMMY_MAPCALC_STRING_T11, out_tj=t11) # Convert to Celsius? if celsius: split_window_expression = '({swe}) - 273.15'.format(swe=split_window_expression) split_window_equation = equation.format(result=outname, expression=split_window_expression) else: split_window_equation = equation.format(result=outname, expression=split_window_expression) grass.mapcalc(split_window_equation, overwrite=True) if info: run('r.info', map=outname, flags='r') del(split_window_expression) del(split_window_equation)
def main(): """ RichDEM flat resolution: give a gentle slope """ # lazy import RICHDEM try: import richdem as rd except: g.message( flags="e", message=("RichDEM not detected. Install pip3 and " + "then type at the command prompt: " + '"pip3 install richdem".'), ) _input = options["input"] _output = options["output"] _method = options["method"] _exponent = options["exponent"] _weights = options["weights"] if (_method == "Holmgren") or (_method == "Freeman"): if _exponent == "": g.message( flags="w", message=("Exponent must be defined for " + "Holmgren or Freeman methods. " + "Exiting."), ) return else: _exponent = float(_exponent) else: _exponent = None if _weights == "": rd_weights = None else: g_weights = garray.array(_weights, null=np.nan) rd_weights = rd.rdarray(g_weights, no_data=np.nan) dem = garray.array(_input, null=np.nan) mask = dem * 0 + 1 rd_input = rd.rdarray(dem, no_data=np.nan) del dem rd_output = rd.FlowAccumulation( dem=rd_input, method=_method, exponent=_exponent, weights=rd_weights, in_place=False, ) rd_output *= mask accum = garray.array() accum[:] = rd_output[:] accum.write(_output, overwrite=gscript.overwrite())
def estimate_cwv_big_expression( outname, cwv_output, t10, t11, cwv_expression, quiet=True, ): """ Derive a column water vapor map using a single mapcalc expression based on eval. *** To Do: evaluate -- does it work correctly? *** ! """ msg = "\n|i Estimating atmospheric column water vapor " if quiet: msg += "| Expression:\n" g.message(msg) if quiet: msg = replace_dummies(cwv_expression, in_ti=t10, out_ti="T10", in_tj=t11, out_tj="T11") msg += "\n" g.message(msg) cwv_equation = EQUATION.format(result=outname, expression=cwv_expression) grass.mapcalc(cwv_equation, overwrite=True) if quiet: run("r.info", map=outname, flags="r") # save Column Water Vapor map? if cwv_output: # strings for metadata history_cwv = "FixMe -- Column Water Vapor model: " history_cwv += "FixMe -- Add equation?" title_cwv = "Column Water Vapor" description_cwv = "Column Water Vapor" units_cwv = "g/cm^2" source1_cwv = "FixMe" source2_cwv = "FixMe" # history entry run( "r.support", map=outname, title=title_cwv, units=units_cwv, description=description_cwv, source1=source1_cwv, source2=source2_cwv, history=history_cwv, ) run("g.rename", raster=(outname, cwv_output))
def main(): """ RichDEM flat resolution: give a gentle slope """ # lazy import RICHDEM try: import richdem as rd except: g.message(flags='e', message=('RichDEM not detected. Install pip3 and ' + 'then type at the command prompt: ' + '"pip3 install richdem".')) options, flags = gscript.parser() _input = options['input'] _output = options['output'] _method = options['method'] _exponent = options['exponent'] _weights = options['weights'] if (_method == 'Holmgren') or (_method == 'Freeman'): if _exponent == '': g.message(flags='w', message=('Exponent must be defined for ' + 'Holmgren or Freeman methods. ' + 'Exiting.')) return else: _exponent = float(_exponent) else: _exponent = None if _weights == '': rd_weights = None else: g_weights = garray.array() g_weights.read(_weights, null=np.nan) rd_weights = rd.rdarray(g_weights, no_data=np.nan) dem = garray.array() dem.read(_input, null=np.nan) mask = dem * 0 + 1 rd_input = rd.rdarray(dem, no_data=np.nan) del dem rd_output = rd.FlowAccumulation(dem=rd_input, method=_method, exponent=_exponent, weights=rd_weights, in_place=False) rd_output *= mask accum = garray.array() accum[:] = rd_output[:] accum.write(_output, overwrite=gscript.overwrite())
def hpf_ascii(center, filter, tmpfile, second_pass): """Exporting a High Pass Filter in a temporary ASCII file""" # structure informative message msg = " > {m}Filter Properties: center: {c}" msg_pass = '******' if second_pass else '' msg = msg.format(m=msg_pass, c=center) g.message(msg, flags='v') # open, write and close file with open(tmpfile, 'w') as asciif: asciif.write(filter)
def list_files_in_tar(tgz): """List files in tar.gz file""" g.message(_('Listing files in tar.gz file')) # open tar.gz file in read mode tar = tarfile.TarFile.open(name=tgz, mode='r') # get names members = tar.getnames() # print out g.message(_(members))
def estimate_cwv_big_expression(outname, t10, t11, cwv_expression): """ Derive a column water vapor map using a single mapcalc expression based on eval. *** To Do: evaluate -- does it work correctly? *** ! """ msg = "\n|i Estimating atmospheric column water vapor " if info: msg += '| Expression:\n' g.message(msg) if info: msg = replace_dummies(cwv_expression, in_ti=t10, out_ti='T10', in_tj=t11, out_tj='T11') msg += '\n' print msg cwv_equation = equation.format(result=outname, expression=cwv_expression) grass.mapcalc(cwv_equation, overwrite=True) if info: run('r.info', map=outname, flags='r') # save Column Water Vapor map? if cwv_output: # strings for metadata history_cwv = 'FixMe -- Column Water Vapor model: ' history_cwv += 'FixMe -- Add equation?' title_cwv = 'Column Water Vapor' description_cwv = 'Column Water Vapor' units_cwv = 'g/cm^2' source1_cwv = 'FixMe' source2_cwv = 'FixMe' # history entry run("r.support", map=outname, title=title_cwv, units=units_cwv, description=description_cwv, source1=source1_cwv, source2=source2_cwv, history=history_cwv) run('g.rename', raster=(outname, cwv_output)) del (cwv_expression) del (cwv_equation)
def unlink_directory(directory, elements_to_unlink, dry_run=True, force=False): """ """ if (pathlib.PurePosixPath(directory).joinpath('r.InternalLink') in pathlib.Path(directory).glob('**/r.InternalLink')): if not os.path.islink(directory): if not force: review_unlinking_directory = MESSAGE_REVIEW_UNLINKING_DIRECTORY.format( directory=directory) g.message(review_unlinking_directory, flags='w') g.message('\n') elements_to_unlink.append(directory)
def list_files_in_tar(tgz): """List files in tar.gz file""" compressed_scene = os.path.basename(tgz) g.message(_(f'Reading compressed scene \'{compressed_scene}\'...')) tar = tarfile.TarFile.open(name=tgz, mode='r') members = tar.getnames() members = """ {} """.format('\n'.join(members[1:])) index_of_dot = compressed_scene.index('.') scene = compressed_scene[:index_of_dot] message = f'List of files in {scene}' message += members g.message(_(message))
def hpf_weight(low_sd, hpf_sd, mod, pss): """Returning an appropriate weighting value for the High Pass Filtered image. The required inputs are: - low_sd: StdDev of Low resolution image - hpf_sd: StdDev of High Pass Filtered image - mod: Appropriate Modulating Factor determining image crispness - pss: Number of Pass (1st or 2nd)""" wgt = low_sd / hpf_sd * mod # mod: modulator msg = ' >> ' if pss == 2: msg += '2nd Pass ' msg += 'Weighting = {l:.{dec}f} / {h:.{dec}f} * {m:.{dec}f} = {w:.{dec}f}' msg = msg.format(l=low_sd, h=hpf_sd, m=mod, w=wgt, dec=3) g.message(msg, flags='v') return wgt
def remove_temporary_maps(save_temporary_maps=False): """Clean up temporary maps""" # options, flags = grass.parser() # if not flags['s']: # 's' for save temporary maps if not save_temporary_maps: g.message("Removing temporary maps") g.remove( flags="f", type="raster", pattern="tmp.{pid}*".format(pid=os.getpid()), quiet=True, ) else: msg = "I will not remove temporary maps in order to support your debugging!" msg += "Take care to remove them, i.e. via `g.remove raster pattern=tmp.*`" grass.warning(_(msg))
def estimate_cwv_big_expression(outname, t10, t11, cwv_expression): """ Derive a column water vapor map using a single mapcalc expression based on eval. *** To Do: evaluate -- does it work correctly? *** ! """ msg = "\n|i Estimating atmospheric column water vapor " if info: msg += '| Expression:\n' g.message(msg) if info: msg = replace_dummies(cwv_expression, in_ti=t10, out_ti='T10', in_tj=t11, out_tj='T11') msg += '\n' print msg cwv_equation = equation.format(result=outname, expression=cwv_expression) grass.mapcalc(cwv_equation, overwrite=True) if info: run('r.info', map=outname, flags='r') # save Column Water Vapor map? if cwv_output: # strings for metadata history_cwv = 'FixMe -- Column Water Vapor model: ' history_cwv += 'FixMe -- Add equation?' title_cwv = 'Column Water Vapor' description_cwv = 'Column Water Vapor' units_cwv = 'g/cm^2' source1_cwv = 'FixMe' source2_cwv = 'FixMe' # history entry run("r.support", map=outname, title=title_cwv, units=units_cwv, description=description_cwv, source1=source1_cwv, source2=source2_cwv, history=history_cwv) run('g.rename', raster=(outname, cwv_output)) del(cwv_expression) del(cwv_equation)
def print_timestamp(scene, timestamp, tgis=False): """ Print out the timestamp """ date = timestamp['date'] date_Ymd = datetime.strptime(date, "%Y-%m-%d") date_tgis = datetime.strftime(date_Ymd, "%d %b %Y") hours = str(timestamp['hours']) minutes = str(timestamp['minutes']) seconds = str(timestamp['seconds']) timezone = timestamp['timezone'] time = ':'.join((hours, minutes, seconds)) string_parse_time = "%H:%M:%S" if '.' not in time: time += '.000000' if '.' in time: string_parse_time += ".%f" time = datetime.strptime(time, string_parse_time) time = datetime.strftime(time, string_parse_time) message = 'Date\t\tTime\n' message += '\t{date}\t{time} {timezone}\n\n' # if -t requested if tgis: # verbose if -t instructed os.environ['GRASS_VERBOSE'] = GRASS_VERBOSITY_LELVEL_3 # timezone = timezone.replace('+', '') prefix = '<Prefix>' if prefix: prefix = options['prefix'] # message = '{p}{s}|{d} {t} {tz}'.format(s=scene, p=prefix, d=date, t=time, tz=timezone) message = '{p}{s}|{d} {t}'.format(s=scene, p=prefix, d=date_tgis, t=time) # add to timestamps if tgis_output: global timestamps timestamps.append(message) if not tgis: message = message.format(date=date, time=time, timezone=timezone) g.message(_(message))
def remove_temporary_maps(): """Clean up temporary maps""" # get list of temporary maps # temporary_raster_maps = grass.list_strings( # type="raster", pattern="tmp.{pid}*".format(pid=os.getpid()) # ) # # remove temporary maps # if temporary_raster_maps: g.message("Removing temporary maps") g.remove( flags="f", type="raster", pattern="tmp.{pid}*".format(pid=os.getpid()), quiet=True, )
def kelvin_to_celsius(outname, lst_map): """ Convert Kelvin to Celsius """ msg = '\n|i Converting LST output from Kelvin to Celsius degrees' #g.message(msg) kelvin_to_celsius_expression = '{lst} - 273.15'.format(lst=lst_map) kelvin_to_celsius_equation = equation.format(result=lst_map, expression=kelvin_to_celsius_expression) grass.mapcalc(kelvin_to_celsius_equation, overwrite=True) msg += '\n|i Applying the "Celsius" color table' g.message(msg) run('r.colors', map=lst_map, color='celsius') del(kelvin_to_celsius_expression) del(kelvin_to_celsius_equation)
def link_to_target(target, link, dry_run=True, softlinking='', relative=False): """ This function creates the requested 'link' to the 'target' file. This function does not return anything. Parameters ---------- target : The target file to link to link : The link file to create dry_run : A boolean flag on whether to actually perform the linking or not softlinking : An empty string or the '-s' string passed to the actual command's 'flags' option to define whether linking softly or not. relative : A boolean flag to define whether to create relative links """ linking_message = MESSAGE_LINKING if softlinking: linking_message = MESSAGE_SOFT_LINKING if relative: linking_message = MESSAGE_RELATIVE_LINKING g.message( linking_message.format(target=target, link=link), flags='v', ) if not dry_run: flags = '' if softlinking: flags += '-s' if relative: flags += 'r' command = f'ln {flags} {target} {link}' command = shlex.split(command) try: subprocess.run(command) except subprocess.CalledProcessError as e: grass.fatal(e.output)
def digital_numbers_to_radiance( outname, band, radiance_expression, null=False, info=False, ): """ Convert Digital Number values to TOA Radiance. For details, see in Landsat8 class. Zero (0) DNs set to NULL here (not via the class' function). """ if null: msg = f'\n|i Setting zero (0) Digital Numbers in {band} to NULL' g.message(msg) run( 'r.null', map=band, setnull=0, ) msg = f'\n|i Rescaling {band} digital numbers to spectral radiance' if info: msg += f'\n {radiance_expression}' g.message(msg) radiance_expression = replace_dummies( radiance_expression, instring=DUMMY_MAPCALC_STRING_DN, outstring=band, ) radiance_equation = EQUATION.format( result=outname, expression=radiance_expression, ) grass.mapcalc(radiance_equation, overwrite=True) if info: run( 'r.info', map=outname, flags='r', )
def hpf_weight(lo_sd, hpf_sd, mod, pss): """Returning an appropriate weighting value for the High Pass Filtered image. The required inputs are: - StdDev of Low resolution image - StdDev of High Pass Filtered image - Appropriate Modulating Factor determining image crispness - Number of Pass (1st or 2nd)""" if pss == 1: wgt = lo_sd / hpf_sd * mod # mod: modulator msg = " >> Weighting = %.2f / %.2f * %.2f = %.2f" % \ (lo_sd, hpf_sd, mod, wgt) g.message(msg, flags='v') if pss == 2: wgt = lo_sd / hpf_sd * mod # mod: modulator msg = " >> 2nd Pass Weighting = %.3f / %.3f * %.3f = %.3f" % \ (lo_sd, hpf_sd, mod, wgt) g.message(msg, flags='v') return wgt
def main(): method = options['method'] # algorithm for speckle removal img = options['input'] # name of input image img_out = options['output'] # name of output image size = options['size'] # size of neighborhood out = grass.core.find_file(img_out) if (out['name'] != '') and not grass.overwrite(): grass.warning(_('Output map name already exists. ' 'Delete it or use overwrite flag')) if method == 'lee': g.message(_('Applying Lee Filter')) img_out = lee_filter(img, size, img_out) g.message(_('Done.')) else: grass.fatal(_("The requested speckle filter is not yet implemented."))
def extract_tgz(tgz): """ Decompress and unpack a .tgz file """ tar = tarfile.TarFile.open(name=tgz, mode='r') tgz_base = os.path.basename(tgz).split('.tar.gz')[0] # try to create a directory with the scene's (base)name # source: <http://stackoverflow.com/a/14364249/1172302> try: os.makedirs(tgz_base) except OSError: if not os.path.isdir(tgz_base): raise # extract files indide the scene directory compressed_scene = os.path.basename(tgz) g.message(_(f'Extracting files from compressed_scene {compressed_scene}')) tar.extractall(path=tgz_base)
def hpf_ascii(center, filter, tmpfile, pss): """Exporting a High Pass Filter in a temporary ASCII file""" if pss == 1: global modulator modulator = filter.modulator msg_ps2 = '' elif pss == 2: global modulator_2 modulator_2 = filter.modulator_2 msg_ps2 = '2nd Pass ' # structure informative message msg = " > %sFilter Properties: size: %s, center: %s" % \ (msg_ps2, filter.size, center) g.message(msg, flags='v') # open, write and close file asciif = open(tmpfile, 'w') asciif.write(filter.filter) asciif.close()
def main(): method = options["method"] # algorithm for speckle removal img = options["input"] # name of input image img_out = options["output"] # name of output image size = options["size"] # size of neighborhood out = grass.core.find_file(img_out) if (out["name"] != "") and not grass.overwrite(): grass.warning( _("Output map name already exists. " "Delete it or use overwrite flag")) if method == "lee": g.message(_("Applying Lee Filter")) img_out = lee_filter(img, size, img_out) g.message(_("Done.")) else: grass.fatal(_("The requested speckle filter is not yet implemented."))
def get_cwv_window_means(outname, t1x, t1x_mean_expression): """ *** This function is NOT used. It was part of an initial step-by-step approach, while coding and testing. Kept for future plans!? *** Get window means for T1x """ msg = ('\n |i Deriving window means from {Tx} ') msg += ('using the expression:\n {exp}') msg = msg.format(Tx=t1x, exp=t1x_mean_expression) g.message(msg) tx_mean_equation = equation.format(result=outname, expression=t1x_mean_expression) grass.mapcalc(tx_mean_equation, overwrite=True) if info: run('r.info', map=outname, flags='r') del(t1x_mean_expression) del(tx_mean_equation)
def copy_mtl_in_cell_misc(scene, mapset, tgis, copy_mtl=True) : """ Copies the *MTL.txt metadata file in the cell_misc directory inside the Landsat scene's independent Mapset or in else the requested single Mapset """ if one_mapset: mapset = mapset path_to_cell_misc = get_path_to_cell_misc(mapset) if is_mtl_in_cell_misc(mapset): message = HORIZONTAL_LINE message += ' MTL exists in: {d}\n'.format(d=path_to_cell_misc) message += HORIZONTAL_LINE g.message(_(message)) pass else: if copy_mtl: metafile = get_metafile(scene, tgis) # copy the metadata file -- Better: check if really copied! message = HORIZONTAL_LINE message += ' MTL file copied at <{directory}>.' message = message.format(directory=path_to_cell_misc) g.message(_(message)) shutil.copy(metafile, path_to_cell_misc) else: message = HORIZONTAL_LINE message += ' MTL not transferred to {m}/cell_misc'.format(m=scene) g.message(_(message))
def main(): global acq_time, esd """1st, get input, output, options and flags""" spectral_bands = options['band'].split(',') outputsuffix = options['outputsuffix'] utc = options['utc'] doy = options['doy'] sea = options['sea'] radiance = flags['r'] if radiance and outputsuffix == 'toar': outputsuffix = 'rad' g.message("Output-suffix set to %s" % outputsuffix) keep_region = flags['k'] info = flags['i'] # ----------------------------------------------------------------------- # Equations # ----------------------------------------------------------------------- if info: # conversion to Radiance based on (1) msg = "|i Spectral Radiance = K * DN / Effective Bandwidth | " \ "Reflectance = ( Pi * Radiance * ESD^2 ) / BAND_Esun * cos(SZA)" g.message(msg) # ----------------------------------------------------------------------- # List images and their properties # ----------------------------------------------------------------------- mapset = grass.gisenv()['MAPSET'] # Current Mapset? # imglst = [pan] # imglst.extend(msxlst) # List of input imagery images = {} for img in spectral_bands: # Retrieving Image Info images[img] = Info(img, mapset) images[img].read() # ----------------------------------------------------------------------- # Temporary Region and Files # ----------------------------------------------------------------------- if not keep_region: grass.use_temp_region() # to safely modify the region tmpfile = grass.tempfile() # Temporary file - replace with os.getpid? tmp = "tmp." + grass.basename(tmpfile) # use its basename # ----------------------------------------------------------------------- # Global Metadata: Earth-Sun distance, Sun Zenith Angle # ----------------------------------------------------------------------- # Earth-Sun distance if doy: g.message("|! Using Day of Year to calculate Earth-Sun distance.") esd = jd_to_esd(int(doy)) elif (not doy) and utc: acq_utc = AcquisitionTime(utc) # will hold esd (earth-sun distance) esd = acq_utc.esd else: grass.fatal(_("Either the UTC string or " "the Day-of-Year (doy) are required!")) sza = 90 - float(sea) # Sun Zenith Angle based on Sun Elevation Angle # ----------------------------------------------------------------------- # Loop processing over all bands # ----------------------------------------------------------------------- for band in spectral_bands: global tmp_rad # ------------------------------------------------------------------- # Match bands region if... ? # ------------------------------------------------------------------- if not keep_region: run('g.region', rast=band) # ## FixMe? msg = "\n|! Region matching the %s spectral band" % band g.message(msg) elif keep_region: msg = "|! Operating on current region" g.message(msg) # ------------------------------------------------------------------- # Band dependent metadata for Spectral Radiance # ------------------------------------------------------------------- g.message("\n|* Processing the %s band" % band, flags='i') # Why is this necessary? Any function to remove the mapsets name? if '@' in band: band = (band.split('@')[0]) # get absolute calibration factor acf = float(CF_BW_ESUN[band][2]) acf_msg = "K=" + str(acf) # effective bandwidth bw = float(CF_BW_ESUN[band][0]) # ------------------------------------------------------------------- # Converting to Spectral Radiance # ------------------------------------------------------------------- msg = "\n|> Converting to Spectral Radiance " \ "| Conversion Factor %s, Bandwidth=%.3f" % (acf_msg, bw) g.message(msg) # convert tmp_rad = "%s.Radiance" % tmp # Temporary Map rad = "%s = %f * %s / %f" \ % (tmp_rad, acf, band, bw) # Attention: 32-bit calculations requ. grass.mapcalc(rad, overwrite=True) # strings for metadata history_rad = rad history_rad += "Conversion Factor=%f; Effective Bandwidth=%.3f" \ % (acf, bw) title_rad = "" description_rad = "Top-of-Atmosphere %s band spectral Radiance " \ "[W/m^2/sr/μm]" % band units_rad = "W / sq.m. / μm / ster" if not radiance: # --------------------------------------------------------------- # Converting to Top-of-Atmosphere Reflectance # --------------------------------------------------------------- global tmp_toar msg = "\n|> Converting to Top-of-Atmosphere Reflectance" g.message(msg) esun = float(CF_BW_ESUN[band][1]) msg = " %s band mean solar exoatmospheric irradiance=%.2f" \ % (band, esun) g.message(msg) # convert tmp_toar = "%s.Reflectance" % tmp # Spectral Reflectance toar = "%s = %f * %s * %f^2 / %f * cos(%f)" \ % (tmp_toar, math.pi, tmp_rad, esd, esun, sza) grass.mapcalc(toar, overwrite=True) # report range? Using a flag and skip actual conversion? # todo? # strings for metadata title_toar = "%s band (Top of Atmosphere Reflectance)" % band description_toar = "Top of Atmosphere %s band spectral Reflectance" \ % band units_toar = "Unitless planetary reflectance" history_toar = "K=%f; Bandwidth=%.1f; ESD=%f; Esun=%.2f; SZA=%.1f" \ % (acf, bw, esd, esun, sza) if tmp_toar: # history entry run("r.support", map=tmp_toar, title=title_toar, units=units_toar, description=description_toar, source1=source1_toar, source2=source2_toar, history=history_toar) # add suffix to basename & rename end product toar_name = ("%s.%s" % (band.split('@')[0], outputsuffix)) run("g.rename", rast=(tmp_toar, toar_name)) elif tmp_rad: # history entry run("r.support", map=tmp_rad, title=title_rad, units=units_rad, description=description_rad, source1=source1_rad, source2=source2_rad, history=history_rad) # add suffix to basename & rename end product rad_name = ("%s.%s" % (band.split('@')[0], outputsuffix)) run("g.rename", rast=(tmp_rad, rad_name)) # visualising-related information if not keep_region: grass.del_temp_region() # restoring previous region settings g.message("\n|! Region's resolution restored!") g.message("\n>>> Hint: rebalancing colors " "(i.colors.enhance) may improve appearance of RGB composites!", flags='i')
def main(): global acq_time, esd """1st, get input, output, options and flags""" spectral_bands = options['band'].split(',') outputsuffix = options['outputsuffix'] utc = options['utc'] doy = options['doy'] sea = options['sea'] radiance = flags['r'] keep_region = flags['k'] # mapset = grass.gisenv()['MAPSET'] # Current Mapset? # imglst = [spectral_bands] # images = {} # for img in imglst: # Retrieving Image Info # images[img] = Info(img, mapset) # images[img].read() # ----------------------------------------------------------------------- # Temporary Region and Files # ----------------------------------------------------------------------- if not keep_region: grass.use_temp_region() # to safely modify the region tmpfile = grass.tempfile() # Temporary file - replace with os.getpid? tmp = "tmp." + grass.basename(tmpfile) # use its basename # ----------------------------------------------------------------------- # Global Metadata: Earth-Sun distance, Sun Zenith Angle # ----------------------------------------------------------------------- # Earth-Sun distance if doy: esd = jd_to_esd(int(doy)) elif utc: acq_utc = AcquisitionTime(utc) # will hold esd (earth-sun distance) acq_dat = datetime(acq_utc.year, acq_utc.month, acq_utc.day) esd = acq_utc.esd else: grass.fatal(_("Either the UTC string or " "the Day-of-Year (doy) are required!")) sza = 90 - float(sea) # Sun Zenith Angle based on Sun Elevation Angle # ----------------------------------------------------------------------- # Loop processing over all bands # ----------------------------------------------------------------------- for band in spectral_bands: global tmp_rad g.message("|* Processing the %s spectral band" % band, flags='i') if not keep_region: g.message("\n|! Matching region to %s" % band) # set region run('g.region', rast=band) # ## FixMe # ------------------------------------------------------------------- # Converting to Spectral Radiance # ------------------------------------------------------------------- msg = "\n|> Converting to Spectral Radiance: " \ # "L(λ) = 10^4 x DN(λ) / CalCoef(λ) x Bandwidth(λ)" # Unicode? ## g.message(msg) # ------------------------------------------------------------------- # Band dependent metadata for Spectral Radiance # ------------------------------------------------------------------- # Why is this necessary? Any function to remove the mapsets name? if '@' in band: band_key = (band.split('@')[0]) else: band_key = band # get coefficients if acq_dat < cc_update: g.message("\n|! Using Pre-2001 Calibration Coefficient values", flags='i') cc = float(CC[band_key][0]) else: cc = float(CC[band_key][1]) # get bandwidth bw = float(CC[band_key][2]) # inform msg = " [Calibration Coefficient=%d, Bandwidth=%.1f]" \ % (cc, bw) g.message(msg) # convert tmp_rad = "%s.Radiance" % tmp # Temporary Map rad = "%s = 10^4 * %s / %f * %f" \ % (tmp_rad, band, cc, bw) grass.mapcalc(rad, overwrite=True) # string for metadata history_rad = rad history_rad += "Calibration Coefficient=%d; Effective Bandwidth=%.1f" \ % (cc, bw) title_rad = "%s band (Spectral Radiance)" % band units_rad = "W / m2 / μm / ster" description_rad = "At-sensor %s band spectral Radiance (W/m2/μm/sr)" \ % band if not radiance: # --------------------------------------------------------------- # Converting to Top-of-Atmosphere Reflectance # --------------------------------------------------------------- global tmp_toar msg = "\n|> Converting to Top-of-Atmosphere Reflectance" \ # "ρ(p) = π x L(λ) x d^2 / ESUN(λ) x cos(θ(S))" # Unicode? g.message(msg) # --------------------------------------------------------------- # Band dependent metadata for Spectral Radiance # --------------------------------------------------------------- # get esun esun = CC[band_key][3] # inform msg = " [Earth-Sun distane=%f, Mean solar exoatmospheric " \ "irradiance=%.1f]" % (esd, esun) g.message(msg) # convert tmp_toar = "%s.Reflectance" % tmp # Spectral Reflectance toar = "%s = %f * %s * %f^2 / %f * cos(%f)" \ % (tmp_toar, math.pi, tmp_rad, esd, esun, sza) grass.mapcalc(toar, overwrite=True) # strings for output's metadata history_toar = toar history_toar += "ESD=%f; BAND_Esun=%f; SZA=%f" % (esd, esun, sza) title_toar = "%s band (Top of Atmosphere Reflectance)" % band units_toar = "Unitless planetary reflectance" description_toar = "Top of Atmosphere `echo ${BAND}` band spectral" " Reflectance (unitless)" if tmp_toar: # history entry run("r.support", map=tmp_toar, title=title_toar, units=units_toar, description=description_toar, source1=source1_toar, source2=source2_toar, history=history_toar) # add suffix to basename & rename end product toar_name = ("%s.%s" % (band.split('@')[0], outputsuffix)) run("g.rename", rast=(tmp_toar, toar_name)) elif tmp_rad: # history entry run("r.support", map=tmp_rad, title=title_rad, units=units_rad, description=description_rad, source1=source1_rad, source2=source2_rad, history=history_rad) # add suffix to basename & rename end product rad_name = ("%s.%s" % (band.split('@')[0], outputsuffix)) run("g.rename", rast=(tmp_rad, rad_name)) # visualising-related information if not keep_region: grass.del_temp_region() # restoring previous region settings g.message("\n|! Region's resolution restored!") g.message("\n>>> Hint: rebalancing colors " "(i.colors.enhance) may improve appearance of RGB composites!", flags='i')
def main(): pan = options['pan'] msxlst = options['msx'].split(',') outputsuffix = options['suffix'] custom_ratio = options['ratio'] center = options['center'] center2 = options['center2'] modulation = options['modulation'] modulation2 = options['modulation2'] if options['trim']: trimming_factor = float(options['trim']) else: trimming_factor = False histogram_match = flags['l'] second_pass = flags['2'] color_match = flags['c'] # # Check & warn user about "ns == ew" resolution of current region ====== # region = grass.region() # nsr = region['nsres'] # ewr = region['ewres'] # # if nsr != ewr: # msg = ('>>> Region's North:South ({ns}) and East:West ({ew}) ' # 'resolutions do not match!') # msg = msg.format(ns=nsr, ew=ewr) # g.message(msg, flags='w') mapset = grass.gisenv()['MAPSET'] # Current Mapset? region = grass.region() # and region settings # List images and their properties imglst = [pan] imglst.extend(msxlst) # List of input imagery images = {} for img in imglst: # Retrieving Image Info images[img] = Info(img, mapset) images[img].read() panres = images[pan].nsres # Panchromatic resolution grass.use_temp_region() # to safely modify the region run('g.region', res=panres) # Respect extent, change resolution g.message("|! Region's resolution matched to Pan's ({p})".format(p=panres)) # Loop Algorithm over Multi-Spectral images for msx in msxlst: g.message("\nProcessing image: {m}".format(m=msx)) # Tracking command history -- Why don't do this all r.* modules? cmd_history = [] # # 1. Compute Ratio # g.message("\n|1 Determining ratio of low to high resolution") # Custom Ratio? Skip standard computation method. if custom_ratio: ratio = float(custom_ratio) g.message('Using custom ratio, overriding standard method!', flags='w') # Multi-Spectral resolution(s), multiple else: # Image resolutions g.message(" > Retrieving image resolutions") msxres = images[msx].nsres # check if panres == msxres: msg = ("The Panchromatic's image resolution ({pr}) " "equals to the Multi-Spectral's one ({mr}). " "Something is probably not right! " "Please check your input images.") msg = msg.format(pr=panres, mr=msxres) grass.fatal(_(msg)) # compute ratio ratio = msxres / panres msg_ratio = (' >> Resolution ratio ' 'low ({m:.{dec}f}) to high ({p:.{dec}f}): {r:.1f}') msg_ratio = msg_ratio.format(m=msxres, p=panres, r=ratio, dec=3) g.message(msg_ratio) # 2nd Pass requested, yet Ratio < 5.5 if second_pass and ratio < 5.5: g.message(" >>> Resolution ratio < 5.5, skipping 2nd pass.\n" " >>> If you insist, force it via the <ratio> option!", flags='i') second_pass = bool(0) # # 2. High Pass Filtering # g.message('\n|2 High Pass Filtering the Panchromatic Image') tmpfile = grass.tempfile() # Temporary file - replace with os.getpid? tmp = 'tmp.' + grass.basename(tmpfile) # use its basenam tmp_pan_hpf = '{tmp}_pan_hpf'.format(tmp=tmp) # HPF image tmp_msx_blnr = '{tmp}_msx_blnr'.format(tmp=tmp) # Upsampled MSx tmp_msx_hpf = '{tmp}_msx_hpf'.format(tmp=tmp) # Fused image tmp_hpf_matrix = grass.tempfile() # ASCII filter # Construct and apply Filter hpf = get_high_pass_filter(ratio, center) hpf_ascii(center, hpf, tmp_hpf_matrix, second_pass) run('r.mfilter', input=pan, filter=tmp_hpf_matrix, output=tmp_pan_hpf, title='High Pass Filtered Panchromatic image', overwrite=True) # 2nd pass if second_pass and ratio > 5.5: # Temporary files tmp_pan_hpf_2 = '{tmp}_pan_hpf_2'.format(tmp=tmp) # 2nd Pass HPF image tmp_hpf_matrix_2 = grass.tempfile() # 2nd Pass ASCII filter # Construct and apply 2nd Filter hpf_2 = get_high_pass_filter(ratio, center2) hpf_ascii(center2, hpf_2, tmp_hpf_matrix_2, second_pass) run('r.mfilter', input=pan, filter=tmp_hpf_matrix_2, output=tmp_pan_hpf_2, title='2-High-Pass Filtered Panchromatic Image', overwrite=True) # # 3. Upsampling low resolution image # g.message("\n|3 Upsampling (bilinearly) low resolution image") run('r.resamp.interp', method='bilinear', input=msx, output=tmp_msx_blnr, overwrite=True) # # 4. Weighting the High Pass Filtered image(s) # g.message("\n|4 Weighting the High-Pass-Filtered image (HPFi)") # Compute (1st Pass) Weighting msg_w = " > Weighting = StdDev(MSx) / StdDev(HPFi) * " \ "Modulating Factor" g.message(msg_w) # StdDev of Multi-Spectral Image(s) msx_avg = avg(msx) msx_sd = stddev(msx) g.message(" >> StdDev of <{m}>: {sd:.3f}".format(m=msx, sd=msx_sd)) # StdDev of HPF Image hpf_sd = stddev(tmp_pan_hpf) g.message(" >> StdDev of HPFi: {sd:.3f}".format(sd=hpf_sd)) # Modulating factor modulator = get_modulator_factor(modulation, ratio) g.message(" >> Modulating Factor: {m:.2f}".format(m=modulator)) # weighting HPFi weighting = hpf_weight(msx_sd, hpf_sd, modulator, 1) # # 5. Adding weighted HPF image to upsampled Multi-Spectral band # g.message("\n|5 Adding weighted HPFi to upsampled image") fusion = '{hpf} = {msx} + {pan} * {wgt}' fusion = fusion.format(hpf=tmp_msx_hpf, msx=tmp_msx_blnr, pan=tmp_pan_hpf, wgt=weighting) grass.mapcalc(fusion) # command history hst = 'Weigthing applied: {msd:.3f} / {hsd:.3f} * {mod:.3f}' cmd_history.append(hst.format(msd=msx_sd, hsd=hpf_sd, mod=modulator)) if second_pass and ratio > 5.5: # # 4+ 2nd Pass Weighting the High Pass Filtered image # g.message("\n|4+ 2nd Pass Weighting the HPFi") # StdDev of HPF Image #2 hpf_2_sd = stddev(tmp_pan_hpf_2) g.message(" >> StdDev of 2nd HPFi: {h:.3f}".format(h=hpf_2_sd)) # Modulating factor #2 modulator_2 = get_modulator_factor2(modulation2) msg = ' >> 2nd Pass Modulating Factor: {m:.2f}' g.message(msg.format(m=modulator_2)) # 2nd Pass weighting weighting_2 = hpf_weight(msx_sd, hpf_2_sd, modulator_2, 2) # # 5+ Adding weighted HPF image to upsampled Multi-Spectral band # g.message("\n|5+ Adding small-kernel-based weighted 2nd HPFi " "back to fused image") add_back = '{final} = {msx_hpf} + {pan_hpf} * {wgt}' add_back = add_back.format(final=tmp_msx_hpf, msx_hpf=tmp_msx_hpf, pan_hpf=tmp_pan_hpf_2, wgt=weighting_2) grass.mapcalc(add_back) # 2nd Pass history entry hst = "2nd Pass Weighting: {m:.3f} / {h:.3f} * {mod:.3f}" cmd_history.append(hst.format(m=msx_sd, h=hpf_2_sd, mod=modulator_2)) if color_match: g.message("\n|* Matching output to input color table") run('r.colors', map=tmp_msx_hpf, raster=msx) # # 6. Stretching linearly the HPF-Sharpened image(s) to match the Mean # and Standard Deviation of the input Multi-Sectral image(s) # if histogram_match: # adapt output StdDev and Mean to the input(ted) ones g.message("\n|+ Matching histogram of Pansharpened image " "to %s" % (msx), flags='v') # Collect stats for linear histogram matching msx_hpf_avg = avg(tmp_msx_hpf) msx_hpf_sd = stddev(tmp_msx_hpf) # expression for mapcalc lhm = '{out} = ({hpf} - {hpfavg}) / {hpfsd} * {msxsd} + {msxavg}' lhm = lhm.format(out=tmp_msx_hpf, hpf=tmp_msx_hpf, hpfavg=msx_hpf_avg, hpfsd=msx_hpf_sd, msxsd=msx_sd, msxavg=msx_avg) # compute grass.mapcalc(lhm, quiet=True, overwrite=True) # update history string cmd_history.append("Linear Histogram Matching: %s" % lhm) # # Optional. Trim to remove black border effect (rectangular only) # if trimming_factor: tf = trimming_factor # communicate msg = '\n|* Trimming output image border pixels by ' msg += '{factor} times the low resolution\n'.format(factor=tf) nsew = ' > Input extent: n: {n}, s: {s}, e: {e}, w: {w}' nsew = nsew.format(n=region.n, s=region.s, e=region.e, w=region.w) msg += nsew g.message(msg) # re-set borders region.n -= tf * images[msx].nsres region.s += tf * images[msx].nsres region.e -= tf * images[msx].ewres region.w += tf * images[msx].ewres # communicate and act msg = ' > Output extent: n: {n}, s: {s}, e: {e}, w: {w}' msg = msg.format(n=region.n, s=region.s, e=region.e, w=region.w) g.message(msg) # modify only the extent run('g.region', n=region.n, s=region.s, e=region.e, w=region.w) trim = "{out} = {input}".format(out=tmp_msx_hpf, input=tmp_msx_hpf) grass.mapcalc(trim) # # End of Algorithm # history entry run("r.support", map=tmp_msx_hpf, history="\n".join(cmd_history)) # add suffix to basename & rename end product msx_name = "{base}.{suffix}" msx_name = msx_name.format(base=msx.split('@')[0], suffix=outputsuffix) run("g.rename", raster=(tmp_msx_hpf, msx_name)) # remove temporary files cleanup() # visualising-related information grass.del_temp_region() # restoring previous region settings g.message("\n|! Original Region restored") g.message("\n>>> Hint, rebalancing colors (via i.colors.enhance) " "may improve appearance of RGB composites!", flags='i')
def main(): """ """ sensor = options['sensor'] mapsets = options['mapsets'] prefix = options['input_prefix'] suffix = options['output_suffix'] metafile = grass.basename(options['metafile']) # 6S parameter names shortened following i.atcorr's manual atm = int(options['atmospheric_model']) # Atmospheric model [index] aer = int(options['aerosols_model']) # Aerosols model [index] vis = options['visibility_range'] # Visibility [km] aod = options['aerosol_optical_depth'] # Aerosol Optical Depth at 550nm xps = options['altitude'] # Mean Target Altitude [negative km] if not xps: msg = "Note, this value will be overwritten if a DEM raster has been "\ "defined as an input!" g.message(msg) elevation_map = options['elevation'] visibility_map = options['visibility'] radiance = flags['r'] if radiance: global rad_flg radiance_flag = 'r' else: radiance_flag = '' # If the scene to be processed was imported via the (custom) python # Landsat import script, then, Mapset name == Scene identifier mapset = grass.gisenv()['MAPSET'] if mapset == 'PERMANENT': grass.fatal(_('Please change to another mapset than the PERMANENT')) # elif 'L' not in mapset: # msg = "Assuming the Landsat scene(s) ha-s/ve been imported using the "\ # "custom python import script, the Mapset's name *should* begin "\ # "with the letter L!" # grass.fatal(_(msg)) else: result = grass.find_file(element='cell_misc', name=metafile, mapset='.') if not result['file']: grass.fatal("The metadata file <%s> is not in GRASS' data base!" % metafile) else: metafile = result['file'] # # Acquisition's metadata # msg = "Acquisition metadata for 6S code (line 2 in Parameters file)\n" # Month, day date = grass.parse_command('i.landsat.toar', flags='p', input='dummy', output='dummy', metfile=metafile, lsatmet='date') mon = int(date['date'][5:7]) # Month of acquisition day = int(date['date'][8:10]) # Day of acquisition # GMT in decimal hours gmt = grass.read_command('i.landsat.toar', flags='p', input='dummy', output='dummy', metfile=metafile, lsatmet='time') gmt = float(gmt.rstrip('\n')) # Scene's center coordinates cll = grass.parse_command('g.region', flags='clg') lon = float(cll['center_long']) # Center Longitude [decimal degrees] lat = float(cll['center_lat']) # Center Latitude [decimal degrees] msg += str(mon) + ' ' + str(day) + ' ' + str(gmt) + ' ' + \ str(lon) + ' ' + str(lat) g.message(msg) # # AOD # if aod: aod = float(options['aerosol_optical_depth']) else: # sane defaults if 4 < mon < 10: aod = float(0.222) # summer else: aod = float(0.111) # winter # # Mapsets are Scenes. Read'em all! # if mapsets == 'all': scenes = grass.mapsets() elif mapsets == 'current': scenes = [mapset] else: scenes = mapsets.split(',') if 'PERMANENT' in scenes: scenes.remove('PERMANENT') # access only to specific mapsets! msg = "\n|* Performing atmospheric correction for scenes: %s" % scenes g.message(msg) for scene in scenes: # ensure access only to *current* mapset run('g.mapsets', mapset='.', operation='set') # scene's basename as in GRASS' db basename = grass.read_command('g.mapset', flags='p') msg = " | Processing scene: %s" % basename g.message(msg) # loop over Landsat bands in question for band in sensors[sensor].keys(): inputband = prefix + str(band) msg = '\n>>> Processing band: {band}'.format(band=inputband) g.message(msg) # Generate 6S parameterization file p6s = Parameters(geo=geo[sensor], mon=mon, day=day, gmt=gmt, lon=lon, lat=lat, atm=atm, aer=aer, vis=vis, aod=aod, xps=xps, xpp=xpp, bnd=sensors[sensor][band]) # # Temporary files # tmpfile = grass.tempfile() tmp = "tmp." + grass.basename(tmpfile) # use its basename tmp_p6s = grass.tempfile() # 6S Parameters ASCII file tmp_atm_cor = "%s_cor_out" % tmp # Atmospherically Corrected Img p6s.export_ascii(tmp_p6s) # Process band-wise atmospheric correction with 6s msg = "6S parameters:\n\n" msg += p6s.parameters g.message(msg) # inform about input's range? input_range = grass.parse_command('r.info', flags='r', map=inputband) input_range['min'] = float(input_range['min']) input_range['max'] = float(input_range['max']) msg = "Input range: %.2f ~ %.2f" % (input_range['min'], input_range['max']) g.message(msg) # # Applying 6S Atmospheric Correction algorithm # run_i_atcorr(radiance_flag, inputband, input_range, elevation_map, visibility_map, tmp_p6s, tmp_atm_cor, (0,1)) # inform about output's range? output_range = grass.parse_command('r.info', flags='r', map=tmp_atm_cor) output_range['min'] = float(output_range['min']) output_range['max'] = float(output_range['max']) msg = "Output range: %.2f ~ %.2f" \ % (output_range['min'], output_range['max']) g.message(msg) # add suffix to basename & rename end product atm_cor_nam = ("%s%s.%s" % (prefix, suffix, band)) run('g.rename', rast=(tmp_atm_cor, atm_cor_nam))
# constants ----------------------------------------------------------------- geo = {'tm': 7, 'mss': 7, 'etm': 8, 'oli': 18} # Geometrical conditions xpp = -1000 # Satellite borne [-1000] # Spectral conditions index sensors = { 'mss': {1: 31, 2: 32, 3: 33, 4: 34}, 'tm': {1: 25, 2: 26, 3: 27, 4: 28, 5: 29, 7: 30}, 'etm': {1: 61, 2: 62, 3: 63, 4: 64, 5: 65, 7: 66, 8: 67}, 'oli': {1: 115, 2: 116, 3: 117, 4: 118, 8: 119, 5: 120, 9: 121, 6: 122, 7: 123} } # globals g.message(msg) radiance_flag = '' # helper functions def cleanup(): """Clean up temporary maps""" grass.run_command('g.remove', flags='f', type="raster", pattern='tmp.%s*' % os.getpid(), quiet=True) def run(cmd, **kwargs): """ Pass quiet flag to grass commands """ grass.run_command(cmd, quiet=True, **kwargs)
def main(): """ Main program """ # Temporary filenames # The following three are meant for a test step-by-step cwv estimation, see # unused functions! # tmp_ti_mean = tmp_map_name('ti_mean') # for cwv # tmp_tj_mean = tmp_map_name('tj_mean') # for cwv # tmp_ratio = tmp_map_name('ratio') # for cwv tmp_avg_lse = tmp_map_name('avg_lse') tmp_delta_lse = tmp_map_name('delta_lse') tmp_cwv = tmp_map_name('cwv') #tmp_lst = tmp_map_name('lst') # basic equation for mapcalc global equation, citation_lst equation = "{result} = {expression}" # user input mtl_file = options['mtl'] if not options['prefix']: b10 = options['b10'] b11 = options['b11'] t10 = options['t10'] t11 = options['t11'] if not options['clouds']: qab = options['qab'] cloud_map = False else: qab = False cloud_map = options['clouds'] elif options['prefix']: prefix = options['prefix'] b10 = prefix + '10' b11 = prefix + '11' if not options['clouds']: qab = prefix + 'QA' cloud_map = False else: cloud_map = options['clouds'] qab = False qapixel = options['qapixel'] lst_output = options['lst'] # save Brightness Temperature maps? global brightness_temperature_prefix if options['prefix_bt']: brightness_temperature_prefix = options['prefix_bt'] else: brightness_temperature_prefix = None global cwv_output cwv_window_size = int(options['window']) assertion_for_cwv_window_size_msg = ('A spatial window of size 5^2 or less is not ' 'recommended. Please select a larger window. ' 'Refer to the manual\'s notes for details.') assert cwv_window_size >= 7, assertion_for_cwv_window_size_msg cwv_output = options['cwv'] # optional maps average_emissivity_map = options['emissivity'] delta_emissivity_map = options['delta_emissivity'] # output for in-between maps? global emissivity_output, delta_emissivity_output emissivity_output = options['emissivity_out'] delta_emissivity_output = options['delta_emissivity_out'] global landcover_map, emissivity_class landcover_map = options['landcover'] emissivity_class = options['emissivity_class'] # flags global info, null info = flags['i'] scene_extent = flags['e'] timestamping = flags['t'] null = flags['n'] global rounding rounding = flags['r'] global celsius celsius = flags['c'] # ToDo: # shell = flags['g'] # # Pre-production actions # # Set Region if scene_extent: grass.use_temp_region() # safely modify the region msg = "\n|! Matching region extent to map {name}" # ToDo: check if extent-B10 == extent-B11? Unnecessary? # Improve below! if b10: run('g.region', rast=b10, align=b10) msg = msg.format(name=b10) elif t10: run('g.region', rast=t10, align=t10) msg = msg.format(name=t10) g.message(msg) elif scene_extent: grass.warning(_('Operating on current region')) # # 1. Mask clouds # if cloud_map: # user-fed cloud map? msg = '\n|i Using {cmap} as a MASK'.format(cmap=cloud_map) g.message(msg) r.mask(raster=cloud_map, flags='i', overwrite=True) else: # using the quality assessment band and a "QA" pixel value mask_clouds(qab, qapixel) # # 2. TIRS > Brightness Temperatures # if mtl_file: # if MTL and b10 given, use it to compute at-satellite temperature t10 if b10: # convert DNs to at-satellite temperatures t10 = tirs_to_at_satellite_temperature(b10, mtl_file) # likewise for b11 -> t11 if b11: # convert DNs to at-satellite temperatures t11 = tirs_to_at_satellite_temperature(b11, mtl_file) # # Initialise a SplitWindowLST object # split_window_lst = SplitWindowLST(emissivity_class) citation_lst = split_window_lst.citation # # 3. Land Surface Emissivities # # use given fixed class? if emissivity_class: if split_window_lst.landcover_class is False: # replace with meaningful error g.warning('Unknown land cover class string! Note, this string ' 'input option is case sensitive.') if emissivity_class == 'Random': msg = "\n|! Random emissivity class selected > " + \ split_window_lst.landcover_class + ' ' else: msg = '\n|! Retrieving average emissivities *only* for {eclass} ' if info: msg += '| Average emissivities (channels 10, 11): ' msg += str(split_window_lst.emissivity_t10) + ', ' + \ str(split_window_lst.emissivity_t11) msg = msg.format(eclass=split_window_lst.landcover_class) g.message(msg) # use the FROM-GLC map elif landcover_map: if average_emissivity_map: tmp_avg_lse = average_emissivity_map if not average_emissivity_map: determine_average_emissivity(tmp_avg_lse, landcover_map, split_window_lst.average_lse_mapcalc) if options['emissivity_out']: tmp_avg_lse = options['emissivity_out'] if delta_emissivity_map: tmp_delta_lse = delta_emissivity_map if not delta_emissivity_map: determine_delta_emissivity(tmp_delta_lse, landcover_map, split_window_lst.delta_lse_mapcalc) if options['delta_emissivity_out']: tmp_delta_lse = options['delta_emissivity_out'] # # 4. Modified Split-Window Variance-Covariance Matrix > Column Water Vapor # if info: msg = '\n|i Spatial window of size {n} for Column Water Vapor estimation: ' msg = msg.format(n=cwv_window_size) g.message(msg) cwv = Column_Water_Vapor(cwv_window_size, t10, t11) citation_cwv = cwv.citation estimate_cwv_big_expression(tmp_cwv, t10, t11, cwv._big_cwv_expression()) if cwv_output: tmp_cwv = cwv_output # # 5. Estimate Land Surface Temperature # if info and emissivity_class == 'Random': msg = '\n|* Will pick a random emissivity class!' grass.verbose(msg) estimate_lst(lst_output, t10, t11, tmp_avg_lse, tmp_delta_lse, tmp_cwv, split_window_lst.sw_lst_mapcalc) # # Post-production actions # # remove MASK r.mask(flags='r', verbose=True) # time-stamping if timestamping: add_timestamp(mtl_file, lst_output) if cwv_output: add_timestamp(mtl_file, cwv_output) # Apply color table if celsius: run('r.colors', map=lst_output, color='celsius') else: # color table for kelvin run('r.colors', map=lst_output, color='kelvin') # ToDo: helper function for r.support # strings for metadata history_lst = '\n' + citation_lst history_lst += '\n\n' + citation_cwv history_lst += '\n\nSplit-Window model: ' history_lst += split_window_lst._equation # :wsw_lst_mapcalc description_lst = ('Land Surface Temperature derived from a split-window algorithm. ') if celsius: title_lst = 'Land Surface Temperature (C)' units_lst = 'Celsius' else: title_lst = 'Land Surface Temperature (K)' units_lst = 'Kelvin' landsat8_metadata = Landsat8_MTL(mtl_file) source1_lst = landsat8_metadata.scene_id source2_lst = landsat8_metadata.origin # history entry run("r.support", map=lst_output, title=title_lst, units=units_lst, description=description_lst, source1=source1_lst, source2=source2_lst, history=history_lst) # (re)name the LST product #run("g.rename", rast=(tmp_lst, lst_output)) # restore region if scene_extent: grass.del_temp_region() # restoring previous region settings g.message("|! Original Region restored") # print citation if info: print '\nSource: ' + citation_lst
def import_geotiffs(scene, bands, mapset, memory, list_bands, tgis = False): """ Imports all bands (GeoTIF format) of a Landsat scene be it Landsat 5, 7 or 8. All known naming conventions are respected, such as "VCID" and "QA" found in newer Landsat scenes for temperature channels and Quality respectively. Parameters ---------- scene : Input scene name string bands : Bands to import mapset : Name of mapset to import to memory : See options for r.in.gdal list_bands : Boolean True or False tgis : Boolean True or False """ timestamp = get_timestamp(scene, tgis) print_timestamp(os.path.basename(scene), timestamp, tgis) if not one_mapset: # set mapset from scene name mapset = os.path.basename(scene) message = str() # a string holder # verbosity: target Mapset if not any(x for x in (list_bands, tgis)): message = 'Target Mapset\n@{mapset}\n\n'.format(mapset=mapset) # communicate input band name if not tgis: message += 'Band\tFilename\n' g.message(_(message)) # loop over files inside a "Landsat" directory # sort band numerals, source: https://stackoverflow.com/a/2669523/1172302 if bands == 'all': filenames = sort_list_of_bands(os.listdir(scene)) # filenames = sorted(os.listdir(scene), key=lambda item: # (int(item.partition('_B')[2].partition('.')[0]) # if item.partition('_B')[2].partition('.')[0].isdigit() # else float('inf'), item)) else: filenames = sort_list_of_bands(bands) for filename in filenames: # if not GeoTIFF, keep on working if os.path.splitext(filename)[-1] != GEOTIFF_EXTENSION: continue # use the full path name to the file name, band = get_name_band(scene, filename) band_title = 'band {band}'.format(band = band) if not tgis: message_overwriting = '\t [ Exists, overwriting]' # communicate input band and source file name message = '{band}'.format(band = band) message += '\t{filename}'.format(filename = filename) if not skip_import: g.message(_(message)) else: # message for skipping import message_skipping = '\t [ Exists, skipping ]' if not any(x for x in (list_bands, tgis)): # get absolute filename absolute_filename = os.path.join(scene, filename) # srt import parameters parameters = dict(input = absolute_filename, output = name, flags = '', title = band_title, quiet = True) if override_projection: parameters['flags'] += 'o' # create Mapset of interest, if it doesn't exist devnull = open(os.devnull, 'w') run('g.mapset', flags='c', mapset=mapset, stderr = devnull) # g.mapset(flags='c', mapset=mapset) if (skip_import and find_existing_band(name) and not grass.overwrite()): if force_timestamp: set_timestamp(name, timestamp) g.message(_(' >>> Forced timestamping for {b}'.format(b=name))) message_skipping = message + message_skipping g.message(_(message_skipping)) pass else: if (grass.overwrite() and find_existing_band(name)): if force_timestamp: set_timestamp(name, timestamp) g.message(_(' >>> Forced timestamping for {b}'.format(b=name))) message_overwriting = message + message_overwriting g.message(_(message_overwriting)) pass if (skip_import and not find_existing_band(name)): # FIXME # communicate input band and source file name message = '{band}'.format(band = band) message += '\t{filename}'.format(filename = filename) grass.message(_(message)) if link_geotiffs: # What happens with the '--overwrite' flag? # Check if it can be retrieved. r.external(**parameters) else: if memory: parameters['memory'] = memory # try: r.in_gdal(**parameters) # except CalledModuleError: # grass.fatal(_("Unable to read GDAL dataset {s}".format(s=scene))) if not do_not_timestamp: set_timestamp(name, timestamp) else: pass # copy MTL if not list_bands and not tgis: copy_mtl_in_cell_misc(scene, mapset, tgis, copy_mtl)
def main(): r_elevation = options['elevation'] mrvbf = options['mrvbf'].split('@')[0] mrrtf = options['mrrtf'].split('@')[0] t_slope = float(options['t_slope']) t_pctl_v = float(options['t_pctl_v']) t_pctl_r = float(options['t_pctl_r']) t_vf = float(options['t_rf']) t_rf = float(options['t_rf']) p_slope = float(options['p_slope']) p_pctl = float(options['p_pctl']) moving_window_square = flags['s'] levels = int(options['levels']) global TMP_RAST global current_region TMP_RAST = {k: [] for k in range(levels)} current_region = Region() ########################################################################### # Some checks if levels < 3: grass.fatal('Number of generalization steps (levels) cannot be < 3') if t_slope <=0 or t_pctl_v <=0 or t_pctl_r <=0 or t_vf <=0 or t_rf <=0 or \ p_slope <=0 or p_pctl <=0: grass.fatal('Parameter values cannot be <= 0') if levels > 10: grass.warning('A large number (>10) processing steps are selected, recommended is between 3 to 8') ########################################################################### # Intermediate outputs Xres_step, Yres_step, DEM = [], [], [] slope, F, PCTL, PVF, PVF_RF = [0]*levels, [0]*levels, [0]*levels, [0]*levels, [0]*levels VF, VF_RF, MRVBF, MRRTF = [0]*levels, [0]*levels, [0]*levels, [0]*levels ########################################################################### # Step 1 (L=0) # Base scale resolution L = 0 Xres_step.append(current_region.ewres) Yres_step.append(current_region.nsres) DEM.append(r_elevation) radi = 3 g.message(os.linesep) g.message("Step {L}".format(L=L+1)) g.message("------") # Calculation of slope (S1) and calculation of flatness (F1) (Equation 2) grass.message("Calculation of slope and transformation to flatness F{L}...".format(L=L+1)) slope[L] = get_slope(L, DEM[L]) F[L] = get_flatness(L, slope[L], t_slope, p_slope) # Calculation of elevation percentile PCTL for step 1 grass.message("Calculation of elevation percentile PCTL{L}...".format(L=L+1)) PCTL[L] = get_percentile(L, DEM[L], radi, moving_window_square) # Transform elevation percentile to local lowness for step 1 (Equation 3) grass.message("Calculation of preliminary valley flatness index PVF{L}...".format(L=L+1)) PVF[L] = get_prelim_flatness(L, F[L], PCTL[L], t_pctl_v, p_pctl) if mrrtf != '': grass.message("Calculation of preliminary ridge top flatness index PRF{L}...".format(L=L+1)) PVF_RF[L] = get_prelim_flatness_rf(L, F[L], PCTL[L], t_pctl_r, p_pctl) # Calculation of the valley flatness step 1 VF1 (Equation 4) grass.message("Calculation of valley flatness VF{L}...".format(L=L+1)) VF[L] = get_valley_flatness(L, PVF[L], t_vf, p_slope) if mrrtf != '': grass.message("Calculation of ridge top flatness RF{L}...".format(L=L+1)) VF_RF[L] = get_valley_flatness(L, PVF_RF[L], t_rf, p_slope) ################################################################################## # Step 2 (L=1) # Base scale resolution L = 1 Xres_step.append(current_region.ewres) Yres_step.append(current_region.nsres) DEM.append(r_elevation) t_slope /= 2.0 radi = 6 grass.message(os.linesep) grass.message("Step {L}".format(L=L+1)) grass.message("------") # Calculation of flatness for step 2 (Equation 5) # The second step commences the same way with the original DEM at its base resolution, # using a slope threshold ts,2 half of ts,1: grass.message("Calculation of flatness F{L}...".format(L=L+1)) F[L] = get_flatness(L, slope[L-1], t_slope, p_slope) # Calculation of elevation percentile PCTL for step 2 (radius of 6 cells) grass.message("Calculation of elevation percentile PCTL{L}...".format(L=L+1)) PCTL[L] = get_percentile(L, r_elevation, radi, moving_window_square) # PVF for step 2 (Equation 6) grass.message("Calculation of preliminary valley flatness index PVF{L}...".format(L=L+1)) PVF[L] = get_prelim_flatness(L, F[L], PCTL[L], t_pctl_v, p_pctl) if mrrtf != '': grass.message("Calculation of preliminary ridge top flatness index PRF{L}...".format(L=L+1)) PVF_RF[L] = get_prelim_flatness_rf(L, F[L], PCTL[L], t_pctl_r, p_pctl) # Calculation of the valley flatness VF for step 2 (Equation 7) grass.message("Calculation of valley flatness VF{L}...".format(L=L+1)) VF[L] = get_valley_flatness(L, PVF[L], t_vf, p_slope) if mrrtf != '': grass.message("Calculation of ridge top flatness RF{L}...".format(L=L+1)) VF_RF[L] = get_valley_flatness(L, PVF_RF[L], t_rf, p_slope) # Calculation of MRVBF for step 2 grass.message("Calculation of MRVBF{L}...".format(L=L+1)) MRVBF[L] = get_mrvbf(L, VF_Lminus1=VF[L-1], VF_L=VF[L], t=t_pctl_v) if mrrtf != '': grass.message("Calculation of MRRTF{L}...".format(L=L+1)) MRRTF[L] = get_mrvbf(L, VF_Lminus1=VF_RF[L-1], VF_L=VF_RF[L], t=t_pctl_r) # Update flatness for step 2 with combined flatness from F1 and F2 (Equation 10) grass.message("Calculation of combined flatness index CF{L}...".format(L=L+1)) F[L] = get_combined_flatness(L, F[L-1], F[L]) ################################################################################## # Remaining steps # DEM_1_1 refers to scale (smoothing) and resolution (cell size) # so that DEM_L1_L-1 refers to smoothing of current step, # but resolution of previous step for L in range(2, levels): t_slope /= 2.0 Xres_step.append(Xres_step[L-1] * 3) Yres_step.append(Yres_step[L-1] * 3) radi = 6 # delete temporary maps from L-2 for tmap in TMP_RAST[L-2]: g.remove(type='raster', name=tmap, flags='f', quiet=True) grass.message(os.linesep) grass.message("Step {L}".format(L=L+1)) grass.message("------") # Coarsen resolution to resolution of prevous step (step L-1) and smooth DEM if L >= 3: grass.run_command('g.region', ewres = Xres_step[L-1], nsres = Yres_step[L-1]) grass.message('Coarsening resolution to ew_res={e} and ns_res={n}...'.format( e=Xres_step[L-1], n=Yres_step[L-1])) grass.message("DEM smoothing 11 x 11 windows with Gaussian smoothing kernel (sigma) 3...") DEM.append(get_smoothed_dem(L, DEM[L-1])) # Calculate slope grass.message("Calculation of slope...") slope[L] = get_slope(L, DEM[L]) # Refine slope to base resolution if L >= 3: grass.message('Resampling slope back to base resolution...') slope[L] = refine(L, slope[L], current_region, method='bilinear') # Coarsen resolution to current step L and calculate PCTL grass.run_command('g.region', ewres=Xres_step[L], nsres=Yres_step[L]) DEM[L] = refine(L, DEM[L], Region(), method = 'average') grass.message("Calculation of elevation percentile PCTL{L}...".format(L=L+1)) PCTL[L] = get_percentile(L, DEM[L], radi, moving_window_square) # Refine PCTL to base resolution grass.message("Resampling PCTL{L} to base resolution...".format(L=L+1)) PCTL[L] = refine(L, PCTL[L], current_region, method='bilinear') # Calculate flatness F at the base resolution grass.message("Calculate F{L} at base resolution...".format(L=L+1)) F[L] = get_flatness(L, slope[L], t_slope, p_slope) # Update flatness with combined flatness CF from the previous step grass.message("Calculate combined flatness CF{L} at base resolution...".format(L=L+1)) F[L] = get_combined_flatness(L, F1=F[L-1], F2=F[L]) # Calculate preliminary valley flatness index PVF at the base resolution grass.message("Calculate preliminary valley flatness index PVF{L} at base resolution...".format(L=L+1)) PVF[L] = get_prelim_flatness(L, F[L], PCTL[L], t_pctl_v, p_pctl) if mrrtf != '': grass.message("Calculate preliminary ridge top flatness index PRF{L} at base resolution...".format(L=L+1)) PVF_RF[L] = get_prelim_flatness_rf(L, F[L], PCTL[L], t_pctl_r, p_pctl) # Calculate valley flatness index VF grass.message("Calculate valley flatness index VF{L} at base resolution...".format(L=L+1)) VF[L] = get_valley_flatness(L, PVF[L], t_vf, p_slope) if mrrtf != '': grass.message("Calculate ridge top flatness index RF{L} at base resolution...".format(L=L+1)) VF_RF[L] = get_valley_flatness(L, PVF_RF[L], t_rf, p_slope) # Calculation of MRVBF grass.message("Calculation of MRVBF{L}...".format(L=L+1)) MRVBF[L] = get_mrvbf(L, VF_Lminus1=MRVBF[L-1], VF_L=VF[L], t=t_pctl_v) if mrrtf != '': grass.message("Calculation of MRRTF{L}...".format(L=L+1)) MRRTF[L] = get_mrvbf(L, VF_Lminus1=MRRTF[L-1], VF_L=VF_RF[L], t=t_pctl_r) # Output final MRVBF grass.mapcalc("$x = $y", x = mrvbf, y=MRVBF[L]) if mrrtf != '': grass.mapcalc("$x = $y", x = mrrtf, y=MRRTF[L])
def main(resistancemap, stmap, stlist, output_prefix, output_folder, variability, scale, simulations, method): # Checking parameters and passing them to LSCorridors instance #--------------------- # Initialize LSCorridors app class instance app = wx.PySimpleApp() frame = wx.Frame(None, -1, "LSCorridors", pos=(0,0), size=(560,450)) corr = Corridors(frame, -1) #--------------------- # Define folder for output files if output_folder == '': output_folder = os.getcwd() # Try to change to output_folder try: os.chdir(output_folder) corr.path = os.getcwd() g.message('Folder for output files: '+corr.path) except: grass.fatal(_('GRASS GIS cannot access the folder '+output_folder+'. Please check if the folder exists'+ 'and its access permissions.')) corr.OutDir_files_TXT = corr.path #--------------------- # Check if the resistance map and ST map are inside the GRASS GIS mapset # If they are, define them as inputs for LSCorridors current_mapset = grass.read_command('g.mapset', flags = 'p').replace('\n','').replace('\r','') maps=grass.list_grouped('rast')[current_mapset] # Resistance map if resistancemap in maps: # Name of the input resistance map corr.OutArqResist = resistancemap g.message('Input resistance map: '+resistancemap) else: grass.fatal(_('Input: resistance map. There is no raster map called '+resistancemap+ ' inside the GRASS GIS mapset '+current_mapset+ '. Please import the map into GRASS GIS.')) if stmap in maps: # Name of the input resistance map corr.OutArqST = stmap g.message('Input Source-Target (ST) map: '+stmap) else: grass.fatal(_('Input: ST map. There is no raster map called '+stmap+ ' inside the GRASS GIS mapset '+current_mapset+ '. Please import the map into GRASS GIS.')) #--------------------- # Transforms stlist into a python list nad checks if the list is ok corr.patch_id_list = stlist.split(',') corr.patch_id_list_bkp = corr.patch_id_list lenlist = len(corr.patch_id_list) ########################## # include a flag with the possibility of being a txt file # Tests if the list has more than one element if lenlist <= 1: grass.fatal(_("Incorrect ST list. List length is smaller than 2! "+ "Please check the list.")) # Tests if the length of the ST list is even elif lenlist > 1 and int(lenlist)%2 == 1: grass.fatal(_("Incorrect ST list. List length cannot be odd. "+ "Please check the list.")) else: g.message('ST list checked and OK.') #--------------------- # Gets prefix for output files and puts that into output final names if output_prefix == '': corr.NEXPER_FINAL = corr.NEXPER_AUX+'_'+resistancemap corr.NEXPER_FINAL_txt = corr.NEXPER_AUX_txt+'_'+resistancemap else: corr.NEXPER_FINAL = corr.NEXPER_AUX+'_'+output_prefix corr.NEXPER_FINAL_txt = corr.NEXPER_AUX_txt+'_'+output_prefix g.message('Prefix of the output files: '+corr.NEXPER_FINAL) #--------------------- # Variability parameter # Checks if the values are positive and real try: # If no varibility parameter was passed, use the standard option if variability == '' or variability == '2.0': # Define the LSCorridors variability list corr.ruidos_float = [2.0] # If values of variability were passed, check that else: varlist = [float(i) for i in variability.split(',')] if len(varlist) < 1: grass.fatal(_('The list has no elements. Please check it.')) elif any(i < 0.0 for i in varlist): grass.fatal(_('Incorrect variability parameter(s). Variability must be '+ 'a number equal to or greater than zero! '+ 'Please check the parameter(s).')) else: # Define the LSCorridors variability list corr.ruidos_float = varlist g.message("Variability parameter(s): "+', '.join(str(i) for i in corr.ruidos_float)) except: grass.fatal(_('One or more of the variability values is not a real number. Check it.')) #--------------------- # Methods and number of simulations # Checks if number of simulations is integer and positive try: if int(simulations) < 1: grass.fatal(_('The number of simulations must be a positive integer value.')) except: grass.fatal(_('The number of simulations must be numeric.')) # Checks if the methods are valid if method == '': # If not parameter was passed, used the standard 'MP' method = 'MP' else: possible_methods = ['MP', 'MLmin', 'MLavg', 'MLmax'] method_list = method.split(',') if all(i in possible_methods for i in method_list): pass else: grass.fatal(_('At list one of the methods is not valid. They must be one of these:'+ 'MP, MLmin, MLavg, or MLmax')) # Define number of simulations for each method if 'MP' in method_list: corr.Nsimulations1 = int(simulations) g.message('Number of simulations for method MP: '+simulations) else: corr.Nsimulations1 = 0 if 'MLmin' in method_list: corr.Nsimulations2 = int(simulations) g.message('Number of simulations for method MLmin: '+simulations) else: corr.Nsimulations2 = 0 if 'MLavg' in method_list: corr.Nsimulations3 = int(simulations) g.message('Number of simulations for method MLavg: '+simulations) else: corr.Nsimulations3 = 0 if 'MLmax' in method_list: corr.Nsimulations4 = int(simulations) g.message('Number of simulations for method MLmax: '+simulations) else: corr.Nsimulations4 = 0 #--------------------- # Scale parameter # Checks if the values are positive and real try: # If no scale parameter was passed, use the standard option if scale == '' or scale == '100': # Define the LSCorridors scale list corr.escalas = [100] # If values of scale were passed, check that else: scalelist = [int(i) for i in scale.split(',')] # First, defining GRASS GIS region as output map region grass.run_command('g.region', rast=resistancemap) # Second, reading map resolution res = grass.read_command('g.region', rast=resistancemap, flags='m') res2 = res.split('\n') res3 = res2[5] res3 = float(res3.replace('ewres=','')) # Third, calculate window size (landscape scale x 2) in number of pixels escalas_pixels = [float(i)*2/res3 for i in scalelist] # Finally, tests if any of the scales are lower than the pixel size # (this only matters if methods MLmin, MLavg, or MLmax are going to be simulated) if any(i < 2.0 for i in escalas_pixels) and (corr.Nsimulations2 > 0 or corr.Nsimulations3 > 0 or corr.Nsimulations4 > 0): #print 'oi '+res3 grass.fatal(_("There may a problem with scale parameter. "+ "Input map resolution is "+`round(res3,1)`+" meters, scale should be greater than that! "+ "Please check the parameter(s).")) else: # Define the LSCorridors variability list corr.escalas = scalelist g.message("Scale parameter(s): "+', '.join(str(i) for i in corr.escalas)) except: grass.fatal(_('One or more of the scale values is not a real number. Check it.')) # Tests are going to be performed; however, as one do not want dialog boxes to be # shown, we keep this option as True corr.perform_tests = True # Event to test RUN SIMULATIONS evt10 = wx.PyCommandEvent(wx.EVT_BUTTON.typeId, 10) corr.OnClick(evt10) # Delete .pyc created #os.remove('LS_corridors_v1_0_0.pyc') os.remove('*.pyc') # call run START button return 0
def main(): global tmp_hpf_matrix pan = options['pan'] msxlst = options['msx'].split(',') outputprefix = options['outputprefix'] custom_ratio = options['ratio'] center = options['center'] center2 = options['center2'] modulation = options['modulation'] modulation2 = options['modulation2'] histogram_match = flags['l'] second_pass = flags['2'] # Check & warn user about "ns == ew" resolution of current region ====== region = grass.region() nsr = region['nsres'] ewr = region['ewres'] if nsr != ewr: g.message(">>> Region's North:South (%s) and East:West (%s)" "resolutions do not match!" % (nsr, ewr), flags='w') # ====================================================================== mapset = grass.gisenv()['MAPSET'] # Current Mapset? imglst = [pan] imglst.extend(msxlst) # List of input imagery images = {} for img in imglst: # Retrieving Image Info images[img] = Info(img, mapset) images[img].read() panres = images[pan].nsres # Panchromatic resolution run('g.region', res=panres) # Respect extent, change resolution g.message("| Region's resolution set to %f" % panres) for msx in msxlst: # Loop over Multi-Spectral images ||||||||||||||||||| global tmp # Inform g.message("\nProcessing image: %s" % msx) # Tracking command history -- Why don't do this all r.* modules? cmd_history = '' # ------------------------------------------------------------------- # 1. Compute Ratio # ------------------------------------------------------------------- g.message("\n|1 Determining ratio of low to high resolution") # Custom Ratio? Skip standard computation method. if custom_ratio: global ratio ratio = float(custom_ratio) g.message('Using custom ratio, overriding standard method!', flags='w') # Multi-Spectral resolution(s), multiple else: # Image resolutions g.message(" > Retrieving image resolutions") msxres = images[msx].nsres ratio = msxres / panres msg_ratio = ' >> Low (%.3f) to high resolution (%.3f) ratio: %.1f'\ % (msxres, panres, ratio) g.message(msg_ratio) # 2nd Pass requested, yet Ratio < 5.5 if second_pass and ratio < 5.5: g.message(" >>> Ratio < 5.5 -- WON'T perform 2nd pass! Use <ratio> option to override.", flags='i') second_pass = bool(0) # ------------------------------------------------------------------- # 2. High Pass Filtering # ------------------------------------------------------------------- g.message('\n|2 High Pass Filtering the Panchromatic Image') # ========================================== end of Temporary files # tmpfile = grass.tempfile() # Temporary file - replace with os.getpid? tmp = "tmp." + grass.basename(tmpfile) # use its basenam tmp_pan_hpf = "%s_pan_hpf" % tmp # HPF image tmp_msx_blnr = "%s_msx_blnr" % tmp # Upsampled MSx tmp_msx_hpf = "%s_msx_hpf" % tmp # Fused image tmp_hpf_matrix = grass.tempfile() # ASCII filter if second_pass and ratio > 5.5: # 2nd Pass? tmp_pan_hpf_2 = "%s_pan_hpf_2" % tmp # 2nd Pass HPF image tmp_hpf_matrix_2 = grass.tempfile() # 2nd Pass ASCII filter # Temporary files =================================================== # Construct Filter hpf = High_Pass_Filter(ratio, center, modulation, False, None) hpf_ascii(center, hpf, tmp_hpf_matrix, 1) # Construct 2nd Filter if second_pass and ratio > 5.5: hpf_2 = High_Pass_Filter(ratio, center2, None, True, modulation2) hpf_ascii(center2, hpf_2, tmp_hpf_matrix_2, 2) # Filtering run('r.mfilter', input=pan, filter=tmp_hpf_matrix, output=tmp_pan_hpf, title="High Pass Filtered Panchromatic image", overwrite=True) # 2nd Filtering if second_pass and ratio > 5.5: run('r.mfilter', input=pan, filter=tmp_hpf_matrix_2, output=tmp_pan_hpf_2, title="2-High-Pass Filtered Panchromatic Image", overwrite=True) # ------------------------------------------------------------------- # 3. Upsampling low resolution image # ------------------------------------------------------------------- g.message("\n|3 Upsampling (bilinearly) low resolution image") # resample -- named "linear" in G7 run('r.resamp.interp', method='bilinear', input=msx, output=tmp_msx_blnr, overwrite=True) # ------------------------------------------------------------------- # 4. Weighting the High Pass Filtered image(s) # ------------------------------------------------------------------- g.message("\n|4 Weighting the High-Pass-Filtered image (HPFi)") # Compute (1st Pass) Weighting msg_w = " > Weighting = StdDev(MSx) / StdDev(HPFi) * " "Modulating Factor" g.message(msg_w) # StdDev of Multi-Spectral Image(s) msx_avg = avg(msx) msx_sd = stddev(msx) g.message(" >> StdDev of <%s>: %.3f" % (msx, msx_sd)) # StdDev of HPF Image hpf_sd = stddev(tmp_pan_hpf) g.message(" >> StdDev of HPFi: %.3f" % hpf_sd) # Modulating factor g.message(" >> Modulating Factor: %.2f" % modulator) # weighting HPFi weighting = hpf_weight(msx_sd, hpf_sd, modulator, 1) # ------------------------------------------------------------------- # 5. Adding weighted HPF image to upsampled Multi-Spectral band # ------------------------------------------------------------------- g.message("\n|5 Adding weighted HPFi to upsampled image") fusion = "%s = %s + %s * %f" \ % (tmp_msx_hpf, tmp_msx_blnr, tmp_pan_hpf, weighting) grass.mapcalc(fusion) # history *********************************************************** cmd_history += "Weigthing applied: %.3f / %.3f * %.3f | " \ % (msx_sd, hpf_sd, modulator) if second_pass and ratio > 5.5: # --------------------------------------------------------------- # 4+ 2nd Pass Weighting the High Pass Filtered image # --------------------------------------------------------------- g.message("\n|4+ 2nd Pass Weighting the HPFi") # Compute 2nd Pass Weighting # Formula? Don't inform again... # StdDev of HPF Image #2 hpf_2_sd = stddev(tmp_pan_hpf_2) g.message(" >> StdDev of 2nd HPFi: %.3f" % hpf_2_sd) # Modulating factor #2 g.message(" >> 2nd Pass Modulating Factor: %.2f" % modulator_2) # 2nd Pass weighting weighting_2 = hpf_weight(msx_sd, hpf_2_sd, modulator_2, 2) # --------------------------------------------------------------- # 5+ Adding weighted HPF image to upsampled Multi-Spectral band # --------------------------------------------------------------- g.message("\n|5+ Adding small-kernel-based weighted 2nd HPFi " "back to fused image") add_back = "%s = %s + %s * %f" \ % (tmp_msx_hpf, tmp_msx_hpf, tmp_pan_hpf_2, weighting_2) grass.mapcalc(add_back) # 2nd Pass history entry **************************************** cmd_history += "2nd Pass Weighting: %s / %s * %s | " \ % (msx_sd, hpf_2_sd, modulator_2) # ------------------------------------------------------------------- # 6. Stretching linearly the HPF-Sharpened image(s) to match the Mean # and Standard Deviation of the input Multi-Sectral image(s) # ------------------------------------------------------------------- if histogram_match: # adapt output StdDev and Mean to the input(ted) ones g.message("\n| Matching histogram of Pansharpened image" "to %s" % (msx), flags='v') # Collect stats for linear histogram matching msx_hpf_avg = avg(tmp_msx_hpf) msx_hpf_sd = stddev(tmp_msx_hpf) # expression for mapcalc lhm = "%s = (%s - %f) / %f * %f + %f" \ % (tmp_msx_hpf, tmp_msx_hpf, msx_hpf_avg, msx_hpf_sd, msx_sd, msx_avg) # compute grass.mapcalc(lhm, quiet=True, overwrite=True) # update history string ***************************************** cmd_history += "Linear Histogram Matching: %s |" % lhm # histogram matching - history entry ******************************** run("r.support", map=tmp_msx_hpf, history=cmd_history) # Rename end product run("g.rename", rast=(tmp_msx_hpf, "%s_%s" % (msx, outputprefix))) # visualising output g.message("\n>>> Rebalance colors " "(e.g. via i.colors.enhance) before working on RGB composites!", flags='i')