From 745f27c87f483e89aa43f12123c343851fe27062 Mon Sep 17 00:00:00 2001 From: Santiago riel Seppi Date: Tue, 10 Oct 2023 19:06:06 -0300 Subject: [PATCH 01/38] Add i.saocom toolset --- src/imagery/i.saocom/Makefile | 13 + .../i.saocom/i.saocom.geocode/Makefile | 7 + .../i.saocom.geocode/i.saocom.geocode.html | 49 ++++ .../i.saocom.geocode/i.saocom.geocode.py | 237 +++++++++++++++++ src/imagery/i.saocom/i.saocom.html | 41 +++ src/imagery/i.saocom/i.saocom.import/Makefile | 7 + .../i.saocom.import/i.saocom.import.html | 65 +++++ .../i.saocom.import/i.saocom.import.py | 249 ++++++++++++++++++ 8 files changed, 668 insertions(+) create mode 100644 src/imagery/i.saocom/Makefile create mode 100755 src/imagery/i.saocom/i.saocom.geocode/Makefile create mode 100755 src/imagery/i.saocom/i.saocom.geocode/i.saocom.geocode.html create mode 100755 src/imagery/i.saocom/i.saocom.geocode/i.saocom.geocode.py create mode 100644 src/imagery/i.saocom/i.saocom.html create mode 100755 src/imagery/i.saocom/i.saocom.import/Makefile create mode 100755 src/imagery/i.saocom/i.saocom.import/i.saocom.import.html create mode 100644 src/imagery/i.saocom/i.saocom.import/i.saocom.import.py diff --git a/src/imagery/i.saocom/Makefile b/src/imagery/i.saocom/Makefile new file mode 100644 index 0000000000..88e7c34f58 --- /dev/null +++ b/src/imagery/i.saocom/Makefile @@ -0,0 +1,13 @@ +MODULE_TOPDIR =../.. + +PGM = i.saocom + +SUBDIRS = i.saocom.geocode \ + i.saocom.import \ + +include $(MODULE_TOPDIR)/include/Make/Dir.make + +default: parsubdirs htmldir + +install: installsubdirs + $(INSTALL_DATA) $(PGM).html $(INST_DIR)/docs/html/ diff --git a/src/imagery/i.saocom/i.saocom.geocode/Makefile b/src/imagery/i.saocom/i.saocom.geocode/Makefile new file mode 100755 index 0000000000..039f345242 --- /dev/null +++ b/src/imagery/i.saocom/i.saocom.geocode/Makefile @@ -0,0 +1,7 @@ +MODULE_TOPDIR = ../.. + +PGM = i.saocom.geocode + +include $(MODULE_TOPDIR)/include/Make/Script.make + +default: script diff --git a/src/imagery/i.saocom/i.saocom.geocode/i.saocom.geocode.html b/src/imagery/i.saocom/i.saocom.geocode/i.saocom.geocode.html new file mode 100755 index 0000000000..9d91cf83d7 --- /dev/null +++ b/src/imagery/i.saocom/i.saocom.geocode/i.saocom.geocode.html @@ -0,0 +1,49 @@ +

DESCRIPTION

+ +The i.saocom.geocode module allows allows the projection of SAOCOM-1 L1A raw or derived products from radar coordinates to a cartographic coordinate system (CS). This can be applied either to bands imported by i.saocom.import and to any raster map calculated from these inputs, or directly to the SAOCOM original files. The tool does not currently support the geocoding of image subsets, so the whole extent must be processed. + +

NOTES

+ +When the tool is directly run on the original SAOCOM files, it will internally call i.saocom.import to import the real and imaginary bands to a temporary XY unprojected location. In this case the data option must be used. If the user wants to geocode already imported files, the map option must be specified. The tool will not allow the use of both options, either one of them must be selected. + +This module makes use of the GCPS.csv file generated by i.saocom.import and associated to a specific image. This GCP file is associated to the image basename specified in the option basename. + +The tool will write the output to a Geotiff external file in the directory specified in the dbase option. The output files will be projected to the CS of the target location indicated in the option location. If the specified location does not exits, GRASS will create it with the CS EPSG:4326. The output map name will we the same as the input map, with the suffix _geo added at the end. + + +

EXAMPLES

+ +

Within an XY unprojeted location where the SAOCOM-1 bands have already been imported and processed, create an amplitude image from the real and imaginary bands, geocode it and then import it to a location called saocom_geo

+ +
+#Calculate the amplitude image 
+i.sar.amplitude real='SAO1B_20211222_hh_real' imag='SAO1B_20211222_hh_imag' output='SAO1B_20211222_hh_amp' 
+
+#Geocode it and import it to new location. The external temporary raster will be saved as GeoTiff in the $HOME directory
+i.saocom.geocode map='SAO1B_20211222_hh_amp' basename='SAO1B_20211222' dbase=$HOME location='saocom_geo'
+
+ +

Geocode the real and imaginary bands of a SAOCOM L1A image and import them to a location called geo_location

+ +
+zip_file = 'S1B_OPER_SAR_EOSSP__CORE_L1A_OLF_20211225T165228.zip'
+i.saocom.geocode data=zip_file pols=['hh'] multilook=[8,4] basename='SAO1B_20211222' location='geo_location' dbase ='$HOME' )
+
+ +The previous example will run i.saocom.import to generate the real and imaginary bands for the polarimetric channels specified in the pols option and will apply +the multilook factor indicated in the multilook option. After that it will geocode the real and imaginary bands and import them to the target location. + +

REFERENCES

+ +Reference or references to paper related to the tool or references which algorithm the tool is based on. + +

SEE ALSO

+ +i.saocom.import, +i.sar.amplitude, +i.sar.speckle, +i.sar.pauliRGB + +

AUTHORS

+ +Santiago Seppi, CONAE, Argentina. diff --git a/src/imagery/i.saocom/i.saocom.geocode/i.saocom.geocode.py b/src/imagery/i.saocom/i.saocom.geocode/i.saocom.geocode.py new file mode 100755 index 0000000000..69bf8444fe --- /dev/null +++ b/src/imagery/i.saocom/i.saocom.geocode/i.saocom.geocode.py @@ -0,0 +1,237 @@ +#!/usr/bin/env python3 + +############################################################################ +# +# MODULE: i.saocom.geocode +# +# AUTHOR: Santiago Seppi +# +# PURPOSE: Geocode SAOCOM SLC derived products using information from Ground Control Points (GCPs). The program writes the geocoded grid to a temporary external file, and then imports it to a new location and mapset. +# +# COPYRIGHT: (C) 2002-2023 by the GRASS Development Team +# +# This program is free software under the GNU General Public +# License (>=v2). Read the file COPYING that comes with GRASS +# for details. +# +# +############################################################################# + +# %Module +# % description: Geocode SAOCOM SLC derived products +# % keyword: imagery +# % keyword: saocom +# % keyword: sar +# % keyword: radar +# % overwrite: yes +# %End +# %option G_OPT_R_INPUT +# % key: map +# % required: no +# % description: Map to be geocoded, in radar coordinates +# %end +# %option +# % key: data +# % type: string +# % required: no +# % multiple: no +# % description: Path to data directory (ZIP or folder) +# %end +# %option +# % key: is_zip +# % type: string +# % required: no +# % multiple: no +# % answer: yes +# % options: yes,no +# % description: Whether the data directory is zipped or not. Only required if geocoding is to ble applied on the original files +# %end +# %option +# % key: pols +# % type: string +# % required: no +# % multiple: yes +# % answer: ['hh','hv','vh','vv'] +# % description: Polarizations to process . Only required if geocoding is to ble applied on the original files. (Default:['hh','hv','vh','vv']) +# %end +# %option +# % key: multilook +# % type: integer +# % required: no +# % multiple: yes +# % answer: 1,1 +# % description: Azimuth and range factors to apply (eg: [4,2])). Only required if geocoding is to be applied on the original files +# %end +# %option +# % key: basename +# % type: string +# % required: yes +# % multiple: no +# % description: Basename folder contaning the GCPS info. This folder is generated by i.saocom.import +# %end +#%option +#% key: location +#% type: string +#% multiple: no +#% required: yes +#% description: Location where the geocoded map will be stored +#%end +#%option G_OPT_M_DIR +#% key: dbase +#% multiple: no +#% required: yes +#% description: GRASS GIS database directory to store the external geocoded map +#%end + + +import os +import numpy as np +import grass.script as grass +from grass.pygrass.modules.shortcuts import general as g +from grass.pygrass.modules.shortcuts import raster as r +from zipfile import ZipFile +import rasterio +from rasterio.mask import mask +from rasterio.vrt import WarpedVRT +import geopandas as gpd +import numpy as np +from xml.etree import ElementTree as ET +from osgeo import gdal +from affine import Affine +import pandas as pd +import shutil +from grass.exceptions import ParameterError + + + +def save_GeoTiff(fn, crs, transform, mat, meta=None, nodata=None, bandnames=[]): + if len(mat.shape)==2: + count=1 + else: + count=mat.shape[0] + + if not meta: + meta = {} + + meta['driver'] = 'GTiff' + meta['height'] = mat.shape[-2] + meta['width'] = mat.shape[-1] + meta['count'] = count + meta['crs'] = crs + meta['transform'] = transform + + if 'dtype' not in meta: #if no datatype is specified, use float32 + meta['dtype'] = np.float32 + + + if nodata==None: + pass + else: + meta['nodata'] = nodata + + with rasterio.open(fn, 'w', **meta) as dst: + if count==1: # Mono-band raster + dst.write(mat.astype(meta['dtype']), 1) + if bandnames: + dst.set_band_description(1, bandnames[0]) + else: # Multi-band raster + for b in range(count): + dst.write(mat[b].astype(meta['dtype']), b+1) + for b,bandname in enumerate(bandnames): + dst.set_band_description(b+1, bandname) + +def read_gcps(gcp_base_folder): + df_gcps = pd.read_csv(os.path.join(gcp_base_folder,'GCPS.csv')) + gcps = [] + for i,d in df_gcps.iterrows(): + gcp = rasterio.control.GroundControlPoint(d.row, d.col, d.x, d.y, d.z, d.id, d.info) + gcps.append(gcp) + return gcps + +def geocode_file(input_map,basename,outdir,output_map,format = 'GTiff'): + #Write the map to Geotiff file + grass.run_command("r.out.gdal", input = input_map, output = os.path.join(outdir,output_map), format = 'GTiff') + #Read as rasterio dataset + ds = rasterio.open(os.path.join(outdir,output_map)) + ds = ds.read()[0] + #Read the GCPS dataframe + env = grass.gisenv() + gcp_base_folder = os.path.join(env["GISDBASE"], env["LOCATION_NAME"], env["MAPSET"], "cell_misc",basename) + gcps = read_gcps(gcp_base_folder) + #Save the geocoded raster (it will replace the previous intermediate file) + geoTs = rasterio.transform.from_gcps(gcps) + crs = rasterio.crs.CRS.from_epsg(4326) + save_GeoTiff(fn = os.path.join(outdir,output_map), crs = crs, transform = geoTs, mat = ds) + +def export_to_location(outdir,location,input_map,int_map,env): + #Run gdalWarp. This is made to avoid ERROR: Input map is rotated - cannot import + output_warp = f'gdalwarp_{int_map}' + os.system(f'gdalwarp {os.path.join(outdir,int_map)} {os.path.join(outdir,output_warp)}') + + grass.warning(_('Switching location')) + + #Create the new location with EPSG:4326, in case it does not exist + location_folder = env["GISDBASE"] + out_location = os.path.join(location_folder,location) + if not os.path.exists(out_location): + grass.create_location(env["GISDBASE"], location, epsg=4326, desc='Location created by i.saocom.geocode') + + grass.run_command('g.mapset',mapset = 'PERMANENT',location = location) + grass.run_command("r.import", input = os.path.join(outdir,output_warp), output = f'{input_map}') + os.remove(os.path.join(outdir,output_warp)) + + +def main(): + input_map = options['map'] + data = options["data"] + zip_v = options["is_zip"] + pols = options['pols'] + multilook = options['multilook'] + basename = options["basename"] + location = options['location'] + outdir = options['dbase'] + env = grass.gisenv() + + if not input_map and not data: + grass.fatal(_("Either one of input map or data folder/zip must be specified")) + + if input_map and data: + grass.fatal(_("Either one of input map or data folder/zip must be specified, not both")) + + if not input_map and data: + #Import real and imaginary bands to a temporary location and geocode them to external file + grass.message(_("Running i.saocom.import")) + grass.create_location(env["GISDBASE"], f'{basename}_XY_tempLocation',overwrite=1) + grass.run_command('g.mapset',mapset = 'PERMANENT',location = f'{basename}_XY_tempLocation') + grass.run_command('i.saocom.import',data=data,is_zip=zip_v,pols=pols,multilook=multilook,basename=basename) + #Get the list of maps to be geocoded + map_list = grass.list_grouped(type="raster",pattern = f'{basename}*')['PERMANENT'] + for m in map_list: + grass.run_command('g.region',raster=m) + geocode_file(input_map=m,basename=basename,outdir=outdir,output_map=f'{m}.tif',format = 'GTiff') + #Import the geocoded bands into the target location + export_to_location(outdir=outdir,location=location,input_map=f'{m}_geo',int_map=f'{m}.tif',env=env) + #Remove intermediate files + os.remove(os.path.join(outdir,f'{m}.tif')) + #Go back to temporary location to continue exporting + grass.run_command('g.mapset',mapset = 'PERMANENT',location = f'{basename}_XY_tempLocation') + #Go back to original location + grass.run_command('g.mapset',mapset = env["MAPSET"],location = env["LOCATION_NAME"]) + shutil.rmtree(os.path.join(env["GISDBASE"], f'{basename}_XY_tempLocation')) + + if input_map and not data: + #Check if this an XY location + proj = grass.read_command('g.proj', flags ='g').split('=')[1].split('\n')[0] + if proj != 'xy_location_unprojected': + raise ValueError('Current location is not XY unprojected (radar coordinates)') + geocode_file(input_map=input_map,basename=basename,outdir=outdir,output_map=f'{input_map}.tif',format = 'GTiff') + export_to_location(outdir=outdir,location=location,input_map=f'{input_map}_geo',int_map=f'{input_map}.tif',env=env) + #Remove intermediate files + os.remove(os.path.join(outdir,f'{input_map}.tif')) + #Go back to original location + grass.run_command('g.mapset',mapset = env["MAPSET"],location = env["LOCATION_NAME"]) + + +if __name__ == "__main__": + options, flags = grass.parser() + main() diff --git a/src/imagery/i.saocom/i.saocom.html b/src/imagery/i.saocom/i.saocom.html new file mode 100644 index 0000000000..24015456a5 --- /dev/null +++ b/src/imagery/i.saocom/i.saocom.html @@ -0,0 +1,41 @@ + + + +i.saocom toolset - GRASS GIS manual + + + + + +
+ +GRASS logo +
+ +

NAME

+ +i.saocom - Toolset to import and process SAOCOM-1 L1A products. + +

KEYWORDS

+imagery, +import, +satellite + + +

DESCRIPTION

+ +The i.saocom toolset consists of two modules: + +
+
i.saocom.import
+
Imports SAOCOM-1 data L1A (SLC) products
+
i.saocom.geocode
+
Projects SAOCOM-1 L1A derived products to a cartographic coordinate system and imports them to a new location
+
+ +

AUTHORS

+ +Santiago Seppi, CONAE, Argentina + +

SOURCE CODE

+ diff --git a/src/imagery/i.saocom/i.saocom.import/Makefile b/src/imagery/i.saocom/i.saocom.import/Makefile new file mode 100755 index 0000000000..ed77eec51a --- /dev/null +++ b/src/imagery/i.saocom/i.saocom.import/Makefile @@ -0,0 +1,7 @@ +MODULE_TOPDIR = ../.. + +PGM = i.saocom.import + +include $(MODULE_TOPDIR)/include/Make/Script.make + +default: script diff --git a/src/imagery/i.saocom/i.saocom.import/i.saocom.import.html b/src/imagery/i.saocom/i.saocom.import/i.saocom.import.html new file mode 100755 index 0000000000..fe2bfdd705 --- /dev/null +++ b/src/imagery/i.saocom/i.saocom.import/i.saocom.import.html @@ -0,0 +1,65 @@ +

DESCRIPTION

+ +The i.saocom.import module allows importing SAOCOM-1 L1A (SLC) products from their native format, as provided by CONAE. +SLC products are complex matrices, but GRASS will import them as two separate bands containing the real and imaginary parts. This structure allows for further manipulation and prevents from losing important information. + +

+By default i.saocom.import will process all the available polarizations, which can be selected with the pols option. +The module assumes by default that the data is zipped but this can be changed with the is_zip option. + +

+The user can also apply a multilooking factor, which must be indicated as a list, followinf the order [az_loos,rg_looks]. +By default no multilooking is applied. + +

+The module requires to specify a basename value which will be used as prefix for all the polarization bands to be imported. Additionaly, a Ground Control Points file +will associated to this basename will be created within de GRASSDATA directory, in case the user performs later geocoding with i.saocom.geocode. This GCP information is extracted from the original SAOCOM-1 matrix using Python rasterio library and will account for any multilooking applied to the images. + +

NOTES

+ +SAOCOM L1A images are projected in radar coordinates. To run this module it is important to previously create an XY (unprojected) location. +A file named GCPS.csv with the Ground Control Points information will be stored in the current location's cell_misc directory, inside a sub-folder that will be named after the basename value. + +

EXAMPLES

+ +

Import all polarizations

+ +Firstly, an unprojected (XY) location must be created, the example below creates a location called saocom: + +
+grass -c XY saocom -e
+
+ +Then, run i.saocom.import from a zip file containing pols = ['hh','hv','vh','vv']: + +
+zip_file = 'S1B_OPER_SAR_EOSSP__CORE_L1A_OLF_20211225T165228.zip'
+i.saocom.import data=zip_file is_zip='yes' basename='SAO1B_20211222'
+
+ +The previous example will create two bands using the given basename as prefix: SAO1B_20211222_[pol]_r (real band) SAO1B_20211222_[pol]_i (imaginary band). [pol] +indicates the imported polarization, which for SAOCOM images can be any of ['hh','hv','vh','vv']. + +

Import specific polarizations and apply multilooking

+ +
+zip_file = 'S1B_OPER_SAR_EOSSP__CORE_L1A_OLF_20211225T165228.zip'
+i.saocom.import data=zip_file is_zip ='yes' basename='SAO1B_20211222' pols=['hh','vv'] multilook=[4,2]
+
+ +The previous example will import only the hh and vv vv polarizations, and in case none of them are found the program will let the user know which are the available polarization channels in the dataset. The multilooking factor will be of 4 in azimuth direction and 2 in range direction. + +

