Skip to content

Commit

Permalink
Merge branch 'master' of github.com:DINFO-UniFI/RoofClassify
Browse files Browse the repository at this point in the history
  • Loading branch information
Guts committed Jun 28, 2021
2 parents 13ce5d8 + 56cc867 commit 989fc4d
Show file tree
Hide file tree
Showing 4 changed files with 223 additions and 19 deletions.
40 changes: 21 additions & 19 deletions roof_classify/roof_classify.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@
from sklearn.ensemble import RandomForestClassifier
from sklearn.svm import SVC

from roof_classify.__about__ import DIR_PLUGIN_ROOT, __title__
from roof_classify.toolbelt import PlgLogger

#creo un set di colori pseudocasuali da usare poi nella classificazione
COLORS = [
"#000000", "#FFFF00", "#1CE6FF", "#FF34FF", "#FF4A46", "#008941", "#006FA6", "#A30059",
Expand Down Expand Up @@ -94,6 +97,7 @@ def __init__(self, iface):
"""
# Save reference to the QGIS interface
self.iface = iface
self.log = PlgLogger().log
# initialize plugin directory
self.plugin_dir = os.path.dirname(__file__)
# initialize locale
Expand All @@ -119,10 +123,9 @@ def __init__(self, iface):
# Declare instance attributes
self.actions = []

self.menu = self.tr(u'&RoofClassify')
# TODO: We are going to let the user set this up in a future iteration
self.toolbar = self.iface.addToolBar(u'RoofClassify')
self.toolbar.setObjectName(u'RoofClassify')
self.menu = __title__
self.toolbar = self.iface.addToolBar(__title__)
self.toolbar.setObjectName(__title__)

self.dlg.lineEdit.clear()
self.dlg.pushButton.clicked.connect(self.select_raster)
Expand All @@ -145,8 +148,7 @@ def tr(self, message):
:returns: Translated version of message.
:rtype: QString
"""
# noinspection PyTypeChecker,PyArgumentList,PyCallByClass
return QCoreApplication.translate('RoofClassify', message)
return QCoreApplication.translate(__title__, message)


def add_action(
Expand Down Expand Up @@ -199,7 +201,7 @@ def add_action(
:rtype: QAction
"""

icon = QIcon(icon_path) #cambiare icon_path se si vuole cambiare l'icona del plugin
icon = QIcon(icon_path)
action = QAction(icon, text, parent)
action.triggered.connect(callback)
action.setEnabled(enabled_flag)
Expand All @@ -225,7 +227,7 @@ def add_action(
def initGui(self):
"""Create the menu entries and toolbar icons inside the QGIS GUI."""

icon_path = ':/plugins/RoofClassify/icon.png'
icon_path = str(DIR_PLUGIN_ROOT / "resources/images/icon.png")
self.add_action(
icon_path,
text=self.tr(u'classify roofs'),
Expand All @@ -237,7 +239,7 @@ def unload(self):
"""Removes the plugin menu item and icon from QGIS GUI."""
for action in self.actions:
self.iface.removePluginMenu(
self.tr(u'&RoofClassify'),
__title__,
action)
self.iface.removeToolBarIcon(action)
# remove the toolbar
Expand Down Expand Up @@ -297,7 +299,7 @@ def create_mask_from_vector(vector_data_path, cols, rows, geo_transform, project
"""
data_source = gdal.OpenEx(vector_data_path, gdal.OF_VECTOR)
if data_source is None:
report_and_exit("File read failed: %s", vector_data_path)
self.log(message=f"File read failed: {vector_data_path}", log_level=2, push=True)
layer = data_source.GetLayer(0)
driver = gdal.GetDriverByName(dataset_format)
target_ds = driver.Create(output_fname, cols, rows, 1, gdal.GDT_UInt16)
Expand Down Expand Up @@ -382,15 +384,15 @@ def write_geotiff(fname, data, geo_transform, projection, data_type=gdal.GDT_Byt



print(self.dlg.lineEdit.text())
print(self.dlg.lineEdit_2.text())
self.log(self.dlg.lineEdit.text())
self.log(self.dlg.lineEdit_2.text())
#rasterIn=self.dlg.lineEdit.text()
directory_raster=self.dlg.lineEdit.text()
directory_shape=self.dlg.lineEdit_2.text()
raster_training=self.dlg.lineEdit_3.text()
#log = open("D:/AMIANTO/output/log.txt", "w")
os.chdir(directory_raster)
print(raster_training)
self.log(raster_training)
#log.write(time.strftime("%Y-%m-%d %H:%M"))
#log.write("caricamento training set..\n")
out_folder=self.dlg.lineEdit_4.text()
Expand All @@ -402,11 +404,11 @@ def write_geotiff(fname, data, geo_transform, projection, data_type=gdal.GDT_Byt

nnn=1
for file in glob.glob("*.tif"):
print(file)
self.log(file)
#raster_dataset2 = gdal.Open("C:/Users/Alessandro/Desktop/11-10/ViaToscanaTestRitagliato.tif", gdal.GA_ReadOnly)

x=directory_raster+'/'+file
print(x)
self.log(x)
raster_dataset2 = gdal.Open(x, gdal.GA_ReadOnly)


Expand Down Expand Up @@ -444,7 +446,7 @@ def write_geotiff(fname, data, geo_transform, projection, data_type=gdal.GDT_Byt
files = [f for f in os.listdir(directory_shape) if f.endswith('.shp')]

classes = [f.split('.')[0] for f in files]
print(classes)
self.log(str(classes))
shapefiles = [os.path.join(directory_shape, f) for f in files if f.endswith('.shp')]
labeled_pixels = vectors_to_raster(shapefiles, rows, cols, geo_transform, proj)
is_train = np.nonzero(labeled_pixels)
Expand All @@ -470,7 +472,7 @@ def write_geotiff(fname, data, geo_transform, projection, data_type=gdal.GDT_Byt
classification = result.reshape((rows2, cols2))
file=file.replace(".tif","")
name=out_folder+"\\"+file+"_classificato.tif"
print(name)
self.log(name)
write_geotiff(name, classification, geo_transform2, proj2)
nnn=nnn+1
nomi = nomi + " " + name
Expand All @@ -481,8 +483,8 @@ def write_geotiff(fname, data, geo_transform, projection, data_type=gdal.GDT_Byt
subprocess.call("gdal_merge.bat -ot UInt16 -pct -o "+dove+" -of GTiff " + nomi)

if self.dlg.checkBox.isChecked():
print("ciao")
self.log("ciao")
#inserire codice che crea shape conteggio
if self.dlg.checkBox_2.isChecked():
print("ciao2")
self.log("ciao2")
#inserire codice che crea shape percentuale
3 changes: 3 additions & 0 deletions roof_classify/toolbelt/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#! python3 # noqa: E265
from .log_handler import PlgLogger # noqa: F401
from .preferences import PlgOptionsManager # noqa: F401
83 changes: 83 additions & 0 deletions roof_classify/toolbelt/log_handler.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
#! python3 # noqa: E265

# standard library
import logging

# PyQGIS
from qgis.core import QgsMessageLog
from qgis.utils import iface

# project package
import roof_classify.toolbelt.preferences as plg_prefs_hdlr
from roof_classify.__about__ import __title__

# ############################################################################
# ########## Classes ###############
# ##################################


class PlgLogger(logging.Handler):
"""Python logging handler supercharged with QGIS useful methods."""

@staticmethod
def log(
message: str,
application: str = __title__,
log_level: int = 0,
push: bool = False,
):
"""Send messages to QGIS messages windows and to the user as a message bar. \
Plugin name is used as title. If debug mode is disabled, only warnings (1) and \
errors (2) or with push are sent.
:param message: message to display
:type message: str
:param application: name of the application sending the message. \
Defaults to __about__.__title__
:type application: str, optional
:param log_level: message level. Possible values: 0 (info), 1 (warning), \
2 (critical), 3 (success), 4 (none - grey). Defaults to 0 (info)
:type log_level: int, optional
:param push: also display the message in the QGIS message bar in addition to \
the log, defaults to False
:type push: bool, optional
:Example:
.. code-block:: python
log(message="Plugin loaded - INFO", log_level=0, push=1)
log(message="Plugin loaded - WARNING", log_level=1, push=1)
log(message="Plugin loaded - ERROR", log_level=2, push=1)
log(message="Plugin loaded - SUCCESS", log_level=3, push=1)
log(message="Plugin loaded - TEST", log_level=4, push=1)
"""
# if debug mode, let's ignore INFO, SUCCESS and TEST
debug_mode = plg_prefs_hdlr.PlgOptionsManager.get_plg_settings().debug_mode
if not debug_mode and (1 < log_level < 3 or not push):
return

# ensure message is a string
if not isinstance(message, str):
try:
message = str(message)
except Exception as err:
err_msg = "Log message must be a string, not: {}. Trace: {}".format(
type(message), err
)
logging.error(err_msg)
message = err_msg

# send it to QGIS messages panel
QgsMessageLog.logMessage(
message=message, tag=application, notifyUser=push, level=log_level
)

# optionally, display message on QGIS Message bar (above the map canvas)
if push:
iface.messageBar().pushMessage(
title=application,
text=message,
level=log_level,
duration=(log_level + 1) * 3,
)
116 changes: 116 additions & 0 deletions roof_classify/toolbelt/preferences.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
#! python3 # noqa: E265

"""
Plugin settings.
"""

# standard
from typing import NamedTuple

# PyQGIS
from qgis.core import QgsSettings

# package
import roof_classify.toolbelt.log_handler as log_hdlr
from roof_classify.__about__ import __title__, __version__

# ############################################################################
# ########## Classes ###############
# ##################################


class PlgSettingsStructure(NamedTuple):
"""Plugin settings structure and defaults values."""

# misc
debug_mode: bool = False
version: str = __version__

class PlgOptionsManager:
@staticmethod
def get_plg_settings() -> PlgSettingsStructure:
"""Load and return plugin settings as a dictionary. \
Useful to get user preferences across plugin logic.
:return: plugin settings
:rtype: PlgSettingsStructure
"""
settings = QgsSettings()
settings.beginGroup(__title__)

options = PlgSettingsStructure(
# misc
debug_mode=settings.value(key="debug_mode", defaultValue=False, type=bool),
version=settings.value(key="version", defaultValue=__version__, type=str),
)

settings.endGroup()

return options

@staticmethod
def get_value_from_key(key: str, default=None, exp_type=None):
"""Load and return plugin settings as a dictionary. \
Useful to get user preferences across plugin logic.
:return: plugin settings value matching key
"""
if not hasattr(PlgSettingsStructure, key):
log_hdlr.PlgLogger.log(
message="Bad settings key. Must be one of: {}".format(
",".join(PlgSettingsStructure._fields)
),
log_level=1,
)
return None

settings = QgsSettings()
settings.beginGroup(__title__)

try:
out_value = settings.value(key=key, defaultValue=default, type=exp_type)
except Exception as err:
log_hdlr.PlgLogger.log(
message="Error occurred trying to get settings: {}.Trace: {}".format(
key, err
)
)
out_value = None

settings.endGroup()

return out_value

@staticmethod
def set_value_from_key(key: str, value):
"""Load and return plugin settings as a dictionary. \
Useful to get user preferences across plugin logic.
:return: plugin settings value matching key
"""
if not hasattr(PlgSettingsStructure, key):
log_hdlr.PlgLogger.log(
message="Bad settings key. Must be one of: {}".format(
",".join(PlgSettingsStructure._fields)
),
log_level=2,
)
return False

settings = QgsSettings()
settings.beginGroup(__title__)

try:
settings.setValue(key, value)
out_value = True
except Exception as err:
log_hdlr.PlgLogger.log(
message="Error occurred trying to set settings: {}.Trace: {}".format(
key, err
)
)
out_value = False

settings.endGroup()

return out_value

0 comments on commit 989fc4d

Please sign in to comment.