diff --git a/README.md b/README.md index cc4eff3..981c266 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ The main goal of __Sen2Like__ is to generate Sentinel-2 like harmonised/fused su It is a contribution to on going worldwide initiatives (*NASA-HLS, Force, CESBIO [2],[3]) undertook to facilitate higher level processing starting from harmonized data. The __Sen2Like__ framework is a scientific and open source software. In its current implementation version (*December 2022*), it combines Landsat-8 and Sentinel-2 data products. -Level 1 and Level 2 input Landsat 8 (LS8) products are processed to be harmonized with Sentinel-2 data (S2). +Level 1 and Level 2 input Landsat 8-9 (LS8-9) products are processed to be harmonized with Sentinel-2 data (S2). The two following ARD product types are generated: * Harmonized Surface Reflectance Products (Level 2H) - at 30m of resolution, * Fused Surface Reflectance Products (Level 2F) - at 10-20m of resolution. @@ -28,7 +28,8 @@ Sen2like software supports the PRISMA L1 products through the usage of a pre-pro The __processing workflow__ is based on following algorithms: * Geometric Corrections including registration to common reference & the stitching [4], -* Atmospheric Corrections by using SMAC [5] relying on auxiliary meteorological data, +* Atmospheric Corrections by using SMAC [5] relying on auxiliary meteorological data, +or "Sen2Cor3" [11] as a first processing step * Application of Spectral Band Adjustment Factor (SBAF) [2], * Transformation to Nadir BRDF-normalized Reflectance (NBAR) [6],[7], * Production of LS8 High Resolution 10 m pixel spacing data (Fusion) [8]. @@ -39,7 +40,7 @@ It is therefore possible, to cover large geographic extent with a __seamless ima It is worth noting that the overall accuracy of your final ARD product strongly depends on the accuracy of sen2like auxiliary data. Two categories of auxiliary data are important: the raster reference for geometric corrections and the meteorological data for atmospheric corrections. Regarding atmospheric corrections, one possibility is to use data from the Copernicus Atmosphere Monitoring Service [9]. The Sen2Like team prepared a dedicated CAMS monthly dataset for the Year 2020, available from [here](http://185.178.85.51/CAMS/). Please refer to this short [description](http://185.178.85.51/CAMS/Readme_CAMS2020.txt) for additional information. For further details on the format specification of the harmonized products or the functionalities of the Sen2Like software, please -refer to the [Product Format Specification](sen2like/docs/source/S2-PDGS-MPC-L2HF-PFS-v1.2.pdf), and the [User Manual v1.8](sen2like/docs/source/S2-SEN2LIKE-UM-V1.9.pdf). +refer to the [Product Format Specification](sen2like/docs/source/S2-PDGS-MPC-L2HF-PFS-v1.2.pdf), and the [User Manual v1.9](sen2like/docs/source/S2-SEN2LIKE-UM-V1.9.pdf). ## Publications and Contacts **Yearning to know more ? Check out** @@ -47,7 +48,7 @@ refer to the [Product Format Specification](sen2like/docs/source/S2-PDGS-MPC-L2H * A [Sen2Like Relaxing Video](https://youtu.be/KBSYYBShyos) prepared for [ESA EO PHI-WEEK 2020](https://www.youtube.com/playlist?list=PLvT7fd9OiI9XELZXcljYTftUtJ_NFWRrY) * A [Sen2Like Time Lapse including NDVI graphic](https://youtu.be/yEObvI1KQBg) prepared for QWG#12 -And the following research papers : +And the following references : + [1] S. Saunier, J. Louis, V. Debaecker et al., "Sen2like, A Tool To Generate Sentinel-2 Harmonised Surface Reflectance Products - First Results with Landsat-8," IGARSS 2019 - 2019 IEEE International Geoscience and Remote Sensing Symposium, Yokohama, Japan, 2019, pp. 5650-5653, doi: 10.1109/IGARSS.2019.8899213. + [2] Claverie, Martin, Junchang Ju, Jeffrey G. Masek, Jennifer L. Dungan, Eric F. Vermote, Jean-Claude Roger, Sergii V. Skakun, et Christopher Justice. "The Harmonized Landsat and Sentinel-2 Surface Reflectance Data Set". Remote Sensing of Environment 219 (15 décembre 2018): 145‑61. (https://doi.org/10.1016/j.rse.2018.09.002). + [3] Frantz, David. "FORCE—Landsat + Sentinel-2 Analysis Ready Data and Beyond". Remote Sensing 11, nᵒ 9 (janvier 2019): 1124. (https://doi.org/10.3390/rs11091124). @@ -58,7 +59,7 @@ And the following research papers : + [8] Sen2Like User Manual + [9] [Copernicus Atmosphere Monitoring Service](https://atmosphere.copernicus.eu/) + [10] Saunier, S.; Pflug, B.; Lobos, I.M.; Franch, B.; Louis, J.; De Los Reyes, R.; Debaecker, V.; Cadau, E.G.; Boccia, V.; Gascon, F.; Kocaman, S. Sen2Like: Paving the Way towards Harmonization and Fusion of Optical Data. Remote Sens. 2022, 14, 3855. (https://doi.org/10.3390/rs14163855) - + + [11] [Sen2Cor3 installation instructions](sen2cor3/README.md) **Learn how to use Sen2Like**, have a look at the [User Manual](sen2like/docs/source/S2-SEN2LIKE-UM-V1.9.pdf). diff --git a/sen2cor3/README.md b/sen2cor3/README.md new file mode 100644 index 0000000..f2d2d1e --- /dev/null +++ b/sen2cor3/README.md @@ -0,0 +1,154 @@ +# Sen2Cor 3 version 3.01.00 + +## Retrieve Sen2cor 3.01.00 documentation from sftp server + +``` +hostname = 'sftp.telespazio.fr' +port = 22 # default SFTP port is 22 +username = 'sen2cor3' +password = '4sen2like' +remote_path = '/upload/Sen2Cor-3.01.00/Documentation/' +``` + +**_Sen2cor 3.01.00 Software Release Note:_** +sftp://sen2cor3@sftp.telespazio.fr/upload/Sen2Cor-3.01.00/Documentation/S2-SEN2LIKE-Sen2Cor_3.01.00-SRN_V1.1.pdf + +**_Sen2cor 3.01.00 Software Configuration and User Manual:_** +sftp://sen2cor3@sftp.telespazio.fr/upload/Sen2Cor-3.01.00/Documentation/S2-SEN2LIKE-Sen2Cor_3.01.00-SUM_V1.1.pdf + +## Retrieve Sen2cor 3.01.00 software from sftp server + +Either with a software like Filezilla: + +``` +hostname = 'sftp.telespazio.fr' +port = 22 # default SFTP port is 22 +username = 'sen2cor3' +password = '4sen2like' +remote_path = '/upload/Sen2Cor-3.01.00/Software/sen2cor_3.1.0_python_3.10_20240313.zip' +``` + +e.g: sftp://sen2cor3@sftp.telespazio.fr/upload/Sen2Cor-3.01.00/Software/sen2cor_3.1.0_python_3.10_20240313.zip + +or with the example script "sen2cor3_download.py" based on "paramiko" module. +It requires paramiko version 3.4.0 that could be installed with conda [see below](#create-the-sen2like-conda-environment): + +``` +conda activate sen2like +conda install paramiko=3.4.0 -c conda-forge +``` + +``` +python sen2cor3_download.py sen2cor3_install_dir +``` + +## Unzip sen2cor_3.1.0_python_3.10.zip into the Sen2Cor 3 directory of your choice + +``` +e.g. sen2cor3_install_dir=/opt/sen2cor3/code/ +cd $sen2cor3_install_dir +unzip sen2cor_3.1.0_python_3.10.zip +``` + +## Auxiliary Data Symbolic linking + +Sen2Cor3 relies on a set of external auxiliary data that needs to be available in Sen2Cor3 "aux_data" folder: +- ECMWF CAMS data: daily, monthly +- ESA CCI files +- Copernicus DEM files + +Further details are available in Sen2Cor3 Software User Manual. + +Examples of symbolic linking is given hereafter: +- symbolic linking of your local CAMS folder that contains daily CAMS data e.g. /data/CAMS/daily +- symbolic linking of your local ESA CCI files e.g. /data/AUX_DATA/ + + +``` +cd $sen2cor3_install_dir/sen2cor_3.1.0_python_3.10/SEN2COR_3/aux_data +ln -s /data/CAMS/daily ./ECMWF/daily +ln -s /data/AUX_DATA/ESACCI-LC-L4-Snow-Cond-500m-MONTHLY-2000-2012-v2.4 ./ESACCI-LC-L4-Snow-Cond-500m-MONTHLY-2000-2012-v2.4 +ln -s /data/AUX_DATA/ESACCI-LC-L4-WB-Map-150m-P13Y-2000-v4.0.tif ./ESACCI-LC-L4-WB-Map-150m-P13Y-2000-v4.0.tif +ln -s /data/AUX_DATA/ESACCI-LC-L4-LCCS-Map-300m-P1Y-2015-v2.0.7.tif ./ESACCI-LC-L4-LCCS-Map-300m-P1Y-2015-v2.0.7.tif +``` + +## Install miniconda if conda is not already installed on your system + +https://repo.anaconda.com/miniconda/Miniconda3-py37_22.11.1-1-Linux-x86_64.sh + +## Create the sen2like conda environment + +Once you retrieved the code, go into Sen2Cor3 root source folder and run the following command to create a conda env named sen2like: + +``` +cd $sen2cor3_install_dir/sen2cor_3.1.0_python_3.10 +conda create -n sen2like --file requirements.txt -c conda-forge +``` + +## Activate sen2like conda environment + +Sen2Cor 3.1 uses the same conda environment as Sen2like: + +``` +conda activate sen2like +``` + +### Test the Command line execution + +``` +python $sen2cor3_install_dir/sen2cor_3.1.0_python_3.10/SEN2COR_3/L2A_Process.py --help + +output: +usage: L2A_Process.py [-h] [--mode MODE] [--resolution {10,20,30,60}] [--datastrip DATASTRIP] [--tile TILE] [--output_dir OUTPUT_DIR] [--work_dir WORK_DIR] + [--img_database_dir IMG_DATABASE_DIR] [--res_database_dir RES_DATABASE_DIR] [--processing_centre PROCESSING_CENTRE] [--archiving_centre ARCHIVING_CENTRE] + [--processing_baseline PROCESSING_BASELINE] [--raw] [--tif] [--sc_only] [--sc_classic] [--sc_cog] [--cr_only] [--debug] [--GIP_L2A GIP_L2A] + [--GIP_L2A_SC GIP_L2A_SC] [--GIP_L2A_AC GIP_L2A_AC] [--GIP_L2A_PB GIP_L2A_PB] [--Hyper_MS] + input_dir + +Sen2Cor. Version: 03.01.00, created: 2024.02.29, supporting Level-1C product version 14.2 - 14.9, supporting Level-1TP Collection_1-2 Landsat_8-9, supporting Hyper Level-1C - . + +positional arguments: + input_dir Directory of Level-1C input + +options: + -h, --help show this help message and exit + --mode MODE Mode: generate_datastrip, process_tile + --resolution {10,20,30,60} + Target resolution, can be 10, 20 or 60m for S2, 30m for Hyper. If omitted, only 20 and 10m resolutions will be processed + --datastrip DATASTRIP + Datastrip folder + --tile TILE Tile folder + --output_dir OUTPUT_DIR + Output directory + --work_dir WORK_DIR Work directory + --img_database_dir IMG_DATABASE_DIR + Database directory for L1C(H) input images + --res_database_dir RES_DATABASE_DIR + Database directory for results and temporary products + --processing_centre PROCESSING_CENTRE + Processing centre as regex: ^[A-Z_]{4}$, e.g "SGS_" + --archiving_centre ARCHIVING_CENTRE + Archiving centre as regex: ^[A-Z_]{4}$, e.g. "SGS_" + --processing_baseline PROCESSING_BASELINE + Processing baseline in the format: "dd.dd", where d=[0:9] + --raw Export raw images in rawl format with ENVI hdr + --tif Export raw images in TIFF format instead of JPEG-2000 + --sc_only Performs only the scene classification at 60 or 20m resolution, 30m for Hyper + --sc_classic Performs scene classification in Sen2Cor 2.9 mode + --sc_cog Export SCL image in COG format instead of JPEG_2000 + --cr_only Performs only the creation of the L2A product tree, no processing + --debug Performs in debug mode + --GIP_L2A GIP_L2A Select the user GIPP + --GIP_L2A_SC GIP_L2A_SC + Select the scene classification GIPP + --GIP_L2A_AC GIP_L2A_AC + Select the atmospheric correction GIPP + --GIP_L2A_PB GIP_L2A_PB + Select the processing baseline GIPP + --Hyper_MS To Process a Hyper_MS product + + +``` + + + diff --git a/sen2cor3/sen2cor3_download.py b/sen2cor3/sen2cor3_download.py new file mode 100644 index 0000000..1aa893e --- /dev/null +++ b/sen2cor3/sen2cor3_download.py @@ -0,0 +1,41 @@ +import sys +import os +import paramiko + +def download_from_sftp(hostname, port, username, password, remote_path, local_path): + # Connect to the SFTP server + transport = paramiko.Transport((hostname, port)) + transport.connect(username=username, password=password) + sftp = paramiko.SFTPClient.from_transport(transport) + + # Create local directory if it doesn't exist + local_dir = os.path.dirname(local_path) + if not os.path.exists(local_dir): + os.makedirs(local_dir) + + try: + # Download the file + sftp.get(remote_path, local_path) + print(f"File downloaded successfully from {remote_path} to {local_path}") + except Exception as e: + print(f"Error downloading file: {e}") + finally: + # Close the connection + sftp.close() + transport.close() + +if __name__ == "__main__": + if len(sys.argv) != 2: + print("Usage: python sen2cor3_download.py local_path") + sys.exit(1) + + local_path = sys.argv[1] + local_path = os.path.join(local_path, 'sen2cor_3.1.0_python_3.10_20240313.zip') + + hostname = "sftp.telespazio.fr" + port = 22 # default SFTP port is 22 + username = 'sen2cor3' + password = '4sen2like' + remote_path = '/upload/Sen2Cor-3.01.00/Software/sen2cor_3.1.0_python_3.10_20240313.zip' + + download_from_sftp(hostname, port, username, password, remote_path, local_path) \ No newline at end of file diff --git a/sen2like/Dockerfile-base b/sen2like/Dockerfile-base index 79a3bee..619e225 100644 --- a/sen2like/Dockerfile-base +++ b/sen2like/Dockerfile-base @@ -1,7 +1,7 @@ # docker image based on miniconda image (debian:latest) # ARG MINICONDA_DOCKER_VERSION # FROM continuumio/miniconda3:${MINICONDA_DOCKER_VERSION} -FROM continuumio/miniconda3:23.3.1-0 +FROM continuumio/miniconda3:23.10.0-1 # set the working dir to /usr/local/sen2like WORKDIR /usr/local/sen2like diff --git a/sen2like/conf/config.ini b/sen2like/conf/config.ini index 1612f12..71cd837 100644 --- a/sen2like/conf/config.ini +++ b/sen2like/conf/config.ini @@ -41,7 +41,7 @@ url_parameters_pattern_Landsat9 = {base_url}/{mission}/{path}/{row} ; location_Landsat8 = path={path}&row={row}&productType=L1TP ; location_Landsat9 = path={path}&row={row}&productType=L1TP ; location_Sentinel2 = productIdentifier=%25T{tile}%25 -; url_parameters_pattern = {base_url}/{mission}/search.json?maxRecords=1000&_pretty=true&cloudCover=%5B0%2C{cloud_cover}%5D&startDate={start_date}&completionDate={end_date}&sortParam=startDate&sortOrder=ascending&status=all&{location}&dataset=ESA-DATASET +; url_parameters_pattern = {base_url}/{mission}/search.json?maxRecords=1000&cloudCover=%5B0%2C{cloud_cover}%5D&startDate={start_date}&completionDate={end_date}&sortParam=startDate&sortOrder=ascending&status=all&{location}&dataset=ESA-DATASET ; thumbnail_property = properties/productIdentifier ; cloud_cover_property = properties/cloudCover ; gml_geometry_property = properties/gmlgeometry @@ -56,7 +56,7 @@ url_parameters_pattern_Landsat9 = {base_url}/{mission}/{path}/{row} # remote S2 part ;base_url_s2 = https://datahub.creodias.eu/resto/api/collections ;location_Sentinel2 = productIdentifier=%25T{tile}%25 -;url_parameters_pattern = {base_url_s2}/{mission}/search.json?maxRecords=1000&_pretty=true&cloudCover=%5B0%2C{cloud_cover}%5D&startDate={start_date}&completionDate={end_date}&sortParam=startDate&sortOrder=ascending&status=all&{location}&dataset=ESA-DATASET +;url_parameters_pattern = {base_url_s2}/{mission}/search.json?maxRecords=1000&cloudCover=%5B0%2C{cloud_cover}%5D&startDate={start_date}&completionDate={end_date}&sortParam=startDate&sortOrder=ascending&status=all&{location}&dataset=ESA-DATASET ;thumbnail_property = properties/productIdentifier ;cloud_cover_property = properties/cloudCover ;gml_geometry_property = properties/gmlgeometry @@ -71,7 +71,7 @@ url_parameters_pattern_Landsat9 = {base_url}/{mission}/{path}/{row} ;base_url_landsat = https://datahub.creodias.eu/resto/api/collections ;location_Landsat8 = path={path}&row={row}&productType=L1TP ;location_Landsat9 = path={path}&row={row}&productType=L1TP -;url_parameters_pattern = {base_url_landsat}/{mission}/search.json?maxRecords=1000&_pretty=true&cloudCover=%5B0%2C{cloud_cover}%5D&startDate={start_date}&completionDate={end_date}&sortParam=startDate&sortOrder=ascending&status=all&{location}&dataset=ESA-DATASET +;url_parameters_pattern = {base_url_landsat}/{mission}/search.json?maxRecords=1000&cloudCover=%5B0%2C{cloud_cover}%5D&startDate={start_date}&completionDate={end_date}&sortParam=startDate&sortOrder=ascending&status=all&{location}&dataset=ESA-DATASET ;thumbnail_property = properties/productIdentifier ;cloud_cover_property = properties/cloudCover ;gml_geometry_property = properties/gmlgeometry @@ -150,4 +150,4 @@ json_metadata = True [RunTime] dx = 0 -dy = 0 \ No newline at end of file +dy = 0 diff --git a/sen2like/conf/config.xml b/sen2like/conf/config.xml index b6c6081..ce3d6e5 100644 --- a/sen2like/conf/config.xml +++ b/sen2like/conf/config.xml @@ -37,7 +37,7 @@ - + @@ -48,7 +48,7 @@ - + @@ -60,7 +60,7 @@ - + diff --git a/sen2like/release-notes.md b/sen2like/release-notes.md index 349e49f..73ab831 100644 --- a/sen2like/release-notes.md +++ b/sen2like/release-notes.md @@ -1,5 +1,24 @@ # Sen2Like Release Notes +## v4.4.3 + +### Fix + +* Fix calculation of Sen2cor region of interest when target UTM differs from the input Landsat product UTM. + +## v4.4.2 + +### Release of Sen2Cor3 documentation and software version 3.01.00 + +Instructions to retrieve sen2cor3 software and associated documentation available [here](../sen2cor3/README.md). + +### Fix + +* Force operational-mode parameter as first command line argument +* Remove `_pretty=` parameter in the creodias catalogue URL in the default configuration as it is no more supported by datahub catalogue. +* Update miniconda in [Dockerfile-base](Dockerfile-base) +* Typos in sen2like project [README.md](../README.md) + ## v4.4.1 ### Important information about sen2like on Creodias diff --git a/sen2like/sen2like/core/argparser.py b/sen2like/sen2like/core/argparser.py index 9359669..f08307d 100644 --- a/sen2like/sen2like/core/argparser.py +++ b/sen2like/sen2like/core/argparser.py @@ -93,7 +93,7 @@ def _configure_arguments(self): # use parser_class=ArgumentParser avoid error on subparsers.add_parser # see https://stackoverflow.com/questions/47833828/subparsers-add-parser-typeerror-init-got-an-unexpected-keyword-argument subparsers = self.add_subparsers(dest='operational_mode', help="Operational mode", parser_class=ArgumentParser) - self._add_common_arguments(self) + # self._add_common_arguments(self) # Product mode arguments sp_product = subparsers.add_parser(Mode.PRODUCT, help="Process a single product") diff --git a/sen2like/sen2like/core/product_preparation.py b/sen2like/sen2like/core/product_preparation.py index b169b21..467f1db 100644 --- a/sen2like/sen2like/core/product_preparation.py +++ b/sen2like/sen2like/core/product_preparation.py @@ -318,7 +318,7 @@ def _extract_product_files(self, product: S2L_Product): if ( scl_dir and (not product.context.use_sen2cor) - and product_reader.data_type != "Level-2A" + and product_reader.data_type != "Level-2A" # Sentinel ): product_reader.scene_classif_band = self._get_scl_map(scl_dir, product) diff --git a/sen2like/sen2like/core/sen2cor_client/sen2cor_client.py b/sen2like/sen2like/core/sen2cor_client/sen2cor_client.py index df6509b..0166719 100644 --- a/sen2like/sen2like/core/sen2cor_client/sen2cor_client.py +++ b/sen2like/sen2like/core/sen2cor_client/sen2cor_client.py @@ -16,17 +16,41 @@ # See the License for the specific language governing permissions and # limitations under the License. - +import affine import logging import os import subprocess import lxml.etree as ET + +from osgeo import osr +import mgrs + from core import S2L_config -from grids.mgrs_framing import pixel_center +from core.image_file import S2L_ImageFile + logger = logging.getLogger("Sen2Like") +def get_mgrs_center(tilecode: str, utm=False) -> tuple: + """Get MGRS tile center coordinates in native tile UTM or WGS84 + + Args: + tilecode (str): tile to get center coords + utm (bool, optional): Flag for output SRS . Defaults to False. + + Returns: + tuple: (lat,long) coords if utm=False, else (utm, N/S, easting, northing) + """ + if tilecode.startswith('T'): + tilecode = tilecode[1:] + centercode = tilecode + '5490045100' + m = mgrs.MGRS() + if utm: + return m.MGRSToUTM(centercode) + return m.toLatLon(centercode) + + class Sen2corClient: gipp_template_file = os.path.join( @@ -117,26 +141,63 @@ def _write_gipp(self, product): # ref_band = None is considered as S2 product format (S2A, S2B, S2P prisma) ref_band = self.roi_ref_band.get(product.mtl.mission, None) - if ref_band is None: - logger.debug("For sentinel, sen2cor don't use ROI") - ET.ElementTree(root).write(gipp_path, encoding='utf-8', xml_declaration=True) - return gipp_path + if ref_band: + # Compute ROI center for landsat and fill template with result + ref_band_file = product.get_band_file(ref_band) - ref_band_file = product.get_band_file(ref_band) + y, x = self._pixel_center(ref_band_file) - y, x = pixel_center(ref_band_file, self.out_mgrs) - logger.debug('Pixel center : (%s, %s)', y, x) + logger.debug('Pixel center : (%s, %s)', y, x) - row0 = root.find('Common_Section/Region_Of_Interest/row0') - row0.text = str(y) - col0 = root.find('Common_Section/Region_Of_Interest/col0') - col0.text = str(x) + row0 = root.find('Common_Section/Region_Of_Interest/row0') + row0.text = str(y) + col0 = root.find('Common_Section/Region_Of_Interest/col0') + col0.text = str(x) - ET.ElementTree(root).write(gipp_path, encoding='utf-8', xml_declaration=True) + ET.ElementTree(root).write(gipp_path, encoding='utf-8', xml_declaration=True) + + else: + logger.debug("For sentinel, sen2cor don't use ROI") logger.info('GIPP L2A : %s', gipp_path) + + ET.ElementTree(root).write(gipp_path, encoding='utf-8', xml_declaration=True) + return gipp_path + def _pixel_center(self, image: S2L_ImageFile): + """Get mgrs tile center coordinates from tile code in image coordinates + + Args: + image (S2L_ImageFile): image to get srs from + + Returns: + tuple: (y,x) image coordinates + """ + + lat, lon = get_mgrs_center(self.out_mgrs) # pylint: disable=W0632 + + # Transform src SRS + wgs84_srs = osr.SpatialReference() + wgs84_srs.ImportFromEPSG(4326) + + # Transform dst SRS + image_srs = osr.SpatialReference(wkt=image.projection) + + # convert MGRS center coordinates from lat lon to image EPSG coordinates (UTM) + transformation = osr.CoordinateTransformation(wgs84_srs, image_srs) + easting, northing, _ = transformation.TransformPoint(lat, lon) + + # northing = y = latitude, easting = x = longitude + tr = affine.Affine( + image.yRes, 0, image.yMax, + 0, image.xRes, image.xMin + ) + + # compute y,x in image coordinates + y, x = (northing, easting) * (~ tr) + return int(y), int(x) + class Sen2corError(Exception): pass diff --git a/sen2like/sen2like/grids/grids.py b/sen2like/sen2like/grids/grids.py index 2b8b217..731c52b 100644 --- a/sen2like/sen2like/grids/grids.py +++ b/sen2like/sen2like/grids/grids.py @@ -22,7 +22,6 @@ import sqlite3 from os.path import abspath, dirname -import mgrs import pandas as pd from osgeo import ogr, osr from shapely.wkt import loads @@ -59,15 +58,6 @@ def getROIfromMGRS(self, tilecode): # return as dict return roi.to_dict(orient='list') - def get_mgrs_center(self, tilecode, utm=False): - if tilecode.startswith('T'): - tilecode = tilecode[1:] - centercode = tilecode + '5490045100' - m = mgrs.MGRS() - if utm: - return m.MGRSToUTM(centercode) - return m.toLatLon(centercode) - # Don't know why but with this method the SRS code is not added in the geojson # if the GDAL_DATA variable is set in the environment. However we need # this GDAL_DATA variable for other methods. So we do not use this method. diff --git a/sen2like/sen2like/grids/mgrs_framing.py b/sen2like/sen2like/grids/mgrs_framing.py index 8e57f5c..306cdd1 100644 --- a/sen2like/sen2like/grids/mgrs_framing.py +++ b/sen2like/sen2like/grids/mgrs_framing.py @@ -24,7 +24,6 @@ from math import ceil from typing import NamedTuple -import affine import numpy as np import pandas as pd from numpy.typing import NDArray @@ -129,35 +128,6 @@ def resample(image: S2L_ImageFile, res: int, filepath_out: str) -> S2L_ImageFile return image.duplicate(filepath_out, array=data, res=res) -def pixel_center(image: S2L_ImageFile, tile_code: str): - """Get mgrs tile center coordinates from tile code in image SRS - - Args: - image (S2L_ImageFile): image to get srs from - tile_code (str): MGRS tile code - - Returns: - tuple: y/x coordinates - """ - converter = grids.GridsConverter() - utm, orientation, easting, northing = converter.get_mgrs_center(tile_code, utm=True) - # UTM South vs. UTM North ? - tile_srs = osr.SpatialReference() - tile_srs.ImportFromEPSG(int('32' + ('6' if orientation == 'N' else '7') + str(utm))) - image_srs = osr.SpatialReference(wkt=image.projection) - if not tile_srs.IsSame(image_srs): - transformation = osr.CoordinateTransformation(tile_srs, image_srs) - northing, easting = transformation.TransformPoint((northing, easting)) - - # northing = y = latitude, easting = x = longitude - tr = affine.Affine( - image.yRes, 0, image.yMax, - 0, image.xRes, image.xMin - ) - y, x = (northing, easting) * (~ tr) - return int(y), int(x) - - def _reproject(filepath: str, dir_out: str, ds_src: gdal.Dataset, x_res: int, y_res: int, target_srs: osr.SpatialReference, order: int) -> ReprojectResult: """Reproject given dataset in the target srs in the given resolution diff --git a/sen2like/tests/core/config.ini b/sen2like/tests/core/config.ini index 39773c3..1341828 100644 --- a/sen2like/tests/core/config.ini +++ b/sen2like/tests/core/config.ini @@ -30,7 +30,7 @@ base_url = /data/PRODUCTS # cloud_cover = 100 # location_Landsat8 = path={path}&row={row}&productType=L1TP # location_Sentinel2 = processingLevel=LEVEL1C&productIdentifier=%25{tile}%25 -# url_parameters_pattern = {base_url}/{mission}/search.json?maxRecords=100&_pretty=true&cloudCover=%5B0%2C{cloud_cover}%5D&startDate={start_date}&completionDate={end_date}&sortParam=startDate&sortOrder=ascending&status=all&{location}&dataset=ESA-DATASET +# url_parameters_pattern = {base_url}/{mission}/search.json?maxRecords=100&cloudCover=%5B0%2C{cloud_cover}%5D&startDate={start_date}&completionDate={end_date}&sortParam=startDate&sortOrder=ascending&status=all&{location}&dataset=ESA-DATASET # thumbnail_property = properties/productIdentifier # cloud_cover_property = properties/cloudCover diff --git a/sen2like/tests/core/downloader/config.ini b/sen2like/tests/core/downloader/config.ini index d4b7c87..6e40886 100644 --- a/sen2like/tests/core/downloader/config.ini +++ b/sen2like/tests/core/downloader/config.ini @@ -28,7 +28,7 @@ base_url = https://datahub.creodias.eu/resto/api/collections cloud_cover = 100 location_Landsat8 = path={path}&row={row}&productType=L1TP location_Sentinel2 = processingLevel=LEVEL1C&productIdentifier=%25{tile}%25 -url_parameters_pattern = {base_url}/{mission}/search.json?maxRecords=100&_pretty=true&cloudCover=%5B0%2C{cloud_cover}%5D&startDate={start_date}&completionDate={end_date}&sortParam=startDate&sortOrder=ascending&status=all&{location}&dataset=ESA-DATASET +url_parameters_pattern = {base_url}/{mission}/search.json?maxRecords=100&cloudCover=%5B0%2C{cloud_cover}%5D&startDate={start_date}&completionDate={end_date}&sortParam=startDate&sortOrder=ascending&status=all&{location}&dataset=ESA-DATASET thumbnail_property = properties/productIdentifier cloud_cover_property = properties/cloudCover diff --git a/sen2like/tests/core/file_extractor/config.ini b/sen2like/tests/core/file_extractor/config.ini index c1bc8eb..d4c5be0 100644 --- a/sen2like/tests/core/file_extractor/config.ini +++ b/sen2like/tests/core/file_extractor/config.ini @@ -28,7 +28,7 @@ base_url = /data/PRODUCTS # cloud_cover = 100 # location_Landsat8 = path={path}&row={row}&productType=L1TP # location_Sentinel2 = processingLevel=LEVEL1C&productIdentifier=%25{tile}%25 -# url_parameters_pattern = {base_url}/{mission}/search.json?maxRecords=100&_pretty=true&cloudCover=%5B0%2C{cloud_cover}%5D&startDate={start_date}&completionDate={end_date}&sortParam=startDate&sortOrder=ascending&status=all&{location}&dataset=ESA-DATASET +# url_parameters_pattern = {base_url}/{mission}/search.json?maxRecords=100&cloudCover=%5B0%2C{cloud_cover}%5D&startDate={start_date}&completionDate={end_date}&sortParam=startDate&sortOrder=ascending&status=all&{location}&dataset=ESA-DATASET # thumbnail_property = properties/productIdentifier # cloud_cover_property = properties/cloudCover diff --git a/sen2like/tests/core/products/config.ini b/sen2like/tests/core/products/config.ini index 39773c3..1341828 100644 --- a/sen2like/tests/core/products/config.ini +++ b/sen2like/tests/core/products/config.ini @@ -30,7 +30,7 @@ base_url = /data/PRODUCTS # cloud_cover = 100 # location_Landsat8 = path={path}&row={row}&productType=L1TP # location_Sentinel2 = processingLevel=LEVEL1C&productIdentifier=%25{tile}%25 -# url_parameters_pattern = {base_url}/{mission}/search.json?maxRecords=100&_pretty=true&cloudCover=%5B0%2C{cloud_cover}%5D&startDate={start_date}&completionDate={end_date}&sortParam=startDate&sortOrder=ascending&status=all&{location}&dataset=ESA-DATASET +# url_parameters_pattern = {base_url}/{mission}/search.json?maxRecords=100&cloudCover=%5B0%2C{cloud_cover}%5D&startDate={start_date}&completionDate={end_date}&sortParam=startDate&sortOrder=ascending&status=all&{location}&dataset=ESA-DATASET # thumbnail_property = properties/productIdentifier # cloud_cover_property = properties/cloudCover diff --git a/sen2like/tests/s2l_processes/config.ini b/sen2like/tests/s2l_processes/config.ini index 89f2549..6a472a8 100644 --- a/sen2like/tests/s2l_processes/config.ini +++ b/sen2like/tests/s2l_processes/config.ini @@ -29,7 +29,7 @@ base_url = /data/PRODUCTS # cloud_cover = 100 # location_Landsat8 = path={path}&row={row}&productType=L1TP # location_Sentinel2 = processingLevel=LEVEL1C&productIdentifier=%25{tile}%25 -# url_parameters_pattern = {base_url}/{mission}/search.json?maxRecords=100&_pretty=true&cloudCover=%5B0%2C{cloud_cover}%5D&startDate={start_date}&completionDate={end_date}&sortParam=startDate&sortOrder=ascending&status=all&{location}&dataset=ESA-DATASET +# url_parameters_pattern = {base_url}/{mission}/search.json?maxRecords=100&cloudCover=%5B0%2C{cloud_cover}%5D&startDate={start_date}&completionDate={end_date}&sortParam=startDate&sortOrder=ascending&status=all&{location}&dataset=ESA-DATASET # thumbnail_property = properties/productIdentifier # cloud_cover_property = properties/cloudCover