REFERENCES

+ +Reference or references to paper related to the tool or references which algorithm the tool is based on. + +

SEE ALSO

+ +i.saocom.geocode, +i.sar.amplitude, +i.sar.speckle, +i.sar.pauliRGB + +

AUTHORS

+ +Santiago Seppi, CONAE, Argentina. diff --git a/src/imagery/i.saocom/i.saocom.import/i.saocom.import.py b/src/imagery/i.saocom/i.saocom.import/i.saocom.import.py new file mode 100644 index 0000000000..0ec887c57e --- /dev/null +++ b/src/imagery/i.saocom/i.saocom.import/i.saocom.import.py @@ -0,0 +1,249 @@ +#!/usr/bin/env python3 + +############################################################################ +# +# MODULE: i.sa +# +# AUTHOR: Santiago Seppi +# +# PURPOSE: Read SAOCOM SLC files into real and imaginary bands +# +# COPYRIGHT: (C) 2002-2023 by the GRASS Development Team +# +# This program is free software under the GNU General Public +# License (>=v2). Read the file COPYING that comes with GRASS +# for details. +# +# +############################################################################# + +# %Module +# % description: Read SAOCOM SLC file into GRASS as real and imaginary bands +# % keyword: imagery +# % keyword: saocom +# % keyword: sar +# % keyword: radar +# % overwrite: yes +# %End +# %option +# % key: data +# % type: string +# % required: yes +# % multiple: no +# % description: Path to data directory (ZIP or folder) +# %end +# %option +# % key: is_zip +# % type: string +# % required: yes +# % multiple: no +# % answer: yes +# % options: yes,no +# % description: Whether the data directory is zipped or not +# %end +# %option +# % key: pols +# % type: string +# % required: yes +# % multiple: yes +# % answer: ['hh','hv','vh','vv'] +# % description: Polarizations to process (Default:['hh','hv','vh','vv']) +# %end +# %option +# % key: multilook +# % type: integer +# % required: yes +# % multiple: yes +# % answer: 1,1 +# % description: Azimuth and range factors to apply (eg: [4,2])) +# %end +# %option G_OPT_R_OUTPUT +# % key: basename +# % description: Prefix for output raster map +# % required: yes +# %end + + +import os +import numpy as np +import grass.script as grass +from grass.pygrass.modules.shortcuts import general as g +from grass.pygrass.modules.shortcuts import raster as r +from zipfile import ZipFile +import rasterio +from rasterio.mask import mask +from rasterio.vrt import WarpedVRT +import geopandas as gpd +import numpy as np +from xml.etree import ElementTree as ET +from osgeo import gdal +from affine import Affine +import pandas as pd + + +def apply_multilook(dataset, azLooks, rgLooks): + ''' + Esta función aplica un multilook dado a una imagen de entrada y actualiza la información de los metadatos + para la imagen de salida. + + parámetros: + dataset: diccionario de datos con las llaves: + 'array': contiene la matriz de datos + 'metadata': contiene los metadatos con el formato dado por la librería rasterio + azLooks: número de looks a aplicar en dirección de azimuth + rgLooks: número de looks a aplicar en dirección de rango + + retorna: + diccionario de datos con la estructura del dataset de entrada pero con el array resultante del + multilook y los metadatos actualizados + ''' + + import numpy as np + from rasterio import Affine + + array = dataset['array'].copy() + metadata = dataset['metadata'].copy() + + array = array[0] + + cols = metadata['width'] + rows = metadata['height'] + new_rows = rows//azLooks + new_cols = cols//rgLooks + new_shape = (new_rows, azLooks, new_cols, rgLooks) + + if rows%azLooks!=0 or cols%rgLooks!=0: + array = array[:new_rows*azLooks,:new_cols*rgLooks] + + multilooked = array.reshape(new_shape).mean(-1).mean(1) + metadata['width'] = new_cols + metadata['height'] = new_rows + geoTs = metadata['transform'] + metadata['transform'] = Affine(geoTs[0]*rgLooks, geoTs[1], geoTs[2], geoTs[3], geoTs[4]*azLooks, geoTs[5]) + + return {'array': np.expand_dims(multilooked, axis=0), 'metadata': metadata} + + + +def read_bands_zip(data, pols): + with ZipFile(data,'r') as zfile: + file_list = [img for img in zfile.namelist() if img.startswith('Data/') and not img.endswith('.xml')] + bands = {} + gcps = tuple() + dataset_pols = [] + for l in file_list: + pol = l.split('-')[6] + dataset_pols.append(pol) + if pol in pols: + bands[pol] = {} + filename = f'/vsizip/{data}/{l}' + with rasterio.open(filename) as banda: + bands[pol]['array'] = banda.read() + bands[pol]['metadata'] = banda.meta + gcps = banda.get_gcps() + return bands,gcps,dataset_pols + +def read_bands_folder(data, pols): + file_list = [img for img in os.listdir(os.path.join(data,'Data')) if not img.endswith('.xml')] + bands = {} + gcps = tuple() + dataset_pols = [] + for l in file_list: + pol = l.split('-')[6] + dataset_pols.append(pol) + if pol in pols: + bands[pol] = {} + filename = os.path.join(data,'Data',l) + with rasterio.open(filename) as banda: + bands[pol]['array'] = banda.read() + bands[pol]['metadata'] = banda.meta + gcps = banda.get_gcps() + return bands,gcps,dataset_pols + + +def save_bands(bands,basename): + for band in bands: + #Change the band metadata: + #Data type must be changed from complex to float + bands[band]['metadata']['dtype'] = np.float32 + #The Y-resolution must be set to negative, otherwise GRASS will interpret the map is flipped + geoTs = bands[band]['metadata']['transform'] + bands[band]['metadata']['transform'] = Affine(geoTs[0], geoTs[1], geoTs[2], geoTs[3], -geoTs[4], geoTs[5]) + outputfn_r = f'{basename}_{band}_real.tif' + outputfn_i = f'{basename}_{band}_imag.tif' + with rasterio.open(outputfn_r, 'w', **bands[band]['metadata']) as dst: + dst.write(bands[band]['array'].real) + with rasterio.open(outputfn_i, 'w', **bands[band]['metadata']) as dst: + dst.write(bands[band]['array'].imag) + +def main(): + #xemt = options["xemt"] + data = options["data"] + zip_v = options["is_zip"] + basename = options["basename"] + pols = options['pols'] + multilook = options['multilook'] + + if zip_v == 'yes': + bands,gcps,dataset_pols = read_bands_zip(data, pols) + else: + bands,gcps,dataset_pols = read_bands_folder(data, pols) + + if len(bands) == 0 or len(gcps) == 0: + grass.fatal(_(f'None of the specified polarizations were found in the dataset \n Please try one of the folowing: {dataset_pols}')) + #pass + + else: + #Create a dataframe containing GCP information + cols = gcps[0][0].asdict().keys() + df = pd.DataFrame(columns = cols) + for i,gcp in enumerate(gcps[0]): + df1 = pd.DataFrame(gcp.asdict(), index = [i]) + df = pd.concat((df,df1)) + + + if multilook[0] != 1 or multilook[2] != 1: + # ~ print(f'Appying ML factor: {multilook}') + grass.message(_(f'Appying ML factor: {multilook}')) + for band in bands: + dim = bands[band]['array'].shape + # ~ print('Original shape ', bands[band]['array'].shape) + grass.message(_(f'Original shape {dim}')) + ml_dic = apply_multilook(bands[band], int(multilook[0]), int(multilook[2])) + bands[band]['array'] = ml_dic['array'] + bands[band]['metadata'] = ml_dic['metadata'] + dim = bands[band]['array'].shape + # ~ print('Shape after ML', bands[band]['array'].shape) + grass.message(_(f'Shape after ML {dim}')) + # Update GCP information + # ~ print('Updating GCP information for later geocoding') + grass.message(_('Updating GCP information for later geocoding')) + df['row'] /= int(multilook[0]) + df['col'] /= int(multilook[2]) + + # ~ print('Saving real and imaginary bands to intermediate GeoTiff outputs') + grass.message(_('Saving real and imaginary bands to intermediate GeoTiff outputs')) + save_bands(bands,basename) + + # ~ print('Reading real and imaginary bands into GRASS GIS, and cleaning intermediate files') + grass.message(_('Reading real and imaginary bands into GRASS GIS, and cleaning intermediate files')) + for band in bands: + input_r = f'{basename}_{band}_real.tif' + input_i = f'{basename}_{band}_imag.tif' + grass.run_command("r.import", input=input_r, output = input_r.split('.tif')[0]) + grass.run_command("r.import", input=input_i, output = input_i.split('.tif')[0]) + os.remove(input_r) + os.remove(input_i) + + # ~ print('Saving GCP information as support file') + grass.message(_('Saving GCP information as support file')) + env = grass.gisenv() + gcp_base_folder = os.path.join(env["GISDBASE"], env["LOCATION_NAME"], env["MAPSET"], "cell_misc",basename) + if not os.path.isdir(gcp_base_folder): + os.makedirs(gcp_base_folder) + df.to_csv(os.path.join(gcp_base_folder,'GCPS.csv')) + + +if __name__ == "__main__": + options, flags = grass.parser() + main() From 6d6f61abc2e4f48b79cdd99a6eb1c9c0b1d74c69 Mon Sep 17 00:00:00 2001 From: Santiago riel Seppi Date: Tue, 10 Oct 2023 19:39:05 -0300 Subject: [PATCH 02/38] Add i.sar toolset --- src/imagery/i.sar/Makefile | 14 ++ src/imagery/i.sar/i.sar.amplitude/Makefile | 7 + .../i.sar.amplitude/i.sar.amplitude.html | 28 +++ .../i.sar/i.sar.amplitude/i.sar.amplitude.py | 52 ++++++ src/imagery/i.sar/i.sar.html | 44 +++++ src/imagery/i.sar/i.sar.pauliRGB/Makefile | 7 + .../i.sar/i.sar.pauliRGB/i.sar.pauliRGB.html | 43 +++++ .../i.sar/i.sar.pauliRGB/i.sar.pauliRGB.py | 80 +++++++++ src/imagery/i.sar/i.sar.speckle/Makefile | 7 + .../i.sar/i.sar.speckle/i.sar.speckle.html | 36 ++++ .../i.sar/i.sar.speckle/i.sar.speckle.py | 162 ++++++++++++++++++ 11 files changed, 480 insertions(+) create mode 100644 src/imagery/i.sar/Makefile create mode 100755 src/imagery/i.sar/i.sar.amplitude/Makefile create mode 100755 src/imagery/i.sar/i.sar.amplitude/i.sar.amplitude.html create mode 100755 src/imagery/i.sar/i.sar.amplitude/i.sar.amplitude.py create mode 100644 src/imagery/i.sar/i.sar.html create mode 100644 src/imagery/i.sar/i.sar.pauliRGB/Makefile create mode 100644 src/imagery/i.sar/i.sar.pauliRGB/i.sar.pauliRGB.html create mode 100644 src/imagery/i.sar/i.sar.pauliRGB/i.sar.pauliRGB.py create mode 100644 src/imagery/i.sar/i.sar.speckle/Makefile create mode 100644 src/imagery/i.sar/i.sar.speckle/i.sar.speckle.html create mode 100755 src/imagery/i.sar/i.sar.speckle/i.sar.speckle.py diff --git a/src/imagery/i.sar/Makefile b/src/imagery/i.sar/Makefile new file mode 100644 index 0000000000..7e2575922d --- /dev/null +++ b/src/imagery/i.sar/Makefile @@ -0,0 +1,14 @@ +MODULE_TOPDIR =../.. + +PGM = i.sar + +SUBDIRS = i.sar.amplitude \ + i.sar.pauliRGB \ + i.sar.speckle \ + +include $(MODULE_TOPDIR)/include/Make/Dir.make + +default: parsubdirs htmldir + +install: installsubdirs + $(INSTALL_DATA) $(PGM).html $(INST_DIR)/docs/html/ diff --git a/src/imagery/i.sar/i.sar.amplitude/Makefile b/src/imagery/i.sar/i.sar.amplitude/Makefile new file mode 100755 index 0000000000..115b542457 --- /dev/null +++ b/src/imagery/i.sar/i.sar.amplitude/Makefile @@ -0,0 +1,7 @@ +MODULE_TOPDIR = ../.. + +PGM = i.sar.amplitude + +include $(MODULE_TOPDIR)/include/Make/Script.make + +default: script diff --git a/src/imagery/i.sar/i.sar.amplitude/i.sar.amplitude.html b/src/imagery/i.sar/i.sar.amplitude/i.sar.amplitude.html new file mode 100755 index 0000000000..c5a65bf375 --- /dev/null +++ b/src/imagery/i.sar/i.sar.amplitude/i.sar.amplitude.html @@ -0,0 +1,28 @@ +

DESCRIPTION

+ +The i.sar.amplitude module is used to calculate an amplitude image from a real and imaginary band of an SLC SAR image. It is intended for any SAR image whose real and +imaginary bands have been imported to GRASS. The module uses r.mapcalc to compute the output. + +

EXAMPLES

+ +

Calculate the amplitude map from a SAOCOM-1 imaginary and real bands

+ +
+i.sar.amplitude real='SAO1B_20211222_hh_real' imag='SAO1B_20211222_hh_imag' output=real='SAO1B_20211222_hh_amplitude'
+
+ +

REFERENCES

+ +Reference or references to paper related to the tool or references which algorithm the tool is based on. + +

SEE ALSO

+ +r.mapcalc, +i.saocom.import, +i.saocom.geocode, +i.sar.speckle, +i.sar.pauliRGB + +

AUTHORS

+ +Santiago Seppi, CONAE, Argentina diff --git a/src/imagery/i.sar/i.sar.amplitude/i.sar.amplitude.py b/src/imagery/i.sar/i.sar.amplitude/i.sar.amplitude.py new file mode 100755 index 0000000000..19d8bede40 --- /dev/null +++ b/src/imagery/i.sar/i.sar.amplitude/i.sar.amplitude.py @@ -0,0 +1,52 @@ +#!/usr/bin/env python3 + +############################################################################ +# +# MODULE: i.sar.amplitude +# +# AUTHOR: Santiago Seppi +# +# PURPOSE: Computation of amplitude map for SLC complex SAR image +# +# COPYRIGHT: (C) 2002-2023 by the GRASS Development Team +# +# This program is free software under the GNU General Public +# License (>=v2). Read the file COPYING that comes with GRASS +# for details. +# +# +############################################################################# + +# %module +# % description: Calculates amplitude for SAR image +# %end +# %option G_OPT_R_INPUT +# % key: real +# % description: Name of real band +# %end +# %option G_OPT_R_INPUT +# % key: imag +# % description: Name of imaginary band +# %end +# %option G_OPT_R_OUTPUT +# % key: output +# %end + +import subprocess +import sys + +import grass.script as gs + + +def main(): + options, flags = gs.parser() + real = options["real"] + imag = options['imag'] + raster_output = options["output"] + amplitude_formula = f'{raster_output} = sqrt(pow({real},2) + pow({imag},2))' + + gs.mapcalc(exp=amplitude_formula) + + +if __name__ == "__main__": + main() diff --git a/src/imagery/i.sar/i.sar.html b/src/imagery/i.sar/i.sar.html new file mode 100644 index 0000000000..3ddd941a9d --- /dev/null +++ b/src/imagery/i.sar/i.sar.html @@ -0,0 +1,44 @@ + + + +i.sar toolset - GRASS GIS manual + + + + + +
+ +GRASS logo +
+ +

NAME

+ +i.sar - Toolset to process SAR products. + +

KEYWORDS

+imagery, +import, +satellite + + +

DESCRIPTION

+ +The i.sar toolset consists of three modules: + +
+
i.sar.speckle
+
A simple procedure to reduce speckle noise in SAR images
+
i.sar.amplitude
+
Module used to calculate an amplitude image from real and imaginary bands
+
i.sar.pauliRGB
+
Module used to generate the three bands that form the Pauli RGB SAR composition
+
+ + +

AUTHORS

+Margherita Di Leo
+Santiago Seppi, CONAE, Argentina + +

SOURCE CODE

+ diff --git a/src/imagery/i.sar/i.sar.pauliRGB/Makefile b/src/imagery/i.sar/i.sar.pauliRGB/Makefile new file mode 100644 index 0000000000..993fb6a86f --- /dev/null +++ b/src/imagery/i.sar/i.sar.pauliRGB/Makefile @@ -0,0 +1,7 @@ +MODULE_TOPDIR = ../.. + +PGM = i.sar.pauliRGB + +include $(MODULE_TOPDIR)/include/Make/Script.make + +default: script diff --git a/src/imagery/i.sar/i.sar.pauliRGB/i.sar.pauliRGB.html b/src/imagery/i.sar/i.sar.pauliRGB/i.sar.pauliRGB.html new file mode 100644 index 0000000000..c17287718e --- /dev/null +++ b/src/imagery/i.sar/i.sar.pauliRGB/i.sar.pauliRGB.html @@ -0,0 +1,43 @@ +

DESCRIPTION

+ +The i.sar.pauliRGB module is used to generate the three bands that form the Pauli RGB SAR composition. The input are amplitude images and the output are three bands: + +
+
- Band for the red channel, equal to HH-VV +
- Band for the green channel, equal to 2*HV +
- Band for the blue channel, equal to HH+VV +
+ +The output bands are prefixed with the value given to the basename option. Color enhancement can be optionally applied with the strength option, the parameter used +in i.colors.enhance. + +

EXAMPLES

+ +

Create the Pauli RGB bands and apply a color enhance with a strength of 98%

+ +
+i.sar.pauliRGB hh='SAO1B_20211222_hh_amp_mean7x7' vv='SAO1B_20211222_vv_amp_mean7x7' hv='SAO1B_20211222_hv_amp_mean7x7' basename='SAO1B_20211222' strength=98
+
+#Check the creation of the Pauli bands:
+g.list type='raster' pattern='*Pauli*'
+
+#Output:
+SAO1B_20211222_Pauli_Blue
+SAO1B_20211222_Pauli_Green
+SAO1B_20211222_Pauli_Red
+
+ +

REFERENCES

+ +GAMMA Remote Sensing AG. User's Guide: Polarimetric Tools. + +

SEE ALSO

+ +r.mapcalc, +i.colors.enhance, +i.sar.speckle, +i.sar.amplitude + +

AUTHOR

