diff --git a/README.md b/README.md
index 1fe6495..1ce676e 100644
--- a/README.md
+++ b/README.md
@@ -18,6 +18,21 @@ Then, as this plugin is very simple, you will just need two things for making a
The shapefile must have a column which contains your classification numbers *(1,3,4...)*. Otherwise if you use text or anything else it certainly won't work.
+## Installation of scikit-learn
+On Linux simply open terminal and type :
+`pip install scikit-learn`
+
+On Windows, you have few more steps to do. Open Windows menu, and search for OsGeo Shell, then type : Column name where class number is stored Mask where 0 are the pixels to ignore and 1 to classify The image to classify
+`curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py`
+
+After get-pip.py has been downloaded write :
+`python get-pip.py`
+
+Now use pip in OsGeo Shell like on Linux. Just type :
+`pip install scikit-learn`
+
+You can now use **Random Forest**, **SVM**, or **KNN** !
+
## Tips
- If your raster is *spot6scene.tif*, you can create your mask under the name *spot6scene_mask.tif* and the script will detect it automatically.
@@ -25,7 +40,7 @@ The shapefile must have a column which contains your classification numbers *(1,
## Todo
-- Implement different classifiers
+- Implement best progress bar for classifier like Random Forest / K-Nearest Neighbors.
### Thanks to...
I would like to thank the [Guiana Amazonian Park](http://www.parc-amazonien-guyane.fr/) for their confidence in my work, and the Master 2 Geomatics [Sigma](http://sigma.univ-toulouse.fr/en/welcome.html) for their excellent lessons in geomatics.
diff --git a/config.txt b/config.txt
new file mode 100644
index 0000000..abd2cd4
--- /dev/null
+++ b/config.txt
@@ -0,0 +1,6 @@
+[Classification]
+classifier = Gaussian Mixture Model
+suffix = _class
+prefix =
+masksuffix = _mask
+
diff --git a/dzetsaka.py b/dzetsaka.py
index ec00fe6..868a381 100644
--- a/dzetsaka.py
+++ b/dzetsaka.py
@@ -1,3 +1,10 @@
+# -*- coding: utf-8 -*-
+"""
+Created on Wed Jun 22 07:52:11 2016
+
+@author: nkarasiak
+"""
+
# -*- coding: utf-8 -*-
"""
/***************************************************************************
@@ -27,32 +34,21 @@
# Initialize Qt resources from file resources.py
import resources
-# Import the code for the DockWidget
-# from dzetsaka_loaddock import dzetsakaDockWidget
-#
+# import librairies
+import ConfigParser
import os
-from scripts import mainfunction
import tempfile
import scipy as sp
-import gdal
-# load dock
-from ui.dzetsaka_dock import Ui_DockWidget
-from ui import filters_dock, historical_dock, help_dock, confusion_dock
-
+from osgeo import gdal
+# load dock
+#from ui.dzetsaka_dock import Ui_DockWidget
+from ui import dzetsakaDockWidget, filters_dock, historical_dock, help_dock, confusion_dock, settings_dock
-# Load main widget
-class dzetsakaDockWidget(QDockWidget, Ui_DockWidget):
- closingPlugin = pyqtSignal()
- def __init__(self, parent=None):
- super(dzetsakaDockWidget, self).__init__(parent)
- self.setupUi(self)
-
- def closeEvent(self, event):
- self.closingPlugin.emit()
- event.accept()
+# import functions
+from scripts import mainfunction
-
+
class dzetsaka ( QDialog ):
"""QGIS Plugin Implementation."""
@@ -68,7 +64,9 @@ def __init__(self, iface):
self.iface = iface
QDialog.__init__(self)
sender = self.sender()
-
+
+ self.loadConfig()
+
# Save reference to the QGIS interface
legendInterface = self.iface.legendInterface()
@@ -105,10 +103,15 @@ def __init__(self, iface):
self.pluginIsActive = False
self.dockwidget = None
+ # load all docks
self.dockwidget = dzetsakaDockWidget()
- self.historicalmap = historical_dock()
- self.filters_dock = filters_dock()
- self.confusiondock = confusion_dock()
+ self.loadMainDock()
+
+
+
+ def loadMainDock(self):
+ """!@brief class that load main dock and init fields
+ """
## Init to choose file (to load or to save)
self.dockwidget.outRaster.clear()
self.dockwidget.outRasterButton.clicked.connect(self.select_output_file)
@@ -127,11 +130,10 @@ def __init__(self, iface):
self.dockwidget.inField.clear()
-
- self.dockwidget.inField.clear()
+ self.dockwidget.settingsButton.clicked.connect(self.loadSettings)
# Then we fill it with new selected Layer
def onChangedLayer():
- """!@brief If active layer is changed, change column combobox"""
+ """!@brief Update columns if vector changes"""
# We clear combobox
self.dockwidget.inField.clear()
# Then we fill it with new selected Layer
@@ -146,21 +148,47 @@ def onChangedLayer():
onChangedLayer()
self.dockwidget.inShape.currentIndexChanged[int].connect(onChangedLayer)
- self.dockwidget.setMaximumHeight(400)
+ #self.dockwidget.setMaximumHeight(360)
+
+
+
## let's run the classification !
self.dockwidget.performMagic.clicked.connect(self.runMagic)
-
+ def loadConfig(self):
+ """!@brief Class that loads all saved settings from config.txt"""
+ try :
+
+ dzetsakaRoot = os.path.dirname(os.path.realpath(__file__))
+ self.Config = ConfigParser.ConfigParser()
+ self.configFile = os.path.join(dzetsakaRoot,'config.txt')
+ self.Config.read(self.configFile)
+
+
+ self.classifiers=['Gaussian Mixture Model','Random Forest','Support Vector Machines','K-Nearest Neighbors']
+ self.classifier = self.Config.get('Classification','classifier')
+
+ self.classSuffix = self.Config.get('Classification','suffix')
+ self.classPrefix = self.Config.get('Classification','prefix')
+
+ self.maskSuffix = self.Config.get('Classification','maskSuffix')
+
+ except :
+
+ QgsMessageLog.logMessage('failed to open config file '+self.configFile)
+
def select_output_file(self):
"""!@brief Select file to save, and gives the right extension if the user don't put it"""
sender = self.sender()
- if sender == self.historicalmap.outShpButton:
- fileName = QFileDialog.getSaveFileName(self.dockwidget, "Select output file","","SHP (*.shp)")
+ # check if historical map run
+ if 'self.historicalmap' in locals():
+ if sender == self.historicalmap.outShpButton:
+ fileName = QFileDialog.getSaveFileName(self.dockwidget, "Select output file","","SHP (*.shp)")
else:
fileName = QFileDialog.getSaveFileName(self.dockwidget, "Select output file","","TIF (*.tif)")
-
+
if not fileName:
return
# If user give right file extension, we don't add it
@@ -171,25 +199,32 @@ def select_output_file(self):
self.dockwidget.outRaster.setText(fileName+'.tif')
else:
self.dockwidget.outRaster.setText(fileName+fileExtension)
- if sender == self.historicalmap.outRasterButton:
- if fileExtension!='.tif':
- self.historicalmap.outRaster.setText(fileName+'.tif')
- else:
- self.historicalmap.outRaster.setText(fileName+fileExtension)
- if sender == self.historicalmap.outShpButton:
- if fileExtension!='.shp':
- self.historicalmap.outShp.setText(fileName+'.shp')
+
+ # check if historical map run
+ if 'self.historicalmap' in locals():
+ if sender == self.historicalmap.outRasterButton:
+ if fileExtension!='.tif':
+ self.historicalmap.outRaster.setText(fileName+'.tif')
+ else:
+ self.historicalmap.outRaster.setText(fileName+fileExtension)
+ if sender == self.historicalmap.outShpButton:
+ if fileExtension!='.shp':
+ self.historicalmap.outShp.setText(fileName+'.shp')
+ else:
+ self.historicalmap.outShp.setText(fileName+fileExtension)
+ # check if filters_dock run
+ if 'self.filters_dock' in locals():
+ if sender == self.filters_dock.outRasterButton:
+ if fileExtension!='.tif':
+ self.filters_dock.outRaster.setText(fileName+'.tif')
else:
- self.historicalmap.outShp.setText(fileName+fileExtension)
- if sender == self.filters_dock.outRasterButton:
- if fileExtension!='.tif':
- self.filters_dock.outRaster.setText(fileName+'.tif')
- else:
- self.filters_dock.outRaster.setText(fileName+fileExtension)
+ self.filters_dock.outRaster.setText(fileName+fileExtension)
def checkbox_state(self):
+ """!@brief Manage checkbox in main dock"""
sender=self.sender()
+ # If load model
if sender == self.dockwidget.checkInModel and self.dockwidget.checkInModel.isChecked():
fileName = QFileDialog.getOpenFileName(self.dockwidget, "Select your file","")
if fileName!='':
@@ -211,7 +246,7 @@ def checkbox_state(self):
self.dockwidget.inShape.setEnabled(True)
self.dockwidget.inField.setEnabled(True)
-
+ # If save model
if sender == self.dockwidget.checkOutModel and self.dockwidget.checkOutModel.isChecked():
fileName = QFileDialog.getSaveFileName(self.dockwidget, "Select output file")
if fileName!='':
@@ -226,7 +261,7 @@ def checkbox_state(self):
self.dockwidget.outModel.clear()
self.dockwidget.outModel.setEnabled(False)
-
+ # If mask
if sender == self.dockwidget.checkInMask and self.dockwidget.checkInMask.isChecked():
fileName = QFileDialog.getOpenFileName(self.dockwidget, "Select your file")
if fileName!='':
@@ -238,7 +273,8 @@ def checkbox_state(self):
elif sender == self.dockwidget.checkInMask :
self.dockwidget.inMask.clear()
self.dockwidget.inMask.setEnabled(False)
-
+
+ # If save matrix
if sender == self.dockwidget.checkOutMatrix and self.dockwidget.checkOutMatrix.isChecked():
fileName = QFileDialog.getSaveFileName(self.dockwidget, "Save to a *.csv file", "", "CSV (*.csv)")
@@ -248,7 +284,6 @@ def checkbox_state(self):
self.dockwidget.inSplit.setEnabled(True)
self.dockwidget.inSplit.setValue(50)
else :
-
self.dockwidget.checkOutMatrix.setChecked(False)
self.dockwidget.outMatrix.setEnabled(False)
self.dockwidget.outMatrix.setEnabled(False)
@@ -256,6 +291,7 @@ def checkbox_state(self):
self.dockwidget.inSplit.setValue(100)
elif sender == self.dockwidget.checkOutMatrix :
+ self.dockwidget.outMatrix.clear()
self.dockwidget.checkOutMatrix.setChecked(False)
self.dockwidget.outMatrix.setEnabled(False)
self.dockwidget.outMatrix.setEnabled(False)
@@ -354,6 +390,7 @@ def add_action(
return action
def loadMenu(self):
+ """!@brief Create dzetsaka menu in Qgis"""
self.menu = QtGui.QMenu(self.iface.mainWindow())
self.menu.setObjectName("dzetsakaMenu")
self.menu.setTitle("dzetsaka")
@@ -409,6 +446,11 @@ def loadMenu(self):
QObject.connect(self.menu.confusionDock, SIGNAL("triggered()"), self.loadConfusion)
self.menu.addAction(self.menu.confusionDock)
+ # Settings
+ self.menu.settings = QAction(QIcon(":/plugins/dzetsaka/img/settings.png"), "Settings", self.iface.mainWindow())
+ QObject.connect(self.menu.settings, SIGNAL("triggered()"), self.loadSettings)
+ self.menu.addAction(self.menu.settings)
+
# Help
self.menu.help = QAction(QIcon(":/plugins/dzetsaka/img/icon.png"), "Help", self.iface.mainWindow())
QObject.connect(self.menu.help, SIGNAL("triggered()"), self.helpPage)
@@ -417,13 +459,89 @@ def loadMenu(self):
# Add menu
menuBar = self.iface.mainWindow().menuBar()
menuBar.insertMenu(self.iface.firstRightStandardMenu().menuAction(), self.menu)
+
+
+ def loadSettings(self):
+ """!@brief load settings dock"""
+ self.settingsdock = settings_dock()
+ self.settingsdock.show()
+
+ try:
+ # Reload config
+ self.loadConfig()
+ # Classification settings
+
+ ## classifier
+ QgsMessageLog.logMessage('Current classifier : '+self.classifier)
+ for i, cls in enumerate(self.classifiers):
+ if self.classifier == cls:
+ self.settingsdock.selectClassifier.setCurrentIndex(i)
+
+ self.settingsdock.selectClassifier.currentIndexChanged[int].connect(self.saveSettings)
+
+ ## suffix
+ self.settingsdock.classSuffix.setText(self.classSuffix)
+ self.settingsdock.classSuffix.textChanged.connect(self.saveSettings)
+
+ ## prefix
+ self.settingsdock.classPrefix.setText(self.classPrefix)
+ self.settingsdock.classPrefix.textChanged.connect(self.saveSettings)
+
+ ## mask suffix
+ self.settingsdock.maskSuffix.setText(self.maskSuffix)
+ self.settingsdock.maskSuffix.textChanged.connect(self.saveSettings)
+
+
+ # Reload config for further use
+ self.loadConfig()
+
+ except:
+ QgsMessageLog.logMessage('Failed to load settings...')
+
+ def saveSettings(self):
+ """!@brief save settings if modifications"""
+ # Change classifier
+ if self.sender() == self.settingsdock.selectClassifier:
+ if self.settingsdock.selectClassifier.currentText() !='Gaussian Mixture Model':
+ # try if Sklearn is installed, or force GMM
+ try:
+ from sklearn import neighbors
+ if self.classifier != self.settingsdock.selectClassifier.currentText():
+ self.modifyConfig('Classification','classifier',self.settingsdock.selectClassifier.currentText())
+ except:
+ QtGui.QMessageBox.warning(self, 'Library missing', 'Scikit-learn library is missing on your computer.
You must use Gaussian Mixture Model, or consult dzetsaka help for installation.', QtGui.QMessageBox.Ok)
+ #reset to GMM
+ self.settingsdock.selectClassifier.setCurrentIndex(0)
+ self.modifyConfig('Classification','classifier','Gaussian Mixture Model')
+
+ else:
+ self.modifyConfig('Classification','classifier','Gaussian Mixture Model')
+
+ if self.sender() == self.settingsdock.classSuffix:
+ if self.classSuffix != self.settingsdock.classSuffix.text():
+ self.modifyConfig('Classification','suffix',self.settingsdock.classSuffix.text())
+ if self.sender() == self.settingsdock.classPrefix:
+ if self.classPrefix != self.settingsdock.classPrefix.text():
+ self.modifyConfig('Classification','prefix',self.settingsdock.classPrefix.text())
+ if self.sender() == self.settingsdock.maskSuffix:
+ if self.maskSuffix != self.settingsdock.maskSuffix.text():
+ self.modifyConfig('Classification','maskSuffix',self.settingsdock.maskSuffix.text())
+
+
+ def modifyConfig(self,section,option,value):
+ configFile = open(self.configFile,'w')
+ self.Config.set(section,option,value)
+ self.Config.write(configFile)
+ configFile.close()
def loadConfusion(self):
+ """!@brief Load confusion dock, init button, and combobox fields """
self.confusiondock = confusion_dock()
self.confusiondock.show()
def onChangedLayer():
+ """!@brief Update columns if vector changes"""
self.confusiondock.inField.clear()
# Then we fill it with new selected Layer
if self.confusiondock.inField.currentText() == '' and self.confusiondock.inShape.currentLayer() and self.confusiondock.inShape.currentLayer()!='NoneType':
@@ -442,8 +560,9 @@ def onChangedLayer():
self.confusiondock.compare.clicked.connect(self.performConfusion)
def performConfusion(self):
- message =''
+ """!@brief Run confusion matrix and show it with kappa and overall accuraccy in confusion dock"""
+ message =''
try:
self.confusiondock.inRaster.currentLayer().dataProvider().dataSourceUri()
except:
@@ -466,32 +585,37 @@ def performConfusion(self):
inField = self.confusiondock.inField.currentText()
- worker=mainfunction.confusionMatrix()
- worker.computeStatistics(inRaster,inShape,inField)
- self.confusiondock.OA.setText(str(round(worker.OA*100,2))+str('%'))
- self.confusiondock.kappa.setText(str(round(worker.Kappa*100,2))+str('%'))
-
- ## Create and save CSV
- import csv
- outCsv = tempfile.mktemp('.csv')
- sp.savetxt(outCsv,worker.confusion_matrix,delimiter=',',fmt='%1.4d')
-
- self.model = QStandardItemModel(self)
- ## add csv to Qtable
-
- with open(outCsv, "rb") as fileInput:
- for row in csv.reader(fileInput):
- items = [
- QStandardItem(field)
- for field in row
- ]
- self.model.appendRow(items)
-
- self.confusiondock.confusionTable.setModel(self.model)
+ try:
+
+ worker=mainfunction.confusionMatrix()
+ worker.computeStatistics(inRaster,inShape,inField)
+ self.confusiondock.OA.setText(str(round(worker.OA*100,2))+str('%'))
+ self.confusiondock.kappa.setText(str(round(worker.Kappa*100,2))+str('%'))
+
+ ## Create and save CSV
+ import csv
+ outCsv = tempfile.mktemp('.csv')
+ sp.savetxt(outCsv,worker.confusion_matrix,delimiter=',',fmt='%1.4d')
- # Auto adapt size to width
- header = self.confusiondock.confusionTable.horizontalHeader()
- header.setResizeMode(QHeaderView.Stretch)
+ self.model = QStandardItemModel(self)
+ ## add csv to Qtable
+
+ with open(outCsv, "rb") as fileInput:
+ for row in csv.reader(fileInput):
+ items = [
+ QStandardItem(field)
+ for field in row
+ ]
+ self.model.appendRow(items)
+
+ self.confusiondock.confusionTable.setModel(self.model)
+
+ # Auto adapt size to width
+ header = self.confusiondock.confusionTable.horizontalHeader()
+ header.setResizeMode(QHeaderView.Stretch)
+
+ except:
+ QtGui.QMessageBox.warning(self, 'Error', 'dzetsaka cannot perform confusion matrix.', QtGui.QMessageBox.Ok)
def initGui(self):
"""Create the menu entries and toolbar icons inside the QGIS GUI."""
@@ -553,6 +677,7 @@ def unload(self):
del self.toolbar
"""
self.menu.deleteLater()
+ self.dockwidget.deleteLater()
#--------------------------------------------------------------------------
@@ -576,13 +701,12 @@ def loadWidget(self):
self.dockwidget.closingPlugin.connect(self.onClosePlugin)
# show the dockwidget
- # TODO: fix to allow choice of dock location
self.iface.addDockWidget(Qt.LeftDockWidgetArea, self.dockwidget)
self.dockwidget.show()
def loadFilters(self):
- """ """
+ """!@brief Load and init filters dock"""
self.filters_dock = filters_dock()
filtersList=['Opening','Closing','Dilation','Erosion','Median']
self.filters_dock.inFilter.addItems(filtersList)
@@ -608,10 +732,8 @@ def loadFilters(self):
self.filters_dock.runFilter.clicked.connect(self.runFilter)
-
-
def runFilter(self):
- """ """
+ """!@brief Perform filtering"""
#verif before doing the job
message=''
@@ -649,7 +771,7 @@ def runFilter(self):
def loadHistoricalMap(self):
-
+ """!@brief Load and init historical map dock"""
self.historicalmap = historical_dock()
self.historicalmap.show()
@@ -667,6 +789,7 @@ def loadHistoricalMap(self):
self.historicalmap.show()
def runHistoricalMapStep1(self):
+ """!@brief Perform pre-classification for historical map"""
message = ''
try:
@@ -698,6 +821,7 @@ def runHistoricalMapStep1(self):
worker.historicalMapFilter(inRaster,outRaster,inShapeGrey,inShapeMedian,iterMedian)
def runHistoricalMapStep2(self):
+ """!@brief Perform post-classification for historical map"""
message = ''
try:
@@ -738,6 +862,7 @@ def helpPage(self):
def runMagic(self):
+ """!@brief Perform training and classification for dzetsaka"""
#verif before doing the job
message=''
@@ -752,18 +877,14 @@ def runMagic(self):
except:
message = "Sorry, you need a raster to make a classification."
-
+
if message != '':
QtGui.QMessageBox.warning(self, 'Information missing or invalid', message, QtGui.QMessageBox.Ok)
# all is ok, so do the job !
else:
- # create temp if not output raster
- if self.dockwidget.outRaster.text()=='':
- outRaster= tempfile.mktemp('.tif')
- else:
- outRaster= self.dockwidget.outRaster.text()
-
+ # get config
+ self.loadConfig()
# Get model if given
model=self.dockwidget.inModel.text()
@@ -772,11 +893,20 @@ def runMagic(self):
inRaster=self.dockwidget.inRaster.currentLayer()
inRaster=inRaster.dataProvider().dataSourceUri()
+ # create temp if not output raster
+ if self.dockwidget.outRaster.text()=='':
+ tempFolder = tempfile.mkdtemp()
+ outRaster= os.path.join(tempFolder,self.classPrefix+os.path.splitext(os.path.basename(inRaster))[0]+self.classSuffix+'.tif')
+
+ else:
+ outRaster= self.dockwidget.outRaster.text()
+
+
inMask=self.dockwidget.inMask.text()
- # check if mask with _mask.extension
-
+
+ # check if mask with _mask.extension
autoMask=os.path.splitext(inRaster)
- autoMask=autoMask[0]+str('_mask')+autoMask[1]
+ autoMask=autoMask[0]+self.maskSuffix+autoMask[1]
if os.path.exists(autoMask):
inMask=autoMask
@@ -786,36 +916,50 @@ def runMagic(self):
# Check if model, else perform training
if self.dockwidget.inModel.text()!='':
model=self.dockwidget.inModel.text()
- # Perform training
+
+
+ # Perform training & classification
else:
- if self.dockwidget.outModel.text()=='':
- model=tempfile.mktemp('.'+str(model))
- else:
- model=self.dockwidget.outModel.text()
-
- inShape = self.dockwidget.inShape.currentLayer()
- # Remove layerid=0 from SHP Path
- inShape=inShape.dataProvider().dataSourceUri().split('|')[0]
-
- inField = self.dockwidget.inField.currentText()
-
- inSeed = 0
- if self.dockwidget.checkOutMatrix.isChecked():
- outMatrix = self.dockwidget.outMatrix.text()
- inSplit = self.dockwidget.inSplit.value()
- else:
- inSplit = 1
- outMatrix = None
+ try:
+
+ if self.dockwidget.outModel.text()=='':
+ model=tempfile.mktemp('.'+str(model))
+ else:
+ model=self.dockwidget.outModel.text()
- temp=mainfunction.learnModel(inRaster,inShape,inField,model,inSplit,inSeed,outMatrix,inClassifier='GMM')
-
+ inShape = self.dockwidget.inShape.currentLayer()
+ # Remove layerid=0 from SHP Path
+ inShape=inShape.dataProvider().dataSourceUri().split('|')[0]
+
+ inField = self.dockwidget.inField.currentText()
+
+ inSeed = 0
+ if self.dockwidget.checkOutMatrix.isChecked():
+ outMatrix = self.dockwidget.outMatrix.text()
+ inSplit = self.dockwidget.inSplit.value()
+ else:
+ inSplit = 1
+ outMatrix = None
+
+ # retrieve shortname classifier
+ classifierShortName = ['GMM','RF','SVM','KNN']
+ for i, cls in enumerate(self.classifiers):
+ if self.classifier == cls:
+ inClassifier=classifierShortName[i]
+ QgsMessageLog.logMessage('Begin training with '+inClassifier+ ' classifier')
+ # perform learning
+ temp=mainfunction.learnModel(inRaster,inShape,inField,model,inSplit,inSeed,outMatrix,inClassifier)
+
+ except:
+ QtGui.QMessageBox.warning(self, 'Problem while training model', 'Something went wrong during the training. Are you sure to have only integer values in your '+str(inField)+' column ?', QtGui.QMessageBox.Ok)
# Perform classification
try:
+ QgsMessageLog.logMessage('Begin classification with '+inClassifier+ ' classifier')
temp=mainfunction.classifyImage()
temp.initPredict(inRaster,model,outRaster,inMask)
self.iface.addRasterLayer(outRaster)
except:
- QtGui.QMessageBox.warning(self, 'dzetsaka Magic didn\t work...', 'Something went wrong during the procress, please consult the log in Qgis to have more details.', QtGui.QMessageBox.Ok)
+ QtGui.QMessageBox.warning(self, 'Problem while training model', 'Something went wrong during the training.
Are you sure to have only integer values in your '+str(inField)+' column ?
Please show Qgis log for more information.', QtGui.QMessageBox.Ok)
diff --git a/img/settings.png b/img/settings.png
new file mode 100644
index 0000000..4beabf2
Binary files /dev/null and b/img/settings.png differ
diff --git a/metadata.txt b/metadata.txt
index ec2d272..cbfdcee 100644
--- a/metadata.txt
+++ b/metadata.txt
@@ -10,11 +10,11 @@
name=dzetsaka : Classification tool
qgisMinimumVersion=2.0
description=Fast and Easy Classification plugin for Qgis
-version=1.2
+version=2.0
author=Nicolaï Van Lennepkade
email=karasiak.nicolas@gmail.com
-about=Plugin for semi-automatic classification with Gaussian Mixture Model classifier. Very easy and fast.
You need to have scipy installed on your computer.
For more information on this tool you can go on your homepage Dzetsaka Classification Tool on Github
+about=Plugin for semi-automatic classification with Gaussian Mixture Model classifier. Very easy and fast.
You need to have scipy and scitkit-learn libraries.
For more information on this tool you can go on your homepage Dzetsaka Classification Tool on Github
tracker=https://github.com/lennepkade/dzetsaka/issues
repository=http://www.github.com/lennepkade/dzetsaka
@@ -23,9 +23,9 @@ repository=http://www.github.com/lennepkade/dzetsaka
# Recommended items:
# Uncomment the following line and add your changelog:
-changelog= New module : Compare prediction with truth (performs kappa, overall accuracy and confusion matrix)
+changelog= Now support Random Forest, SVM and KNN classifiers. Correct some bugs and add settings management.
# Tags are comma separated with spaces allowed
-tags=classification,automatic,gaussian,mixture,model
+tags=classification,semi-automatic,gaussian,mixture,model,random forest,svm,knn,forest
homepage=http://www.github.com/lennepkade/dzetsaka
category=Raster
diff --git a/resources.py b/resources.py
index bad7d4e..b752807 100644
--- a/resources.py
+++ b/resources.py
@@ -2,8 +2,7 @@
# Resource object code
#
-# Created: dim. juin 12 19:20:45 2016
-# by: The Resource Compiler for PyQt (Qt v4.8.6)
+# Created by: The Resource Compiler for PyQt4 (Qt v4.8.7)
#
# WARNING! All changes made in this file will be lost!
@@ -10508,6 +10507,149 @@
\x59\x80\x44\x85\xe4\x68\x13\x08\x14\xc8\xe4\x62\x87\x14\x6a\x9d\
\xbc\xf1\x59\x77\x2f\x7a\xd6\xea\x15\x0f\x7c\x5d\xe3\x2b\xf9\xdb\
\x67\xff\x01\x0b\x8e\x13\x7e\
+\x00\x00\x08\xc5\
+\x89\
+\x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52\x00\
+\x00\x00\x80\x00\x00\x00\x80\x08\x06\x00\x00\x00\xc3\x3e\x61\xcb\
+\x00\x00\x00\x04\x73\x42\x49\x54\x08\x08\x08\x08\x7c\x08\x64\x88\
+\x00\x00\x00\x09\x70\x48\x59\x73\x00\x00\x0b\x13\x00\x00\x0b\x13\
+\x01\x00\x9a\x9c\x18\x00\x00\x08\x67\x49\x44\x41\x54\x78\x9c\xed\
+\x9d\x57\x88\x9d\x45\x14\x80\xbf\x35\xc6\x65\xd7\x14\x63\x34\x31\
+\x36\x54\x2c\x6b\x21\x68\x88\x1a\x2b\x82\x28\x36\xac\x48\x2c\x0f\
+\x01\x5b\xd0\x60\x43\x45\xc5\x8a\x0f\x56\x8c\x10\x15\x7b\x05\xf1\
+\x45\x11\x11\x2c\x08\x1a\x44\x11\x35\x26\xf6\x44\x4d\xd4\x6c\x8a\
+\x29\x1a\xd7\x34\xdd\x98\xe4\xfa\x70\xee\xba\xbb\xf1\xde\xbd\x7f\
+\x39\x67\xe6\xbf\xff\x9e\x0f\xce\xdb\xee\x99\x39\x33\xe7\x9f\x3b\
+\xe5\xcc\x19\x70\x1c\xc7\x71\x1c\xc7\x71\x1c\xc7\x71\x1c\xc7\x71\
+\x1c\xa7\xfc\xb4\xc4\xae\x80\x01\x13\x80\x7d\xd0\xb7\xad\x02\xfc\
+\x00\xcc\x51\xd6\xeb\x28\xf2\x30\xd2\x51\x96\xf2\x50\x30\x6b\x9c\
+\x54\x1c\x82\x7d\xe7\xf7\xc8\x84\x40\x36\x99\xb3\x55\xec\x0a\x28\
+\x72\x68\xc0\xb2\x0e\x0f\x58\x96\x29\x65\x72\x80\xbd\x4b\x5a\x96\
+\x29\xee\x00\xc5\x2f\xcb\x94\x32\x39\xc0\x3e\x25\x2d\xcb\x94\xb2\
+\x2c\x03\x5b\x80\xb5\x40\x7b\xa0\xf2\xba\xab\x65\x6d\x0e\x54\x9e\
+\x19\x65\x19\x01\x76\x26\x5c\xe7\x03\xb4\x02\xbb\x06\x2c\xcf\x8c\
+\xb2\x38\x40\x8c\xdf\xe4\x52\xcc\x03\xca\xe2\x00\x31\x7e\x93\x4b\
+\x31\x0f\x28\x8b\x03\xf8\x08\x90\x11\x77\x80\xe6\x2a\x53\x1d\x77\
+\x80\xe6\x2a\x53\x9d\xb2\x2c\x03\xd7\x02\xdb\x06\x2e\xf3\xaf\x6a\
+\x99\x95\xc0\xe5\xaa\x52\x86\x11\x60\x1c\xe1\x3b\x1f\xa0\x0d\xd8\
+\x25\x42\xb9\xaa\x84\x70\x80\x31\xc0\x31\xc0\x76\x46\xfa\x63\x0e\
+\xc5\x56\x65\x8f\x04\x8e\x05\xc6\x1a\xe9\x0f\xc6\xc5\xc8\xae\x59\
+\x05\x19\x32\x5f\x00\x8e\x54\xd2\x3d\x1c\xb8\x1e\x58\x48\xb8\x63\
+\xe0\x2d\xa5\x13\xb8\xa1\x5a\x17\x0d\x8e\x00\x9e\x07\xd6\x57\xf5\
+\x6f\x00\x2e\x55\xd2\x1d\x9c\xbd\x80\xbf\xa9\xdd\x70\x5f\x01\xd3\
+\x10\x4f\x4f\x4b\x1b\x70\x13\xf0\x7b\x1d\xdd\x31\xe4\x77\xe0\xe6\
+\x6a\xdd\xd2\x32\x02\xb8\x02\xf8\xb2\x8e\xee\x6e\x9a\x74\xc2\xf9\
+\x1a\x8d\x1b\x6e\x1d\xf0\x0c\xc9\xcf\xf2\xcf\x03\x16\x25\xd0\x1b\
+\x4b\x16\x01\x93\x13\xda\x32\x11\x78\x1a\x99\xc0\x36\xd2\xfb\x7a\
+\x42\x9d\x85\xe1\x78\xd2\x37\xde\x6c\x60\x2a\x30\xac\x86\xbe\xdd\
+\x80\x77\x32\xe8\x8c\x25\x6f\x57\xeb\xbc\x25\xc3\x80\xcb\x80\xcf\
+\x33\xe8\x3c\xa1\x66\x4b\x17\x90\x21\xc0\xd7\x64\x6f\xbc\xd5\xc0\
+\xe3\x48\x88\x17\xc8\x57\xdf\x95\x43\x5f\x2c\xe9\xaa\xd6\x1d\xe0\
+\x60\xe0\xb1\xaa\x6d\x59\xf5\x7d\x03\x6c\x9d\xa8\x07\x22\x33\x0d\
+\xbd\x46\xfc\x41\x51\x57\x2c\xf9\x5e\x51\xd7\x95\x29\xfa\x21\x11\
+\xda\x1b\x41\xa3\x80\x1f\x81\xd1\xca\x7a\x1d\x61\x15\x72\x08\xb5\
+\x4a\x4b\xe1\x10\x2d\x45\x55\xee\x07\x8e\x53\xd6\xe9\xf4\xd2\x86\
+\xcc\x23\xde\x8c\x5d\x91\x5a\x1c\x00\xfc\x43\xfc\x21\xb7\xec\xb2\
+\x11\x38\x28\x61\x9f\x04\xa5\x99\x66\xe9\xcd\x2e\xef\x26\xec\x93\
+\x60\x9c\x4e\xfc\x46\x19\x6c\x72\x46\xa2\x9e\x69\x80\xc6\x24\x70\
+\x1b\xe0\x5b\x9a\x74\xb7\xaa\x89\x59\x80\xfc\xec\x6e\xc8\xa3\x44\
+\x63\x12\x78\x1d\xc9\x77\xbf\x1c\x3d\xb6\x47\x76\x11\x3f\xca\xa3\
+\x24\xef\x08\x30\x16\x59\xf6\x69\x1d\x86\x38\xe9\x58\x83\x2c\x0b\
+\x97\x67\x55\x90\xf7\x38\xf8\x1e\xbc\xf3\x63\x32\x1c\xe9\x83\x28\
+\x4c\x44\x2e\x46\xc4\x9e\x0c\x0d\x76\xd9\x5c\xed\x8b\xe0\x7c\x94\
+\xa1\xb2\x2e\x36\xf2\x61\x83\xbe\x52\xe7\x02\xa5\x8a\xbb\xe8\xc9\
+\xf9\x03\xf6\x58\x1d\xb2\x4c\x02\xdb\x91\x03\x8e\x66\xbc\x1a\xb5\
+\x08\xf8\x18\xa9\xff\x62\x64\x16\x0d\xb2\xbd\xba\x2b\xd0\x81\x44\
+\x2c\x35\x63\xac\xdf\x22\xa4\xfe\xeb\xad\x0b\xba\x83\xf8\xde\x9e\
+\x46\x16\x02\x77\x02\xfb\xa5\xb0\xb1\x03\xb8\x0b\x09\xf9\x8a\x5d\
+\xff\x34\x72\x7b\x0a\x1b\x33\x33\x2f\x92\x71\x69\xa5\x13\x98\x42\
+\xbe\x33\xf4\xa1\xc0\x45\xc8\x68\x11\xdb\x9e\x24\x32\x37\x87\xad\
+\x89\x99\x15\xc9\xb8\xa4\xb2\x19\x98\x8e\x6e\xa8\xf8\x30\x60\x46\
+\x01\x6c\x6b\x24\xb3\x14\x6d\xae\xcb\xd9\xc0\xa6\x08\xc6\x25\x91\
+\x3f\x81\x53\xed\x4c\xe7\x4c\x64\xf3\x25\xb6\x9d\xf5\x1c\xff\x1c\
+\x3b\xd3\xfb\x73\x12\x12\x94\x10\xdb\xe8\xbe\xb2\x82\xde\x30\x32\
+\x4b\x26\x02\x2b\x23\xd8\x37\x90\xac\x02\x4e\xb1\x34\xba\x16\x7b\
+\x22\x49\x13\x63\x1b\x5f\x41\xbe\xfc\x10\x9d\xdf\xc3\xa1\x14\x67\
+\x24\x98\x83\x84\xe0\x47\xa1\x0d\xb9\xec\x11\xb3\x01\x36\x63\x3b\
+\xec\xd7\xe3\xac\x8c\xf5\xd5\x94\x17\xc8\x76\x17\x41\x9d\x2b\xe8\
+\xbd\x01\x14\x5a\xa6\x07\xb0\xaf\x1e\x8f\x0c\x50\x2f\x4b\xe9\x46\
+\xda\xbc\x50\x4c\x22\xfc\x72\xa9\x93\x38\x17\x43\x7b\x18\x01\x2c\
+\xad\x51\x2f\x4b\x59\x8c\xb4\x75\x21\x19\x0b\xcc\x24\x5c\x63\x4c\
+\x09\x62\xd5\xc0\x4c\x25\x9c\xbd\xef\x23\x97\x6d\x0b\xcd\xd6\xc0\
+\x83\xd8\x37\xc6\x42\x8a\x71\x51\xa2\x15\x58\x82\xbd\xbd\x0f\xa0\
+\x1f\xc5\x6d\xca\x64\x92\xdd\x7b\xcb\x2a\x77\x06\xb3\xa4\x31\xf7\
+\x62\x67\xe7\x6a\x02\xae\xef\xb5\x39\x00\xbb\xeb\xdb\x69\xf6\xf6\
+\xad\x19\x8f\x8d\x8d\x3f\x01\xfb\x07\xb4\xc3\x04\x8b\x70\xf1\xce\
+\xa0\x16\x24\x63\x39\xfa\x76\xbe\x61\x5d\xe9\x10\x19\x42\x2c\x8e\
+\x56\x3f\x36\xd0\x99\x17\x8b\x3a\x99\x1f\x4b\x87\x4a\x11\xa3\xcd\
+\xf7\x06\x3a\xf3\x32\xcf\x40\xa7\xf9\x8c\x3f\x84\x03\x8c\x32\xd0\
+\xb9\xd8\x40\x67\x5e\x2c\xea\x64\x95\x57\xe9\x3f\xac\x1d\x60\x08\
+\x36\x4b\xb5\xb5\x8d\xff\x24\x38\x6b\x0c\x74\x9a\x6f\xf3\x96\x21\
+\x4d\x9c\x93\x03\x6b\x07\xd8\x84\xdc\x18\xd6\xa6\x56\x1a\x99\xd8\
+\x58\xdc\x8f\xf8\xcb\x40\x67\x3f\x42\x8c\x00\x5d\x06\x3a\x8b\x18\
+\x90\x5a\x2b\x27\x50\x5e\x2c\xda\xae\x1f\x21\x1c\x60\x85\x81\xce\
+\x0e\x03\x9d\x79\xb1\xa8\x53\xe6\x2b\x5f\x49\x09\xe1\x00\x4b\x0c\
+\x74\x1e\x61\xa0\x33\x0f\x2d\xd8\xd4\x69\xa9\x81\xce\xa0\x8c\xc7\
+\x2e\xb4\xba\x48\xa3\xc0\xc1\xd8\xd8\xf8\x0b\x70\x60\x38\x33\x74\
+\xb9\x10\x49\x04\x69\xd1\x30\x15\x24\x6e\xbf\x28\xdc\x87\x9d\x9d\
+\x6b\x69\xb2\xeb\xf7\x43\x09\x13\x42\xdd\x59\x2d\x2b\x36\xad\xc0\
+\xaf\xd8\xdb\x3b\x9d\x62\x1c\x7f\x0f\xc8\x38\xe4\xa2\xa2\x75\x63\
+\xf4\xc8\x45\x61\xcc\x1a\x90\xcb\x09\x67\xef\x4c\x0a\x9c\x41\xfc\
+\x68\xc2\x7c\x09\x7d\x65\x31\x71\xf7\x04\x46\x02\xcb\x6a\xd4\xcb\
+\xda\xe6\xa2\x4d\x82\xb9\x1a\xc9\x55\x13\xb2\x21\x7a\x64\x46\x00\
+\xfb\xea\xf1\xc4\x00\xf5\xb2\x94\x6e\x24\x23\x6b\x74\xda\x81\x97\
+\x88\xd3\x08\x7d\x45\x25\x63\x56\x4a\xce\xcd\x51\x5f\x2d\x79\x91\
+\x88\x61\xe1\x7b\x23\x79\xff\x63\x37\x42\x05\x39\x88\x09\x99\x25\
+\x63\x12\xb6\x2b\x9c\x34\x32\x07\xb9\xa4\x13\x94\xd3\x80\x3f\x72\
+\x56\x5c\x5b\x56\x12\xc6\x09\x26\x51\xac\xc7\x2a\x2a\xc8\xd5\xb0\
+\x93\x2d\x8d\xee\xcb\x64\x8a\x9b\x1b\x68\x0d\x72\x63\xc7\x8a\x73\
+\x29\xce\x97\xbf\xa5\x6c\x22\xd0\x4f\xe1\xec\x08\xc6\xa5\x95\x47\
+\x90\x4b\x1b\x5a\x8c\x24\xde\x84\x2f\x8d\x04\x09\x95\x9b\x1b\xc9\
+\xb8\xb4\xb2\x14\xb9\xb4\xb1\x4d\x0e\x5b\x5b\x91\x75\x7e\xe8\xa5\
+\x5e\x56\xf9\x32\x87\xad\x89\xb9\x35\x92\x71\x59\x65\x09\x12\xb7\
+\x3f\x3e\xa1\x7d\x2d\xc8\xde\xfe\x7d\x84\xdf\xd7\xc8\x2b\x37\x26\
+\xb4\xb1\x9f\xb1\x69\x69\x43\x02\x20\x77\xcf\xf0\xbf\xb1\x59\x81\
+\x0c\x93\xf3\x90\x0d\x95\x9e\x30\xae\xe1\xc8\x79\x7e\x07\xb2\xc9\
+\xb2\x63\x94\xda\xe5\xe3\x67\xe4\x0e\x41\x77\x88\xc2\x26\x13\xdf\
+\xdb\x5d\xfa\xcb\xd9\x03\xf6\x98\x01\x1f\x28\x55\xdc\x25\xbf\xbc\
+\xd7\xa0\xaf\x4c\x98\x40\x71\x73\x05\x0d\x26\xd9\x48\xf2\xf9\xcd\
+\xff\xc8\x13\x11\x34\x1b\x78\x2e\xc7\xff\x3b\x3a\x3c\x85\xec\xc8\
+\x66\x22\x6f\xba\xf8\x31\x48\xba\x78\xcd\x35\xb7\x93\x9c\x3f\x80\
+\x7d\x81\xdf\xb2\x2a\xc8\x7b\xdf\x7c\x1d\x32\x04\x9d\x98\x53\x8f\
+\x93\x8d\x9b\x91\xa4\x11\x99\xd1\x78\x32\x66\x28\xf2\xaa\xe5\xbe\
+\x0a\xba\x9c\xe4\xcc\x45\x7e\xfb\x37\xe6\x51\xa2\x11\x15\xfc\x0f\
+\xf2\x6c\x8c\x13\x96\x6b\xc8\xd9\xf9\xda\xbc\x45\xfc\x19\xf1\x60\
+\x11\xb5\xbc\x01\x9a\x4f\xc7\x76\x20\x8f\x46\x17\x3e\x70\xb1\xc9\
+\xd9\x80\x3c\x1c\xf9\xa3\x86\x32\xcd\x8b\x21\xf3\x80\x47\x15\xf5\
+\x39\xb5\x99\x81\x52\xe7\x83\xfe\xe3\xd1\xdb\x21\x95\xdb\x41\x59\
+\xaf\x23\x2c\x47\x26\xdb\xab\xb5\x14\x6a\x5f\x0d\xeb\x02\x6e\x53\
+\xd4\xf7\x9d\xa2\xae\x58\x68\xda\x70\x0b\x8a\x9d\x6f\xc5\x56\xc0\
+\x17\x64\x9f\xe0\x74\x01\x0f\xd3\xfb\x40\xf2\x59\xc8\x46\x47\xec\
+\x89\x57\x5a\x59\x89\x3c\xa9\x0b\xb2\x5c\x7b\x14\x49\x6a\x9d\x55\
+\xdf\x2c\x9a\x28\x9f\xc3\x71\xa4\x37\xf0\x13\xe4\xa2\x47\x7b\x0d\
+\x7d\xe3\x80\xd7\x32\xe8\x8c\x25\xaf\x52\xfb\x02\xc7\xb6\xc0\x25\
+\xc0\x67\x19\x74\x1e\x55\xab\xa1\x8b\xcc\x2b\x34\x36\x6a\x0d\xf0\
+\x38\x12\x80\x91\x84\x33\x90\xdc\x79\xb1\x3b\xb8\x9e\xcc\xa7\xf7\
+\xab\x6f\xc4\x04\xe0\x49\x92\xa5\x9d\x7f\x39\xa1\xce\x42\xb1\x07\
+\x92\xe1\xa2\x96\x41\xb3\x91\x70\xad\x2c\xb7\x7a\x5a\x81\x6b\xb1\
+\xc9\xcb\x97\x55\x96\x01\x57\x91\x2d\xfc\x6c\x38\x12\x76\x56\xef\
+\x67\x73\x1d\x36\xc9\x27\x82\x30\x85\x5e\x27\x58\x07\x3c\x8d\x3c\
+\xb6\xa0\x41\x3b\xd2\xe8\x0b\x88\xfb\xc5\x4f\x43\xef\x72\xc6\xe1\
+\xc0\xb3\xf4\x46\x1e\xaf\x27\xe3\x7b\x80\x45\x62\x34\x12\x4b\x6f\
+\xf5\xc6\xf0\x31\xc4\x73\x00\xab\xb4\xed\x23\x80\xc3\xb0\x49\xb1\
+\x57\x3a\x76\x22\x9e\x03\x8c\x0e\x60\x9f\x93\x80\x18\xef\xf7\xac\
+\x0a\x62\x99\x31\x4d\xb3\xae\x6c\xc0\x82\x41\x52\xa6\x3a\x65\x71\
+\x80\xf9\x83\xa4\x4c\x75\xca\xe2\x00\x6a\x87\x23\x05\x2f\x53\x9d\
+\xb2\x38\x80\x8f\x00\x19\x71\x07\x68\xae\x32\xd5\x71\x07\x68\xae\
+\x32\xd5\xd1\x8e\x07\x88\x45\x0b\x92\x4f\xaf\xd6\x41\x92\x05\xab\
+\x91\x2b\xe3\x4d\x4f\x59\x46\x80\x0a\x61\x97\x65\xa5\xf8\xfa\xa1\
+\x3c\x0e\x00\x61\x3b\xc5\x1d\xa0\x80\xb8\x03\x64\xa0\x4c\x0e\x10\
+\x72\x5d\x5e\x8a\x3d\x00\x28\x97\x03\x7c\x16\xb0\xac\x4f\x03\x96\
+\xe5\xa4\x60\x3a\xf6\x87\x40\x77\x07\xb3\x26\x00\x65\x59\x06\xf6\
+\xe5\x20\xe4\x59\x59\x6d\xdb\x2a\xc8\x7d\xbc\x32\x44\x2a\x3b\x8e\
+\xe3\x38\x8e\xe3\x38\x8e\xe3\x38\x8e\xe3\x38\x8e\x33\xa8\xf8\x17\
+\x0b\x2c\x77\xbc\xb5\x56\x26\xed\x00\x00\x00\x00\x49\x45\x4e\x44\
+\xae\x42\x60\x82\
\x00\x00\x52\x29\
\x89\
\x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52\x00\
@@ -11886,6 +12028,10 @@
\x0b\x6a\xcd\x87\
\x00\x76\
\x00\x65\x00\x63\x00\x74\x00\x6f\x00\x72\x00\x2e\x00\x73\x00\x76\x00\x67\
+\x00\x0c\
+\x0b\xdf\x21\x47\
+\x00\x73\
+\x00\x65\x00\x74\x00\x74\x00\x69\x00\x6e\x00\x67\x00\x73\x00\x2e\x00\x70\x00\x6e\x00\x67\
\x00\x08\
\x0c\x33\x5a\x87\
\x00\x68\
@@ -11896,7 +12042,7 @@
\x00\x00\x00\x00\x00\x02\x00\x00\x00\x01\x00\x00\x00\x01\
\x00\x00\x00\x00\x00\x02\x00\x00\x00\x01\x00\x00\x00\x02\
\x00\x00\x00\x14\x00\x02\x00\x00\x00\x01\x00\x00\x00\x03\
-\x00\x00\x00\x2a\x00\x02\x00\x00\x00\x0c\x00\x00\x00\x04\
+\x00\x00\x00\x2a\x00\x02\x00\x00\x00\x0d\x00\x00\x00\x04\
\x00\x00\x00\xb0\x00\x00\x00\x00\x00\x01\x00\x00\x72\xea\
\x00\x00\x00\xdc\x00\x00\x00\x00\x00\x01\x00\x01\x9a\xb6\
\x00\x00\x00\x6a\x00\x00\x00\x00\x00\x01\x00\x00\x4f\xc9\
@@ -11907,6 +12053,7 @@
\x00\x00\x01\x14\x00\x01\x00\x00\x00\x01\x00\x01\xfa\x51\
\x00\x00\x01\x56\x00\x01\x00\x00\x00\x01\x00\x02\x82\xf1\
\x00\x00\x01\x70\x00\x00\x00\x00\x00\x01\x00\x02\x8e\xad\
+\x00\x00\x01\x8e\x00\x00\x00\x00\x00\x01\x00\x02\x97\x76\
\x00\x00\x00\x50\x00\x01\x00\x00\x00\x01\x00\x00\x44\x52\
\x00\x00\x01\x2e\x00\x00\x00\x00\x00\x01\x00\x02\x02\x65\
"
diff --git a/resources.qrc b/resources.qrc
index 5a91162..74e7ff7 100644
--- a/resources.qrc
+++ b/resources.qrc
@@ -12,5 +12,6 @@
Your ROI
", None)) + self.label.setText(_translate("DockWidget", "or", None)) + self.checkInModel.setText(_translate("DockWidget", "Load model", None)) + self.label_4.setToolTip(_translate("DockWidget", "Column name where class number is stored
", None)) + self.inModel.setPlaceholderText(_translate("DockWidget", "Model", None)) + self.outRaster.setPlaceholderText(_translate("DockWidget", "Classification. Leave empty for temporary file", None)) + self.performMagic.setText(_translate("DockWidget", "Perform the classification", None)) + self.settingsButton.setText(_translate("DockWidget", "...", None)) + self.outRasterButton.setText(_translate("DockWidget", "...", None)) + self.mGroupBox.setTitle(_translate("DockWidget", "Optional", None)) + self.label_5.setToolTip(_translate("DockWidget", "Mask where 0 are the pixels to ignore and 1 to classify
", None)) + self.checkInMask.setText(_translate("DockWidget", "Mask", None)) + self.inMask.setPlaceholderText(_translate("DockWidget", "Automatic find filename_mask.ext", None)) + self.label_6.setToolTip(_translate("DockWidget", "If you want to save the model for a further use and with another image
", None)) + self.checkOutModel.setText(_translate("DockWidget", "Save model", None)) + self.outModel.setPlaceholderText(_translate("DockWidget", "To use with another image", None)) + self.label_11.setToolTip(_translate("DockWidget", "If you want to save the model for a further use and with another image
", None)) + self.checkOutMatrix.setText(_translate("DockWidget", "Save matrix", None)) + self.outMatrix.setPlaceholderText(_translate("DockWidget", "Save confusion matrix", None)) + self.label_9.setText(_translate("DockWidget", "Split", None)) + self.label_10.setToolTip(_translate("DockWidget", "In percent, number of polygons used for classification and number used for stats (confusion matrix, overall accuracy and Kappa)
", None)) + self.label_10.setText(_translate("DockWidget", "(?)", None)) + self.inSplit.setSuffix(_translate("DockWidget", "%", None)) + +from qgis import gui diff --git a/ui/dzetsaka_dock.ui b/ui/dzetsaka_dock.ui index 7b37da3..5edf202 100644 --- a/ui/dzetsaka_dock.ui +++ b/ui/dzetsaka_dock.ui @@ -6,27 +6,27 @@dzetsaka : classification tool
\n" -"Welcome to dzetsaka plugin for Qgis !
\n" -"dzetsaka allows you to make classification from a vector and a raster, to filter your image (median, closing, dilation...) and to use the Historical Map Process (tool for automatic vectorizing forest from old map).
\n" -"If you want more information or some help for using it, please consult our GitHub page :
\n" -"dzetsaka : classification tool on GitHub.
\n" -"Plugin developped by Nicolaï Van Lennepkade.
\n" -"dzetsaka : classification tool
\n" +"Welcome to dzetsaka plugin for Qgis !
\n" +"dzetsaka allows you to make classification from a vector and a raster using Random Forest, Gaussian Mixture Model, Support Vector Machines or K-Nearest Neighbors.
\n" +"You can also filter your image (median, closing, dilation...), use the Historical Map Process (tool for automatic vectorizing forest from old map) or perform a confusion matrix with Kappa and overall accuracy stats.
\n" +"If you want more information or some help for using it, please consult our GitHub page :
\n" +"dzetsaka : classification tool on GitHub.
\n" +"Plugin developped by Nicolaï Van Lennepkade.
", None)) diff --git a/ui/help_dock.ui b/ui/help_dock.ui index 80e92fb..c89dd55 100644 --- a/ui/help_dock.ui +++ b/ui/help_dock.ui @@ -6,8 +6,8 @@