From 00376e608e0b79ca253f9ad055febf364e09f051 Mon Sep 17 00:00:00 2001 From: Emmanuel Mathot Date: Tue, 26 Mar 2024 11:10:01 +0100 Subject: [PATCH] Fix print statements and update method calls in s3-olci-composites.py --- .../libexec/ts-scripts/s3-olci-composites.py | 56 +- .../ts-scripts/s3-olci-composites.py.bak | 719 ++++++++++++++++++ 2 files changed, 747 insertions(+), 28 deletions(-) create mode 100644 src/cdab-remote-client/libexec/ts-scripts/s3-olci-composites.py.bak diff --git a/src/cdab-remote-client/libexec/ts-scripts/s3-olci-composites.py b/src/cdab-remote-client/libexec/ts-scripts/s3-olci-composites.py index bcdec4b..4e0a198 100644 --- a/src/cdab-remote-client/libexec/ts-scripts/s3-olci-composites.py +++ b/src/cdab-remote-client/libexec/ts-scripts/s3-olci-composites.py @@ -54,7 +54,7 @@ def view_graph(self): Raises: None. """ - print(etree.tostring(self.root , pretty_print=True)) + print((etree.tostring(self.root , pretty_print=True))) def add_node(self, node_id, operator, parameters, source): """This method adds or overwrites a node to the SNAP Graph @@ -80,7 +80,7 @@ def add_node(self, node_id, operator, parameters, source): sources_elem = self.root.xpath(xpath_expr + '/sources')[0] parameters_elem = self.root.xpath(xpath_expr + '/parameters') - for key, value in parameters.iteritems(): + for key, value in list(parameters.items()): if key == 'targetBandDescriptors': @@ -114,7 +114,7 @@ def add_node(self, node_id, operator, parameters, source): elif isinstance(source, dict): - for key, value in source.iteritems(): + for key, value in list(source.items()): source_product_elem = etree.SubElement(sources_elem, key) source_product_elem.text = value @@ -126,7 +126,7 @@ def add_node(self, node_id, operator, parameters, source): parameters_elem = etree.SubElement(node_elem, 'parameters') parameters_elem.attrib['class'] = 'com.bc.ceres.binding.dom.XppDomElement' - for key, value in parameters.iteritems(): + for key, value in list(parameters.items()): if key == 'targetBandDescriptors': @@ -207,9 +207,9 @@ def run(self): p = subprocess.Popen(options, stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.PIPE) - print('Process PID: %s' % p.pid) + print(('Process PID: %s' % p.pid)) res, err = p.communicate() - print (res, err) + print((res, err)) finally: os.remove(path) @@ -269,18 +269,18 @@ def get_operator_help(operator): """ op_spi = GPF.getDefaultInstance().getOperatorSpiRegistry().getOperatorSpi(operator) - print('Operator name: {}'.format(op_spi.getOperatorDescriptor().getName())) + print(('Operator name: {}'.format(op_spi.getOperatorDescriptor().getName()))) - print('Operator alias: {}\n'.format(op_spi.getOperatorDescriptor().getAlias())) + print(('Operator alias: {}\n'.format(op_spi.getOperatorDescriptor().getAlias()))) print('Parameters:\n') param_Desc = op_spi.getOperatorDescriptor().getParameterDescriptors() for param in param_Desc: - print('{}: {}\nDefault Value: {}\n'.format(param.getName(), + print(('{}: {}\nDefault Value: {}\n'.format(param.getName(), param.getDescription(), - param.getDefaultValue())) + param.getDefaultValue()))) - print('Possible values: {}\n').format(list(param.getValueSet())) + print(('Possible values: {}\n').format(list(param.getValueSet()))) def op_help(op): @@ -297,18 +297,18 @@ def op_help(op): """ op_spi = snappy.GPF.getDefaultInstance().getOperatorSpiRegistry().getOperatorSpi(op) - print('Operator name: {}'.format(op_spi.getOperatorDescriptor().getName())) + print(('Operator name: {}'.format(op_spi.getOperatorDescriptor().getName()))) - print('Operator alias: {}\n'.format(op_spi.getOperatorDescriptor().getAlias())) + print(('Operator alias: {}\n'.format(op_spi.getOperatorDescriptor().getAlias()))) print('Parameters:\n') param_Desc = op_spi.getOperatorDescriptor().getParameterDescriptors() for param in param_Desc: - print('{}: {}\nDefault Value: {}\n'.format(param.getName(), + print(('{}: {}\nDefault Value: {}\n'.format(param.getName(), param.getDescription(), - param.getDefaultValue())) + param.getDefaultValue()))) - print('Possible values: {}\n').format(list(param.getValueSet())) + print(('Possible values: {}\n').format(list(param.getValueSet()))) def get_operators(): """This function provides a Python dictionary with all SNAP operators. @@ -330,7 +330,7 @@ def get_operators(): while op_spi_it.hasNext(): - op_spi = op_spi_it.next() + op_spi = next(op_spi_it) op_class = op_spi.getOperatorDescriptor().getName() @@ -373,8 +373,8 @@ def get_write_formats(): write_plugins = ProductIOPlugInManager.getInstance().getAllWriterPlugIns() while write_plugins.hasNext(): - plugin = write_plugins.next() - print ('{} ({})'.format(plugin.getFormatNames()[0], plugin.getDefaultFileExtensions()[0])) + plugin = next(write_plugins) + print(('{} ({})'.format(plugin.getFormatNames()[0], plugin.getDefaultFileExtensions()[0]))) def get_mask(idepix, classif_flags): @@ -470,25 +470,25 @@ def s3_olci_import(idepix, **kwargs): ] for operator in operators: - print('Getting default values for Operator {}'.format(operator)) + print(('Getting default values for Operator {}'.format(operator))) parameters = get_operator_default_parameters(operator) options[operator] = parameters - for key, value in kwargs.items(): - print('Updating Operator {}'.format(key)) + for key, value in list(kwargs.items()): + print(('Updating Operator {}'.format(key))) options[key.replace('_', '-')].update(value) mygraph = GraphProcessor() for index, operator in enumerate(operators): - print ('Adding Operator {} to graph').format(operator) + print(('Adding Operator {} to graph'.format(operator))) if index == 0: source_node_id = '' else: source_node_id = operators[index - 1] - if operator == 'Idepix.Sentinel3.Olci': + if operator == 'Idepix.Olci': mygraph.add_node(operator, operator, idepix, source_node_id) else: mygraph.add_node(operator, operator, options[operator], source_node_id) @@ -610,7 +610,7 @@ def extract_info(search_result_file): s3_olci_bands = [] -for key, value in composites.items(): +for key, value in list(composites.items()): if value['create']: for band in value['bands'].split(','): s3_olci_bands.append(band) @@ -652,13 +652,13 @@ def extract_info(search_result_file): output_stopdate = input_metadata.iloc[0]['enddate'] -for k, v in composites.items(): +for k, v in list(composites.items()): - print("k = {0}".format(k)) + print(("k = {0}".format(k))) bands = [os.path.join(write['file'] + '.data', '{}.img'.format(band)) for band in (composites[k]['bands'].split(',') + ['pixel_classif_flags'])] - print("BANDS = {0}".format(bands)) + print(("BANDS = {0}".format(bands))) ds = gdal.Open(bands[0]) diff --git a/src/cdab-remote-client/libexec/ts-scripts/s3-olci-composites.py.bak b/src/cdab-remote-client/libexec/ts-scripts/s3-olci-composites.py.bak new file mode 100644 index 0000000..4e0a198 --- /dev/null +++ b/src/cdab-remote-client/libexec/ts-scripts/s3-olci-composites.py.bak @@ -0,0 +1,719 @@ +import os +import sys +import os +import sys +import geopandas as gp +import pandas as pd +import numpy as np +sys.path.append(os.getcwd()) +sys.path.append('/opt/otb/lib/python') +sys.path.append('/opt/otb/lib/libfftw3.so.3') +os.environ['OTB_APPLICATION_PATH'] = '/opt/otb/lib/otb/applications' +os.environ['LD_LIBRARY_PATH'] = '/opt/otb/lib' +os.environ['ITK_AUTOLOAD_PATH'] = '/opt/otb/lib/otb/applications' +import otbApplication +import gdal +from shapely.wkt import loads +from shapely.geometry import box +import shutil +import math +import json +import lxml.etree as etree +import subprocess +import tempfile +import snappy +from snappy import GPF + +class GraphProcessor(): + """SNAP Graph class + + This class provides the methods to create, view and run a SNAP Graph + + Attributes: + None. + """ + + def __init__(self, wdir='.'): + self.root = etree.Element('graph') + + version = etree.SubElement(self.root, 'version') + version.text = '1.0' + self.pid = None + self.p = None + self.wdir = wdir + + def view_graph(self): + """This method prints SNAP Graph + + Args: + None. + + Returns + None. + + Raises: + None. + """ + print((etree.tostring(self.root , pretty_print=True))) + + def add_node(self, node_id, operator, parameters, source): + """This method adds or overwrites a node to the SNAP Graph + + Args: + node_id: node identifier + operator: SNAP operator + parameter: dictionary with the SNAP operator parameters + source: string or list of sources (previous node identifiers in the SNAP Graph) + + Returns + None. + + Raises: + None. + """ + xpath_expr = '/graph/node[@id="%s"]' % node_id + + if len(self.root.xpath(xpath_expr)) != 0: + + node_elem = self.root.xpath(xpath_expr)[0] + operator_elem = self.root.xpath(xpath_expr + '/operator')[0] + sources_elem = self.root.xpath(xpath_expr + '/sources')[0] + parameters_elem = self.root.xpath(xpath_expr + '/parameters') + + for key, value in list(parameters.items()): + + if key == 'targetBandDescriptors': + + parameters_elem.append(etree.fromstring(value)) + + else: + p_elem = self.root.xpath(xpath_expr + '/parameters/%s' % key)[0] + + if value is not None: + if value[0] != '<': + p_elem.text = value + else: + p_elem.text.append(etree.fromstring(value)) + + else: + + node_elem = etree.SubElement(self.root, 'node') + operator_elem = etree.SubElement(node_elem, 'operator') + sources_elem = etree.SubElement(node_elem, 'sources') + + if isinstance(source, list): + + for index, s in enumerate(source): + if index == 0: + source_product_elem = etree.SubElement(sources_elem, 'sourceProduct') + + else: + source_product_elem = etree.SubElement(sources_elem, 'sourceProduct.%s' % str(index)) + + source_product_elem.attrib['refid'] = s + + elif isinstance(source, dict): + + for key, value in list(source.items()): + + source_product_elem = etree.SubElement(sources_elem, key) + source_product_elem.text = value + + elif source != '': + source_product_elem = etree.SubElement(sources_elem, 'sourceProduct') + source_product_elem.attrib['refid'] = source + + parameters_elem = etree.SubElement(node_elem, 'parameters') + parameters_elem.attrib['class'] = 'com.bc.ceres.binding.dom.XppDomElement' + + for key, value in list(parameters.items()): + + if key == 'targetBandDescriptors': + + parameters_elem.append(etree.fromstring(value)) + + else: + + parameter_elem = etree.SubElement(parameters_elem, key) + + if value is not None: + if value[0] != '<': + parameter_elem.text = value + else: + parameter_elem.append(etree.fromstring(value)) + + node_elem.attrib['id'] = node_id + + operator_elem.text = operator + + def save_graph(self, filename): + """This method saves the SNAP Graph + + Args: + filename: XML filename with '.xml' extension + + Returns + None. + + Raises: + None. + """ + with open(filename, 'wb') as file: + file.write('\n') + file.write(etree.tostring(self.root, pretty_print=True)) + + #def plot_graph(self): + + # for node_id in self.root.xpath('/graph/node/@id'): + + + # xpath_expr = '/graph/node[@id="%s"]' % node_id + + # if len(self.root.xpath(xpath_expr + '/sources/sourceProduct')) != 0: + # print(self.root.xpath(xpath_expr + '/sources/sourceProduct'))[0].attrib['refid'] + # print(node_id) + # else: + # print(node_id) + # return True + + def run(self): + """This method runs the SNAP Graph using gpt + + Args: + None. + + Returns + res: gpt exit code + err: gpt stderr + + Raises: + None. + """ + os.environ['LD_LIBRARY_PATH'] = '.' + + print('Processing the graph') + + fd, path = tempfile.mkstemp() + + try: + + self.save_graph(filename=path) + options = ['/opt/snap/bin/gpt', + '-x', + '-c', + '2048M', + path] + + p = subprocess.Popen(options, + stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.PIPE) + + print(('Process PID: %s' % p.pid)) + res, err = p.communicate() + print((res, err)) + finally: + os.remove(path) + + print('Done.') + return res, err + + +def get_snap_parameters(operator): + """This function returns the SNAP operator ParameterDescriptors (snappy method op_spi.getOperatorDescriptor().getParameterDescriptors()) + + Args: + operator: SNAP operator + + Returns + The snappy object returned by op_spi.getOperatorDescriptor().getParameterDescriptors(). + + Raises: + None. + """ + op_spi = GPF.getDefaultInstance().getOperatorSpiRegistry().getOperatorSpi(operator) + + op_params = op_spi.getOperatorDescriptor().getParameterDescriptors() + + return op_params + +def get_operator_default_parameters(operator): + """This function returns a Python dictionary with the SNAP operator parameters and their default values, if available. + + Args: + operator: SNAP operator + + Returns + A Python dictionary with the SNAP operator parameters and their default values. + + Raises: + None. + """ + parameters = dict() + + for param in get_snap_parameters(operator): + + parameters[param.getName()] = param.getDefaultValue() + + return parameters + +def get_operator_help(operator): + """This function prints the human readable information about a SNAP operator + + Args: + operator: SNAP operator + + Returns + The human readable information about the provided SNAP operator. + + Raises: + None. + """ + op_spi = GPF.getDefaultInstance().getOperatorSpiRegistry().getOperatorSpi(operator) + + print(('Operator name: {}'.format(op_spi.getOperatorDescriptor().getName()))) + + print(('Operator alias: {}\n'.format(op_spi.getOperatorDescriptor().getAlias()))) + print('Parameters:\n') + param_Desc = op_spi.getOperatorDescriptor().getParameterDescriptors() + + for param in param_Desc: + print(('{}: {}\nDefault Value: {}\n'.format(param.getName(), + param.getDescription(), + param.getDefaultValue()))) + + print(('Possible values: {}\n').format(list(param.getValueSet()))) + + +def op_help(op): + """This function prints the human readable information about a SNAP operator + + Args: + op: the SNAP operator + + Returns + Human readable information about a SNAP operator. + + Raises: + None. + """ + op_spi = snappy.GPF.getDefaultInstance().getOperatorSpiRegistry().getOperatorSpi(op) + + print(('Operator name: {}'.format(op_spi.getOperatorDescriptor().getName()))) + + print(('Operator alias: {}\n'.format(op_spi.getOperatorDescriptor().getAlias()))) + print('Parameters:\n') + param_Desc = op_spi.getOperatorDescriptor().getParameterDescriptors() + + for param in param_Desc: + print(('{}: {}\nDefault Value: {}\n'.format(param.getName(), + param.getDescription(), + param.getDefaultValue()))) + + print(('Possible values: {}\n').format(list(param.getValueSet()))) + +def get_operators(): + """This function provides a Python dictionary with all SNAP operators. + + Args: + None. + + Returns + Python dictionary with all SNAP operators. + + Raises: + None. + """ + snappy.GPF.getDefaultInstance().getOperatorSpiRegistry().loadOperatorSpis() + + op_spi_it = snappy.GPF.getDefaultInstance().getOperatorSpiRegistry().getOperatorSpis().iterator() + + snap_operators = dict() + + while op_spi_it.hasNext(): + + op_spi = next(op_spi_it) + + op_class = op_spi.getOperatorDescriptor().getName() + + if 's1tbx' in op_spi.getOperatorDescriptor().getName(): + + op_toolbox = 's1tbx' + + elif 's2tbx' in op_spi.getOperatorDescriptor().getName(): + + op_toolbox = 's2tbx' + + elif 's3tbx' in op_spi.getOperatorDescriptor().getName(): + + op_toolbox = 's3tbx' + else: + + op_toolbox = 'other' + + snap_operators[op_spi.getOperatorAlias()] = {'name' : op_spi.getOperatorDescriptor().getName(), + 'toolbox' : op_toolbox} + + return snap_operators + +def get_write_formats(): + """This function provides a human readable list of SNAP Write operator formats. + + Args: + None. + + Returns + Human readable list of SNAP Write operator formats. + + Raises: + None. + """ + ProductIOPlugInManager = snappy.jpy.get_type('org.esa.snap.core.dataio.ProductIOPlugInManager') + + ProductWriterPlugIn = snappy.jpy.get_type('org.esa.snap.core.dataio.ProductWriterPlugIn') + + write_plugins = ProductIOPlugInManager.getInstance().getAllWriterPlugIns() + + while write_plugins.hasNext(): + plugin = next(write_plugins) + print(('{} ({})'.format(plugin.getFormatNames()[0], plugin.getDefaultFileExtensions()[0]))) + +def get_mask(idepix, classif_flags): + + pixel_classif_flags = { + 'IDEPIX_BRIGHT': 128, + 'IDEPIX_CLOUD': 2, + 'IDEPIX_CLOUD_AMBIGUOUS': 4, + 'IDEPIX_CLOUD_BUFFER': 16, + 'IDEPIX_CLOUD_SHADOW': 32, + 'IDEPIX_CLOUD_SURE': 8, + 'IDEPIX_COASTLINE': 512, + 'IDEPIX_INVALID': 1, + 'IDEPIX_LAND': 1024, + 'IDEPIX_SNOW_ICE': 64, + 'IDEPIX_WHITE': 256 + } + + + b1 = int(math.log(pixel_classif_flags[idepix], 2)) + b2 = b1 + + return _capture_bits(classif_flags.astype(np.int64), b1, b2) + +def _capture_bits(arr, b1, b2): + + width_int = int((b1 - b2 + 1) * "1", 2) + + return ((arr >> b2) & width_int).astype('uint8') + +def export_s3(bands): + + ds = gdal.Open(bands[0]) + + width = ds.RasterXSize + height = ds.RasterYSize + + input_geotransform = ds.GetGeoTransform() + input_georef = ds.GetProjectionRef() + + ds = None + + driver = gdal.GetDriverByName('GTiff') + + output = driver.Create( + 's3.tif', + width, + height, + len(bands), + gdal.GDT_Float32 + ) + + output.SetGeoTransform(input_geotransform) + output.SetProjection(input_georef) + + for index, band in enumerate(bands): + print(band) + temp_ds = gdal.Open(band) + + band_data = temp_ds.GetRasterBand(1).ReadAsArray() + output.GetRasterBand(index+1).WriteArray(band_data) + + output.FlushCache() + + return True + +def read_s3(bands): + + gdal.UseExceptions() + + stack = [] + + for index, band in enumerate(bands): + + temp_ds = gdal.Open(band) + + if not temp_ds: + raise ValueError() + + stack.append(temp_ds.GetRasterBand(1).ReadAsArray()) + + return np.dstack(stack) + + +def s3_olci_import(idepix, **kwargs): + + options = dict() + + operators = [ + 'Read', + 'Idepix.Olci', + 'Reproject', + 'Write' + ] + + for operator in operators: + print(('Getting default values for Operator {}'.format(operator))) + parameters = get_operator_default_parameters(operator) + + options[operator] = parameters + + for key, value in list(kwargs.items()): + print(('Updating Operator {}'.format(key))) + options[key.replace('_', '-')].update(value) + + mygraph = GraphProcessor() + + for index, operator in enumerate(operators): + print(('Adding Operator {} to graph'.format(operator))) + if index == 0: + source_node_id = '' + else: + source_node_id = operators[index - 1] + + if operator == 'Idepix.Olci': + mygraph.add_node(operator, operator, idepix, source_node_id) + else: + mygraph.add_node(operator, operator, options[operator], source_node_id) + + mygraph.run() + + +def s3_rgb_composite(red, green, blue, classif_flags, geo_transform, projection_ref, output_name): + + rgb_r = np.zeros(red.shape) + rgb_g = np.zeros(red.shape) + rgb_b = np.zeros(red.shape) + + mask_cloud = get_mask('IDEPIX_CLOUD', classif_flags) + + mask = (red == -10000) | (green == -10000) | (blue == -10000) | (red > 1) | (green > 1) | (blue > 1) + + rgb_r = np.where(mask, 0, red*255).astype(np.uint8) + + rgb_g = np.where(mask, 0, green*255).astype(np.uint8) + + rgb_b = np.where(mask, 0, blue*255).astype(np.uint8) + + alpha = np.where(mask, 0, 255).astype(int) + + # contrast enhancement + ContrastEnhancement = otbApplication.Registry.CreateApplication('ContrastEnhancement') + + rgb_data = np.dstack([rgb_r, rgb_g, rgb_b]) + + ContrastEnhancement.SetVectorImageFromNumpyArray('in', rgb_data) + + ContrastEnhancement.SetParameterOutputImagePixelType('out', + otbApplication.ImagePixelType_uint8) + ContrastEnhancement.SetParameterFloat('nodata', 0.0) + ContrastEnhancement.SetParameterFloat('hfact', 3.0) + ContrastEnhancement.SetParameterInt('bins', 256) + ContrastEnhancement.SetParameterInt('spatial.local.w', 500) + ContrastEnhancement.SetParameterInt('spatial.local.h', 500) + ContrastEnhancement.SetParameterString('mode', 'lum') + + ContrastEnhancement.Execute() + + ce_data = ContrastEnhancement.GetVectorImageAsNumpyArray('out') + + rgb_r = None + rgb_g = None + rgb_b = None + + driver = gdal.GetDriverByName('GTiff') + + output = driver.Create(output_name, ce_data.shape[1], ce_data.shape[0], 4, gdal.GDT_Byte) + + output.SetGeoTransform(geo_transform) + output.SetProjection(projection_ref) + output.GetRasterBand(1).WriteArray(ce_data[:,:,0]) + output.GetRasterBand(2).WriteArray(ce_data[:,:,1]) + output.GetRasterBand(3).WriteArray(ce_data[:,:,2]) + output.GetRasterBand(4).WriteArray(alpha) + + output.FlushCache() + + return rgb_r, rgb_g, rgb_b, alpha + + +def extract_info(search_result_file): + result = {} + with open(search_result_file) as f: + search_result = json.loads(f.read()) + result['startdate'] = search_result['value'][0]['ContentDate']['Start'] + result['enddate'] = search_result['value'][0]['ContentDate']['End'] + footprint = search_result['value'][0]['Footprint'] + #footprint = "ssss" + footprint = footprint[footprint.find(';') + 1:] + result['wkt'] = footprint + + return [ result ] + + +# Get parameters + +search_result_file = sys.argv[1] +sen_folder = sys.argv[2] + +s3_file = "{0}/xfdumanifest.xml".format(sen_folder) + +input_metadata = gp.GeoDataFrame( + extract_info(search_result_file) +) + +input_metadata['geometry'] = input_metadata['wkt'].apply(loads) +input_metadata['startdate'] = pd.to_datetime(input_metadata['startdate']) +input_metadata['enddate'] = pd.to_datetime(input_metadata['enddate']) + + + + +natural_colors = { + 'id': 'natural_colors', + 'title': 'Natural colors (Oa08, Oa06, Oa_04)', + 'abstract': 'Natural colors (Oa08, Oa06, Oa_04)', + 'value': 'Yes', + 'options': 'Yes,No' +} + +gdal.UseExceptions() +GPF.getDefaultInstance().getOperatorSpiRegistry().loadOperatorSpis() + + +# Check the bands to ingest + +composites = dict() + +composites['S3 OLCI Natural Colors'] = { + 'bands': 'Oa08_reflectance,Oa06_reflectance,Oa04_reflectance', + 'create': True if (natural_colors['value'] == 'Yes') else False, + 'hfact': 2.0 +} + +s3_olci_bands = [] + +for key, value in list(composites.items()): + if value['create']: + for band in value['bands'].split(','): + s3_olci_bands.append(band) + +s3_olci_bands = list(set(s3_olci_bands)) + + +# Import Sentinel-3 OLCI product + +operators = [ + 'Read', + 'Idepix.Olci', + 'Reproject', + 'Write' +] + +read = dict() +read['file'] = s3_file + +idepix = get_operator_default_parameters('Idepix.Olci') +idepix['reflBandsToCopy'] = ','.join(s3_olci_bands) + +reproject = dict() +reproject['crs'] = 'EPSG:4326' + +write = dict() +write['file'] = 's3_olci' + +s3_olci_import(idepix, + Read=read, + Reproject=reproject, + Write=write) + +# RGB Composites + +date_format = '%Y%m%dT%H%m%S' + +output_startdate = input_metadata.iloc[0]['startdate'] +output_stopdate = input_metadata.iloc[0]['enddate'] + + +for k, v in list(composites.items()): + + print(("k = {0}".format(k))) + + bands = [os.path.join(write['file'] + '.data', '{}.img'.format(band)) for band in (composites[k]['bands'].split(',') + ['pixel_classif_flags'])] + + print(("BANDS = {0}".format(bands))) + + ds = gdal.Open(bands[0]) + + geo_transform = ds.GetGeoTransform() + projection_ref = ds.GetProjectionRef() + + ds = None + + s3_rgb_data = read_s3(bands) + + red = s3_rgb_data[:,:,0] + green = s3_rgb_data[:,:,1] + blue = s3_rgb_data[:,:,2] + classif_flags = s3_rgb_data[:,:,3] + + date_format = '%Y%m%dT%H%m%S' + + output_name = '-'.join( + [ + k.replace(' ', '-').upper(), + output_startdate.strftime(date_format), + output_startdate.strftime(date_format) + ] + ) + + s3_rgb_composite( + red, + green, + blue, + classif_flags, + geo_transform, + projection_ref, + output_name + '.tif' + ) + + date_format = '%Y-%m-%dT%H:%m:%S' + + with open(output_name + '.tif.properties', 'wb') as file: + file.write('title={} ({}/{})\n'.format(k, output_startdate.strftime(date_format), output_stopdate.strftime(date_format))) + file.write('date={}Z/{}Z\n'.format(output_startdate.strftime(date_format), output_stopdate.strftime(date_format))) + file.write('geometry={}'.format(input_metadata.iloc[0].wkt)) + + # PNG + gdal.Translate('{}.png'.format(output_name), '{}.tif'.format(output_name), format='PNG') + + os.remove('{}.png.aux.xml'.format(output_name)) + + with open(output_name + '.png.properties', 'wb') as file: + file.write('title={} - Quicklook ({}/{})\n'.format(k, output_startdate.strftime(date_format), output_stopdate.strftime(date_format))) + file.write('date={}Z/{}Z\n'.format(output_startdate.strftime(date_format), output_stopdate.strftime(date_format))) + file.write('geometry={}'.format(input_metadata.iloc[0].wkt)) + + +# Clean-up + +shutil.rmtree('{}.data'.format(write['file'])) + +os.remove('{}.dim'.format(write['file'])) \ No newline at end of file