+ +Santiago Seppi, CONAE, Argentina diff --git a/src/imagery/i.sar/i.sar.pauliRGB/i.sar.pauliRGB.py b/src/imagery/i.sar/i.sar.pauliRGB/i.sar.pauliRGB.py new file mode 100644 index 0000000000..04c43953b3 --- /dev/null +++ b/src/imagery/i.sar/i.sar.pauliRGB/i.sar.pauliRGB.py @@ -0,0 +1,80 @@ +#!/usr/bin/env python3 + +############################################################################ +# +# MODULE: i.sar.saocomSLC +# +# AUTHOR: Santiago Seppi +# +# PURPOSE: Create the RGB bands for the Pauli combination +# +# COPYRIGHT: (C) 2002-2023 by the GRASS Development Team +# +# This program is free software under the GNU General Public +# License (>=v2). Read the file COPYING that comes with GRASS +# for details. +# +# +############################################################################# + +# %Module +# % description: Create the RGB bands for the Pauli combination. +# % keyword: imagery +# % keyword: sar +# % keyword: radar +# % keyword: rgb +# % overwrite: yes +# %End +# %option G_OPT_R_INPUT +# % key: hh +# % description: HH polarization band +# %end +# %option G_OPT_R_INPUT +# % key: vv +# % description: VV polarization band +# %end +# %option G_OPT_R_INPUT +# % key: hv +# % description: HV polarization band +# %end +# %option G_OPT_R_OUTPUT +# % key: basename +# % description: Prefix for output raster maps +# % required: yes +# %end +# %option +# % key: strength +# % type: double +# % description: Cropping intensity (upper brightness level) +# % options: 0-100 +# % required: no +# %end + +import subprocess +import sys + +import grass.script as grass + +def main(): + hh = options['hh'] + vv = options['vv'] + hv = options['hv'] + basename = options['basename'] + strength = options['strength'] + pauli_red = f'{basename}_Pauli_Red = {hh}-{vv}' + grass.mapcalc(exp=pauli_red) + pauli_green = f'{basename}_Pauli_Green = 2*{hv}' + grass.mapcalc(exp=pauli_green) + pauli_blue = f'{basename}_Pauli_Blue = {hh}+{vv}' + grass.mapcalc(exp=pauli_blue) + + if strength: + grass.run_command("i.colors.enhance", + red=f'{basename}_Pauli_Red', + green=f'{basename}_Pauli_Green', + blue=f'{basename}_Pauli_Blue', + strength=strength) + +if __name__ == "__main__": + options, flags = grass.parser() + main() diff --git a/src/imagery/i.sar/i.sar.speckle/Makefile b/src/imagery/i.sar/i.sar.speckle/Makefile new file mode 100644 index 0000000000..614ff88031 --- /dev/null +++ b/src/imagery/i.sar/i.sar.speckle/Makefile @@ -0,0 +1,7 @@ +MODULE_TOPDIR = ../.. + +PGM = i.sar.speckle + +include $(MODULE_TOPDIR)/include/Make/Script.make + +default: script diff --git a/src/imagery/i.sar/i.sar.speckle/i.sar.speckle.html b/src/imagery/i.sar/i.sar.speckle/i.sar.speckle.html new file mode 100644 index 0000000000..f98d680d21 --- /dev/null +++ b/src/imagery/i.sar/i.sar.speckle/i.sar.speckle.html @@ -0,0 +1,36 @@ +

DESCRIPTION

+ +

A simple procedure to reduce speckle noise in SAR images. + +

So far, the implemented algorithms are Lee filter, mean and gaussian. The +method parameter is set to lee by default. + +

The size parameter is the one used in +r.neighbors and is used to calculate local +mean and local square mean for the Lee filter. It must be odd. +The same parameter is used for the other two methods, and in case the gaussian one is selected, a standard deviation +value must also be specified. + +

EXAMPLES

+ +

Apply a speckle filter using the gaussian method with a 7x7 window and a standard deviation = 1

+ +
+i.sar.speckle input='SAO1B_20211222_hh_amp' output='SAO1B_20211222_hh_amp_gauss7x7' method='gauss' size=7 std=1
+
+ +

REFERENCES

+ +Lee, J. S. (1986). Speckle suppression and analysis for synthetic aperture +radar images. Optical engineering, 25(5), 255636. + +

SEE ALSO

+ +r.neighbors, +i.sar.speckle, +i.sar.pauliRGB + +

AUTHOR

