From 5414a3456c463b8df826ea55543c24c373857b58 Mon Sep 17 00:00:00 2001 From: ptresson <paul.tresson@ird.fr> Date: Thu, 26 Sep 2024 14:40:05 +0200 Subject: [PATCH] get unique filenames and layer names for all algorithms --- clustering.py | 32 +++++++++++++++++++------------- iamap.py | 19 ++++++++++++++----- random_forest.py | 35 ++++++++++++++++++++++------------- reduction.py | 30 +++++++++++++++++++----------- similarity.py | 34 +++++++++++++++++++--------------- 5 files changed, 93 insertions(+), 57 deletions(-) diff --git a/clustering.py b/clustering.py index 27706ac..2f3f776 100644 --- a/clustering.py +++ b/clustering.py @@ -3,6 +3,8 @@ import numpy as np from pathlib import Path from typing import Dict, Any import joblib +import tempfile +import json import rasterio from rasterio import windows @@ -26,8 +28,7 @@ from qgis.core import (Qgis, from sklearn.cluster import KMeans -import json - +from .utils.misc import get_unique_filename class ClusterAlgorithm(QgsProcessingAlgorithm): @@ -53,6 +54,7 @@ class ClusterAlgorithm(QgsProcessingAlgorithm): with some other properties. """ cwd = Path(__file__).parent.absolute() + tmp_wd = os.path.join(tempfile.gettempdir(), "iamap_clustering") self.addParameter( QgsProcessingParameterRasterLayer( @@ -145,7 +147,8 @@ class ClusterAlgorithm(QgsProcessingAlgorithm): self.OUTPUT, self.tr( "Output directory (choose the location that the image features will be saved)"), - defaultValue=os.path.join(cwd,'models'), + # defaultValue=os.path.join(cwd,'models'), + defaultValue=tmp_wd, ) ) @@ -221,15 +224,16 @@ class ClusterAlgorithm(QgsProcessingAlgorithm): params_file = os.path.join(self.output_dir, 'cluster_parameters.json') - if os.path.exists(dst_path): - i = 1 - while True: - modified_output_file = os.path.join(self.output_dir, f"cluster_{i}.tif") - if not os.path.exists(modified_output_file): - dst_path = modified_output_file - break - i += 1 + # if os.path.exists(dst_path): + # i = 1 + # while True: + # modified_output_file = os.path.join(self.output_dir, f"cluster_{i}.tif") + # if not os.path.exists(modified_output_file): + # dst_path = modified_output_file + # break + # i += 1 + dst_path, layer_name = get_unique_filename(self.output_dir, 'cluster.tif', 'clustered features') if os.path.exists(params_file): i = 1 while True: @@ -251,7 +255,7 @@ class ClusterAlgorithm(QgsProcessingAlgorithm): parameters['OUTPUT_RASTER']=dst_path - return {'OUTPUT_RASTER':dst_path} + return {'OUTPUT_RASTER':dst_path, 'OUTPUT_LAYER_NAME':layer_name} def process_options(self,parameters, context, feedback): self.iPatch = 0 @@ -299,10 +303,12 @@ class ClusterAlgorithm(QgsProcessingAlgorithm): parameters, self.CRS, context) extent = self.parameterAsExtent( parameters, self.EXTENT, context) - self.output_dir = self.parameterAsString( + output_dir = self.parameterAsString( parameters, self.OUTPUT, context) self.save_model = self.parameterAsBoolean( parameters, self.SAVE_MODEL, context) + self.output_dir = Path(output_dir) + self.output_dir.mkdir(parents=True, exist_ok=True) rlayer_data_provider = rlayer.dataProvider() diff --git a/iamap.py b/iamap.py index f66f95b..fbd320c 100644 --- a/iamap.py +++ b/iamap.py @@ -9,7 +9,12 @@ from PyQt5.QtCore import pyqtSignal, QObject from qgis.core import QgsApplication from qgis.gui import QgisInterface from .provider import IAMapProvider -from .icons import QIcon_EncoderTool, QIcon_ReductionTool, QIcon_ClusterTool, QIcon_SimilarityTool, QIcon_RandomforestTool +from .icons import (QIcon_EncoderTool, + QIcon_ReductionTool, + QIcon_ClusterTool, + QIcon_SimilarityTool, + QIcon_RandomforestTool, + ) class IAMap(QObject): @@ -135,9 +140,10 @@ class IAMap(QObject): # Retrieve output parameters from the result dictionary if 'OUTPUT_RASTER' in result: output_raster_path = result['OUTPUT_RASTER'] + output_layer_name = result['OUTPUT_LAYER_NAME'] # Add the output raster layer to the map canvas - self.iface.addRasterLayer(str(output_raster_path), 'reduced features') + self.iface.addRasterLayer(str(output_raster_path), output_layer_name) else: # Handle missing or unexpected output print('Output raster not found in algorithm result.') @@ -157,9 +163,10 @@ class IAMap(QObject): # Retrieve output parameters from the result dictionary if 'OUTPUT_RASTER' in result: output_raster_path = result['OUTPUT_RASTER'] + output_layer_name = result['OUTPUT_LAYER_NAME'] # Add the output raster layer to the map canvas - self.iface.addRasterLayer(str(output_raster_path), 'clustering') + self.iface.addRasterLayer(str(output_raster_path), output_layer_name) else: # Handle missing or unexpected output print('Output raster not found in algorithm result.') @@ -179,9 +186,10 @@ class IAMap(QObject): # Retrieve output parameters from the result dictionary if 'OUTPUT_RASTER' in result: output_raster_path = result['OUTPUT_RASTER'] + output_layer_name = result['OUTPUT_LAYER_NAME'] # Add the output raster layer to the map canvas - self.iface.addRasterLayer(str(output_raster_path), 'similarity map') + self.iface.addRasterLayer(str(output_raster_path), output_layer_name) else: # Handle missing or unexpected output print('Output raster not found in algorithm result.') @@ -200,9 +208,10 @@ class IAMap(QObject): # Retrieve output parameters from the result dictionary if 'OUTPUT_RASTER' in result: output_raster_path = result['OUTPUT_RASTER'] + output_layer_name = result['OUTPUT_LAYER_NAME'] # Add the output raster layer to the map canvas - self.iface.addRasterLayer(str(output_raster_path), 'random forest map') + self.iface.addRasterLayer(str(output_raster_path), output_layer_name) else: # Handle missing or unexpected output print('Output raster not found in algorithm result.') diff --git a/random_forest.py b/random_forest.py index 690b3ed..fa5e1a2 100644 --- a/random_forest.py +++ b/random_forest.py @@ -3,6 +3,8 @@ import numpy as np from pathlib import Path from typing import Dict, Any import joblib +import json +import tempfile import rasterio from rasterio import windows @@ -34,7 +36,8 @@ from sklearn.metrics import accuracy_score from sklearn.preprocessing import LabelEncoder from sklearn.model_selection import train_test_split -import json +from .utils.misc import get_unique_filename + class RFAlgorithm(QgsProcessingAlgorithm): """ @@ -57,6 +60,7 @@ class RFAlgorithm(QgsProcessingAlgorithm): with some other properties. """ cwd = Path(__file__).parent.absolute() + tmp_wd = os.path.join(tempfile.gettempdir(), "iamap_rf") self.addParameter( QgsProcessingParameterRasterLayer( @@ -109,7 +113,8 @@ class RFAlgorithm(QgsProcessingAlgorithm): name=self.TEMPLATE, description=self.tr( 'Input shapefile path for training data set for random forest (if no test data_set, will be devised in train and test)'), - defaultValue=os.path.join(cwd,'assets','rf.gpkg'), + # defaultValue=os.path.join(cwd,'assets','rf.gpkg'), + defaultValue=os.path.join(cwd,'assets','rf.shp'), ), ) @@ -128,7 +133,7 @@ class RFAlgorithm(QgsProcessingAlgorithm): self.OUTPUT, self.tr( "Output directory (choose the location that the image features will be saved)"), - defaultValue=os.path.join(cwd,'models'), + defaultValue=tmp_wd, ) ) @@ -324,14 +329,15 @@ class RFAlgorithm(QgsProcessingAlgorithm): - if os.path.exists(dst_path): - i = 1 - while True: - modified_output_file = os.path.join(self.output_dir, f"random_forest_{i}.tif") - if not os.path.exists(modified_output_file): - dst_path = modified_output_file - break - i += 1 + dst_path, layer_name = get_unique_filename(self.output_dir, 'random_forest.tif', 'random forest') + # if os.path.exists(dst_path): + # i = 1 + # while True: + # modified_output_file = os.path.join(self.output_dir, f"random_forest_{i}.tif") + # if not os.path.exists(modified_output_file): + # dst_path = modified_output_file + # break + # i += 1 if os.path.exists(params_file): i = 1 @@ -353,7 +359,7 @@ class RFAlgorithm(QgsProcessingAlgorithm): parameters['OUTPUT_RASTER']=dst_path - return {'OUTPUT_RASTER':dst_path} + return {'OUTPUT_RASTER':dst_path, 'OUTPUT_LAYER_NAME':layer_name} def process_options(self,parameters, context, feedback): self.iPatch = 0 @@ -402,8 +408,11 @@ class RFAlgorithm(QgsProcessingAlgorithm): parameters, self.CRS, context) extent = self.parameterAsExtent( parameters, self.EXTENT, context) - self.output_dir = self.parameterAsString( + output_dir = self.parameterAsString( parameters, self.OUTPUT, context) + self.output_dir = Path(output_dir) + self.output_dir.mkdir(parents=True, exist_ok=True) + rlayer_data_provider = rlayer.dataProvider() diff --git a/reduction.py b/reduction.py index 35e0b28..d9339c5 100644 --- a/reduction.py +++ b/reduction.py @@ -1,4 +1,5 @@ import os +import tempfile import numpy as np from pathlib import Path from typing import Dict, Any @@ -31,6 +32,8 @@ from qgis.core import (Qgis, from sklearn.preprocessing import StandardScaler from sklearn.decomposition import PCA, IncrementalPCA from sklearn.cluster import KMeans + +from .utils.misc import get_unique_filename #from umap.umap_ import UMAP @@ -76,6 +79,7 @@ class ReductionAlgorithm(QgsProcessingAlgorithm): with some other properties. """ cwd = Path(__file__).parent.absolute() + tmp_wd = os.path.join(tempfile.gettempdir(), "iamap_reduction") self.addParameter( QgsProcessingParameterRasterLayer( @@ -181,7 +185,8 @@ class ReductionAlgorithm(QgsProcessingAlgorithm): self.OUTPUT, self.tr( "Output directory (choose the location that the image features will be saved)"), - defaultValue=os.path.join(cwd,'models'), + # defaultValue=os.path.join(cwd,'models'), + defaultValue=tmp_wd, ) ) @@ -320,14 +325,15 @@ class ReductionAlgorithm(QgsProcessingAlgorithm): feedback.pushInfo(f'Export to geotif\n') - if os.path.exists(dst_path): - i = 1 - while True: - modified_output_file = os.path.join(self.output_dir, f"proj_{i}.tif") - if not os.path.exists(modified_output_file): - dst_path = modified_output_file - break - i += 1 + dst_path, layer_name = get_unique_filename(self.output_dir, 'proj.tif', 'reduced features') + # if os.path.exists(dst_path): + # i = 1 + # while True: + # modified_output_file = os.path.join(self.output_dir, f"proj_{i}.tif") + # if not os.path.exists(modified_output_file): + # dst_path = modified_output_file + # break + # i += 1 with rasterio.open(dst_path, 'w', driver='GTiff', height=height, width=width, count=channels, dtype='float32', @@ -340,7 +346,7 @@ class ReductionAlgorithm(QgsProcessingAlgorithm): parameters['OUTPUT_RASTER']=dst_path - return {'OUTPUT_RASTER':dst_path} + return {'OUTPUT_RASTER':dst_path, 'OUTPUT_LAYER_NAME':layer_name} def process_options(self,parameters, context, feedback): @@ -393,10 +399,12 @@ class ReductionAlgorithm(QgsProcessingAlgorithm): parameters, self.CRS, context) extent = self.parameterAsExtent( parameters, self.EXTENT, context) - self.output_dir = self.parameterAsString( + output_dir = self.parameterAsString( parameters, self.OUTPUT, context) self.save_model = self.parameterAsBoolean( parameters, self.SAVE_MODEL, context) + self.output_dir = Path(output_dir) + self.output_dir.mkdir(parents=True, exist_ok=True) rlayer_data_provider = rlayer.dataProvider() diff --git a/similarity.py b/similarity.py index fe6d750..c7cc89d 100644 --- a/similarity.py +++ b/similarity.py @@ -3,6 +3,8 @@ import numpy as np from pathlib import Path from typing import Dict, Any import joblib +import json +import tempfile import rasterio from rasterio import windows @@ -11,9 +13,7 @@ from shapely.geometry import box from qgis.PyQt.QtCore import QCoreApplication from qgis.core import (Qgis, QgsGeometry, - QgsProcessingParameterBoolean, QgsProcessingParameterFile, - QgsProcessingParameterEnum, QgsCoordinateTransform, QgsProcessingException, QgsProcessingAlgorithm, @@ -28,7 +28,8 @@ from qgis.core import (Qgis, import torch import torch.nn as nn -import json +from .utils.misc import get_unique_filename + class SimilarityAlgorithm(QgsProcessingAlgorithm): @@ -51,6 +52,7 @@ class SimilarityAlgorithm(QgsProcessingAlgorithm): with some other properties. """ cwd = Path(__file__).parent.absolute() + tmp_wd = os.path.join(tempfile.gettempdir(), "iamap_sim") self.addParameter( QgsProcessingParameterRasterLayer( @@ -113,7 +115,7 @@ class SimilarityAlgorithm(QgsProcessingAlgorithm): self.OUTPUT, self.tr( "Output directory (choose the location that the image features will be saved)"), - defaultValue=os.path.join(cwd,'features'), + defaultValue=tmp_wd, ) ) @@ -207,17 +209,17 @@ class SimilarityAlgorithm(QgsProcessingAlgorithm): sim = sim.numpy() height, width, channels = sim.shape - dst_path = os.path.join(self.output_dir,'similarity.tif') + dst_path, layer_name = get_unique_filename(self.output_dir, 'similarity.tif', 'similarity') params_file = os.path.join(self.output_dir,'cosine.json') - if os.path.exists(dst_path): - i = 1 - while True: - modified_output_file = os.path.join(self.output_dir, f"similarity_{i}.tif") - if not os.path.exists(modified_output_file): - dst_path = modified_output_file - break - i += 1 + # if os.path.exists(dst_path): + # i = 1 + # while True: + # modified_output_file = os.path.join(self.output_dir, f"similarity_{i}.tif") + # if not os.path.exists(modified_output_file): + # dst_path = modified_output_file + # break + # i += 1 if os.path.exists(params_file): i = 1 while True: @@ -238,7 +240,7 @@ class SimilarityAlgorithm(QgsProcessingAlgorithm): parameters['OUTPUT_RASTER']=dst_path - return {'OUTPUT_RASTER':dst_path} + return {'OUTPUT_RASTER':dst_path, 'OUTPUT_LAYER_NAME':layer_name} def process_options(self,parameters, context, feedback): self.iPatch = 0 @@ -281,8 +283,10 @@ class SimilarityAlgorithm(QgsProcessingAlgorithm): parameters, self.CRS, context) extent = self.parameterAsExtent( parameters, self.EXTENT, context) - self.output_dir = self.parameterAsString( + output_dir = self.parameterAsString( parameters, self.OUTPUT, context) + self.output_dir = Path(output_dir) + self.output_dir.mkdir(parents=True, exist_ok=True) rlayer_data_provider = rlayer.dataProvider() -- GitLab