Commit 17a4b83a authored by Aurore Dupuis's avatar Aurore Dupuis
Browse files

Merge branch 'cosims_implementation' into 'develop'

Cosims implementation

See merge request !3
parents 453772d6 a0d674bd
......@@ -12,13 +12,13 @@ import zipfile
### Configuration Template ###
conf_template = {"general":{"pout":"",
"nodata":-10000,
"ram":1024,
"ram":2048,
"nb_threads":1,
"preprocessing":False,
"log":True,
"multi":1,
"multi":10,
"target_resolution":-1},
"vector":{"generate_vector":True,
"vector":{"generate_vector":False,
"generate_intermediate_vectors":False,
"use_gdal_trace_outline":True,
"gdal_trace_outline_dp_toler":0,
......@@ -39,10 +39,10 @@ conf_template = {"general":{"pout":"",
"fsnow_lim":0.1,
"fclear_lim":0.1,
"fsnow_total_lim":0.001},
"cloud":{"shadow_in_mask":64,
"shadow_out_mask":128,
"cloud":{"shadow_in_mask":32,
"shadow_out_mask":64,
"all_cloud_mask":1,
"high_cloud_mask":32,
"high_cloud_mask":128,
"rf":12,
"red_darkcloud":300,
"red_backtocloud":100,
......@@ -50,7 +50,20 @@ conf_template = {"general":{"pout":"",
"rm_snow_inside_cloud":False,
"rm_snow_inside_cloud_dilation_radius":1,
"rm_snow_inside_cloud_threshold":0.85,
"rm_snow_inside_cloud_min_area":5000}}
"rm_snow_inside_cloud_min_area":5000},
"fsc": {
"dofsc": False,
"fscToc_Eq": "1.45*ndsi-0.01",
"fscOg_Eq": "fscToc/(1-tcd)",
"tcd": "",
"cosims_mode": False
},
"water_mask": {
"apply": False,
"path": None,
"raster_values": [1]
}
}
### Mission Specific Parameters ###
......@@ -295,6 +308,16 @@ def main():
group_cloud.add_argument("-red_darkcloud", type=int)
group_cloud.add_argument("-red_backtocloud", type=int)
group_cloud.add_argument("-strict_cloud_mask", type=str2bool, help="true/false")
group_fsc = parser.add_argument_group('fsc', 'fractional snow cover parameters')
group_fsc.add_argument("-fsc", type=str, help="path to tree cover density file, automatically activates sets fsc: dofsc to true")
group_fsc.add_argument("-cosims_mode", action='store_true', help="CoSIMS mode : Generate CoSIMS formatted outputs.")
group_water_mask = parser.add_argument_group('water_mask', 'water mask parameters')
group_water_mask.add_argument("-water_mask_path", type=str, help="Path to a raster or a shapefile")
group_water_mask.add_argument("-water_mask_raster_value", type=int, action='append', help="If the input water_mask_path is a raster, you can specify all the values corresponding " + \
"to water which are to be masked by repeating this optional argument -water_mask_raster_value value1 -water_mask_raster_value value2 etc... " + \
"If no values are specified, 1 will be used by default.")
args = parser.parse_args()
......@@ -405,6 +428,26 @@ def main():
if not jsonData["inputs"].get("dem"):
logging.error("No DEM found!")
return 1
if args.fsc:
jsonData["fsc"]["dofsc"] = True
jsonData["fsc"]["tcd"] = os.path.abspath(args.fsc)
jsonData["fsc"]["cosims_mode"] = args.cosims_mode
else:
jsonData["fsc"]["dofsc"] = False
if args.water_mask_path is not None:
jsonData["water_mask"]["apply"] = True
suffix = args.water_mask_path.split('.')[-1].lower()
if suffix not in ['shp', 'tif']:
raise IOError('Input water_mask_path must either be a GeoTIFF raster (.tif) or a shapefile (.shp)')
jsonData["water_mask"]["water_mask_path"] = os.path.abspath(args.water_mask_path)
if args.water_mask_raster_value is None:
jsonData["water_mask"]["water_mask_raster_values"] = [1]
else:
jsonData["water_mask"]["water_mask_raster_values"] = args.water_mask_raster_value
else:
jsonData["water_mask"]["apply"] = False
jsonFile = open(os.path.join(outputPath, "param_test.json"), "w")
jsonFile.write(json.dumps(jsonData, indent=4))
......
......@@ -10,12 +10,12 @@ VERSION="0.1"
def show_help():
"""Show help of the run_cloud_removal script"""
print "Usage: python run_cloud_removal.py param.json"
print "python run_cloud_removal.py version to show version"
print "python run_cloud_removal.py help to show help"
print("Usage: python run_cloud_removal.py param.json")
print("python run_cloud_removal.py version to show version")
print("python run_cloud_removal.py help to show help")
def show_version():
print VERSION
print(VERSION)
#----------------- MAIN ---------------------------------------------------
......
......@@ -12,15 +12,15 @@ VERSION = "0.1.0"
def show_help():
"""Show help of the run_snow_annual_map script"""
print "This script is used to run the snow annual map " \
+ "module that compute snow coverage onto a given date range"
print "Usage: python run_snow_annual_map.py param.json"
print "python run_snow_annual_map.py version to show version"
print "python run_snow_annual_map.py help to show help"
print("This script is used to run the snow annual map " \
+ "module that compute snow coverage onto a given date range")
print("Usage: python run_snow_annual_map.py param.json")
print("python run_snow_annual_map.py version to show version")
print("python run_snow_annual_map.py help to show help")
def show_version():
print VERSION
print(VERSION)
# ----------------- MAIN ---------------------------------------------------
......
......@@ -11,15 +11,15 @@ from s2snow.version import VERSION
def show_help():
"""Show help of the run_snow_detector script"""
print "This script is used to run the snow detector module that compute snow mask" \
+ " using OTB applications on Spot/LandSat/Sentinel-2 products from theia platform"
print "Usage: python run_snow_detector.py param.json"
print "python run_snow_detector.py version to show version"
print "python run_snow_detector.py help to show help"
print("This script is used to run the snow detector module that compute snow mask" \
+ " using OTB applications on Spot/LandSat/Sentinel-2 products from theia platform")
print("Usage: python run_snow_detector.py param.json")
print("python run_snow_detector.py version to show version")
print("python run_snow_detector.py help to show help")
def show_version():
print VERSION
print(VERSION)
# ----------------- MAIN ---------------------------------------------------
......
......@@ -12,12 +12,12 @@ import itertools,operator,sys,os
# Example: /work/OT/siaa/Theia/Neige/SNOW_ANNUAL_MAP_LIS_1.5/S2_with_L8_Densification//T31TCH_20160901_20170831/DAILY_SNOW_MASKS_T31TCH_20160901_20170831.tif
f=sys.argv[1]
src=rasterio.open(f, 'r')
print "Start compute_SOD_SMOD.py using: ",f
print("Start compute_SOD_SMOD.py using: ",f)
# memory heavy, load all raster bands in memory
# runs in 23 min in HAl with 100 Gb RAM: qsub -I -l select=1:ncpus=4:mem=100000mb -l walltime=05:00:00
# 20 Gb should be fine: qsub -I -l walltime=00:50:00 -l select=1:ncpus=1:mem=20000mb
W = src.read(range(1,365))
W = src.read(list(range(1,365)))
n=np.shape(W)[1]
m=np.shape(W)[2]
......@@ -45,5 +45,5 @@ with rasterio.Env():
with rasterio.open("{}/SOD_{}".format(os.path.split(f)[0],os.path.split(f)[1]), 'w', **profile) as dst:
dst.write(SOD.astype(rasterio.uint16), 1)
print "End of compute_SOD_SMOD.py"
print("End of compute_SOD_SMOD.py")
This diff is collapsed.
This diff is collapsed.
......@@ -40,7 +40,7 @@ def band_math(il, out, exp, ram=None, out_type=None):
bandMathApp = otb.Registry.CreateApplication("BandMath")
bandMathApp.SetParameterString("exp", exp)
for image in il:
if isinstance(image, basestring):
if isinstance(image, str):
bandMathApp.AddParameterStringList("il", image)
else:
bandMathApp.AddImageToParameterInputImageList("il", image)
......@@ -155,7 +155,7 @@ def band_mathX(il, out, exp, ram=None, out_type=None):
bandMathApp = otb.Registry.CreateApplication("BandMathX")
bandMathApp.SetParameterString("exp", exp)
for image in il:
if isinstance(image, basestring):
if isinstance(image, str):
bandMathApp.AddParameterStringList("il", image)
else:
bandMathApp.AddImageToParameterInputImageList("il", image)
......@@ -199,10 +199,17 @@ def compute_snow_line(img_dem, img_snow, img_cloud, dz, fsnowlim, fclearlim, \
snowLineApp.SetParameterFloat("fsnowlim", fsnowlim)
snowLineApp.SetParameterFloat("fclearlim", fclearlim)
snowLineApp.SetParameterInt("offset", offset)
if not isinstance(centeroffset, int):
if round(centeroffset,0) != centeroffset:
raise IOError("centeroffset shoud be an integer, got %s instead with value %s => error"%(type(centeroffset), centeroffset))
else:
print("WARNING: centeroffset shoud be an integer, got %s instead with value %s => converting to int"%(type(centeroffset), centeroffset))
centeroffset = int(centeroffset)
snowLineApp.SetParameterInt("centeroffset", centeroffset)
if reverse:
snowLineApp.SetParameterString("reverse", "true")
snowLineApp.SetParameterInt("reverse", 1)
else:
snowLineApp.SetParameterInt("reverse", 0)
if ram is not None:
logging.info("ram = " + str(ram))
......@@ -304,8 +311,10 @@ def compute_contour(img_in, img_out, foreground_value, fullyconnected, \
logging.info("out = " + img_out)
cloudMaskApp.SetParameterString("out", img_out)
if fullyconnected:
cloudMaskApp.SetParameterString("fullyconnected", "true")
cloudMaskApp.SetParameterInt("fullyconnected", 1)
cloudMaskApp.SetParameterString("inputmask", img_in)
else:
cloudMaskApp.SetParameterInt("fullyconnected", 0)
if ram is not None:
logging.info("ram = " + str(ram))
cloudMaskApp.SetParameterString("ram", str(ram))
......
......@@ -13,9 +13,9 @@ from subprocess import call
def show_help():
print "This script is used to create clouds on data"
print "Usage: cloud_builder.py mode plaincloudthreshold randomcloudthreshold inputpath outputplaincloudpath ouputrandomcloudpath"
print "Mode : 0 %plain cloud image, 1 %random cloud image, 2 both"
print("This script is used to create clouds on data")
print("Usage: cloud_builder.py mode plaincloudthreshold randomcloudthreshold inputpath outputplaincloudpath ouputrandomcloudpath")
print("Mode : 0 %plain cloud image, 1 %random cloud image, 2 both")
def main(argv):
......
......@@ -15,8 +15,8 @@ import gdalconst
def show_help():
print "This script is used to remove clouds from snow data"
print "Usage: cloud_removal.py config.json"
print("This script is used to remove clouds from snow data")
print("Usage: cloud_removal.py config.json")
def get_raster_as_array(raster_file_name):
......@@ -124,7 +124,7 @@ def step1(m2_path, m1_path, t0_path, p1_path, p2_path, output_path, ram):
def step2(t0_path, dem_path, output_path, ram):
percentage_cloud = compute_cloudpercent(t0_path)
print "cloud percent : " + str(percentage_cloud)
print("cloud percent : " + str(percentage_cloud))
# Perform step 2 only if cloud coverage is less than a threshold value
# (hard coded for now to 30%)
......@@ -133,7 +133,7 @@ def step2(t0_path, dem_path, output_path, ram):
if cloudpercent_condition:
# S(y,x,t) = 1 if (H(x,y) < Hsmin(t))
hs_min = compute_HSmin(t0_path, dem_path)
print "hs_min: " + str(hs_min)
print("hs_min: " + str(hs_min))
call(["otbcli_BandMath",
"-ram",
str(ram),
......@@ -145,7 +145,7 @@ def step2(t0_path, dem_path, output_path, ram):
"-exp",
"im1b1==205?(im2b1<" + str(hs_min) + "?0:im1b1):im1b1"])
hs_max = compute_HSmax(t0_path, dem_path)
print "hs_max: " + str(hs_max)
print("hs_max: " + str(hs_max))
# S(y,x,t) = 1 if (H(x,y) > Hsmax(t))
call(["otbcli_BandMath",
"-ram",
......@@ -164,7 +164,7 @@ def step2(t0_path, dem_path, output_path, ram):
def step3(t0_path, output_path):
# four-pixels neighboring
print "Starting step 3"
print("Starting step 3")
array, dataset = get_raster_as_array(t0_path)
# compute 4 pixel snow neighboring
......@@ -172,7 +172,7 @@ def step3(t0_path, output_path):
set_array_as_raster(array, dataset, output_path)
# create file
print "End of step 3"
print("End of step 3")
def step3_internal(array):
......@@ -194,7 +194,7 @@ def step3_internal(array):
def step4(t0_path, dem_path, output_path):
# S(y,x,t) = 1 if (S(y+k,x+k,t)(kc(-1,1)) = 1 and H(y+k,x+k)(kc(-1,1)) <
# H(y,x))
print "Starting step 4"
print("Starting step 4")
array, dataset = get_raster_as_array(t0_path)
array_dem, dataset_dem = get_raster_as_array(dem_path)
......@@ -203,7 +203,7 @@ def step4(t0_path, dem_path, output_path):
# create file
set_array_as_raster(array, dataset, output_path)
print "End of step 4"
print("End of step 4")
def step4_internal(array, array_dem):
......@@ -333,7 +333,7 @@ def format_percent(array, total_cloud):
def plot_stats(array):
steps = range(0, array.shape[0])
steps = list(range(0, array.shape[0]))
TCE = array[:, 0]
TRUE = array[:, 1]
FALSE = array[:, 2]
......@@ -355,7 +355,7 @@ def run(data):
try:
nb_defaultThreads = multiprocessing.cpu_count()
except NotImplementedError:
print "Cannot get max number of CPU on the system. nbDefaultThreads set to 1."
print("Cannot get max number of CPU on the system. nbDefaultThreads set to 1.")
nb_defaultThreads = 1
nb_threads = general.get("nb_threads", nb_defaultThreads)
......@@ -450,10 +450,10 @@ def run(data):
stats_array_percent = np.vstack([stats_array_percent, np.sum(
stats_array_percent, axis=0)]) # add total to array
print stats_array
print(stats_array)
np.set_printoptions(precision=3)
np.set_printoptions(suppress=True)
print stats_array_percent
print(stats_array_percent)
# plot_stats(stats_array)
......
......@@ -9,8 +9,8 @@ import ast
from osgeo import gdal, gdalconst, osr
def show_help():
print "This script is used to compute srtm mask from a vrt file to a region extent"
print "Usage: preprocessing.py srtm.vrt img.tif output.tif"
print("This script is used to compute srtm mask from a vrt file to a region extent")
print("Usage: preprocessing.py srtm.vrt img.tif output.tif")
def get_extent(geotransform, cols, rows):
......@@ -94,9 +94,9 @@ def build_dem(psrtm, pimg, pout, ram, nbThreads):
)
except subprocess.CalledProcessError as e:
print e.output
print 'Error running command: ' + str(e.cmd) + ' see above shell error'
print 'Return code: ' + str(e.returncode)
print(e.output)
print('Error running command: ' + str(e.cmd) + ' see above shell error')
print('Return code: ' + str(e.returncode))
return e.returncode
def main(argv):
......
......@@ -22,15 +22,15 @@ def main(argv):
# Find potential
if snow_percent > minsnowthreshold and cloud_percent > mincloudthreshold and snow_percent < maxsnowthreshold and cloud_percent < maxcloudthreshold :
print root
print "snow percent: " + str(snow_percent)
print "cloud percent: " + str(cloud_percent)
print(root)
print(("snow percent: " + str(snow_percent)))
print(("cloud percent: " + str(cloud_percent)))
total_images += 1
print "total images :" + str(total_images)
print(("total images :" + str(total_images)))
if __name__ == "__main__":
if len(sys.argv) != 5:
print "Missing arguments"
print("Missing arguments")
else:
main(sys.argv)
......@@ -113,7 +113,7 @@ def merge_masks_at_same_date(snow_product_list, merged_snow_product, threshold=1
# the order of the images in the input list is important:
# we expect to have first the main input products
# and then the densification products
img_index = range(1, len(snow_product_list)+1)
img_index = list(range(1, len(snow_product_list)+1))
expression_merging = "".join(["(im" + str(i) + "b1<=" + str(threshold) + "?im" + str(i) + "b1:" for i in img_index])
expression_merging += "im"+str(img_index[-1])+"b1"
expression_merging += "".join([")" for i in img_index])
......@@ -168,7 +168,7 @@ class snow_annual_map():
self.label_no_snow = "0"
self.label_snow = "100"
self.label_cloud = "205"
self.label_no_data = "254"
self.label_no_data = "255"
# Build useful paths
self.input_dates_filename = op.join(self.path_tmp, "input_dates.txt")
......@@ -209,7 +209,7 @@ class snow_annual_map():
if densification_product_dict:
# Reproject the densification products on S2 tile before going further
for densifier_product_key in densification_product_dict.keys():
for densifier_product_key in list(densification_product_dict.keys()):
for densifier_product in densification_product_dict[densifier_product_key]:
original_mask = densifier_product.get_snow_mask()
reprojected_mask = op.join(self.path_tmp,
......@@ -228,7 +228,7 @@ class snow_annual_map():
logging.debug(densifier_product.snow_mask)
# Add the products to extend the self.product_dict
if densifier_product_key in self.product_dict.keys():
if densifier_product_key in list(self.product_dict.keys()):
self.product_dict[densifier_product_key].extend(densification_product_dict[densifier_product_key])
else:
self.product_dict[densifier_product_key] = densification_product_dict[densifier_product_key]
......@@ -255,7 +255,7 @@ class snow_annual_map():
# merge products at the same date
self.resulting_snow_mask_dict={}
for key in self.product_dict.keys():
for key in list(self.product_dict.keys()):
if len(self.product_dict[key]) > 1:
merged_mask = op.join(self.path_tmp, key + "_merged_snow_product.tif")
merge_masks_at_same_date(self.product_dict[key],
......@@ -286,7 +286,7 @@ class snow_annual_map():
separate=True)
# generate the summary map
band_index = range(1, len(self.binary_cloudmask_list)+1)
band_index = list(range(1, len(self.binary_cloudmask_list)+1))
expression = "+".join(["im1b" + str(i) for i in band_index])
bandMathApp = band_math([self.multitemp_cloud_vrt],
......@@ -327,7 +327,7 @@ class snow_annual_map():
app_gap_filling = None
# generate the annual map
band_index = range(1, len(output_dates)+1)
band_index = list(range(1, len(output_dates)+1))
expression = "+".join(["im1b" + str(i) for i in band_index])
bandMathApp = band_math([img_in],
......@@ -368,7 +368,7 @@ class snow_annual_map():
if (product_type is not None) and (product_type not in product.platform):
test_result = False
if test_result:
if current_day not in product_dict.keys():
if current_day not in list(product_dict.keys()):
product_dict[current_day] = [product]
else:
product_dict[current_day].append(product)
......
......@@ -98,18 +98,18 @@ def get_raster_intersection(raster1, raster2):
Return the instersection polygon and the associated projection
"""
poly1, srs1 = get_raster_extent_as_poly(raster1)
print "poly1", poly1
print("poly1", poly1)
poly2, srs2 = get_raster_extent_as_poly(raster2)
print "poly2", poly2
print("poly2", poly2)
# convert poly2 into poly1 ProjectionRef
transform = osr.CoordinateTransformation(srs2, srs1)
poly2.Transform(transform)
print "poly2 transformed", poly2
print("poly2 transformed", poly2)
intersection = poly2.Intersection(poly1)
print "intersection", intersection
print("intersection", intersection)
#return also the srs in which is expressed the intersection
return intersection, srs1
......@@ -159,7 +159,7 @@ class snow_annual_map_evaluation(snow_annual_map):
# load required product
self.resulting_snow_mask_dict={}
for key in self.product_dict.keys():
for key in list(self.product_dict.keys()):
comparison_tag = key + "_comparison"
if len(self.product_dict[key]) > 1:
merged_mask = op.join(self.path_tmp, comparison_tag + "_merged_snow_product.tif")
......@@ -182,7 +182,7 @@ class snow_annual_map_evaluation(snow_annual_map):
for comparison_index, comparison_date in enumerate(comparison_input_dates):
if ts_date in comparison_date:
pair_dict[comparison_date] = (ts_index, comparison_index)
print pair_dict
print(pair_dict)
# project the snow masks onto the same foot print
self.binary_snowmask_list_reprojected = []
......@@ -202,7 +202,7 @@ class snow_annual_map_evaluation(snow_annual_map):
# compare the two snow masks
comparision_list = []
for comparison_date in pair_dict.keys():
for comparison_date in list(pair_dict.keys()):
s2_index, comparison_index = pair_dict[comparison_date]
path_extracted = op.join(self.path_tmp, "gapfilled_s2_" + comparison_date + ".tif")
......@@ -279,7 +279,7 @@ class snow_annual_map_evaluation(snow_annual_map):
modis_stop_index = i
# generate the summary map
band_index = range(modis_start_index+1, modis_stop_index+2)
band_index = list(range(modis_start_index+1, modis_stop_index+2))
expression = "+".join(["(im1b" + str(i) + "==200?1:0)" for i in band_index])
if not op.exists(self.modis_annual_snow_map):
......
......@@ -36,7 +36,7 @@ from s2snow.app_wrappers import compute_snow_mask, compute_cloud_mask
from s2snow.app_wrappers import band_math, compute_snow_line
# Import utilities for snow detection
from s2snow.utils import polygonize, extract_band, burn_polygons_edges, composition_RGB
from s2snow.utils import polygonize, extract_band, burn_polygons_edges, composition_RGB, edit_raster_from_shapefile, edit_raster_from_raster, edit_nodata_value
from s2snow.utils import compute_percent, format_SEB_VEC_values, get_raster_as_array
# this allows GDAL to throw Python Exceptions
......@@ -80,9 +80,11 @@ class snow_detector:
self.tcd_path = str(data["fsc"]['tcd'])
self.fscOg_Eq = data["fsc"]['fscOg_Eq']
self.fscToc_Eq = data["fsc"]['fscToc_Eq']
self.cosims_mode = data["fsc"]['cosims_mode']
else:
self.dofsc = False
# Parse cloud data
cloud = data["cloud"]
self.rf = cloud.get("rf")
......@@ -133,6 +135,7 @@ class snow_detector:
gb_path_extracted = extract_band(inputs, "green_band", self.path_tmp, self.nodata)
rb_path_extracted = extract_band(inputs, "red_band", self.path_tmp, self.nodata)
sb_path_extracted = extract_band(inputs, "swir_band", self.path_tmp, self.nodata)
# Keep the input product directory basename as product_id
self.product_id = op.basename(op.dirname(inputs["green_band"]["path"]))
......@@ -196,6 +199,23 @@ class snow_detector:
yRes=self.target_resolution)
else:
sb_path_resampled = sb_path_extracted
#apply water mask as NAN values to extracted bands so that they are not used
if 'water_mask' in data:
if data['water_mask']['apply']:
water_mask_path = data['water_mask']['water_mask_path']
water_mask_type = water_mask_path.split('.')[-1].lower()
if water_mask_type == 'tif':
self.water_mask_raster_values = data['water_mask']['water_mask_raster_values']
edit_raster_from_raster(rb_path_resampled, water_mask_path, src_values=data['water_mask']['water_mask_raster_values'], applied_value=self.nodata)
edit_raster_from_raster(gb_path_resampled, water_mask_path, src_values=data['water_mask']['water_mask_raster_values'], applied_value=self.nodata)
edit_raster_from_raster(sb_path_resampled, water_mask_path, src_values=data['water_mask']['water_mask_raster_values'], applied_value=self.nodata)
elif water_mask_type == 'shp':
edit_raster_from_shapefile(rb_path_resampled, water_mask_path, applied_value=self.nodata)
edit_raster_from_shapefile(gb_path_resampled, water_mask_path, applied_value=self.nodata)
edit_raster_from_shapefile(sb_path_resampled, water_mask_path, applied_value=self.nodata)
else:
raise IOError('Input water_mask_path must either be a GeoTIFF raster (.tif) or a shapefile (.shp)')
# build vrt
logging.info("building bands vrt")
......@@ -232,7 +252,7 @@ class snow_detector:
self.label_no_snow = "0"
self.label_snow = "100"
self.label_cloud = "205"
self.label_no_data = "254"
self.label_no_data = "255"
# Build useful paths
self.pass1_path = op.join(self.path_tmp, "pass1.tif")
......@@ -294,42 +314,46 @@ class snow_detector:
if self.dofsc:
self.passfsc()
# RGB composition
composition_RGB(
self.img,
self.composition_path,
self.nSWIR,
self.nRed,
self.nGreen,
self.multi)
# Gdal polygonize (needed to produce composition)
# TODO: Study possible loss and issue with vectorization product
if self.generate_vector:
polygonize(
self.final_mask_path,
if self.cosims_mode:
self.create_cosims_metadata()
else:
# RGB com