+ +Margherita Di Leo
+Santiago Seppi, CONAE, Argentina diff --git a/src/imagery/i.sar/i.sar.speckle/i.sar.speckle.py b/src/imagery/i.sar/i.sar.speckle/i.sar.speckle.py new file mode 100755 index 0000000000..e449d800c2 --- /dev/null +++ b/src/imagery/i.sar/i.sar.speckle/i.sar.speckle.py @@ -0,0 +1,162 @@ +#!/usr/bin/env python3 + +############################################################################ +# +# MODULE: i.sar.speckle +# +# AUTHOR: Margherita Di Leo +# +# PURPOSE: Speckle noise removal for synthetic aperture radar (SAR) images +# +# COPYRIGHT: (C) 2002-2019 by the GRASS Development Team +# +# This program is free software under the GNU General Public +# License (>=v2). Read the file COPYING that comes with GRASS +# for details. +# +# REFERENCES: +# +# Lee, J. S. (1986). Speckle suppression and analysis for synthetic aperture +# radar images. Optical engineering, 25(5), 255636. +# +############################################################################# + +# %Module +# % description: Remove speckle from SAR image +# % keyword: imagery +# % keyword: speckle +# % keyword: sar +# % keyword: radar +# % overwrite: yes +# %End +# %option G_OPT_R_INPUT +# % key: input +# % description: Name of input image +# % required: yes +# %end +# %option G_OPT_R_OUTPUT +# % key: output +# % description: Name of output image +# % required: yes +# %end +# %option +# % key: method +# % description: Method for speckle removal +# % options: lee,mean,gauss +# % answer: lee +# % required: yes +# %end +# %option +# % key: size +# % type: integer +# % description: Size of neighborhood +# % answer: 11 +# % required: yes +# %end +# %option +# % key: std +# % type: float +# % description: Standard deviation value in case gaussian filter is selected +# % answer: 1 +# % required: no +# %end + + +import os +import grass.script as grass +from grass.pygrass.modules.shortcuts import general as g +from grass.pygrass.modules.shortcuts import raster as r + + +def lee_filter(img, size, img_out): + + pid = str(os.getpid()) + img_mean = "tmp%s_img_mean" % pid + img_sqr = "tmp%s_img_sqr" % pid + img_sqr_mean = "tmp%s_img_sqr_mean" % pid + img_variance = "tmp%s_img_variance" % pid + img_weights = "tmp%s_img_weights" % pid + + # Local mean + r.neighbors(input=img, size=size, method="average", output=img_mean) + # Local square mean + r.mapcalc("%s = %s^2" % (img_sqr, img)) + r.neighbors(input=img_sqr, size=size, method="average", output=img_sqr_mean) + # Local variance + r.mapcalc("%s = %s - (%s^2)" % (img_variance, img_sqr_mean, img_mean)) + # Overall variance + return_univar = grass.read_command("r.univar", map=img, flags="ge") + univar_stats = grass.parse_key_val(return_univar) + overall_variance = univar_stats["variance"] + # Weights + r.mapcalc( + "%s = %s / (%s + %s)" + % (img_weights, img_variance, img_variance, overall_variance) + ) + # Output + r.mapcalc( + "%s = %s + %s * (%s - %s)" % (img_out, img_mean, img_weights, img, img_mean) + ) + + # Cleanup + grass.message(_("Cleaning up intermediate files...")) + try: + grass.run_command( + "g.remove", flags="f", quiet=False, type="raster", pattern="tmp*" + ) + except: + """ """ + + return img_out + +def mean_filter(img, size, img_out): + + # Local mean + r.neighbors(input=img, size=size, method="average", output=img_out) + + return img_out + +def gauss_filter(img, size, std, img_out): + + # Gauss function + r.neighbors(input=img, size=size, weighting_function = "gaussian", weighting_factor = std, output=img_out) + + return img_out + +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.")) + + elif method == 'mean': + g.message(_("Applying Mean Filter")) + img_out = mean_filter(img, size, img_out) + g.message(_("Done.")) + + elif method == 'gauss': + std = options['std'] + g.message(_("Applying Gauss Filter")) + img_out = gauss_filter(img, size, std, img_out) + g.message(_("Done.")) + + else: + grass.fatal(_("The requested speckle filter is not yet implemented.")) + + +if __name__ == "__main__": + options, flags = grass.parser() + main() From d3d1b7c9955dbeebf3e5293975279ddd47828d2b Mon Sep 17 00:00:00 2001 From: Santiago riel Seppi Date: Wed, 11 Oct 2023 15:56:35 -0300 Subject: [PATCH 03/38] Run Black and flake8 to correct formatting of .py files --- .../i.saocom.geocode/i.saocom.geocode.py | 270 +++++++++------ .../i.saocom.import/i.saocom.import.py | 316 ++++++++++-------- .../i.sar/i.sar.amplitude/i.sar.amplitude.py | 4 +- .../i.sar/i.sar.pauliRGB/i.sar.pauliRGB.py | 46 +-- .../i.sar/i.sar.speckle/i.sar.speckle.py | 25 +- 5 files changed, 383 insertions(+), 278 deletions(-) diff --git a/src/imagery/i.saocom/i.saocom.geocode/i.saocom.geocode.py b/src/imagery/i.saocom/i.saocom.geocode/i.saocom.geocode.py index 69bf8444fe..4db868834c 100755 --- a/src/imagery/i.saocom/i.saocom.geocode/i.saocom.geocode.py +++ b/src/imagery/i.saocom/i.saocom.geocode/i.saocom.geocode.py @@ -69,19 +69,19 @@ # % multiple: no # % description: Basename folder contaning the GCPS info. This folder is generated by i.saocom.import # %end -#%option -#% key: location -#% type: string -#% multiple: no -#% required: yes -#% description: Location where the geocoded map will be stored -#%end -#%option G_OPT_M_DIR -#% key: dbase -#% multiple: no -#% required: yes -#% description: GRASS GIS database directory to store the external geocoded map -#%end +# %option +# % key: location +# % type: string +# % multiple: no +# % required: yes +# % description: Location where the geocoded map will be stored +# %end +# %option G_OPT_M_DIR +# % key: dbase +# % multiple: no +# % required: yes +# % description: GRASS GIS database directory to store the external geocoded map +# %end import os @@ -103,135 +103,201 @@ from grass.exceptions import ParameterError - def save_GeoTiff(fn, crs, transform, mat, meta=None, nodata=None, bandnames=[]): - if len(mat.shape)==2: - count=1 + if len(mat.shape) == 2: + count = 1 else: - count=mat.shape[0] + count = mat.shape[0] if not meta: meta = {} - meta['driver'] = 'GTiff' - meta['height'] = mat.shape[-2] - meta['width'] = mat.shape[-1] - meta['count'] = count - meta['crs'] = crs - meta['transform'] = transform + meta["driver"] = "GTiff" + meta["height"] = mat.shape[-2] + meta["width"] = mat.shape[-1] + meta["count"] = count + meta["crs"] = crs + meta["transform"] = transform - if 'dtype' not in meta: #if no datatype is specified, use float32 - meta['dtype'] = np.float32 - + if "dtype" not in meta: # if no datatype is specified, use float32 + meta["dtype"] = np.float32 - if nodata==None: + if nodata is None: pass else: - meta['nodata'] = nodata + meta["nodata"] = nodata - with rasterio.open(fn, 'w', **meta) as dst: - if count==1: # Mono-band raster - dst.write(mat.astype(meta['dtype']), 1) + with rasterio.open(fn, "w", **meta) as dst: + if count == 1: # Mono-band raster + dst.write(mat.astype(meta["dtype"]), 1) if bandnames: dst.set_band_description(1, bandnames[0]) - else: # Multi-band raster + else: # Multi-band raster for b in range(count): - dst.write(mat[b].astype(meta['dtype']), b+1) - for b,bandname in enumerate(bandnames): - dst.set_band_description(b+1, bandname) + dst.write(mat[b].astype(meta["dtype"]), b + 1) + for b, bandname in enumerate(bandnames): + dst.set_band_description(b + 1, bandname) + def read_gcps(gcp_base_folder): - df_gcps = pd.read_csv(os.path.join(gcp_base_folder,'GCPS.csv')) + df_gcps = pd.read_csv(os.path.join(gcp_base_folder, "GCPS.csv")) gcps = [] - for i,d in df_gcps.iterrows(): - gcp = rasterio.control.GroundControlPoint(d.row, d.col, d.x, d.y, d.z, d.id, d.info) - gcps.append(gcp) + for i, d in df_gcps.iterrows(): + gcp = rasterio.control.GroundControlPoint( + d.row, d.col, d.x, d.y, d.z, d.id, d.info + ) + gcps.append(gcp) return gcps -def geocode_file(input_map,basename,outdir,output_map,format = 'GTiff'): - #Write the map to Geotiff file - grass.run_command("r.out.gdal", input = input_map, output = os.path.join(outdir,output_map), format = 'GTiff') - #Read as rasterio dataset - ds = rasterio.open(os.path.join(outdir,output_map)) + +def geocode_file(input_map, basename, outdir, output_map, format="GTiff"): + # Write the map to Geotiff file + grass.run_command( + "r.out.gdal", + input=input_map, + output=os.path.join(outdir, output_map), + format="GTiff", + ) + # Read as rasterio dataset + ds = rasterio.open(os.path.join(outdir, output_map)) ds = ds.read()[0] - #Read the GCPS dataframe + # Read the GCPS dataframe env = grass.gisenv() - gcp_base_folder = os.path.join(env["GISDBASE"], env["LOCATION_NAME"], env["MAPSET"], "cell_misc",basename) + gcp_base_folder = os.path.join( + env["GISDBASE"], env["LOCATION_NAME"], env["MAPSET"], "cell_misc", basename + ) gcps = read_gcps(gcp_base_folder) - #Save the geocoded raster (it will replace the previous intermediate file) + # Save the geocoded raster (it will replace the previous intermediate file) geoTs = rasterio.transform.from_gcps(gcps) crs = rasterio.crs.CRS.from_epsg(4326) - save_GeoTiff(fn = os.path.join(outdir,output_map), crs = crs, transform = geoTs, mat = ds) - -def export_to_location(outdir,location,input_map,int_map,env): - #Run gdalWarp. This is made to avoid ERROR: Input map is rotated - cannot import - output_warp = f'gdalwarp_{int_map}' - os.system(f'gdalwarp {os.path.join(outdir,int_map)} {os.path.join(outdir,output_warp)}') - - grass.warning(_('Switching location')) - - #Create the new location with EPSG:4326, in case it does not exist + save_GeoTiff(fn=os.path.join(outdir, output_map), crs=crs, transform=geoTs, mat=ds) + + +def export_to_location(outdir, location, input_map, int_map, env): + # Run gdalWarp. This is made to avoid ERROR: Input map is rotated - cannot import + output_warp = f"gdalwarp_{int_map}" + os.system( + f"gdalwarp {os.path.join(outdir,int_map)} {os.path.join(outdir,output_warp)}" + ) + + grass.warning(_("Switching location")) + + # Create the new location with EPSG:4326, in case it does not exist location_folder = env["GISDBASE"] - out_location = os.path.join(location_folder,location) + out_location = os.path.join(location_folder, location) if not os.path.exists(out_location): - grass.create_location(env["GISDBASE"], location, epsg=4326, desc='Location created by i.saocom.geocode') - - grass.run_command('g.mapset',mapset = 'PERMANENT',location = location) - grass.run_command("r.import", input = os.path.join(outdir,output_warp), output = f'{input_map}') - os.remove(os.path.join(outdir,output_warp)) + grass.create_location( + env["GISDBASE"], + location, + epsg=4326, + desc="Location created by i.saocom.geocode", + ) + + grass.run_command("g.mapset", mapset="PERMANENT", location=location) + grass.run_command( + "r.import", input=os.path.join(outdir, output_warp), output=f"{input_map}" + ) + os.remove(os.path.join(outdir, output_warp)) + - def main(): - input_map = options['map'] + input_map = options["map"] data = options["data"] zip_v = options["is_zip"] - pols = options['pols'] - multilook = options['multilook'] + pols = options["pols"] + multilook = options["multilook"] basename = options["basename"] - location = options['location'] - outdir = options['dbase'] + location = options["location"] + outdir = options["dbase"] env = grass.gisenv() if not input_map and not data: grass.fatal(_("Either one of input map or data folder/zip must be specified")) - + if input_map and data: - grass.fatal(_("Either one of input map or data folder/zip must be specified, not both")) - + grass.fatal( + _("Either one of input map or data folder/zip must be specified, not both") + ) + if not input_map and data: - #Import real and imaginary bands to a temporary location and geocode them to external file + # Import real and imaginary bands to a temporary location and geocode them to external file grass.message(_("Running i.saocom.import")) - grass.create_location(env["GISDBASE"], f'{basename}_XY_tempLocation',overwrite=1) - grass.run_command('g.mapset',mapset = 'PERMANENT',location = f'{basename}_XY_tempLocation') - grass.run_command('i.saocom.import',data=data,is_zip=zip_v,pols=pols,multilook=multilook,basename=basename) - #Get the list of maps to be geocoded - map_list = grass.list_grouped(type="raster",pattern = f'{basename}*')['PERMANENT'] + grass.create_location( + env["GISDBASE"], f"{basename}_XY_tempLocation", overwrite=1 + ) + grass.run_command( + "g.mapset", mapset="PERMANENT", location=f"{basename}_XY_tempLocation" + ) + grass.run_command( + "i.saocom.import", + data=data, + is_zip=zip_v, + pols=pols, + multilook=multilook, + basename=basename, + ) + # Get the list of maps to be geocoded + map_list = grass.list_grouped(type="raster", pattern=f"{basename}*")[ + "PERMANENT" + ] for m in map_list: - grass.run_command('g.region',raster=m) - geocode_file(input_map=m,basename=basename,outdir=outdir,output_map=f'{m}.tif',format = 'GTiff') - #Import the geocoded bands into the target location - export_to_location(outdir=outdir,location=location,input_map=f'{m}_geo',int_map=f'{m}.tif',env=env) - #Remove intermediate files - os.remove(os.path.join(outdir,f'{m}.tif')) - #Go back to temporary location to continue exporting - grass.run_command('g.mapset',mapset = 'PERMANENT',location = f'{basename}_XY_tempLocation') - #Go back to original location - grass.run_command('g.mapset',mapset = env["MAPSET"],location = env["LOCATION_NAME"]) - shutil.rmtree(os.path.join(env["GISDBASE"], f'{basename}_XY_tempLocation')) - + grass.run_command("g.region", raster=m) + geocode_file( + input_map=m, + basename=basename, + outdir=outdir, + output_map=f"{m}.tif", + format="GTiff", + ) + # Import the geocoded bands into the target location + export_to_location( + outdir=outdir, + location=location, + input_map=f"{m}_geo", + int_map=f"{m}.tif", + env=env, + ) + # Remove intermediate files + os.remove(os.path.join(outdir, f"{m}.tif")) + # Go back to temporary location to continue exporting + grass.run_command( + "g.mapset", mapset="PERMANENT", location=f"{basename}_XY_tempLocation" + ) + # Go back to original location + grass.run_command( + "g.mapset", mapset=env["MAPSET"], location=env["LOCATION_NAME"] + ) + shutil.rmtree(os.path.join(env["GISDBASE"], f"{basename}_XY_tempLocation")) + if input_map and not data: - #Check if this an XY location - proj = grass.read_command('g.proj', flags ='g').split('=')[1].split('\n')[0] - if proj != 'xy_location_unprojected': - raise ValueError('Current location is not XY unprojected (radar coordinates)') - geocode_file(input_map=input_map,basename=basename,outdir=outdir,output_map=f'{input_map}.tif',format = 'GTiff') - export_to_location(outdir=outdir,location=location,input_map=f'{input_map}_geo',int_map=f'{input_map}.tif',env=env) - #Remove intermediate files - os.remove(os.path.join(outdir,f'{input_map}.tif')) - #Go back to original location - grass.run_command('g.mapset',mapset = env["MAPSET"],location = env["LOCATION_NAME"]) - - + # Check if this an XY location + proj = grass.read_command("g.proj", flags="g").split("=")[1].split("\n")[0] + if proj != "xy_location_unprojected": + raise ValueError( + "Current location is not XY unprojected (radar coordinates)" + ) + geocode_file( + input_map=input_map, + basename=basename, + outdir=outdir, + output_map=f"{input_map}.tif", + format="GTiff", + ) + export_to_location( + outdir=outdir, + location=location, + input_map=f"{input_map}_geo", + int_map=f"{input_map}.tif", + env=env, + ) + # Remove intermediate files + os.remove(os.path.join(outdir, f"{input_map}.tif")) + # Go back to original location + grass.run_command( + "g.mapset", mapset=env["MAPSET"], location=env["LOCATION_NAME"] + ) + + if __name__ == "__main__": options, flags = grass.parser() main() diff --git a/src/imagery/i.saocom/i.saocom.import/i.saocom.import.py b/src/imagery/i.saocom/i.saocom.import/i.saocom.import.py index 0ec887c57e..e0608cee9b 100644 --- a/src/imagery/i.saocom/i.saocom.import/i.saocom.import.py +++ b/src/imagery/i.saocom/i.saocom.import/i.saocom.import.py @@ -82,168 +82,198 @@ def apply_multilook(dataset, azLooks, rgLooks): - ''' + """ Esta función aplica un multilook dado a una imagen de entrada y actualiza la información de los metadatos para la imagen de salida. - + parámetros: dataset: diccionario de datos con las llaves: 'array': contiene la matriz de datos - 'metadata': contiene los metadatos con el formato dado por la librería rasterio + 'metadata': contiene los metadatos con el formato dado por la librería rasterio azLooks: número de looks a aplicar en dirección de azimuth rgLooks: número de looks a aplicar en dirección de rango - + retorna: - diccionario de datos con la estructura del dataset de entrada pero con el array resultante del + diccionario de datos con la estructura del dataset de entrada pero con el array resultante del multilook y los metadatos actualizados - ''' - + """ + import numpy as np from rasterio import Affine - - array = dataset['array'].copy() - metadata = dataset['metadata'].copy() - + + array = dataset["array"].copy() + metadata = dataset["metadata"].copy() + array = array[0] - - cols = metadata['width'] - rows = metadata['height'] - new_rows = rows//azLooks - new_cols = cols//rgLooks + + cols = metadata["width"] + rows = metadata["height"] + new_rows = rows // azLooks + new_cols = cols // rgLooks new_shape = (new_rows, azLooks, new_cols, rgLooks) - - if rows%azLooks!=0 or cols%rgLooks!=0: - array = array[:new_rows*azLooks,:new_cols*rgLooks] - + + if rows % azLooks != 0 or cols % rgLooks != 0: + array = array[: new_rows * azLooks, : new_cols * rgLooks] + multilooked = array.reshape(new_shape).mean(-1).mean(1) - metadata['width'] = new_cols - metadata['height'] = new_rows - geoTs = metadata['transform'] - metadata['transform'] = Affine(geoTs[0]*rgLooks, geoTs[1], geoTs[2], geoTs[3], geoTs[4]*azLooks, geoTs[5]) - - return {'array': np.expand_dims(multilooked, axis=0), 'metadata': metadata} + metadata["width"] = new_cols + metadata["height"] = new_rows + geoTs = metadata["transform"] + metadata["transform"] = Affine( + geoTs[0] * rgLooks, geoTs[1], geoTs[2], geoTs[3], geoTs[4] * azLooks, geoTs[5] + ) + return {"array": np.expand_dims(multilooked, axis=0), "metadata": metadata} def read_bands_zip(data, pols): - with ZipFile(data,'r') as zfile: - file_list = [img for img in zfile.namelist() if img.startswith('Data/') and not img.endswith('.xml')] - bands = {} - gcps = tuple() - dataset_pols = [] - for l in file_list: - pol = l.split('-')[6] - dataset_pols.append(pol) - if pol in pols: - bands[pol] = {} - filename = f'/vsizip/{data}/{l}' - with rasterio.open(filename) as banda: - bands[pol]['array'] = banda.read() - bands[pol]['metadata'] = banda.meta - gcps = banda.get_gcps() - return bands,gcps,dataset_pols - + with ZipFile(data, "r") as zfile: + file_list = [ + img + for img in zfile.namelist() + if img.startswith("Data/") and not img.endswith(".xml") + ] + bands = {} + gcps = tuple() + dataset_pols = [] + for l in file_list: + pol = l.split("-")[6] + dataset_pols.append(pol) + if pol in pols: + bands[pol] = {} + filename = f"/vsizip/{data}/{l}" + with rasterio.open(filename) as banda: + bands[pol]["array"] = banda.read() + bands[pol]["metadata"] = banda.meta + gcps = banda.get_gcps() + return bands, gcps, dataset_pols + + def read_bands_folder(data, pols): - file_list = [img for img in os.listdir(os.path.join(data,'Data')) if not img.endswith('.xml')] - bands = {} - gcps = tuple() - dataset_pols = [] - for l in file_list: - pol = l.split('-')[6] - dataset_pols.append(pol) - if pol in pols: - bands[pol] = {} - filename = os.path.join(data,'Data',l) - with rasterio.open(filename) as banda: - bands[pol]['array'] = banda.read() - bands[pol]['metadata'] = banda.meta - gcps = banda.get_gcps() - return bands,gcps,dataset_pols - - -def save_bands(bands,basename): - for band in bands: - #Change the band metadata: - #Data type must be changed from complex to float - bands[band]['metadata']['dtype'] = np.float32 - #The Y-resolution must be set to negative, otherwise GRASS will interpret the map is flipped - geoTs = bands[band]['metadata']['transform'] - bands[band]['metadata']['transform'] = Affine(geoTs[0], geoTs[1], geoTs[2], geoTs[3], -geoTs[4], geoTs[5]) - outputfn_r = f'{basename}_{band}_real.tif' - outputfn_i = f'{basename}_{band}_imag.tif' - with rasterio.open(outputfn_r, 'w', **bands[band]['metadata']) as dst: - dst.write(bands[band]['array'].real) - with rasterio.open(outputfn_i, 'w', **bands[band]['metadata']) as dst: - dst.write(bands[band]['array'].imag) - + file_list = [ + img + for img in os.listdir(os.path.join(data, "Data")) + if not img.endswith(".xml") + ] + bands = {} + gcps = tuple() + dataset_pols = [] + for l in file_list: + pol = l.split("-")[6] + dataset_pols.append(pol) + if pol in pols: + bands[pol] = {} + filename = os.path.join(data, "Data", l) + with rasterio.open(filename) as banda: + bands[pol]["array"] = banda.read() + bands[pol]["metadata"] = banda.meta + gcps = banda.get_gcps() + return bands, gcps, dataset_pols + + +def save_bands(bands, basename): + for band in bands: + # Change the band metadata: + # Data type must be changed from complex to float + bands[band]["metadata"]["dtype"] = np.float32 + # The Y-resolution must be set to negative, otherwise GRASS will interpret the map is flipped + geoTs = bands[band]["metadata"]["transform"] + bands[band]["metadata"]["transform"] = Affine( + geoTs[0], geoTs[1], geoTs[2], geoTs[3], -geoTs[4], geoTs[5] + ) + outputfn_r = f"{basename}_{band}_real.tif" + outputfn_i = f"{basename}_{band}_imag.tif" + with rasterio.open(outputfn_r, "w", **bands[band]["metadata"]) as dst: + dst.write(bands[band]["array"].real) + with rasterio.open(outputfn_i, "w", **bands[band]["metadata"]) as dst: + dst.write(bands[band]["array"].imag) + + def main(): - #xemt = options["xemt"] - data = options["data"] - zip_v = options["is_zip"] - basename = options["basename"] - pols = options['pols'] - multilook = options['multilook'] - - if zip_v == 'yes': - bands,gcps,dataset_pols = read_bands_zip(data, pols) - else: - bands,gcps,dataset_pols = read_bands_folder(data, pols) - - if len(bands) == 0 or len(gcps) == 0: - grass.fatal(_(f'None of the specified polarizations were found in the dataset \n Please try one of the folowing: {dataset_pols}')) - #pass - - else: - #Create a dataframe containing GCP information - cols = gcps[0][0].asdict().keys() - df = pd.DataFrame(columns = cols) - for i,gcp in enumerate(gcps[0]): - df1 = pd.DataFrame(gcp.asdict(), index = [i]) - df = pd.concat((df,df1)) - - - if multilook[0] != 1 or multilook[2] != 1: - # ~ print(f'Appying ML factor: {multilook}') - grass.message(_(f'Appying ML factor: {multilook}')) - for band in bands: - dim = bands[band]['array'].shape - # ~ print('Original shape ', bands[band]['array'].shape) - grass.message(_(f'Original shape {dim}')) - ml_dic = apply_multilook(bands[band], int(multilook[0]), int(multilook[2])) - bands[band]['array'] = ml_dic['array'] - bands[band]['metadata'] = ml_dic['metadata'] - dim = bands[band]['array'].shape - # ~ print('Shape after ML', bands[band]['array'].shape) - grass.message(_(f'Shape after ML {dim}')) - # Update GCP information - # ~ print('Updating GCP information for later geocoding') - grass.message(_('Updating GCP information for later geocoding')) - df['row'] /= int(multilook[0]) - df['col'] /= int(multilook[2]) - - # ~ print('Saving real and imaginary bands to intermediate GeoTiff outputs') - grass.message(_('Saving real and imaginary bands to intermediate GeoTiff outputs')) - save_bands(bands,basename) - - # ~ print('Reading real and imaginary bands into GRASS GIS, and cleaning intermediate files') - grass.message(_('Reading real and imaginary bands into GRASS GIS, and cleaning intermediate files')) - for band in bands: - input_r = f'{basename}_{band}_real.tif' - input_i = f'{basename}_{band}_imag.tif' - grass.run_command("r.import", input=input_r, output = input_r.split('.tif')[0]) - grass.run_command("r.import", input=input_i, output = input_i.split('.tif')[0]) - os.remove(input_r) - os.remove(input_i) - - # ~ print('Saving GCP information as support file') - grass.message(_('Saving GCP information as support file')) - env = grass.gisenv() - gcp_base_folder = os.path.join(env["GISDBASE"], env["LOCATION_NAME"], env["MAPSET"], "cell_misc",basename) - if not os.path.isdir(gcp_base_folder): - os.makedirs(gcp_base_folder) - df.to_csv(os.path.join(gcp_base_folder,'GCPS.csv')) - + # xemt = options["xemt"] + data = options["data"] + zip_v = options["is_zip"] + basename = options["basename"] + pols = options["pols"] + multilook = options["multilook"] + + if zip_v == "yes": + bands, gcps, dataset_pols = read_bands_zip(data, pols) + else: + bands, gcps, dataset_pols = read_bands_folder(data, pols) + + if len(bands) == 0 or len(gcps) == 0: + grass.fatal( + _( + f"None of the specified polarizations were found in the dataset \n Please try one of the folowing: {dataset_pols}" + ) + ) + # pass + + else: + # Create a dataframe containing GCP information + cols = gcps[0][0].asdict().keys() + df = pd.DataFrame(columns=cols) + for i, gcp in enumerate(gcps[0]): + df1 = pd.DataFrame(gcp.asdict(), index=[i]) + df = pd.concat((df, df1)) + + if multilook[0] != 1 or multilook[2] != 1: + # ~ print(f'Appying ML factor: {multilook}') + grass.message(_(f"Appying ML factor: {multilook}")) + for band in bands: + dim = bands[band]["array"].shape + # ~ print('Original shape ', bands[band]['array'].shape) + grass.message(_(f"Original shape {dim}")) + ml_dic = apply_multilook( + bands[band], int(multilook[0]), int(multilook[2]) + ) + bands[band]["array"] = ml_dic["array"] + bands[band]["metadata"] = ml_dic["metadata"] + dim = bands[band]["array"].shape + # ~ print('Shape after ML', bands[band]['array'].shape) + grass.message(_(f"Shape after ML {dim}")) + # Update GCP information + # ~ print('Updating GCP information for later geocoding') + grass.message(_("Updating GCP information for later geocoding")) + df["row"] /= int(multilook[0]) + df["col"] /= int(multilook[2]) + + # ~ print('Saving real and imaginary bands to intermediate GeoTiff outputs') + grass.message( + _("Saving real and imaginary bands to intermediate GeoTiff outputs") + ) + save_bands(bands, basename) + + # ~ print('Reading real and imaginary bands into GRASS GIS, and cleaning intermediate files') + grass.message( + _( + "Reading real and imaginary bands into GRASS GIS, and cleaning intermediate files" + ) + ) + for band in bands: + input_r = f"{basename}_{band}_real.tif" + input_i = f"{basename}_{band}_imag.tif" + grass.run_command( + "r.import", input=input_r, output=input_r.split(".tif")[0] + ) + grass.run_command( + "r.import", input=input_i, output=input_i.split(".tif")[0] + ) + os.remove(input_r) + os.remove(input_i) + + # ~ print('Saving GCP information as support file') + grass.message(_("Saving GCP information as support file")) + env = grass.gisenv() + gcp_base_folder = os.path.join( + env["GISDBASE"], env["LOCATION_NAME"], env["MAPSET"], "cell_misc", basename + ) + if not os.path.isdir(gcp_base_folder): + os.makedirs(gcp_base_folder) + df.to_csv(os.path.join(gcp_base_folder, "GCPS.csv")) + if __name__ == "__main__": - options, flags = grass.parser() - main() + options, flags = grass.parser() + main() diff --git a/src/imagery/i.sar/i.sar.amplitude/i.sar.amplitude.py b/src/imagery/i.sar/i.sar.amplitude/i.sar.amplitude.py index 19d8bede40..0e6774eb56 100755 --- a/src/imagery/i.sar/i.sar.amplitude/i.sar.amplitude.py +++ b/src/imagery/i.sar/i.sar.amplitude/i.sar.amplitude.py @@ -41,9 +41,9 @@ def main(): options, flags = gs.parser() real = options["real"] - imag = options['imag'] + imag = options["imag"] raster_output = options["output"] - amplitude_formula = f'{raster_output} = sqrt(pow({real},2) + pow({imag},2))' + amplitude_formula = f"{raster_output} = sqrt(pow({real},2) + pow({imag},2))" gs.mapcalc(exp=amplitude_formula) diff --git a/src/imagery/i.sar/i.sar.pauliRGB/i.sar.pauliRGB.py b/src/imagery/i.sar/i.sar.pauliRGB/i.sar.pauliRGB.py index 04c43953b3..c19715b102 100644 --- a/src/imagery/i.sar/i.sar.pauliRGB/i.sar.pauliRGB.py +++ b/src/imagery/i.sar/i.sar.pauliRGB/i.sar.pauliRGB.py @@ -54,27 +54,31 @@ import sys import grass.script as grass - + + def main(): - hh = options['hh'] - vv = options['vv'] - hv = options['hv'] - basename = options['basename'] - strength = options['strength'] - pauli_red = f'{basename}_Pauli_Red = {hh}-{vv}' - grass.mapcalc(exp=pauli_red) - pauli_green = f'{basename}_Pauli_Green = 2*{hv}' - grass.mapcalc(exp=pauli_green) - pauli_blue = f'{basename}_Pauli_Blue = {hh}+{vv}' - grass.mapcalc(exp=pauli_blue) - - if strength: - grass.run_command("i.colors.enhance", - red=f'{basename}_Pauli_Red', - green=f'{basename}_Pauli_Green', - blue=f'{basename}_Pauli_Blue', - strength=strength) + hh = options["hh"] + vv = options["vv"] + hv = options["hv"] + basename = options["basename"] + strength = options["strength"] + pauli_red = f"{basename}_Pauli_Red = {hh}-{vv}" + grass.mapcalc(exp=pauli_red) + pauli_green = f"{basename}_Pauli_Green = 2*{hv}" + grass.mapcalc(exp=pauli_green) + pauli_blue = f"{basename}_Pauli_Blue = {hh}+{vv}" + grass.mapcalc(exp=pauli_blue) + + if strength: + grass.run_command( + "i.colors.enhance", + red=f"{basename}_Pauli_Red", + green=f"{basename}_Pauli_Green", + blue=f"{basename}_Pauli_Blue", + strength=strength, + ) + if __name__ == "__main__": - options, flags = grass.parser() - main() + options, flags = grass.parser() + main() diff --git a/src/imagery/i.sar/i.sar.speckle/i.sar.speckle.py b/src/imagery/i.sar/i.sar.speckle/i.sar.speckle.py index e449d800c2..2fda62e666 100755 --- a/src/imagery/i.sar/i.sar.speckle/i.sar.speckle.py +++ b/src/imagery/i.sar/i.sar.speckle/i.sar.speckle.py @@ -69,7 +69,6 @@ def lee_filter(img, size, img_out): - pid = str(os.getpid()) img_mean = "tmp%s_img_mean" % pid img_sqr = "tmp%s_img_sqr" % pid @@ -109,22 +108,28 @@ def lee_filter(img, size, img_out): return img_out -def mean_filter(img, size, img_out): +def mean_filter(img, size, img_out): # Local mean r.neighbors(input=img, size=size, method="average", output=img_out) return img_out -def gauss_filter(img, size, std, img_out): +def gauss_filter(img, size, std, img_out): # Gauss function - r.neighbors(input=img, size=size, weighting_function = "gaussian", weighting_factor = std, output=img_out) + r.neighbors( + input=img, + size=size, + weighting_function="gaussian", + weighting_factor=std, + output=img_out, + ) - return img_out + return img_out -def main(): +def main(): method = options["method"] # algorithm for speckle removal img = options["input"] # name of input image img_out = options["output"] # name of output image @@ -141,14 +146,14 @@ def main(): g.message(_("Applying Lee Filter")) img_out = lee_filter(img, size, img_out) g.message(_("Done.")) - - elif method == 'mean': + + elif method == "mean": g.message(_("Applying Mean Filter")) img_out = mean_filter(img, size, img_out) g.message(_("Done.")) - elif method == 'gauss': - std = options['std'] + elif method == "gauss": + std = options["std"] g.message(_("Applying Gauss Filter")) img_out = gauss_filter(img, size, std, img_out) g.message(_("Done.")) From 43a8502dad52d501b3f7db77a1f4a8c77db72e79 Mon Sep 17 00:00:00 2001 From: sase1988 <36776334+sase1988@users.noreply.github.com> Date: Wed, 1 Nov 2023 17:51:21 -0300 Subject: [PATCH 04/38] Update src/imagery/i.saocom/i.saocom.geocode/i.saocom.geocode.html Co-authored-by: Veronica Andreo --- src/imagery/i.saocom/i.saocom.geocode/i.saocom.geocode.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/imagery/i.saocom/i.saocom.geocode/i.saocom.geocode.html b/src/imagery/i.saocom/i.saocom.geocode/i.saocom.geocode.html index 9d91cf83d7..b56595d706 100755 --- a/src/imagery/i.saocom/i.saocom.geocode/i.saocom.geocode.html +++ b/src/imagery/i.saocom/i.saocom.geocode/i.saocom.geocode.html @@ -1,6 +1,6 @@

