diff --git a/.gitignore b/.gitignore index 7e99e367f8443d86e5e8825b9fda39dfbb39630d..83658ec52733073084336058333361a36e6c8de6 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ -*.pyc \ No newline at end of file +*.pyc +*.log diff --git a/Archive.py b/Archive.py index 04d24254705a04dd56a335eec985a3089baa3947..55f948ee8fc367d2b00b6456fd05aed972e6d26e 100644 --- a/Archive.py +++ b/Archive.py @@ -18,43 +18,44 @@ # along with PHYMOBAT 3.0. If not, see <http://www.gnu.org/licenses/>. import os, sys, glob, re, shutil, time -import math, subprocess, json, urllib # urllib2 +import math, subprocess, json +import urllib.request import tarfile, zipfile try : import ogr except : - from osgeo import ogr + import osgeo.ogr as org -# import UserDict import numpy as np -from lxml import etree +import lxml from collections import defaultdict, UserDict +import Constantes, Satellites, Outils -from RasterSat_by_date import RasterSat_by_date +import RasterSat_by_date class Archive(): """ - Class to list, download and unpack Theia image archive because of a shapefile (box). - This shapefile get extent of the area. - - :param captor: Name of the satellite (ex: Landsat or SpotWorldHeritage ...). - - Name used to the url on website Theia Land - :type captor: str - :param list_year: Processing's year (string for one year) - :type list_year: list of str - :param box: Path of the study area - :type box: str - :param folder: Path of the source folder - :type folder: str - :param repertory: Name of the archive's folder - :type repertory: str + Class to list, download and unpack Theia image archive because of a shapefile (box). + This shapefile get extent of the area. + + :param captor: Name of the satellite (ex: Landsat or SpotWorldHeritage ...). + + Name used to the url on website Theia Land + :type captor: str + :param list_year: Processing's year (string for one year) + :type list_year: list of str + :param box: Path of the study area + :type box: str + :param folder: Path of the source folder + :type folder: str + :param repertory: Name of the archive's folder + :type repertory: str """ def __init__(self, captor, list_year, box, folder, repertory, proxy_enabled): - """Create a new 'Archive' instance - + """ + Create a new 'Archive' instance """ self._captor = captor self._list_year = list_year.split(";") @@ -67,38 +68,31 @@ class Archive(): # 1. List of the website path archives # 2. List of the local path archives self.list_archive = [] - self.server = '' # Host - self.resto ='' - # Info from Theia-land website or Olivier Hagolle blog - if self._captor == 'SENTINEL2': - self.server = 'https://theia.cnes.fr/atdistrib' - self.resto = 'resto2' - self.token_type = 'text' - else: - self.server = 'https://theia-landsat.cnes.fr' - self.resto = 'resto' - self.token_type = 'json' + + self.logger = Outils.Log("Log", "archive") + + self.server = Satellites.SATELLITE[self._captor]["server"] + self.resto = Satellites.SATELLITE[self._captor]["resto"] + self.token_type = Satellites.SATELLITE[self._captor]["token_type"] + self.url = '' # str : complete website JSON database self.list_img = [] # List (dim 5) to get year, month, day, path of multispectral's images and path of cloud's images self.single_date = [] # date list without duplication - - def __str__(self) : - return 'Year\'s list : ', self._list_year - + def set_list_archive_to_try(self, few_list_archive): """ - Test function to download a few archives - - :param few_list_archive: [archive_download, out_archive] - - with : - - * archive_dowload : Archives downloaded - - * out_archive : Output archives path - - :type few_list_archive: list dimension 2 + Test function to download a few archives + + :param few_list_archive: [archive_download, out_archive] + + with : + + * archive_dowload : Archives downloaded + + * out_archive : Output archives path + + :type few_list_archive: list dimension 2 """ _few_list_archive = np.array(few_list_archive) @@ -110,21 +104,20 @@ class Archive(): def utm_to_latlng(self, zone, easting, northing, northernHemisphere=True): """ - Function to convert UTM to geographic coordinates - - :param zone: UTM zone - :type zone: int - :param easting: Coordinates UTM in x - :type easting: float - :param northing: Coordinates UTM in y - :type northing: float - :param northernHemisphere: North hemisphere or not - :type northernHemisphere: boolean - - :returns: tuple -- integer on the **longitude** and **latitude** - - Source : http://www.ibm.com/developerworks/java/library/j-coordconvert/index.html - + Function to convert UTM to geographic coordinates + + :param zone: UTM zone + :type zone: int + :param easting: Coordinates UTM in x + :type easting: float + :param northing: Coordinates UTM in y + :type northing: float + :param northernHemisphere: North hemisphere or not + :type northernHemisphere: boolean + + :returns: tuple -- integer on the **longitude** and **latitude** + + Source : http://www.ibm.com/developerworks/java/library/j-coordconvert/index.html """ if not northernHemisphere: @@ -179,18 +172,18 @@ class Archive(): def coord_box_dd(self): """ - Function to get area's coordinates of shapefile + Function to get area's coordinates of shapefile - :returns: str -- **area_coord_corner** : Area coordinates corner - - --> Left bottom on x, Left bottom on y, Right top on x, Right top on y - :Example: - - >>> import Archive - >>> test = Archive(captor, list_year, box, folder, repertory, proxy_enabled) - >>> coor_test = test.coord_box_dd() - >>> coor_test - '45.52, 2.25, 46.71, 3.27' + :returns: str -- **area_coord_corner** : Area coordinates corner + + --> Left bottom on x, Left bottom on y, Right top on x, Right top on y + :Example: + + >>> import Archive + >>> test = Archive(captor, list_year, box, folder, repertory, proxy_enabled) + >>> coor_test = test.coord_box_dd() + >>> coor_test + '45.52, 2.25, 46.71, 3.27' """ # Processus to convert the UTM shapefile in decimal degrees shapefile with ogr2ogr in command line @@ -208,7 +201,7 @@ class Archive(): data_source = driver.Open(utm_outfile, 0) if data_source is None: - print ('Could not open file') + self.logger.error('Could not open file') sys.exit(1) shp_ogr = data_source.GetLayer() @@ -230,56 +223,45 @@ class Archive(): def listing(self): """ - Function to list available archive on plateform Theia Land, and on the area - + Function to list available archive on plateform Theia Land, and on the area """ # Loop on the years - print ("Images availables") + self.logger.info("Images availables") for year in self._list_year: first_date = year.split(',')[0] # Tricks to put whether a year or a date (year-month-day) try: end_date = year.split(',')[1] - print ("=============== " + str(first_date) + " to " + str(end_date) + " ===============") - self.url = self.server + '/' + self.resto + '/api/collections/' + self._captor + '/search.json?lang=fr&_pretty=true&completionDate=' + str(end_date) + '&box=' + self.coord_box_dd() + '&maxRecord=500&startDate=' + str(first_date) - + self.logger.info("=============== {0} to {1} ===============".format(first_date, end_date)) + self.url = "{0}/{1}/api/collections/{2}/search.json?lang=fr&_pretty=true&completionDate={3}&box={4}&maxRecord=500&startDate={5}".format(self.server, self.resto, self._captor, end_date, self.coord_box_dd(), first_date) except IndexError: - print ("=============== " + str(first_date) + " ===============" ) - self.url = self.server + '/' + self.resto + '/api/collections/' + self._captor + '/search.json?lang=fr&_pretty=true&q=' + str(year) + '&box=' + self.coord_box_dd() + '&maxRecord=500' + self.logger.info("=============== {0} ===============".format(first_date)) + self.url = "{0}/{1}/api/collections/{2}/search.json?lang=fr&_pretty=true&q={3}&box={4}&maxRecord=500".format(self.server, self.resto, self._captor, year, self.coord_box_dd()) - print (self.url) - # Link to connect in the database JSON of the Theia plateform -# self.url = r'https://theia.cnes.fr/resto/api/collections/' + self._captor + '/search.json?lang=fr&_pretty=true&q=' + str(year) + '&box=' + self.coord_box_dd() + '&maxRecord=500' - # Temporary link -# if self._captor == 'SENTINEL2': -# self.url = r'https://theia.cnes.fr/atdistrib/resto2/api/collections/' -# else: -# self.url = r'https://theia-landsat.cnes.fr/resto/api/collections/' - # Initialisation variable for a next page # There is a next page, next = 1 # There isn't next page, next = 0 next_ = 1 - if not os.path.exists(self._folder + '/' + self._repertory): - os.mkdir(self._folder + '/' + self._repertory) + if not os.path.exists("{0}/{1}".format(self._folder ,self._repertory)): + os.mkdir("{0}/{1}".format(self._folder ,self._repertory)) # To know path to download images while next_ == 1: try : - request_headers = {"User-Agent": "Firefox/48.0"} - req = urllib.Request(str(self.url), headers = request_headers) # Connexion in the database - data = urllib.urlopen(req).read() # Read in the database - - new_data = re.sub("null", "'null'", data) # Remove "null" because Python don't like - new_data = re.sub("false", "False", new_data) # Remove "false" and replace by False (Python know False with a capital letter F) - + request_headers = {"User-Agent": "Magic-browser"} + req = urllib.request.Request(self.url, headers = request_headers) # Connexion in the database + data = urllib.request.urlopen(req).read() # Read in the database + + new_data = re.sub(b"null", b"'null'", data) # Remove "null" because Python don't like + new_data = re.sub(b"false", b"False", new_data) # Remove "false" and replace by False (Python know False with a capital letter F) + # Transform the data in dictionary data_Dict = defaultdict(list) - data_Dict = UserDict.UserDict(eval(new_data)) - + data_Dict = UserDict(eval(new_data)) + # Select archives to download for d in range(len(data_Dict['features'])): name_archive = data_Dict['features'][d]['properties']['productIdentifier'] @@ -288,29 +270,31 @@ class Archive(): url_archive = link_archive.replace(self.resto, "rocket/#") archive_download = url_archive.replace("/download", "") # Path to download out_archive = self._folder + '/' + self._repertory + '/' + name_archive + '.tgz' # Name after download - self.list_archive.append([archive_download, out_archive, feature_id]) + if len(self.list_archive) == 0 : self.list_archive.append([archive_download, out_archive, feature_id]) # Verify if there is another page (next) if data_Dict['properties']['links'][len(data_Dict['properties']['links'])-1]['title'] == 'suivant': self.url = data_Dict['properties']['links'][len(data_Dict['properties']['links'])-1]['href'].replace("\\", "") else: next_ = 0 - except: - print ("Error connexion or error variable !") + + except Exception as e: + self.logger.error("Error connexion or error variable : {0}".format(e)) sys.exit(1) - print ("There is " + str(len(self.list_archive)) + " images to download !") + self.logger.info("{0} image(s) matched the criteria.".format(len(self.list_archive))) + + return len(self.list_archive) def download_auto(self, user_theia, password_theia): """ - Function to download images archive automatically on Theia land data center. - Source : https://github.com/olivierhagolle/theia_download - - :param user_theia: Username Theia Land data center - :type user_theia: str - :param password_theia: Password Theia Land data center - :type password_theia: str - + Function to download images archive automatically on Theia land data center. + Source : https://github.com/olivierhagolle/theia_download + + :param user_theia: Username Theia Land data center + :type user_theia: str + :param password_theia: Password Theia Land data center + :type password_theia: str """ #===================== # Proxy @@ -331,7 +315,7 @@ class Archive(): #============================================================= if os.path.exists('token.json'): os.remove('token.json') -# get_token='curl -k -s -X POST --data-urlencode "ident=%s" --data-urlencode "pass=%s" https://theia.cnes.fr/services/authenticate/>token.json'%(curl_proxy,user_theia, password_theia) + get_token='curl -k -s -X POST %s --data-urlencode "ident=%s" --data-urlencode "pass=%s" %s/services/authenticate/>token.json'%(curl_proxy, user_theia, password_theia, self.server) os.system(get_token) @@ -342,8 +326,8 @@ class Archive(): token = token_json["access_token"] elif self.token_type=="text": token=data_file.readline() - except : - print ("Authentification is probably wrong") + except Exception as e: + self.logger.error("Authentification is probably wrong : {0}".format(e)) sys.exit(-1) #==================== @@ -353,25 +337,19 @@ class Archive(): for d in range(len(self.list_archive)): # Download if not exist if not os.path.exists(self.list_archive[d][1]): - - print (str(round(100*float(d)/len(self.list_archive),2)) + "%") # Print loading bar - print (os.path.split(str(self.list_archive[d][1]))[1]) - -# get_product='curl -o %s -k -H "Authorization: Bearer %s" https://theia.cnes.fr/resto/collections/Landsat/%s/download/?issuerId=theia'%(curl_proxy,self.list_archive[d][1], token, self.list_archive[d][2]) get_product='curl %s -o %s -k -H "Authorization: Bearer %s" %s/%s/collections/%s/%s/download/?issuerId=theia'%(curl_proxy, self.list_archive[d][1], token, self.server, self.resto, self._captor, self.list_archive[d][2]) - print (get_product) + self.logger.debug(get_product) os.system(get_product) os.remove('token.json') - print ("100%") - print ("END OF DOWNLOAD !" ) + self.logger.info("All images have been downloaded !") def decompress(self): """ - Function to unpack archives and store informations of the images (date, path, ...) + Function to unpack archives and store informations of the images (date, path, ...) """ - print ("Unpack archives") + self.logger.info("Unpack archives") for annee in self._list_year: @@ -379,29 +357,23 @@ class Archive(): # Tricks to put whether a year or a date (year-month-day) try: end_date = annee.split(',')[1] - print ("=============== " + str(first_date) + " to " + str(end_date) + " ===============") + self.logger.info("=============== {0} to {1} ===============".format(first_date, end_date)) except IndexError: - print ("=============== " + str(first_date) + " ===============") + self.logger.info ("=============== {0} ===============".format(first_date)) - img_in_glob = [] - img_in_glob = glob.glob(str(self._folder) + '/'+ str(self._repertory) + '/*gz') + img_in_glob = sorted(glob.glob("{0}/{1}/*gz".format(self._folder, self._repertory))) - if img_in_glob == []: - print ("There isn't tgzfile in the folder") - sys.exit() + if not img_in_glob : + self.logger.error("There isn't tgzfile in the folder") + sys.exit(1) else: # Create a folder "Unpack" - folder_unpack = self._folder + '/' + self._repertory + '/Unpack' + folder_unpack = "{0}/{1}/Unpack".format(self._folder, self._repertory) - if os.path.isdir(folder_unpack): - print('The folder already exists') - # shutil.rmtree(FolderOut) # Remove the folder that it contains if exists ... - else: - process_tocall = ['mkdir', folder_unpack] - subprocess.call(process_tocall) + if not os.path.isdir(folder_unpack): + os.mkdir(folder_unpack) for img in img_in_glob: - # Unpack the archives if they aren't again! if self._captor == 'Landsat': out_folder_unpack = folder_unpack + '/' + os.path.split(img)[1][:len(os.path.split(img)[1])-4] @@ -411,7 +383,7 @@ class Archive(): tfile.extractall(str(folder_unpack)) # On xmlfile, extract dates, path of images, cloud's images - xmlfile = etree.parse(str(out_folder_unpack) + '/' + os.path.split(img)[1][:len(os.path.split(img)[1])-4] + '.xml') + xmlfile = lxml.etree.parse(str(out_folder_unpack) + '/' + os.path.split(img)[1][:len(os.path.split(img)[1])-4] + '.xml') # Date images # Exemple : '2015-09-27 10:41:25.956749' @@ -442,7 +414,7 @@ class Archive(): tzip.extract(str(z_out), str(folder_unpack)) # On xmlfile, extract dates, path of images, cloud's images - xmlfile = etree.parse(str(extraction_img[4])) + xmlfile = lxml.etree.parse(str(extraction_img[4])) # Date images di = xmlfile.xpath("/Muscate_Metadata_Document/Product_Characteristics/ACQUISITION_DATE")[0].text.split('T')[0].split('-') # Multispectral images @@ -450,7 +422,7 @@ class Archive(): if not os.path.exists(hi): # For Sentinel2 from Theia plateform, we need to make a stack layer for rasters # There is a function that make this in RasterSat_by_date class - stack_img = RasterSat_by_date('', '', [0]) + stack_img = RasterSat_by_date.RasterSat_by_date('', '', [0]) input_stack = extraction_img[:4] input_stack.insert(0,'-separate') stack_img.vrt_translate_gdal('vrt', input_stack, hi[:-4] + '.VRT') diff --git a/Constantes.py b/Constantes.py new file mode 100644 index 0000000000000000000000000000000000000000..9ec418553205a57943cb28340dcc2a75ff634c19 --- /dev/null +++ b/Constantes.py @@ -0,0 +1,6 @@ + +SIMPLE_MODE = 0 +EXPERT_MODE = 1 + +MULTIPROCESSING_ENABLE = True +MULTIPROCESSING_DISABLE = False diff --git a/Log/.gitkeep b/Log/.gitkeep new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/Outils.py b/Outils.py new file mode 100644 index 0000000000000000000000000000000000000000..7500da87ef663f921b7f527cd1d6bbc260a7906a --- /dev/null +++ b/Outils.py @@ -0,0 +1,81 @@ +#!/bin/env python +# -*- coding: utf-8 -*- + +import argparse +import logging +from logging.handlers import RotatingFileHandler +import signal +from contextlib import contextmanager + +class Fusion(argparse.Action): + def __init__(self, option_strings, dest, nargs=None, **kwargs): + super(Fusion, self).__init__(option_strings, dest, nargs, **kwargs) + def __call__(self, parser, namespace, values, option_string=None): + setattr(namespace, self.dest, ' '.join(values).lower()) + +class Log(object): + + def __init__(self, dossier, nomFichier, niveau=logging.DEBUG): + super(Log, self).__init__() + + self.__logger__ = logging.getLogger(nomFichier) + self.__logger__.setLevel(niveau) + + format = logging.Formatter('%(asctime)s :: %(levelname)s :: %(message)s', datefmt='%d-%m-%Y %H:%M:%S') + fichierLog = RotatingFileHandler("{0}/{1}.log".format(dossier, nomFichier), 'a', 1000000, 1) + + fichierLog.setLevel(niveau) + fichierLog.setFormatter(format) + self.__logger__.addHandler(fichierLog) + + console = logging.StreamHandler() + console.setLevel(niveau) + self.__logger__.addHandler(console) + + def info(self, message): + self.__logger__.info(message) + + def debug(self, message): + self.__logger__.debug(message) + + def warning(self, message): + self.__logger__.warning(message) + + def error(self, message): + self.__logger__.error(message) + + def critical(self, message): + self.__logger__.critical(message) + + def exception(self, message): + self.__logger__.exception(message) + + def close(self): + for handler in self.__logger__.handlers[:] : + handler.close() + self.__logger__.removeHandler(handler) + + +class TimeoutException(Exception): pass + +@contextmanager +def limitation_temporelle(secondes): + + def signal_handler(signum, frame): + raise TimeoutException + + signal.signal(signal.SIGALRM, signal_handler) + signal.alarm(secondes) + + try: + yield + finally: + signal.alarm(0) + +# Utilisation : +# +# try: +# with limitation_temporelle(temps_en_seconde): +# appel_fonction() +# except TimeoutException: +# pass \ No newline at end of file diff --git a/PHYMOBAT.py b/PHYMOBAT.py index a6505a033d41ed948001bc4178eb0c3ad7c457db..8278ebf5c743fb8c5b910b352353f723e8ba7a89 100644 --- a/PHYMOBAT.py +++ b/PHYMOBAT.py @@ -36,1503 +36,1383 @@ from PyQt5 import QtWidgets, QtCore from _collections import defaultdict try : - import ogr + import ogr except : - from osgeo import ogr + from osgeo import ogr import webbrowser import lxml.etree as ET import os.path -from ui_A_propos_PHYMOBAT_window import Ui_About -from ui_Warming_study_area import Ui_Warming_study_area -from ui_Warming_forgetting import Ui_Warming_forgetting -from ui_Proxy_window import Ui_Proxy_window +import Popup from Processing import Processing +import Constantes +import Outils class PHYMOBAT(QtWidgets.QMainWindow, Processing): - """ - Interface main class. It makes to link ``ui_PHYMOBAT_tab`` and ``Processing``. - """ - - def __init__(self, mode = 0, parent=None): - super(PHYMOBAT, self).__init__(parent) - Processing.__init__(self) + """ + Interface main class. It makes to link ``ui_PHYMOBAT_tab`` and ``Processing``. + """ + + def __init__(self, mode = Constantes.SIMPLE_MODE, parent=None): + super(PHYMOBAT, self).__init__(parent) + Processing.__init__(self) - self.apropos = None # For the "About PHYMOBAT" window - self.w_study_area = None # For the "Warming : forget study area" window - self.w_forget = None # For the "Warming : forgetting" window - - self.simpli = None # For the "PHYMOBATs" window - self.expert = None # For the "PHYMOBATe" window - self.mode = mode # For the mode simple (0 by default) or expert (1) - - # To select interface's parameters - if self.mode == 1: - print ("Expert") - global Ui_PHYMOBAT, _translate - from ui_PHYMOBATe_tab import Ui_PHYMOBAT, _translate - elif self.mode == 0: - print ("Simple") - global Ui_PHYMOBAT, _translate - from ui_PHYMOBATs_tab import Ui_PHYMOBAT, _translate - - self.initUI() - - def initUI(self): - - """ - Get initial values from interface after a click button. - - There is : - - - Connect browser button to search a path - * Main folder path - * Study area shapefile path - * VHRS image path - * MNT image path - * Segmentation shapefile path - * Output classification shapefile path - * Sample shapefile path - * Image path for samples if the first processing image hasn't been launched - - - Connect button to add sample in the memory list - - Connect button to clear sample record. Clear in the interface and in the memory list - - Connect close|ok button - - Connect menu bar tab (Open backup, save in a xml file, close, help, About PHYMOBAT, mode) - - Initialize backup variable - - """ - - # Initial interface - self.ui = Ui_PHYMOBAT() - self.ui.setupUi(self) + self.apropos = Popup.about() # For the "About PHYMOBAT" window + self.w_study_area = Popup.warming_study_area() # For the "Warming : forget study area" window + self.w_forget = Popup.warming_forgetting() # For the "Warming : forgetting" window - # Connect browser button to search a path - ########################################## - # Main folder path - self.ui.lineEdit_principal_folder.clear() - self.ui.pushButton_browser_principal_folder.clicked.connect(self.f_path_folder_dpt) - - # Block other function if SpotWorldHeritage is chose - try : - self.ui.comboBox_captor.currentIndexChanged.connect(self.block_for_swh) - except AttributeError: - pass - - # VHRS image path - self.ui.lineEdit_VHRS.clear() - self.ui.pushButton_browser_VHRS.clicked.connect(self.f_path_ortho) - - # Study area shapefile path - self.ui.lineEdit_area_path.clear() - self.ui.pushButton_browser_area_path.clicked.connect(self.f_path_area) - - # Proxy - self.ui.proxy.clicked.connect(self.f_proxy) - - # Segmentation shapefile path - self.ui.lineEdit_segmentation.clear() - self.ui.pushButton_browser_segmentation.clicked.connect(self.f_path_segm) - - # MNT image path - self.ui.lineEdit_MNT.clear() - self.ui.pushButton_browser_MNT.clicked.connect(self.f_path_mnt) - - # Output classification shapefile path - self.ui.lineEdit_output.clear() - self.ui.pushButton_browser_output.clicked.connect(self.f_output_name_moba) - - # Sample shapefile path. - # For the simply mode, RPG file sample. - self.ui.lineEdit_sample_path.clear() - self.ui.pushButton_browser_sample_path.clicked.connect(self.enter_sample_name) - - if self.mode == 0: - # For the simply mode, grass/wooden file sample. - self.ui.lineEdit_sample_path_2.clear() - self.ui.pushButton_browser_sample_path_2.clicked.connect(self.enter_sample_name_hl) - # For the simply mode, wooden file sample. - self.ui.lineEdit_sample_path_3.clear() - self.ui.pushButton_browser_sample_path_3.clicked.connect(self.enter_sample_name_ll) - - # Image path for samples if the first processing image hasn't been launched - try: - self.ui.pushButton_img_sample.clicked.connect(self.img_sample_name) - except AttributeError: - pass # Simple mode - ########################################## + self.window = None # The "PHYMOBAT" window + self.current_mode = mode - # Connect button to add sample in the memory list - try: - self.ui.pushButton_add_sample.clicked.connect(self.add_sample) - except AttributeError: - pass # Simple mode - - # Connect button to clear sample record. Clear in the interface and in the memory list - try: - self.ui.pushButton_clear_sample.clicked.connect(self.clear_sample) - except AttributeError: - pass # Simple mode - - # Connect close|ok button - self.ui.buttonBox.button(QtWidgets.QDialogButtonBox.Close).clicked.connect(self.close_button) - self.ui.buttonBox.button(QtWidgets.QDialogButtonBox.Ok).clicked.connect(self.ok_button) - - # Connect Menu bar - self.ui.actionOuvrir.triggered.connect(self.open_backup) # Open backup - self.ui.actionSauver.triggered.connect(self.save_backup) # Save field name on the interface - self.ui.actionQuiter.triggered.connect(self.close_button) # Close - self.ui.actionAide_de_PHYMOBAT.triggered.connect(self.help_tools) # Help - self.ui.actionA_propos_de_PHYMOBAT.triggered.connect(self.about_PHYMOBA) # About PHYMOBA - self.ui.actionMode_Simplifi.triggered.connect(self.mode_simpli) # To open the simple apply - self.ui.actionMode_expert.triggered.connect(self.mode_expert) # To open the expert apply - - self.rpg_tchek = [] # To backup rpg mode - self.img_sample = [] # To backup - - # Connect change line edit on sample path to extract fieldnames. For the simply mode, this - # is with RPG sample - self.ui.lineEdit_select_sample_fieldname_1.textChanged.connect(self.field_display_1) - self.ui.lineEdit_select_sample_fieldname_2.textChanged.connect(self.field_display_2) - - # To choose the classification method - if self.mode == 1: - if self.ui.radioButton_rf.isChecked(): - self.ui.checkBox_classifier_1.setEnabled(False) - self.ui.checkBox_classifier_2.setEnabled(False) - - self.ui.radioButton_rf.toggled.connect(self.activate_level) - self.ui.radioButton_s.toggled.connect(self.activate_level) - - if self.mode == 0: - # Connect change line edit to grass/wooden sample - self.ui.lineEdit_select_sample_fieldname_3.textChanged.connect(self.field_display_3) - self.ui.lineEdit_select_sample_fieldname_4.textChanged.connect(self.field_display_4) - self.ui.lineEdit_select_sample_fieldname_5.textChanged.connect(self.field_display_5) - self.ui.lineEdit_select_sample_fieldname_6.textChanged.connect(self.field_display_6) - - # Change connect for classification checkboxes - try: - self.ui.checkBox_classifier_1.stateChanged.connect(self.display_one_level) - self.ui.checkBox_classifier_2.stateChanged.connect(self.display_two_levels) - self.ui.checkBox_classifier_3.stateChanged.connect(self.display_all_levels) - except AttributeError: - pass # Simple mode - - def get_variable(self): - - """ - Add a all system value like : - - - Main folder path by line edit - - Satellite captor name by combo box - - Classification year by line edit - - Study area shapefile path by line edit - - Connexion username and password by line edit - - VHRS image path by line edit - - MNT image path by line edit - - Segmentation shapefile path path by line edit - - Output classification shapefile path by line edit - - Output shapefile field name by line edit and field type by combo box - - """ - # Main folder path by line edit. - self.path_folder_dpt = "%s" % self.ui.lineEdit_principal_folder.text() - - # Satellite captor name by combo box - try: - self.captor_project = self.ui.comboBox_captor.currentText() - except AttributeError: - self.captor_project = "Landsat" - - # Classification year by line edit - self.classif_year = "%s" % self.ui.lineEdit_year_images.text() - - # Study area shapefile path by line edit - self.path_area = "%s" % self.ui.lineEdit_area_path.text() - - # Connexion username and password by line edit - self.user = "%s" % self.ui.lineEdit_user.text() - self.password = "%s" % self.ui.lineEdit_password.text() - - # VHRS image path by line edit - self.path_ortho = "%s" % self.ui.lineEdit_VHRS.text() - - # MNT image path by line edit - self.path_mnt = "%s" % self.ui.lineEdit_MNT.text() - - # Output shapefile field name by line edit and field type by combo box - try: - if self.ui.checkBox_classifier_1.isChecked() and self.ui.lineEdit_fieldname_1.text() != '': - self.out_fieldname_carto.append("%s" % self.ui.lineEdit_fieldname_1.text()) - self.out_fieldtype_carto.append(eval("ogr.OFT%s" % self.ui.comboBox_fieldname_1.currentText())) - - if self.ui.checkBox_classifier_2.isChecked() and self.ui.lineEdit_fieldname_12.text() != '': - self.out_fieldname_carto.append("%s" % self.ui.lineEdit_fieldname_12.text()) - self.out_fieldtype_carto.append(eval("ogr.OFT%s" % self.ui.comboBox_fieldname_12.currentText())) - - if self.ui.lineEdit_fieldname_2.text() != '': - self.out_fieldname_carto.append("%s" % self.ui.lineEdit_fieldname_2.text()) - self.out_fieldtype_carto.append(eval("ogr.OFT%s" % self.ui.comboBox_fieldname_2.currentText())) - - if self.ui.checkBox_classifier_3.isChecked() and self.ui.lineEdit_fieldname_13.text() != '': - self.out_fieldname_carto.append("%s" % self.ui.lineEdit_fieldname_13.text()) - self.out_fieldtype_carto.append(eval("ogr.OFT%s" % self.ui.comboBox_fieldname_13.currentText())) - - if self.ui.lineEdit_fieldname_23.text() != '': - self.out_fieldname_carto.append("%s" % self.ui.lineEdit_fieldname_23.text()) - self.out_fieldtype_carto.append(eval("ogr.OFT%s" % self.ui.comboBox_fieldname_23.currentText())) - - if self.ui.lineEdit_fieldname_3.text() != '': - self.out_fieldname_carto.append("%s" % self.ui.lineEdit_fieldname_3.text()) - self.out_fieldtype_carto.append(eval("ogr.OFT%s" % self.ui.comboBox_fieldname_3.currentText())) - - if self.ui.lineEdit_fieldname_4.text() != '': - self.out_fieldname_carto.append("%s" % self.ui.lineEdit_fieldname_4.text()) - self.out_fieldtype_carto.append(eval("ogr.OFT%s" % self.ui.comboBox_fieldname_4.currentText())) - except AttributeError: - modes_fieldname = ["NIVEAU_1", "NIVEAU_2", "NIVEAU_3", "POURC"] - modes_fieldtype = [eval("ogr.OFTString"), eval("ogr.OFTString"), eval("ogr.OFTString"), eval("ogr.OFTReal")] - - for mf in range(len(modes_fieldname)): - - self.out_fieldname_carto.append(modes_fieldname[mf]) - self.out_fieldtype_carto.append(modes_fieldtype[mf]) - - # Segmentation shapefile path path by line edit - self.path_segm = "%s" % self.ui.lineEdit_segmentation.text() - - # Output shapefile field name by line edit and field type by combo box - self.output_name_moba = "%s" % self.ui.lineEdit_output.text() - - def set_variable(self): - """ - Print number of available image from Theia's GeoJSON . - """ - # self.ui.lineEdit_listing.setText(str(self.nb_avalaible_images)) - try: - self.ui.label_listing.setText(str(self.nb_avalaible_images)) - except AttributeError: - pass # Simple mode - - def f_path_folder_dpt(self): - """ - Open a input browser box to select the main folder path by line edit. - """ - infoldername = QtWidgets.QFileDialog.getExistingDirectory(self, "Principal folder path", os.getcwd(), QtWidgets.QFileDialog.ShowDirsOnly) - self.ui.lineEdit_principal_folder.setText(str(infoldername).replace('[','').replace(']','').replace(' ','')) - - def block_for_swh(self): - """ - Function to block others function when SportWorldHeritage is selected in the comboxbox captor. - """ - ind_captor = int(self.ui.comboBox_captor.currentIndex()) - if ind_captor == 2: - self.ui.checkBox_processing.setEnabled(False) - self.ui.checkBox_MNT.setEnabled(False) - self.ui.lineEdit_MNT.setEnabled(False) - self.ui.pushButton_browser_MNT.setEnabled(False) - self.ui.checkBox_VHRS.setEnabled(False) - self.ui.lineEdit_VHRS.setEnabled(False) - self.ui.pushButton_browser_VHRS.setEnabled(False) - self.ui.tabWidget.setTabEnabled(1, False) - self.ui.tabWidget.setTabEnabled(2, False) - # If the user want, on the same moment, come back on other captor that SWH. - else: - self.ui.checkBox_processing.setEnabled(True) - self.ui.checkBox_MNT.setEnabled(True) - self.ui.lineEdit_MNT.setEnabled(True) - self.ui.pushButton_browser_MNT.setEnabled(True) - self.ui.checkBox_VHRS.setEnabled(True) - self.ui.lineEdit_VHRS.setEnabled(True) - self.ui.pushButton_browser_VHRS.setEnabled(True) - self.ui.tabWidget.setTabEnabled(1, True) - self.ui.tabWidget.setTabEnabled(2, True) - - def f_path_ortho(self): - """ - Open a input browser box to select the VHRS image path by line edit. - """ - orthofilename = QtWidgets.QFileDialog.getOpenFileName(self, "THRS image", self.ui.lineEdit_principal_folder.text(), '*.TIF *.tif')[0] - self.ui.lineEdit_VHRS.setText(str(orthofilename).replace('[','').replace(']','').replace(' ','')) - - def f_path_mnt(self): - """ - Open a input browser box to select the MNT image path by line edit. - """ - mntfilename = QtWidgets.QFileDialog.getOpenFileName(self, "MNT image", self.ui.lineEdit_principal_folder.text(), '*.TIF *.tif')[0] - self.ui.lineEdit_MNT.setText(str(mntfilename).replace('[','').replace(']','').replace(' ','')) - - def f_path_area(self): - """ - Open a input browser box to select the study area shapefile path by line edit. - """ - areafilename = QtWidgets.QFileDialog.getOpenFileName(self, "Area shapefile", self.ui.lineEdit_principal_folder.text(), '*.shp')[0] - self.ui.lineEdit_area_path.setText(str(areafilename).replace('[','').replace(']','').replace(' ','')) - - def f_proxy(self): - """ - Function to open a popup in order to enter proxy ID - """ - if self.w_proxy is None: - self.w_proxy = MyPopup_proxy_window() - self.w_proxy.show() - - def f_path_segm(self): - """ - Open a input browser box to select segmentation shapefile path path by line edit. - """ - segmfilename = QtWidgets.QFileDialog.getOpenFileName(self, "Segmentation shapefile", self.ui.lineEdit_principal_folder.text(), '*.shp')[0] - self.ui.lineEdit_segmentation.setText(str(segmfilename).replace('[','').replace(']','').replace(' ','')) - - def f_output_name_moba(self): - """ - Set the output classification shapefile path by line edit. - """ - outfilename = QtWidgets.QFileDialog.getSaveFileName(self, "FB file", self.ui.lineEdit_principal_folder.text(), '*.shp')[0] - # if the user has forgotten to put .shp at the end of the output shapefile - if outfilename[-4:] != '.shp': - outfilename = outfilename + '.shp' - self.ui.lineEdit_output.setText(outfilename) - - def enter_sample_name(self): - """ - Open a input browser box to select the sample shapefile path by line edit. With :func:`add_sample` conditions for the expert mode. - For the simply mode, this function is used for the RPG shapefile. - """ - samplefilename = QtWidgets.QFileDialog.getOpenFileName(self, "Sample shapefile", self.ui.lineEdit_principal_folder.text(), '*.shp')[0] - self.ui.lineEdit_sample_path.setText(str(samplefilename).replace('[','').replace(']','').replace(' ','')) - - def enter_sample_name_hl(self): - """ - Open a input browser box to select the grass and wooden sample shapefile path by line edit. With :func:`add_sample` conditions - for the simply mode. - """ - samplefilename_hl = QtWidgets.QFileDialog.getOpenFileName(self, "Grass/Wooden sample shapefile", self.ui.lineEdit_principal_folder.text(), '*.shp')[0] - self.ui.lineEdit_sample_path_2.setText(str(samplefilename_hl).replace('[','').replace(']','').replace(' ','')) - - def enter_sample_name_ll(self): - """ - Open a input browser box to select the wooden sample shapefile path by line edit. With :func:`add_sample` conditions for the simply mode. - """ - samplefilename_ll = QtWidgets.QFileDialog.getOpenFileName(self, "Wooden sample shapefile", self.ui.lineEdit_principal_folder.text(), '*.shp')[0] - self.ui.lineEdit_sample_path_3.setText(str(samplefilename_ll).replace('[','').replace(']','').replace(' ','')) - - def img_sample_name(self): - """ - Open a input browser box to select the image for samples path by line edit. With :func:`add_sample` conditions. - """ - imgsamplefilename = QtWidgets.QFileDialog.getOpenFileName(self, "Sample image", self.ui.lineEdit_principal_folder.text(), '*.TIF')[0] - self.ui.lineEdit_img_sample.setText(str(imgsamplefilename).replace('[','').replace(']','').replace(' ','')) - - def add_sample(self): - """ - Add sample information and location to compute optimal threshold : - - For the expert mode (mode=1) : - - - Append a sample name by line Edit. *This is a check box* ``RPG``, *if the sample is RPG file. It launch the Rpg class. And append a other sample from Rpg class*. - - Append two existent sample field names by combobox. It will be the same. - - Append sample class names by line edit. One or more for every sample. - - Append number of polygons for every samples by line edit. - - Print in a plain text edit : sample name, two sample field names, sample class names and number of polygons. - - *This check box* ``Image echantillonee``, *image path for samples if the first processing image hasn't been launched*. - .. note:: This is for a image with one spectral band - - Clear all widget field at the end. - - For the simply mode (mode=0): - - - Append a sample name by a different line Edit (a line Edit for each sample). - - Append sample class names, existing sample fields and number of polygons (a different line Edit for each sample) - """ - - nb_sample = len(self.sample_name)# Compute number of samples added. Condition : max three. - # Study area shapefile path by line edit if no processing other - # Because the function "Vector" need study area - self.path_area = "%s" % self.ui.lineEdit_area_path.text() - if self.path_area == '': - self.forget_study_area() - - if self.mode == 1: - # Expert mode - if nb_sample < 3 and not self.ui.lineEdit_sample_path.text().isEmpty() and \ - not self.ui.lineEdit_select_sample_fieldname_1.text().isEmpty() and not self.ui.lineEdit_select_sample_fieldname_2.text().isEmpty() and \ - not self.ui.lineEdit_select_sample_class_1.text().isEmpty() and not self.ui.lineEdit_select_sample_class_2.text().isEmpty() and \ - not self.ui.lineEdit_select_sample_nb_poly.text().isEmpty() and not self.ui.lineEdit_area_path.text().isEmpty(): - - # Append a sample name by line Edit. - if self.ui.checkBox_RPG.isChecked(): - # Check box, if the sample of the RPG file. It launch the Rpg class. And append a other sample from Rpg class - self.sample_name.append(self.i_rpg("%s" % self.ui.lineEdit_sample_path.text())) - self.rpg_tchek.append(1) # To backup - self.ui.checkBox_RPG.setChecked(False) - else: - self.sample_name.append("%s" % self.ui.lineEdit_sample_path.text()) - self.rpg_tchek.append(0) - - # Append two sample field names by line edit. It must be the same. - self.fieldname_args.append("%s" % self.ui.lineEdit_select_sample_fieldname_1.text()) - self.fieldname_args.append("%s" % self.ui.lineEdit_select_sample_fieldname_2.text()) - # Append sample class names by line edit. One or more for every sample - self.class_args.append("%s" % self.ui.lineEdit_select_sample_class_1.text()) - self.class_args.append("%s" % self.ui.lineEdit_select_sample_class_2.text()) - # Append number of polygons for every samples by line edit. - self.list_nb_sample.append("%s" % self.ui.lineEdit_select_sample_nb_poly.text()) - - nb_sample = len(self.sample_name) # Number of samples added - # Print in a plain text edit : sample name, two sample field names, sample class names and number of polygons. - cursor = self.ui.plainTextEdit_sample.textCursor() - cursor.movePosition(QTextCursor.End, QTextCursor.MoveAnchor) - self.ui.plainTextEdit_sample.setTextCursor(cursor) - self.ui.plainTextEdit_sample.insertPlainText(str(self.sample_name[nb_sample-1]) + "\n") - cursor.movePosition(QTextCursor.Down, QTextCursor.MoveAnchor) - self.ui.plainTextEdit_sample.setTextCursor(cursor) - self.ui.plainTextEdit_sample.insertPlainText(str(self.fieldname_args[(nb_sample-1)*2]) + ' ' + str(self.fieldname_args[((nb_sample-1)*2)+1]) + "\n") - cursor.movePosition(QTextCursor.Down, QTextCursor.MoveAnchor) - self.ui.plainTextEdit_sample.setTextCursor(cursor) - self.ui.plainTextEdit_sample.insertPlainText(str(self.class_args[(nb_sample-1)*2]) + ' ' + str(self.class_args[(nb_sample-1)*2+1]) + "\n") - cursor.movePosition(QTextCursor.Down, QTextCursor.MoveAnchor) - self.ui.plainTextEdit_sample.setTextCursor(cursor) - self.ui.plainTextEdit_sample.insertPlainText(str(self.list_nb_sample[nb_sample-1]) + "\n") - - # Check box, image path for samples if the first processing image hasn't been launched - # Warming : This is for a image with one spectral band - if self.ui.checkBox_img_sample.isChecked(): - self.raster_path.append("%s" % self.ui.lineEdit_img_sample.text()) - self.list_band_outraster.append(1) - self.ui.lineEdit_img_sample.clear() - self.ui.checkBox_img_sample.setChecked(False) - self.img_sample.append(1) - else: # To backup - self.img_sample.append(0) - - # Clear all line edit after addition, ie after click add button. - self.ui.lineEdit_sample_path.clear() - self.ui.lineEdit_select_sample_fieldname_1.clear() - self.ui.lineEdit_select_sample_fieldname_2.clear() - self.ui.lineEdit_select_sample_class_1.clear() - self.ui.lineEdit_select_sample_class_2.clear() - self.ui.lineEdit_select_sample_nb_poly.clear() - - elif self.mode == 0: - - # Simple mode - # Append a sample name by line Edit. - # For the sample of the RPG file. It launch the Rpg class. And append a other sample from Rpg class - self.sample_name.append(self.i_rpg("%s" % self.ui.lineEdit_sample_path.text())) - - # Append two sample field names by line edit. It must be the same. - self.fieldname_args.append("%s" % self.ui.lineEdit_select_sample_fieldname_1.text()) - self.fieldname_args.append("%s" % self.ui.lineEdit_select_sample_fieldname_2.text()) - # Append sample class names by line edit. One or more for every sample - self.class_args.append("%s" % self.ui.lineEdit_select_sample_class_1.text()) - self.class_args.append("%s" % self.ui.lineEdit_select_sample_class_2.text()) - # Append number of polygons for every samples by line edit. - self.list_nb_sample.append("%s" % self.ui.lineEdit_select_sample_nb_poly.text()) - - # Same process that the RPG process except the start of the RPG class. - # To Grass/wooden - self.sample_name.append("%s" % self.ui.lineEdit_sample_path_2.text()) - self.fieldname_args.append("%s" % self.ui.lineEdit_select_sample_fieldname_3.text()) - self.fieldname_args.append("%s" % self.ui.lineEdit_select_sample_fieldname_4.text()) - self.class_args.append("%s" % self.ui.lineEdit_select_sample_class_3.text()) - self.class_args.append("%s" % self.ui.lineEdit_select_sample_class_4.text()) - self.list_nb_sample.append("%s" % self.ui.lineEdit_select_sample_nb_poly_2.text()) - - # To wooden - self.sample_name.append("%s" % self.ui.lineEdit_sample_path_3.text()) - self.fieldname_args.append("%s" % self.ui.lineEdit_select_sample_fieldname_5.text()) - self.fieldname_args.append("%s" % self.ui.lineEdit_select_sample_fieldname_6.text()) - self.class_args.append("%s" % self.ui.lineEdit_select_sample_class_5.text()) - self.class_args.append("%s" % self.ui.lineEdit_select_sample_class_6.text()) - self.list_nb_sample.append("%s" % self.ui.lineEdit_select_sample_nb_poly_3.text()) - - nb_sample = 3 - - def clear_sample(self): - """ - Function to clear sample record. Clear in the interface and in the memory list. - """ - self.sample_name = [] - self.fieldname_args = [] - self.class_args = [] - self.list_nb_sample = [] - self.rpg_tchek = [] - self.img_sample = [] - - self.ui.lineEdit_sample_path.clear() - self.ui.lineEdit_select_sample_fieldname_1.clear() - self.ui.lineEdit_select_sample_fieldname_2.clear() - self.ui.lineEdit_select_sample_class_1.clear() - self.ui.lineEdit_select_sample_class_2.clear() - self.ui.lineEdit_select_sample_nb_poly.clear() - self.ui.checkBox_RPG.setChecked(False) - self.ui.lineEdit_img_sample.clear() - self.ui.checkBox_img_sample.setChecked(False) - self.ui.plainTextEdit_sample.clear() - self.ui.plainTextEdit_sample.insertPlainText("1 - Végétation non naturelle / Semi-naturelle\n") - self.ui.plainTextEdit_sample.insertPlainText("2 - Herbacés / Ligneux\n") - self.ui.plainTextEdit_sample.insertPlainText("3 - Lingeux mixtes / denses\n") - self.ui.plainTextEdit_sample.insertPlainText("\n") - self.ui.plainTextEdit_sample.insertPlainText("\n") - self.ui.plainTextEdit_sample.insertPlainText("") - - def field_display_1(self): - """ - Function to display fieldname class 1 in the other fieldname class 2 when text changed. - For the simply mode, this is RPG sample. - """ - - self.ui.lineEdit_select_sample_fieldname_2.setText("%s" % self.ui.lineEdit_select_sample_fieldname_1.text()) - - def field_display_2(self): - """ - Function to display fieldname class 2 in the other fieldname class 2 when text changed. - For the simply mode, this is RPG sample. - """ - - self.ui.lineEdit_select_sample_fieldname_1.setText("%s" % self.ui.lineEdit_select_sample_fieldname_2.text()) - - def field_display_3(self): - """ - For the grass/wooden sample, a function to display fieldname class 1 in the other fieldname class 2 when text changed. - """ - - self.ui.lineEdit_select_sample_fieldname_4.setText("%s" % self.ui.lineEdit_select_sample_fieldname_3.text()) - - def field_display_4(self): - """ - For the grass/wooden sample, a function to display fieldname class 2 in the other fieldname class 2 when text changed. - """ - - self.ui.lineEdit_select_sample_fieldname_3.setText("%s" % self.ui.lineEdit_select_sample_fieldname_4.text()) - - def field_display_5(self): - """ - For the wooden sample, a function to display fieldname class 1 in the other fieldname class 2 when text changed. - """ - - self.ui.lineEdit_select_sample_fieldname_6.setText("%s" % self.ui.lineEdit_select_sample_fieldname_5.text()) - - def field_display_6(self): - """ - For the wooden sample, a function to display fieldname class 2 in the other fieldname class 2 when text changed. - """ - - self.ui.lineEdit_select_sample_fieldname_5.setText("%s" % self.ui.lineEdit_select_sample_fieldname_6.text()) - - def activate_level(self): - """ - To activate the first levels with seath method. This is in pushing on the decision tree radio button. - Else it activates the last level to random forest method. - """ - if self.ui.radioButton_s.isChecked() and not self.ui.radioButton_rf.isChecked(): - self.ui.checkBox_classifier_1.setEnabled(True) - self.ui.checkBox_classifier_2.setEnabled(True) - else: - self.ui.checkBox_classifier_1.setEnabled(False) - self.ui.checkBox_classifier_2.setEnabled(False) - self.ui.checkBox_classifier_3.setChecked(True) - - - def display_one_level(self): - """ - Function to display fieldnames option to classifier one level - """ - if self.ui.checkBox_classifier_1.isChecked(): - - # Don't checked others checkboxes - self.ui.checkBox_classifier_2.setChecked(False) - self.ui.checkBox_classifier_3.setChecked(False) - - # Display options filednames - self.ui.label_chps_1 = QLabel(self.ui.tab_3) - self.ui.label_chps_1.setObjectName("label_chps_1") - self.ui.gridLayout_2.addWidget(self.ui.label_chps_1, 10, 0, 2, 2) - self.ui.label_chps_name_1 = QLabel(self.ui.tab_3) - self.ui.label_chps_name_1.setObjectName("label_chps_name_1") - self.ui.gridLayout_2.addWidget(self.ui.label_chps_name_1, 10, 2, 1, 1) - self.ui.label_chps_type_1 = QLabel(self.ui.tab_3) - self.ui.label_chps_type_1.setObjectName("label_chps_type_1") - self.ui.gridLayout_2.addWidget(self.ui.label_chps_type_1, 11, 2, 1, 1) - self.ui.lineEdit_fieldname_1 = QLineEdit(self.ui.tab_3) - self.ui.lineEdit_fieldname_1.setObjectName("lineEdit_fieldname_1") - self.ui.gridLayout_2.addWidget(self.ui.lineEdit_fieldname_1, 10, 3, 1, 1) - self.ui.comboBox_fieldname_1 = QComboBox(self.ui.tab_3) - self.ui.comboBox_fieldname_1.setObjectName("comboBox_fieldname_1") - self.ui.gridLayout_2.addWidget(self.ui.comboBox_fieldname_1, 11, 3, 1, 1) - - self.ui.lineEdit_fieldname_1.setText(_translate("PHYMOBAT", "NIVEAU_1", None)) - self.ui.comboBox_fieldname_1.addItem("String") - self.ui.comboBox_fieldname_1.addItem("Real") - - self.ui.label_chps_1.setText(_translate("PHYMOBAT", " Champs\n"+" des entités", None)) - self.ui.label_chps_name_1.setText(_translate("PHYMOBAT", "Nom :", None)) - self.ui.label_chps_type_1.setText(_translate("PHYMOBAT", "Type :", None)) - - if not self.ui.checkBox_classifier_1.isChecked(): - # Clear options filednames - try: - self.ui.label_chps_1.deleteLater() - self.ui.label_chps_name_1.deleteLater() - self.ui.label_chps_type_1.deleteLater() - self.ui.lineEdit_fieldname_1.deleteLater() - self.ui.comboBox_fieldname_1.deleteLater() - except AttributeError: - pass - - def display_two_levels(self): - """ - Function to display fieldnames option to classifier two first levels - """ - - if self.ui.checkBox_classifier_2.isChecked(): - - # Don't checked others checkboxes - self.ui.checkBox_classifier_1.setChecked(False) - self.ui.checkBox_classifier_3.setChecked(False) - - self.ui.label_chps_2 = QLabel(self.ui.tab_3) - self.ui.label_chps_2.setObjectName("label_chps_2") - self.ui.gridLayout_2.addWidget(self.ui.label_chps_2, 13, 0, 2, 2) - self.ui.lineEdit_fieldname_12 = QLineEdit(self.ui.tab_3) - self.ui.lineEdit_fieldname_12.setObjectName("lineEdit_fieldname_12") - self.ui.gridLayout_2.addWidget(self.ui.lineEdit_fieldname_12, 13, 3, 1, 1) - self.ui.lineEdit_fieldname_2 = QLineEdit(self.ui.tab_3) - self.ui.lineEdit_fieldname_2.setObjectName("lineEdit_fieldname_2") - self.ui.gridLayout_2.addWidget(self.ui.lineEdit_fieldname_2, 13, 4, 1, 1) - self.ui.label_chps_type_2 = QLabel(self.ui.tab_3) - self.ui.label_chps_type_2.setObjectName("label_chps_type_2") - self.ui.gridLayout_2.addWidget(self.ui.label_chps_type_2, 14, 2, 1, 1) - self.ui.comboBox_fieldname_12 = QComboBox(self.ui.tab_3) - self.ui.comboBox_fieldname_12.setObjectName("comboBox_fieldname_12") - self.ui.gridLayout_2.addWidget(self.ui.comboBox_fieldname_12, 14, 3, 1, 1) - self.ui.comboBox_fieldname_2 = QComboBox(self.ui.tab_3) - self.ui.comboBox_fieldname_2.setObjectName("comboBox_fieldname_2") - self.ui.gridLayout_2.addWidget(self.ui.comboBox_fieldname_2, 14, 4, 1, 1) - self.ui.label_chps_name_2 = QLabel(self.ui.tab_3) - self.ui.label_chps_name_2.setObjectName("label_chps_name_2") - self.ui.gridLayout_2.addWidget(self.ui.label_chps_name_2, 13, 2, 1, 1) - - self.ui.lineEdit_fieldname_12.setText(_translate("PHYMOBAT", "NIVEAU_1", None)) - self.ui.comboBox_fieldname_12.addItem("String") - self.ui.comboBox_fieldname_12.addItem("Real") - self.ui.lineEdit_fieldname_2.setText(_translate("PHYMOBAT", "NIVEAU_2", None)) - self.ui.comboBox_fieldname_2.addItem("String") - self.ui.comboBox_fieldname_2.addItem("Real") - - self.ui.label_chps_type_2.setText(_translate("PHYMOBAT", "Type :", None)) - self.ui.label_chps_2.setText(_translate("PHYMOBAT", " Champs\n"+" des entités", None)) - self.ui.label_chps_name_2.setText(_translate("PHYMOBAT", "Nom :", None)) - - if not self.ui.checkBox_classifier_2.isChecked(): - # Clear options filednames - try: - self.ui.label_chps_2.deleteLater() - self.ui.label_chps_name_2.deleteLater() - self.ui.label_chps_type_2.deleteLater() - self.ui.lineEdit_fieldname_12.deleteLater() - self.ui.comboBox_fieldname_12.deleteLater() - self.ui.lineEdit_fieldname_2.deleteLater() - self.ui.comboBox_fieldname_2.deleteLater() - except AttributeError: - pass - - def display_all_levels(self): - """ - Function to display fieldnames option to launch complete classification - """ - - if self.ui.checkBox_classifier_3.isChecked(): - - # Don't checked others checkboxes - self.ui.checkBox_classifier_1.setChecked(False) - self.ui.checkBox_classifier_2.setChecked(False) - - self.ui.label_chps_name_3 = QLabel(self.ui.tab_3) - self.ui.label_chps_name_3.setObjectName("label_chps_name_3") - self.ui.gridLayout_2.addWidget(self.ui.label_chps_name_3, 16, 2, 1, 1) - self.ui.label_chps_3 = QLabel(self.ui.tab_3) - self.ui.label_chps_3.setObjectName("label_chps_3") - self.ui.gridLayout_2.addWidget(self.ui.label_chps_3, 16, 0, 2, 2) - self.ui.label_chps_type_3 = QLabel(self.ui.tab_3) - self.ui.label_chps_type_3.setObjectName("label_chps_type_3") - self.ui.gridLayout_2.addWidget(self.ui.label_chps_type_3, 17, 2, 1, 1) - self.ui.lineEdit_fieldname_13 = QLineEdit(self.ui.tab_3) - self.ui.lineEdit_fieldname_13.setObjectName("lineEdit_fieldname_13") - self.ui.gridLayout_2.addWidget(self.ui.lineEdit_fieldname_13, 16, 3, 1, 1) - self.ui.lineEdit_fieldname_23 = QLineEdit(self.ui.tab_3) - self.ui.lineEdit_fieldname_23.setObjectName("lineEdit_fieldname_23") - self.ui.gridLayout_2.addWidget(self.ui.lineEdit_fieldname_23, 16, 4, 1, 1) - self.ui.lineEdit_fieldname_3 = QLineEdit(self.ui.tab_3) - self.ui.lineEdit_fieldname_3.setObjectName("lineEdit_fieldname_3") - self.ui.gridLayout_2.addWidget(self.ui.lineEdit_fieldname_3, 16, 5, 1, 1) - self.ui.lineEdit_fieldname_4 = QLineEdit(self.ui.tab_3) - self.ui.lineEdit_fieldname_4.setObjectName("lineEdit_fieldname_4") - self.ui.gridLayout_2.addWidget(self.ui.lineEdit_fieldname_4, 16, 6, 1, 1) - self.ui.comboBox_fieldname_13 = QComboBox(self.ui.tab_3) - self.ui.comboBox_fieldname_13.setObjectName("comboBox_fieldname_13") - self.ui.gridLayout_2.addWidget(self.ui.comboBox_fieldname_13, 17, 3, 1, 1) - self.ui.comboBox_fieldname_23 = QComboBox(self.ui.tab_3) - self.ui.comboBox_fieldname_23.setObjectName("comboBox_fieldname_23") - self.ui.gridLayout_2.addWidget(self.ui.comboBox_fieldname_23, 17, 4, 1, 1) - self.ui.comboBox_fieldname_3 = QComboBox(self.ui.tab_3) - self.ui.comboBox_fieldname_3.setObjectName("comboBox_fieldname_3") - self.ui.gridLayout_2.addWidget(self.ui.comboBox_fieldname_3, 17, 5, 1, 1) - self.ui.comboBox_fieldname_4 = QComboBox(self.ui.tab_3) - self.ui.comboBox_fieldname_4.setObjectName("comboBox_fieldname_4") - self.ui.gridLayout_2.addWidget(self.ui.comboBox_fieldname_4, 17, 6, 1, 1) - - self.ui.lineEdit_fieldname_13.setText(_translate("PHYMOBAT", "NIVEAU_1", None)) - self.ui.comboBox_fieldname_13.addItem("String") - self.ui.comboBox_fieldname_13.addItem("Real") - self.ui.lineEdit_fieldname_23.setText(_translate("PHYMOBAT", "NIVEAU_2", None)) - self.ui.comboBox_fieldname_23.addItem("String") - self.ui.comboBox_fieldname_23.addItem("Real") - self.ui.lineEdit_fieldname_3.setText(_translate("PHYMOBAT", "NIVEAU_3", None)) - self.ui.comboBox_fieldname_3.addItem("String") - self.ui.comboBox_fieldname_3.addItem("Real") - self.ui.lineEdit_fieldname_4.setText(_translate("PHYMOBAT", "POURC", None)) - self.ui.comboBox_fieldname_4.addItem("Real") - self.ui.comboBox_fieldname_4.addItem("String") - - self.ui.label_chps_3.setText(_translate("PHYMOBAT", " Champs\n"+" des entités", None)) - self.ui.label_chps_type_3.setText(_translate("PHYMOBAT", "Type :", None)) - self.ui.label_chps_name_3.setText(_translate("PHYMOBAT", "Nom :", None)) - - if not self.ui.checkBox_classifier_3.isChecked(): - # Clear options filednames - try: - self.ui.label_chps_3.deleteLater() - self.ui.label_chps_name_3.deleteLater() - self.ui.label_chps_type_3.deleteLater() - self.ui.lineEdit_fieldname_13.deleteLater() - self.ui.comboBox_fieldname_13.deleteLater() - self.ui.lineEdit_fieldname_23.deleteLater() - self.ui.comboBox_fieldname_23.deleteLater() - self.ui.lineEdit_fieldname_3.deleteLater() - self.ui.comboBox_fieldname_3.deleteLater() - self.ui.lineEdit_fieldname_4.deleteLater() - self.ui.comboBox_fieldname_4.deleteLater() - except AttributeError: - pass - - def ok_button(self): - - """ - Function to launch the processing. This function take account : - - - The ``Multi-processing`` check box if the processing has launched with multi process. By default, this is checked. It need a computer with minimum 12Go memory. - - Append a few system value with :func:`get_variable`. - - There are 3 principal check boxes : - - to get number download available images - - for downloading and processing on theia platform - - to compute optimal threshold. - - to compute slope raster - - for classification processing. - """ - - # Start the processus - startTime = time.time() - - # To know if the processing must be launch on several thread - if self.ui.checkBox_multiprocess.isChecked(): - self.mp = 1 - else: - self.mp = 0 - - self.get_variable() # Append a few system value - vs = 0 # Variable to launch VHRS texture processing - dd = 0 # Variable to launch image downloading - ok = 1 # Variable to verify informations -> 0 not ok, 1 ok - - if self.mode == 1: - # if download check box is checked only - if not self.ui.checkBox_listing.isChecked() and self.ui.checkBox_download.isChecked(): - - self.ui.checkBox_listing.setChecked(True) - - # # if processing check box is checked only - # if not self.ui.checkBox_listing.isChecked() and not self.ui.checkBox_download.isChecked() and self.ui.checkBox_processing.isChecked(): - # - # self.ui.checkBox_listing.setChecked(True) - # self.ui.checkBox_download.setChecked(True) - - # Verify raster or sample to launch a good processing classification tab - # If not ok, there will appear a message windows to enter the miss information - # if self.ui.checkBox_classifier_1.isChecked(): - # if not self.ui.checkBox_processing.isChecked() or (len(self.raster_path) < 1 and len(self.sample_name) > 0) or \ - # len(self.sample_name) < 1: - # self.forget_raster_sample() - # ok = 0 - # if self.ui.checkBox_classifier_2.isChecked(): - # if (not self.ui.checkBox_processing.isChecked() and not self.ui.checkBox_MNT.isChecked() and \ - # not self.ui.checkBox_VHRS.isChecked()) or (len(self.raster_path) < 2 and len(self.sample_name) > 0) or \ - # len(self.sample_name) < 2: - # self.forget_raster_sample() - # ok = 0 - # if self.ui.checkBox_classifier_3.isChecked(): - # if (not self.ui.checkBox_processing.isChecked() and not self.ui.checkBox_MNT.isChecked() and \ - # not self.ui.checkBox_VHRS.isChecked()) or (len(self.raster_path) != 6 and len(self.sample_name) > 0) or \ - # len(self.sample_name) != 3: - # self.forget_raster_sample() - # ok = 0 - - if ok == 1: - # Compute a output slope raster - if self.ui.checkBox_MNT.isChecked(): - - self.i_slope() - - # Downloading and processing on theia platform - # A check box to get number download available images - if self.ui.checkBox_listing.isChecked(): - - if self.ui.checkBox_download.isChecked(): - # To launch the downloading - dd = 1 - - self.i_download(dd) # Launch image listing and downloading if dd = 1 - self.set_variable() # to write in the line edit about number download available images - - # Check box to launch the image processing - if self.ui.checkBox_processing.isChecked(): - # Another check box to launch VHRS texture processing. If checked, vs = 1. - if self.ui.checkBox_VHRS.isChecked(): - vs = 1 - self.i_images_processing(vs) # function to launch the image processing - - # To launch the image processing without dowloading but with the images in a main folder - # Without internet connection - if not self.ui.checkBox_download.isChecked() and self.ui.checkBox_processing.isChecked(): - - # Launch pre-processing without downloading - self.i_glob() - # Another check box to launch VHRS texture processing. If checked, vs = 1. - if self.ui.checkBox_VHRS.isChecked(): - vs = 1 - self.i_images_processing(vs) # function to launch the image processing - - # To launch texture processing only - if not self.ui.checkBox_listing.isChecked() and not self.ui.checkBox_processing.isChecked() and self.ui.checkBox_VHRS.isChecked(): - - self.i_vhrs() - - # Compute optimal threshold - if self.ui.checkBox_threshold.isChecked(): - - if self.ui.radioButton_rf.isChecked(): - self.i_sample_rf() - elif self.ui.radioButton_s.isChecked(): - self.i_sample() - - # Classification processing - if self.ui.radioButton_rf.isChecked(): - - if self.ui.checkBox_classifier_3.isChecked(): - - self.out_fieldname_carto = self.out_fieldname_carto - self.out_fieldtype_carto = self.out_fieldtype_carto - self.i_classifier_rf() - self.i_validate() - - elif self.ui.radioButton_s.isChecked(): - - if self.ui.checkBox_classifier_1.isChecked() : - - self.out_fieldname_carto = self.out_fieldname_carto[:3] - self.out_fieldtype_carto = self.out_fieldtype_carto[:3] - self.i_classifier_s() - self.i_validate() - - if self.ui.checkBox_classifier_2.isChecked() : - - self.out_fieldname_carto = self.out_fieldname_carto[:4] - self.out_fieldtype_carto = self.out_fieldtype_carto[:4] - self.i_classifier_s() - self.i_validate() - - if self.ui.checkBox_classifier_3.isChecked(): - - self.out_fieldname_carto = self.out_fieldname_carto - self.out_fieldtype_carto = self.out_fieldtype_carto - self.i_classifier_s() - self.i_validate() - - if self.mode == 0: - - # Compute a output slope raster - if self.path_mnt != '': - self.i_slope() - - # Save the sample features - self.add_sample() - try: - # Look at if the the images has been already downlaoded - self.i_glob() - except: - # Else the processus download it - self.i_download(1) - - # function to launch the image processing - self.i_images_processing(1) - # To launch texture processing only - self.i_vhrs() - # Compute optimal threshold - self.i_sample_rf() - - # Classification processing - self.out_fieldname_carto = self.out_fieldname_carto - self.out_fieldtype_carto = self.out_fieldtype_carto - self.i_classifier_rf() - self.i_validate() - - -# # Clear variables after processing -# self.clear_sample() - self.out_fieldname_carto = ['ID', 'AREA'] - self.out_fieldtype_carto = [ogr.OFTString, ogr.OFTReal] - # Images after processing images - self.out_ndvistats_folder_tab = defaultdict(list) - - Processing.__init__(self)# Initialize variable without to close and launch again the application - - # End of the processus - endTime = time.time() # Tps : Terminé - print ('...........' + ' Outputted to File in ' + str(endTime - startTime) + ' secondes') - nb_day_processing = int(time.strftime('%d', time.gmtime(endTime - startTime))) - 1 - print ("That is, " + str(nb_day_processing) + ' day(s) ' + time.strftime('%Hh %Mmin%S', time.gmtime(endTime - startTime))) - - def open_backup(self): - """ - Function to load input text in every fields. The input file must be a XML file. - """ - - in_backup = QtWidgets.QFileDialog.getOpenFileName(self, "Open backup", os.getcwd(), '*.xml')[0] - - if in_backup != None and len(in_backup) > 0 : + self.logger = Outils.Log("Log", "Phymobat") + + # To select interface's parameters + if self.current_mode == Constantes.EXPERT_MODE: + self.logger.info("Expert mode.") + global Ui_PHYMOBAT, _translate + from ui_PHYMOBATe_tab import Ui_PHYMOBAT, _translate + elif self.current_mode == Constantes.SIMPLE_MODE: + self.logger.info("Simple mode.") + global Ui_PHYMOBAT, _translate + from ui_PHYMOBATs_tab import Ui_PHYMOBAT, _translate + + self.initUI() - # Parse the xml file if the user choose a file - tree = ET.parse(str(in_backup)) - - if tree.find("Multi_process").text == '1': - self.ui.checkBox_multiprocess.setChecked(True) - else: - self.ui.checkBox_multiprocess.setChecked(False) - - pr = tree.find("Tab[@id='Processing_raster']") + # Chargement et lancement automatique pour les tests à supprimer + self.open_backup("/home/commandre/Documents/data_test_2/2018.xml") + # self.ok_button() + + def initUI(self): + + """ + Get initial values from interface after a click button. + + There is : + + - Connect browser button to search a path + * Main folder path + * Study area shapefile path + * VHRS image path + * MNT image path + * Segmentation shapefile path + * Output classification shapefile path + * Sample shapefile path + * Image path for samples if the first processing image hasn't been launched + + - Connect button to add sample in the memory list + - Connect button to clear sample record. Clear in the interface and in the memory list + - Connect close|ok button + - Connect menu bar tab (Open backup, save in a xml file, close, help, About PHYMOBAT, mode) + - Initialize backup variable + + """ + + # Initial interface + self.ui = Ui_PHYMOBAT() + self.ui.setupUi(self) - try: - self.ui.lineEdit_principal_folder.setText(pr.find("Principal_folder").text) - except: - print('Not principal folder') + # Connect browser button to search a path + ########################################## + # Main folder path + self.ui.lineEdit_principal_folder.clear() + self.ui.pushButton_browser_principal_folder.clicked.connect(self.f_path_folder_dpt) + + # Block other function if SpotWorldHeritage is chose + try : + self.ui.comboBox_captor.currentIndexChanged.connect(self.block_for_swh) + except AttributeError: + pass + + # VHRS image path + self.ui.lineEdit_VHRS.clear() + self.ui.pushButton_browser_VHRS.clicked.connect(self.f_path_ortho) + + # Study area shapefile path + self.ui.lineEdit_area_path.clear() + self.ui.pushButton_browser_area_path.clicked.connect(self.f_path_area) + + # Proxy + self.ui.proxy.clicked.connect(self.f_proxy) + + # Segmentation shapefile path + self.ui.lineEdit_segmentation.clear() + self.ui.pushButton_browser_segmentation.clicked.connect(self.f_path_segm) + + # MNT image path + self.ui.lineEdit_MNT.clear() + self.ui.pushButton_browser_MNT.clicked.connect(self.f_path_mnt) + + # Output classification shapefile path + self.ui.lineEdit_output.clear() + self.ui.pushButton_browser_output.clicked.connect(self.f_output_name_moba) + + # Sample shapefile path. + # For the simply mode, RPG file sample. + self.ui.lineEdit_sample_path.clear() + self.ui.pushButton_browser_sample_path.clicked.connect(self.enter_sample_name) + + if self.current_mode == Constantes.SIMPLE_MODE: + # For the simply mode, grass/wooden file sample. + self.ui.lineEdit_sample_path_2.clear() + self.ui.pushButton_browser_sample_path_2.clicked.connect(self.enter_sample_name_hl) + # For the simply mode, wooden file sample. + self.ui.lineEdit_sample_path_3.clear() + self.ui.pushButton_browser_sample_path_3.clicked.connect(self.enter_sample_name_ll) + + # Image path for samples if the first processing image hasn't been launched + try: + self.ui.pushButton_img_sample.clicked.connect(self.img_sample_name) + except AttributeError: + pass # Simple mode + ########################################## - if self.mode == 1: - index_captor = self.ui.comboBox_captor.findText(pr.find("Captor").text) # To find combo box index - self.ui.comboBox_captor.setCurrentIndex(index_captor) + # Connect button to add sample in the memory list + try: + self.ui.pushButton_add_sample.clicked.connect(self.add_sample) + except AttributeError: + pass # Simple mode + + # Connect button to clear sample record. Clear in the interface and in the memory list + try: + self.ui.pushButton_clear_sample.clicked.connect(self.clear_sample) + except AttributeError: + pass # Simple mode + + # Connect close|ok button + # self.ui.buttonBox.button(QtWidgets.QDialogButtonBox.Close).clicked.connect(self.close_button) + self.ui.buttonBox.button(QtWidgets.QDialogButtonBox.Close).clicked.connect(self.close_button) + self.ui.buttonBox.button(QtWidgets.QDialogButtonBox.Ok).clicked.connect(self.ok_button) + + # Connect Menu bar + self.ui.actionOuvrir.triggered.connect(self.open_backup) # Open backup + self.ui.actionSauver.triggered.connect(self.save_backup) # Save field name on the interface + self.ui.actionQuiter.triggered.connect(self.close_button) # Close + self.ui.actionAide_de_PHYMOBAT.triggered.connect(self.help_tools) # Help + self.ui.actionA_propos_de_PHYMOBAT.triggered.connect(self.about_PHYMOBA) # About PHYMOBA + self.ui.actionMode_Simplifi.triggered.connect(lambda checked, mode=Constantes.SIMPLE_MODE: self.change_mode(mode)) # To open the simple apply + self.ui.actionMode_expert.triggered.connect(lambda checked, mode=Constantes.EXPERT_MODE: self.change_mode(mode)) # To open the expert apply + + self.rpg_tchek = [] # To backup rpg mode + self.img_sample = [] # To backup + + # Connect change line edit on sample path to extract fieldnames. For the simply mode, this + # is with RPG sample + self.ui.lineEdit_select_sample_fieldname_1.textChanged.connect(self.field_display_1) + self.ui.lineEdit_select_sample_fieldname_2.textChanged.connect(self.field_display_2) + + # To choose the classification method + if self.current_mode == Constantes.EXPERT_MODE: + if self.ui.radioButton_rf.isChecked(): + self.ui.checkBox_classifier_1.setEnabled(False) + self.ui.checkBox_classifier_2.setEnabled(False) + + self.ui.radioButton_rf.toggled.connect(self.activate_level) + self.ui.radioButton_s.toggled.connect(self.activate_level) + + if self.current_mode == Constantes.SIMPLE_MODE: + # Connect change line edit to grass/wooden sample + self.ui.lineEdit_select_sample_fieldname_3.textChanged.connect(self.field_display_3) + self.ui.lineEdit_select_sample_fieldname_4.textChanged.connect(self.field_display_4) + self.ui.lineEdit_select_sample_fieldname_5.textChanged.connect(self.field_display_5) + self.ui.lineEdit_select_sample_fieldname_6.textChanged.connect(self.field_display_6) + + # Change connect for classification checkboxes + try: + self.ui.checkBox_classifier_1.stateChanged.connect(self.display_one_level) + self.ui.checkBox_classifier_2.stateChanged.connect(self.display_two_levels) + self.ui.checkBox_classifier_3.stateChanged.connect(self.display_all_levels) + except AttributeError: + pass # Simple mode + + def get_variable(self): + """ + Add a all system value like : + + - Main folder path by line edit + - Satellite captor name by combo box + - Classification year by line edit + - Study area shapefile path by line edit + - Connexion username and password by line edit + - VHRS image path by line edit + - MNT image path by line edit + - Segmentation shapefile path path by line edit + - Output classification shapefile path by line edit + - Output shapefile field name by line edit and field type by combo box + + """ + # Main folder path by line edit. + self.path_folder_dpt = "%s" % self.ui.lineEdit_principal_folder.text() + + # Satellite captor name by combo box + try: + self.captor_project = self.ui.comboBox_captor.currentText() + except AttributeError: + self.captor_project = "Landsat" + + # Classification year by line edit + self.classif_year = "%s" % self.ui.lineEdit_year_images.text() + + # Study area shapefile path by line edit + self.path_area = "%s" % self.ui.lineEdit_area_path.text() + + # Connexion username and password by line edit + self.user = "%s" % self.ui.lineEdit_user.text() + self.password = "%s" % self.ui.lineEdit_password.text() + + # VHRS image path by line edit + self.path_ortho = "%s" % self.ui.lineEdit_VHRS.text() + + # MNT image path by line edit + self.path_mnt = "%s" % self.ui.lineEdit_MNT.text() + + # Output shapefile field name by line edit and field type by combo box + try: + if self.ui.checkBox_classifier_1.isChecked() and self.ui.lineEdit_fieldname_1.text() != '': + self.out_fieldname_carto.append("%s" % self.ui.lineEdit_fieldname_1.text()) + self.out_fieldtype_carto.append(eval("ogr.OFT%s" % self.ui.comboBox_fieldname_1.currentText())) + + if self.ui.checkBox_classifier_2.isChecked() and self.ui.lineEdit_fieldname_12.text() != '': + self.out_fieldname_carto.append("%s" % self.ui.lineEdit_fieldname_12.text()) + self.out_fieldtype_carto.append(eval("ogr.OFT%s" % self.ui.comboBox_fieldname_12.currentText())) + + if self.ui.lineEdit_fieldname_2.text() != '': + self.out_fieldname_carto.append("%s" % self.ui.lineEdit_fieldname_2.text()) + self.out_fieldtype_carto.append(eval("ogr.OFT%s" % self.ui.comboBox_fieldname_2.currentText())) + + if self.ui.checkBox_classifier_3.isChecked() and self.ui.lineEdit_fieldname_13.text() != '': + self.out_fieldname_carto.append("%s" % self.ui.lineEdit_fieldname_13.text()) + self.out_fieldtype_carto.append(eval("ogr.OFT%s" % self.ui.comboBox_fieldname_13.currentText())) + + if self.ui.lineEdit_fieldname_23.text() != '': + self.out_fieldname_carto.append("%s" % self.ui.lineEdit_fieldname_23.text()) + self.out_fieldtype_carto.append(eval("ogr.OFT%s" % self.ui.comboBox_fieldname_23.currentText())) + + if self.ui.lineEdit_fieldname_3.text() != '': + self.out_fieldname_carto.append("%s" % self.ui.lineEdit_fieldname_3.text()) + self.out_fieldtype_carto.append(eval("ogr.OFT%s" % self.ui.comboBox_fieldname_3.currentText())) + + if self.ui.lineEdit_fieldname_4.text() != '': + self.out_fieldname_carto.append("%s" % self.ui.lineEdit_fieldname_4.text()) + self.out_fieldtype_carto.append(eval("ogr.OFT%s" % self.ui.comboBox_fieldname_4.currentText())) + except AttributeError: + modes_fieldname = ["NIVEAU_1", "NIVEAU_2", "NIVEAU_3", "POURC"] + modes_fieldtype = [eval("ogr.OFTString"), eval("ogr.OFTString"), eval("ogr.OFTString"), eval("ogr.OFTReal")] + + for mf in range(len(modes_fieldname)): + + self.out_fieldname_carto.append(modes_fieldname[mf]) + self.out_fieldtype_carto.append(modes_fieldtype[mf]) + + # Segmentation shapefile path path by line edit + self.path_segm = "%s" % self.ui.lineEdit_segmentation.text() + + # Output shapefile field name by line edit and field type by combo box + self.output_name_moba = "%s" % self.ui.lineEdit_output.text() + + def set_variable(self): + """ + Print number of available image from Theia's GeoJSON . + """ - try: - self.ui.lineEdit_year_images.setText(pr.find("Year_images").text) - except: - print('Not year images') + # self.ui.lineEdit_listing.setText(str(self.nb_avalaible_images)) + try: + self.ui.label_listing.setText(str(self.nb_avalaible_images)) + except AttributeError: + pass # Simple mode + + def f_path_folder_dpt(self): + """ + Open a input browser box to select the main folder path by line edit. + """ + infoldername = QtWidgets.QFileDialog.getExistingDirectory(self, "Principal folder path", os.getcwd(), QtWidgets.QFileDialog.ShowDirsOnly) + self.ui.lineEdit_principal_folder.setText(str(infoldername).replace('[','').replace(']','').replace(' ','')) + + def block_for_swh(self): + """ + Function to block others function when SportWorldHeritage is selected in the comboxbox captor. + """ + ind_captor = int(self.ui.comboBox_captor.currentIndex()) + if ind_captor == 2: + self.ui.checkBox_processing.setEnabled(False) + self.ui.checkBox_MNT.setEnabled(False) + self.ui.lineEdit_MNT.setEnabled(False) + self.ui.pushButton_browser_MNT.setEnabled(False) + self.ui.checkBox_VHRS.setEnabled(False) + self.ui.lineEdit_VHRS.setEnabled(False) + self.ui.pushButton_browser_VHRS.setEnabled(False) + self.ui.tabWidget.setTabEnabled(1, False) + self.ui.tabWidget.setTabEnabled(2, False) + # If the user want, on the same moment, come back on other captor that SWH. + else: + self.ui.checkBox_processing.setEnabled(True) + self.ui.checkBox_MNT.setEnabled(True) + self.ui.lineEdit_MNT.setEnabled(True) + self.ui.pushButton_browser_MNT.setEnabled(True) + self.ui.checkBox_VHRS.setEnabled(True) + self.ui.lineEdit_VHRS.setEnabled(True) + self.ui.pushButton_browser_VHRS.setEnabled(True) + self.ui.tabWidget.setTabEnabled(1, True) + self.ui.tabWidget.setTabEnabled(2, True) + + def f_path_ortho(self): + """ + Open a input browser box to select the VHRS image path by line edit. + """ + orthofilename = QtWidgets.QFileDialog.getOpenFileName(self, "THRS image", self.ui.lineEdit_principal_folder.text(), '*.TIF *.tif')[0] + self.ui.lineEdit_VHRS.setText(str(orthofilename).replace('[','').replace(']','').replace(' ','')) + + def f_path_mnt(self): + """ + Open a input browser box to select the MNT image path by line edit. + """ + mntfilename = QtWidgets.QFileDialog.getOpenFileName(self, "MNT image", self.ui.lineEdit_principal_folder.text(), '*.TIF *.tif')[0] + self.ui.lineEdit_MNT.setText(str(mntfilename).replace('[','').replace(']','').replace(' ','')) + + def f_path_area(self): + """ + Open a input browser box to select the study area shapefile path by line edit. + """ + areafilename = QtWidgets.QFileDialog.getOpenFileName(self, "Area shapefile", self.ui.lineEdit_principal_folder.text(), '*.shp')[0] + self.ui.lineEdit_area_path.setText(str(areafilename).replace('[','').replace(']','').replace(' ','')) + + def f_proxy(self): + """ + Function to open a popup in order to enter proxy ID + """ + if self.w_proxy is None: + self.w_proxy = Popup.proxy_window() + self.w_proxy.show() + + def f_path_segm(self): + """ + Open a input browser box to select segmentation shapefile path path by line edit. + """ + segmfilename = QtWidgets.QFileDialog.getOpenFileName(self, "Segmentation shapefile", self.ui.lineEdit_principal_folder.text(), '*.shp')[0] + self.ui.lineEdit_segmentation.setText(str(segmfilename).replace('[','').replace(']','').replace(' ','')) + + def f_output_name_moba(self): + """ + Set the output classification shapefile path by line edit. + """ + outfilename = QtWidgets.QFileDialog.getSaveFileName(self, "FB file", self.ui.lineEdit_principal_folder.text(), '*.shp')[0] + # if the user has forgotten to put .shp at the end of the output shapefile + if outfilename[-4:] != '.shp': + outfilename = outfilename + '.shp' + self.ui.lineEdit_output.setText(outfilename) + + def enter_sample_name(self): + """ + Open a input browser box to select the sample shapefile path by line edit. With :func:`add_sample` conditions for the expert mode. + For the simply mode, this function is used for the RPG shapefile. + """ + samplefilename = QtWidgets.QFileDialog.getOpenFileName(self, "Sample shapefile", self.ui.lineEdit_principal_folder.text(), '*.shp')[0] + self.ui.lineEdit_sample_path.setText(str(samplefilename).replace('[','').replace(']','').replace(' ','')) + + def enter_sample_name_hl(self): + """ + Open a input browser box to select the grass and wooden sample shapefile path by line edit. With :func:`add_sample` conditions + for the simply mode. + """ + samplefilename_hl = QtWidgets.QFileDialog.getOpenFileName(self, "Grass/Wooden sample shapefile", self.ui.lineEdit_principal_folder.text(), '*.shp')[0] + self.ui.lineEdit_sample_path_2.setText(str(samplefilename_hl).replace('[','').replace(']','').replace(' ','')) + + def enter_sample_name_ll(self): + """ + Open a input browser box to select the wooden sample shapefile path by line edit. With :func:`add_sample` conditions for the simply mode. + """ + samplefilename_ll = QtWidgets.QFileDialog.getOpenFileName(self, "Wooden sample shapefile", self.ui.lineEdit_principal_folder.text(), '*.shp')[0] + self.ui.lineEdit_sample_path_3.setText(str(samplefilename_ll).replace('[','').replace(']','').replace(' ','')) + + def img_sample_name(self): + """ + Open a input browser box to select the image for samples path by line edit. With :func:`add_sample` conditions. + """ + imgsamplefilename = QtWidgets.QFileDialog.getOpenFileName(self, "Sample image", self.ui.lineEdit_principal_folder.text(), '*.TIF')[0] + self.ui.lineEdit_img_sample.setText(str(imgsamplefilename).replace('[','').replace(']','').replace(' ','')) + + def add_sample(self): + """ + Add sample information and location to compute optimal threshold : + + For the expert mode (mode=1) : + + - Append a sample name by line Edit. *This is a check box* ``RPG``, *if the sample is RPG file. It launch the Rpg class. And append a other sample from Rpg class*. + - Append two existent sample field names by combobox. It will be the same. + - Append sample class names by line edit. One or more for every sample. + - Append number of polygons for every samples by line edit. + - Print in a plain text edit : sample name, two sample field names, sample class names and number of polygons. + - *This check box* ``Image echantillonee``, *image path for samples if the first processing image hasn't been launched*. + .. note:: This is for a image with one spectral band + - Clear all widget field at the end. + + For the simply mode (mode=0): + + - Append a sample name by a different line Edit (a line Edit for each sample). + - Append sample class names, existing sample fields and number of polygons (a different line Edit for each sample) + """ + + nb_sample = len(self.sample_name)# Compute number of samples added. Condition : max three. + # Study area shapefile path by line edit if no processing other + # Because the function "Vector" need study area + self.path_area = "%s" % self.ui.lineEdit_area_path.text() + if self.path_area == '': + self.forget_study_area() + + if self.current_mode == Constantes.EXPERT_MODE: + # Expert mode + if nb_sample < 3 and not self.ui.lineEdit_sample_path.text().isEmpty() and \ + not self.ui.lineEdit_select_sample_fieldname_1.text().isEmpty() and not self.ui.lineEdit_select_sample_fieldname_2.text().isEmpty() and \ + not self.ui.lineEdit_select_sample_class_1.text().isEmpty() and not self.ui.lineEdit_select_sample_class_2.text().isEmpty() and \ + not self.ui.lineEdit_select_sample_nb_poly.text().isEmpty() and not self.ui.lineEdit_area_path.text().isEmpty(): + + # Append a sample name by line Edit. + if self.ui.checkBox_RPG.isChecked(): + # Check box, if the sample of the RPG file. It launch the Rpg class. And append a other sample from Rpg class + self.sample_name.append(self.i_rpg("%s" % self.ui.lineEdit_sample_path.text())) + self.rpg_tchek.append(1) # To backup + self.ui.checkBox_RPG.setChecked(False) + else: + self.sample_name.append("%s" % self.ui.lineEdit_sample_path.text()) + self.rpg_tchek.append(0) + + # Append two sample field names by line edit. It must be the same. + self.fieldname_args.append("%s" % self.ui.lineEdit_select_sample_fieldname_1.text()) + self.fieldname_args.append("%s" % self.ui.lineEdit_select_sample_fieldname_2.text()) + # Append sample class names by line edit. One or more for every sample + self.class_args.append("%s" % self.ui.lineEdit_select_sample_class_1.text()) + self.class_args.append("%s" % self.ui.lineEdit_select_sample_class_2.text()) + # Append number of polygons for every samples by line edit. + self.list_nb_sample.append("%s" % self.ui.lineEdit_select_sample_nb_poly.text()) + + nb_sample = len(self.sample_name) # Number of samples added + # Print in a plain text edit : sample name, two sample field names, sample class names and number of polygons. + cursor = self.ui.plainTextEdit_sample.textCursor() + cursor.movePosition(QTextCursor.End, QTextCursor.MoveAnchor) + self.ui.plainTextEdit_sample.setTextCursor(cursor) + self.ui.plainTextEdit_sample.insertPlainText(str(self.sample_name[nb_sample-1]) + "\n") + cursor.movePosition(QTextCursor.Down, QTextCursor.MoveAnchor) + self.ui.plainTextEdit_sample.setTextCursor(cursor) + self.ui.plainTextEdit_sample.insertPlainText(str(self.fieldname_args[(nb_sample-1)*2]) + ' ' + str(self.fieldname_args[((nb_sample-1)*2)+1]) + "\n") + cursor.movePosition(QTextCursor.Down, QTextCursor.MoveAnchor) + self.ui.plainTextEdit_sample.setTextCursor(cursor) + self.ui.plainTextEdit_sample.insertPlainText(str(self.class_args[(nb_sample-1)*2]) + ' ' + str(self.class_args[(nb_sample-1)*2+1]) + "\n") + cursor.movePosition(QTextCursor.Down, QTextCursor.MoveAnchor) + self.ui.plainTextEdit_sample.setTextCursor(cursor) + self.ui.plainTextEdit_sample.insertPlainText(str(self.list_nb_sample[nb_sample-1]) + "\n") + + # Check box, image path for samples if the first processing image hasn't been launched + # Warming : This is for a image with one spectral band + if self.ui.checkBox_img_sample.isChecked(): + self.raster_path.append("%s" % self.ui.lineEdit_img_sample.text()) + self.list_band_outraster.append(1) + self.ui.lineEdit_img_sample.clear() + self.ui.checkBox_img_sample.setChecked(False) + self.img_sample.append(1) + else: # To backup + self.img_sample.append(0) + + # Clear all line edit after addition, ie after click add button. + self.ui.lineEdit_sample_path.clear() + self.ui.lineEdit_select_sample_fieldname_1.clear() + self.ui.lineEdit_select_sample_fieldname_2.clear() + self.ui.lineEdit_select_sample_class_1.clear() + self.ui.lineEdit_select_sample_class_2.clear() + self.ui.lineEdit_select_sample_nb_poly.clear() + + elif self.current_mode == Constantes.SIMPLE_MODE: + + # Simple mode + # Append a sample name by line Edit. + # For the sample of the RPG file. It launch the Rpg class. And append a other sample from Rpg class + self.sample_name.append(self.i_rpg("%s" % self.ui.lineEdit_sample_path.text())) + + # Append two sample field names by line edit. It must be the same. + self.fieldname_args.append("%s" % self.ui.lineEdit_select_sample_fieldname_1.text()) + self.fieldname_args.append("%s" % self.ui.lineEdit_select_sample_fieldname_2.text()) + # Append sample class names by line edit. One or more for every sample + self.class_args.append("%s" % self.ui.lineEdit_select_sample_class_1.text()) + self.class_args.append("%s" % self.ui.lineEdit_select_sample_class_2.text()) + # Append number of polygons for every samples by line edit. + self.list_nb_sample.append("%s" % self.ui.lineEdit_select_sample_nb_poly.text()) + + # Same process that the RPG process except the start of the RPG class. + # To Grass/wooden + self.sample_name.append("%s" % self.ui.lineEdit_sample_path_2.text()) + self.fieldname_args.append("%s" % self.ui.lineEdit_select_sample_fieldname_3.text()) + self.fieldname_args.append("%s" % self.ui.lineEdit_select_sample_fieldname_4.text()) + self.class_args.append("%s" % self.ui.lineEdit_select_sample_class_3.text()) + self.class_args.append("%s" % self.ui.lineEdit_select_sample_class_4.text()) + self.list_nb_sample.append("%s" % self.ui.lineEdit_select_sample_nb_poly_2.text()) + + # To wooden + self.sample_name.append("%s" % self.ui.lineEdit_sample_path_3.text()) + self.fieldname_args.append("%s" % self.ui.lineEdit_select_sample_fieldname_5.text()) + self.fieldname_args.append("%s" % self.ui.lineEdit_select_sample_fieldname_6.text()) + self.class_args.append("%s" % self.ui.lineEdit_select_sample_class_5.text()) + self.class_args.append("%s" % self.ui.lineEdit_select_sample_class_6.text()) + self.list_nb_sample.append("%s" % self.ui.lineEdit_select_sample_nb_poly_3.text()) + + nb_sample = 3 + + def clear_sample(self): + """ + Function to clear sample record. Clear in the interface and in the memory list. + """ + self.sample_name = [] + self.fieldname_args = [] + self.class_args = [] + self.list_nb_sample = [] + self.rpg_tchek = [] + self.img_sample = [] + + self.ui.lineEdit_sample_path.clear() + self.ui.lineEdit_select_sample_fieldname_1.clear() + self.ui.lineEdit_select_sample_fieldname_2.clear() + self.ui.lineEdit_select_sample_class_1.clear() + self.ui.lineEdit_select_sample_class_2.clear() + self.ui.lineEdit_select_sample_nb_poly.clear() + self.ui.checkBox_RPG.setChecked(False) + self.ui.lineEdit_img_sample.clear() + self.ui.checkBox_img_sample.setChecked(False) + self.ui.plainTextEdit_sample.clear() + self.ui.plainTextEdit_sample.insertPlainText("1 - Végétation non naturelle / Semi-naturelle\n") + self.ui.plainTextEdit_sample.insertPlainText("2 - Herbacés / Ligneux\n") + self.ui.plainTextEdit_sample.insertPlainText("3 - Lingeux mixtes / denses\n") + self.ui.plainTextEdit_sample.insertPlainText("\n") + self.ui.plainTextEdit_sample.insertPlainText("\n") + self.ui.plainTextEdit_sample.insertPlainText("") + + def field_display_1(self): + """ + Function to display fieldname class 1 in the other fieldname class 2 when text changed. + For the simply mode, this is RPG sample. + """ + self.ui.lineEdit_select_sample_fieldname_2.setText("%s" % self.ui.lineEdit_select_sample_fieldname_1.text()) + + def field_display_2(self): + """ + Function to display fieldname class 2 in the other fieldname class 2 when text changed. + For the simply mode, this is RPG sample. + """ + self.ui.lineEdit_select_sample_fieldname_1.setText("%s" % self.ui.lineEdit_select_sample_fieldname_2.text()) + + def field_display_3(self): + """ + For the grass/wooden sample, a function to display fieldname class 1 in the other fieldname class 2 when text changed. + """ + self.ui.lineEdit_select_sample_fieldname_4.setText("%s" % self.ui.lineEdit_select_sample_fieldname_3.text()) + + def field_display_4(self): + """ + For the grass/wooden sample, a function to display fieldname class 2 in the other fieldname class 2 when text changed. + """ + self.ui.lineEdit_select_sample_fieldname_3.setText("%s" % self.ui.lineEdit_select_sample_fieldname_4.text()) + + def field_display_5(self): + """ + For the wooden sample, a function to display fieldname class 1 in the other fieldname class 2 when text changed. + """ + self.ui.lineEdit_select_sample_fieldname_6.setText("%s" % self.ui.lineEdit_select_sample_fieldname_5.text()) + + def field_display_6(self): + """ + For the wooden sample, a function to display fieldname class 2 in the other fieldname class 2 when text changed. + """ + self.ui.lineEdit_select_sample_fieldname_5.setText("%s" % self.ui.lineEdit_select_sample_fieldname_6.text()) + + def activate_level(self): + """ + To activate the first levels with seath method. This is in pushing on the decision tree radio button. + Else it activates the last level to random forest method. + """ + if self.ui.radioButton_s.isChecked() and not self.ui.radioButton_rf.isChecked(): + self.ui.checkBox_classifier_1.setEnabled(True) + self.ui.checkBox_classifier_2.setEnabled(True) + else: + self.ui.checkBox_classifier_1.setEnabled(False) + self.ui.checkBox_classifier_2.setEnabled(False) + self.ui.checkBox_classifier_3.setChecked(True) + + def display_one_level(self): + """ + Function to display fieldnames option to classifier one level + """ + if self.ui.checkBox_classifier_1.isChecked(): + + # Don't checked others checkboxes + self.ui.checkBox_classifier_2.setChecked(False) + self.ui.checkBox_classifier_3.setChecked(False) + + # Display options filednames + self.ui.label_chps_1 = QtWidgets.QLabel(self.ui.tab_3) + self.ui.label_chps_1.setObjectName("label_chps_1") + self.ui.gridLayout_2.addWidget(self.ui.label_chps_1, 10, 0, 2, 2) + self.ui.label_chps_name_1 = QtWidgets.QLabel(self.ui.tab_3) + self.ui.label_chps_name_1.setObjectName("label_chps_name_1") + self.ui.gridLayout_2.addWidget(self.ui.label_chps_name_1, 10, 2, 1, 1) + self.ui.label_chps_type_1 = QtWidgets.QLabel(self.ui.tab_3) + self.ui.label_chps_type_1.setObjectName("label_chps_type_1") + self.ui.gridLayout_2.addWidget(self.ui.label_chps_type_1, 11, 2, 1, 1) + self.ui.lineEdit_fieldname_1 = QtWidgets.QLineEdit(self.ui.tab_3) + self.ui.lineEdit_fieldname_1.setObjectName("lineEdit_fieldname_1") + self.ui.gridLayout_2.addWidget(self.ui.lineEdit_fieldname_1, 10, 3, 1, 1) + self.ui.comboBox_fieldname_1 = QtWidgets.QComboBox(self.ui.tab_3) + self.ui.comboBox_fieldname_1.setObjectName("comboBox_fieldname_1") + self.ui.gridLayout_2.addWidget(self.ui.comboBox_fieldname_1, 11, 3, 1, 1) + + self.ui.lineEdit_fieldname_1.setText(_translate("PHYMOBAT", "NIVEAU_1", None)) + self.ui.comboBox_fieldname_1.addItem("String") + self.ui.comboBox_fieldname_1.addItem("Real") + + self.ui.label_chps_1.setText(_translate("PHYMOBAT", " Champs\n"+" des entités", None)) + self.ui.label_chps_name_1.setText(_translate("PHYMOBAT", "Nom :", None)) + self.ui.label_chps_type_1.setText(_translate("PHYMOBAT", "Type :", None)) + + if not self.ui.checkBox_classifier_1.isChecked(): + # Clear options filednames + try: + self.ui.label_chps_1.deleteLater() + self.ui.label_chps_name_1.deleteLater() + self.ui.label_chps_type_1.deleteLater() + self.ui.lineEdit_fieldname_1.deleteLater() + self.ui.comboBox_fieldname_1.deleteLater() + except AttributeError: + pass + + def display_two_levels(self): + """ + Function to display fieldnames option to classifier two first levels + """ + if self.ui.checkBox_classifier_2.isChecked(): + + # Don't checked others checkboxes + self.ui.checkBox_classifier_1.setChecked(False) + self.ui.checkBox_classifier_3.setChecked(False) + + self.ui.label_chps_2 = QtWidgets.QLabel(self.ui.tab_3) + self.ui.label_chps_2.setObjectName("label_chps_2") + self.ui.gridLayout_2.addWidget(self.ui.label_chps_2, 13, 0, 2, 2) + self.ui.lineEdit_fieldname_12 = QtWidgets.QLineEdit(self.ui.tab_3) + self.ui.lineEdit_fieldname_12.setObjectName("lineEdit_fieldname_12") + self.ui.gridLayout_2.addWidget(self.ui.lineEdit_fieldname_12, 13, 3, 1, 1) + self.ui.lineEdit_fieldname_2 = QtWidgets.QLineEdit(self.ui.tab_3) + self.ui.lineEdit_fieldname_2.setObjectName("lineEdit_fieldname_2") + self.ui.gridLayout_2.addWidget(self.ui.lineEdit_fieldname_2, 13, 4, 1, 1) + self.ui.label_chps_type_2 = QtWidgets.QLabel(self.ui.tab_3) + self.ui.label_chps_type_2.setObjectName("label_chps_type_2") + self.ui.gridLayout_2.addWidget(self.ui.label_chps_type_2, 14, 2, 1, 1) + self.ui.comboBox_fieldname_12 = QtWidgets.QComboBox(self.ui.tab_3) + self.ui.comboBox_fieldname_12.setObjectName("comboBox_fieldname_12") + self.ui.gridLayout_2.addWidget(self.ui.comboBox_fieldname_12, 14, 3, 1, 1) + self.ui.comboBox_fieldname_2 = QtWidgets.QComboBox(self.ui.tab_3) + self.ui.comboBox_fieldname_2.setObjectName("comboBox_fieldname_2") + self.ui.gridLayout_2.addWidget(self.ui.comboBox_fieldname_2, 14, 4, 1, 1) + self.ui.label_chps_name_2 = QtWidgets.QLabel(self.ui.tab_3) + self.ui.label_chps_name_2.setObjectName("label_chps_name_2") + self.ui.gridLayout_2.addWidget(self.ui.label_chps_name_2, 13, 2, 1, 1) + + self.ui.lineEdit_fieldname_12.setText(_translate("PHYMOBAT", "NIVEAU_1", None)) + self.ui.comboBox_fieldname_12.addItem("String") + self.ui.comboBox_fieldname_12.addItem("Real") + self.ui.lineEdit_fieldname_2.setText(_translate("PHYMOBAT", "NIVEAU_2", None)) + self.ui.comboBox_fieldname_2.addItem("String") + self.ui.comboBox_fieldname_2.addItem("Real") + + self.ui.label_chps_type_2.setText(_translate("PHYMOBAT", "Type :", None)) + self.ui.label_chps_2.setText(_translate("PHYMOBAT", " Champs\n"+" des entités", None)) + self.ui.label_chps_name_2.setText(_translate("PHYMOBAT", "Nom :", None)) + + if not self.ui.checkBox_classifier_2.isChecked(): + # Clear options filednames + try: + self.ui.label_chps_2.deleteLater() + self.ui.label_chps_name_2.deleteLater() + self.ui.label_chps_type_2.deleteLater() + self.ui.lineEdit_fieldname_12.deleteLater() + self.ui.comboBox_fieldname_12.deleteLater() + self.ui.lineEdit_fieldname_2.deleteLater() + self.ui.comboBox_fieldname_2.deleteLater() + except AttributeError: + pass + + def display_all_levels(self): + """ + Function to display fieldnames option to launch complete classification + """ + + if self.ui.checkBox_classifier_3.isChecked(): + + # Don't checked others checkboxes + self.ui.checkBox_classifier_1.setChecked(False) + self.ui.checkBox_classifier_2.setChecked(False) + + self.ui.label_chps_name_3 = QtWidgets.QLabel(self.ui.tab_3) + self.ui.label_chps_name_3.setObjectName("label_chps_name_3") + self.ui.gridLayout_2.addWidget(self.ui.label_chps_name_3, 16, 2, 1, 1) + self.ui.label_chps_3 = QtWidgets.QLabel(self.ui.tab_3) + self.ui.label_chps_3.setObjectName("label_chps_3") + self.ui.gridLayout_2.addWidget(self.ui.label_chps_3, 16, 0, 2, 2) + self.ui.label_chps_type_3 = QtWidgets.QLabel(self.ui.tab_3) + self.ui.label_chps_type_3.setObjectName("label_chps_type_3") + self.ui.gridLayout_2.addWidget(self.ui.label_chps_type_3, 17, 2, 1, 1) + self.ui.lineEdit_fieldname_13 = QtWidgets.QLineEdit(self.ui.tab_3) + self.ui.lineEdit_fieldname_13.setObjectName("lineEdit_fieldname_13") + self.ui.gridLayout_2.addWidget(self.ui.lineEdit_fieldname_13, 16, 3, 1, 1) + self.ui.lineEdit_fieldname_23 = QtWidgets.QLineEdit(self.ui.tab_3) + self.ui.lineEdit_fieldname_23.setObjectName("lineEdit_fieldname_23") + self.ui.gridLayout_2.addWidget(self.ui.lineEdit_fieldname_23, 16, 4, 1, 1) + self.ui.lineEdit_fieldname_3 = QtWidgets.QLineEdit(self.ui.tab_3) + self.ui.lineEdit_fieldname_3.setObjectName("lineEdit_fieldname_3") + self.ui.gridLayout_2.addWidget(self.ui.lineEdit_fieldname_3, 16, 5, 1, 1) + self.ui.lineEdit_fieldname_4 = QtWidgets.QLineEdit(self.ui.tab_3) + self.ui.lineEdit_fieldname_4.setObjectName("lineEdit_fieldname_4") + self.ui.gridLayout_2.addWidget(self.ui.lineEdit_fieldname_4, 16, 6, 1, 1) + self.ui.comboBox_fieldname_13 = QtWidgets.QComboBox(self.ui.tab_3) + self.ui.comboBox_fieldname_13.setObjectName("comboBox_fieldname_13") + self.ui.gridLayout_2.addWidget(self.ui.comboBox_fieldname_13, 17, 3, 1, 1) + self.ui.comboBox_fieldname_23 = QtWidgets.QComboBox(self.ui.tab_3) + self.ui.comboBox_fieldname_23.setObjectName("comboBox_fieldname_23") + self.ui.gridLayout_2.addWidget(self.ui.comboBox_fieldname_23, 17, 4, 1, 1) + self.ui.comboBox_fieldname_3 = QtWidgets.QComboBox(self.ui.tab_3) + self.ui.comboBox_fieldname_3.setObjectName("comboBox_fieldname_3") + self.ui.gridLayout_2.addWidget(self.ui.comboBox_fieldname_3, 17, 5, 1, 1) + self.ui.comboBox_fieldname_4 = QtWidgets.QComboBox(self.ui.tab_3) + self.ui.comboBox_fieldname_4.setObjectName("comboBox_fieldname_4") + self.ui.gridLayout_2.addWidget(self.ui.comboBox_fieldname_4, 17, 6, 1, 1) + + self.ui.lineEdit_fieldname_13.setText(_translate("PHYMOBAT", "NIVEAU_1", None)) + self.ui.comboBox_fieldname_13.addItem("String") + self.ui.comboBox_fieldname_13.addItem("Real") + self.ui.lineEdit_fieldname_23.setText(_translate("PHYMOBAT", "NIVEAU_2", None)) + self.ui.comboBox_fieldname_23.addItem("String") + self.ui.comboBox_fieldname_23.addItem("Real") + self.ui.lineEdit_fieldname_3.setText(_translate("PHYMOBAT", "NIVEAU_3", None)) + self.ui.comboBox_fieldname_3.addItem("String") + self.ui.comboBox_fieldname_3.addItem("Real") + self.ui.lineEdit_fieldname_4.setText(_translate("PHYMOBAT", "POURC", None)) + self.ui.comboBox_fieldname_4.addItem("Real") + self.ui.comboBox_fieldname_4.addItem("String") + + self.ui.label_chps_3.setText(_translate("PHYMOBAT", " Champs\n"+" des entités", None)) + self.ui.label_chps_type_3.setText(_translate("PHYMOBAT", "Type :", None)) + self.ui.label_chps_name_3.setText(_translate("PHYMOBAT", "Nom :", None)) + + if not self.ui.checkBox_classifier_3.isChecked(): + # Clear options filednames + try: + self.ui.label_chps_3.deleteLater() + self.ui.label_chps_name_3.deleteLater() + self.ui.label_chps_type_3.deleteLater() + self.ui.lineEdit_fieldname_13.deleteLater() + self.ui.comboBox_fieldname_13.deleteLater() + self.ui.lineEdit_fieldname_23.deleteLater() + self.ui.comboBox_fieldname_23.deleteLater() + self.ui.lineEdit_fieldname_3.deleteLater() + self.ui.comboBox_fieldname_3.deleteLater() + self.ui.lineEdit_fieldname_4.deleteLater() + self.ui.comboBox_fieldname_4.deleteLater() + except AttributeError: + pass + + def ok_button(self): + """ + Function to launch the processing. This function take account : + + - The ``Multi-processing`` check box if the processing has launched with multi process. By default, this is checked. It need a computer with minimum 12Go memory. + - Append a few system value with :func:`get_variable`. + - There are 3 principal check boxes : + - to get number download available images + - for downloading and processing on theia platform + - to compute optimal threshold. + - to compute slope raster + - for classification processing. + """ + + # Start the processus + startTime = time.time() + + # To know if the processing must be launch on several thread + self.mp = Constantes.MULTIPROCESSING_ENABLE if self.ui.checkBox_multiprocess.isChecked() else Constantes.MULTIPROCESSING_DISABLE + + self.get_variable() # Append a few system value + vs = 0 # Variable to launch VHRS texture processing + dd = 0 # Variable to launch image downloading + ok = 1 # Variable to verify informations -> 0 not ok, 1 ok + + if self.current_mode == Constantes.EXPERT_MODE: + # if download check box is checked only + if not self.ui.checkBox_listing.isChecked() and self.ui.checkBox_download.isChecked(): + self.ui.checkBox_listing.setChecked(True) + + if ok == 1: + # Compute a output slope raster + if self.ui.checkBox_MNT.isChecked(): + + self.i_slope() + + # Downloading and processing on theia platform + # A check box to get number download available images + if self.ui.checkBox_listing.isChecked(): + + if self.ui.checkBox_download.isChecked(): + # To launch the downloading + dd = 1 + + self.i_download(dd) # Launch image listing and downloading if dd = 1 + self.set_variable() # to write in the line edit about number download available images + + # Check box to launch the image processing + if self.ui.checkBox_processing.isChecked(): + # Another check box to launch VHRS texture processing. If checked, vs = 1. + if self.ui.checkBox_VHRS.isChecked(): + vs = 1 + self.i_images_processing(vs) # function to launch the image processing + + # To launch the image processing without dowloading but with the images in a main folder + # Without internet connection + if not self.ui.checkBox_download.isChecked() and self.ui.checkBox_processing.isChecked(): + + # Launch pre-processing without downloading + self.i_glob() + # Another check box to launch VHRS texture processing. If checked, vs = 1. + if self.ui.checkBox_VHRS.isChecked(): + vs = 1 + self.i_images_processing(vs) # function to launch the image processing + + # To launch texture processing only + if not self.ui.checkBox_listing.isChecked() and not self.ui.checkBox_processing.isChecked() and self.ui.checkBox_VHRS.isChecked(): + + self.i_vhrs() + + # Compute optimal threshold + if self.ui.checkBox_threshold.isChecked(): + + if self.ui.radioButton_rf.isChecked(): + self.i_sample_rf() + elif self.ui.radioButton_s.isChecked(): + self.i_sample() + + # Classification processing + if self.ui.radioButton_rf.isChecked(): + + if self.ui.checkBox_classifier_3.isChecked(): + + self.out_fieldname_carto = self.out_fieldname_carto + self.out_fieldtype_carto = self.out_fieldtype_carto + self.i_classifier_rf() + self.i_validate() + + elif self.ui.radioButton_s.isChecked(): + + if self.ui.checkBox_classifier_1.isChecked() : + + self.out_fieldname_carto = self.out_fieldname_carto[:3] + self.out_fieldtype_carto = self.out_fieldtype_carto[:3] + self.i_classifier_s() + self.i_validate() + + if self.ui.checkBox_classifier_2.isChecked() : + + self.out_fieldname_carto = self.out_fieldname_carto[:4] + self.out_fieldtype_carto = self.out_fieldtype_carto[:4] + self.i_classifier_s() + self.i_validate() + + if self.ui.checkBox_classifier_3.isChecked(): + + self.out_fieldname_carto = self.out_fieldname_carto + self.out_fieldtype_carto = self.out_fieldtype_carto + self.i_classifier_s() + self.i_validate() + + if self.current_mode == Constantes.SIMPLE_MODE: + + # Compute a output slope raster - self.ui.lineEdit_area_path.setText(pr.find("Area_path").text) - - if self.mode == 1: - if pr.find("Images_available").text == '1': - self.ui.checkBox_listing.setChecked(True) - else: - self.ui.checkBox_listing.setChecked(False) - if pr.find("Download").text == '1': - self.ui.checkBox_download.setChecked(True) - else: - self.ui.checkBox_download.setChecked(False) - - try: - self.ui.lineEdit_user.setText(pr.find("Username").text) - self.ui.lineEdit_password.setText(pr.find("Password").text) - except: - print('Not username or password Theia') - - self.f_proxy() - try: - pp = pr.find("Proxy[@id='Proxy']") - self.w_proxy.w_proxy.lineEdit_proxy.setText(pp.find("Proxy_adress").text) - try: - self.w_proxy.w_proxy.lineEdit_password_proxy.setText(pp.find("Proxy_login").text) - except TypeError: - pass - try: - self.w_proxy.w_proxy.lineEdit_login_proxy.setText(pp.find("Proxy_password").text) - except TypeError: - pass - self.w_proxy.id_proxy() - except AttributeError: - print('Not proxy') - self.w_proxy.close_window() - - if self.mode == 1: - if pr.find("Img_processing").text == '1': - self.ui.checkBox_processing.setChecked(True) - else: - self.ui.checkBox_processing.setChecked(False) - if pr.find("VHRS_checked").text == '1': - self.ui.checkBox_VHRS.setChecked(True) - else: - self.ui.checkBox_VHRS.setChecked(False) - - try: - self.ui.lineEdit_VHRS.setText(pr.find("VHRS").text) - except: - print('Not VHRS image') - - if self.mode == 1: - if pr.find("MNT_checked").text == '1': - self.ui.checkBox_MNT.setChecked(True) - else: - self.ui.checkBox_MNT.setChecked(False) - - try: - self.ui.lineEdit_MNT.setText(pr.find("MNT").text) - except: - print('Not MNT') - - ps = tree.find("Tab[@id='Processing_sample']") - if self.mode == 1: - try: - for sple_n in ps.iter("Sample"): - self.ui.lineEdit_sample_path.setText(sple_n.find("Sample_path").text) - self.ui.lineEdit_select_sample_fieldname_1.setText(sple_n.find("Fieldname_1").text) - self.ui.lineEdit_select_sample_fieldname_2.setText(sple_n.find("Fieldname_2").text) - self.ui.lineEdit_select_sample_class_1.setText(sple_n.find("Classname_1").text) - self.ui.lineEdit_select_sample_class_2.setText(sple_n.find("Classname_2").text) - self.ui.lineEdit_select_sample_nb_poly.setText(sple_n.find("Nb_polygones").text) - # Launch rpg method if the box is checked and if the shapefile hasn't go through rpg method (with prefix MONO_) - if sple_n.find("RPG").text == '1' and os.path.split(sple_n.find("Sample_path").text)[1][:5] != 'MONO_': - self.ui.checkBox_RPG.setChecked(True) - try: - if sple_n.find("Img_sample").text != "": - self.ui.lineEdit_img_sample.setText(sple_n.find("Img_sample").text) - self.ui.checkBox_img_sample.setChecked(True) - except: - print('Not sample raster only !') - self.add_sample() - except: - print('Not sample') - elif self.mode ==0: - # RPG - sple_n = ps[0] - self.ui.lineEdit_sample_path.setText(sple_n.find("Sample_path").text) - self.ui.lineEdit_select_sample_fieldname_1.setText(sple_n.find("Fieldname_1").text) - self.ui.lineEdit_select_sample_fieldname_2.setText(sple_n.find("Fieldname_2").text) - self.ui.lineEdit_select_sample_class_1.setText(sple_n.find("Classname_1").text) - self.ui.lineEdit_select_sample_class_2.setText(sple_n.find("Classname_2").text) - self.ui.lineEdit_select_sample_nb_poly.setText(sple_n.find("Nb_polygones").text) - - # To Grass/wooden - sple_n = ps[1] - self.ui.lineEdit_sample_path_2.setText(sple_n.find("Sample_path").text) - self.ui.lineEdit_select_sample_fieldname_3.setText(sple_n.find("Fieldname_1").text) - self.ui.lineEdit_select_sample_fieldname_4.setText(sple_n.find("Fieldname_2").text) - self.ui.lineEdit_select_sample_class_3.setText(sple_n.find("Classname_1").text) - self.ui.lineEdit_select_sample_class_4.setText(sple_n.find("Classname_2").text) - self.ui.lineEdit_select_sample_nb_poly_2.setText(sple_n.find("Nb_polygones").text) - - # To wooden - sple_n = ps[2] - self.ui.lineEdit_sample_path_3.setText(sple_n.find("Sample_path").text) - self.ui.lineEdit_select_sample_fieldname_5.setText(sple_n.find("Fieldname_1").text) - self.ui.lineEdit_select_sample_fieldname_6.setText(sple_n.find("Fieldname_2").text) - self.ui.lineEdit_select_sample_class_5.setText(sple_n.find("Classname_1").text) - self.ui.lineEdit_select_sample_class_6.setText(sple_n.find("Classname_2").text) - self.ui.lineEdit_select_sample_nb_poly_3.setText(sple_n.find("Nb_polygones").text) - - if self.mode == 1: - if ps.find("Threshold_checked").text == '1': - self.ui.checkBox_threshold.setChecked(True) - else: - self.ui.checkBox_threshold.setChecked(False) - - c = tree.find("Tab[@id='Classification']") - try: - self.ui.lineEdit_segmentation.setText(c.find("Segmentation_path").text) - except: - print('Not segmentation') - try: - self.ui.lineEdit_output.setText(c.find("Output_path").text) - except: - print('Not output file') - if self.mode == 1: - if len(c) == 5: - self.ui.checkBox_classifier_1.setChecked(True) - self.ui.lineEdit_fieldname_1.setText(c.find("Output_fieldname_1").text) - index_fieldname_1 = self.ui.comboBox_fieldname_1.findText(c.find("Output_type_1").text) - self.ui.comboBox_fieldname_1.setCurrentIndex(index_fieldname_1) - elif len(c) == 7: - self.ui.checkBox_classifier_2.setChecked(True) - self.ui.lineEdit_fieldname_12.setText(c.find("Output_fieldname_1").text) - self.ui.lineEdit_fieldname_2.setText(c.find("Output_fieldname_2").text) - index_fieldname_12 = self.ui.comboBox_fieldname_12.findText(c.find("Output_type_1").text) - self.ui.comboBox_fieldname_12.setCurrentIndex(index_fieldname_12) - index_fieldname_2 = self.ui.comboBox_fieldname_2.findText(c.find("Output_type_2").text) - self.ui.comboBox_fieldname_2.setCurrentIndex(index_fieldname_2) - elif len(c) == 11: - self.ui.checkBox_classifier_3.setChecked(True) - self.ui.lineEdit_fieldname_13.setText(c.find("Output_fieldname_1").text) - self.ui.lineEdit_fieldname_23.setText(c.find("Output_fieldname_2").text) - self.ui.lineEdit_fieldname_3.setText(c.find("Output_fieldname_3").text) - self.ui.lineEdit_fieldname_4.setText(c.find("Output_fieldname_4").text) - index_fieldname_13 = self.ui.comboBox_fieldname_13.findText(c.find("Output_type_1").text) - self.ui.comboBox_fieldname_13.setCurrentIndex(index_fieldname_13) - index_fieldname_23 = self.ui.comboBox_fieldname_23.findText(c.find("Output_type_2").text) - self.ui.comboBox_fieldname_23.setCurrentIndex(index_fieldname_23) - index_fieldname_3 = self.ui.comboBox_fieldname_3.findText(c.find("Output_type_3").text) - self.ui.comboBox_fieldname_3.setCurrentIndex(index_fieldname_3) - index_fieldname_4 = self.ui.comboBox_fieldname_4.findText(c.find("Output_type_4").text) - self.ui.comboBox_fieldname_4.setCurrentIndex(index_fieldname_4) - - # Classification mode - if c.find("Classification_method").text == '1': - self.ui.radioButton_rf.setChecked(True) - else: - self.ui.radioButton_s.setChecked(True) - - def save_backup(self): - """ - Function to save input text in every fields. The output file must be a XML file. - """ - - out_backup = QtWidgets.QFileDialog.getSaveFileName(self, "Save backup", os.getcwd(), '*.xml')[0] + if self.path_mnt != "": + self.i_slope() + + # Save the sample features + self.add_sample() + + # Look at if the the images has been already downloaded, download them otherwise + # Commenté pour ne traiter qu'une image + self.i_download() + + # function to launch the image processing + self.i_images_processing() - # if the user has forgotten to put .shp at the end of the output xml - if out_backup[-4:] != '.xml': - out_backup = out_backup + '.xml' - - root = ET.Element("Data_filled") - - if self.ui.checkBox_multiprocess.isChecked(): - ET.SubElement(root, "Multi_process", type = "int").text = str(1) - else: - ET.SubElement(root, "Multi_process", type = "int").text = str(0) - - doc = ET.SubElement(root, "Tab", id="Processing_raster") - ET.SubElement(doc, "Principal_folder", type = "str").text = "%s" % self.ui.lineEdit_principal_folder.text() - if self.mode == 1: - ET.SubElement(doc, "Captor", type = "str").text = "%s" % self.ui.comboBox_captor.currentText() - else: - ET.SubElement(doc, "Captor", type = "str").text = "Landsat" - ET.SubElement(doc, "Year_images", type = "str").text = "%s" % self.ui.lineEdit_year_images.text() - ET.SubElement(doc, "Area_path", type = "str").text = "%s" % self.ui.lineEdit_area_path.text() - - if self.mode == 1: - if self.ui.checkBox_listing.isChecked(): - ET.SubElement(doc, "Images_available", type = "int").text = str(1) - else: - ET.SubElement(doc, "Images_available", type = "int").text = str(0) - if self.ui.checkBox_download.isChecked(): - ET.SubElement(doc, "Download", type = "int").text = str(1) - else: - ET.SubElement(doc, "Download", type = "int").text = str(0) - else: - ET.SubElement(doc, "Images_available", type = "int").text = str(0) - ET.SubElement(doc, "Download", type = "int").text = str(0) - - ET.SubElement(doc, "Username", type = "str").text = "%s" % self.ui.lineEdit_user.text() - ET.SubElement(doc, "Password", type = "str").text = "%s" % self.ui.lineEdit_password.text() - if self.w_proxy is None: - sub_proxy = ET.SubElement(doc, "Proxy", id="No_proxy") - ET.SubElement(sub_proxy, "Proxy_adress", type = "str").text = "" - ET.SubElement(sub_proxy, "Proxy_login", type = "str").text = "" - ET.SubElement(sub_proxy, "Proxy_password", type = "str").text = "" - elif self.w_proxy.proxy == "": - sub_proxy = ET.SubElement(doc, "Proxy", id="No_proxy") - ET.SubElement(sub_proxy, "Proxy_adress", type = "str").text = "" - ET.SubElement(sub_proxy, "Proxy_login", type = "str").text = "" - ET.SubElement(sub_proxy, "Proxy_password", type = "str").text = "" - else: - sub_proxy = ET.SubElement(doc, "Proxy", id="Proxy") - ET.SubElement(sub_proxy, "Proxy_adress", type = "str").text = "%s" % self.w_proxy.proxy - ET.SubElement(sub_proxy, "Proxy_login", type = "str").text = "%s" % self.w_proxy.login_proxy - ET.SubElement(sub_proxy, "Proxy_password", type = "str").text = "%s" % self.w_proxy.password_proxy - - if self.mode == 1: - if self.ui.checkBox_processing.isChecked(): - ET.SubElement(doc, "Img_processing", type = "int").text = str(1) - else: - ET.SubElement(doc, "Img_processing", type = "int").text = str(0) - - if self.ui.checkBox_VHRS.isChecked(): - ET.SubElement(doc, "VHRS_checked", type = "int").text = str(1) - else: - ET.SubElement(doc, "VHRS_checked", type = "int").text = str(0) - else: - ET.SubElement(doc, "Img_processing", type = "int").text = str(1) - ET.SubElement(doc, "VHRS_checked", type = "int").text = str(1) - - ET.SubElement(doc, "VHRS", type = "str").text = "%s" % self.ui.lineEdit_VHRS.text() - - if self.mode == 1: - if self.ui.checkBox_MNT.isChecked(): - ET.SubElement(doc, "MNT_checked", type = "int").text = str(1) - else: - ET.SubElement(doc, "MNT_checked", type = "int").text = str(0) - else: - if "%s" % self.ui.lineEdit_MNT.text() != '': - ET.SubElement(doc, "MNT_checked", type = "int").text = str(1) - else: - ET.SubElement(doc, "MNT_checked", type = "int").text = str(0) - - ET.SubElement(doc, "MNT", type = "str").text = "%s" % self.ui.lineEdit_MNT.text() - - doc = ET.SubElement(root, "Tab", id="Processing_sample") - if self.mode == 1: - for sa in range(len(self.sample_name)): - sub_doc = ET.SubElement(doc, "Sample", id="Sample_" + str(sa)) - ET.SubElement(sub_doc, "Sample_path", type = "str").text = self.sample_name[sa] - ET.SubElement(sub_doc, "Fieldname_1", type = "str").text = self.fieldname_args[2*sa] - ET.SubElement(sub_doc, "Fieldname_2", type = "str").text = self.fieldname_args[2*sa+1] - ET.SubElement(sub_doc, "Classname_1", type = "str").text = self.class_args[2*sa] - ET.SubElement(sub_doc, "Classname_2", type = "str").text = self.class_args[2*sa+1] - ET.SubElement(sub_doc, "Nb_polygones", type = "str").text = self.list_nb_sample[sa] - ET.SubElement(sub_doc, "RPG", type = "int").text = str(self.rpg_tchek[sa]) - try: - # To enter a sample raster if the first tab doesn't launch before - if self.img_sample[sa] == 1: - ET.SubElement(sub_doc, "Img_sample", type = "str").text = self.raster_path[sa] - except: - print('Not sample raster only !') - else: - # RPG - sub_doc = ET.SubElement(doc, "Sample", id="Sample_0") - ET.SubElement(sub_doc, "Sample_path", type = "str").text = "%s" % self.ui.lineEdit_sample_path.text() - ET.SubElement(sub_doc, "Fieldname_1", type = "str").text = "%s" % self.ui.lineEdit_select_sample_fieldname_1.text() - ET.SubElement(sub_doc, "Fieldname_2", type = "str").text = "%s" % self.ui.lineEdit_select_sample_fieldname_2.text() - ET.SubElement(sub_doc, "Classname_1", type = "str").text = "%s" % self.ui.lineEdit_select_sample_class_1.text() - ET.SubElement(sub_doc, "Classname_2", type = "str").text = "%s" % self.ui.lineEdit_select_sample_class_2.text() - ET.SubElement(sub_doc, "Nb_polygones", type = "str").text = "%s" % self.ui.lineEdit_select_sample_nb_poly.text() - ET.SubElement(sub_doc, "RPG", type = "int").text = str(1) - - # To Grass/wooden - sub_doc = ET.SubElement(doc, "Sample", id="Sample_1") - ET.SubElement(sub_doc, "Sample_path", type = "str").text = "%s" % self.ui.lineEdit_sample_path_2.text() - ET.SubElement(sub_doc, "Fieldname_1", type = "str").text = "%s" % self.ui.lineEdit_select_sample_fieldname_3.text() - ET.SubElement(sub_doc, "Fieldname_2", type = "str").text = "%s" % self.ui.lineEdit_select_sample_fieldname_4.text() - ET.SubElement(sub_doc, "Classname_1", type = "str").text = "%s" % self.ui.lineEdit_select_sample_class_3.text() - ET.SubElement(sub_doc, "Classname_2", type = "str").text = "%s" % self.ui.lineEdit_select_sample_class_4.text() - ET.SubElement(sub_doc, "Nb_polygones", type = "str").text = "%s" % self.ui.lineEdit_select_sample_nb_poly_2.text() - ET.SubElement(sub_doc, "RPG", type = "int").text = str(0) - - # To wooden - sub_doc = ET.SubElement(doc, "Sample", id="Sample_2") - ET.SubElement(sub_doc, "Sample_path", type = "str").text = "%s" % self.ui.lineEdit_sample_path_3.text() - ET.SubElement(sub_doc, "Fieldname_1", type = "str").text = "%s" % self.ui.lineEdit_select_sample_fieldname_5.text() - ET.SubElement(sub_doc, "Fieldname_2", type = "str").text = "%s" % self.ui.lineEdit_select_sample_fieldname_6.text() - ET.SubElement(sub_doc, "Classname_1", type = "str").text = "%s" % self.ui.lineEdit_select_sample_class_5.text() - ET.SubElement(sub_doc, "Classname_2", type = "str").text = "%s" % self.ui.lineEdit_select_sample_class_6.text() - ET.SubElement(sub_doc, "Nb_polygones", type = "str").text = "%s" % self.ui.lineEdit_select_sample_nb_poly_3.text() - ET.SubElement(sub_doc, "RPG", type = "int").text = str(0) - - if self.mode == 1: - if self.ui.checkBox_threshold.isChecked(): - ET.SubElement(doc, "Threshold_checked", type = "int").text = str(1) - else: - ET.SubElement(doc, "Threshold_checked", type = "int").text = str(0) - else: - ET.SubElement(doc, "Threshold_checked", type = "int").text = str(1) - - doc = ET.SubElement(root, "Tab", id="Classification") - ET.SubElement(doc, "Segmentation_path", type = "str").text = "%s" % self.ui.lineEdit_segmentation.text() - ET.SubElement(doc, "Output_path", type = "str").text = "%s" % self.ui.lineEdit_output.text() - - if self.mode == 1: - - if self.ui.checkBox_classifier_1.isChecked(): - ET.SubElement(doc, "Output_fieldname_1", type = "str").text = "%s" % self.ui.lineEdit_fieldname_1.text() - ET.SubElement(doc, "Output_type_1", type = "str").text = "%s" % self.ui.comboBox_fieldname_1.currentText() - - if self.ui.checkBox_classifier_2.isChecked(): - ET.SubElement(doc, "Output_fieldname_1", type = "str").text = "%s" % self.ui.lineEdit_fieldname_12.text() - ET.SubElement(doc, "Output_type_1", type = "str").text = "%s" % self.ui.comboBox_fieldname_12.currentText() - ET.SubElement(doc, "Output_fieldname_2", type = "str").text = "%s" % self.ui.lineEdit_fieldname_2.text() - ET.SubElement(doc, "Output_type_2", type = "str").text = "%s" % self.ui.comboBox_fieldname_2.currentText() - - if self.ui.checkBox_classifier_3.isChecked(): - ET.SubElement(doc, "Output_fieldname_1", type = "str").text = "%s" % self.ui.lineEdit_fieldname_13.text() - ET.SubElement(doc, "Output_type_1", type = "str").text = "%s" % self.ui.comboBox_fieldname_13.currentText() - ET.SubElement(doc, "Output_fieldname_2", type = "str").text = "%s" % self.ui.lineEdit_fieldname_23.text() - ET.SubElement(doc, "Output_type_2", type = "str").text = "%s" % self.ui.comboBox_fieldname_23.currentText() - ET.SubElement(doc, "Output_fieldname_3", type = "str").text = "%s" % self.ui.lineEdit_fieldname_3.text() - ET.SubElement(doc, "Output_type_3", type = "str").text = "%s" % self.ui.comboBox_fieldname_3.currentText() - ET.SubElement(doc, "Output_fieldname_4", type = "str").text = "%s" % self.ui.lineEdit_fieldname_4.text() - ET.SubElement(doc, "Output_type_4", type = "str").text = "%s" % self.ui.comboBox_fieldname_4.currentText() - - # Classification mode - if self.ui.radioButton_rf.isChecked(): - ET.SubElement(doc, "Classification_method", type = "int").text = str(1) - elif self.ui.radioButton_s.isChecked(): - ET.SubElement(doc, "Classification_method", type = "int").text = str(0) - else: - ET.SubElement(doc, "Output_fieldname_1", type = "str").text = "NIVEAU_1" - ET.SubElement(doc, "Output_type_1", type = "str").text = "String" - ET.SubElement(doc, "Output_fieldname_2", type = "str").text = "NIVEAU_2" - ET.SubElement(doc, "Output_type_2", type = "str").text = "String" - ET.SubElement(doc, "Output_fieldname_3", type = "str").text = "NIVEAU_3" - ET.SubElement(doc, "Output_type_3", type = "str").text = "String" - ET.SubElement(doc, "Output_fieldname_4", type = "str").text = "POURC" - ET.SubElement(doc, "Output_type_4", type = "str").text = "Real" - ET.SubElement(doc, "Classification_method", type = "int").text = str(1) - - tree = ET.ElementTree(root) - # Write in a xml file - tree.write(str(out_backup), encoding="UTF-8",xml_declaration=True, pretty_print=True) - - def about_PHYMOBA(self): - """ - Function to open a new window "About PHYMOBAT" - """ - if self.apropos is None: - self.apropos = MyPopup_about() - self.apropos.show() - - def help_tools(self): - """ - Function to open html help - """ - webbrowser.open('file://' + os.getcwd() + '/Documentation/methode_tuto.html#tutoriels-interface') - - def mode_simpli(self): - """ - Function to open a new window in simple mode "PHYMOBATs" - """ - if self.simpli is None: - print ("Simplify mode") - self.close() - self.simpli = PHYMOBAT(mode = 0) - - self.simpli.show() - - def mode_expert(self): - """ - Function to open a new window in expert mode "PHYMOBATe" - """ - if self.expert is None: - print ("Expert mode") - self.close() - self.expert = PHYMOBAT(mode = 1) - - self.expert.show() - - def forget_study_area(self): - """ - Function to open a new window 'Alert' because user forgotten to declare study area. - """ - if self.w_study_area is None: - self.w_study_area = MyPopup_warming_study_area() - self.w_study_area.show() - - def forget_raster_sample(self): - """ - Function to open a new window 'Alert' because user forgotten to declare rasters or samples. - """ - if self.w_forget is None: - self.w_forget = MyPopup_warming_forgetting() - self.w_forget.show() - - def close_button(self): - """ - Function to close the interface. - """ - self.close() + # To launch texture processing only + self.i_vhrs() -class MyPopup_about(QtWidgets.QWidget): - """ - Popup to display "About PHYMOBAT". In this windows, it prints informations on the processing, license - and version. - """ - def __init__(self, parent=None): - QtWidgets.QWidget.__init__(self, parent) - self.prop = Ui_About() - self.prop.setupUi(self) - - self.prop.close_newWindow.clicked.connect(self.close_window) - - def close_window(self): - """ - Function to close the "A propos PHYMOBAT". - """ - self.close() - -class MyPopup_warming_study_area(QtWidgets.QWidget): - """ - Popup to display a message to say there isn't declared study area file. - """ - def __init__(self, parent=None): - QtWidgets.QWidget.__init__(self, parent) - self.w_study_a = Ui_Warming_study_area() - self.w_study_a.setupUi(self) - - self.w_study_a.pushButton_ok_window_warning_study_area.clicked.connect(self.close_window) - - def close_window(self): - """ - Function to close the popup. - """ - self.close() - -class MyPopup_warming_forgetting(QtWidgets.QWidget): - """ - Popup to display a message to tell you if you fogotten to enter a raster or a sample. - """ - def __init__(self, parent=None): - QtWidgets.QWidget.__init__(self, parent) - self.w_forget = Ui_Warming_forgetting() - self.w_forget.setupUi(self) - - self.w_forget.pushButton_ok_forget.clicked.connect(self.close_window) - - def close_window(self): - """ - Function to close the popup. - """ - self.close() - -class MyPopup_proxy_window(QtWidgets.QWidget): - """ - Popup to display a message to tell you if you fogotten to enter a raster or a sample. - """ - def __init__(self, parent=None): - QtWidgets.QWidget.__init__(self, parent) - self.w_proxy = Ui_Proxy_window() - self.w_proxy.setupUi(self) - - # Proxy ID - self.proxy = "" - self.login_proxy = "" - self.password_proxy = "" - - # Connect Apply|Close button - self.w_proxy.buttonBox_proxy.button(QtWidgets.QDialogButtonBox.Close).clicked.connect(self.close_window) - self.w_proxy.buttonBox_proxy.button(QtWidgets.QDialogButtonBox.Apply).clicked.connect(self.id_proxy) - - def id_proxy(self): - """ - Function to use input proxy id - """ - self.login_proxy = "%s" % self.w_proxy.lineEdit_login_proxy.text() - self.password_proxy = "%s" % self.w_proxy.lineEdit_password_proxy.text() - self.proxy = "%s" % self.w_proxy.lineEdit_proxy.text() - - def close_window(self): - """ - Function to close the popup. - """ - self.close() - + # Compute optimal threshold + self.i_sample_rf() + + # Classification processing + self.out_fieldname_carto = self.out_fieldname_carto + self.out_fieldtype_carto = self.out_fieldtype_carto + self.i_classifier_rf() + self.i_validate() + + # Clear variables after processing + #self.clear_sample() + self.out_fieldname_carto = ['ID', 'AREA'] + self.out_fieldtype_carto = [ogr.OFTString, ogr.OFTReal] + # Images after processing images + self.out_ndvistats_folder_tab = defaultdict(list) + + Processing.__init__(self)# Initialize variable without to close and launch again the application + + # End of the processus + endTime = time.time() # Tps : Terminé + self.logger.info('...........' + ' Outputted to File in ' + str(endTime - startTime) + ' secondes') + nb_day_processing = int(time.strftime('%d', time.gmtime(endTime - startTime))) - 1 + self.logger.info("That is, " + str(nb_day_processing) + ' day(s) ' + time.strftime('%Hh %Mmin%S', time.gmtime(endTime - startTime))) + + def open_backup(self, test=None): + """ + Function to load input text in every fields. The input file must be a XML file. + """ + if test is None : + in_backup = QtWidgets.QFileDialog.getOpenFileName(self, "Open backup", os.getcwd(), '*.xml')[0] + else : + in_backup = test + + if in_backup != None and len(in_backup) > 0 : + + # Parse the xml file if the user choose a file + tree = ET.parse(str(in_backup)) + + if tree.find("Multi_process").text == '1': + self.ui.checkBox_multiprocess.setChecked(True) + else: + self.ui.checkBox_multiprocess.setChecked(False) + + pr = tree.find("Tab[@id='Processing_raster']") + + try: + self.ui.lineEdit_principal_folder.setText(pr.find("Principal_folder").text) + except: + self.info.debug('Not principal folder') + + if self.current_mode == Constantes.EXPERT_MODE: + index_captor = self.ui.comboBox_captor.findText(pr.find("Captor").text) # To find combo box index + self.ui.comboBox_captor.setCurrentIndex(index_captor) + + try: + self.ui.lineEdit_year_images.setText(pr.find("Year_images").text) + except: + self.logger.debug('Not year images') + + self.ui.lineEdit_area_path.setText(pr.find("Area_path").text) + + if self.current_mode == Constantes.EXPERT_MODE: + if pr.find("Images_available").text == '1': + self.ui.checkBox_listing.setChecked(True) + else: + self.ui.checkBox_listing.setChecked(False) + if pr.find("Download").text == '1': + self.ui.checkBox_download.setChecked(True) + else: + self.ui.checkBox_download.setChecked(False) + + try: + self.ui.lineEdit_user.setText(pr.find("Username").text) + self.ui.lineEdit_password.setText(pr.find("Password").text) + except: + self.logger.debug('Not username or password Theia') + + self.f_proxy() + try: + pp = pr.find("Proxy[@id='Proxy']") + self.w_proxy.w_proxy.lineEdit_proxy.setText(pp.find("Proxy_adress").text) + try: + self.w_proxy.w_proxy.lineEdit_password_proxy.setText(pp.find("Proxy_login").text) + except TypeError: + pass + try: + self.w_proxy.w_proxy.lineEdit_login_proxy.setText(pp.find("Proxy_password").text) + except TypeError: + pass + self.w_proxy.id_proxy() + except AttributeError: + self.logger.debug('Not proxy') + self.w_proxy.close_window() + + if self.current_mode == Constantes.EXPERT_MODE: + if pr.find("Img_processing").text == '1': + self.ui.checkBox_processing.setChecked(True) + else: + self.ui.checkBox_processing.setChecked(False) + if pr.find("VHRS_checked").text == '1': + self.ui.checkBox_VHRS.setChecked(True) + else: + self.ui.checkBox_VHRS.setChecked(False) + + try: + self.ui.lineEdit_VHRS.setText(pr.find("VHRS").text) + except: + self.logger.debug('Not VHRS image') + + if self.current_mode == Constantes.EXPERT_MODE: + if pr.find("MNT_checked").text == '1': + self.ui.checkBox_MNT.setChecked(True) + else: + self.ui.checkBox_MNT.setChecked(False) + + try: + self.ui.lineEdit_MNT.setText(pr.find("MNT").text) + except: + self.logger.debug('Not MNT') + + ps = tree.find("Tab[@id='Processing_sample']") + if self.current_mode == Constantes.EXPERT_MODE: + try: + for sple_n in ps.iter("Sample"): + self.ui.lineEdit_sample_path.setText(sple_n.find("Sample_path").text) + self.ui.lineEdit_select_sample_fieldname_1.setText(sple_n.find("Fieldname_1").text) + self.ui.lineEdit_select_sample_fieldname_2.setText(sple_n.find("Fieldname_2").text) + self.ui.lineEdit_select_sample_class_1.setText(sple_n.find("Classname_1").text) + self.ui.lineEdit_select_sample_class_2.setText(sple_n.find("Classname_2").text) + self.ui.lineEdit_select_sample_nb_poly.setText(sple_n.find("Nb_polygones").text) + # Launch rpg method if the box is checked and if the shapefile hasn't go through rpg method (with prefix MONO_) + if sple_n.find("RPG").text == '1' and os.path.split(sple_n.find("Sample_path").text)[1][:5] != 'MONO_': + self.ui.checkBox_RPG.setChecked(True) + try: + if sple_n.find("Img_sample").text != "": + self.ui.lineEdit_img_sample.setText(sple_n.find("Img_sample").text) + self.ui.checkBox_img_sample.setChecked(True) + except: + self.logger.debug('Not sample raster only !') + + self.add_sample() + except: + self.logger.debug('Not sample') + + elif self.current_mode == Constantes.SIMPLE_MODE: + # RPG + sple_n = ps[0] + self.ui.lineEdit_sample_path.setText(sple_n.find("Sample_path").text) + self.ui.lineEdit_select_sample_fieldname_1.setText(sple_n.find("Fieldname_1").text) + self.ui.lineEdit_select_sample_fieldname_2.setText(sple_n.find("Fieldname_2").text) + self.ui.lineEdit_select_sample_class_1.setText(sple_n.find("Classname_1").text) + self.ui.lineEdit_select_sample_class_2.setText(sple_n.find("Classname_2").text) + self.ui.lineEdit_select_sample_nb_poly.setText(sple_n.find("Nb_polygones").text) + + # To Grass/wooden + sple_n = ps[1] + self.ui.lineEdit_sample_path_2.setText(sple_n.find("Sample_path").text) + self.ui.lineEdit_select_sample_fieldname_3.setText(sple_n.find("Fieldname_1").text) + self.ui.lineEdit_select_sample_fieldname_4.setText(sple_n.find("Fieldname_2").text) + self.ui.lineEdit_select_sample_class_3.setText(sple_n.find("Classname_1").text) + self.ui.lineEdit_select_sample_class_4.setText(sple_n.find("Classname_2").text) + self.ui.lineEdit_select_sample_nb_poly_2.setText(sple_n.find("Nb_polygones").text) + + # To wooden + sple_n = ps[2] + self.ui.lineEdit_sample_path_3.setText(sple_n.find("Sample_path").text) + self.ui.lineEdit_select_sample_fieldname_5.setText(sple_n.find("Fieldname_1").text) + self.ui.lineEdit_select_sample_fieldname_6.setText(sple_n.find("Fieldname_2").text) + self.ui.lineEdit_select_sample_class_5.setText(sple_n.find("Classname_1").text) + self.ui.lineEdit_select_sample_class_6.setText(sple_n.find("Classname_2").text) + self.ui.lineEdit_select_sample_nb_poly_3.setText(sple_n.find("Nb_polygones").text) + + if self.current_mode == Constantes.EXPERT_MODE: + if ps.find("Threshold_checked").text == '1': + self.ui.checkBox_threshold.setChecked(True) + else: + self.ui.checkBox_threshold.setChecked(False) + + c = tree.find("Tab[@id='Classification']") + + try: + self.ui.lineEdit_segmentation.setText(c.find("Segmentation_path").text) + except: + self.logger.debug('Not segmentation') + + try: + self.ui.lineEdit_output.setText(c.find("Output_path").text) + except: + self.logger.debug('Not output file') + + if self.current_mode == Constantes.EXPERT_MODE: + if len(c) == 5: + self.ui.checkBox_classifier_1.setChecked(True) + self.ui.lineEdit_fieldname_1.setText(c.find("Output_fieldname_1").text) + index_fieldname_1 = self.ui.comboBox_fieldname_1.findText(c.find("Output_type_1").text) + self.ui.comboBox_fieldname_1.setCurrentIndex(index_fieldname_1) + elif len(c) == 7: + self.ui.checkBox_classifier_2.setChecked(True) + self.ui.lineEdit_fieldname_12.setText(c.find("Output_fieldname_1").text) + self.ui.lineEdit_fieldname_2.setText(c.find("Output_fieldname_2").text) + index_fieldname_12 = self.ui.comboBox_fieldname_12.findText(c.find("Output_type_1").text) + self.ui.comboBox_fieldname_12.setCurrentIndex(index_fieldname_12) + index_fieldname_2 = self.ui.comboBox_fieldname_2.findText(c.find("Output_type_2").text) + self.ui.comboBox_fieldname_2.setCurrentIndex(index_fieldname_2) + elif len(c) == 11: + self.ui.checkBox_classifier_3.setChecked(True) + self.ui.lineEdit_fieldname_13.setText(c.find("Output_fieldname_1").text) + self.ui.lineEdit_fieldname_23.setText(c.find("Output_fieldname_2").text) + self.ui.lineEdit_fieldname_3.setText(c.find("Output_fieldname_3").text) + self.ui.lineEdit_fieldname_4.setText(c.find("Output_fieldname_4").text) + index_fieldname_13 = self.ui.comboBox_fieldname_13.findText(c.find("Output_type_1").text) + self.ui.comboBox_fieldname_13.setCurrentIndex(index_fieldname_13) + index_fieldname_23 = self.ui.comboBox_fieldname_23.findText(c.find("Output_type_2").text) + self.ui.comboBox_fieldname_23.setCurrentIndex(index_fieldname_23) + index_fieldname_3 = self.ui.comboBox_fieldname_3.findText(c.find("Output_type_3").text) + self.ui.comboBox_fieldname_3.setCurrentIndex(index_fieldname_3) + index_fieldname_4 = self.ui.comboBox_fieldname_4.findText(c.find("Output_type_4").text) + self.ui.comboBox_fieldname_4.setCurrentIndex(index_fieldname_4) + + # Classification mode + if c.find("Classification_method").text == '1': + self.ui.radioButton_rf.setChecked(True) + else: + self.ui.radioButton_s.setChecked(True) + + def save_backup(self): + """ + Function to save input text in every fields. The output file must be a XML file. + """ + + out_backup = QtWidgets.QFileDialog.getSaveFileName(self, "Save backup", os.getcwd(), '*.xml')[0] + + # if the user has forgotten to put .shp at the end of the output xml + if out_backup[-4:] != '.xml': + out_backup = out_backup + '.xml' + + root = ET.Element("Data_filled") + + if self.ui.checkBox_multiprocess.isChecked(): + ET.SubElement(root, "Multi_process", type = "int").text = str(1) + else: + ET.SubElement(root, "Multi_process", type = "int").text = str(0) + + doc = ET.SubElement(root, "Tab", id="Processing_raster") + ET.SubElement(doc, "Principal_folder", type = "str").text = "%s" % self.ui.lineEdit_principal_folder.text() + + if self.current_mode == Constantes.EXPERT_MODE: + ET.SubElement(doc, "Captor", type = "str").text = "%s" % self.ui.comboBox_captor.currentText() + else: + ET.SubElement(doc, "Captor", type = "str").text = "Landsat" + + ET.SubElement(doc, "Year_images", type = "str").text = "%s" % self.ui.lineEdit_year_images.text() + ET.SubElement(doc, "Area_path", type = "str").text = "%s" % self.ui.lineEdit_area_path.text() + + if self.current_mode == Constantes.EXPERT_MODE: + if self.ui.checkBox_listing.isChecked(): + ET.SubElement(doc, "Images_available", type = "int").text = str(1) + else: + ET.SubElement(doc, "Images_available", type = "int").text = str(0) + if self.ui.checkBox_download.isChecked(): + ET.SubElement(doc, "Download", type = "int").text = str(1) + else: + ET.SubElement(doc, "Download", type = "int").text = str(0) + else: + ET.SubElement(doc, "Images_available", type = "int").text = str(0) + ET.SubElement(doc, "Download", type = "int").text = str(0) + + ET.SubElement(doc, "Username", type = "str").text = "%s" % self.ui.lineEdit_user.text() + ET.SubElement(doc, "Password", type = "str").text = "%s" % self.ui.lineEdit_password.text() + if self.w_proxy is None: + sub_proxy = ET.SubElement(doc, "Proxy", id="No_proxy") + ET.SubElement(sub_proxy, "Proxy_adress", type = "str").text = "" + ET.SubElement(sub_proxy, "Proxy_login", type = "str").text = "" + ET.SubElement(sub_proxy, "Proxy_password", type = "str").text = "" + elif self.w_proxy.proxy == "": + sub_proxy = ET.SubElement(doc, "Proxy", id="No_proxy") + ET.SubElement(sub_proxy, "Proxy_adress", type = "str").text = "" + ET.SubElement(sub_proxy, "Proxy_login", type = "str").text = "" + ET.SubElement(sub_proxy, "Proxy_password", type = "str").text = "" + else: + sub_proxy = ET.SubElement(doc, "Proxy", id="Proxy") + ET.SubElement(sub_proxy, "Proxy_adress", type = "str").text = "%s" % self.w_proxy.proxy + ET.SubElement(sub_proxy, "Proxy_login", type = "str").text = "%s" % self.w_proxy.login_proxy + ET.SubElement(sub_proxy, "Proxy_password", type = "str").text = "%s" % self.w_proxy.password_proxy + + if self.current_mode == Constantes.EXPERT_MODE: + if self.ui.checkBox_processing.isChecked(): + ET.SubElement(doc, "Img_processing", type = "int").text = str(1) + else: + ET.SubElement(doc, "Img_processing", type = "int").text = str(0) + + if self.ui.checkBox_VHRS.isChecked(): + ET.SubElement(doc, "VHRS_checked", type = "int").text = str(1) + else: + ET.SubElement(doc, "VHRS_checked", type = "int").text = str(0) + else: + ET.SubElement(doc, "Img_processing", type = "int").text = str(1) + ET.SubElement(doc, "VHRS_checked", type = "int").text = str(1) + + ET.SubElement(doc, "VHRS", type = "str").text = "%s" % self.ui.lineEdit_VHRS.text() + + if self.current_mode == Constantes.EXPERT_MODE: + if self.ui.checkBox_MNT.isChecked(): + ET.SubElement(doc, "MNT_checked", type = "int").text = str(1) + else: + ET.SubElement(doc, "MNT_checked", type = "int").text = str(0) + else: + if "%s" % self.ui.lineEdit_MNT.text() != '': + ET.SubElement(doc, "MNT_checked", type = "int").text = str(1) + else: + ET.SubElement(doc, "MNT_checked", type = "int").text = str(0) + + ET.SubElement(doc, "MNT", type = "str").text = "%s" % self.ui.lineEdit_MNT.text() + + doc = ET.SubElement(root, "Tab", id="Processing_sample") + if self.current_mode == Constantes.EXPERT_MODE: + for sa in range(len(self.sample_name)): + sub_doc = ET.SubElement(doc, "Sample", id="Sample_" + str(sa)) + ET.SubElement(sub_doc, "Sample_path", type = "str").text = self.sample_name[sa] + ET.SubElement(sub_doc, "Fieldname_1", type = "str").text = self.fieldname_args[2*sa] + ET.SubElement(sub_doc, "Fieldname_2", type = "str").text = self.fieldname_args[2*sa+1] + ET.SubElement(sub_doc, "Classname_1", type = "str").text = self.class_args[2*sa] + ET.SubElement(sub_doc, "Classname_2", type = "str").text = self.class_args[2*sa+1] + ET.SubElement(sub_doc, "Nb_polygones", type = "str").text = self.list_nb_sample[sa] + ET.SubElement(sub_doc, "RPG", type = "int").text = str(self.rpg_tchek[sa]) + try: + # To enter a sample raster if the first tab doesn't launch before + if self.img_sample[sa] == 1: + ET.SubElement(sub_doc, "Img_sample", type = "str").text = self.raster_path[sa] + except: + self.logger.debug('Not sample raster only !') + else: + # RPG + sub_doc = ET.SubElement(doc, "Sample", id="Sample_0") + ET.SubElement(sub_doc, "Sample_path", type = "str").text = "%s" % self.ui.lineEdit_sample_path.text() + ET.SubElement(sub_doc, "Fieldname_1", type = "str").text = "%s" % self.ui.lineEdit_select_sample_fieldname_1.text() + ET.SubElement(sub_doc, "Fieldname_2", type = "str").text = "%s" % self.ui.lineEdit_select_sample_fieldname_2.text() + ET.SubElement(sub_doc, "Classname_1", type = "str").text = "%s" % self.ui.lineEdit_select_sample_class_1.text() + ET.SubElement(sub_doc, "Classname_2", type = "str").text = "%s" % self.ui.lineEdit_select_sample_class_2.text() + ET.SubElement(sub_doc, "Nb_polygones", type = "str").text = "%s" % self.ui.lineEdit_select_sample_nb_poly.text() + ET.SubElement(sub_doc, "RPG", type = "int").text = str(1) + + # To Grass/wooden + sub_doc = ET.SubElement(doc, "Sample", id="Sample_1") + ET.SubElement(sub_doc, "Sample_path", type = "str").text = "%s" % self.ui.lineEdit_sample_path_2.text() + ET.SubElement(sub_doc, "Fieldname_1", type = "str").text = "%s" % self.ui.lineEdit_select_sample_fieldname_3.text() + ET.SubElement(sub_doc, "Fieldname_2", type = "str").text = "%s" % self.ui.lineEdit_select_sample_fieldname_4.text() + ET.SubElement(sub_doc, "Classname_1", type = "str").text = "%s" % self.ui.lineEdit_select_sample_class_3.text() + ET.SubElement(sub_doc, "Classname_2", type = "str").text = "%s" % self.ui.lineEdit_select_sample_class_4.text() + ET.SubElement(sub_doc, "Nb_polygones", type = "str").text = "%s" % self.ui.lineEdit_select_sample_nb_poly_2.text() + ET.SubElement(sub_doc, "RPG", type = "int").text = str(0) + + # To wooden + sub_doc = ET.SubElement(doc, "Sample", id="Sample_2") + ET.SubElement(sub_doc, "Sample_path", type = "str").text = "%s" % self.ui.lineEdit_sample_path_3.text() + ET.SubElement(sub_doc, "Fieldname_1", type = "str").text = "%s" % self.ui.lineEdit_select_sample_fieldname_5.text() + ET.SubElement(sub_doc, "Fieldname_2", type = "str").text = "%s" % self.ui.lineEdit_select_sample_fieldname_6.text() + ET.SubElement(sub_doc, "Classname_1", type = "str").text = "%s" % self.ui.lineEdit_select_sample_class_5.text() + ET.SubElement(sub_doc, "Classname_2", type = "str").text = "%s" % self.ui.lineEdit_select_sample_class_6.text() + ET.SubElement(sub_doc, "Nb_polygones", type = "str").text = "%s" % self.ui.lineEdit_select_sample_nb_poly_3.text() + ET.SubElement(sub_doc, "RPG", type = "int").text = str(0) + + if self.current_mode == Constantes.EXPERT_MODE: + if self.ui.checkBox_threshold.isChecked(): + ET.SubElement(doc, "Threshold_checked", type = "int").text = str(1) + else: + ET.SubElement(doc, "Threshold_checked", type = "int").text = str(0) + else: + ET.SubElement(doc, "Threshold_checked", type = "int").text = str(1) + + doc = ET.SubElement(root, "Tab", id="Classification") + ET.SubElement(doc, "Segmentation_path", type = "str").text = "%s" % self.ui.lineEdit_segmentation.text() + ET.SubElement(doc, "Output_path", type = "str").text = "%s" % self.ui.lineEdit_output.text() + + if self.current_mode == Constantes.EXPERT_MODE: + + if self.ui.checkBox_classifier_1.isChecked(): + ET.SubElement(doc, "Output_fieldname_1", type = "str").text = "%s" % self.ui.lineEdit_fieldname_1.text() + ET.SubElement(doc, "Output_type_1", type = "str").text = "%s" % self.ui.comboBox_fieldname_1.currentText() + + if self.ui.checkBox_classifier_2.isChecked(): + ET.SubElement(doc, "Output_fieldname_1", type = "str").text = "%s" % self.ui.lineEdit_fieldname_12.text() + ET.SubElement(doc, "Output_type_1", type = "str").text = "%s" % self.ui.comboBox_fieldname_12.currentText() + ET.SubElement(doc, "Output_fieldname_2", type = "str").text = "%s" % self.ui.lineEdit_fieldname_2.text() + ET.SubElement(doc, "Output_type_2", type = "str").text = "%s" % self.ui.comboBox_fieldname_2.currentText() + + if self.ui.checkBox_classifier_3.isChecked(): + ET.SubElement(doc, "Output_fieldname_1", type = "str").text = "%s" % self.ui.lineEdit_fieldname_13.text() + ET.SubElement(doc, "Output_type_1", type = "str").text = "%s" % self.ui.comboBox_fieldname_13.currentText() + ET.SubElement(doc, "Output_fieldname_2", type = "str").text = "%s" % self.ui.lineEdit_fieldname_23.text() + ET.SubElement(doc, "Output_type_2", type = "str").text = "%s" % self.ui.comboBox_fieldname_23.currentText() + ET.SubElement(doc, "Output_fieldname_3", type = "str").text = "%s" % self.ui.lineEdit_fieldname_3.text() + ET.SubElement(doc, "Output_type_3", type = "str").text = "%s" % self.ui.comboBox_fieldname_3.currentText() + ET.SubElement(doc, "Output_fieldname_4", type = "str").text = "%s" % self.ui.lineEdit_fieldname_4.text() + ET.SubElement(doc, "Output_type_4", type = "str").text = "%s" % self.ui.comboBox_fieldname_4.currentText() + + # Classification mode + if self.ui.radioButton_rf.isChecked(): + ET.SubElement(doc, "Classification_method", type = "int").text = str(1) + elif self.ui.radioButton_s.isChecked(): + ET.SubElement(doc, "Classification_method", type = "int").text = str(0) + else: + ET.SubElement(doc, "Output_fieldname_1", type = "str").text = "NIVEAU_1" + ET.SubElement(doc, "Output_type_1", type = "str").text = "String" + ET.SubElement(doc, "Output_fieldname_2", type = "str").text = "NIVEAU_2" + ET.SubElement(doc, "Output_type_2", type = "str").text = "String" + ET.SubElement(doc, "Output_fieldname_3", type = "str").text = "NIVEAU_3" + ET.SubElement(doc, "Output_type_3", type = "str").text = "String" + ET.SubElement(doc, "Output_fieldname_4", type = "str").text = "POURC" + ET.SubElement(doc, "Output_type_4", type = "str").text = "Real" + ET.SubElement(doc, "Classification_method", type = "int").text = str(1) + + tree = ET.ElementTree(root) + # Write in a xml file + tree.write(str(out_backup), encoding="UTF-8",xml_declaration=True, pretty_print=True) + + def help_tools(self): + """ + Function to open html help + """ + webbrowser.open('file://' + os.getcwd() + '/Documentation/methode_tuto.html#tutoriels-interface') + + + def change_mode(self, new_mode): + """ + Function to switch between SIMPLE and EXPERT mode of "PHYMOBAT" + """ + if new_mode != self.current_mode : + if new_mode == Constantes.SIMPLE_MODE : + self.logger.info("Simplify mode") + self.close() + self.window = PHYMOBAT(mode = Constantes.SIMPLE_MODE) + else : + self.logger.info("Expert mode") + self.close() + self.window = PHYMOBAT(mode = Constantes.EXPERT_MODE) + + self.window.show() + + def about_PHYMOBA(self): + """ + Function to open a new window "About PHYMOBAT" + """ + self.apropos.show() + + def forget_study_area(self): + """ + Function to open a new window 'Alert' because user forgotten to declare study area. + """ + self.w_study_area.show() + + def forget_raster_sample(self): + """ + Function to open a new window 'Alert' because user forgotten to declare rasters or samples. + """ + self.w_forget.show() + + def close_button(self): + """ + Function to close the interface. + """ + self.close() + if __name__ == "__main__": - - app = QtWidgets.QApplication(sys.argv) - myapp = PHYMOBAT() - myapp.show() - - sys.exit(app.exec_()) + + app = QtWidgets.QApplication(sys.argv) + myapp = PHYMOBAT() + myapp.show() + + sys.exit(app.exec_()) diff --git a/Popup.py b/Popup.py new file mode 100644 index 0000000000000000000000000000000000000000..ea9e1a04a70842d0d7c6f343fa26af285babfb36 --- /dev/null +++ b/Popup.py @@ -0,0 +1,94 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +import os, sys, time +from PyQt5 import QtWidgets, QtCore + +from ui_A_propos_PHYMOBAT_window import Ui_About +from ui_Warming_study_area import Ui_Warming_study_area +from ui_Warming_forgetting import Ui_Warming_forgetting +from ui_Proxy_window import Ui_Proxy_window + +class about(QtWidgets.QWidget): + """ + Popup to display "About PHYMOBAT". In this windows, it prints informations on the processing, license + and version. + """ + def __init__(self, parent=None): + QtWidgets.QWidget.__init__(self, parent) + self.prop = Ui_About() + self.prop.setupUi(self) + + self.prop.close_newWindow.clicked.connect(self.close_window) + + def close_window(self): + """ + Function to close the "A propos PHYMOBAT". + """ + self.close() + +class warming_study_area(QtWidgets.QWidget): + """ + Popup to display a message to say there isn't declared study area file. + """ + def __init__(self, parent=None): + QtWidgets.QWidget.__init__(self, parent) + self.w_study_a = Ui_Warming_study_area() + self.w_study_a.setupUi(self) + + self.w_study_a.pushButton_ok_window_warning_study_area.clicked.connect(self.close_window) + + def close_window(self): + """ + Function to close the popup. + """ + self.close() + +class warming_forgetting(QtWidgets.QWidget): + """ + Popup to display a message to tell you if you fogotten to enter a raster or a sample. + """ + def __init__(self, parent=None): + QtWidgets.QWidget.__init__(self, parent) + self.w_forget = Ui_Warming_forgetting() + self.w_forget.setupUi(self) + + self.w_forget.pushButton_ok_forget.clicked.connect(self.close_window) + + def close_window(self): + """ + Function to close the popup. + """ + self.close() + +class proxy_window(QtWidgets.QWidget): + """ + Popup to display a message to tell you if you fogotten to enter a raster or a sample. + """ + def __init__(self, parent=None): + QtWidgets.QWidget.__init__(self, parent) + self.w_proxy = Ui_Proxy_window() + self.w_proxy.setupUi(self) + + # Proxy ID + self.proxy = "" + self.login_proxy = "" + self.password_proxy = "" + + # Connect Apply|Close button + self.w_proxy.buttonBox_proxy.button(QtWidgets.QDialogButtonBox.Close).clicked.connect(self.close_window) + self.w_proxy.buttonBox_proxy.button(QtWidgets.QDialogButtonBox.Apply).clicked.connect(self.id_proxy) + + def id_proxy(self): + """ + Function to use input proxy id + """ + self.login_proxy = "%s" % self.w_proxy.lineEdit_login_proxy.text() + self.password_proxy = "%s" % self.w_proxy.lineEdit_password_proxy.text() + self.proxy = "%s" % self.w_proxy.lineEdit_proxy.text() + + def close_window(self): + """ + Function to close the popup. + """ + self.close() diff --git a/Precision_moba.py b/Precision_moba.py index 244ab4e17513da38c58ae5fb211ba3098b115e61..ff3e1ddb7b6eeddac0bad4469f9dc1d4e378ebc0 100644 --- a/Precision_moba.py +++ b/Precision_moba.py @@ -115,53 +115,52 @@ class Precision_moba(): data_val = data_val.flatten() # Add pixel value in a list without no data - fb_stats_2 = [[data_class[x],data_val[x]] for x in range(len(data_val)) if data_val[x] != -10000] - fb_stats_2 = map(list, zip(*fb_stats_2))# transpose list + fb_stats_2 = [[int(data_class[x]),int(data_val[x])] for x in range(len(data_val)) if data_val[x] != -10000] + fb_stats_2 = list(map(list, zip(*fb_stats_2)))# transpose list + fb_stats_in = fb_stats_2[0] fb_stats_val = fb_stats_2[1] # Open a file (txt) to save results - f = open(self.path_save + "/ConfusionMatrix.txt", "wb") - - # Compute statistics on the classification - cm = confusion_matrix(fb_stats_val, fb_stats_in) - f.write("Confusion Matrix :\n") - for out in cm: - f.write(str(out) + "\n") - - all_pr = classification_report(fb_stats_val, fb_stats_in) - f.write("\n") - f.write(all_pr) - - accur = accuracy_score(fb_stats_val, fb_stats_in) - f.write("\n") - f.write("Accuracy : " + str(accur) + "\n") - - recall = recall_score(fb_stats_val, fb_stats_in) - f.write("\n") - f.write("Recall : " + str(recall) + "\n") - - pr = precision_score(fb_stats_val, fb_stats_in) - f.write("\n") - f.write("Precision : " + str(pr) + "\n") - - f_scor = f1_score(fb_stats_val, fb_stats_in) - f.write("\n") - f.write("F_score : " + str(f_scor) + "\n") - - kappa = self.cohen_kappa_score(fb_stats_val, fb_stats_in) - f.write("\n") - f.write("Kappa : " + str(kappa) + "\n") - print('') - print('') - print('Accuracy : %f, Kappa : %f, Recall : %f, Precision : %f, F_score : %f' % (accur, kappa, recall, pr, f_scor)) - print('') - print (all_pr) - print('') - print('Confusion matrix :') - print (cm) - - f.close() + with open(self.path_save + "/ConfusionMatrix.txt", "w") as f : + # Compute statistics on the classification + cm = confusion_matrix(fb_stats_val, fb_stats_in) + f.write("Confusion Matrix :\n") + for out in cm: + f.write(str(out) + "\n") + + all_pr = classification_report(fb_stats_val, fb_stats_in) + f.write("\n") + f.write(all_pr) + + accur = accuracy_score(fb_stats_val, fb_stats_in) + f.write("\n") + f.write("Accuracy : " + str(accur) + "\n") + + recall = recall_score(fb_stats_val, fb_stats_in) + f.write("\n") + f.write("Recall : " + str(recall) + "\n") + + pr = precision_score(fb_stats_val, fb_stats_in) + f.write("\n") + f.write("Precision : " + str(pr) + "\n") + + f_scor = f1_score(fb_stats_val, fb_stats_in) + f.write("\n") + f.write("F_score : " + str(f_scor) + "\n") + + kappa = self.cohen_kappa_score(fb_stats_val, fb_stats_in) + f.write("\n") + f.write("Kappa : " + str(kappa) + "\n") + print('') + print('') + print('Accuracy : %f, Kappa : %f, Recall : %f, Precision : %f, F_score : %f' % (accur, kappa, recall, pr, f_scor)) + print('') + print (all_pr) + print('') + print('Confusion matrix :') + print (cm) + def cohen_kappa_score(self, y1, y2, labels=None): """ diff --git a/Processing.py b/Processing.py index 5ffbbbf19b72f7def198d66c2be44a8ac44e8bbe..af90bb46500dc869cabdbab24830fd405f64934d 100644 --- a/Processing.py +++ b/Processing.py @@ -23,13 +23,14 @@ import subprocess from sklearn.ensemble import RandomForestClassifier from sklearn import tree try : - import ogr, gdal + import ogr, gdal except : - from osgeo import ogr, gdal + from osgeo import ogr, gdal from Toolbox import Toolbox from Seath import Seath from Precision_moba import Precision_moba + # Class group image from Archive import Archive from RasterSat_by_date import RasterSat_by_date @@ -42,835 +43,815 @@ from Sample import Sample from Segmentation import Segmentation from Rpg import Rpg +import Constantes + from collections import defaultdict from multiprocessing import Process from multiprocessing.managers import BaseManager, DictProxy class Processing(): - - """ - Main processing. This class launch the others system classes. It take into account - CarHab classification method MOBA. - - This way is broken down into 3 parts : - - Image Processing (Search, download and processing) - - Vector Processing (Optimal threshold, Sample processing) - - Classification - - Validation - - **Main parameters** - - :param captor_project: Satellite captor name - :type captor_project: str - :param classif_year: Classification year - :type classif_year: str - :param nb_avalaible_images: Number download available images - :type nb_avalaible_images: int - :param path_folder_dpt: Main folder path - :type path_folder_dpt: str - :param folder_archive: Archive downloaded folder path - :type folder_archive: str - :param folder_processing: Processing folder name. By default : 'Traitement' - :type folder_processing: str - :param path_area: Study area shapefile - :type path_area: str - :param path_ortho: VHRS image path - :type path_ortho: str - :param path_mnt: MNT image path - :type path_mnt: str - :param path_segm: Segmentation shapefile - :type path_segm: str - - **Id information to download on theia platform** - - :param user: Connexion Username - :type user: str - :param password: Connexion Password - :type password: str - - **Output parameters** - - :param output_name_moba: Output classification shapefile - :type output_name_moba: str - :param out_fieldname_carto: Output shapefile field name - :type out_fieldname_carto: list of str - :param out_fieldtype_carto: Output shapefile field type - :type out_fieldtype_carto: list of str (eval ogr pointer) - - **Sample parameters** - - :param fieldname_args: Sample field names 2 by 2 - :type fieldname_args: list of str - :param class_args: Sample class names 2 by 2 - :type class_args: list of str - :param sample_name: List of sample name (path) - :type sample_name: list of str - :param list_nb_sample: Number of polygons for every sample - :type list_nb_sample: list of int - - **Multi-processing parameters** - - :param mp: Boolean variable -> 0 or 1. - - - 0 means, not multi-processing - - 1 means, launch process with multi-processing - :type mp: int - """ - - def __init__(self): - - # Used variables - self.captor_project = '' - self.classif_year = '' - self.path_folder_dpt = '' - self.folder_archive = '' - self.folder_processing = 'Traitement' - self.path_area = '' - self.path_ortho = '' - self.path_mnt = '' - self.path_segm = '' - self.output_name_moba = '' - - self.w_proxy = None # For the "Proxy window" - - # Id information to download on theia platform - self.user = '' - self.password = '' + + """ + Main processing. This class launch the others system classes. It take into account + CarHab classification method MOBA. + + This way is broken down into 3 parts : + - Image Processing (Search, download and processing) + - Vector Processing (Optimal threshold, Sample processing) + - Classification + - Validation + + **Main parameters** + + :param captor_project: Satellite captor name + :type captor_project: str + :param classif_year: Classification year + :type classif_year: str + :param nb_avalaible_images: Number download available images + :type nb_avalaible_images: int + :param path_folder_dpt: Main folder path + :type path_folder_dpt: str + :param folder_processing: Processing folder name. By default : 'Traitement' + :type folder_processing: str + :param path_area: Study area shapefile + :type path_area: str + :param path_ortho: VHRS image path + :type path_ortho: str + :param path_mnt: MNT image path + :type path_mnt: str + :param path_segm: Segmentation shapefile + :type path_segm: str + + **Id information to download on theia platform** + + :param user: Connexion Username + :type user: str + :param password: Connexion Password + :type password: str + + **Output parameters** + + :param output_name_moba: Output classification shapefile + :type output_name_moba: str + :param out_fieldname_carto: Output shapefile field name + :type out_fieldname_carto: list of str + :param out_fieldtype_carto: Output shapefile field type + :type out_fieldtype_carto: list of str (eval ogr pointer) + + **Sample parameters** + + :param fieldname_args: Sample field names 2 by 2 + :type fieldname_args: list of str + :param class_args: Sample class names 2 by 2 + :type class_args: list of str + :param sample_name: List of sample name (path) + :type sample_name: list of str + :param list_nb_sample: Number of polygons for every sample + :type list_nb_sample: list of int + + **Multi-processing parameters** + + :param mp: Boolean variable -> 0 or 1. + + - 0 means, not multi-processing + - 1 means, launch process with multi-processing + :type mp: int + """ + + def __init__(self): + + # Used variables + self.captor_project = '' + self.classif_year = '' + self.path_folder_dpt = '' + self.folder_processing = 'Traitement' + self.path_area = '' + self.path_ortho = '' + self.path_mnt = '' + self.path_segm = '' + self.output_name_moba = '' + + self.w_proxy = None # For the "Proxy window" + + # Id information to download on theia platform + self.user = '' + self.password = '' + + # List of output raster path + self.raster_path = [] + self.list_band_outraster = [] + + # Class name + + # TODO : Change index of the classes -> Harbacées 6 / Ligneux 7 by Agriculuture 4 / Eboulis 5 + + self.in_class_name = ['Non Vegetation semi-naturelle', 'Vegetation semi-naturelle',\ + 'Herbacees', 'Ligneux', \ + 'Ligneux mixtes', 'Ligneux denses',\ + 'Agriculture', 'Eboulis', \ + 'Forte phytomasse', 'Moyenne phytomasse', 'Faible phytomasse'] + # Sample field names 2 by 2 + self.fieldname_args = [] +# 'CODE_GROUP', 'CODE_GROUP',\ +# 'echant', 'echant',\ +# 'echant', 'echant'] + # Sample class names 2 by 2 + self.class_args = [] +# '1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 14, 15, 20, 21, 22, 23, 24, 26, 28', '18',\ +# 'H','LF, LO',\ +# 'LF', 'LO'] + + # Decision tree combination + self.tree_direction = [[0],\ + [0],\ + [1, 3, 4],\ + [1, 3, 5],\ + [1, 2, 8],\ + [1, 2, 9],\ + [1, 2, 10]] # [['Cultures'],['Semi-naturelles', 'Herbacees', 'Forte phytomasse'], ... + # ..., ['Semi-naturelles', 'Ligneux', 'Ligneux denses']] + # Slope degrees + self.slope_degree = 30 + + # Output shapefile field name + self.out_fieldname_carto = ['ID', 'AREA'] #, 'NIVEAU_1', 'NIVEAU_2', 'NIVEAU_3', 'POURC'] + # Output shapefile field type + self.out_fieldtype_carto = [ogr.OFTString, ogr.OFTReal] #, ogr.OFTString, ogr.OFTString, ogr.OFTString, ogr.OFTReal] + + # List of sample name path + self.sample_name = [] + # List of number sample + self.list_nb_sample = [] + # Number download available images + self.nb_avalaible_images = 0 + + # Multi-processing variable + self.mp = Constantes.MULTIPROCESSING_DISABLE + + # Function followed + self.check_download = '' + self.decis = {} + # Images after processing images + self.out_ndvistats_folder_tab = defaultdict(list) + + # Validation shapefiles information + self.valid_shp = [] + + # Radom Forest Model + # Set the parameters of this random forest from the estimator + self.rf = RandomForestClassifier(n_estimators=500, criterion='gini', max_depth=None, min_samples_split=2, \ + min_samples_leaf=1, max_features='auto', \ + bootstrap=True, oob_score=True) + + def i_tree_direction(self): + """ + Interface function to can extract one level or two levels of the final classification + """ + + if len(self.out_fieldname_carto) == 3: + self.tree_direction = [[0], [1]] + + if len(self.out_fieldname_carto) == 4: + self.tree_direction = [[0], [0], [1, 2], [1, 3]] + + def i_download(self): + """ + Interface function to download archives on the website Theia Land. This function extract + the number of downloadable image with :func:`Archive.Archive.listing`. + + Then, this function download :func:`Archive.Archive.download` and unzip :func:`Archive.Archive.decompress` images + in the archive folder (**folder_archive**). + """ + + folder_archive = self.captor_project + '_PoleTheia' - # List of output raster path - self.raster_path = [] - self.list_band_outraster = [] - - # Class name - - # TODO : Change index of the classes -> Harbacées 6 / Ligneux 7 by Agriculuture 4 / Eboulis 5 - - self.in_class_name = ['Non Vegetation semi-naturelle', 'Vegetation semi-naturelle',\ - 'Herbacees', 'Ligneux', \ - 'Ligneux mixtes', 'Ligneux denses',\ - 'Agriculture', 'Eboulis', \ - 'Forte phytomasse', 'Moyenne phytomasse', 'Faible phytomasse'] - # Sample field names 2 by 2 - self.fieldname_args = [] -# 'CODE_GROUP', 'CODE_GROUP',\ -# 'echant', 'echant',\ -# 'echant', 'echant'] - # Sample class names 2 by 2 - self.class_args = [] -# '1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 14, 15, 20, 21, 22, 23, 24, 26, 28', '18',\ -# 'H','LF, LO',\ -# 'LF', 'LO'] - - # Decision tree combination - self.tree_direction = [[0],\ - [0],\ - [1, 3, 4],\ - [1, 3, 5],\ - [1, 2, 8],\ - [1, 2, 9],\ - [1, 2, 10]] # [['Cultures'],['Semi-naturelles', 'Herbacees', 'Forte phytomasse'], ... - # ..., ['Semi-naturelles', 'Ligneux', 'Ligneux denses']] - # Slope degrees - self.slope_degree = 30 - - # Output shapefile field name - self.out_fieldname_carto = ['ID', 'AREA'] #, 'NIVEAU_1', 'NIVEAU_2', 'NIVEAU_3', 'POURC'] - # Output shapefile field type - self.out_fieldtype_carto = [ogr.OFTString, ogr.OFTReal] #, ogr.OFTString, ogr.OFTString, ogr.OFTString, ogr.OFTReal] - - # List of sample name path - self.sample_name = [] - # List of number sample - self.list_nb_sample = [] - # Number download available images - self.nb_avalaible_images = 0 - # Multi-processing variable - self.mp = 1 - - # Function followed - self.check_download = '' - self.decis = {} - # Images after processing images - self.out_ndvistats_folder_tab = defaultdict(list) - - # Validation shapefiles information - self.valid_shp = [] - - # Radom Forest Model - # Set the parameters of this random forest from the estimator - self.rf = RandomForestClassifier(n_estimators=500, criterion='gini', max_depth=None, min_samples_split=2, \ - min_samples_leaf=1, max_features='auto', \ - bootstrap=True, oob_score=True) - - def i_tree_direction(self): - - """ - Interface function to can extract one level or two levels of the final classification - """ + self.check_download = Archive(self.captor_project, self.classif_year, self.path_area, self.path_folder_dpt, folder_archive, self.w_proxy) + self.nb_avalaible_images = self.check_download.listing() + self.check_download.download_auto(self.user, self.password) + self.check_download.decompress() + + def i_img_sat(self): + + """ + Interface function to processing satellite images: + + 1. Clip archive images and modify Archive class to integrate clip image path. + With :func:`Toolbox.clip_raster` in ``Toolbox`` module. + + 2. Search cloud's percentage :func:`RasterSat_by_date.RasterSat_by_date.pourc_cloud`, select + image and compute ndvi index :func:`RasterSat_by_date.RasterSat_by_date.calcul_ndvi`. If cloud's percentage is + greater than 40%, then not select and compute ndvi index. + + 3. Compute temporal stats on ndvi index [min, max, std, min-max]. With :func:`Toolbox.calc_serie_stats` + in ``Toolbox`` module. + + 4. Create stats ndvi raster and stats cloud raster. + + >>> import RasterSat_by_date + >>> stats_test = RasterSat_by_date(class_archive, big_folder, one_date) + >>> stats_test.complete_raster(stats_test.create_raster(in_raster, stats_data, in_ds), stats_data) + """ - if len(self.out_fieldname_carto) == 3: - self.tree_direction = [[0], [1]] - - if len(self.out_fieldname_carto) == 4: - self.tree_direction = [[0], [0], [1, 2], [1, 3]] - - def i_download(self, dd): - - """ - Interface function to download archives on the website Theia Land. This function extract - the number of downloadable image with :func:`Archive.Archive.listing`. - - Then, this function download :func:`Archive.Archive.download` and unzip :func:`Archive.Archive.decompress` images - in the archive folder (**folder_archive**). - - :param dd: Boolean variable to launch download images -> 0 or 1. - - - 0 means, not downloading - - 1 means, launch downloading - :type dd: int - """ - - self.folder_archive = self.captor_project + '_PoleTheia' - self.check_download = Archive(self.captor_project, self.classif_year, self.path_area, self.path_folder_dpt, self.folder_archive, self.w_proxy) - self.check_download.listing() - self.nb_avalaible_images = len(self.check_download.list_archive) - # check_download.set_list_archive_to_try(check_download.list_archive[:3]) - if dd == 1: -# self.check_download.download_auto(self.user, self.password) - self.check_download.download_auto(self.user, self.password) - self.check_download.decompress() - - def i_glob(self): - """ - Function to load existing images to launch the processing. - It need to archives. Then, to select processing images, select archives - - """ - - self.folder_archive = self.captor_project + '_PoleTheia' - self.check_download = Archive(self.captor_project, self.classif_year, self.path_area, self.path_folder_dpt, self.folder_archive, self.w_proxy) - self.check_download.decompress() - - def i_img_sat(self): - - """ - Interface function to processing satellite images: - - 1. Clip archive images and modify Archive class to integrate clip image path. - With :func:`Toolbox.clip_raster` in ``Toolbox`` module. - - 2. Search cloud's percentage :func:`RasterSat_by_date.RasterSat_by_date.pourc_cloud`, select - image and compute ndvi index :func:`RasterSat_by_date.RasterSat_by_date.calcul_ndvi`. If cloud's percentage is - greater than 40%, then not select and compute ndvi index. - - 3. Compute temporal stats on ndvi index [min, max, std, min-max]. With :func:`Toolbox.calc_serie_stats` - in ``Toolbox`` module. - - 4. Create stats ndvi raster and stats cloud raster. - - >>> import RasterSat_by_date - >>> stats_test = RasterSat_by_date(class_archive, big_folder, one_date) - >>> stats_test.complete_raster(stats_test.create_raster(in_raster, stats_data, in_ds), stats_data) - """ + # Clip archive images and modify Archive class to integrate clip image path + for clip in self.check_download.list_img: + clip_index = self.check_download.list_img.index(clip) + + current_list = Toolbox() + current_list.imag = clip[3] + current_list.vect = self.path_area + current_list.check_proj() # Check if projection is RFG93 + self.check_download.list_img[clip_index][3] = current_list.clip_raster() # Multispectral images + + current_list.imag = clip[4] + current_list.check_proj() # Check if projection is RFG93 + self.check_download.list_img[clip_index][4] = current_list.clip_raster() # Cloud images + + # Images pre-processing + spectral_out = [] + for date in self.check_download.single_date: + + check_L8 = RasterSat_by_date(self.check_download, self.folder_processing, date) + check_L8.mosaic_by_date() + + # Search cloud's percentage, select image and compute ndvi index if > cl + cl = check_L8.pourc_cloud(check_L8._one_date[3], check_L8._one_date[4]) + if cl > 0.60: + check_L8.calcul_ndvi(check_L8._one_date[3]) + spectral_out.append(check_L8._one_date) - # Clip archive images and modify Archive class to integrate clip image path - for clip in self.check_download.list_img: - clip_index = self.check_download.list_img.index(clip) - - current_list = Toolbox() - current_list.imag = clip[3] - current_list.vect = self.path_area - current_list.check_proj() # Check if projection is RFG93 - self.check_download.list_img[clip_index][3] = current_list.clip_raster() # Multispectral images - - current_list.imag = clip[4] - current_list.check_proj() # Check if projection is RFG93 - self.check_download.list_img[clip_index][4] = current_list.clip_raster() # Cloud images - - # Images pre-processing - spectral_out = [] - for date in self.check_download.single_date: - - check_L8 = RasterSat_by_date(self.check_download, self.folder_processing, date) - check_L8.mosaic_by_date() - - # Search cloud's percentage, select image and compute ndvi index if > cl - cl = check_L8.pourc_cloud(check_L8._one_date[3], check_L8._one_date[4]) - if cl > 0.60: - check_L8.calcul_ndvi(check_L8._one_date[3]) - spectral_out.append(check_L8._one_date) + # Compute temporal stats on ndvi index [min, max, std, min-max] + spectral_trans = np.transpose(np.array(spectral_out, dtype=object)) + stats_name = ['Min', 'Date', 'Max', 'Std', 'MaxMin'] + stats_ndvi, stats_cloud = current_list.calc_serie_stats(spectral_trans) + + # Create stats ndvi raster and stats cloud raster + stats_L8 = RasterSat_by_date(self.check_download, self.folder_processing, [0]) + + # Stats cloud raster + out_cloud_folder = stats_L8._class_archive._folder + '/' + stats_L8._big_folder + '/' + self.captor_project + '/Cloud_number_' + self.captor_project + '.TIF' + + stats_L8.complete_raster(*stats_L8.create_raster(out_cloud_folder, stats_cloud, stats_L8.raster_data(self.check_download.list_img[0][4])[1]), stats_cloud) + + # Stats ndvi rasters + for stats_index in range(len(stats_ndvi)): + out_ndvistats_folder = stats_L8._class_archive._folder + '/' + stats_L8._big_folder + '/' + self.captor_project + '/' + stats_name[stats_index] + '_' + self.captor_project + '.TIF' + self.out_ndvistats_folder_tab[stats_index] = out_ndvistats_folder + stats_L8.complete_raster(*stats_L8.create_raster(out_ndvistats_folder, stats_ndvi[stats_index], stats_L8.raster_data(self.check_download.list_img[0][4])[1]), stats_ndvi[stats_index]) + + def i_slope(self): + """ + Interface function to processing slope raster. From a MNT, and with a command line gdal, + this function compute slope in degrees :func:`Slope.Slope`. + """ + + current_path_mnt = Toolbox() + current_path_mnt.imag = self.path_mnt + current_path_mnt.vect = self.path_area + path_mnt = current_path_mnt.clip_raster() + + study_slope = Slope(path_mnt) + study_slope.extract_slope()# Call this function to compute slope raster + self.path_mnt = study_slope.out_mnt + + def i_vhrs(self):#, vs): + """ + Interface function to processing VHRS images. It create two OTB texture images :func:`Vhrs.Vhrs` : SFS Texture and Haralick Texture + """ + + # Create texture image + # Clip orthography image + current_path_ortho = Toolbox() + current_path_ortho.imag = self.path_ortho + current_path_ortho.vect = self.path_area + path_ortho = current_path_ortho.clip_raster() + + texture_irc = Vhrs(path_ortho, self.mp) + self.out_ndvistats_folder_tab['sfs'] = texture_irc.out_sfs + self.out_ndvistats_folder_tab['haralick'] = texture_irc.out_haralick + + def i_images_processing(self, vs=1): + + """ + Interface function to launch processing VHRS images :func:`i_vhrs` and satellite images :func:`i_img_sat` in multi-processing. + + :param vs: Boolean variable to launch texture processing because of interface checkbox -> 0 or 1. + + - 0 means, not texture processing + - 1 means, launch texture processing + :type vs: int + """ + + ######################### Multiprocessing ######################### + + mgr = BaseManager() + mgr.register('defaultdict', defaultdict, DictProxy) + mgr.start() - # Compute temporal stats on ndvi index [min, max, std, min-max] - spectral_trans = np.transpose(np.array(spectral_out, dtype=object)) - stats_name = ['Min', 'Date', 'Max', 'Std', 'MaxMin'] - stats_ndvi, stats_cloud = current_list.calc_serie_stats(spectral_trans) - - # Create stats ndvi raster and stats cloud raster - stats_L8 = RasterSat_by_date(self.check_download, self.folder_processing, [0]) - # Stats cloud raster - out_cloud_folder = stats_L8._class_archive._folder + '/' + stats_L8._big_folder + '/' + self.captor_project + \ - '/Cloud_number_' + self.captor_project + '.TIF' - stats_L8.complete_raster(stats_L8.create_raster(out_cloud_folder, stats_cloud, \ - stats_L8.raster_data(self.check_download.list_img[0][4])[1]), \ - stats_cloud) - - # Stats ndvi rasters - for stats_index in range(len(stats_ndvi)): - out_ndvistats_folder = stats_L8._class_archive._folder + '/' + stats_L8._big_folder + '/' + self.captor_project + \ - '/' + stats_name[stats_index] + '_' + self.captor_project + '.TIF' - self.out_ndvistats_folder_tab[stats_index] = out_ndvistats_folder - stats_L8.complete_raster(stats_L8.create_raster(out_ndvistats_folder, stats_ndvi[stats_index], \ - stats_L8.raster_data(self.check_download.list_img[0][4])[1]), \ - stats_ndvi[stats_index]) - - def i_slope(self): - """ - Interface function to processing slope raster. From a MNT, and with a command line gdal, - this function compute slope in degrees :func:`Slope.Slope`. - - """ - - current_path_mnt = Toolbox() - current_path_mnt.imag = self.path_mnt - current_path_mnt.vect = self.path_area - path_mnt = current_path_mnt.clip_raster() - - study_slope = Slope(path_mnt) - study_slope.extract_slope()# Call this function to compute slope raster - self.path_mnt = study_slope.out_mnt - - def i_vhrs(self):#, vs): - """ - Interface function to processing VHRS images. It create two OTB texture images :func:`Vhrs.Vhrs` : SFS Texture and Haralick Texture + self.out_ndvistats_folder_tab = mgr.defaultdict(list) + + p_img_sat = Process(target=self.i_img_sat) + p_img_sat.start() + + if self.mp == Constantes.MULTIPROCESSING_DISABLE: + p_img_sat.join() + + if vs == 1: + p_vhrs = Process(target=self.i_vhrs) + p_vhrs.start() + p_vhrs.join() + + if self.mp == Constantes.MULTIPROCESSING_ENABLE: + p_img_sat.join() + + ################################################################### + + # List of output raster path + self.raster_path.append(self.out_ndvistats_folder_tab[0]) + # List of output raster band + self.list_band_outraster.append(1) + + if vs == 1: + self.raster_path.append(self.out_ndvistats_folder_tab['sfs']) + self.list_band_outraster.append(4) + self.raster_path.append(self.out_ndvistats_folder_tab['haralick']) + self.list_band_outraster.append(2) + + # To slope, to extract scree + if self.path_mnt != '': + self.raster_path.append(self.path_mnt) + self.list_band_outraster.append(1) + + self.raster_path.append(self.out_ndvistats_folder_tab[2]) + # example raster path tab : + # [path_folder_dpt + '/' + folder_processing + '/' + classif_year + '/Min_2014.TIF',\ + # os.path.dirname(path_ortho) + '/Clip_buffer_surface_dep_18_IRCOrtho65_2m_sfs.TIF',\ + # os.path.dirname(path_ortho) + '/Clip_buffer_surface_dep_18_IRCOrtho65_2m_haralick.TIF',\ + # path_folder_dpt + '/' + folder_processing + '/' + classif_year + '/Max_2014.TIF'] + + # List of output raster band + self.list_band_outraster.append(1) #[1, 4, 2, 1] + + self.logger.info("End of images processing !") + + def i_rpg(self, path_rpg): + """ + Interface function to extract mono rpg crops. + + :param path_rpg: Input RPG shapefile. + :type path_rpg: str + + :returns: str -- variable **Rpg.vector_used**, output no duplicated crops shapefile (path). + """ + + # Extract mono rpg crops + mono_sample = Rpg(path_rpg, self.path_area) + # If exists, do not create a mono rpg file + if os.path.basename(str(path_rpg))[:5]!='MONO_': + mono_sample.mono_rpg() + mono_sample.create_new_rpg_files() + else: + print('MONO RPG file exists already !!!') + print('End of RPG processing') + + return mono_sample.vector_used + + def i_sample(self): + """ + Interface function to compute threshold with various sample. It also extract a list of validation layer (shapefile) + to compute the precision of the next classification :func:`i_validate`. + + It create samples 2 by 2 with kwargs field names and class :func:`Sample.Sample.create_sample`. + Then, it compute zonal statistics by polygons :func:`Vector.Sample.zonal_stats`. + + With zonal statistics computed, a optimal threshold is determined :func:`Seath.Seath.separability_and_threshold` that + will print in a text file .lg in the main folder. + + .. warning:: :func:`Seath.Seath.separability_and_threshold` does not always allow to discriminate optimal threshold. + Then, this function will be launch at least ten time until it reaches a optimal threshold. + """ + + # Compute threshold with various sample + i_s = 0 + while i_s < 10: + try : + self.valid_shp = [] + sample_rd = {} + for sple in range(len(self.sample_name) * 2): + kwargs = {} + kwargs['fieldname'] = self.fieldname_args[sple] + kwargs['class'] = self.class_args[sple] + sample_rd[sple] = Sample(self.sample_name[sple/2], self.path_area, self.list_nb_sample[sple/2]) + sample_rd[sple].create_sample(**kwargs) + sample_rd[sple].zonal_stats((self.raster_path[sple/2], self.list_band_outraster[sple/2])) + + # Add the validation shapefile + self.valid_shp.append([sample_rd[sple].vector_val, kwargs['fieldname'], kwargs['class']]) + + # Search the optimal threshold by class + # Open a text file to print stats of Seath method + file_J = self.path_folder_dpt + '/log_J.lg' + f = open(file_J, "wb") + for th_seath in range(len(self.sample_name)): + self.decis[th_seath] = Seath() + self.decis[th_seath].value_1 = sample_rd[th_seath*2].stats_dict + self.decis[th_seath].value_2 = sample_rd[th_seath*2 + 1].stats_dict + self.decis[th_seath].separability_and_threshold() + + # Print the J value in the text file .lg + f.write('For ' + str(self.sample_name[th_seath]) + ' :\n') + f.write('J = ' + str(self.decis[th_seath].J[0]) +'\n') + f.write('The class 1 ' + str(self.decis[th_seath].threshold[0]) +'\n') + + f.close() + i_s = 20 + except: + i_s = i_s + 1 + # Method to stop the processus if there is not found a valid threshold + if i_s != 20: + print ('Problem in the sample processing !!!') + sys.exit(1) - """ + def i_sample_rf(self): + """ + This function build a random forest trees like model to create a final classification. + All of This using the method described in the :func:`i_validate` function and because + of sklearn module. + """ + + X_rf = [] + y_rf = [] + sample_rd = {} + # Tricks to add all textural indexes + rm_index = 1 + self.raster_path.remove(self.raster_path[rm_index]) # Remove SFS layer + self.raster_path.remove(self.raster_path[rm_index]) # Remove Haralick layer + self.list_band_outraster.remove(self.list_band_outraster[rm_index]) # Remove band of the layer + self.list_band_outraster.remove(self.list_band_outraster[rm_index]) # Remove band of the layer + # Add all layers in the simple index haralick + for add_layer in range(8): + self.raster_path.insert(add_layer+1, self.out_ndvistats_folder_tab['haralick']) + self.list_band_outraster.insert(add_layer+1, add_layer+1) + # Add all layers in the SFS index + for add_layer in range(6): + self.raster_path.insert(add_layer+1, self.out_ndvistats_folder_tab['sfs']) + self.list_band_outraster.insert(add_layer+1, add_layer+1) + + # Extract value mean from polygons + for sple in range(len(self.sample_name) * 2): + kwargs = {} + kwargs['fieldname'] = self.fieldname_args[sple] + kwargs['class'] = self.class_args[sple] + sample_rd[sple] = Sample(self.sample_name[round(sple/2)], self.path_area, self.list_nb_sample[round(sple/2)]) + + sample_rd[sple].create_sample(**kwargs) + + # Add the validation shapefile + self.valid_shp.append([sample_rd[sple].vector_val, kwargs['fieldname'], kwargs['class']]) - # Create texture image - # Clip orthography image - current_path_ortho = Toolbox() - current_path_ortho.imag = self.path_ortho - current_path_ortho.vect = self.path_area - path_ortho = current_path_ortho.clip_raster() - - texture_irc = Vhrs(path_ortho, self.mp) - self.out_ndvistats_folder_tab['sfs'] = texture_irc.out_sfs - self.out_ndvistats_folder_tab['haralick'] = texture_irc.out_haralick - - def i_images_processing(self, vs): - - """ - Interface function to launch processing VHRS images :func:`i_vhrs` and satellite images :func:`i_img_sat` in multi-processing. - - :param vs: Boolean variable to launch processing because of interface checkbox -> 0 or 1. - - - 0 means, not texture processing - - 1 means, launch texture processing - :type vs: int - """ - - # Multiprocessing - mgr = BaseManager() - mgr.register('defaultdict', defaultdict, DictProxy) - mgr.start() - self.out_ndvistats_folder_tab = mgr.defaultdict(list) - - p_img_sat = Process(target=self.i_img_sat) - p_img_sat.start() - if self.mp == 0: - p_img_sat.join() - - if vs == 1: - p_vhrs = Process(target=self.i_vhrs)#, args=(vs, )) - p_vhrs.start() - p_vhrs.join() - - if self.mp == 1: - p_img_sat.join() - - # List of output raster path - self.raster_path.append(self.out_ndvistats_folder_tab[0]) - # List of output raster band - self.list_band_outraster.append(1) - - if vs == 1: - self.raster_path.append(self.out_ndvistats_folder_tab['sfs']) - self.list_band_outraster.append(4) - self.raster_path.append(self.out_ndvistats_folder_tab['haralick']) - self.list_band_outraster.append(2) - - # To slope, to extract scree - if self.path_mnt != '': - self.raster_path.append(self.path_mnt) - self.list_band_outraster.append(1) - - self.raster_path.append(self.out_ndvistats_folder_tab[2]) - # example raster path tab : - # [path_folder_dpt + '/' + folder_processing + '/' + classif_year + '/Min_2014.TIF',\ - # os.path.dirname(path_ortho) + '/Clip_buffer_surface_dep_18_IRCOrtho65_2m_sfs.TIF',\ - # os.path.dirname(path_ortho) + '/Clip_buffer_surface_dep_18_IRCOrtho65_2m_haralick.TIF',\ - # path_folder_dpt + '/' + folder_processing + '/' + classif_year + '/Max_2014.TIF'] - - # List of output raster band - self.list_band_outraster.append(1) #[1, 4, 2, 1] - - print("End of images processing !") - - def i_rpg(self, path_rpg): - """ - Interface function to extract mono rpg crops. - - :param path_rpg: Input RPG shapefile. - :type path_rpg: str - - :returns: str -- variable **Rpg.vector_used**, output no duplicated crops shapefile (path). - """ - - # Extract mono rpg crops - mono_sample = Rpg(path_rpg, self.path_area) - # If exists, do not create a mono rpg file - if os.path.basename(str(path_rpg))[:5]!='MONO_': - mono_sample.mono_rpg() - mono_sample.create_new_rpg_files() - else: - print('MONO RPG file exists already !!!') - print('End of RPG processing') - - return mono_sample.vector_used - - def i_sample(self): - """ - Interface function to compute threshold with various sample. It also extract a list of validation layer (shapefile) - to compute the precision of the next classification :func:`i_validate`. - - It create samples 2 by 2 with kwargs field names and class :func:`Sample.Sample.create_sample`. - Then, it compute zonal statistics by polygons :func:`Vector.Sample.zonal_stats`. - - With zonal statistics computed, a optimal threshold is determined :func:`Seath.Seath.separability_and_threshold` that - will print in a text file .lg in the main folder. - - .. warning:: :func:`Seath.Seath.separability_and_threshold` does not always allow to discriminate optimal threshold. - Then, this function will be launch at least ten time until it reaches a optimal threshold. - """ - - # Compute threshold with various sample - i_s = 0 - while i_s < 10: - try : - self.valid_shp = [] - sample_rd = {} - for sple in range(len(self.sample_name) * 2): - kwargs = {} - kwargs['fieldname'] = self.fieldname_args[sple] - kwargs['class'] = self.class_args[sple] - sample_rd[sple] = Sample(self.sample_name[sple/2], self.path_area, self.list_nb_sample[sple/2]) - sample_rd[sple].create_sample(**kwargs) - sample_rd[sple].zonal_stats((self.raster_path[sple/2], self.list_band_outraster[sple/2])) - - # Add the validation shapefile - self.valid_shp.append([sample_rd[sple].vector_val, kwargs['fieldname'], kwargs['class']]) - - # Search the optimal threshold by class - # Open a text file to print stats of Seath method - file_J = self.path_folder_dpt + '/log_J.lg' - f = open(file_J, "wb") - for th_seath in range(len(self.sample_name)): - self.decis[th_seath] = Seath() - self.decis[th_seath].value_1 = sample_rd[th_seath*2].stats_dict - self.decis[th_seath].value_2 = sample_rd[th_seath*2 + 1].stats_dict - self.decis[th_seath].separability_and_threshold() - - # Print the J value in the text file .lg - f.write('For ' + str(self.sample_name[th_seath]) + ' :\n') - f.write('J = ' + str(self.decis[th_seath].J[0]) +'\n') - f.write('The class 1 ' + str(self.decis[th_seath].threshold[0]) +'\n') - - f.close() - i_s = 20 - except: - i_s = i_s + 1 - # Method to stop the processus if there is not found a valid threshold - if i_s != 20: - print ('Problem in the sample processing !!!') - sys.exit(1) - - def i_sample_rf(self): - """ - This function build a random forest trees like model to create a final classification. - All of This using the method described in the :func:`i_validate` function and because - of sklearn module. - """ - - X_rf = [] - y_rf = [] - sample_rd = {} - # Tricks to add all textural indexes - rm_index = 1 - self.raster_path.remove(self.raster_path[rm_index]) # Remove SFS layer - self.raster_path.remove(self.raster_path[rm_index]) # Remove Haralick layer - self.list_band_outraster.remove(self.list_band_outraster[rm_index]) # Remove band of the layer - self.list_band_outraster.remove(self.list_band_outraster[rm_index]) # Remove band of the layer - # Add all layers in the simple index haralick - for add_layer in range(8): - self.raster_path.insert(add_layer+1, self.out_ndvistats_folder_tab['haralick']) - self.list_band_outraster.insert(add_layer+1, add_layer+1) - # Add all layers in the SFS index - for add_layer in range(6): - self.raster_path.insert(add_layer+1, self.out_ndvistats_folder_tab['sfs']) - self.list_band_outraster.insert(add_layer+1, add_layer+1) - - # Extract value mean from polygons - for sple in range(len(self.sample_name) * 2): - kwargs = {} - kwargs['fieldname'] = self.fieldname_args[sple] - kwargs['class'] = self.class_args[sple] - sample_rd[sple] = Sample(self.sample_name[sple/2], self.path_area, self.list_nb_sample[sple/2]) - sample_rd[sple].create_sample(**kwargs) - - # Add the validation shapefile - self.valid_shp.append([sample_rd[sple].vector_val, kwargs['fieldname'], kwargs['class']]) + for lbo in range(len(self.raster_path)): + kwargs['rank'] = lbo + kwargs['nb_img'] = len(self.raster_path) + sample_rd[sple].zonal_stats(self.raster_path[lbo], self.list_band_outraster[lbo], **kwargs) + + # To convert the dictionnary in a list + # for key, value in sample_rd[sple].stats_dict.iteritems(): + for key, value in sample_rd[sple].stats_dict.items(): +# X_rf.append([-10000 if (math.isnan(x) or math.isinf(x)) else x for x in value]) + # To set the grassland class of the RPG and PIAO (same class) + if sple == 2: +# y_rf.append(1) + pass + elif sple == 3: +# y_rf.append(4) + pass + else: + y_rf.append(sple) + X_rf.append([-10000 if (x is None or math.isnan(x) or math.isinf(x)) else x for x in value]) + + # Build a forest of trees from the samples + self.rf = self.rf.fit(X_rf, y_rf) + + # Print in a file feature important + importance = self.rf.feature_importances_ + importance = [(importance[x],x+1) for x in range(len(importance))] + importance.sort() + + file_feat_import = os.path.dirname(str(self.raster_path[0])) + '/Feature_important_RF.ft' + if os.path.exists(file_feat_import): + os.remove(file_feat_import) + + with open(file_feat_import, "w") as f_out : + f_out.write(str(importance)) + + # Print in a file decision tree + file_decisiontree = os.path.dirname(str(self.raster_path[0])) + '/Decision_tree.dot' + + if os.path.exists(file_decisiontree): + os.remove(file_decisiontree) + + tree_in_forest = self.rf.estimators_[499] + with open(file_decisiontree, 'w') as my_file: + my_file = tree.export_graphviz(tree_in_forest, out_file = my_file) - for lbo in range(len(self.raster_path)): - kwargs['rank'] = lbo - kwargs['nb_img'] = len(self.raster_path) - sample_rd[sple].zonal_stats((self.raster_path[lbo], self.list_band_outraster[lbo]), **kwargs) - - # To convert the dictionnary in a list - for key, value in sample_rd[sple].stats_dict.iteritems(): -# X_rf.append([-10000 if (math.isnan(x) or math.isinf(x)) else x for x in value]) - # To set the grassland class of the RPG and PIAO (same class) - if sple == 2: -# y_rf.append(1) - pass - elif sple == 3: -# y_rf.append(4) - pass - else: - y_rf.append(sple) - X_rf.append([-10000 if (math.isnan(x) or math.isinf(x)) else x for x in value]) - - # Build a forest of trees from the samples - self.rf = self.rf.fit(X_rf, y_rf) - - # Print in a file feature important - importance = self.rf.feature_importances_ - importance = [(importance[x],x+1) for x in range(len(importance))] - importance.sort() - - file_feat_import = os.path.dirname(str(self.raster_path[0])) + '/Feature_important_RF.ft' - if os.path.exists(file_feat_import): - os.remove(file_feat_import) - f_out = open(file_feat_import, "wb") - f_out.write(str(importance)) - # Close the output file - f_out.close() - - # Print in a file decision tree - file_decisiontree = os.path.dirname(str(self.raster_path[0])) + '/Decision_tree.dot' - if os.path.exists(file_decisiontree): - os.remove(file_decisiontree) - - tree_in_forest = self.rf.estimators_[499] - with open(file_decisiontree, 'w') as my_file: - my_file = tree.export_graphviz(tree_in_forest, out_file = my_file) + def i_classifier_rf(self): + """ + Interface function to launch random forest classification with a input segmentation :func:`Segmentation.Segmentation`. + + This function use the sklearn module to build the best of decision tree to extract classes. + The optimal threshold are stored by class **rf** variable in :func:`Processing.i_sample_rf`. Then it computes zonal statistics by polygons + for every images in multi-processing (if **mp** = 1). + """ + + # Multiprocessing + mgr = BaseManager() + mgr.register('defaultdict', defaultdict, DictProxy) + mgr.start() + multi_process_var = [] # Multi processing variable + + # Extract final cartography + out_carto = Segmentation(self.path_segm, self.path_area) + out_carto.output_file = self.output_name_moba + out_carto.out_class_name = self.in_class_name +# out_carto.out_threshold = [] - def i_classifier_rf(self): - """ - Interface function to launch random forest classification with a input segmentation :func:`Segmentation.Segmentation`. - - This function use the sklearn module to build the best of decision tree to extract classes. - The optimal threshold are stored by class **rf** variable in :func:`Processing.i_sample_rf`. Then it computes zonal statistics by polygons - for every images in multi-processing (if **mp** = 1). - """ - - # Multiprocessing - mgr = BaseManager() - mgr.register('defaultdict', defaultdict, DictProxy) - mgr.start() - multi_process_var = [] # Multi processing variable - - # Extract final cartography - out_carto = Segmentation(self.path_segm, self.path_area) - out_carto.output_file = self.output_name_moba - out_carto.out_class_name = self.in_class_name -# out_carto.out_threshold = [] - for ind_th in range(len(self.raster_path)): - multi_process_var.append([self.raster_path[ind_th], self.list_band_outraster[ind_th]]) + for ind_th in range(len(self.raster_path)): + multi_process_var.append([self.raster_path[ind_th], self.list_band_outraster[ind_th]]) - # Compute zonal stats with multi processing - exist_stats = 1 # By default, the stats file exists already - file_stats = os.path.dirname(str(self.raster_path[0])) + '/Stats_raster_spectral_texture.stats' # Stats backup file - if not os.path.exists(file_stats): - exist_stats = 0 # The sats file doesn't exist - # Open a stats backup to avoid computing again (Gain of time) - f_out = open(file_stats, "wb") - - p = [] - kwargs = {} - X_out_rf = [] # Variable list to compute decision tree with random forest method - if exist_stats == 0: - out_carto.stats_dict = mgr.defaultdict(list) - for i in range(len(multi_process_var)): - kwargs['rank'] = i - kwargs['nb_img'] = len(multi_process_var) - p.append(Process(target=out_carto.zonal_stats, args=(multi_process_var[i], ), kwargs=kwargs)) - p[i].start() - - if self.mp == 0: - p[i].join() - - if self.mp == 1: - for i in range(len(multi_process_var)): - p[i].join() - - for key, value_seg in out_carto.stats_dict.items(): - true_value = [-10000 if (math.isnan(x) or math.isinf(x)) else x for x in value_seg] - X_out_rf.append(true_value) - - # Print rasters stats value in the text file .lg - f_out.write(str(true_value) + '\n') - - # Close the output file - f_out.close() - - else: - # If the stats file exists already, open this file and append in the stats_dict variable - out_carto.stats_dict = defaultdict(list) - with open(file_stats, "r") as f_in: - index_in_stats=-1 - for x_in in f_in.readlines(): - index_in_stats = index_in_stats + 1 - out_carto.stats_dict[index_in_stats] = eval(x_in.strip('\n')) - X_out_rf.append(eval(x_in.strip('\n'))) - - predicted_rf = self.rf.predict(X_out_rf) - - # For the higher than level 1 - if len(self.sample_name) > 2: - # Compute the biomass and density distribution - # Use 'out_carto.out_threshold' to konw predicted in the segmentation class - out_carto.out_threshold = predicted_rf - # In the compute_biomass_density function, this variable used normally to define - # threshold of the classification with SEATH method is initialized - out_carto.compute_biomass_density('RF') - - out_carto.class_tab_final = defaultdict(list) - for i_polyg in range(len(predicted_rf)): - i_final = 0 - class_final = [] - # Initialize the predicted output format - # For example : predicted => 4, formatted => [1,3,4] - while i_final < len(self.tree_direction): - if self.tree_direction[i_final][len(self.tree_direction[i_final])-1] == predicted_rf[i_polyg]: - class_final = self.tree_direction[i_final] - i_final = len(self.tree_direction) - i_final = i_final + 1 - - if class_final == []: - class_final = [1, 2] - # Set the class name because of predicted output formatted - out_carto.class_tab_final[i_polyg] = [self.in_class_name[f] for f in class_final] + \ - [predicted_rf[i_polyg]] + [predicted_rf[i_polyg]] - - # For the output line with one level, add a phantom level - # TODO : Replace constant by a variable in the condition 'while' - while len(out_carto.class_tab_final[i_polyg]) < 5: - out_carto.class_tab_final[i_polyg].insert(len(out_carto.class_tab_final[i_polyg])-2,'') - - # If there is more one fieldnames line edit fulled in classification tab - if len(self.sample_name) > 2: - # Compute biomass and density scale - out_carto.append_scale(self.in_class_name[2], 'self.stats_dict[ind_stats][3]/self.max_bio') - out_carto.append_scale(self.in_class_name[3], 'self.stats_dict[ind_stats][2]/self.max_wood_idm') - - # Rasterize RPG shapefile to complete the final shapefile - opt = {} - opt['Remove'] = 1 - rpg_tif = Vector(self.sample_name[0], self.path_area, **opt) -# if not os.path.exists(str(rpg_tif.vector_used[:-3]+'TIF')): - kwargs['choice_nb_b'] = 1 - out_carto.stats_rpg_tif = out_carto.zonal_stats_pp(rpg_tif.layer_rasterization(self.path_ortho, 'CODE_GROUP', **kwargs)) + # Compute zonal stats with multi processing + exist_stats = 1 # By default, the stats file exists already + file_stats = os.path.dirname(str(self.raster_path[0])) + '/Stats_raster_spectral_texture.stats' # Stats backup file + if not os.path.exists(file_stats): + exist_stats = 0 # The sats file doesn't exist + # Open a stats backup to avoid computing again (Gain of time) + f_out = open(file_stats, "w") + + p = [] + kwargs = {} + X_out_rf = [] # Variable list to compute decision tree with random forest method + if exist_stats == 0: + out_carto.stats_dict = mgr.defaultdict(list) + + for i in range(len(multi_process_var)): + kwargs['rank'] = i + kwargs['nb_img'] = len(multi_process_var) + p.append(Process(target=out_carto.zonal_stats, args=(*multi_process_var[i], ), kwargs=kwargs)) + p[i].start() + + if self.mp == Constantes.MULTIPROCESSING_DISABLE: + p[i].join() + + if self.mp == Constantes.MULTIPROCESSING_ENABLE: + for i in range(len(multi_process_var)): + p[i].join() + + for key, value_seg in out_carto.stats_dict.items(): + true_value = [-10000 if (x == None or math.isnan(x) or math.isinf(x)) else x for x in value_seg] + X_out_rf.append(true_value) + + # Print rasters stats value in the text file .lg + f_out.write(str(true_value) + '\n') + + # Close the output file + f_out.close() + + else: + # If the stats file exists already, open this file and append in the stats_dict variable + out_carto.stats_dict = defaultdict(list) + with open(file_stats, "r") as f_in: + index_in_stats=-1 + for x_in in f_in.readlines(): + index_in_stats = index_in_stats + 1 + out_carto.stats_dict[index_in_stats] = eval(x_in.strip('\n')) + X_out_rf.append(eval(x_in.strip('\n'))) + + predicted_rf = self.rf.predict(X_out_rf) + + # For the higher than level 1 + if len(self.sample_name) > 2: + # Compute the biomass and density distribution + # Use 'out_carto.out_threshold' to konw predicted in the segmentation class + out_carto.out_threshold = predicted_rf + # In the compute_biomass_density function, this variable used normally to define + # threshold of the classification with SEATH method is initialized + out_carto.compute_biomass_density('RF') + + out_carto.class_tab_final = defaultdict(list) + for i_polyg in range(len(predicted_rf)): + i_final = 0 + class_final = [] + # Initialize the predicted output format + # For example : predicted => 4, formatted => [1,3,4] + while i_final < len(self.tree_direction): + if self.tree_direction[i_final][len(self.tree_direction[i_final])-1] == predicted_rf[i_polyg]: + class_final = self.tree_direction[i_final] + i_final = len(self.tree_direction) + i_final = i_final + 1 + + if class_final == []: + class_final = [1, 2] + # Set the class name because of predicted output formatted + out_carto.class_tab_final[i_polyg] = [self.in_class_name[f] for f in class_final] + \ + [predicted_rf[i_polyg]] + [predicted_rf[i_polyg]] + + # For the output line with one level, add a phantom level + # TODO : Replace constant by a variable in the condition 'while' + while len(out_carto.class_tab_final[i_polyg]) < 5: + out_carto.class_tab_final[i_polyg].insert(len(out_carto.class_tab_final[i_polyg])-2,'') + + # If there is more one fieldnames line edit fulled in classification tab + if len(self.sample_name) > 2: + # Compute biomass and density scale + out_carto.append_scale(self.in_class_name[2], 'self.stats_dict[ind_stats][3]/self.max_bio') + out_carto.append_scale(self.in_class_name[3], 'self.stats_dict[ind_stats][2]/self.max_wood_idm') + + # Rasterize RPG shapefile to complete the final shapefile + opt = {} + opt['Remove'] = 1 + rpg_tif = Vector(self.sample_name[0], self.path_area, **opt) +# if not os.path.exists(str(rpg_tif.vector_used[:-3]+'TIF')): + kwargs['choice_nb_b'] = 1 + out_carto.stats_rpg_tif = out_carto.zonal_stats_pp(rpg_tif.layer_rasterization(self.path_ortho, 'CODE_GROUP', **kwargs)) - # Final cartography - out_carto.create_cartography(self.out_fieldname_carto, self.out_fieldtype_carto) - - def i_classifier_s(self): - """ - Interface function to launch decision tree classification with a input segmentation :func:`Segmentation.Segmentation`. - - This function store optimal threshold by class **Segmentation.out_threshold**. Then it computes zonal statistics by polygons - for every images in multi-processing (if **mp** = 1). - """ - - # Multiprocessing - mgr = BaseManager() - mgr.register('defaultdict', defaultdict, DictProxy) - mgr.start() - multi_process_var = [] # Multi processing variable - - # Extract final cartography - out_carto = Segmentation(self.path_segm, self.path_area) - out_carto.output_file = self.output_name_moba - out_carto.out_class_name = self.in_class_name - out_carto.out_threshold = [] - for ind_th in range(len(self.sample_name)): - out_carto.out_threshold.append(self.decis[ind_th].threshold[0]) - if '>' in self.decis[ind_th].threshold[0]: - out_carto.out_threshold.append(self.decis[ind_th].threshold[0].replace('>', '<=')) - elif '<' in self.decis[ind_th].threshold[0]: - out_carto.out_threshold.append(self.decis[ind_th].threshold[0].replace('<', '>=')) - # out_carto.zonal_stats((raster_path[ind_th], list_band_outraster[ind_th])) - multi_process_var.append([self.raster_path[ind_th], self.list_band_outraster[ind_th]]) - - # Compute zonal stats on slope raster - multi_process_var.append([self.raster_path[ind_th+1], self.list_band_outraster[ind_th+1]]) - out_carto.out_threshold.append('<'+str(self.slope_degree)) # To agriculture - out_carto.out_threshold.append('>='+str(self.slope_degree)) # To scree - if self.path_mnt != '': - # Add class indexes - self.tree_direction[0].append(6) - self.tree_direction[0].append(7) - - # Compute zonal stats on Max NDVI raster - try: - # out_carto.zonal_stats((raster_path[ind_th+1], list_band_outraster[ind_th+1])) - multi_process_var.append([self.raster_path[ind_th+2], self.list_band_outraster[ind_th+2]]) - # Compute stats twice, because there is 3 classes and not 2 - # out_carto.zonal_stats((raster_path[ind_th+1], list_band_outraster[ind_th+1])) - multi_process_var.append([self.raster_path[ind_th+2], self.list_band_outraster[ind_th+2]]) - except: - print('Not MNT on the 3rd step') - multi_process_var.append([self.raster_path[ind_th+1], self.list_band_outraster[ind_th+1]]) - multi_process_var.append([self.raster_path[ind_th+1], self.list_band_outraster[ind_th+1]]) + # Final cartography + out_carto.create_cartography(self.out_fieldname_carto, self.out_fieldtype_carto) + + def i_classifier_s(self): + """ + Interface function to launch decision tree classification with a input segmentation :func:`Segmentation.Segmentation`. + + This function store optimal threshold by class **Segmentation.out_threshold**. Then it computes zonal statistics by polygons + for every images in multi-processing (if **mp** = 1). + """ + + # Multiprocessing + mgr = BaseManager() + mgr.register('defaultdict', defaultdict, DictProxy) + mgr.start() + multi_process_var = [] # Multi processing variable + + # Extract final cartography + out_carto = Segmentation(self.path_segm, self.path_area) + out_carto.output_file = self.output_name_moba + out_carto.out_class_name = self.in_class_name + out_carto.out_threshold = [] + for ind_th in range(len(self.sample_name)): + out_carto.out_threshold.append(self.decis[ind_th].threshold[0]) + if '>' in self.decis[ind_th].threshold[0]: + out_carto.out_threshold.append(self.decis[ind_th].threshold[0].replace('>', '<=')) + elif '<' in self.decis[ind_th].threshold[0]: + out_carto.out_threshold.append(self.decis[ind_th].threshold[0].replace('<', '>=')) + # out_carto.zonal_stats((raster_path[ind_th], list_band_outraster[ind_th])) + multi_process_var.append([self.raster_path[ind_th], self.list_band_outraster[ind_th]]) + + # Compute zonal stats on slope raster + multi_process_var.append([self.raster_path[ind_th+1], self.list_band_outraster[ind_th+1]]) + out_carto.out_threshold.append('<'+str(self.slope_degree)) # To agriculture + out_carto.out_threshold.append('>='+str(self.slope_degree)) # To scree + if self.path_mnt != '': + # Add class indexes + self.tree_direction[0].append(6) + self.tree_direction[0].append(7) + + # Compute zonal stats on Max NDVI raster + try: + # out_carto.zonal_stats((raster_path[ind_th+1], list_band_outraster[ind_th+1])) + multi_process_var.append([self.raster_path[ind_th+2], self.list_band_outraster[ind_th+2]]) + # Compute stats twice, because there is 3 classes and not 2 + # out_carto.zonal_stats((raster_path[ind_th+1], list_band_outraster[ind_th+1])) + multi_process_var.append([self.raster_path[ind_th+2], self.list_band_outraster[ind_th+2]]) + except: + print('Not MNT on the 3rd step') + multi_process_var.append([self.raster_path[ind_th+1], self.list_band_outraster[ind_th+1]]) + multi_process_var.append([self.raster_path[ind_th+1], self.list_band_outraster[ind_th+1]]) - # Compute zonal stats with multi processing - exist_stats = 1 # By default, the stats file exists already - file_stats = os.path.dirname(str(self.raster_path[0])) + '/Stats_raster_spectral_texture.stats' # Stats backup file - if not os.path.exists(file_stats): - exist_stats = 0 # The sats file doesn't exist - # Open a stats backup to avoid computing again (Gain of time) - f_out = open(file_stats, "wb") - - p = [] - kwargs = {} - X_out_rf = [] # Variable list to compute decision tree with random forest method - if exist_stats == 0: - out_carto.stats_dict = mgr.defaultdict(list) - for i in range(len(multi_process_var)): - kwargs['rank'] = i - kwargs['nb_img'] = len(multi_process_var) - p.append(Process(target=out_carto.zonal_stats, args=(multi_process_var[i], ), kwargs=kwargs)) - p[i].start() - - if self.mp == 0: - p[i].join() - - if self.mp == 1: - for i in range(len(multi_process_var)): - p[i].join() - - for key, value_seg in out_carto.stats_dict.items(): - - true_value = [-10000 if (math.isnan(x) or math.isinf(x)) else x for x in value_seg] - # Print rasters stats value in the text file .lg - f_out.write(str(true_value) + '\n') - - # Close the output file - f_out.close() - - else: - # If the stats file exists already, open this file and append in the stats_dict variable - out_carto.stats_dict = defaultdict(list) - with open(file_stats, "r") as f_in: - index_in_stats=-1 - for x_in in f_in.readlines(): - index_in_stats = index_in_stats + 1 - out_carto.stats_dict[index_in_stats] = eval(x_in.strip('\n')) - X_out_rf.append(eval(x_in.strip('\n'))) - - # For the higher than level 1 - if len(self.sample_name) > 2: - # Compute the biomass and density distribution - out_carto.compute_biomass_density() - - out_carto.class_tab_final = defaultdict(list) - self.i_tree_direction() - out_carto.decision_tree(self.tree_direction) - - # If there is more one fieldnames line edit fulled in classification tab - if len(self.sample_name) > 2: - # Compute biomass and density scale - out_carto.append_scale(self.in_class_name[2], 'self.stats_dict[ind_stats][3]/self.max_bio') - out_carto.append_scale(self.in_class_name[3], 'self.stats_dict[ind_stats][2]/self.max_wood_idm') - - # Rasterize RPG shapefile to complete the final shapefile - opt = {} - opt['Remove'] = 1 - rpg_tif = Vector(self.sample_name[0], self.path_area, **opt) - rpg_tif.layer_rasterization(self.path_ortho, 'CODE_GROUP') - - # Final cartography - out_carto.mono_rpg_tif = self.sample_name[0][:-4] + '.TIF' - out_carto.create_cartography(self.out_fieldname_carto, self.out_fieldtype_carto) - - def i_validate(self): - """ - Interface to validate a classification. It going to rasterize the validation shapefile and the - classification shapefile with :func:`layer_rasterization`. Next, to compare pixel by pixel, the classification - quality to built a confusion matrix in a csv file. - - """ - # Variable to convert the input classname to an individual interger - # Only for the validate sample - class_validate = 0 - complete_validate_shp = os.path.dirname(str(self.valid_shp[0][0])) + '/validate.shp' + # Compute zonal stats with multi processing + exist_stats = 1 # By default, the stats file exists already + file_stats = os.path.dirname(str(self.raster_path[0])) + '/Stats_raster_spectral_texture.stats' # Stats backup file + if not os.path.exists(file_stats): + exist_stats = 0 # The sats file doesn't exist + # Open a stats backup to avoid computing again (Gain of time) + f_out = open(file_stats, "wb") + + p = [] + kwargs = {} + X_out_rf = [] # Variable list to compute decision tree with random forest method + if exist_stats == 0: + out_carto.stats_dict = mgr.defaultdict(list) + for i in range(len(multi_process_var)): + kwargs['rank'] = i + kwargs['nb_img'] = len(multi_process_var) + p.append(Process(target=out_carto.zonal_stats, args=(multi_process_var[i], ), kwargs=kwargs)) + p[i].start() + + if self.mp == Constantes.MULTIPROCESSING_DISABLE: + p[i].join() + + if self.mp == Constantes.MULTIPROCESSING_ENABLE: + for i in range(len(multi_process_var)): + p[i].join() + + for key, value_seg in out_carto.stats_dict.items(): + + true_value = [-10000 if (math.isnan(x) or math.isinf(x)) else x for x in value_seg] + # Print rasters stats value in the text file .lg + f_out.write(str(true_value) + '\n') + + # Close the output file + f_out.close() + + else: + # If the stats file exists already, open this file and append in the stats_dict variable + out_carto.stats_dict = defaultdict(list) + with open(file_stats, "r") as f_in: + index_in_stats=-1 + for x_in in f_in.readlines(): + index_in_stats = index_in_stats + 1 + out_carto.stats_dict[index_in_stats] = eval(x_in.strip('\n')) + X_out_rf.append(eval(x_in.strip('\n'))) + + # For the higher than level 1 + if len(self.sample_name) > 2: + # Compute the biomass and density distribution + out_carto.compute_biomass_density() + + out_carto.class_tab_final = defaultdict(list) + self.i_tree_direction() + out_carto.decision_tree(self.tree_direction) + + # If there is more one fieldnames line edit fulled in classification tab + if len(self.sample_name) > 2: + # Compute biomass and density scale + out_carto.append_scale(self.in_class_name[2], 'self.stats_dict[ind_stats][3]/self.max_bio') + out_carto.append_scale(self.in_class_name[3], 'self.stats_dict[ind_stats][2]/self.max_wood_idm') + + # Rasterize RPG shapefile to complete the final shapefile + opt = {} + opt['Remove'] = 1 + rpg_tif = Vector(self.sample_name[0], self.path_area, **opt) + rpg_tif.layer_rasterization(self.path_ortho, 'CODE_GROUP') + + # Final cartography + out_carto.mono_rpg_tif = self.sample_name[0][:-4] + '.TIF' + out_carto.create_cartography(self.out_fieldname_carto, self.out_fieldtype_carto) + + def i_validate(self): + """ + Interface to validate a classification. It going to rasterize the validation shapefile and the + classification shapefile with :func:`layer_rasterization`. Next, to compare pixel by pixel, the classification + quality to built a confusion matrix in a csv file. + + """ + # Variable to convert the input classname to an individual interger + # Only for the validate sample + class_validate = 0 + complete_validate_shp = os.path.dirname(str(self.valid_shp[0][0])) + '/validate.shp' - # TODO: Set this method in the Precision_moba class + # TODO: Set this method in the Precision_moba class - - # Processing to rasterize the validate shapefile. 1) Merge sahpefiles 2) Rasterization - for val in self.valid_shp: - if class_validate != 2: - # Grassland to 1 - if (class_validate !=3 and len(self.out_fieldname_carto) != 4+2) or len(self.out_fieldname_carto) == 4+2: - # To the level 3 with woodeen to 4 and 5 - # - # Self.valid_shp is a list of list. In this variable there is : - # [Shapefile path, fieldname classes, classnames] - opt = {} - opt['Remove'] = 1 # To overwrite - - # Create a raster to valide the classification - # First time, create a new shapefile with a new field integer - sample_val = Sample(val[0], self.path_area, 1, **opt) - opt['add_fieldname'] = 1 - opt['fieldname'] = 'CLASS_CODE' - opt['class'] = str(class_validate) # Add integer classes - # Set the new shapefile - val[0] = val[0][:-4] + '_.shp' - val[1] = opt['fieldname'] - val[2] = opt['class'] - # Complete the new shapefile - sample_val.fill_sample(val[0], 0, **opt) - # Second time, merge the validate shapefile - if class_validate == 0: - process_tocall_merge = ['ogr2ogr', '-overwrite', complete_validate_shp, val[0]] - elif class_validate > 0: - process_tocall_merge = ['ogr2ogr', '-update', '-append', complete_validate_shp, \ - val[0], '-nln', os.path.basename(str(complete_validate_shp[:-4]))] - subprocess.call(process_tocall_merge) - # Increrment variable - class_validate = self.valid_shp.index(val) + 1 - - # Compute precision of the classification - valid = Precision_moba(self.path_area, self.path_folder_dpt) - valid.complete_validation_shp = complete_validate_shp - valid.ex_raster = self.raster_path[0] - - # TODO: Call the RasterSat_by_Date class here instead of the Precision_moba class - - valid.preprocess_to_raster_precision(self.output_name_moba, 'FBPHY_CODE') # To the classification's data - valid.preprocess_to_raster_precision(complete_validate_shp, val[1]) # To the validation's data - - # Compute precision on the output classification - valid.confus_matrix(valid.complete_img[0].raster_data(valid.img_pr[0])[0], \ - valid.complete_img[1].raster_data(valid.img_pr[1])[0]) + + # Processing to rasterize the validate shapefile. 1) Merge sahpefiles 2) Rasterization + for val in self.valid_shp: + if class_validate != 2: + # Grassland to 1 + if (class_validate !=3 and len(self.out_fieldname_carto) != 4+2) or len(self.out_fieldname_carto) == 4+2: + # To the level 3 with woodeen to 4 and 5 + # + # Self.valid_shp is a list of list. In this variable there is : + # [Shapefile path, fieldname classes, classnames] + opt = {} + opt['Remove'] = 1 # To overwrite + + # Create a raster to valide the classification + # First time, create a new shapefile with a new field integer + sample_val = Sample(val[0], self.path_area, 1, **opt) + opt['add_fieldname'] = 1 + opt['fieldname'] = 'CLASS_CODE' + opt['class'] = str(class_validate) # Add integer classes + # Set the new shapefile + val[0] = val[0][:-4] + '_.shp' + val[1] = opt['fieldname'] + val[2] = opt['class'] + # Complete the new shapefile + sample_val.fill_sample(val[0], 0, **opt) + # Second time, merge the validate shapefile + if class_validate == 0: + process_tocall_merge = ['ogr2ogr', '-overwrite', complete_validate_shp, val[0]] + elif class_validate > 0: + process_tocall_merge = ['ogr2ogr', '-update', '-append', complete_validate_shp, \ + val[0], '-nln', os.path.basename(str(complete_validate_shp[:-4]))] + subprocess.call(process_tocall_merge) + # Increrment variable + class_validate = self.valid_shp.index(val) + 1 + + # Compute precision of the classification + valid = Precision_moba(self.path_area, self.path_folder_dpt) + valid.complete_validation_shp = complete_validate_shp + valid.ex_raster = self.raster_path[0] + + # TODO: Call the RasterSat_by_Date class here instead of the Precision_moba class + + valid.preprocess_to_raster_precision(self.output_name_moba, 'FBPHY_CODE') # To the classification's data + valid.preprocess_to_raster_precision(complete_validate_shp, val[1]) # To the validation's data + + # Compute precision on the output classification + valid.confus_matrix(valid.complete_img[0].raster_data(valid.img_pr[0])[0], valid.complete_img[1].raster_data(valid.img_pr[1])[0]) diff --git a/RasterSat_by_date.py b/RasterSat_by_date.py index ef9489f417b9b7e4c556635abba9aaed4f147cbb..0f44f9670154e6c30dee28bc602eef592c70c06b 100644 --- a/RasterSat_by_date.py +++ b/RasterSat_by_date.py @@ -20,389 +20,389 @@ import os, sys import math, subprocess try : - import gdal + import gdal except : - from osgeo import gdal + from osgeo import gdal import numpy as np class RasterSat_by_date(): - """ - Satellite image processing's class. This class include several processes to group images by date, mosaic images by date, - extract images information, compute ndvi, compute cloud pourcent and create new rasters. - - :param class_archive: Archive class name with every information on downloaded images - :type class_archive: class - :param big_folder: Image processing folder - :type big_folder: str - :param one_date: [year, month, day] ... - This variable is modified in the function :func:`mosaic_by_date()`. - To append mosaic image path, mosaic cloud image path, cloud pixel value table, mosaic ndvi image path and ndvi pixel value table. - :type one_date: list of str - :param choice_nb_b: A option to choice output image number of band :func:`layer_rasterization` in Vector's class. If this option is 0, it take input band. By default 0. - :type choice_nb_b: int - - """ - def __init__(self, class_archive, big_folder, one_date): - """Create a new 'Landsat_by_date' instance - - """ - - self._class_archive = class_archive - self._big_folder = big_folder - self._one_date = one_date - # Verify list of list of str - if one_date == []: - print ("Enter dates to mosaic images like [[str(year), str(month), str(day)], [str(year), str(month), str(day)], ...]") - sys.exit(1) - else: - self._one_date = one_date - - self.out_ds = None - self.choice_nb_b = 0 - - def group_by_date(self, d_uni): - """ - Function to extract images on a single date - - :param d_uni: [year, month, day] - :type d_uni: list of str - - :returns: list of str -- variable **group** = [year, month, day, multispectral image path, cloud image path] - """ - - # Group of images with the same date - group = [] - - # Take images with the same date - for d_dup in self._class_archive.list_img: - if d_dup[:3] == d_uni: - group.append(d_dup) - - return group - - def vrt_translate_gdal(self, vrt_translate, src_data, dst_data): - """ - Function to launch gdal tools in command line. With ``gdalbuildvrt`` and ``gdal_translate``. - This function is used :func:`mosaic_by_date` to mosaic image by date. - - :param vrt_translate: ``vrt`` or ``translate`` - :type vrt_translate: str - :param src_data: Data source. Several data for vrt process and one data (vrt data) for gdal_translate - :type src_data: list (process ``vrt``) or str (process ``translate``) - :param dst_data: Output path - :type dst_data: str - """ - - if os.path.exists(dst_data): - os.remove(dst_data) - - # Select process - if vrt_translate == 'vrt': - # Verify input data - if type(src_data) is not np.ndarray and type(src_data) is not list: - print ('VRT file ! The data source should be composed of several data. A list minimal of 2 dimensions') - sys.exit(1) - - print ('Build VRT file') - if not os.path.exists(dst_data): - process_tocall = ['gdalbuildvrt', '-srcnodata', '-10000', dst_data] - - # Copy rasters - for cp_image in src_data: - process_tocall.append(cp_image) - - elif vrt_translate == 'translate': - # Verify input data - try : - src_data = str(src_data) - except:# if type(src_data) is not str: - print ('Geotiff file ! The data source should be composed of path file. A character string !') - sys.exit(1) - - print ('Build Geotiff file') - if not os.path.exists(dst_data): - process_tocall = ['gdal_translate', '-a_nodata', '-10000', src_data, dst_data] - - # Launch vrt process - subprocess.call(process_tocall) - - def mosaic_by_date(self): - """ - Function to merge images of the same date in a image group :func:`group_by_date`. - """ - - # Create the processing images folder if not exists - if not os.path.exists(self._class_archive._folder + '/' + self._big_folder): - os.mkdir(self._class_archive._folder + '/' + self._big_folder) - - # Matrix multi images for a single date - group = self.group_by_date(self._one_date) # Every images [year, month, day, multispectral image, cloud image] - group_ = np.transpose(np.array(group)) # Transpose matrix to extract path of images - - # Create a folder with images year if it doesn't exist - index_repertory_img = self._class_archive._captor - if not os.path.exists(self._class_archive._folder + '/' + self._big_folder + '/' + index_repertory_img): - os.mkdir(self._class_archive._folder + '/' + self._big_folder + '/' + index_repertory_img) - - index_repertory_img = index_repertory_img + '/' - # Create a folder with images date if it doesn't exist - for d_ in self._one_date: - index_repertory_img = index_repertory_img + d_ - - if not os.path.exists(self._class_archive._folder + '/' + self._big_folder + '/' + index_repertory_img): - os.mkdir(self._class_archive._folder + '/' + self._big_folder + '/' + index_repertory_img) - - # Build VRT file with data images required - vrt_out = self._class_archive._folder + '/' + self._big_folder + '/' + index_repertory_img + '/' \ - + self._class_archive._captor + index_repertory_img.split("/")[1] + '.VRT' # Multispectral VRT outfile - if not os.path.exists(vrt_out): - self.vrt_translate_gdal('vrt', group_[3], vrt_out) - - vrtcloud_out = self._class_archive._folder + '/' + self._big_folder + '/' + index_repertory_img + '/' \ - + self._class_archive._captor + index_repertory_img.split("/")[1] + '_' + group_[4][0][-7:-4] + '.VRT' # Cloud TIF outfile - if not os.path.exists(vrtcloud_out): - self.vrt_translate_gdal('vrt', group_[4], vrtcloud_out) - - # Build Geotiff file with data images required - gtif_out = vrt_out[:-4] + '.TIF' # Multispectral VRT outfile - if not os.path.exists(gtif_out): - self.vrt_translate_gdal('translate', vrt_out, gtif_out) - self._one_date.append(gtif_out) - - gtifcloud_out = vrtcloud_out[:-4] + '.TIF' # Cloud TIF outfile - if not os.path.exists(gtifcloud_out): - self.vrt_translate_gdal('translate', vrtcloud_out, gtifcloud_out) - self._one_date.append(gtifcloud_out) - - def raster_data(self, img): - """ - Function to extract raster information. - Return table of pixel values and raster information like line number, pixel size, ... (gdal pointer) - - :param img: Raster path - :type img: str + """ + Satellite image processing's class. This class include several processes to group images by date, mosaic images by date, + extract images information, compute ndvi, compute cloud pourcent and create new rasters. + + :param class_archive: Archive class name with every information on downloaded images + :type class_archive: class + :param big_folder: Image processing folder + :type big_folder: str + :param one_date: [year, month, day] ... + This variable is modified in the function :func:`mosaic_by_date()`. + To append mosaic image path, mosaic cloud image path, cloud pixel value table, mosaic ndvi image path and ndvi pixel value table. + :type one_date: list of str + :param choice_nb_b: A option to choice output image number of band :func:`layer_rasterization` in Vector's class. If this option is 0, it take input band. By default 0. + :type choice_nb_b: int + + """ + def __init__(self, class_archive, big_folder, one_date): + """Create a new 'Landsat_by_date' instance + + """ + + self._class_archive = class_archive + self._big_folder = big_folder + self._one_date = one_date + # Verify list of list of str + if one_date == []: + print ("Enter dates to mosaic images like [[str(year), str(month), str(day)], [str(year), str(month), str(day)], ...]") + sys.exit(1) + else: + self._one_date = one_date + + self.out_ds = None + self.choice_nb_b = 0 + + def group_by_date(self, d_uni): + """ + Function to extract images on a single date + + :param d_uni: [year, month, day] + :type d_uni: list of str + + :returns: list of str -- variable **group** = [year, month, day, multispectral image path, cloud image path] + """ + + # Group of images with the same date + group = [] + + # Take images with the same date + for d_dup in self._class_archive.list_img: + if d_dup[:3] == d_uni: + group.append(d_dup) + + return group + + def vrt_translate_gdal(self, vrt_translate, src_data, dst_data): + """ + Function to launch gdal tools in command line. With ``gdalbuildvrt`` and ``gdal_translate``. + This function is used :func:`mosaic_by_date` to mosaic image by date. + + :param vrt_translate: ``vrt`` or ``translate`` + :type vrt_translate: str + :param src_data: Data source. Several data for vrt process and one data (vrt data) for gdal_translate + :type src_data: list (process ``vrt``) or str (process ``translate``) + :param dst_data: Output path + :type dst_data: str + """ + + if os.path.exists(dst_data): + os.remove(dst_data) + + # Select process + if vrt_translate == 'vrt': + # Verify input data + if type(src_data) is not np.ndarray and type(src_data) is not list: + print ('VRT file ! The data source should be composed of several data. A list minimal of 2 dimensions') + sys.exit(1) + + print ('Build VRT file') + if not os.path.exists(dst_data): + process_tocall = ['gdalbuildvrt', '-srcnodata', '-10000', dst_data] + + # Copy rasters + for cp_image in src_data: + process_tocall.append(cp_image) + + elif vrt_translate == 'translate': + # Verify input data + try : + src_data = str(src_data) + except:# if type(src_data) is not str: + print ('Geotiff file ! The data source should be composed of path file. A character string !') + sys.exit(1) + + print ('Build Geotiff file') + if not os.path.exists(dst_data): + process_tocall = ['gdal_translate', '-a_nodata', '-10000', src_data, dst_data] + + # Launch vrt process + subprocess.call(process_tocall) + + def mosaic_by_date(self): + """ + Function to merge images of the same date in a image group :func:`group_by_date`. + """ + + # Create the processing images folder if not exists + if not os.path.exists(self._class_archive._folder + '/' + self._big_folder): + os.mkdir(self._class_archive._folder + '/' + self._big_folder) + + # Matrix multi images for a single date + group = self.group_by_date(self._one_date) # Every images [year, month, day, multispectral image, cloud image] + group_ = np.transpose(np.array(group)) # Transpose matrix to extract path of images + + # Create a folder with images year if it doesn't exist + index_repertory_img = self._class_archive._captor + if not os.path.exists(self._class_archive._folder + '/' + self._big_folder + '/' + index_repertory_img): + os.mkdir(self._class_archive._folder + '/' + self._big_folder + '/' + index_repertory_img) + + index_repertory_img = index_repertory_img + '/' + # Create a folder with images date if it doesn't exist + for d_ in self._one_date: + index_repertory_img = index_repertory_img + d_ + + if not os.path.exists(self._class_archive._folder + '/' + self._big_folder + '/' + index_repertory_img): + os.mkdir(self._class_archive._folder + '/' + self._big_folder + '/' + index_repertory_img) + + # Build VRT file with data images required + vrt_out = self._class_archive._folder + '/' + self._big_folder + '/' + index_repertory_img + '/' \ + + self._class_archive._captor + index_repertory_img.split("/")[1] + '.VRT' # Multispectral VRT outfile + if not os.path.exists(vrt_out): + self.vrt_translate_gdal('vrt', group_[3], vrt_out) + + vrtcloud_out = self._class_archive._folder + '/' + self._big_folder + '/' + index_repertory_img + '/' \ + + self._class_archive._captor + index_repertory_img.split("/")[1] + '_' + group_[4][0][-7:-4] + '.VRT' # Cloud TIF outfile + if not os.path.exists(vrtcloud_out): + self.vrt_translate_gdal('vrt', group_[4], vrtcloud_out) + + # Build Geotiff file with data images required + gtif_out = vrt_out[:-4] + '.TIF' # Multispectral VRT outfile + if not os.path.exists(gtif_out): + self.vrt_translate_gdal('translate', vrt_out, gtif_out) + self._one_date.append(gtif_out) + + gtifcloud_out = vrtcloud_out[:-4] + '.TIF' # Cloud TIF outfile + if not os.path.exists(gtifcloud_out): + self.vrt_translate_gdal('translate', vrtcloud_out, gtifcloud_out) + self._one_date.append(gtifcloud_out) + + def raster_data(self, img): + """ + Function to extract raster information. + Return table of pixel values and raster information like line number, pixel size, ... (gdal pointer) + + :param img: Raster path + :type img: str - :returns: numpy.array -- variable **data**, Pixel value matrix of a raster. - - gdal pointer -- variable **_in_ds**, Raster information. - """ - - # Load Gdal's drivers - gdal.AllRegister() - - # Loading input raster - print ('Loading input raster :', os.path.split(str(img))[1][:-4]) - in_ds = gdal.Open(str(img), gdal.GA_ReadOnly) - - # if it doesn't exist - if in_ds is None: - print('could not open ') - sys.exit(1) - - # Information on the input raster - if self.choice_nb_b == 0: - nbband = in_ds.RasterCount # Spectral band number - else: - nbband = self.choice_nb_b - rows = in_ds.RasterYSize # Rows number - cols = in_ds.RasterXSize # Columns number - - # Table's declaration - data = [] # np.float32([[0]*cols for i in xrange(rows)]) - for band in range(nbband): - - canal = in_ds.GetRasterBand(band + 1) # Select a band - if nbband == 1: - data = canal.ReadAsArray(0, 0, cols, rows).astype(np.float32) # Assign pixel values at the data - else: - data.append(canal.ReadAsArray(0, 0, cols, rows).astype(np.float32)) -# print('Copie des pixels du raster ! Bande :', (band + 1)) - - ################################### - # Close input raster - _in_ds = in_ds - in_ds = None - - return data, _in_ds - - def pourc_cloud(self, img_spec, img_cloud): - """ - Return clear pixel percentage on the image **img_spec** because of a cloud image **img_cloud**. - - :param img_spec: Spectral image path - :type img_spec: str - :param img_cloud: Cloud image path - :type img_cloud: str - - :returns: float -- variable **nb0**, clear pixel percentage. - :Example: - - >>> import RasterSat_by_date - >>> Landsat_test = RasterSat_by_date(class_archive, big_folder, one_date) - >>> nb0_test = Landsat_test.pourc_cloud(Landsat_test._one_date[3], Landsat_test._one_date[4]) - >>> nb0_test - 98 - """ - - # Extract raster's information - data_spec, info_spec = self.raster_data(img_spec) - data_cloud, info_cloud = self.raster_data(img_cloud) - self._one_date.append(data_cloud) # Add cloud pixel value table - - # Extent of the images - mask_spec = np.in1d(data_spec[0], [-10000, math.isnan], invert=True) # ex : array([ True, True, True, True, False, True, True, True, True], dtype=bool) -> False where there is -10000 ou NaN - - # Print area account of the pixel size 'info_spec.GetGeoTransform()' - print ('Area = ' + str(float((np.sum(mask_spec) * info_spec.GetGeoTransform()[1] * abs(info_spec.GetGeoTransform()[-1]) )/10000)) + 'ha' ) - - # Cloud mask - mask_cloud = np.in1d(data_cloud, 0) # This is the same opposite False where there is 0 - cloud = np.choose(mask_cloud, (False, mask_spec)) # If True in cloud mask, it take spectral image else False - dist = np.sum(cloud) # Sum of True. True is cloud - - # Computer cloud's percentage with dist (sum of cloud) by sum of the image's extent - try : - nb0 = float(dist)/(np.sum(mask_spec)) - print('For ' + os.path.split(str(img_spec))[1][:-4] + ', cloudy cover ' + str(100 - round(nb0*100, 2)) + "%") - except ZeroDivisionError: - nb0 = 0 - print("The raster isn\'t in the area !") - - return nb0 - - def calcul_ndvi(self, img_spec): - """ - Computer NDVI index for a Landsat image. - - NDVI = band4 - band3 / band4 + band3 with nb_captor = 0 - - or for Sentinel 2 image (2A) : NDVI = band3 - band2 / band3 + band2 with nb_captor = -1 - - :param img_spec: Spectral image path - :type img_spec: str + :returns: numpy.array -- variable **data**, Pixel value matrix of a raster. + + gdal pointer -- variable **_in_ds**, Raster information. + """ + + # Load Gdal's drivers + gdal.AllRegister() + + # Loading input raster + print ('Loading input raster :', os.path.split(str(img))[1][:-4]) + in_ds = gdal.Open(str(img), gdal.GA_ReadOnly) + + # if it doesn't exist + if in_ds is None: + print('could not open ') + sys.exit(1) + + # Information on the input raster + if self.choice_nb_b == 0: + nbband = in_ds.RasterCount # Spectral band number + else: + nbband = self.choice_nb_b + rows = in_ds.RasterYSize # Rows number + cols = in_ds.RasterXSize # Columns number + + # Table's declaration + data = [] # np.float32([[0]*cols for i in xrange(rows)]) + for band in range(nbband): + + canal = in_ds.GetRasterBand(band + 1) # Select a band + if nbband == 1: + data = canal.ReadAsArray(0, 0, cols, rows).astype(np.float32) # Assign pixel values at the data + else: + data.append(canal.ReadAsArray(0, 0, cols, rows).astype(np.float32)) +# print('Copie des pixels du raster ! Bande :', (band + 1)) + + ################################### + # Close input raster + _in_ds = in_ds + in_ds = None + + return data, _in_ds + + def pourc_cloud(self, img_spec, img_cloud): + """ + Return clear pixel percentage on the image **img_spec** because of a cloud image **img_cloud**. + + :param img_spec: Spectral image path + :type img_spec: str + :param img_cloud: Cloud image path + :type img_cloud: str + + :returns: float -- variable **nb0**, clear pixel percentage. + :Example: + + >>> import RasterSat_by_date + >>> Landsat_test = RasterSat_by_date(class_archive, big_folder, one_date) + >>> nb0_test = Landsat_test.pourc_cloud(Landsat_test._one_date[3], Landsat_test._one_date[4]) + >>> nb0_test + 98 + """ + + # Extract raster's information + data_spec, info_spec = self.raster_data(img_spec) + data_cloud, info_cloud = self.raster_data(img_cloud) + self._one_date.append(data_cloud) # Add cloud pixel value table + + # Extent of the images + mask_spec = np.in1d(data_spec[0], [-10000, math.isnan], invert=True) # ex : array([ True, True, True, True, False, True, True, True, True], dtype=bool) -> False where there is -10000 ou NaN + + # Print area account of the pixel size 'info_spec.GetGeoTransform()' + print ('Area = ' + str(float((np.sum(mask_spec) * info_spec.GetGeoTransform()[1] * abs(info_spec.GetGeoTransform()[-1]) )/10000)) + 'ha' ) + + # Cloud mask + mask_cloud = np.in1d(data_cloud, 0) # This is the same opposite False where there is 0 + cloud = np.choose(mask_cloud, (False, mask_spec)) # If True in cloud mask, it take spectral image else False + dist = np.sum(cloud) # Sum of True. True is cloud + + # Computer cloud's percentage with dist (sum of cloud) by sum of the image's extent + try : + nb0 = float(dist)/(np.sum(mask_spec)) + print('For ' + os.path.split(str(img_spec))[1][:-4] + ', cloudy cover ' + str(100 - round(nb0*100, 2)) + "%") + except ZeroDivisionError: + nb0 = 0 + print("The raster isn\'t in the area !") + + return nb0 + + def calcul_ndvi(self, img_spec): + """ + Computer NDVI index for a Landsat image. + + NDVI = (band4 - band3) / (band4 + band3) with nb_captor = 0 + + or for Sentinel 2 image (2A) : NDVI = band3 - band2 / band3 + band2 with nb_captor = -1 + + :param img_spec: Spectral image path + :type img_spec: str - """ - - # NDVI formula index for 2 captor (L8 or S2A Theia) - if self._class_archive._captor == 'SENTINEL2': - n_captor = -1 - else : - n_captor = 0 - - # Extract raster's information - data, in_ds = self.raster_data(img_spec) - - # Computer NDVI - mask = np.greater(data[0], -10000) - ndvi = np.choose(mask, (-10000, eval('(data[4+n_captor]-data[3+n_captor])') / eval('(data[4+n_captor]+data[3+n_captor])'))) # If True, -10000 (NaN) else compute mathematical operation - - # Outfile name - img_ndvi = img_spec[:-4] + '_ndvi.TIF' - self._one_date.append(img_ndvi) # Add ndvi image path - self._one_date.append(ndvi) # Add ndvi pixel value table - self.create_raster(img_ndvi, ndvi, in_ds) - - def create_raster(self, out_raster, data, in_ds): - """ - Create a raster empty with the input raster property - - :param out_raster: Output image path - :type out_raster: str - :param data: Pixel value matrix. Matrix size equal to that of a raster. - :type data: numpy.array - :param in_ds: Raster information - :type in_ds: gdal pointer - - :returns: gdal pointer -- variable **out_ds**, Raster out information. - - int -- variable **nbband**, Band number of the out layer. - - int -- variable **e**, Index to know if the raster exists. If it doesn't exists e = 0 else e = 1 (by default). - """ - -# if os.path.exists(str(out_raster)): -# os.remove(str(out_raster)) - e = 1 # Raster out exists by default - # Verify if the processing take input band or one spectral band - if data.ndim == 2 or self.choice_nb_b == 1: - nbband = 1 - else: - nbband = in_ds.RasterCount - - driver = gdal.GetDriverByName('GTiff') - if not os.path.exists(str(out_raster)): - e = 0 - # Create outfile - self.out_ds = driver.Create(str(out_raster), in_ds.RasterXSize, in_ds.RasterYSize, nbband, gdal.GDT_Float32) - if self.out_ds is None: - print ('Could not create ' + os.path.split(str(out_raster))[1]) - sys.exit(1) - - # Get extent coordinates and raster resolution - transform = in_ds.GetGeoTransform() - # print transform - - minX = transform[0] - maxY = transform[3] - pixelWidth = transform[1] - pixelHeight = transform[5] - - geotransform = [minX, pixelWidth, 0, maxY, 0, pixelHeight] - - # Record projection - def_projection = in_ds.GetProjection() + """ + + # NDVI formula index for 2 captor (L8 or S2A Theia) + if self._class_archive._captor == 'SENTINEL2': + n_captor = -1 + else : + n_captor = 0 + + # Extract raster's information + data, in_ds = self.raster_data(img_spec) + + # Computer NDVI + mask = np.greater(data[0], -10000) + ndvi = np.choose(mask, (-10000, eval('(data[4+n_captor]-data[3+n_captor])') / eval('(data[4+n_captor]+data[3+n_captor])'))) # If True, -10000 (NaN) else compute mathematical operation + + # Outfile name + img_ndvi = img_spec[:-4] + '_ndvi.TIF' + self._one_date.append(img_ndvi) # Add ndvi image path + self._one_date.append(ndvi) # Add ndvi pixel value table + self.create_raster(img_ndvi, ndvi, in_ds) + + def create_raster(self, out_raster, data, in_ds): + """ + Create a raster empty with the input raster property + + :param out_raster: Output image path + :type out_raster: str + :param data: Pixel value matrix. Matrix size equal to that of a raster. + :type data: numpy.array + :param in_ds: Raster information + :type in_ds: gdal pointer + + :returns: gdal pointer -- variable **out_ds**, Raster out information. + + int -- variable **nbband**, Band number of the out layer. + + int -- variable **e**, Index to know if the raster exists. If it doesn't exists e = 0 else e = 1 (by default). + """ + +# if os.path.exists(str(out_raster)): +# os.remove(str(out_raster)) + e = 1 # Raster out exists by default + # Verify if the processing take input band or one spectral band + if data.ndim == 2 or self.choice_nb_b == 1: + nbband = 1 + else: + nbband = in_ds.RasterCount + + driver = gdal.GetDriverByName('GTiff') + if not os.path.exists(str(out_raster)): + e = 0 + # Create outfile + self.out_ds = driver.Create(str(out_raster), in_ds.RasterXSize, in_ds.RasterYSize, nbband, gdal.GDT_Float32) + if self.out_ds is None: + print ('Could not create ' + os.path.split(str(out_raster))[1]) + sys.exit(1) + + # Get extent coordinates and raster resolution + transform = in_ds.GetGeoTransform() + # print transform + + minX = transform[0] + maxY = transform[3] + pixelWidth = transform[1] + pixelHeight = transform[5] + + geotransform = [minX, pixelWidth, 0, maxY, 0, pixelHeight] + + # Record projection + def_projection = in_ds.GetProjection() - # Set the geo-traking and outfile projection - self.out_ds.SetGeoTransform(geotransform) - self.out_ds.SetProjection(def_projection) - - else: - - self.out_ds = gdal.Open(str(out_raster), gdal.GA_ReadOnly) - - return nbband, e - - def complete_raster(self, nbband, e, data): - """ - This function complete the function above :func:`create_raster()`. It - fills the raster table and close the layer. - - :param out_ds: Raster out information - :type out_ds: gdal pointer - :param nbband: Band number of the out layer - :type nbband: int - :param e: Index to know if the raster existed. If it didn't exist e = 0. - :type e: int - :param data: Pixel value matrix. Matrix size equal to that of a raster. - :type data: numpy.array - """ - - # The e index to verify if the layer existed already because of the - # function :func:`create_raster()` - if e == 0 : - p = 0 # Increment for the number band - while p < nbband: - #Incrementation - p = p + 1 - - print ("Copy on the band ", p) - - # Loading spectral band of outfile - out_band = self.out_ds.GetRasterBand(p) - # write the data - if data.ndim == 2: - out_band.WriteArray(data, 0, 0) - else: - out_band.WriteArray(data[p-1], 0, 0) - - # Closing and statistics on output raster - out_band.FlushCache() - out_band.SetNoDataValue(-10000) - out_band.GetStatistics(-1, 1) - out_band = None - - # Close open data - self.out_ds = None + # Set the geo-traking and outfile projection + self.out_ds.SetGeoTransform(geotransform) + self.out_ds.SetProjection(def_projection) + + else: + + self.out_ds = gdal.Open(str(out_raster), gdal.GA_ReadOnly) + + return nbband, e + + def complete_raster(self, nbband, e, data): + """ + This function complete the function above :func:`create_raster()`. It + fills the raster table and close the layer. + + :param out_ds: Raster out information + :type out_ds: gdal pointer + :param nbband: Band number of the out layer + :type nbband: int + :param e: Index to know if the raster existed. If it didn't exist e = 0. + :type e: int + :param data: Pixel value matrix. Matrix size equal to that of a raster. + :type data: numpy.array + """ + + # The e index to verify if the layer existed already because of the + # function :func:`create_raster()` + if e == 0 : + p = 0 # Increment for the number band + while p < nbband: + #Incrementation + p = p + 1 + + print ("Copy on the band ", p) + + # Loading spectral band of outfile + out_band = self.out_ds.GetRasterBand(p) + # write the data + if data.ndim == 2: + out_band.WriteArray(data, 0, 0) + else: + out_band.WriteArray(data[p-1], 0, 0) + + # Closing and statistics on output raster + out_band.FlushCache() + out_band.SetNoDataValue(-10000) + out_band.GetStatistics(-1, 1) + out_band = None + + # Close open data + self.out_ds = None - \ No newline at end of file + \ No newline at end of file diff --git a/Rpg.py b/Rpg.py index 580f1ec306249411b1f4e92ab1d3485111be6ffb..18c722c92d8e1d523826012528c0a145067339f8 100644 --- a/Rpg.py +++ b/Rpg.py @@ -150,7 +150,7 @@ class Rpg(Vector): self.head_in_read.append(y) else: self.head_in_read.append(y[:10]) - body_in_read = map(list, zip(*in_read[1:])) # Transpose table [[e,e,e],[a,a,a]] -> [[e,a],[e,a],[e,a]] + body_in_read = list(map(list, zip(*in_read[1:]))) # Transpose table [[e,e,e],[a,a,a]] -> [[e,a],[e,a],[e,a]] # self.rm_dupli = [[x, body_in_read[1][body_in_read[0].index(x)], body_in_read[2][body_in_read[0].index(x)]] \ # for x in body_in_read[0] if body_in_read[0].count(x) == 1] diff --git a/Sample.py b/Sample.py index 9b5409dad2722a4258e6d89ae4380c50de41a3c3..91ed7bc595b74c684b89ff2f7c8ffe215dca486a 100644 --- a/Sample.py +++ b/Sample.py @@ -22,195 +22,194 @@ import random import numpy as np from Vector import Vector try : - import ogr + import ogr except : - from osgeo import ogr + from osgeo import ogr class Sample(Vector): - - """ - Vector class inherits the super vector class properties. This class create training sample. - - :param vector_used: Input/Output shapefile to clip (path) - :type vector_used: str - :param vector_cut: Area shapefile (path) - :type vector_cut: str - :param nb_sample: Number of polygons for every sample - :type nb_sample: int - :param vector_val: Output shapefile to validate the futur classification - :type vector_val: str - - :opt: Refer to the Vector class - """ - - def __init__(self, used, cut, nb_sample, **opt): - """Create a new 'Sample' instance - - """ - Vector.__init__(self, used, cut, **opt) - - self._nb_sample = nb_sample - self.vector_val = '' - - def create_sample(self, **kwargs): - """ - Function to create a sample shapefile of a specific class - - :kwargs: **fieldname** (list of str) - Fieldname in the input shapefile (if the user want select polygons of the class names specific) - - **class** (list of str) - class names in the input shapefile (with fieldname index). - Can use one or several classes like this --> example : [classname1, classname2, ...] - """ - - kw_field = kwargs['fieldname'] if kwargs.get('fieldname') else '' - kw_classes = kwargs['class'] if kwargs.get('class') else '' - - # If the users want select polygons with a certain class name - if kw_field and kw_classes: - # The random sample with class name selected only - random_sample = np.array(random.sample(self.select_random_sample(kw_field, kw_classes), int(self._nb_sample))) - else: - # The random sample without class name selected - random_sample = np.array(random.sample(range(self.data_source.GetLayer().GetFeatureCount()), self._nb_sample)) - - # Output shapefile of the sample's polygons (path) - self.vector_used = self.vector_used[:-4] + '_' + kw_classes.replace(',','').replace(' ','') + 'rd.shp' - # Fill and create the sample shapefile - self.fill_sample(self.vector_used, random_sample[:len(random_sample)/2]) - # Output shapefile of the validate polygon (path) - self.vector_val = self.vector_used[:-6] + 'val.shp' - # Fill and create the validate polygons shapefile - self.fill_sample(self.vector_val, random_sample[len(random_sample)/2:]) - - def select_random_sample(self, kw_field, kw_classes): - """ - Function to select id with class name specific only. This function is used in :func:`create_sample` + + """ + Vector class inherits the super vector class properties. This class create training sample. + + :param vector_used: Input/Output shapefile to clip (path) + :type vector_used: str + :param vector_cut: Area shapefile (path) + :type vector_cut: str + :param nb_sample: Number of polygons for every sample + :type nb_sample: int + :param vector_val: Output shapefile to validate the futur classification + :type vector_val: str + + :opt: Refer to the Vector class + """ + + def __init__(self, used, cut, nb_sample, **opt): + """ + Create a new 'Sample' instance + """ + Vector.__init__(self, used, cut, **opt) + + self._nb_sample = nb_sample + self.vector_val = '' + + def create_sample(self, **kwargs): + """ + Function to create a sample shapefile of a specific class + + :kwargs: **fieldname** (list of str) - Fieldname in the input shapefile (if the user want select polygons of the class names specific) + + **class** (list of str) - class names in the input shapefile (with fieldname index). + Can use one or several classes like this --> example : [classname1, classname2, ...] + """ + + kw_field = kwargs['fieldname'] if kwargs.get('fieldname') else '' + kw_classes = kwargs['class'] if kwargs.get('class') else '' + + # If the users want select polygons with a certain class name + if kw_field and kw_classes: + # The random sample with class name selected only + random_sample = np.array(random.sample(self.select_random_sample(kw_field, kw_classes), int(self._nb_sample))) + else: + # The random sample without class name selected + random_sample = np.array(random.sample(range(self.data_source.GetLayer().GetFeatureCount()), self._nb_sample)) + + # Output shapefile of the sample's polygons (path) + self.vector_used = self.vector_used[:-4] + '_' + kw_classes.replace(',','').replace(' ','') + 'rd.shp' + # Fill and create the sample shapefile + self.fill_sample(self.vector_used, random_sample[:round(len(random_sample)/2)]) + # Output shapefile of the validate polygon (path) + self.vector_val = self.vector_used[:-6] + 'val.shp' + # Fill and create the validate polygons shapefile + self.fill_sample(self.vector_val, random_sample[round(len(random_sample)/2):]) - :param kw_field: Field name in the input shapefile - :type kw_field: str - :param kw_classes: Class names in the input shapefile like this --> 'classname1, classname2' - :type kw_classes: str - :returns: list -- variable **select_id**, List of id with a class name specific. - """ - - # Convert string in a list. For that, it remove - # space and clip this string with comma (Add everywhere if the script modified - # because the process work with a input string chain) - kw_classes = kw_classes.replace(' ','').split(',') - - # List of class name id - select_id = [] - - shp_ogr = self.data_source.GetLayer() - - # Loop on input polygons - in_feature = shp_ogr.SetNextByIndex(0) # Initialization - in_feature = shp_ogr.GetNextFeature() - while in_feature: - - # if polygon is a defined class name - ## .replace('0','') to remove '0' in front of for example '1' (RPG -> '01') - table_name_class = in_feature.GetField(self.field_names[self.field_names.index(kw_field)]) - # To avoid that the process crashed this part of the algorithm will be launch if the field is contains characters - if table_name_class != None : - if in_feature.GetField(self.field_names[self.field_names.index(kw_field)]).replace('0','') in kw_classes: - - # Add id in the extract list - select_id.append(in_feature.GetFID()) - - in_feature.Destroy() - - in_feature = shp_ogr.GetNextFeature() - return select_id - - def fill_sample(self, output_sample, polygon, **opt): - - """ - Function to fill and create the output sample shapefile. This function is used in :func:`create_sample` - to create samples polygons and validated polygons (to the take out the precision of the classification) + def select_random_sample(self, kw_field, kw_classes): + """ + Function to select id with class name specific only. This function is used in :func:`create_sample` - :param output_sample: Path of the output shapefile - :type output_sample: str - :param polygon: Identity of the selected random polygons. If this variable = 0, the processing will take all polygons - :type polygon: list or int - - :opt: **add_fieldname** (int) - Variable to kown if add a field. By default non (0), if it have to add (1) - - **fieldname** (str) - Fieldname to add in the input shapefile - - **class** (int) - class names in integer to add in the input shapefile - """ - - # In option to add a integer field - add_field = opt['add_fieldname'] if opt.get('add_fieldname') else 0 - opt_field = opt['fieldname'] if opt.get('fieldname') else '' - opt_class = opt['class'] if opt.get('class') else 0 - - shp_ogr = self.data_source.GetLayer() - - # To take all polygon - if type(polygon) == int: - polygon = range(shp_ogr.GetFeatureCount()) - - # Projection - # Import input shapefile projection - srsObj = shp_ogr.GetSpatialRef() - # Conversion to syntax ESRI - srsObj.MorphToESRI() - - ## Remove the output shapefile if it exists - if os.path.exists(output_sample): - self.data_source.GetDriver().DeleteDataSource(output_sample) - out_ds = self.data_source.GetDriver().CreateDataSource(output_sample) - - if out_ds is None: - print('Could not create file') - sys.exit(1) - - # Specific output layer - out_layer = out_ds.CreateLayer(str(output_sample), srsObj, geom_type=ogr.wkbMultiPolygon) - - # Add existing fields - for i in range(0, len(self.field_names)): - # use the input FieldDefn to add a field to the output - fieldDefn = shp_ogr.GetFeature(0).GetFieldDefnRef(self.field_names[i]) - out_layer.CreateField(fieldDefn) - - # In Option : Add a integer field - if add_field == 1: - new_field = ogr.FieldDefn(opt_field, 0) - out_layer.CreateField(new_field) - - # Feature for the ouput shapefile - featureDefn = out_layer.GetLayerDefn() - - # Loop on the input elements - # Create a existing polygons in random list - for cnt in polygon: - - # Select input polygon by id - in_feature = shp_ogr.SetNextByIndex(cnt) - in_feature = shp_ogr.GetNextFeature() - - geom = in_feature.GetGeometryRef() # Extract input geometry + :param kw_field: Field name in the input shapefile + :type kw_field: str + :param kw_classes: Class names in the input shapefile like this --> 'classname1, classname2' + :type kw_classes: str + :returns: list -- variable **select_id**, List of id with a class name specific. + """ + + # Convert string in a list. For that, it remove + # space and clip this string with comma (Add everywhere if the script modified + # because the process work with a input string chain) + kw_classes = kw_classes.replace(' ','').split(',') + + # List of class name id + select_id = [] - # Create a new polygon - out_feature = ogr.Feature(featureDefn) + shp_ogr = self.data_source.GetLayer() - # Set the polygon geometry and attribute - out_feature.SetGeometry(geom) - for i in range(0, len(self.field_names)): - out_feature.SetField(self.field_names[i], in_feature.GetField(self.field_names[i])) - # In Option : Add a integer field - if add_field == 1: - out_feature.SetField(opt_field, opt_class[0]) - - # Append polygon to the output shapefile - out_layer.CreateFeature(out_feature) - - # Destroy polygons - out_feature.Destroy() - in_feature.Destroy() - - # Close data - out_ds.Destroy() \ No newline at end of file + # Loop on input polygons + in_feature = shp_ogr.SetNextByIndex(0) # Initialization + in_feature = shp_ogr.GetNextFeature() + while in_feature: + # if polygon is a defined class name + ## .replace('0','') to remove '0' in front of for example '1' (RPG -> '01') + table_name_class = in_feature.GetField(self.field_names[self.field_names.index(kw_field)]) + # To avoid that the process crashed this part of the algorithm will be launch if the field is contains characters + if table_name_class != None : + if in_feature.GetField(self.field_names[self.field_names.index(kw_field)]).replace('0','') in kw_classes: + + # Add id in the extract list + select_id.append(in_feature.GetFID()) + + in_feature.Destroy() + + in_feature = shp_ogr.GetNextFeature() + return select_id + + def fill_sample(self, output_sample, polygon, **opt): + + """ + Function to fill and create the output sample shapefile. This function is used in :func:`create_sample` + to create samples polygons and validated polygons (to the take out the precision of the classification) + + :param output_sample: Path of the output shapefile + :type output_sample: str + :param polygon: Identity of the selected random polygons. If this variable = 0, the processing will take all polygons + :type polygon: list or int + + :opt: **add_fieldname** (int) - Variable to kown if add a field. By default non (0), if it have to add (1) + + **fieldname** (str) - Fieldname to add in the input shapefile + + **class** (int) - class names in integer to add in the input shapefile + """ + + # In option to add a integer field + add_field = opt['add_fieldname'] if opt.get('add_fieldname') else 0 + opt_field = opt['fieldname'] if opt.get('fieldname') else '' + opt_class = opt['class'] if opt.get('class') else 0 + + shp_ogr = self.data_source.GetLayer() + + # To take all polygon + if type(polygon) == int: + polygon = range(shp_ogr.GetFeatureCount()) + + # Projection + # Import input shapefile projection + srsObj = shp_ogr.GetSpatialRef() + # Conversion to syntax ESRI + srsObj.MorphToESRI() + + ## Remove the output shapefile if it exists + if os.path.exists(output_sample): + self.data_source.GetDriver().DeleteDataSource(output_sample) + out_ds = self.data_source.GetDriver().CreateDataSource(output_sample) + + if out_ds is None: + print('Could not create file') + sys.exit(1) + + # Specific output layer + out_layer = out_ds.CreateLayer(str(output_sample), srsObj, geom_type=ogr.wkbMultiPolygon) + + # Add existing fields + for i in range(0, len(self.field_names)): + # use the input FieldDefn to add a field to the output + fieldDefn = shp_ogr.GetFeature(0).GetFieldDefnRef(self.field_names[i]) + out_layer.CreateField(fieldDefn) + + # In Option : Add a integer field + if add_field == 1: + new_field = ogr.FieldDefn(opt_field, 0) + out_layer.CreateField(new_field) + + # Feature for the ouput shapefile + featureDefn = out_layer.GetLayerDefn() + + # Loop on the input elements + # Create a existing polygons in random list + for cnt in polygon: + + # Select input polygon by id + in_feature = shp_ogr.SetNextByIndex(cnt) + in_feature = shp_ogr.GetNextFeature() + + geom = in_feature.GetGeometryRef() # Extract input geometry + + # Create a new polygon + out_feature = ogr.Feature(featureDefn) + + # Set the polygon geometry and attribute + out_feature.SetGeometry(geom) + for i in range(0, len(self.field_names)): + out_feature.SetField(self.field_names[i], in_feature.GetField(self.field_names[i])) + # In Option : Add a integer field + if add_field == 1: + out_feature.SetField(opt_field, opt_class[0]) + + # Append polygon to the output shapefile + out_layer.CreateFeature(out_feature) + + # Destroy polygons + out_feature.Destroy() + in_feature.Destroy() + + # Close data + out_ds.Destroy() \ No newline at end of file diff --git a/Satellites.py b/Satellites.py new file mode 100644 index 0000000000000000000000000000000000000000..814082a83beba3b69af67512f979e330cafd51f6 --- /dev/null +++ b/Satellites.py @@ -0,0 +1,23 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +import collections + +SATELLITE = collections.defaultdict(dict) + + # Info from Theia-land website or Olivier Hagolle blog + +########################## SENTINEL2 ############################### + +SATELLITE["SENTINEL2"]["server"] = "https://theia.cnes.fr/atdistrib" +SATELLITE["SENTINEL2"]["resto"] = "resto2" +SATELLITE["SENTINEL2"]["token_type"] = "text" + +########################## LANDSAT ################################# + +SATELLITE["Landsat"]["server"] = "https://theia-landsat.cnes.fr" +SATELLITE["Landsat"]["resto"] = "resto" +SATELLITE["Landsat"]["token_type"] = "json" + + + diff --git a/Segmentation.py b/Segmentation.py index 7e53b0768afaafcfaee54ecae1b6ceb836ceed10..18c3d8007a792f1e12ee6b0ed01fd754581d43d0 100644 --- a/Segmentation.py +++ b/Segmentation.py @@ -257,6 +257,7 @@ class Segmentation(Vector): :type method: str """ + print("Calcul densité : ") if method == 'SEATH': distri = [v[1:] for k, v in self.stats_dict.items() if eval('v[0]' + self.out_threshold[1])] @@ -268,6 +269,7 @@ class Segmentation(Vector): else: distri_den.append(b) elif method == 'RF': + distri = [v[1:] for k, v in self.stats_dict.items() if not self.out_threshold[k] in [0,6,7]] distri_bio = [] @@ -280,21 +282,31 @@ class Segmentation(Vector): # Set this variable used normally to define threshold of the classification with SEATH method self.out_threshold = [] + # Transpose table t_distri_bio = list(map(list, zip(*distri_bio))) t_distri_den = list(map(list, zip(*distri_den))) - - # Biomass threshold - stdmore = (np.mean(t_distri_bio[2]) + np.std(t_distri_bio[2]))/np.max(t_distri_bio[2]) - stdless = (np.mean(t_distri_bio[2]) - np.std(t_distri_bio[2]))/np.max(t_distri_bio[2]) - self.out_threshold.append('>'+str(stdmore)) - self.out_threshold.append('') - self.out_threshold.append('<'+str(stdless)) - - # Compute density and biomass maximum - self.max_wood_idm = np.max(t_distri_den[1]) - self.max_wood_sfs = np.max(t_distri_den[0]) - self.max_bio = np.max(t_distri_bio[2]) + + try: + # Biomass threshold + stdmore = (np.mean(t_distri_bio[2]) + np.std(t_distri_bio[2]))/np.max(t_distri_bio[2]) + stdless = (np.mean(t_distri_bio[2]) - np.std(t_distri_bio[2]))/np.max(t_distri_bio[2]) + self.out_threshold.append('>'+str(stdmore)) + self.out_threshold.append('') + self.out_threshold.append('<'+str(stdless)) + + except Exception as e: + print("Bio : ", t_distri_bio) + print("Den : ", t_distri_den) + + try: + # Compute density and biomass maximum + self.max_wood_idm = np.max(t_distri_den[1]) + self.max_wood_sfs = np.max(t_distri_den[0]) + self.max_bio = np.max(t_distri_bio[2]) + except Exception as e: + print(e) + def append_scale(self, select_class, form): """ @@ -307,7 +319,7 @@ class Segmentation(Vector): :type form: str """ - + print(self.max_wood_idm) for ind_stats in range(len(self.stats_dict)): # Only valid on the second level try: diff --git a/Toolbox.py b/Toolbox.py index 7f675bbb96e1473c1f26fd3560513be2f5c3b3ac..3ef37903cdfbce532851c822918fd7dd3700418f 100644 --- a/Toolbox.py +++ b/Toolbox.py @@ -24,30 +24,29 @@ import json class Toolbox(): """ - Class used to grouped small tools to cut raster or compute statistics on a raster. - - :param imag: Input image (path) - :type imag: str - :param vect: Extent shapefile (path) - :type vect: str + Class used to grouped small tools to cut raster or compute statistics on a raster. + + :param imag: Input image (path) + :type imag: str + :param vect: Extent shapefile (path) + :type vect: str """ def __init__(self): """ - Create a new 'Toolbox' instance + Create a new 'Toolbox' instance """ - self.imag = '' self.vect = '' def clip_raster(self, **kwargs): """ - Function to clip a raster with a vector. The raster created will be in the same folder than the input raster. - With a prefix *Clip_*. - - :kwargs: **rm_rast** (int) - 0 (by default) or 1. Variable to remove the output raster. 0 to keep and 1 to remove. - - :returns: str -- variable **outclip**, output raster clip (path). + Function to clip a raster with a vector. The raster created will be in the same folder than the input raster. + With a prefix *Clip_*. + + :kwargs: **rm_rast** (int) - 0 (by default) or 1. Variable to remove the output raster. 0 to keep and 1 to remove. + + :returns: str -- variable **outclip**, output raster clip (path). """ rm_rast = kwargs['rm_rast'] if kwargs.get('rm_rast') else 0 @@ -78,14 +77,14 @@ class Toolbox(): def calc_serie_stats(self, table): """ - Function to compute stats on temporal cloud and ndvi spectral table - Ndvi stats : min max std max-min - - :param table: Spectral data, cloud raster and ndvi raster - :type table: numpy.ndarray - :returns: list of numpy.ndarray -- variable **account_stats**, list of temporal NDVI stats. - - numpy.ndarray -- variable **account_cloud**, pixel number clear on the area. + Function to compute stats on temporal cloud and ndvi spectral table + Ndvi stats : min max std max-min + + :param table: Spectral data, cloud raster and ndvi raster + :type table: numpy.ndarray + :returns: list of numpy.ndarray -- variable **account_stats**, list of temporal NDVI stats. + + numpy.ndarray -- variable **account_cloud**, pixel number clear on the area. """ # Compute stats on these indexes @@ -129,8 +128,8 @@ class Toolbox(): def check_proj(self): """ - Function to check if raster's projection is RFG93. - For the moment, PHYMOBAT works with one projection only Lambert 93 EPSG:2154 + Function to check if raster's projection is RFG93. + For the moment, PHYMOBAT works with one projection only Lambert 93 EPSG:2154 """ # Projection for PHYMOBAT diff --git a/Vector.py b/Vector.py index 737ea71e9a6f4e91cddfae500f478a68eafcb8b4..c97590cea85cb9159a2b409b9fd68c9075e9a736 100644 --- a/Vector.py +++ b/Vector.py @@ -25,7 +25,8 @@ try : except : from osgeo import ogr, gdal -from rasterstats import * +# from rasterstats import * +import rasterstats from collections import * from RasterSat_by_date import RasterSat_by_date @@ -106,8 +107,7 @@ class Vector(): def close_data(self): """ - Function to remove allocate memory - + Function to remove allocate memory """ # Close data sources @@ -117,7 +117,7 @@ class Vector(): def zonal_stats(self, inraster, band, **kwargs): """ - Function to compute the average in every polygons for a raster + Function to compute the mean in every polygons for a raster because of package ``rasterstats`` in */usr/local/lib/python2.7/dist-packages/rasterstats-0.3.2-py2.7.egg/rasterstats/* :param (inraster,band): inraster -> Input image path, and band -> band number @@ -130,9 +130,8 @@ class Vector(): ranking = kwargs['rank'] if kwargs.get('rank') else 0 nb_img = kwargs['nb_img'] if kwargs.get('nb_img') else 1 - print('Compute ' + os.path.split(str(self.vector_used))[1] + ' stats on ' + os.path.split(str(inraster))[1]) - stats = raster_stats(str(self.vector_used), str(inraster), stats =['mean'], band_num=band) - + print('Compute ' + os.path.split(self.vector_used)[1] + ' stats on ' + os.path.split(inraster)[1]) + stats = rasterstats.zonal_stats(self.vector_used, inraster, stats =['mean'], nodata=float('nan'), band=band) for i in range(len(stats)): temp = defaultdict(lambda : [0]*nb_img) for j in range(nb_img): @@ -140,22 +139,24 @@ class Vector(): temp[0][j] = self.stats_dict[i][j] except IndexError: pass - temp[0][ranking] = stats[i].values()[1] + + # temp[0][ranking] = stats[i].values()[1] + temp[0][ranking] = list(stats)[i]['mean'] self.stats_dict[i] = temp[0] print('End of stats on ' + os.path.split(str(inraster))[1]) def zonal_stats_pp(self, inraster): """ - A zonal statistics ++ to dertermine pxl percent in every polygon + A zonal statistics ++ to dertermine pxl percent in every polygon - :param inraster: Input image path - :type inraster: str - :returns: dict -- **p_stats** : dictionnary with pxl percent in every polygon. Mainly 'Maj_count' (Majority Value) and 'Maj_count_perc' (Majority Percent) + :param inraster: Input image path + :type inraster: str + :returns: dict -- **p_stats** : dictionnary with pxl percent in every polygon. Mainly 'Maj_count' (Majority Value) and 'Maj_count_perc' (Majority Percent) """ - p_stats = raster_stats(str(self.vector_used), str(inraster), stats=['count'], copy_properties=True, categorical=True) + p_stats = rasterstats.zonal_stats(self.vector_used, inraster, stats=['count'], copy_properties=True, categorical=True) for i in range(len(p_stats)): percent = 0.0 @@ -216,7 +217,7 @@ class Vector(): self.raster_ds = None # Complete the raster creation - example_raster.complete_raster(info_out, new_data) + example_raster.complete_raster(*info_out, new_data) return valid_raster diff --git a/ui_PHYMOBATs_tab.py b/ui_PHYMOBATs_tab.py index 9c512b1b40b2a0d738fe195f670d2d6fa343a793..bc5911b9ae0d5b083206e3b7d6ba770b3e8facf8 100644 --- a/ui_PHYMOBATs_tab.py +++ b/ui_PHYMOBATs_tab.py @@ -19,7 +19,7 @@ except AttributeError: class Ui_PHYMOBAT(object): """ - Class to display “Simplify PHYMOBAT windowâ€. + Class to display “Simplify PHYMOBAT windowâ€. """ def setupUi(self, PHYMOBAT): @@ -36,7 +36,7 @@ class Ui_PHYMOBAT(object): self.gridLayout_4.addWidget(self.buttonBox, 5, 1, 1, 1) self.checkBox_multiprocess = QtWidgets.QCheckBox(self.centralwidget) self.checkBox_multiprocess.setCheckable(True) - self.checkBox_multiprocess.setChecked(True) + self.checkBox_multiprocess.setChecked(False) self.checkBox_multiprocess.setAutoRepeat(False) self.checkBox_multiprocess.setObjectName("checkBox_multiprocess") self.gridLayout_4.addWidget(self.checkBox_multiprocess, 5, 0, 1, 1)