From a639f0833c02e7fc6c7ad2cc8423f8074bcc37bd Mon Sep 17 00:00:00 2001 From: Commandre Benjamin <benjamin.commandre@irstea.fr> Date: Thu, 29 Nov 2018 15:33:53 +0100 Subject: [PATCH] Nettoyage du code + Optimisation --- PHYMOBAT.py | 540 ++++++++++++++++++++++++++------------------------ Processing.py | 400 +++++++++++++++++++------------------ Sample.py | 140 ++++++------- Vector.py | 87 ++++---- 4 files changed, 590 insertions(+), 577 deletions(-) diff --git a/PHYMOBAT.py b/PHYMOBAT.py index ca791f8..39dbf39 100644 --- a/PHYMOBAT.py +++ b/PHYMOBAT.py @@ -1,18 +1,18 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- -# +# # Copyright 2016 Sylvio Laventure (IRSTEA - UMR TETIS) # # PHYMOBAT 3.0 is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. -# +# # PHYMOBAT 3.0 is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. -# +# # You should have received a copy of the GNU General Public License # along with PHYMOBAT 3.0. If not, see <http://www.gnu.org/licenses/>. @@ -52,7 +52,7 @@ class PHYMOBAT(QtWidgets.QMainWindow, Processing): """ 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) @@ -65,8 +65,8 @@ class PHYMOBAT(QtWidgets.QMainWindow, Processing): self.current_mode = mode self.logger = Outils.Log("Log", "Phymobat") - - # To select interface's parameters + + # To select interface's parameters if self.current_mode == Constantes.EXPERT_MODE: self.logger.info("Expert mode.") global Ui_PHYMOBAT, _translate @@ -75,16 +75,16 @@ class PHYMOBAT(QtWidgets.QMainWindow, Processing): self.logger.info("Simple mode.") 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 @@ -94,15 +94,15 @@ class PHYMOBAT(QtWidgets.QMainWindow, Processing): * 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) @@ -112,41 +112,41 @@ class PHYMOBAT(QtWidgets.QMainWindow, Processing): # 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() @@ -154,7 +154,7 @@ class PHYMOBAT(QtWidgets.QMainWindow, Processing): # 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) @@ -167,18 +167,18 @@ class PHYMOBAT(QtWidgets.QMainWindow, Processing): 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 @@ -187,31 +187,31 @@ class PHYMOBAT(QtWidgets.QMainWindow, Processing): 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_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) @@ -219,11 +219,11 @@ class PHYMOBAT(QtWidgets.QMainWindow, Processing): self.ui.checkBox_classifier_3.stateChanged.connect(self.display_all_levels) except AttributeError: pass # Simple mode - - def get_variable(self): + + 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 @@ -234,77 +234,77 @@ class PHYMOBAT(QtWidgets.QMainWindow, Processing): - 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 = self.ui.lineEdit_MNT.text() - + self.path_mnt = 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() != '': + + 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() != '': + + 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 . @@ -315,14 +315,14 @@ class PHYMOBAT(QtWidgets.QMainWindow, Processing): 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. @@ -349,43 +349,43 @@ class PHYMOBAT(QtWidgets.QMainWindow, Processing): 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(' ','')) - + 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(' ','')) - + 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): + + 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. @@ -395,7 +395,7 @@ class PHYMOBAT(QtWidgets.QMainWindow, Processing): 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. @@ -403,35 +403,35 @@ class PHYMOBAT(QtWidgets.QMainWindow, Processing): """ 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 + 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. @@ -440,14 +440,14 @@ class PHYMOBAT(QtWidgets.QMainWindow, Processing): - *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. + + 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 @@ -455,24 +455,24 @@ class PHYMOBAT(QtWidgets.QMainWindow, Processing): if not 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 + # 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()) @@ -481,7 +481,7 @@ class PHYMOBAT(QtWidgets.QMainWindow, Processing): 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() @@ -497,7 +497,7 @@ class PHYMOBAT(QtWidgets.QMainWindow, Processing): 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(): @@ -508,7 +508,7 @@ class PHYMOBAT(QtWidgets.QMainWindow, Processing): 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() @@ -516,14 +516,14 @@ class PHYMOBAT(QtWidgets.QMainWindow, Processing): 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 + # 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(self.ui.lineEdit_sample_path.text())) - + # Append two sample field names by line edit. It must be the same. self.fieldname_args.append(self.ui.lineEdit_select_sample_fieldname_1.text()) self.fieldname_args.append(self.ui.lineEdit_select_sample_fieldname_2.text()) @@ -534,7 +534,7 @@ class PHYMOBAT(QtWidgets.QMainWindow, Processing): # Append number of polygons for every samples by line edit. self.list_nb_sample.append(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(self.ui.lineEdit_sample_path_2.text()) @@ -543,7 +543,7 @@ class PHYMOBAT(QtWidgets.QMainWindow, Processing): self.class_args.append(self.ui.lineEdit_select_sample_class_3.text()) self.class_args.append(self.ui.lineEdit_select_sample_class_4.text()) self.list_nb_sample.append(self.ui.lineEdit_select_sample_nb_poly_2.text()) - + # To wooden self.sample_name.append(self.ui.lineEdit_sample_path_3.text()) self.fieldname_args.append(self.ui.lineEdit_select_sample_fieldname_5.text()) @@ -551,7 +551,7 @@ class PHYMOBAT(QtWidgets.QMainWindow, Processing): self.class_args.append(self.ui.lineEdit_select_sample_class_5.text()) self.class_args.append(self.ui.lineEdit_select_sample_class_6.text()) self.list_nb_sample.append(self.ui.lineEdit_select_sample_nb_poly_3.text()) - + def clear_sample(self): """ Function to clear sample record. Clear in the interface and in the memory list. @@ -562,7 +562,7 @@ class PHYMOBAT(QtWidgets.QMainWindow, Processing): 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() @@ -578,46 +578,46 @@ class PHYMOBAT(QtWidgets.QMainWindow, Processing): 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("") - + 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()) - + 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()) - + 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()) - + 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. @@ -630,17 +630,17 @@ class PHYMOBAT(QtWidgets.QMainWindow, Processing): 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") @@ -657,36 +657,36 @@ class PHYMOBAT(QtWidgets.QMainWindow, Processing): 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(): + 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.label_chps_type_1.deleteLater() self.ui.lineEdit_fieldname_1.deleteLater() self.ui.comboBox_fieldname_1.deleteLater() - except AttributeError: + 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) @@ -695,7 +695,7 @@ class PHYMOBAT(QtWidgets.QMainWindow, Processing): 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.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) @@ -708,46 +708,44 @@ class PHYMOBAT(QtWidgets.QMainWindow, Processing): 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(): + + 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.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: + 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 = 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) @@ -777,7 +775,6 @@ class PHYMOBAT(QtWidgets.QMainWindow, Processing): 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") @@ -788,19 +785,19 @@ class PHYMOBAT(QtWidgets.QMainWindow, Processing): 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("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(): + + 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.label_chps_type_3.deleteLater() self.ui.lineEdit_fieldname_13.deleteLater() self.ui.comboBox_fieldname_13.deleteLater() self.ui.lineEdit_fieldname_23.deleteLater() @@ -809,13 +806,13 @@ class PHYMOBAT(QtWidgets.QMainWindow, Processing): self.ui.comboBox_fieldname_3.deleteLater() self.ui.lineEdit_fieldname_4.deleteLater() self.ui.comboBox_fieldname_4.deleteLater() - except AttributeError: + 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`. @@ -826,127 +823,144 @@ class PHYMOBAT(QtWidgets.QMainWindow, Processing): - 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.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 + 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(): + 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 ok == 1 : + # Compute a output slope raster if self.ui.checkBox_MNT.isChecked(): - self.i_slope() - + 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 - + 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 - + 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 + + # 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 + + # 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.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() : - + + 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.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.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 + + # Compute a output slope raster 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 self.i_download(self.ui.ignore_download.isChecked()) - - # function to launch the image processing + + # function to launch the image processing self.i_images_processing() - # Compute optimal threshold + os.system("clear") + + self.logger.debug("Début sample") + + # Compute optimal threshold self.i_sample_rf() - # Classification processing + self.logger.debug("Fin sample") + + os.system("clear") + + self.logger.debug("Début classifier") + + # Classification processing self.i_classifier_rf() + self.logger.debug("Fin classifier") + + os.system("clear") + + self.logger.debug("Début validation") + self.i_validate() + self.logger.debug("Fin validation") + # Clear variables after processing #self.clear_sample() self.out_fieldname_carto = ['ID', 'AREA'] @@ -954,37 +968,37 @@ class PHYMOBAT(QtWidgets.QMainWindow, Processing): # 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() self.logger.info('Outputted to File in {0} secondes'.format(endTime - startTime)) nb_day_processing = int(time.strftime('%d', time.gmtime(endTime - startTime))) - 1 self.logger.info("That is {0} day(s) {1}".format(nb_day_processing, 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. """ # in_backup = QtWidgets.QFileDialog.getOpenFileName(self, "Open backup", os.getcwd(), '*.xml')[0] - + if test is False : in_backup = QtWidgets.QFileDialog.getOpenFileName(self, "Open backup", os.getcwd(), '*.xml')[0] else : in_backup = test - + if in_backup 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: @@ -1002,7 +1016,7 @@ class PHYMOBAT(QtWidgets.QMainWindow, Processing): 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) @@ -1012,13 +1026,13 @@ class PHYMOBAT(QtWidgets.QMainWindow, Processing): 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']") @@ -1035,7 +1049,7 @@ class PHYMOBAT(QtWidgets.QMainWindow, Processing): 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) @@ -1044,25 +1058,25 @@ class PHYMOBAT(QtWidgets.QMainWindow, Processing): if pr.find("VHRS_checked").text == '1': self.ui.checkBox_VHRS.setChecked(True) else: - self.ui.checkBox_VHRS.setChecked(False) - + 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) - + 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']") + + ps = tree.find("Tab[@id='Processing_sample']") if self.current_mode == Constantes.EXPERT_MODE: try: for sple_n in ps.iter("Sample"): @@ -1085,7 +1099,7 @@ class PHYMOBAT(QtWidgets.QMainWindow, Processing): self.add_sample() except: self.logger.debug('Not sample') - + elif self.current_mode == Constantes.SIMPLE_MODE: # RPG sple_n = ps[0] @@ -1095,7 +1109,7 @@ class PHYMOBAT(QtWidgets.QMainWindow, Processing): 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) @@ -1103,8 +1117,8 @@ class PHYMOBAT(QtWidgets.QMainWindow, Processing): 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) - + 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) @@ -1113,13 +1127,13 @@ class PHYMOBAT(QtWidgets.QMainWindow, Processing): 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) - + self.ui.checkBox_threshold.setChecked(False) + c = tree.find("Tab[@id='Classification']") try: @@ -1136,15 +1150,15 @@ class PHYMOBAT(QtWidgets.QMainWindow, Processing): 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) + 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) + 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) + 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) @@ -1152,43 +1166,43 @@ class PHYMOBAT(QtWidgets.QMainWindow, Processing): 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) + 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) + 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) + 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) + 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 not out_backup.endswith('.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: @@ -1196,7 +1210,7 @@ class PHYMOBAT(QtWidgets.QMainWindow, Processing): 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) @@ -1209,7 +1223,7 @@ class PHYMOBAT(QtWidgets.QMainWindow, Processing): 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: @@ -1227,13 +1241,13 @@ class PHYMOBAT(QtWidgets.QMainWindow, Processing): 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: @@ -1241,9 +1255,9 @@ class PHYMOBAT(QtWidgets.QMainWindow, Processing): 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) @@ -1254,9 +1268,9 @@ class PHYMOBAT(QtWidgets.QMainWindow, Processing): 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)): @@ -1269,11 +1283,11 @@ class PHYMOBAT(QtWidgets.QMainWindow, Processing): 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 + # 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 !') + self.logger.debug('Not sample raster only !') else: # RPG sub_doc = ET.SubElement(doc, "Sample", id="Sample_0") @@ -1284,7 +1298,7 @@ class PHYMOBAT(QtWidgets.QMainWindow, Processing): 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() @@ -1294,8 +1308,8 @@ class PHYMOBAT(QtWidgets.QMainWindow, Processing): 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 + + # 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() @@ -1303,8 +1317,8 @@ class PHYMOBAT(QtWidgets.QMainWindow, Processing): 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) - + 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) @@ -1312,33 +1326,33 @@ class PHYMOBAT(QtWidgets.QMainWindow, Processing): 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_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_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) @@ -1346,7 +1360,7 @@ class PHYMOBAT(QtWidgets.QMainWindow, Processing): 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_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" @@ -1354,17 +1368,17 @@ class PHYMOBAT(QtWidgets.QMainWindow, Processing): 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): """ @@ -1393,23 +1407,23 @@ class PHYMOBAT(QtWidgets.QMainWindow, Processing): 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_()) diff --git a/Processing.py b/Processing.py index 9d833cb..218d330 100644 --- a/Processing.py +++ b/Processing.py @@ -3,17 +3,17 @@ # # This file is part of PHYMOBAT 2.0. # Copyright 2016 Sylvio Laventure (IRSTEA - UMR TETIS) -# +# # PHYMOBAT 2.0 is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. -# +# # PHYMOBAT 2.0 is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. -# +# # You should have received a copy of the GNU General Public License # along with PHYMOBAT 2.0. If not, see <http://www.gnu.org/licenses/>. @@ -22,6 +22,7 @@ import numpy as np import subprocess from sklearn.ensemble import RandomForestClassifier from sklearn import tree +import pydot try : import ogr, gdal @@ -52,19 +53,18 @@ from multiprocessing import Process from multiprocessing.managers import BaseManager, DictProxy class Processing(object): - """ Main processing. This class launch the others system classes. It take into account - CarHab classification method MOBA. - + 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 - + - Classification + - Validation + **Main parameters** - + :param captor_project: Satellite captor name :type captor_project: str :param classif_year: Classification year @@ -83,25 +83,25 @@ class Processing(object): :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 @@ -110,18 +110,18 @@ class Processing(object): :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 = '' @@ -132,16 +132,16 @@ class Processing(object): 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 = defaultdict(dict) - + # TODO : Change index of the classes -> Harbacées 6 / Ligneux 7 by Agriculuture 4 / Eboulis 5 # Class name self.in_class_name = ['Non Vegetation semi-naturelle', 'Vegetation semi-naturelle',\ @@ -149,7 +149,7 @@ class Processing(object): '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',\ @@ -161,7 +161,7 @@ class Processing(object): # '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],\ @@ -173,105 +173,104 @@ class Processing(object): # ..., ['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 = None 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 + # 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): + + def i_tree_direction(self): """ - Interface function to can extract one level or two levels of the final classification + 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, ignore_download=False): """ - Interface function to download archives on the website Theia Land. This function extract + 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 = "{0}/{1}_PoleTheia".format(self.folder_processing, self.captor_project) if not os.path.exists(folder_archive) : os.makedirs(folder_archive) self.check_download = Archive(self.captor_project, self.classif_year, self.path_area, folder_archive, self.w_proxy) - + if not ignore_download : 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): + 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`, + + 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` + + 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) """ - + current_list = Toolbox() current_list.vect = self.path_area # Map projection of the image and the cloud mask for clip_index, clip in enumerate(self.check_download.list_img): - + current_list.image = clip[3] - - current_list.check_proj() # Check if projection is RFG93 + + 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.image = clip[4] - current_list.check_proj() # Check if projection is RFG93 + current_list.check_proj() # Check if projection is RFG93 self.check_download.list_img[clip_index][4] = current_list.clip_raster() # Cloud images @@ -283,8 +282,8 @@ class Processing(object): for date in self.check_download.single_date: check_L8.mosaic_by_date(date) - - # Search cloud's percentage, select image and compute ndvi index + + # Search cloud's percentage, select image and compute ndvi index if check_L8.pourc_cloud() < Constantes.CLOUD_THRESHOLD : tmp = date check_L8.calcul_ndvi() @@ -294,7 +293,7 @@ class Processing(object): # Compute temporal stats on ndvi index [min, max, std, min-max] spectral_trans = np.transpose(np.array(spectral_out, dtype=object)) - del spectral_out + del spectral_out # stats_name = ['Min', 'Date', 'Max', 'Std', 'MaxMin'] stats_name = ['Min', 'Max'] @@ -311,12 +310,12 @@ class Processing(object): 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.image = self.path_mnt current_path_mnt.vect = self.path_area path_mnt = current_path_mnt.clip_raster() - + study_slope = Slope(path_mnt) # Call this function to compute slope raster @@ -324,27 +323,27 @@ class Processing(object): self.path_mnt = study_slope.out_mnt current_path_mnt.logger.close() - + def i_vhrs(self): """ - Interface function to processing VHRS images. - It create two OTB texture images : + 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 + + # Clip orthography image current_path_ortho = Toolbox() current_path_ortho.image = self.path_ortho current_path_ortho.vect = self.path_area current_path_ortho.output = "{0}/MosaiqueOrtho/Clip_{1}".format(self.folder_processing, os.path.basename(self.path_ortho)) - + self.path_ortho = current_path_ortho.output 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 @@ -352,10 +351,10 @@ class Processing(object): current_path_ortho.logger.close() texture_irc.logger.close() - - def i_images_processing(self): + + def i_images_processing(self): """ - Interface function to launch processing VHRS images : func:`i_vhrs` + Interface function to launch processing VHRS images : func:`i_vhrs` and satellite images :func:`i_img_sat` in multi-processing. """ @@ -365,18 +364,18 @@ class Processing(object): mgr.register('defaultdict', defaultdict, DictProxy) mgr.start() - self.out_ndvistats_folder_tab = mgr.defaultdict(list) - + self.out_ndvistats_folder_tab = mgr.defaultdict(list) + p_img_sat = Process(target=self.i_img_sat) p_vhrs = Process(target=self.i_vhrs) self.logger.debug("Multiprocessing : {0}".format(self.mp)) - + if self.mp == Constantes.MULTIPROCESSING_DISABLE: p_img_sat.start() p_img_sat.join() p_vhrs.start() - p_vhrs.join() + p_vhrs.join() else : p_img_sat.start() p_vhrs.start() @@ -387,7 +386,7 @@ class Processing(object): self.raster_path["Min"]["PATH"] = self.out_ndvistats_folder_tab['Min'] self.raster_path["Min"]["BAND"] = 1 - + for i in range(1,7) : self.raster_path["SFS_{0}".format(i)]["PATH"] = self.out_ndvistats_folder_tab['sfs'] self.raster_path["SFS_{0}".format(i)]["BAND"] = i @@ -395,24 +394,24 @@ class Processing(object): for i in range(1,9) : self.raster_path["HARALICK_{0}".format(i)]["PATH"] = self.out_ndvistats_folder_tab['haralick'] self.raster_path["HARALICK_{0}".format(i)]["BAND"] = i - + # To slope, to extract scree if self.path_mnt : self.raster_path["MNT"]["PATH"] = self.path_mnt self.raster_path["MNT"]["BAND"] = 1 - + self.raster_path["MAX"]["PATH"] = self.out_ndvistats_folder_tab['Max'] self.raster_path["MAX"]["BAND"] = 1 - + self.logger.info("End of images processing !") - - def i_rpg(self, path_rpg): + + 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). """ @@ -420,10 +419,10 @@ class Processing(object): format(self.path_folder_dpt, self.folder_processing, self.captor_project) dossier_rpg = "{0}/RPG".format(self.folder_processing) - + # Extract rpg crops mono_sample = Rpg(path_rpg, self.path_area) - + mono_sample.clip_vector(dossier_rpg) mono_sample.vector_data() @@ -440,25 +439,25 @@ class Processing(object): mono_sample.logger.close() 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`. + 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 + 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: @@ -483,24 +482,24 @@ class Processing(object): sample_rd[sple].create_sample(**kwargs) sample_rd[sple].zonal_stats((self.raster_path[round(sple/2)],\ self.list_band_outraster[round(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 + + # Search the optimal threshold by class # Open a text file to print stats of Seath method - with open("{0}/log_J.lg".format(self.path_folder_dpt), "wb") as f : + with open("{0}/log_J.lg".format(self.path_folder_dpt), "wb") as f : 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 {0} :\n'.format(self.sample_name[th_seath])) f.write('J = {0}\n'.format(self.decis[th_seath].J[0])) f.write('The class 1 {0}\n'.format(self.decis[th_seath].threshold[0])) - + i_s = 20 except Exception as e: self.logger.error("Error 519 : {0}".format(e)) @@ -510,17 +509,16 @@ class Processing(object): if i_s != 20 or True: self.logger.error('Problem during 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 = {} self.liste_chemin = [self.out_ndvistats_folder_tab['Min'], self.out_ndvistats_folder_tab['sfs'],\ self.out_ndvistats_folder_tab['haralick'], self.out_ndvistats_folder_tab['Max'] ] @@ -534,32 +532,32 @@ class Processing(object): self.logger.debug("Creation Sample : {0} - {1} - {2}".format(\ self.sample_name[round(sple/2)], self.path_area, self.list_nb_sample[round(sple/2)]) ) - sample_rd[sple] = Sample(self.sample_name[round(sple/2)], self.path_area,\ + sample_rd = Sample(self.sample_name[round(sple/2)], self.path_area,\ self.list_nb_sample[round(sple/2)]) - sample_rd[sple].clip_vector("{0}/{1}".format(self.folder_processing, os.path.basename(\ + sample_rd.clip_vector("{0}/{1}".format(self.folder_processing, os.path.basename(\ os.path.dirname(self.sample_name[round(sple/2)])))) - - sample_rd[sple].vector_data() - sample_rd[sple].output_folder = self.folder_processing - + + sample_rd.vector_data() + sample_rd.output_folder = self.folder_processing + self.logger.debug("kwargs : {0}".format(kwargs)) - sample_rd[sple].create_sample(**kwargs) + sample_rd.create_sample(**kwargs) # Add the validation shapefile - self.valid_shp.append([sample_rd[sple].vector_val, kwargs['fieldname'], kwargs['class']]) + self.valid_shp.append([sample_rd.vector_val, kwargs['fieldname'], kwargs['class']]) items = list(self.raster_path.items()) self.logger.debug("Raster path items: {0}".format(self.raster_path.items())) - sample_rd[sple].zonal_stats(self.liste_chemin) + sample_rd.zonal_stats(self.liste_chemin) # To convert the dictionnary in a list - for key, value in sample_rd[sple].stats_dict.items(): + for key, value in sample_rd.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) + # To set the grassland class of the RPG and PIAO (same class) if sple == 2 : # y_rf.append(1) pass @@ -568,53 +566,61 @@ class Processing(object): 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]) - - sample_rd[sple].logger.close() + # X_rf.append([-10000 if (x is None or math.isnan(x) or math.isinf(x)) else x for x in value]) + X_rf.append([x for x in value if (x is not None and not math.isnan(x) and not math.isinf(x))]) + + sample_rd.logger.close() + sample_rd = None - # Build a forest of trees from the samples + # Build a forest of trees from the samples self.rf = self.rf.fit(X_rf, y_rf) - + + X_rf = None + y_rf = None + # 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 = "{0}/Feature_important_RF.ft".format(self.folder_processing) if os.path.exists(file_feat_import): os.remove(file_feat_import) - + with open(file_feat_import, "w") as f_out : f_out.write("{0}".format(importance)) - + # Print in a file decision tree file_decisiontree = "{0}/Decision_tree.dot".format(self.folder_processing) - + image_decisiontree = "{0}/Decision_tree.png".format(self.folder_processing) + 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): + (graph,) = pydot.graph_from_dot_file(file_decisiontree) + graph.write_png(image_decisiontree) + + def i_classifier_rf(self): """ - Interface function to launch random forest classification with a input segmentation : + 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.Segmentation(self.path_segm, self.path_area) @@ -633,7 +639,7 @@ class Processing(object): # Stats backup file file_stats = "{0}/Stats_raster_spectral_texture.stats".format(self.folder_processing) - + p = [] kwargs = {} X_out_rf = [] # Variable list to compute decision tree with random forest method @@ -644,13 +650,15 @@ class Processing(object): out_carto.stats_dict = mgr.defaultdict(list) out_carto.zonal_stats(self.liste_chemin) - + for key, value_seg in out_carto.stats_dict.items(): - true_value = [-10000 if (x is None or math.isnan(x) or math.isinf(x)) else x for x in value_seg] + # true_value = [-10000 if (x is None or math.isnan(x) or math.isinf(x)) else x for x in value_seg] + true_value = [x for x in value_seg if (x is not None and not math.isnan(x) and not math.isinf(x))] + X_out_rf.append(true_value) - + f_out.write("{0}\n".format(true_value)) - + else: # If the stats file exists already, open this file and append in the stats_dict variable out_carto.stats_dict = defaultdict(list) @@ -662,19 +670,20 @@ class Processing(object): X_out_rf.append(eval(x_in.strip('\n'))) predicted_rf = self.rf.predict(X_out_rf) + X_out_rf = None self.logger.debug("Taille sample_name : {0}".format(len(self.sample_name))) - + # For the higher than level 1 if len(self.sample_name) > 2: # Compute the biomass and density distribution # Use 'out_carto.out_threshold' to know predicted in the segmentation class out_carto.out_threshold["PREDICTION"] = predicted_rf - - # In the compute_biomass_density function, this variable used normally to define + + # 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 @@ -686,24 +695,27 @@ class Processing(object): 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 + # 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,'') - + + predicted_rf = None # 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') - + + out_carto.stats_dict = None + # Rasterize RPG shapefile to complete the final shapefile opt = {} opt['Remove'] = 1 @@ -712,32 +724,33 @@ class Processing(object): rpg_tif.clip_vector(os.path.dirname(self.sample_name[0])) rpg_tif.vector_data() - self.logger.debug(self.path_ortho) + self.logger.debug("path_ortho : {0}".format(self.path_ortho)) out_carto.stats_rpg_tif = out_carto.zonal_stats_pp(rpg_tif.layer_rasterization(self.path_ortho, 'CODE_GROUP')) # Final cartography out_carto.create_cartography(self.out_fieldname_carto, self.out_fieldtype_carto) - - def i_classifier_s(self): + out_carto = None + + def i_classifier_s(self): """ - Interface function to launch decision tree classification with a input + 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 = Segmentation(self.path_segm, self.path_area) out_carto.output_file = self.output_name_moba out_carto.out_class_name = self.in_class_name - + 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]: @@ -747,7 +760,7 @@ class Processing(object): # 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 @@ -756,8 +769,8 @@ class Processing(object): # Add class indexes self.tree_direction[0].append(6) self.tree_direction[0].append(7) - - # Compute zonal stats on Max NDVI raster + + # 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]]) @@ -776,7 +789,7 @@ class Processing(object): 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 @@ -787,23 +800,24 @@ class Processing(object): 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: + + 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] + + # true_value = [-10000 if (math.isnan(x) or math.isinf(x)) else x for x in value_seg] + true_value = [x for x in value_seg if (not math.isnan(x) and not math.isinf(x))] # 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) @@ -813,36 +827,36 @@ class Processing(object): 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 + + # 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: + 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 = "{0}.TIF".format(self.sample_name[0][:-4]) 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`. + 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. """ @@ -855,10 +869,10 @@ class Processing(object): complete_validate_shp = "{0}/validate.shp".format(os.path.dirname(self.valid_shp[0][0])) # 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: + 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 @@ -866,15 +880,15 @@ class Processing(object): # Self.valid_shp is a list of list. In this variable there is : # [Shapefile path, fieldname classes, classnames] opt = {} - opt['Remove'] = 1 # To overwrite - + 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['add_fieldname'] = 1 opt['fieldname'] = 'CLASS_CODE' opt['class'] = str(class_validate) # Add integer classes - + # Set the new shapefile val[0] = "{0}_.shp".format(val[0][:-4]) val[1] = opt['fieldname'] @@ -882,36 +896,36 @@ class Processing(object): sample_val.clip_vector(sample_val.vector_folder) sample_val.vector_data() - + # 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) sample_val.logger.close() - - # Increrment variable + + # Increment 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 = Precision_moba(self.path_area, self.path_folder_dpt) valid.complete_validation_shp = complete_validate_shp valid.ex_raster = list(self.raster_path.items())[0][1]["PATH"] # TODO: Call the RasterSat_by_Date class here instead of the Precision_moba class self.logger.debug("Name moba : {0}".format(self.output_name_moba)) - + 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/Sample.py b/Sample.py index 266127d..0c2ce2b 100644 --- a/Sample.py +++ b/Sample.py @@ -3,17 +3,17 @@ # # This file is part of PHYMOBAT 1.2. # Copyright 2016 Sylvio Laventure (IRSTEA - UMR TETIS) -# +# # PHYMOBAT 1.2 is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. -# +# # PHYMOBAT 1.2 is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. -# +# # You should have received a copy of the GNU General Public License # along with PHYMOBAT 1.2. If not, see <http://www.gnu.org/licenses/>. @@ -31,9 +31,9 @@ except : class Sample(Vector): """ - Vector class inherits the super vector class properties. + 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 @@ -45,32 +45,32 @@ class Sample(Vector): @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 + Create a new 'Sample' instance """ self.logger = Outils.Log('Log', 'Sample') - + 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 '' @@ -78,7 +78,7 @@ class Sample(Vector): self.logger.debug("kw_classes : {0}".format(kw_classes)) self.output_folder = "{0}/{1}".format(self.output_folder, os.path.basename(os.path.dirname(self.vector_used))) - + if not os.path.exists(self.output_folder) : os.mkdir(self.output_folder) @@ -89,7 +89,7 @@ class Sample(Vector): else: # The random sample without class name selected random_sample = np.array(random.sample(range(self.data_source.GetLayer().GetFeatureCount()), self._nb_sample)) - + self.logger.debug("random_sample : {0}".format(random_sample)) # Output shapefile of the sample's polygons (path) @@ -102,61 +102,51 @@ class Sample(Vector): # 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 = "{0}val.shp".format(self.vector_used[:-6]) - + self.vector_val = "{0}val.shp".format(self.vector_used[:-6]) + # Fill and create the validate polygons shapefile self.fill_sample(self.vector_val, random_sample[round(len(random_sample)/2):]) - def select_random_sample(self, kw_field, kw_classes): + 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` + This function is used in :func:`create_sample` @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(',') - self.logger.debug('kw_classes : {0}'.format(kw_classes)) - + # List of class name id select_id = [] - shp_ogr = self.data_source.GetLayer() + layer = 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() + assert layer.GetFeatureCount() != 0, "Le shapefile : {0} est vide.".format(self.data_source.GetLayer().GetName()) + + for i in range(layer.GetFeatureCount()) : + feature = layer.GetFeature(i) + + if feature.GetFieldIndex(self.field_names[self.field_names.index(kw_field)]) != -1 \ + and not feature.GetField(self.field_names[self.field_names.index(kw_field)]) is None : + if feature.GetField(self.field_names[self.field_names.index(kw_field)]).replace('0','') in kw_classes : + select_id.append(i) + + assert len(select_id) > 0, "Aucun polygone ne correspond." return select_id - + def fill_sample(self, output_sample, polygon, **opt): """ Function to fill and create the output sample shapefile. @@ -165,15 +155,15 @@ class Sample(Vector): @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 - + 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 """ @@ -181,56 +171,56 @@ class Sample(Vector): 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() - + 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: self.logger.error('Could not create file') sys.exit(1) - + # Specific output layer out_layer = out_ds.CreateLayer(output_sample, srsObj, geom_type=ogr.wkbMultiPolygon) - - # Add existing fields + + # 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 + # 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() - + # Extract input geometry - geom = in_feature.GetGeometryRef() + geom = in_feature.GetGeometryRef() # Create a new polygon out_feature = ogr.Feature(featureDefn) @@ -249,10 +239,10 @@ class Sample(Vector): # Append polygon to the output shapefile out_layer.CreateFeature(out_feature) - + # Destroy polygons - out_feature.Destroy() + out_feature.Destroy() in_feature.Destroy() - + # Close data - out_ds.Destroy() \ No newline at end of file + out_ds.Destroy() diff --git a/Vector.py b/Vector.py index e9fd31c..2cca534 100644 --- a/Vector.py +++ b/Vector.py @@ -3,39 +3,34 @@ # # This file is part of PHYMOBAT 1.2. # Copyright 2016 Sylvio Laventure (IRSTEA - UMR TETIS) -# +# # PHYMOBAT 1.2 is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. -# +# # PHYMOBAT 1.2 is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. -# +# # You should have received a copy of the GNU General Public License # along with PHYMOBAT 1.2. If not, see <http://www.gnu.org/licenses/>. import os, sys import subprocess import numpy as np -import osgeo - -# try : -# import ogr, gdal -# except : -# from osgeo import ogr, gdal - +from osgeo import ogr import otbApplication as otb from collections import * + import Outils from RasterSat_by_date import RasterSat_by_date class Vector(): - """ + """ Vector class to extract a area, vector data and zonal statistic - + @param vector_used: Input/Output shapefile to clip (path) @type vector_used: str @@ -59,10 +54,10 @@ class Vector(): @opt: **Remove** (int) - For the remove_shp variable """ - + def __init__(self, used, cut, **opt): """ - Create a new 'Vector' instance + Create a new 'Vector' instance """ if not hasattr(self, "logger") : @@ -74,19 +69,19 @@ class Vector(): self.vector_cut = cut self.vector_used = used self.remove_shp = opt['Remove'] if opt.get('Remove') else 0 - + self.stats_dict = defaultdict(list) - + def clip_vector(self, output_folder): """ Function to clip a vector with a vector - """ + """ if not os.path.exists(output_folder) : os.makedirs(output_folder) - + outclip = "{0}/Clip_{1}".format(output_folder, self.vector_name) - + if not os.path.exists(outclip) or self.remove_shp == 1: self.logger.info('Clip of {0}'.format(self.vector_name)) @@ -100,43 +95,43 @@ class Vector(): # Replace input filename by output filename self.vector_used = outclip - + def vector_data(self): """ - Function to extract vector layer information + Function to extract vector layer information """ try: - self.data_source = osgeo.ogr.GetDriverByName('ESRI Shapefile').Open(self.vector_used, 0) + self.data_source = ogr.Open(self.vector_used) self.logger.info('Shapefile opening : {0}'.format(self.data_source.GetLayer().GetName())) except : self.logger.error('Could not open file') - sys.exit(1) + sys.exit(1) # List of field name self.field_names = [self.data_source.GetLayer().GetLayerDefn().GetFieldDefn(l).GetName() \ - for l in range(self.data_source.GetLayer().GetLayerDefn().GetFieldCount())] + for l in range(self.data_source.GetLayer().GetLayerDefn().GetFieldCount())] def close_data(self): """ - Function to remove allocate memory - """ - + Function to remove allocate memory + """ + + self.logger.info('Shapefile closing : {0}'.format(self.data_source.GetLayer().GetName())) + # Close data sources self.data_source.Destroy() - - self.logger.info('Shapefile closing : {0}'.format(self.data_source.GetLayer().GetName())) - + def zonal_stats(self, liste_chemin): """ Function to compute the mean in every polygons on a list images with otb - - :param liste_chemin : List input image path - :type liste_chemin: list(string) + + @param liste_chemin : List input image path + @type liste_chemin : list(string) """ - + self.logger.info("Compute stats 'mean' on {0}".format(os.path.split(self.vector_used)[1])) - + zonal_stats = otb.Registry.CreateApplication("ZonalStatistics") zonal_stats.SetParameterStringList("il", liste_chemin) zonal_stats.SetParameterStringList("vec", [self.vector_used]) @@ -159,15 +154,15 @@ class Vector(): for idx, r in enumerate(resultats) : self.stats_dict[idx] = r.tolist() - + self.logger.info("End of stats 'mean' on {0}".format(os.path.split(self.vector_used)[1])) def zonal_stats_pp(self, inraster): """ A zonal statistics ++ to dertermine pxl percent in every polygon - + :param inraster: Input image path - :type inraster: str + :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) """ @@ -191,30 +186,30 @@ class Vector(): dico['Maj_count'] = float(liste_item[1]) dico['Maj_count_perc'] = float(liste_item[2]) p_stats.append(dico) - + return p_stats - + def layer_rasterization(self, raster_head, attribute_r, **kwargs): """ Function to rasterize a vector using OTB. - + @param raster_head: Raster path that will look like the final raster of the rasterization @type raster_head: str @param attribute_r: Field name of the shapefile that contains class names @type attribute_r: str - @kwargs: **choice_nb_b** (int) - Output image number of band. If you choice 1, take first band. If you choice 2, take two first band etc... + @kwargs: **choice_nb_b** (int) - Output image number of band. If you choice 1, take first band. If you choice 2, take two first band etc... @returns: str -- **valid_raster** : output raster path from the rasterization """ valid_raster = "{0}.TIF".format(self.vector_used[:-4])# Name of the output raster self.logger.debug("valid_raster : {0}".format(valid_raster)) - + if os.path.exists(valid_raster): os.remove(valid_raster) - + layerRasterization = otb.Registry.CreateApplication("Rasterization") layerRasterization.SetParameterString("in", self.vector_used) layerRasterization.SetParameterString("out", valid_raster) @@ -223,5 +218,5 @@ class Vector(): layerRasterization.SetParameterString("mode.attribute.field", attribute_r) layerRasterization.ExecuteAndWriteOutput() - - return valid_raster \ No newline at end of file + + return valid_raster -- GitLab