DESCRIPTION

-The i.saocom.geocode module allows allows the projection of SAOCOM-1 L1A raw or derived products from radar coordinates to a cartographic coordinate system (CS). This can be applied either to bands imported by i.saocom.import and to any raster map calculated from these inputs, or directly to the SAOCOM original files. The tool does not currently support the geocoding of image subsets, so the whole extent must be processed. +The i.saocom.geocode module allows the projection of SAOCOM-1 L1A raw or derived products from radar coordinates to a cartographic coordinate system (CS). This can be applied to bands imported by i.saocom.import, any raster map calculated from these inputs, or directly to the SAOCOM original files. The tool does not currently support the geocoding of image subsets, so the whole extent must be processed.

NOTES

From 508ce86fc005c5486fcf720932e93514197eba27 Mon Sep 17 00:00:00 2001 From: sase1988 <36776334+sase1988@users.noreply.github.com> Date: Wed, 1 Nov 2023 17:51:46 -0300 Subject: [PATCH 05/38] Update src/imagery/i.saocom/i.saocom.geocode/i.saocom.geocode.html Co-authored-by: Veronica Andreo --- src/imagery/i.saocom/i.saocom.geocode/i.saocom.geocode.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/imagery/i.saocom/i.saocom.geocode/i.saocom.geocode.html b/src/imagery/i.saocom/i.saocom.geocode/i.saocom.geocode.html index b56595d706..4c804bfb81 100755 --- a/src/imagery/i.saocom/i.saocom.geocode/i.saocom.geocode.html +++ b/src/imagery/i.saocom/i.saocom.geocode/i.saocom.geocode.html @@ -8,7 +8,7 @@

NOTES

This module makes use of the GCPS.csv file generated by i.saocom.import and associated to a specific image. This GCP file is associated to the image basename specified in the option basename. -The tool will write the output to a Geotiff external file in the directory specified in the dbase option. The output files will be projected to the CS of the target location indicated in the option location. If the specified location does not exits, GRASS will create it with the CS EPSG:4326. The output map name will we the same as the input map, with the suffix _geo added at the end. +The tool will write the output to a Geotiff external file in the directory specified by the dbase option. The output files will be projected to the CS of the target location indicated in the option location. If the specified location does not exist, GRASS will create it with the CS EPSG:4326. The output map name will be the same as the input map, with the suffix _geo added at the end.

EXAMPLES

From 17b21ec57bb10abfb7fc51bb9e9274b87bf35619 Mon Sep 17 00:00:00 2001 From: sase1988 <36776334+sase1988@users.noreply.github.com> Date: Wed, 1 Nov 2023 17:56:07 -0300 Subject: [PATCH 06/38] Update src/imagery/i.saocom/i.saocom.geocode/i.saocom.geocode.html Co-authored-by: Veronica Andreo --- src/imagery/i.saocom/i.saocom.geocode/i.saocom.geocode.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/imagery/i.saocom/i.saocom.geocode/i.saocom.geocode.html b/src/imagery/i.saocom/i.saocom.geocode/i.saocom.geocode.html index 4c804bfb81..9251e97b5f 100755 --- a/src/imagery/i.saocom/i.saocom.geocode/i.saocom.geocode.html +++ b/src/imagery/i.saocom/i.saocom.geocode/i.saocom.geocode.html @@ -13,7 +13,7 @@

NOTES

EXAMPLES

-

Within an XY unprojeted location where the SAOCOM-1 bands have already been imported and processed, create an amplitude image from the real and imaginary bands, geocode it and then import it to a location called saocom_geo

+

Within an XY unprojected location where the SAOCOM-1 bands have already been imported and processed, create an amplitude image from the real and imaginary bands, geocode it and then import it into a location called saocom_geo

 #Calculate the amplitude image 

From a5dea5156a6c4275a704c0e820c4eacbececf9e7 Mon Sep 17 00:00:00 2001
From: sase1988 <36776334+sase1988@users.noreply.github.com>
Date: Wed, 1 Nov 2023 17:58:38 -0300
Subject: [PATCH 07/38] Update
 src/imagery/i.saocom/i.saocom.geocode/i.saocom.geocode.html

Co-authored-by: Veronica Andreo 
---
 src/imagery/i.saocom/i.saocom.geocode/i.saocom.geocode.html | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/imagery/i.saocom/i.saocom.geocode/i.saocom.geocode.html b/src/imagery/i.saocom/i.saocom.geocode/i.saocom.geocode.html
index 9251e97b5f..f254b45984 100755
--- a/src/imagery/i.saocom/i.saocom.geocode/i.saocom.geocode.html
+++ b/src/imagery/i.saocom/i.saocom.geocode/i.saocom.geocode.html
@@ -20,7 +20,7 @@ 

Within an XY unprojected location where the SAOCOM-1 bands have already been i.sar.amplitude real='SAO1B_20211222_hh_real' imag='SAO1B_20211222_hh_imag' output='SAO1B_20211222_hh_amp' #Geocode it and import it to new location. The external temporary raster will be saved as GeoTiff in the $HOME directory -i.saocom.geocode map='SAO1B_20211222_hh_amp' basename='SAO1B_20211222' dbase=$HOME location='saocom_geo' +i.saocom.geocode map=SAO1B_20211222_hh_amp basename=SAO1B_20211222 dbase=$HOME location=saocom_geo

Geocode the real and imaginary bands of a SAOCOM L1A image and import them to a location called geo_location

From 30a4eca836f61331930ef667b498e2fdbdbd1612 Mon Sep 17 00:00:00 2001 From: sase1988 <36776334+sase1988@users.noreply.github.com> Date: Wed, 1 Nov 2023 18:09:42 -0300 Subject: [PATCH 08/38] Update src/imagery/i.saocom/i.saocom.geocode/i.saocom.geocode.html Co-authored-by: Veronica Andreo --- src/imagery/i.saocom/i.saocom.geocode/i.saocom.geocode.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/imagery/i.saocom/i.saocom.geocode/i.saocom.geocode.html b/src/imagery/i.saocom/i.saocom.geocode/i.saocom.geocode.html index f254b45984..cfb15cb3d5 100755 --- a/src/imagery/i.saocom/i.saocom.geocode/i.saocom.geocode.html +++ b/src/imagery/i.saocom/i.saocom.geocode/i.saocom.geocode.html @@ -17,7 +17,7 @@

Within an XY unprojected location where the SAOCOM-1 bands have already been
 #Calculate the amplitude image 
-i.sar.amplitude real='SAO1B_20211222_hh_real' imag='SAO1B_20211222_hh_imag' output='SAO1B_20211222_hh_amp' 
+i.sar.amplitude real=SAO1B_20211222_hh_real imag=SAO1B_20211222_hh_imag output=SAO1B_20211222_hh_amp
 
 #Geocode it and import it to new location. The external temporary raster will be saved as GeoTiff in the $HOME directory
 i.saocom.geocode map=SAO1B_20211222_hh_amp basename=SAO1B_20211222 dbase=$HOME location=saocom_geo

From 11c0383751dc46aad4859fcf1a7c1d5c0283fd83 Mon Sep 17 00:00:00 2001
From: sase1988 <36776334+sase1988@users.noreply.github.com>
Date: Wed, 1 Nov 2023 18:10:05 -0300
Subject: [PATCH 09/38] Update
 src/imagery/i.sar/i.sar.amplitude/i.sar.amplitude.html

Co-authored-by: Veronica Andreo 
---
 src/imagery/i.sar/i.sar.amplitude/i.sar.amplitude.html | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/imagery/i.sar/i.sar.amplitude/i.sar.amplitude.html b/src/imagery/i.sar/i.sar.amplitude/i.sar.amplitude.html
index c5a65bf375..97db88b36d 100755
--- a/src/imagery/i.sar/i.sar.amplitude/i.sar.amplitude.html
+++ b/src/imagery/i.sar/i.sar.amplitude/i.sar.amplitude.html
@@ -5,7 +5,7 @@ 

DESCRIPTION

EXAMPLES

-

Calculate the amplitude map from a SAOCOM-1 imaginary and real bands

+

Calculate the amplitude map from SAOCOM-1 imaginary and real bands

 i.sar.amplitude real='SAO1B_20211222_hh_real' imag='SAO1B_20211222_hh_imag' output=real='SAO1B_20211222_hh_amplitude'

From 8cc02120c4c00c3ca22cd700f2a6fa2ed6347fa8 Mon Sep 17 00:00:00 2001
From: sase1988 <36776334+sase1988@users.noreply.github.com>
Date: Wed, 1 Nov 2023 18:10:18 -0300
Subject: [PATCH 10/38] Update
 src/imagery/i.sar/i.sar.amplitude/i.sar.amplitude.html

Co-authored-by: Veronica Andreo 
---
 src/imagery/i.sar/i.sar.amplitude/i.sar.amplitude.html | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/imagery/i.sar/i.sar.amplitude/i.sar.amplitude.html b/src/imagery/i.sar/i.sar.amplitude/i.sar.amplitude.html
index 97db88b36d..45e65c6358 100755
--- a/src/imagery/i.sar/i.sar.amplitude/i.sar.amplitude.html
+++ b/src/imagery/i.sar/i.sar.amplitude/i.sar.amplitude.html
@@ -8,7 +8,7 @@ 

EXAMPLES

Calculate the amplitude map from SAOCOM-1 imaginary and real bands

-i.sar.amplitude real='SAO1B_20211222_hh_real' imag='SAO1B_20211222_hh_imag' output=real='SAO1B_20211222_hh_amplitude'
+i.sar.amplitude real=SAO1B_20211222_hh_real imag=SAO1B_20211222_hh_imag output=SAO1B_20211222_hh_amplitude
 

REFERENCES

From 808e70d2ad6c65da0632e61fdfc064e84d290504 Mon Sep 17 00:00:00 2001 From: sase1988 <36776334+sase1988@users.noreply.github.com> Date: Wed, 1 Nov 2023 18:10:34 -0300 Subject: [PATCH 11/38] Update src/imagery/i.sar/i.sar.amplitude/i.sar.amplitude.html Co-authored-by: Veronica Andreo --- src/imagery/i.sar/i.sar.amplitude/i.sar.amplitude.html | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/imagery/i.sar/i.sar.amplitude/i.sar.amplitude.html b/src/imagery/i.sar/i.sar.amplitude/i.sar.amplitude.html index 45e65c6358..3d2a57337d 100755 --- a/src/imagery/i.sar/i.sar.amplitude/i.sar.amplitude.html +++ b/src/imagery/i.sar/i.sar.amplitude/i.sar.amplitude.html @@ -11,10 +11,6 @@

Calculate the amplitude map from SAOCOM-1 imaginary and real bands

i.sar.amplitude real=SAO1B_20211222_hh_real imag=SAO1B_20211222_hh_imag output=SAO1B_20211222_hh_amplitude
-

REFERENCES

- -Reference or references to paper related to the tool or references which algorithm the tool is based on. -

SEE ALSO

r.mapcalc, From 624e55722deee1ee610175f2e3c2fde4654a4392 Mon Sep 17 00:00:00 2001 From: sase1988 <36776334+sase1988@users.noreply.github.com> Date: Wed, 1 Nov 2023 18:11:49 -0300 Subject: [PATCH 12/38] Update src/imagery/i.sar/i.sar.pauliRGB/i.sar.pauliRGB.html Co-authored-by: Veronica Andreo --- src/imagery/i.sar/i.sar.pauliRGB/i.sar.pauliRGB.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/imagery/i.sar/i.sar.pauliRGB/i.sar.pauliRGB.html b/src/imagery/i.sar/i.sar.pauliRGB/i.sar.pauliRGB.html index c17287718e..a550ebabc9 100644 --- a/src/imagery/i.sar/i.sar.pauliRGB/i.sar.pauliRGB.html +++ b/src/imagery/i.sar/i.sar.pauliRGB/i.sar.pauliRGB.html @@ -13,7 +13,7 @@

DESCRIPTION

EXAMPLES

-

Create the Pauli RGB bands and apply a color enhance with a strength of 98%

+

Create the Pauli RGB bands and apply a color enhancement with a strength of 98%

 i.sar.pauliRGB hh='SAO1B_20211222_hh_amp_mean7x7' vv='SAO1B_20211222_vv_amp_mean7x7' hv='SAO1B_20211222_hv_amp_mean7x7' basename='SAO1B_20211222' strength=98

From c97825a0ceea659c339e04814232a60d521279bf Mon Sep 17 00:00:00 2001
From: sase1988 <36776334+sase1988@users.noreply.github.com>
Date: Wed, 1 Nov 2023 18:12:20 -0300
Subject: [PATCH 13/38] Update
 src/imagery/i.sar/i.sar.pauliRGB/i.sar.pauliRGB.html

Co-authored-by: Veronica Andreo 
---
 src/imagery/i.sar/i.sar.pauliRGB/i.sar.pauliRGB.html | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/imagery/i.sar/i.sar.pauliRGB/i.sar.pauliRGB.html b/src/imagery/i.sar/i.sar.pauliRGB/i.sar.pauliRGB.html
index a550ebabc9..1f9587dcf0 100644
--- a/src/imagery/i.sar/i.sar.pauliRGB/i.sar.pauliRGB.html
+++ b/src/imagery/i.sar/i.sar.pauliRGB/i.sar.pauliRGB.html
@@ -16,10 +16,10 @@ 

EXAMPLES

Create the Pauli RGB bands and apply a color enhancement with a strength of 98%

-i.sar.pauliRGB hh='SAO1B_20211222_hh_amp_mean7x7' vv='SAO1B_20211222_vv_amp_mean7x7' hv='SAO1B_20211222_hv_amp_mean7x7' basename='SAO1B_20211222' strength=98
+i.sar.pauliRGB hh=SAO1B_20211222_hh_amp_mean7x7 vv=SAO1B_20211222_vv_amp_mean7x7 hv=SAO1B_20211222_hv_amp_mean7x7 basename=SAO1B_20211222 strength=98
 
 #Check the creation of the Pauli bands:
-g.list type='raster' pattern='*Pauli*'
+g.list type=raster pattern='*Pauli*'
 
 #Output:
 SAO1B_20211222_Pauli_Blue

From b9081431fa7ef3643bb38f52ce52d7eba7319e48 Mon Sep 17 00:00:00 2001
From: sase1988 <36776334+sase1988@users.noreply.github.com>
Date: Fri, 10 Nov 2023 09:23:06 -0300
Subject: [PATCH 14/38] Update
 src/imagery/i.sar/i.sar.speckle/i.sar.speckle.html

Co-authored-by: Anna Petrasova 
---
 src/imagery/i.sar/i.sar.speckle/i.sar.speckle.html | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/imagery/i.sar/i.sar.speckle/i.sar.speckle.html b/src/imagery/i.sar/i.sar.speckle/i.sar.speckle.html
index f98d680d21..fe24a0a6ad 100644
--- a/src/imagery/i.sar/i.sar.speckle/i.sar.speckle.html
+++ b/src/imagery/i.sar/i.sar.speckle/i.sar.speckle.html
@@ -16,7 +16,7 @@ 

EXAMPLES

Apply a speckle filter using the gaussian method with a 7x7 window and a standard deviation = 1

-i.sar.speckle input='SAO1B_20211222_hh_amp' output='SAO1B_20211222_hh_amp_gauss7x7' method='gauss' size=7 std=1
+i.sar.speckle input=SAO1B_20211222_hh_amp output=SAO1B_20211222_hh_amp_gauss7x7 method=gauss size=7 std=1
 

REFERENCES

From 8db88bfd5cdf4f7c966d98e63158dca25fdf3574 Mon Sep 17 00:00:00 2001 From: sase1988 <36776334+sase1988@users.noreply.github.com> Date: Fri, 10 Nov 2023 09:23:39 -0300 Subject: [PATCH 15/38] Update src/imagery/i.sar/i.sar.speckle/i.sar.speckle.py Co-authored-by: Anna Petrasova --- src/imagery/i.sar/i.sar.speckle/i.sar.speckle.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/imagery/i.sar/i.sar.speckle/i.sar.speckle.py b/src/imagery/i.sar/i.sar.speckle/i.sar.speckle.py index 2fda62e666..cf0a89b6af 100755 --- a/src/imagery/i.sar/i.sar.speckle/i.sar.speckle.py +++ b/src/imagery/i.sar/i.sar.speckle/i.sar.speckle.py @@ -63,7 +63,7 @@ import os -import grass.script as grass +import grass.script as gs from grass.pygrass.modules.shortcuts import general as g from grass.pygrass.modules.shortcuts import raster as r From 1de88dd2e8f93489c28692f13cd1cad5b78089df Mon Sep 17 00:00:00 2001 From: sase1988 <36776334+sase1988@users.noreply.github.com> Date: Fri, 10 Nov 2023 09:25:04 -0300 Subject: [PATCH 16/38] Update src/imagery/i.sar/i.sar.speckle/i.sar.speckle.html Co-authored-by: Anna Petrasova --- src/imagery/i.sar/i.sar.speckle/i.sar.speckle.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/imagery/i.sar/i.sar.speckle/i.sar.speckle.html b/src/imagery/i.sar/i.sar.speckle/i.sar.speckle.html index fe24a0a6ad..22a46a5d88 100644 --- a/src/imagery/i.sar/i.sar.speckle/i.sar.speckle.html +++ b/src/imagery/i.sar/i.sar.speckle/i.sar.speckle.html @@ -13,7 +13,7 @@

