diff --git a/plugins/filter_collection/__init__.py b/plugins/filter_collection/__init__.py index 4b95114..b826e77 100644 --- a/plugins/filter_collection/__init__.py +++ b/plugins/filter_collection/__init__.py @@ -1,5 +1,5 @@ from misc import Register -FILTER = Register('filter') +FILTER = Register('滤波处理算法') from filter_collection.main import * \ No newline at end of file diff --git a/plugins/follow/__init__.py b/plugins/follow/__init__.py new file mode 100644 index 0000000..388f667 --- /dev/null +++ b/plugins/follow/__init__.py @@ -0,0 +1,5 @@ +from misc import Register + +FOLLOW = Register('流程') + +from follow.main import * \ No newline at end of file diff --git a/plugins/follow/main.py b/plugins/follow/main.py new file mode 100644 index 0000000..784ee7e --- /dev/null +++ b/plugins/follow/main.py @@ -0,0 +1,163 @@ +from threading import Thread +from rscder.plugins.basic import BasicPlugin +from rscder.utils.icons import IconInstance +from rscder.gui.actions import ActionManager +from PyQt5 import QtWidgets, QtGui +from follow import FOLLOW +from misc import AlgFrontend + +class FollowDialog(QtWidgets.QDialog): + + def __init__(self, parent=None, alg:AlgFrontend=None) -> None: + super().__init__(parent) + if alg is None: + return + self.setMinimumWidth(700) + # self.setMinimumHeight(500) + vbox = QtWidgets.QVBoxLayout() + + self.widget = alg.get_widget(self) + vbox.addWidget(self.widget) + + self.ok_button = QtWidgets.QPushButton('确定', self) + self.ok_button.setIcon(IconInstance().OK) + self.ok_button.clicked.connect(self.accept) + self.ok_button.setDefault(True) + + self.cancel_button = QtWidgets.QPushButton('取消', self) + self.cancel_button.setIcon(IconInstance().CANCEL) + self.cancel_button.clicked.connect(self.reject) + self.cancel_button.setDefault(False) + buttonbox= QtWidgets.QDialogButtonBox() + buttonbox.addButton(self.ok_button,QtWidgets.QDialogButtonBox.NoRole) + buttonbox.addButton(self.cancel_button,QtWidgets.QDialogButtonBox.NoRole) + buttonbox.setCenterButtons(True) + + vbox.addWidget(buttonbox) + vbox.addStretch() + + self.setLayout(vbox) + +class FollowPlugin(BasicPlugin): + + @staticmethod + def get_info(): + return { + 'name': 'Follow', + 'version': '1.0.0' + } + + + def set_action(self): + follow_box:QtWidgets.QWidget = ActionManager().follow_box + toolbar = ActionManager().add_toolbar('Follow') + vbox = QtWidgets.QVBoxLayout(follow_box) + + combox = QtWidgets.QComboBox(follow_box) + + # print(FOLLOW.keys()) + for key in FOLLOW.keys(): + alg:AlgFrontend = FOLLOW[key] + if alg.get_name() is None: + name = key + else: + name = alg.get_name() + combox.addItem(name, key) + + action = QtWidgets.QAction(alg.get_icon(), name, self.mainwindow) + action.triggered.connect(lambda : self.run_dialog(alg)) + toolbar.addAction(action) + + + combox.currentIndexChanged.connect(self.on_change) + + vbox.addWidget(combox) + + self.current_widget = None + + + self.combox = combox + self.layout = vbox + + self.ok_button = QtWidgets.QPushButton('运行') + self.ok_button.setIcon(IconInstance().OK) + self.ok_button.clicked.connect(self.run) + self.ok_button.setDefault(True) + + self.cancel_button = QtWidgets.QPushButton('重置') + self.cancel_button.setIcon(IconInstance().CANCEL) + self.cancel_button.clicked.connect(self.reset) + self.cancel_button.setDefault(False) + buttonbox= QtWidgets.QDialogButtonBox() + buttonbox.addButton(self.ok_button,QtWidgets.QDialogButtonBox.NoRole) + buttonbox.addButton(self.cancel_button,QtWidgets.QDialogButtonBox.NoRole) + buttonbox.setCenterButtons(True) + + self.btn_box = buttonbox + follow_box.setLayout(vbox) + # vbox.addStretch() + self.on_change(0) + + def on_change(self, index): + + print(self.combox.currentData()) + if self.current_widget is not None: + self.current_widget.setParent(None) + self.btn_box.setParent(None) + self.layout.removeWidget(self.current_widget) + self.layout.removeWidget(self.btn_box) + self.current_widget = None + + alg:AlgFrontend = FOLLOW[self.combox.currentData()] + + if alg.get_widget() is None: + return + + self.current_widget = alg.get_widget(ActionManager().follow_box) + self.layout.addWidget(self.current_widget) + self.layout.addWidget(self.btn_box) + + + def run(self): + alg:AlgFrontend = FOLLOW[self.combox.currentData()] + + if alg is None: + return + + params = alg.get_params(self.current_widget) + + t = Thread(target=self.run_alg, args=(params,)) + t.start() + + def run_dialog(self, alg:AlgFrontend): + + dialog = FollowDialog(self.mainwindow, alg) + dialog.show() + + if dialog.exec_() == QtWidgets.QDialog.Accepted: + + params = alg.get_params(dialog.widget) + + t = Thread(target=self.run_alg, args = (params,)) + t.start() + + + def run_alg(self, alg:AlgFrontend, p): + + alg.run_alg(**p, send_message=self.send_message) + + def reset(self): + + if self.current_widget is None: + return + self.current_widget.setParent(None) + self.btn_box.setParent(None) + self.layout.removeWidget(self.current_widget) + self.layout.removeWidget(self.btn_box) + + self.current_widget = FOLLOW[self.combox.currentData()].get_widget(ActionManager().follow_box) + + self.layout.addWidget(self.current_widget) + self.layout.addLayout(self.btn_box) + + \ No newline at end of file diff --git a/plugins/misc/main.py b/plugins/misc/main.py index 6990ebc..cd4ba61 100644 --- a/plugins/misc/main.py +++ b/plugins/misc/main.py @@ -1,7 +1,7 @@ from threading import Thread from plugins.misc.utils import Register from rscder.plugins.basic import BasicPlugin -from PyQt5.QtWidgets import QWidget, QComboBox, QVBoxLayout +from PyQt5.QtWidgets import QGroupBox, QWidget, QComboBox, QVBoxLayout class MISCPlugin(BasicPlugin): @@ -25,6 +25,10 @@ class AlgFrontend(object): def get_name(): return None + @staticmethod + def get_icon(): + return None + @staticmethod def get_widget(parent=None): return QWidget(parent) @@ -38,14 +42,14 @@ class AlgFrontend(object): pass -class AlgSelectWidget(QWidget): +class AlgSelectWidget(QGroupBox): def __init__(self, parent= None, registery:Register = None) -> None: super().__init__(parent) self.reg = registery if registery is None: return - + self.setTitle(registery.name) self.selectbox = QComboBox(self) self.selectbox.addItem('--', None) for key in self.reg.keys(): @@ -59,20 +63,28 @@ class AlgSelectWidget(QWidget): self.vbox = QVBoxLayout(self) self.vbox.addWidget(self.selectbox) - self.params_widget = QWidget(self) + self.params_widget = QWidget() self.vbox.addWidget(self.params_widget) self.selectbox.currentIndexChanged.connect(self.on_changed) def on_changed(self, index): if index == 0: + self.alg = None + self.params_widget.setParent(None) + self.vbox.removeWidget(self.params_widget) + self.params_widget = QWidget(self) + self.vbox.addWidget(self.params_widget) return self.alg:AlgFrontend = self.reg[self.selectbox.itemData(index)] + self.params_widget.setParent(None) self.vbox.removeWidget(self.params_widget) self.params_widget = self.alg.get_widget(self) self.vbox.addWidget(self.params_widget) + + def get_alg_and_params(self): if self.selectbox.currentIndex() == 0: return None, None diff --git a/plugins/misc/utils.py b/plugins/misc/utils.py index 8b592e4..311f457 100644 --- a/plugins/misc/utils.py +++ b/plugins/misc/utils.py @@ -9,6 +9,10 @@ class Register: self._dict = {} self._name = registry_name + @property + def name(self): + return self._name + def __setitem__(self, key, value): if not callable(value): raise Exception(f"Value of a Registry must be a callable!\nValue: {value}") diff --git a/plugins/plugins.yaml b/plugins/plugins.yaml index 169900e..315ad5a 100644 --- a/plugins/plugins.yaml +++ b/plugins/plugins.yaml @@ -39,4 +39,11 @@ module: change_rate name: set_change_rate path: ./plugin\change_rate + version: 1.0.0 +- author: RSCDER + description: Follow box + enabled: true + module: follow + name: FollowPlugin + path: ./plugin\follow version: 1.0.0 \ No newline at end of file diff --git a/plugins/thres/__init__.py b/plugins/thres/__init__.py index 8ab0e4c..b5bcc0b 100644 --- a/plugins/thres/__init__.py +++ b/plugins/thres/__init__.py @@ -1,5 +1,5 @@ from misc import Register -THRES = Register('Thres') +THRES = Register('阈值方法') from thres.main import * \ No newline at end of file diff --git a/plugins/unsupervised_method/main.py b/plugins/unsupervised_method/main.py index a398a2e..ca3f623 100644 --- a/plugins/unsupervised_method/main.py +++ b/plugins/unsupervised_method/main.py @@ -10,6 +10,7 @@ from filter_collection import FILTER from .scripts import UNSUPER_CD from thres import THRES from misc import table_layer, AlgSelectWidget +from follow import FOLLOW class UnsupervisedCDMethod(QDialog): def __init__(self,parent=None, alg:AlgFrontend=None): @@ -51,52 +52,112 @@ class UnsupervisedCDMethod(QDialog): if self.param_widget is not None: totalvlayout.addWidget(self.param_widget) totalvlayout.addWidget(self.thres_select) - totalvlayout.addWidget(buttonbox) - totalvlayout.addStretch() + totalvlayout.addStretch(1) + hbox = QHBoxLayout() + hbox.addStretch(1) + hbox.addWidget(buttonbox) + totalvlayout.addLayout(hbox) + # totalvlayout.addStretch() self.setLayout(totalvlayout) -class UnsupervisedCD(QDialog): - def __init__(self,parent=None): - super(UnsupervisedCD, self).__init__(parent) - self.setWindowTitle('无监督变化检测') - self.setWindowIcon(IconInstance().LOGO) - self.setMinimumWidth(600) - self.initUI() +@FOLLOW.register +class UnsupervisedCDFollow(AlgFrontend): - def initUI(self): - #图层 - self.layer_combox = PairLayerCombox(self) - layerbox = QHBoxLayout() - layerbox.addWidget(self.layer_combox) + @staticmethod + def get_name(): + return '无监督变化检测' + + @staticmethod + def get_icon(): + return IconInstance().UNSUPERVISED + + @staticmethod + def get_widget(parent=None): + widget = QWidget(parent) + layer_combox = PairLayerCombox(widget) + layer_combox.setObjectName('layer_combox') - self.filter_select = AlgSelectWidget(self, FILTER) - self.unsupervised_select = AlgSelectWidget(self, UNSUPER_CD) - self.thres_select = AlgSelectWidget(self, THRES) - - self.ok_button = QPushButton('确定', self) - self.ok_button.setIcon(IconInstance().OK) - self.ok_button.clicked.connect(self.accept) - self.ok_button.setDefault(True) - - self.cancel_button = QPushButton('取消', self) - self.cancel_button.setIcon(IconInstance().CANCEL) - self.cancel_button.clicked.connect(self.reject) - self.cancel_button.setDefault(False) - buttonbox=QDialogButtonBox(self) - buttonbox.addButton(self.ok_button,QDialogButtonBox.NoRole) - buttonbox.addButton(self.cancel_button,QDialogButtonBox.NoRole) - buttonbox.setCenterButtons(True) + filter_select = AlgSelectWidget(widget, FILTER) + filter_select.setObjectName('filter_select') + unsupervised_select = AlgSelectWidget(widget, UNSUPER_CD) + unsupervised_select.setObjectName('unsupervised_select') + thres_select = AlgSelectWidget(widget, THRES) + thres_select.setObjectName('thres_select') totalvlayout=QVBoxLayout() - totalvlayout.addLayout(layerbox) - totalvlayout.addWidget(self.filter_select) - totalvlayout.addWidget(self.unsupervised_select) - totalvlayout.addWidget(self.thres_select) - totalvlayout.addWidget(buttonbox) + totalvlayout.addWidget(layer_combox) + totalvlayout.addWidget(filter_select) + totalvlayout.addWidget(unsupervised_select) + totalvlayout.addWidget(thres_select) totalvlayout.addStretch() - self.setLayout(totalvlayout) + widget.setLayout(totalvlayout) + + return widget + + @staticmethod + def get_params(widget:QWidget=None): + if widget is None: + return dict() + + layer_combox = widget.findChild(PairLayerCombox, 'layer_combox') + filter_select = widget.findChild(AlgSelectWidget, 'filter_select') + unsupervised_select = widget.findChild(AlgSelectWidget, 'unsupervised_select') + thres_select = widget.findChild(AlgSelectWidget, 'thres_select') + + layer1=layer_combox.layer1 + pth1 = layer_combox.layer1.path + pth2 = layer_combox.layer2.path + + falg, fparams = filter_select.get_alg_and_params() + cdalg, cdparams = unsupervised_select.get_alg_and_params() + thalg, thparams = thres_select.get_alg_and_params() + + if cdalg is None or thalg is None: + return dict() + + return dict( + layer1=layer1, + pth1 = pth1, + pth2 = pth2, + falg = falg, + fparams = fparams, + cdalg = cdalg, + cdparams = cdparams, + thalg = thalg, + thparams = thparams, + ) + + @staticmethod + def run_alg(layer1=None, + pth1 = None, + pth2 = None, + falg = None, + fparams = None, + cdalg = None, + cdparams = None, + thalg = None, + thparams = None, + send_message = None): + + if cdalg is None or thalg is None: + return + + name = layer1.name + + if falg is not None: + pth1 = falg.run_alg(pth1, name=name, send_message= send_message, **fparams) + pth2 = falg.run_alg(pth2, name=name, send_message= send_message, **fparams) + + + cdpth = cdalg.run_alg(pth1, pth2, layer1.layer_parent, send_message= send_message,**cdparams) + + + thpth = thalg.run_alg(cdpth, name=name, send_message= send_message, **thparams) + + table_layer(thpth,layer1,name, send_message) + @@ -116,12 +177,7 @@ class UnsupervisedPlugin(BasicPlugin): unsupervised_menu = QMenu('&无监督变化检测', self.mainwindow) unsupervised_menu.setIcon(IconInstance().UNSUPERVISED) ActionManager().change_detection_menu.addMenu(unsupervised_menu) - basic_diff_method_in_one = QAction(IconInstance().UNSUPERVISED, '&无监督变化检测', self.mainwindow) - basic_diff_method_in_one.triggered.connect(self.run) - toolbar:QToolBar = ActionManager().add_toolbar('无监督变化检测') - toolbar.addAction(basic_diff_method_in_one) - # self.mainwindow.addToolbar(toolbar) - # print(UNSUPER_CD.keys()) + for key in UNSUPER_CD.keys(): alg:AlgFrontend = UNSUPER_CD[key] if alg.get_name() is None: @@ -134,13 +190,6 @@ class UnsupervisedPlugin(BasicPlugin): unsupervised_menu.addAction(action) - def run(self): - myDialog= UnsupervisedCD(self.mainwindow) - myDialog.show() - if myDialog.exec_()==QDialog.Accepted: - w=myDialog - t=Thread(target=self.run_alg,args=(w,)) - t.start() def run_cd(self, alg): dialog = UnsupervisedCDMethod(self.mainwindow, alg) @@ -174,29 +223,4 @@ class UnsupervisedPlugin(BasicPlugin): thpth = thalg.run_alg(cdpth, name=name, send_message=self.send_message, **thparams) table_layer(thpth,layer1,name,self.send_message) - - def run_alg(self,w:UnsupervisedCD): - - layer1=w.layer_combox.layer1 - pth1 = w.layer_combox.layer1.path - pth2 = w.layer_combox.layer2.path - name = layer1.layer_parent.name - - falg, fparams = w.filter_select.get_alg_and_params() - cdalg, cdparams = w.unsupervised_select.get_alg_and_params() - thalg, thparams = w.thres_select.get_alg_and_params() - - if cdalg is None or thalg is None: - return - - if falg is not None: - pth1 = falg.run_alg(pth1, name=name, send_message=self.send_message, **fparams) - pth2 = falg.run_alg(pth2, name=name, send_message=self.send_message, **fparams) - - - cdpth = cdalg.run_alg(pth1, pth2, layer1.layer_parent, send_message=self.send_message,**cdparams) - - - thpth = thalg.run_alg(cdpth, name=name, send_message=self.send_message, **thparams) - - table_layer(thpth,layer1,name,self.send_message) \ No newline at end of file + \ No newline at end of file diff --git a/plugins/unsupervised_method/scripts/__init__.py b/plugins/unsupervised_method/scripts/__init__.py index f85a810..f0fe433 100644 --- a/plugins/unsupervised_method/scripts/__init__.py +++ b/plugins/unsupervised_method/scripts/__init__.py @@ -8,7 +8,7 @@ from rscder.utils.geomath import geo2imageRC, imageRC2geo from rscder.utils.project import Project, PairLayer from misc import Register, AlgFrontend -UNSUPER_CD = Register('unsuper cd') +UNSUPER_CD = Register('无监督变化检测方法') import numpy as np from .ACD import ACD @@ -153,8 +153,10 @@ class LSTS(AlgFrontend): widget = QtWidgets.QWidget(parent) + return widget - def get_params(self): + @staticmethod + def get_params(widget=None): return dict(n=5, w_size=(3,3)) @staticmethod diff --git a/rscder/gui/actions.py b/rscder/gui/actions.py index 19a584d..c524810 100644 --- a/rscder/gui/actions.py +++ b/rscder/gui/actions.py @@ -3,7 +3,7 @@ import os from pathlib import Path from PyQt5 import QtCore, QtGui, QtWidgets from PyQt5.QtCore import Qt, QSize, QSettings, pyqtSignal -from PyQt5.QtWidgets import QAction, QActionGroup, QLabel, QFileDialog, QMenuBar, QToolBar +from PyQt5.QtWidgets import QAction, QActionGroup, QLabel, QFileDialog, QMenuBar, QToolBar, QVBoxLayout, QComboBox from rscder.gui import project from rscder.gui.project import Create from rscder.utils.icons import IconInstance @@ -76,6 +76,12 @@ class ActionManager(QtCore.QObject): self.plugin_menu = menubar.addMenu('&插件') self.help_menu = menubar.addMenu( '&帮助') + # vbox = QVBoxLayout() + # follow_combox = QComboBox(self.follow_box) + # vbox.addWidget(follow_combox) + # self.follow_box.setLayout(vbox) + + def set_toolbar(self, toolbar): self.toolbar:QToolBar = toolbar self.toolbar.setIconSize(QtCore.QSize(24, 24)) diff --git a/rscder/gui/layercombox.py b/rscder/gui/layercombox.py index 00e75af..3450221 100644 --- a/rscder/gui/layercombox.py +++ b/rscder/gui/layercombox.py @@ -1,5 +1,6 @@ from PyQt5.QtWidgets import QComboBox, QWidget, QLabel, QHBoxLayout, QVBoxLayout from PyQt5.QtGui import QIcon +from PyQt5.QtCore import Qt from rscder.utils.icons import IconInstance from rscder.utils.project import PairLayer, Project, RasterLayer, ResultPointLayer,SingleBandRasterLayer class LayerCombox(QComboBox): @@ -35,8 +36,9 @@ class PairLayerCombox(QWidget): layer_label = QLabel('图层组:') hbox = QHBoxLayout() + hbox.setAlignment(Qt.AlignLeft) hbox.addWidget(layer_label) - hbox.addWidget(self.layer_combox) + hbox.addWidget(self.layer_combox, 2) self.raster_layer1 = QComboBox(self) self.raster_layer1.addItem('---', None) @@ -50,13 +52,14 @@ class PairLayerCombox(QWidget): self.layer_combox.currentIndexChanged.connect(self.on_group_changed) hbox1 = QHBoxLayout() - + hbox1.setAlignment(Qt.AlignLeft) hbox1.addWidget(QLabel('时相1:')) - hbox1.addWidget(self.raster_layer1) + hbox1.addWidget(self.raster_layer1, 2) hbox2 = QHBoxLayout() + hbox2.setAlignment(Qt.AlignLeft) hbox2.addWidget(QLabel('时相2:')) - hbox2.addWidget(self.raster_layer2) + hbox2.addWidget(self.raster_layer2, 2) vbox = QVBoxLayout() vbox.addLayout(hbox)