DESCRIPTION

EXAMPLES

-

Apply a speckle filter using the gaussian method with a 7x7 window and a standard deviation = 1

+Apply a speckle filter using the gaussian method with a 7x7 window and a standard deviation = 1:
 i.sar.speckle input=SAO1B_20211222_hh_amp output=SAO1B_20211222_hh_amp_gauss7x7 method=gauss size=7 std=1

From 94ddb1c17a339f3e03d1f20949cb86aa98aa62e7 Mon Sep 17 00:00:00 2001
From: sase1988 <36776334+sase1988@users.noreply.github.com>
Date: Fri, 10 Nov 2023 09:25:17 -0300
Subject: [PATCH 17/38] Update
 src/imagery/i.sar/i.sar.speckle/i.sar.speckle.html

Co-authored-by: Anna Petrasova 
---
 src/imagery/i.sar/i.sar.speckle/i.sar.speckle.html | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/imagery/i.sar/i.sar.speckle/i.sar.speckle.html b/src/imagery/i.sar/i.sar.speckle/i.sar.speckle.html
index 22a46a5d88..1819ff9337 100644
--- a/src/imagery/i.sar/i.sar.speckle/i.sar.speckle.html
+++ b/src/imagery/i.sar/i.sar.speckle/i.sar.speckle.html
@@ -32,5 +32,5 @@ 

SEE ALSO

AUTHOR

-Margherita Di Leo
+Margherita Di Leo
Santiago Seppi, CONAE, Argentina From 5c778ecac35c2e54eee40d1aba5f1f3b1357aa9b Mon Sep 17 00:00:00 2001 From: sase1988 <36776334+sase1988@users.noreply.github.com> Date: Fri, 10 Nov 2023 09:25:28 -0300 Subject: [PATCH 18/38] Update src/imagery/i.sar/i.sar.pauliRGB/i.sar.pauliRGB.html Co-authored-by: Anna Petrasova --- src/imagery/i.sar/i.sar.pauliRGB/i.sar.pauliRGB.html | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/imagery/i.sar/i.sar.pauliRGB/i.sar.pauliRGB.html b/src/imagery/i.sar/i.sar.pauliRGB/i.sar.pauliRGB.html index 1f9587dcf0..575081b714 100644 --- a/src/imagery/i.sar/i.sar.pauliRGB/i.sar.pauliRGB.html +++ b/src/imagery/i.sar/i.sar.pauliRGB/i.sar.pauliRGB.html @@ -2,11 +2,11 @@

DESCRIPTION

The i.sar.pauliRGB module is used to generate the three bands that form the Pauli RGB SAR composition. The input are amplitude images and the output are three bands: -
-
- Band for the red channel, equal to HH-VV -
- Band for the green channel, equal to 2*HV -
- Band for the blue channel, equal to HH+VV -
+
    +
  • Band for the red channel, equal to HH-VV
  • +
  • Band for the green channel, equal to 2*HV
  • +
  • Band for the blue channel, equal to HH+VV
  • +
The output bands are prefixed with the value given to the basename option. Color enhancement can be optionally applied with the strength option, the parameter used in i.colors.enhance. From 8f8bc698607ff8efa4ae7cd4811c68af74d6653e Mon Sep 17 00:00:00 2001 From: sase1988 <36776334+sase1988@users.noreply.github.com> Date: Fri, 10 Nov 2023 09:45:52 -0300 Subject: [PATCH 19/38] Update src/imagery/i.sar/i.sar.speckle/i.sar.speckle.py Co-authored-by: Anna Petrasova --- src/imagery/i.sar/i.sar.speckle/i.sar.speckle.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/imagery/i.sar/i.sar.speckle/i.sar.speckle.py b/src/imagery/i.sar/i.sar.speckle/i.sar.speckle.py index cf0a89b6af..972d8e3c62 100755 --- a/src/imagery/i.sar/i.sar.speckle/i.sar.speckle.py +++ b/src/imagery/i.sar/i.sar.speckle/i.sar.speckle.py @@ -55,7 +55,7 @@ # %end # %option # % key: std -# % type: float +# % type: double # % description: Standard deviation value in case gaussian filter is selected # % answer: 1 # % required: no From 42cca3957271d614eb0d7f8a7436dccd1d955146 Mon Sep 17 00:00:00 2001 From: sase1988 <36776334+sase1988@users.noreply.github.com> Date: Fri, 10 Nov 2023 09:46:28 -0300 Subject: [PATCH 20/38] Update src/imagery/i.sar/i.sar.amplitude/i.sar.amplitude.html Co-authored-by: Anna Petrasova --- src/imagery/i.sar/i.sar.amplitude/i.sar.amplitude.html | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/imagery/i.sar/i.sar.amplitude/i.sar.amplitude.html b/src/imagery/i.sar/i.sar.amplitude/i.sar.amplitude.html index 3d2a57337d..4fb1393a55 100755 --- a/src/imagery/i.sar/i.sar.amplitude/i.sar.amplitude.html +++ b/src/imagery/i.sar/i.sar.amplitude/i.sar.amplitude.html @@ -14,10 +14,10 @@

Calculate the amplitude map from SAOCOM-1 imaginary and real bands

SEE ALSO

r.mapcalc, -i.saocom.import, -i.saocom.geocode, -i.sar.speckle, -i.sar.pauliRGB +i.saocom.import, +i.saocom.geocode, +i.sar.speckle, +i.sar.pauliRGB

AUTHORS

From 2a36fb696bbd21c5b29daed65fc2c1443732f4a9 Mon Sep 17 00:00:00 2001 From: sase1988 <36776334+sase1988@users.noreply.github.com> Date: Fri, 10 Nov 2023 09:46:47 -0300 Subject: [PATCH 21/38] Update src/imagery/i.sar/i.sar.html Co-authored-by: Anna Petrasova --- src/imagery/i.sar/i.sar.html | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/imagery/i.sar/i.sar.html b/src/imagery/i.sar/i.sar.html index 3ddd941a9d..633960723e 100644 --- a/src/imagery/i.sar/i.sar.html +++ b/src/imagery/i.sar/i.sar.html @@ -27,11 +27,11 @@

DESCRIPTION

The i.sar toolset consists of three modules:
-
i.sar.speckle
+
i.sar.speckle
A simple procedure to reduce speckle noise in SAR images
-
i.sar.amplitude
+
i.sar.amplitude
Module used to calculate an amplitude image from real and imaginary bands
-
i.sar.pauliRGB
+
i.sar.pauliRGB
Module used to generate the three bands that form the Pauli RGB SAR composition
From f5d33eba551c5475c9b297e9ce9691b199d04bc0 Mon Sep 17 00:00:00 2001 From: sase1988 <36776334+sase1988@users.noreply.github.com> Date: Fri, 10 Nov 2023 09:51:15 -0300 Subject: [PATCH 22/38] Update src/imagery/i.sar/i.sar.pauliRGB/i.sar.pauliRGB.html Co-authored-by: Anna Petrasova --- src/imagery/i.sar/i.sar.pauliRGB/i.sar.pauliRGB.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/imagery/i.sar/i.sar.pauliRGB/i.sar.pauliRGB.html b/src/imagery/i.sar/i.sar.pauliRGB/i.sar.pauliRGB.html index 575081b714..38db107e1d 100644 --- a/src/imagery/i.sar/i.sar.pauliRGB/i.sar.pauliRGB.html +++ b/src/imagery/i.sar/i.sar.pauliRGB/i.sar.pauliRGB.html @@ -35,8 +35,8 @@

SEE ALSO

r.mapcalc, i.colors.enhance, -i.sar.speckle, -i.sar.amplitude +i.sar.speckle, +i.sar.amplitude

AUTHOR

From 5c1b994423ce996efe64adb0241cc32a036bda20 Mon Sep 17 00:00:00 2001 From: sase1988 <36776334+sase1988@users.noreply.github.com> Date: Fri, 10 Nov 2023 09:51:24 -0300 Subject: [PATCH 23/38] Update src/imagery/i.saocom/i.saocom.import/i.saocom.import.html Co-authored-by: Anna Petrasova --- src/imagery/i.saocom/i.saocom.import/i.saocom.import.html | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/imagery/i.saocom/i.saocom.import/i.saocom.import.html b/src/imagery/i.saocom/i.saocom.import/i.saocom.import.html index fe2bfdd705..eb2ff9f0a6 100755 --- a/src/imagery/i.saocom/i.saocom.import/i.saocom.import.html +++ b/src/imagery/i.saocom/i.saocom.import/i.saocom.import.html @@ -55,10 +55,10 @@

REFERENCES

SEE ALSO

-i.saocom.geocode, -i.sar.amplitude, -i.sar.speckle, -i.sar.pauliRGB +i.saocom.geocode, +i.sar.amplitude, +i.sar.speckle, +i.sar.pauliRGB

AUTHORS

From 05257d105e3b89c7d3493fe612c7a1f79b68e612 Mon Sep 17 00:00:00 2001 From: sase1988 <36776334+sase1988@users.noreply.github.com> Date: Fri, 10 Nov 2023 09:51:34 -0300 Subject: [PATCH 24/38] Update src/imagery/i.saocom/i.saocom.html Co-authored-by: Anna Petrasova --- src/imagery/i.saocom/i.saocom.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/imagery/i.saocom/i.saocom.html b/src/imagery/i.saocom/i.saocom.html index 24015456a5..468b5fbd5b 100644 --- a/src/imagery/i.saocom/i.saocom.html +++ b/src/imagery/i.saocom/i.saocom.html @@ -27,9 +27,9 @@

DESCRIPTION

The i.saocom toolset consists of two modules:
-
i.saocom.import
+
i.saocom.import
Imports SAOCOM-1 data L1A (SLC) products
-
i.saocom.geocode
+
i.saocom.geocode
Projects SAOCOM-1 L1A derived products to a cartographic coordinate system and imports them to a new location
From 9317ea494b05a8d8c0d032b47d43ad0c6e5b1614 Mon Sep 17 00:00:00 2001 From: sase1988 <36776334+sase1988@users.noreply.github.com> Date: Fri, 10 Nov 2023 09:53:07 -0300 Subject: [PATCH 25/38] Update src/imagery/i.sar/i.sar.speckle/i.sar.speckle.html Co-authored-by: Anna Petrasova --- src/imagery/i.sar/i.sar.speckle/i.sar.speckle.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/imagery/i.sar/i.sar.speckle/i.sar.speckle.html b/src/imagery/i.sar/i.sar.speckle/i.sar.speckle.html index 1819ff9337..e85a890995 100644 --- a/src/imagery/i.sar/i.sar.speckle/i.sar.speckle.html +++ b/src/imagery/i.sar/i.sar.speckle/i.sar.speckle.html @@ -27,8 +27,8 @@

REFERENCES

SEE ALSO

r.neighbors, -i.sar.speckle, -i.sar.pauliRGB +i.sar.amplitude, +i.sar.pauliRGB

AUTHOR

From 397d6737f0bb129cc93f254d85f879dffdd976c5 Mon Sep 17 00:00:00 2001 From: sase1988 <36776334+sase1988@users.noreply.github.com> Date: Fri, 10 Nov 2023 09:53:17 -0300 Subject: [PATCH 26/38] Update src/imagery/i.saocom/i.saocom.geocode/i.saocom.geocode.html Co-authored-by: Anna Petrasova --- .../i.saocom/i.saocom.geocode/i.saocom.geocode.html | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/imagery/i.saocom/i.saocom.geocode/i.saocom.geocode.html b/src/imagery/i.saocom/i.saocom.geocode/i.saocom.geocode.html index cfb15cb3d5..b6d73cab2c 100755 --- a/src/imagery/i.saocom/i.saocom.geocode/i.saocom.geocode.html +++ b/src/imagery/i.saocom/i.saocom.geocode/i.saocom.geocode.html @@ -39,10 +39,10 @@

REFERENCES

SEE ALSO

-i.saocom.import, -i.sar.amplitude, -i.sar.speckle, -i.sar.pauliRGB +i.saocom.import, +i.sar.amplitude, +i.sar.speckle, +i.sar.pauliRGB

AUTHORS

From a9aee3a87d2088e54a34a143f4c158b2574a8094 Mon Sep 17 00:00:00 2001 From: sase1988 <36776334+sase1988@users.noreply.github.com> Date: Fri, 10 Nov 2023 11:01:23 -0300 Subject: [PATCH 27/38] Update src/imagery/i.saocom/i.saocom.import/i.saocom.import.html Co-authored-by: Veronica Andreo --- src/imagery/i.saocom/i.saocom.import/i.saocom.import.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/imagery/i.saocom/i.saocom.import/i.saocom.import.html b/src/imagery/i.saocom/i.saocom.import/i.saocom.import.html index eb2ff9f0a6..a46eecfa62 100755 --- a/src/imagery/i.saocom/i.saocom.import/i.saocom.import.html +++ b/src/imagery/i.saocom/i.saocom.import/i.saocom.import.html @@ -33,8 +33,8 @@

Import all polarizations

Then, run i.saocom.import from a zip file containing pols = ['hh','hv','vh','vv']:
-zip_file = 'S1B_OPER_SAR_EOSSP__CORE_L1A_OLF_20211225T165228.zip'
-i.saocom.import data=zip_file is_zip='yes' basename='SAO1B_20211222'
+zip_file = S1B_OPER_SAR_EOSSP__CORE_L1A_OLF_20211225T165228.zip
+i.saocom.import data=zip_file is_zip=yes basename=SAO1B_20211222
 
The previous example will create two bands using the given basename as prefix: SAO1B_20211222_[pol]_r (real band) SAO1B_20211222_[pol]_i (imaginary band). [pol] From 52331ba7de80f09d04f0fafc1e27501e0da463c7 Mon Sep 17 00:00:00 2001 From: sase1988 <36776334+sase1988@users.noreply.github.com> Date: Fri, 10 Nov 2023 11:02:29 -0300 Subject: [PATCH 28/38] Update src/imagery/i.saocom/i.saocom.import/i.saocom.import.html Co-authored-by: Veronica Andreo --- src/imagery/i.saocom/i.saocom.import/i.saocom.import.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/imagery/i.saocom/i.saocom.import/i.saocom.import.html b/src/imagery/i.saocom/i.saocom.import/i.saocom.import.html index a46eecfa62..6d159303d2 100755 --- a/src/imagery/i.saocom/i.saocom.import/i.saocom.import.html +++ b/src/imagery/i.saocom/i.saocom.import/i.saocom.import.html @@ -13,7 +13,7 @@

DESCRIPTION

The module requires to specify a basename value which will be used as prefix for all the polarization bands to be imported. Additionaly, a Ground Control Points file -will associated to this basename will be created within de GRASSDATA directory, in case the user performs later geocoding with i.saocom.geocode. This GCP information is extracted from the original SAOCOM-1 matrix using Python rasterio library and will account for any multilooking applied to the images. +associated to this basename will be created within de GRASSDATA directory, in case the user performs later geocoding with i.saocom.geocode. This GCP information is extracted from the original SAOCOM-1 matrix using Python rasterio library and will account for any multilooking applied to the images.

NOTES

From 6d975725acd0b8e3442f2c8c684bc675c375beee Mon Sep 17 00:00:00 2001 From: sase1988 <36776334+sase1988@users.noreply.github.com> Date: Fri, 10 Nov 2023 11:02:45 -0300 Subject: [PATCH 29/38] Update src/imagery/i.saocom/i.saocom.geocode/i.saocom.geocode.html Co-authored-by: Veronica Andreo --- src/imagery/i.saocom/i.saocom.geocode/i.saocom.geocode.html | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/imagery/i.saocom/i.saocom.geocode/i.saocom.geocode.html b/src/imagery/i.saocom/i.saocom.geocode/i.saocom.geocode.html index b6d73cab2c..991cb7be0d 100755 --- a/src/imagery/i.saocom/i.saocom.geocode/i.saocom.geocode.html +++ b/src/imagery/i.saocom/i.saocom.geocode/i.saocom.geocode.html @@ -33,9 +33,6 @@

Geocode the real and imaginary bands of a SAOCOM L1A image and import them t The previous example will run i.saocom.import to generate the real and imaginary bands for the polarimetric channels specified in the pols option and will apply the multilook factor indicated in the multilook option. After that it will geocode the real and imaginary bands and import them to the target location. -

REFERENCES

- -Reference or references to paper related to the tool or references which algorithm the tool is based on.

SEE ALSO

From d0d78bc290451e317ae921d1d1654507737bc343 Mon Sep 17 00:00:00 2001 From: sase1988 <36776334+sase1988@users.noreply.github.com> Date: Fri, 10 Nov 2023 11:03:35 -0300 Subject: [PATCH 30/38] Update src/imagery/i.saocom/i.saocom.import/i.saocom.import.html Co-authored-by: Veronica Andreo --- src/imagery/i.saocom/i.saocom.import/i.saocom.import.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/imagery/i.saocom/i.saocom.import/i.saocom.import.html b/src/imagery/i.saocom/i.saocom.import/i.saocom.import.html index 6d159303d2..00108b178c 100755 --- a/src/imagery/i.saocom/i.saocom.import/i.saocom.import.html +++ b/src/imagery/i.saocom/i.saocom.import/i.saocom.import.html @@ -43,8 +43,8 @@

Import all polarizations

Import specific polarizations and apply multilooking

-zip_file = 'S1B_OPER_SAR_EOSSP__CORE_L1A_OLF_20211225T165228.zip'
-i.saocom.import data=zip_file is_zip ='yes' basename='SAO1B_20211222' pols=['hh','vv'] multilook=[4,2]
+zip_file = S1B_OPER_SAR_EOSSP__CORE_L1A_OLF_20211225T165228.zip
+i.saocom.import data=zip_file is_zip =yes basename=SAO1B_20211222 pols=hh,vv multilook=4,2
 
The previous example will import only the hh and vv vv polarizations, and in case none of them are found the program will let the user know which are the available polarization channels in the dataset. The multilooking factor will be of 4 in azimuth direction and 2 in range direction. From 4e91227a470a1ab95c83155f66c4872323e8f33b Mon Sep 17 00:00:00 2001 From: Santiago riel Seppi Date: Mon, 13 Nov 2023 10:11:26 -0300 Subject: [PATCH 31/38] Add graphical workflows for i.saocom.import and i.saocom.geocode --- .../i.saocom.geocode/i.saocom.geocode.html | 6 +++++ .../i.saocom.geocode/saocomGeocodeWF.png | Bin 0 -> 80562 bytes .../i.saocom.import/i.saocom.import.html | 22 +++++++++++------- .../i.saocom.import/saocomImportWF.png | Bin 0 -> 73655 bytes 4 files changed, 20 insertions(+), 8 deletions(-) create mode 100644 src/imagery/i.saocom/i.saocom.geocode/saocomGeocodeWF.png create mode 100644 src/imagery/i.saocom/i.saocom.import/saocomImportWF.png diff --git a/src/imagery/i.saocom/i.saocom.geocode/i.saocom.geocode.html b/src/imagery/i.saocom/i.saocom.geocode/i.saocom.geocode.html index 991cb7be0d..241b662759 100755 --- a/src/imagery/i.saocom/i.saocom.geocode/i.saocom.geocode.html +++ b/src/imagery/i.saocom/i.saocom.geocode/i.saocom.geocode.html @@ -2,6 +2,12 @@

DESCRIPTION

The i.saocom.geocode module allows the projection of SAOCOM-1 L1A raw or derived products from radar coordinates to a cartographic coordinate system (CS). This can be applied to bands imported by i.saocom.import, any raster map calculated from these inputs, or directly to the SAOCOM original files. The tool does not currently support the geocoding of image subsets, so the whole extent must be processed. +

+

+ +

Graphical description of the workflow followed by i.saocom.geocode +

+

NOTES

When the tool is directly run on the original SAOCOM files, it will internally call i.saocom.import to import the real and imaginary bands to a temporary XY unprojected location. In this case the data option must be used. If the user wants to geocode already imported files, the map option must be specified. The tool will not allow the use of both options, either one of them must be selected. diff --git a/src/imagery/i.saocom/i.saocom.geocode/saocomGeocodeWF.png b/src/imagery/i.saocom/i.saocom.geocode/saocomGeocodeWF.png new file mode 100644 index 0000000000000000000000000000000000000000..c6f5edc0a99bfe4eb0bc587e66bd632583780e2b GIT binary patch literal 80562 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%0ABB29@#Z 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

-The i.saocom.import module allows importing SAOCOM-1 L1A (SLC) products from their native format, as provided by CONAE. -SLC products are complex matrices, but GRASS will import them as two separate bands containing the real and imaginary parts. This structure allows for further manipulation and prevents from losing important information. +The i.saocom.import module allows importing SAOCOM-1 L1A (SLC) products from their native format, as provided by CONAE. +SLC products are complex matrices, but GRASS will import them as two separate bands containing the real and imaginary parts, which allows further manipulation and prevents from losing important information. +As described in the graphical workflow, most of the code works outside GRASS GIS: It temporarily reads the SLC data (either a folder or zip file), extracts the real and imaginary components, and saves them as GeoTiff files. +These GeoTiff files are then imported to GRASS GIS using r.import and stored as raster maps in the PERMANENT mapset. Additionaly, a Ground Control Points file +associated to these files will be created within de cell_misc directory, in case the user performs later geocoding with i.saocom.geocode. This GCP information is extracted from the original SAOCOM-1 matrix using Python rasterio library and will account for any multilooking applied to the images.

By default i.saocom.import will process all the available polarizations, which can be selected with the pols option. -The module assumes by default that the data is zipped but this can be changed with the is_zip option. +The module assumes by default that the data is zipped but this can be changed with the is_zip option. The user can also apply a multilooking factor, which must be indicated as a list, followinf the order [az_loos,rg_looks]. +By default no multilooking is applied. The module requires to specify a basename value which will be used as prefix for all the polarization bands to be imported. -

-The user can also apply a multilooking factor, which must be indicated as a list, followinf the order [az_loos,rg_looks]. -By default no multilooking is applied.

-The module requires to specify a basename value which will be used as prefix for all the polarization bands to be imported. Additionaly, a Ground Control Points file -associated to this basename will be created within de GRASSDATA directory, in case the user performs later geocoding with i.saocom.geocode. This GCP information is extracted from the original SAOCOM-1 matrix using Python rasterio library and will account for any multilooking applied to the images. +Important: i.saocom.import assumes a GRASS session is active in an XY unprojected location. Importing the files to projected locations may lead to non-desired outputs. + + +

+ +

Graphical description of the workflow followed by i.saocom.import +

NOTES

diff --git a/src/imagery/i.saocom/i.saocom.import/saocomImportWF.png b/src/imagery/i.saocom/i.saocom.import/saocomImportWF.png new file mode 100644 index 0000000000000000000000000000000000000000..5ddac61f5090e495cbe483cf6f6082315de32f24 GIT binary patch literal 73655 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�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 Aq5uE@ literal 0 HcmV?d00001 From e7a89b487e97f19598fd6a0a0741ff49710a19b7 Mon Sep 17 00:00:00 2001 From: Santiago riel Seppi Date: Mon, 13 Nov 2023 11:00:14 -0300 Subject: [PATCH 32/38] Change i.sar.pauliRGB to i.sar.paulirgb --- src/imagery/i.sar/Makefile | 2 +- src/imagery/i.sar/i.sar.html | 2 +- src/imagery/i.sar/{i.sar.pauliRGB => i.sar.paulirgb}/Makefile | 2 +- .../i.sar.pauliRGB.html => i.sar.paulirgb/i.sar.paulirgb.html} | 0 .../i.sar.pauliRGB.py => i.sar.paulirgb/i.sar.paulirgb.py} | 0 5 files changed, 3 insertions(+), 3 deletions(-) rename src/imagery/i.sar/{i.sar.pauliRGB => i.sar.paulirgb}/Makefile (81%) rename src/imagery/i.sar/{i.sar.pauliRGB/i.sar.pauliRGB.html => i.sar.paulirgb/i.sar.paulirgb.html} (100%) rename src/imagery/i.sar/{i.sar.pauliRGB/i.sar.pauliRGB.py => i.sar.paulirgb/i.sar.paulirgb.py} (100%) diff --git a/src/imagery/i.sar/Makefile b/src/imagery/i.sar/Makefile index 7e2575922d..40646ab490 100644 --- a/src/imagery/i.sar/Makefile +++ b/src/imagery/i.sar/Makefile @@ -3,7 +3,7 @@ MODULE_TOPDIR =../.. PGM = i.sar SUBDIRS = i.sar.amplitude \ - i.sar.pauliRGB \ + i.sar.paulirgb \ i.sar.speckle \ include $(MODULE_TOPDIR)/include/Make/Dir.make diff --git a/src/imagery/i.sar/i.sar.html b/src/imagery/i.sar/i.sar.html index 633960723e..dbcdb21de3 100644 --- a/src/imagery/i.sar/i.sar.html +++ b/src/imagery/i.sar/i.sar.html @@ -31,7 +31,7 @@

DESCRIPTION

A simple procedure to reduce speckle noise in SAR images
i.sar.amplitude
Module used to calculate an amplitude image from real and imaginary bands
-
i.sar.pauliRGB
+
i.sar.paulirgb
Module used to generate the three bands that form the Pauli RGB SAR composition
diff --git a/src/imagery/i.sar/i.sar.pauliRGB/Makefile b/src/imagery/i.sar/i.sar.paulirgb/Makefile similarity index 81% rename from src/imagery/i.sar/i.sar.pauliRGB/Makefile rename to src/imagery/i.sar/i.sar.paulirgb/Makefile index 993fb6a86f..49c2b71d7c 100644 --- a/src/imagery/i.sar/i.sar.pauliRGB/Makefile +++ b/src/imagery/i.sar/i.sar.paulirgb/Makefile @@ -1,6 +1,6 @@ MODULE_TOPDIR = ../.. -PGM = i.sar.pauliRGB +PGM = i.sar.paulirgb include $(MODULE_TOPDIR)/include/Make/Script.make diff --git a/src/imagery/i.sar/i.sar.pauliRGB/i.sar.pauliRGB.html b/src/imagery/i.sar/i.sar.paulirgb/i.sar.paulirgb.html similarity index 100% rename from src/imagery/i.sar/i.sar.pauliRGB/i.sar.pauliRGB.html rename to src/imagery/i.sar/i.sar.paulirgb/i.sar.paulirgb.html diff --git a/src/imagery/i.sar/i.sar.pauliRGB/i.sar.pauliRGB.py b/src/imagery/i.sar/i.sar.paulirgb/i.sar.paulirgb.py similarity index 100% rename from src/imagery/i.sar/i.sar.pauliRGB/i.sar.pauliRGB.py rename to src/imagery/i.sar/i.sar.paulirgb/i.sar.paulirgb.py From 64e96d8dcc21b83b2c865a392219127891779ee8 Mon Sep 17 00:00:00 2001 From: Santiago riel Seppi Date: Mon, 13 Nov 2023 11:02:47 -0300 Subject: [PATCH 33/38] Change i.sar.pauliRGB to i.sar.paulirgb --- src/imagery/i.sar/i.sar.paulirgb/i.sar.paulirgb.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/imagery/i.sar/i.sar.paulirgb/i.sar.paulirgb.py b/src/imagery/i.sar/i.sar.paulirgb/i.sar.paulirgb.py index c19715b102..2cdd521492 100644 --- a/src/imagery/i.sar/i.sar.paulirgb/i.sar.paulirgb.py +++ b/src/imagery/i.sar/i.sar.paulirgb/i.sar.paulirgb.py @@ -2,7 +2,7 @@ ############################################################################ # -# MODULE: i.sar.saocomSLC +# MODULE: i.sar.paulirgb # # AUTHOR: Santiago Seppi # From 5114820a480092eeadff4c3d8d7b4aa4c5782dbf Mon Sep 17 00:00:00 2001 From: Santiago riel Seppi Date: Mon, 13 Nov 2023 14:08:58 -0300 Subject: [PATCH 34/38] Change temporary maps creation in i.sar.speckle and other minor changes --- .../i.saocom.geocode/i.saocom.geocode.py | 42 +++++------ .../i.saocom.import/i.saocom.import.py | 32 ++++----- .../i.sar/i.sar.paulirgb/i.sar.paulirgb.py | 12 ++-- .../i.sar/i.sar.speckle/i.sar.speckle.py | 71 +++++++++++-------- 4 files changed, 86 insertions(+), 71 deletions(-) diff --git a/src/imagery/i.saocom/i.saocom.geocode/i.saocom.geocode.py b/src/imagery/i.saocom/i.saocom.geocode/i.saocom.geocode.py index 4db868834c..a00e26e0b6 100755 --- a/src/imagery/i.saocom/i.saocom.geocode/i.saocom.geocode.py +++ b/src/imagery/i.saocom/i.saocom.geocode/i.saocom.geocode.py @@ -86,7 +86,7 @@ import os import numpy as np -import grass.script as grass +import grass.script as gs from grass.pygrass.modules.shortcuts import general as g from grass.pygrass.modules.shortcuts import raster as r from zipfile import ZipFile @@ -152,7 +152,7 @@ def read_gcps(gcp_base_folder): def geocode_file(input_map, basename, outdir, output_map, format="GTiff"): # Write the map to Geotiff file - grass.run_command( + gs.run_command( "r.out.gdal", input=input_map, output=os.path.join(outdir, output_map), @@ -162,7 +162,7 @@ def geocode_file(input_map, basename, outdir, output_map, format="GTiff"): ds = rasterio.open(os.path.join(outdir, output_map)) ds = ds.read()[0] # Read the GCPS dataframe - env = grass.gisenv() + env = gs.gisenv() gcp_base_folder = os.path.join( env["GISDBASE"], env["LOCATION_NAME"], env["MAPSET"], "cell_misc", basename ) @@ -180,21 +180,21 @@ def export_to_location(outdir, location, input_map, int_map, env): f"gdalwarp {os.path.join(outdir,int_map)} {os.path.join(outdir,output_warp)}" ) - grass.warning(_("Switching location")) + gs.warning(_("Switching location")) # Create the new location with EPSG:4326, in case it does not exist location_folder = env["GISDBASE"] out_location = os.path.join(location_folder, location) if not os.path.exists(out_location): - grass.create_location( + gs.create_location( env["GISDBASE"], location, epsg=4326, desc="Location created by i.saocom.geocode", ) - grass.run_command("g.mapset", mapset="PERMANENT", location=location) - grass.run_command( + gs.run_command("g.mapset", mapset="PERMANENT", location=location) + gs.run_command( "r.import", input=os.path.join(outdir, output_warp), output=f"{input_map}" ) os.remove(os.path.join(outdir, output_warp)) @@ -209,26 +209,26 @@ def main(): basename = options["basename"] location = options["location"] outdir = options["dbase"] - env = grass.gisenv() + env = gs.gisenv() if not input_map and not data: - grass.fatal(_("Either one of input map or data folder/zip must be specified")) + gs.fatal(_("Either one of input map or data folder/zip must be specified")) if input_map and data: - grass.fatal( + gs.fatal( _("Either one of input map or data folder/zip must be specified, not both") ) if not input_map and data: # Import real and imaginary bands to a temporary location and geocode them to external file - grass.message(_("Running i.saocom.import")) - grass.create_location( + gs.message(_("Running i.saocom.import")) + gs.create_location( env["GISDBASE"], f"{basename}_XY_tempLocation", overwrite=1 ) - grass.run_command( + gs.run_command( "g.mapset", mapset="PERMANENT", location=f"{basename}_XY_tempLocation" ) - grass.run_command( + gs.run_command( "i.saocom.import", data=data, is_zip=zip_v, @@ -237,11 +237,11 @@ def main(): basename=basename, ) # Get the list of maps to be geocoded - map_list = grass.list_grouped(type="raster", pattern=f"{basename}*")[ + map_list = gs.list_grouped(type="raster", pattern=f"{basename}*")[ "PERMANENT" ] for m in map_list: - grass.run_command("g.region", raster=m) + gs.run_command("g.region", raster=m) geocode_file( input_map=m, basename=basename, @@ -260,18 +260,18 @@ def main(): # Remove intermediate files os.remove(os.path.join(outdir, f"{m}.tif")) # Go back to temporary location to continue exporting - grass.run_command( + gs.run_command( "g.mapset", mapset="PERMANENT", location=f"{basename}_XY_tempLocation" ) # Go back to original location - grass.run_command( + gs.run_command( "g.mapset", mapset=env["MAPSET"], location=env["LOCATION_NAME"] ) shutil.rmtree(os.path.join(env["GISDBASE"], f"{basename}_XY_tempLocation")) if input_map and not data: # Check if this an XY location - proj = grass.read_command("g.proj", flags="g").split("=")[1].split("\n")[0] + proj = gs.read_command("g.proj", flags="g").split("=")[1].split("\n")[0] if proj != "xy_location_unprojected": raise ValueError( "Current location is not XY unprojected (radar coordinates)" @@ -293,11 +293,11 @@ def main(): # Remove intermediate files os.remove(os.path.join(outdir, f"{input_map}.tif")) # Go back to original location - grass.run_command( + gs.run_command( "g.mapset", mapset=env["MAPSET"], location=env["LOCATION_NAME"] ) if __name__ == "__main__": - options, flags = grass.parser() + options, flags = gs.parser() main() diff --git a/src/imagery/i.saocom/i.saocom.import/i.saocom.import.py b/src/imagery/i.saocom/i.saocom.import/i.saocom.import.py index e0608cee9b..f236d05f26 100644 --- a/src/imagery/i.saocom/i.saocom.import/i.saocom.import.py +++ b/src/imagery/i.saocom/i.saocom.import/i.saocom.import.py @@ -66,7 +66,7 @@ import os import numpy as np -import grass.script as grass +import grass.script as gs from grass.pygrass.modules.shortcuts import general as g from grass.pygrass.modules.shortcuts import raster as r from zipfile import ZipFile @@ -176,7 +176,7 @@ def save_bands(bands, basename): # Change the band metadata: # Data type must be changed from complex to float bands[band]["metadata"]["dtype"] = np.float32 - # The Y-resolution must be set to negative, otherwise GRASS will interpret the map is flipped + # The Y-resolution must be set to negative, otherwise gs.will interpret the map is flipped geoTs = bands[band]["metadata"]["transform"] bands[band]["metadata"]["transform"] = Affine( geoTs[0], geoTs[1], geoTs[2], geoTs[3], -geoTs[4], geoTs[5] @@ -203,7 +203,7 @@ def main(): bands, gcps, dataset_pols = read_bands_folder(data, pols) if len(bands) == 0 or len(gcps) == 0: - grass.fatal( + gs.fatal( _( f"None of the specified polarizations were found in the dataset \n Please try one of the folowing: {dataset_pols}" ) @@ -220,11 +220,11 @@ def main(): if multilook[0] != 1 or multilook[2] != 1: # ~ print(f'Appying ML factor: {multilook}') - grass.message(_(f"Appying ML factor: {multilook}")) + gs.message(_(f"Appying ML factor: {multilook}")) for band in bands: dim = bands[band]["array"].shape # ~ print('Original shape ', bands[band]['array'].shape) - grass.message(_(f"Original shape {dim}")) + gs.message(_(f"Original shape {dim}")) ml_dic = apply_multilook( bands[band], int(multilook[0]), int(multilook[2]) ) @@ -232,40 +232,40 @@ def main(): bands[band]["metadata"] = ml_dic["metadata"] dim = bands[band]["array"].shape # ~ print('Shape after ML', bands[band]['array'].shape) - grass.message(_(f"Shape after ML {dim}")) + gs.message(_(f"Shape after ML {dim}")) # Update GCP information # ~ print('Updating GCP information for later geocoding') - grass.message(_("Updating GCP information for later geocoding")) + gs.message(_("Updating GCP information for later geocoding")) df["row"] /= int(multilook[0]) df["col"] /= int(multilook[2]) # ~ print('Saving real and imaginary bands to intermediate GeoTiff outputs') - grass.message( + gs.message( _("Saving real and imaginary bands to intermediate GeoTiff outputs") ) save_bands(bands, basename) - # ~ print('Reading real and imaginary bands into GRASS GIS, and cleaning intermediate files') - grass.message( + # ~ print('Reading real and imaginary bands into gs.GIS, and cleaning intermediate files') + gs.message( _( - "Reading real and imaginary bands into GRASS GIS, and cleaning intermediate files" + "Reading real and imaginary bands into gs.GIS, and cleaning intermediate files" ) ) for band in bands: input_r = f"{basename}_{band}_real.tif" input_i = f"{basename}_{band}_imag.tif" - grass.run_command( + gs.run_command( "r.import", input=input_r, output=input_r.split(".tif")[0] ) - grass.run_command( + gs.run_command( "r.import", input=input_i, output=input_i.split(".tif")[0] ) os.remove(input_r) os.remove(input_i) # ~ print('Saving GCP information as support file') - grass.message(_("Saving GCP information as support file")) - env = grass.gisenv() + gs.message(_("Saving GCP information as support file")) + env = gs.gisenv() gcp_base_folder = os.path.join( env["GISDBASE"], env["LOCATION_NAME"], env["MAPSET"], "cell_misc", basename ) @@ -275,5 +275,5 @@ def main(): if __name__ == "__main__": - options, flags = grass.parser() + options, flags = gs.parser() main() diff --git a/src/imagery/i.sar/i.sar.paulirgb/i.sar.paulirgb.py b/src/imagery/i.sar/i.sar.paulirgb/i.sar.paulirgb.py index 2cdd521492..fad69cee66 100644 --- a/src/imagery/i.sar/i.sar.paulirgb/i.sar.paulirgb.py +++ b/src/imagery/i.sar/i.sar.paulirgb/i.sar.paulirgb.py @@ -53,7 +53,7 @@ import subprocess import sys -import grass.script as grass +import grass.script as gs def main(): @@ -63,14 +63,14 @@ def main(): basename = options["basename"] strength = options["strength"] pauli_red = f"{basename}_Pauli_Red = {hh}-{vv}" - grass.mapcalc(exp=pauli_red) + gs.mapcalc(exp=pauli_red) pauli_green = f"{basename}_Pauli_Green = 2*{hv}" - grass.mapcalc(exp=pauli_green) + gs.mapcalc(exp=pauli_green) pauli_blue = f"{basename}_Pauli_Blue = {hh}+{vv}" - grass.mapcalc(exp=pauli_blue) + gs.mapcalc(exp=pauli_blue) if strength: - grass.run_command( + gs.run_command( "i.colors.enhance", red=f"{basename}_Pauli_Red", green=f"{basename}_Pauli_Green", @@ -80,5 +80,5 @@ def main(): if __name__ == "__main__": - options, flags = grass.parser() + options, flags = gs.parser() main() diff --git a/src/imagery/i.sar/i.sar.speckle/i.sar.speckle.py b/src/imagery/i.sar/i.sar.speckle/i.sar.speckle.py index 972d8e3c62..bf94fca13c 100755 --- a/src/imagery/i.sar/i.sar.speckle/i.sar.speckle.py +++ b/src/imagery/i.sar/i.sar.speckle/i.sar.speckle.py @@ -4,11 +4,11 @@ # # MODULE: i.sar.speckle # -# AUTHOR: Margherita Di Leo +# AUTHOR: Margherita Di Leo, Santiago Seppi # # PURPOSE: Speckle noise removal for synthetic aperture radar (SAR) images # -# COPYRIGHT: (C) 2002-2019 by the GRASS Development Team +# COPYRIGHT: (C) 2002-2023 by the GRASS Development Team # # This program is free software under the GNU General Public # License (>=v2). Read the file COPYING that comes with GRASS @@ -64,17 +64,32 @@ import os import grass.script as gs +import atexit from grass.pygrass.modules.shortcuts import general as g from grass.pygrass.modules.shortcuts import raster as r +def remove(name): + gs.run_command("g.remove", type="raster", name=name, flags="f", quiet=True, errors="ignore") def lee_filter(img, size, img_out): pid = str(os.getpid()) - img_mean = "tmp%s_img_mean" % pid - img_sqr = "tmp%s_img_sqr" % pid - img_sqr_mean = "tmp%s_img_sqr_mean" % pid - img_variance = "tmp%s_img_variance" % pid - img_weights = "tmp%s_img_weights" % pid + # ~ img_mean = "tmp%s_img_mean" % pid + # ~ img_sqr = "tmp%s_img_sqr" % pid + # ~ img_sqr_mean = "tmp%s_img_sqr_mean" % pid + # ~ img_variance = "tmp%s_img_variance" % pid + # ~ img_weights = "tmp%s_img_weights" % pid + + img_mean = gs.append_node_pid("img_mean") + img_sqr = gs.append_node_pid("img_sqr") + img_sqr_mean = gs.append_node_pid("img_sqr_mean") + img_variance = gs.append_node_pid("img_variance") + img_weights = gs.append_node_pid("img_weights") + atexit.register(remove, img_mean) + atexit.register(remove, img_sqr) + atexit.register(remove, img_sqr_mean) + atexit.register(remove, img_variance) + atexit.register(remove, img_weights) + # Local mean r.neighbors(input=img, size=size, method="average", output=img_mean) @@ -84,8 +99,8 @@ def lee_filter(img, size, img_out): # Local variance r.mapcalc("%s = %s - (%s^2)" % (img_variance, img_sqr_mean, img_mean)) # Overall variance - return_univar = grass.read_command("r.univar", map=img, flags="ge") - univar_stats = grass.parse_key_val(return_univar) + return_univar = gs.read_command("r.univar", map=img, flags="ge") + univar_stats = gs.parse_key_val(return_univar) overall_variance = univar_stats["variance"] # Weights r.mapcalc( @@ -97,14 +112,14 @@ def lee_filter(img, size, img_out): "%s = %s + %s * (%s - %s)" % (img_out, img_mean, img_weights, img, img_mean) ) - # Cleanup - grass.message(_("Cleaning up intermediate files...")) - try: - grass.run_command( - "g.remove", flags="f", quiet=False, type="raster", pattern="tmp*" - ) - except: - """ """ + # ~ # Cleanup + # ~ gs.message(_("Cleaning up intermediate files...")) + # ~ try: + # ~ gs.run_command( + # ~ "g.remove", flags="f", quiet=False, type="raster", pattern="tmp*" + # ~ ) + # ~ except: + # ~ """ """ return img_out @@ -135,33 +150,33 @@ def main(): img_out = options["output"] # name of output image size = options["size"] # size of neighborhood - out = grass.core.find_file(img_out) + out = gs.core.find_file(img_out) - if (out["name"] != "") and not grass.overwrite(): - grass.warning( + if (out["name"] != "") and not gs.overwrite(): + gs.warning( _("Output map name already exists. " "Delete it or use overwrite flag") ) if method == "lee": - g.message(_("Applying Lee Filter")) + #g.message(_("Applying Lee Filter")) img_out = lee_filter(img, size, img_out) - g.message(_("Done.")) + #g.message(_("Done.")) elif method == "mean": - g.message(_("Applying Mean Filter")) + #g.message(_("Applying Mean Filter")) img_out = mean_filter(img, size, img_out) - g.message(_("Done.")) + #g.message(_("Done.")) elif method == "gauss": std = options["std"] - g.message(_("Applying Gauss Filter")) + #g.message(_("Applying Gauss Filter")) img_out = gauss_filter(img, size, std, img_out) - g.message(_("Done.")) + #g.message(_("Done.")) else: - grass.fatal(_("The requested speckle filter is not yet implemented.")) + gs.fatal(_("The requested speckle filter is not yet implemented.")) if __name__ == "__main__": - options, flags = grass.parser() + options, flags = gs.parser() main() From 62c5269f972991ccf70142194c30b2539db6d28d Mon Sep 17 00:00:00 2001 From: Santiago riel Seppi Date: Mon, 13 Nov 2023 14:36:29 -0300 Subject: [PATCH 35/38] Use gs.parse_command() instead of gs.read_command() in i.sar.spleckle --- src/imagery/i.sar/i.sar.speckle/i.sar.speckle.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/imagery/i.sar/i.sar.speckle/i.sar.speckle.py b/src/imagery/i.sar/i.sar.speckle/i.sar.speckle.py index bf94fca13c..094442e654 100755 --- a/src/imagery/i.sar/i.sar.speckle/i.sar.speckle.py +++ b/src/imagery/i.sar/i.sar.speckle/i.sar.speckle.py @@ -99,8 +99,7 @@ def lee_filter(img, size, img_out): # Local variance r.mapcalc("%s = %s - (%s^2)" % (img_variance, img_sqr_mean, img_mean)) # Overall variance - return_univar = gs.read_command("r.univar", map=img, flags="ge") - univar_stats = gs.parse_key_val(return_univar) + univar_stats = gs.parse_command("r.univar", map=img, flags="ge") overall_variance = univar_stats["variance"] # Weights r.mapcalc( From 0442071523a3a821e9e87c26e4bcb194dcfcf1c6 Mon Sep 17 00:00:00 2001 From: Santiago riel Seppi Date: Mon, 13 Nov 2023 15:35:57 -0300 Subject: [PATCH 36/38] Use full name for the option like 'polarizations' --- src/imagery/i.saocom/i.saocom.import/i.saocom.import.html | 6 +++--- src/imagery/i.saocom/i.saocom.import/i.saocom.import.py | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/imagery/i.saocom/i.saocom.import/i.saocom.import.html b/src/imagery/i.saocom/i.saocom.import/i.saocom.import.html index 3926f757d7..2ba68e7174 100755 --- a/src/imagery/i.saocom/i.saocom.import/i.saocom.import.html +++ b/src/imagery/i.saocom/i.saocom.import/i.saocom.import.html @@ -7,7 +7,7 @@

DESCRIPTION

associated to these files will be created within de cell_misc directory, in case the user performs later geocoding with i.saocom.geocode. This GCP information is extracted from the original SAOCOM-1 matrix using Python rasterio library and will account for any multilooking applied to the images.

-By default i.saocom.import will process all the available polarizations, which can be selected with the pols option. +By default i.saocom.import will process all the available polarizations, which can be selected with the polarizations option. The module assumes by default that the data is zipped but this can be changed with the is_zip option. The user can also apply a multilooking factor, which must be indicated as a list, followinf the order [az_loos,rg_looks]. By default no multilooking is applied. The module requires to specify a basename value which will be used as prefix for all the polarization bands to be imported. @@ -36,7 +36,7 @@

Import all polarizations

grass -c XY saocom -e
-Then, run i.saocom.import from a zip file containing pols = ['hh','hv','vh','vv']: +Then, run i.saocom.import from a zip file containing polarizations = ['hh','hv','vh','vv']:
 zip_file = S1B_OPER_SAR_EOSSP__CORE_L1A_OLF_20211225T165228.zip
@@ -50,7 +50,7 @@ 

Import specific polarizations and apply multilooking

 zip_file = S1B_OPER_SAR_EOSSP__CORE_L1A_OLF_20211225T165228.zip
-i.saocom.import data=zip_file is_zip =yes basename=SAO1B_20211222 pols=hh,vv multilook=4,2
+i.saocom.import data=zip_file is_zip =yes basename=SAO1B_20211222 polarizations=hh,vv multilook=4,2
 
The previous example will import only the hh and vv vv polarizations, and in case none of them are found the program will let the user know which are the available polarization channels in the dataset. The multilooking factor will be of 4 in azimuth direction and 2 in range direction. diff --git a/src/imagery/i.saocom/i.saocom.import/i.saocom.import.py b/src/imagery/i.saocom/i.saocom.import/i.saocom.import.py index f236d05f26..739f1fb484 100644 --- a/src/imagery/i.saocom/i.saocom.import/i.saocom.import.py +++ b/src/imagery/i.saocom/i.saocom.import/i.saocom.import.py @@ -42,7 +42,7 @@ # % description: Whether the data directory is zipped or not # %end # %option -# % key: pols +# % key: polarizations # % type: string # % required: yes # % multiple: yes @@ -194,7 +194,7 @@ def main(): data = options["data"] zip_v = options["is_zip"] basename = options["basename"] - pols = options["pols"] + pols = options["polarizations"] multilook = options["multilook"] if zip_v == "yes": From bd0e1e0b122b965ec49b30eb9e829e016a213bc9 Mon Sep 17 00:00:00 2001 From: Santiago riel Seppi Date: Mon, 13 Nov 2023 16:03:17 -0300 Subject: [PATCH 37/38] Avoid importing unused dependencies or packages --- .../i.saocom/i.saocom.geocode/i.saocom.geocode.py | 10 ++-------- .../i.saocom/i.saocom.import/i.saocom.import.py | 1 - src/imagery/i.sar/i.sar.amplitude/i.sar.amplitude.py | 3 --- src/imagery/i.sar/i.sar.paulirgb/i.sar.paulirgb.py | 3 --- src/imagery/i.sar/i.sar.speckle/i.sar.speckle.py | 6 +++--- 5 files changed, 5 insertions(+), 18 deletions(-) diff --git a/src/imagery/i.saocom/i.saocom.geocode/i.saocom.geocode.py b/src/imagery/i.saocom/i.saocom.geocode/i.saocom.geocode.py index a00e26e0b6..81951a9a0e 100755 --- a/src/imagery/i.saocom/i.saocom.geocode/i.saocom.geocode.py +++ b/src/imagery/i.saocom/i.saocom.geocode/i.saocom.geocode.py @@ -47,7 +47,7 @@ # % description: Whether the data directory is zipped or not. Only required if geocoding is to ble applied on the original files # %end # %option -# % key: pols +# % key: polarizations # % type: string # % required: no # % multiple: yes @@ -89,15 +89,9 @@ import grass.script as gs from grass.pygrass.modules.shortcuts import general as g from grass.pygrass.modules.shortcuts import raster as r -from zipfile import ZipFile import rasterio -from rasterio.mask import mask -from rasterio.vrt import WarpedVRT -import geopandas as gpd import numpy as np -from xml.etree import ElementTree as ET from osgeo import gdal -from affine import Affine import pandas as pd import shutil from grass.exceptions import ParameterError @@ -204,7 +198,7 @@ def main(): input_map = options["map"] data = options["data"] zip_v = options["is_zip"] - pols = options["pols"] + pols = options["polarizations"] multilook = options["multilook"] basename = options["basename"] location = options["location"] diff --git a/src/imagery/i.saocom/i.saocom.import/i.saocom.import.py b/src/imagery/i.saocom/i.saocom.import/i.saocom.import.py index 739f1fb484..d385e7c038 100644 --- a/src/imagery/i.saocom/i.saocom.import/i.saocom.import.py +++ b/src/imagery/i.saocom/i.saocom.import/i.saocom.import.py @@ -73,7 +73,6 @@ import rasterio from rasterio.mask import mask from rasterio.vrt import WarpedVRT -import geopandas as gpd import numpy as np from xml.etree import ElementTree as ET from osgeo import gdal diff --git a/src/imagery/i.sar/i.sar.amplitude/i.sar.amplitude.py b/src/imagery/i.sar/i.sar.amplitude/i.sar.amplitude.py index 0e6774eb56..feb2814149 100755 --- a/src/imagery/i.sar/i.sar.amplitude/i.sar.amplitude.py +++ b/src/imagery/i.sar/i.sar.amplitude/i.sar.amplitude.py @@ -32,9 +32,6 @@ # % key: output # %end -import subprocess -import sys - import grass.script as gs diff --git a/src/imagery/i.sar/i.sar.paulirgb/i.sar.paulirgb.py b/src/imagery/i.sar/i.sar.paulirgb/i.sar.paulirgb.py index fad69cee66..cfe1505433 100644 --- a/src/imagery/i.sar/i.sar.paulirgb/i.sar.paulirgb.py +++ b/src/imagery/i.sar/i.sar.paulirgb/i.sar.paulirgb.py @@ -50,9 +50,6 @@ # % required: no # %end -import subprocess -import sys - import grass.script as gs diff --git a/src/imagery/i.sar/i.sar.speckle/i.sar.speckle.py b/src/imagery/i.sar/i.sar.speckle/i.sar.speckle.py index 094442e654..13a5e1bf8b 100755 --- a/src/imagery/i.sar/i.sar.speckle/i.sar.speckle.py +++ b/src/imagery/i.sar/i.sar.speckle/i.sar.speckle.py @@ -62,17 +62,17 @@ # %end -import os +#import os import grass.script as gs import atexit -from grass.pygrass.modules.shortcuts import general as g +#from grass.pygrass.modules.shortcuts import general as g from grass.pygrass.modules.shortcuts import raster as r def remove(name): gs.run_command("g.remove", type="raster", name=name, flags="f", quiet=True, errors="ignore") def lee_filter(img, size, img_out): - pid = str(os.getpid()) + #pid = str(os.getpid()) # ~ img_mean = "tmp%s_img_mean" % pid # ~ img_sqr = "tmp%s_img_sqr" % pid # ~ img_sqr_mean = "tmp%s_img_sqr_mean" % pid From f4602f6159481d6d31a7961ff33b5f51a07877f7 Mon Sep 17 00:00:00 2001 From: Santiago riel Seppi Date: Mon, 13 Nov 2023 16:06:21 -0300 Subject: [PATCH 38/38] Avoid importing unused dependencies or packages --- src/imagery/i.saocom/i.saocom.geocode/i.saocom.geocode.py | 3 --- src/imagery/i.saocom/i.saocom.import/i.saocom.import.py | 7 ------- 2 files changed, 10 deletions(-) diff --git a/src/imagery/i.saocom/i.saocom.geocode/i.saocom.geocode.py b/src/imagery/i.saocom/i.saocom.geocode/i.saocom.geocode.py index 81951a9a0e..5a00b5e627 100755 --- a/src/imagery/i.saocom/i.saocom.geocode/i.saocom.geocode.py +++ b/src/imagery/i.saocom/i.saocom.geocode/i.saocom.geocode.py @@ -87,14 +87,11 @@ import os import numpy as np import grass.script as gs -from grass.pygrass.modules.shortcuts import general as g -from grass.pygrass.modules.shortcuts import raster as r import rasterio import numpy as np from osgeo import gdal import pandas as pd import shutil -from grass.exceptions import ParameterError def save_GeoTiff(fn, crs, transform, mat, meta=None, nodata=None, bandnames=[]): diff --git a/src/imagery/i.saocom/i.saocom.import/i.saocom.import.py b/src/imagery/i.saocom/i.saocom.import/i.saocom.import.py index d385e7c038..ab4c038a95 100644 --- a/src/imagery/i.saocom/i.saocom.import/i.saocom.import.py +++ b/src/imagery/i.saocom/i.saocom.import/i.saocom.import.py @@ -67,14 +67,9 @@ import os import numpy as np import grass.script as gs -from grass.pygrass.modules.shortcuts import general as g -from grass.pygrass.modules.shortcuts import raster as r from zipfile import ZipFile import rasterio -from rasterio.mask import mask -from rasterio.vrt import WarpedVRT import numpy as np -from xml.etree import ElementTree as ET from osgeo import gdal from affine import Affine import pandas as pd @@ -97,8 +92,6 @@ def apply_multilook(dataset, azLooks, rgLooks): multilook y los metadatos actualizados """ - import numpy as np - from rasterio import Affine array = dataset["array"].copy() metadata = dataset["metadata"].copy()