diff --git a/run.py b/RSCDer.py
similarity index 100%
rename from run.py
rename to RSCDer.py
diff --git a/build.bat b/build.bat
index 85084c1..7aea222 100644
--- a/build.bat
+++ b/build.bat
@@ -1,4 +1,5 @@
-nuitka run.py --standalone --plugin-enable=qt-plugins --plugin-enable=numpy --show-progress --include-package=qgis --plugin-enable=pylint-warnings --output-dir=package --windows-disable-console --windows-icon-from-ico=logo.ico --no-pyi-file
+nuitka RSCDer.py --standalone --plugin-enable=qt-plugins --plugin-enable=numpy --show-progress --include-package=qgis --plugin-enable=pylint-warnings --output-dir=package --windows-disable-console --windows-icon-from-ico=logo.ico --no-pyi-file
+@REM nuitka keygen.py --standalone --plugin-enable=qt-plugins --plugin-enable=numpy --show-progress --include-package=qgis --plugin-enable=pylint-warnings --output-dir=package --windows-disable-console --windows-icon-from-ico=logo.ico --no-pyi-file
REM Win7 with console
diff --git a/icons/logo.png b/icons/logo.png
new file mode 100644
index 0000000..79985f3
Binary files /dev/null and b/icons/logo.png differ
diff --git a/icons/splash.png b/icons/splash.png
index 82266d9..5b17fa0 100644
Binary files a/icons/splash.png and b/icons/splash.png differ
diff --git a/keygen.py b/keygen.py
new file mode 100644
index 0000000..c6ed530
--- /dev/null
+++ b/keygen.py
@@ -0,0 +1,9 @@
+from rscder.gui.keygen import LicenseGen
+from PyQt5.QtWidgets import QApplication
+import sys
+
+if __name__ == "__main__":
+ app =QApplication(sys.argv)
+ license = LicenseGen()
+ license.show()
+ sys.exit(app.exec_())
\ No newline at end of file
diff --git a/lic/license.lic b/lic/license.lic
index 175477c..02a42fd 100644
--- a/lic/license.lic
+++ b/lic/license.lic
@@ -1 +1 @@
-pGZJMmJtule8fwDCz4mnyHoQa7N6pl5GRdLqfoXREBqG4Xb1jbvgf7RmC8f1+sNpiCFSIt7NgvU362tKhB5UBXn/vUAadG1lOGC70dUhprGzBoqJN7VkAHkNGg0XjoE8H0SCVynr8To7ciwcnmK6HJXre6i+mBdTjACmKseTMlWp480XOt7uHysltORbTA3J
\ No newline at end of file
+IieXktda+1nRK9zLwe87uPPn2VpCwmUrEOPfyenaW/Sek70/CqqbCr7nangL1+pVXSkzDELia7Qq8e+pDMuHCXzxyJOALRj4j3bhFVExwqSTLuXwdev1e26nr7vnECl7H0SCVynr8To7ciwcnmK6HJXre6i+mBdTjACmKseTMlWp480XOt7uHysltORbTA3J
\ No newline at end of file
diff --git a/lic_t.lic b/lic_t.lic
new file mode 100644
index 0000000..02a42fd
--- /dev/null
+++ b/lic_t.lic
@@ -0,0 +1 @@
+IieXktda+1nRK9zLwe87uPPn2VpCwmUrEOPfyenaW/Sek70/CqqbCr7nangL1+pVXSkzDELia7Qq8e+pDMuHCXzxyJOALRj4j3bhFVExwqSTLuXwdev1e26nr7vnECl7H0SCVynr8To7ciwcnmK6HJXre6i+mBdTjACmKseTMlWp480XOt7uHysltORbTA3J
\ No newline at end of file
diff --git a/logo.ico b/logo.ico
index a468498..d41874a 100644
Binary files a/logo.ico and b/logo.ico differ
diff --git a/plugins/about/main.py b/plugins/about/main.py
index a6e0e4e..0847560 100644
--- a/plugins/about/main.py
+++ b/plugins/about/main.py
@@ -63,6 +63,6 @@ class AboutPlugin(BasicPlugin):
menu.addAction(action)
def on_about(self):
- print('on_about')
+ # print('on_about')
dialog = AboutDialog(self.ctx['mainwindow'])
dialog.show()
\ No newline at end of file
diff --git a/plugins/basic_change/main.py b/plugins/basic_change/main.py
index c206c33..f111d0a 100644
--- a/plugins/basic_change/main.py
+++ b/plugins/basic_change/main.py
@@ -10,7 +10,7 @@ from rscder.gui.layercombox import LayerCombox
from osgeo import gdal, gdal_array
from threading import Thread
import numpy as np
-
+from basic_change.otsu import OTSU
class MyDialog(QDialog):
def __init__(self, parent=None):
@@ -154,7 +154,7 @@ class BasicMethod(BasicPlugin):
out_normal_tif = os.path.join(out, 'diff_0_255.tif')
out_normal_ds = driver.Create(out_normal_tif, xsize, ysize, 1, gdal.GDT_Byte)
-
+ hist = np.zeros(256, dtype=np.int32)
for j in range(yblocks):
block_xy = (0, j * cell_size[1])
block_size = (xsize, cell_size[1])
@@ -164,7 +164,13 @@ class BasicMethod(BasicPlugin):
block_data = (block_data - min_diff) / (max_diff - min_diff) * 255
block_data = block_data.astype(np.uint8)
out_normal_ds.GetRasterBand(1).WriteArray(block_data, *block_xy)
+ hist_t, _ = np.histogram(block_data, bins=256)
+ hist += hist_t
+ self.gap = OTSU(hist)
+
+ self.message_send.emit('OTSU:' + str(self.gap))
+
out_normal_ds.FlushCache()
del out_normal_ds
self.message_send.emit('完成归一化概率')
@@ -194,7 +200,7 @@ class BasicMethod(BasicPlugin):
center_y = j * cell_size[1] + cell_size[1] // 2
center_x = center_x * geo[1] + geo [0]
center_y = center_y * geo[5] + geo [3]
- f.write(f'{center_x},{center_y},{block_data_xy.mean() / 255},1\n')
+ f.write(f'{center_x},{center_y},{block_data_xy.mean() / 255 * 100},1\n')
self.result_ok.emit({
diff --git a/plugins/export_to/__init__.py b/plugins/export_to/__init__.py
new file mode 100644
index 0000000..00be9b3
--- /dev/null
+++ b/plugins/export_to/__init__.py
@@ -0,0 +1 @@
+from export_to.main import *
\ No newline at end of file
diff --git a/plugins/export_to/main.py b/plugins/export_to/main.py
new file mode 100644
index 0000000..90f7558
--- /dev/null
+++ b/plugins/export_to/main.py
@@ -0,0 +1,100 @@
+import shutil
+from rscder.utils.project import Project, PairLayer, ResultLayer
+from rscder.plugins.basic import BasicPlugin
+from PyQt5.QtWidgets import QDialog, QHBoxLayout, QFileDialog, QComboBox, QVBoxLayout, QPushButton, QLabel, QLineEdit, QAction
+from PyQt5.QtGui import QIcon
+class ExportDialog(QDialog):
+
+ def __init__(self, parent=None):
+ super().__init__(parent)
+
+ self.setWindowTitle('Export')
+ self.setWindowIcon(QIcon(":/icons/logo.png"))
+
+ self.out_path = None
+ self.result_layer = None
+
+ result_layer_select_label = QLabel('选择结果:')
+
+ result_layer_select = QComboBox(self)
+
+ result_layer_select.addItem('---', None)
+ for layer in Project().layers.values():
+ for result_layer in layer.results:
+ if result_layer.layer_type == ResultLayer.POINT:
+ result_layer_select.addItem( layer.name[5:] + '-' + result_layer.name, result_layer)
+
+ for i in range(result_layer_select.count() - 1):
+ result_layer_select.setItemIcon(i + 1, QIcon(":/icons/layer.png"))
+
+
+ def on_result_layer_select(index):
+ self.result_layer = result_layer_select.currentData()
+
+ result_layer_select.currentIndexChanged.connect(on_result_layer_select)
+
+ out_path_label = QLabel('输出路径:')
+ out_path_text = QLineEdit(self)
+ out_path_text.setReadOnly(True)
+ out_path_text.setPlaceholderText('选择输出路径')
+
+ def on_out_path_btn():
+ select_file = QFileDialog.getSaveFileName(self, '选择输出路径', '', '*.txt')
+ if select_file[0]:
+ out_path_text.setText(select_file[0])
+ self.out_path = select_file[0]
+ out_path_btn = QPushButton('...', self)
+ out_path_btn.clicked.connect(on_out_path_btn)
+
+ ok_btn = QPushButton('OK', self)
+ ok_btn.clicked.connect(self.accept)
+ cancel_btn = QPushButton('Cancel', self)
+ cancel_btn.clicked.connect(self.reject)
+
+
+ hbox1 = QHBoxLayout()
+ hbox1.addWidget(result_layer_select_label)
+ hbox1.addWidget(result_layer_select)
+
+ hbox2 = QHBoxLayout()
+ hbox2.addWidget(out_path_label)
+ hbox2.addWidget(out_path_text)
+ hbox2.addWidget(out_path_btn)
+
+ hbox3 = QHBoxLayout()
+ hbox3.addWidget(ok_btn)
+ hbox3.addWidget(cancel_btn)
+
+ vbox = QVBoxLayout()
+ vbox.addLayout(hbox1)
+ vbox.addLayout(hbox2)
+ vbox.addLayout(hbox3)
+
+ self.setLayout(vbox)
+
+class ExportPlugin(BasicPlugin):
+
+ @staticmethod
+ def info():
+ return {
+ 'name': 'Export',
+ 'description': 'Export to other format',
+ 'author': 'RSCDER',
+ }
+
+ def set_action(self):
+ self.export_txt = QAction(QIcon(":/icons/document.png"), '导出为 Arcgis 兼容的TXT', self.mainwindow)
+ self.export_txt.triggered.connect(self.export_txt_action)
+
+ self.ctx['postop_menu'].addAction(self.export_txt)
+
+ self.ctx['toolbar'].addAction(self.export_txt)
+
+ def export_txt_action(self):
+ dialog = ExportDialog(self.mainwindow)
+ if dialog.exec_():
+ result = dialog.result_layer
+ out = dialog.out_path
+ if result:
+ shutil.copy(result.path, out)
+ self.message_box.info('导出成功')
\ No newline at end of file
diff --git a/plugins/plugins.yaml b/plugins/plugins.yaml
index c94f978..11706d8 100644
--- a/plugins/plugins.yaml
+++ b/plugins/plugins.yaml
@@ -3,12 +3,19 @@
enabled: true
module: about
name: "\u5173\u4E8E"
- path: ./plugin-build\about
+ path: ./plugin\about
version: 1.0.0
- author: RSCDER
description: BasicMethod
enabled: true
module: basic_change
name: BasicMethod
- path: ./plugin-build\basic_change
+ path: ./plugin\basic_change
version: 1.0.0
+- author: RSCDER
+ description: ExportTo
+ enabled: true
+ module: export_to
+ name: ExportTo
+ path: ./plugin\export_to
+ version: 1.0.0
\ No newline at end of file
diff --git a/res.qrc b/res.qrc
index 5664d29..7bd32c7 100644
--- a/res.qrc
+++ b/res.qrc
@@ -28,7 +28,7 @@
icons\zoom_out.png
icons\zoom_to.png
icons\load.svg
- icons\logo.svg
+ icons\logo.png
icons\model.svg
icons\ok.svg
icons\outline.svg
diff --git a/rscder/gui/keygen.py b/rscder/gui/keygen.py
new file mode 100644
index 0000000..ad4d27c
--- /dev/null
+++ b/rscder/gui/keygen.py
@@ -0,0 +1,83 @@
+from PyQt5.QtWidgets import QDialog, QLineEdit, QDateTimeEdit, QVBoxLayout, QHBoxLayout, QLabel, QPushButton, QTextEdit, QFileDialog, QMessageBox
+from PyQt5 import QtCore
+from PyQt5.QtGui import QIcon
+
+from rscder.utils.license import LicenseHelper
+import re
+class LicenseGen(QDialog):
+
+ def __init__(self, parent = None, flags = QtCore.Qt.WindowFlags() ) -> None:
+ super().__init__(parent, flags)
+
+ self.setWindowTitle("License Generator")
+ self.setWindowIcon(QIcon(':/icons/logo.png'))
+
+ mac_address_label = QLabel("MAC Address:")
+ self.mac_address_text = QLineEdit()
+
+ hbox1 = QHBoxLayout()
+ hbox1.addWidget(mac_address_label)
+ hbox1.addWidget(self.mac_address_text)
+
+ end_date_label = QLabel("End Date:")
+ self.end_date_text = QDateTimeEdit()
+
+ hbox2 = QHBoxLayout()
+ hbox2.addWidget(end_date_label)
+ hbox2.addWidget(self.end_date_text)
+
+
+ self.license_file_path_text = QLineEdit()
+ self.license_file_path_text.setReadOnly(True)
+
+ btn_open = QPushButton("Open")
+ btn_open.clicked.connect(self.open_file)
+
+ hbox3 = QHBoxLayout()
+ hbox3.addWidget(btn_open)
+ hbox3.addWidget(self.license_file_path_text)
+ # hbox3.addWidget(btn_open)
+
+
+ self.btn_generate = QPushButton("Generate")
+ self.btn_generate.clicked.connect(self.generate_license)
+
+ self.btn_cancel = QPushButton("Cancel")
+ self.btn_cancel.clicked.connect(self.reject)
+
+ hbox4 = QHBoxLayout()
+ hbox4.addWidget(self.btn_generate, alignment = QtCore.Qt.AlignRight, stretch= 0)
+ hbox4.addWidget(self.btn_cancel, alignment = QtCore.Qt.AlignRight, stretch= 0)
+
+ vbox = QVBoxLayout()
+ vbox.addLayout(hbox1)
+ vbox.addLayout(hbox2)
+ vbox.addLayout(hbox3)
+ vbox.addLayout(hbox4)
+
+ self.setLayout(vbox)
+
+ def open_file(self) -> None:
+ file_path, _ = QFileDialog.getSaveFileName(self, "Save License File", "", "License Files (*.lic)")
+ if file_path:
+ self.license_file_path_text.setText(file_path)
+
+ def isValidMac(self,mac):
+ if re.match(r"^\s*([0-9a-fA-F]{2,2}:){5,5}[0-9a-fA-F]{2,2}\s*$", mac):
+ return True
+ return False
+
+
+ def generate_license(self) -> None:
+ if self.mac_address_text.text() and self.license_file_path_text.text() and \
+ self.end_date_text.dateTime().isValid():
+ if not self.isValidMac(self.mac_address_text.text()):
+ QMessageBox.warning(self, "Warning", "Invalid MAC Address")
+
+ end_date = self.end_date_text.dateTime().toPyDateTime().strftime("%Y-%m-%d %H:%M:%S")
+
+ lic = LicenseHelper().generate_license(end_date, self.mac_address_text.text())
+ with open(self.license_file_path_text.text(), 'w') as f:
+ f.write(lic[::-1])
+
+ QMessageBox.information(self, "Information", "License Generated")
\ No newline at end of file
diff --git a/rscder/gui/layertree.py b/rscder/gui/layertree.py
index eec75d7..760f4d7 100644
--- a/rscder/gui/layertree.py
+++ b/rscder/gui/layertree.py
@@ -1,8 +1,9 @@
+import logging
import pdb
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtCore import Qt,QModelIndex
-from PyQt5.QtGui import QStandardItemModel, QStandardItem, QCursor
+from PyQt5.QtGui import QStandardItemModel, QStandardItem, QCursor, QIcon
from PyQt5.QtWidgets import (QTreeView, QTreeWidgetItem, QAbstractItemView, QHeaderView, QStyleFactory)
from rscder.gui.actions import get_action_manager
@@ -18,6 +19,7 @@ class LayerTree(QtWidgets.QWidget):
GRID = 3
tree_changed = QtCore.pyqtSignal(str)
+ zoom_to_layer_signal = QtCore.pyqtSignal(str)
result_clicked = QtCore.pyqtSignal(str, int)
def __init__(self, parent=None):
super().__init__(parent)
@@ -52,6 +54,7 @@ class LayerTree(QtWidgets.QWidget):
self.setLayout(layout)
self.setLayoutDirection(Qt.LeftToRight)
self.is_in_add_layer = False
+ self.current_item = None
def onItemClicked(self, item:QtWidgets.QTreeWidgetItem, column):
if item == self.root:
@@ -153,7 +156,7 @@ class LayerTree(QtWidgets.QWidget):
if item_root.data(0, Qt.UserRole + 1) == layer.id:
layer_root = item_root
break
- print(layer_root.text(0))
+ logging.info(layer_root.text(0))
if layer_root is None:
self.add_layer(layer.id)
return
@@ -172,38 +175,72 @@ class LayerTree(QtWidgets.QWidget):
self.root.setText(0,'图层')
self.tree.addTopLevelItem(self.root)
+ def delete_layer(self):
+ item = self.current_item
+ if item is None:
+ return
+ if item == self.root:
+ return
+ root = item
+ if item.data(0, Qt.UserRole) != LayerTree.LAYER_TOOT:
+ root = item.parent()
+
+ if item.data(0, Qt.UserRole) == LayerTree.LAYER_TOOT:
+ self.root.takeChild(self.root.indexOfChild(item))
+ del Project().layers[root.data(0, Qt.UserRole + 1)]
+ elif item.data(0, Qt.UserRole) == LayerTree.SUB_RASTER:
+ return
+ elif item.data(0, Qt.UserRole) == LayerTree.GRID:
+ return
+ elif item.data(0, Qt.UserRole) == LayerTree.RESULT:
+ root.takeChild(root.indexOfChild(item))
+ del Project().layers[root.data(0, Qt.UserRole + 1)].results[item.data(0, Qt.UserRole + 1)]
+ self.update_layer(root.data(0, Qt.UserRole + 1))
+ self.tree_changed.emit(root.data(0, Qt.UserRole + 1))
+
+ def zoom_to_layer(self):
+ item = self.current_item
+ if item is None:
+ return
+ if item == self.root:
+ return
+ root = item
+ if item.data(0, Qt.UserRole) != LayerTree.LAYER_TOOT:
+ root = item.parent()
+
+ self.zoom_to_layer_signal.emit(root.data(0, Qt.UserRole + 1))
+
+
def right_menu_show(self, position):
rightMenu = QtWidgets.QMenu(self)
# QAction = QtWidgets.QAction(self.menuBar1)
item = self.tree.itemAt(position)
-
+ self.current_item = item
action_manager = get_action_manager()
actions = []
data_load_action = action_manager.get_action('&数据加载', 'File')
actions.append(data_load_action)
+ zoom_to_action = QtWidgets.QAction(QIcon(':/icons/full.svg'), '&缩放至该图层', self)
+ del_action = QtWidgets.QAction(QIcon(':/icons/delete.png'), '&删除该图层', self)
+ zoom_to_action.triggered.connect(self.zoom_to_layer)
+ del_action.triggered.connect(self.delete_layer)
if item is None:
- print('nothing')
+ logging.info('nothing')
else:
if item == self.root:
pass
elif item.data(0, Qt.UserRole) == LayerTree.LAYER_TOOT:
- actions.append(QtWidgets.QAction('&缩放至该图层', self))
-
+ actions.append(zoom_to_action)
actions.append(QtWidgets.QAction('&重命名', self))
- actions.append(QtWidgets.QAction('&删除', self))
+ actions.append(del_action)
elif item.data(0, Qt.UserRole) == LayerTree.SUB_RASTER:
- actions.append(QtWidgets.QAction('&缩放至该图层', self))
-
+ actions.append(zoom_to_action)
actions.append(QtWidgets.QAction('&重命名', self))
- actions.append(QtWidgets.QAction('&删除', self))
elif item.data(0, Qt.UserRole) == LayerTree.RESULT:
- actions.append(QtWidgets.QAction('&缩放至该图层', self))
-
+ actions.append(zoom_to_action)
actions.append(QtWidgets.QAction('&重命名', self))
- actions.append(QtWidgets.QAction('&导出', self))
- actions.append(QtWidgets.QAction('&删除', self))
+ actions.append(del_action)
-
for action in actions:
rightMenu.addAction(action)
diff --git a/rscder/gui/license.py b/rscder/gui/license.py
index f231334..302f13f 100644
--- a/rscder/gui/license.py
+++ b/rscder/gui/license.py
@@ -11,7 +11,7 @@ class License(QtWidgets.QDialog):
def __init__(self, parent = None, flags = QtCore.Qt.WindowFlags() ) -> None:
super().__init__(parent, flags)
self.setWindowTitle("License")
- self.setWindowIcon(QIcon(':/icons/license.png'))
+ self.setWindowIcon(QIcon(':/icons/logo.png'))
self.setWindowFlags(QtCore.Qt.WindowCloseButtonHint)
self.setFixedSize(600, 400)
diff --git a/rscder/gui/mainwindow.py b/rscder/gui/mainwindow.py
index 598f43e..620c516 100644
--- a/rscder/gui/mainwindow.py
+++ b/rscder/gui/mainwindow.py
@@ -37,6 +37,7 @@ class MainWindow(QMainWindow):
self.layer_tree.result_clicked.connect(self.result_box.on_result)
self.result_box.on_item_click.connect(self.double_map.zoom_to_result)
self.result_box.on_item_changed.connect(Project().change_result)
+ self.layer_tree.zoom_to_layer_signal.connect(self.double_map.zoom_to_layer)
self.action_manager = ActionManager(
self.double_map,
diff --git a/rscder/gui/mapcanvas.py b/rscder/gui/mapcanvas.py
index ec38b12..68bbfbb 100644
--- a/rscder/gui/mapcanvas.py
+++ b/rscder/gui/mapcanvas.py
@@ -1,6 +1,7 @@
# from alg.utils import random_color
# from mul.mulgrubcut import GrabCut
+import logging
import multiprocessing
# from alg.grubcut import grubcut
# from gui.layerselect import LayerSelect
@@ -82,24 +83,27 @@ class DoubleCanvas(QWidget):
zoom_out.triggered.connect( self.set_zoom_out)
def set_pan_tool(self, s):
- print('set pan tool')
+ # print('set pan tool')
if s:
self.mapcanva1.setMapTool(QgsMapToolPan(self.mapcanva1))
self.mapcanva2.setMapTool(QgsMapToolPan(self.mapcanva2))
def set_zoom_in(self, s):
- print('set zoom in')
+ # print('set zoom in')
if s:
self.mapcanva1.setMapTool(QgsMapToolZoom(self.mapcanva1, False))
self.mapcanva2.setMapTool(QgsMapToolZoom(self.mapcanva2, False))
def set_zoom_out(self, s):
- print('set zoom out')
+ # print('set zoom out')
if s:
self.mapcanva1.setMapTool(QgsMapToolZoom(self.mapcanva1, True))
self.mapcanva2.setMapTool(QgsMapToolZoom(self.mapcanva2, True))
def add_layer(self, layer:str):
+ if not layer in Project().layers:
+ self.clear()
+ return
layer:PairLayer = Project().layers[layer]
if not layer.enable:
return
@@ -209,431 +213,4 @@ class CanvasWidget(QgsMapCanvas):
def coordinates2text(pt:QgsPointXY):
return self.update_coordinates_text.emit("X: {:.5f}, Y: {:.5f}".format(pt.x(), pt.y()))
self.xyCoordinates.connect(coordinates2text)
- self.scaleChanged.connect(lambda _ : self.update_scale_text.emit("1 : {:.3f}".format(self.scale())))
-
- self.total_f = 0
- self.start_extract = False
- self.label_pal = None
- # self.result_layers = []
-
- def dragEnterEvent(self, e:QDragEnterEvent) -> None:
- '''
- Can drag
- '''
- candidates = [".tif", ".tiff", ".jpg", ".jpeg", ".bmp", ".png"]
-
- if e.mimeData().hasUrls():
- if Path(e.mimeData().urls()[0].toLocalFile()).suffix in candidates:
- e.accept()
- return
-
- e.ignore()
-
- def dropEvent(self, e:QDropEvent) -> None:
- '''
- Drop image to the canvas
- '''
- url_path = e.mimeData().urls()[0]
- image_path = QUrl(url_path).toLocalFile()
- self.load_image(image_path)
-
- def load_image(self, path) -> None:
- if not Path(path).exists():
- return
-
- raster_layer = QgsRasterLayer(path, Path(path).name)
- if not raster_layer.isValid():
- print("栅格图层加载失败!")
- raster_layer.file_path = path
-
- # self.layers.insert(0, raster_layer)
- # self.layers.insert(0, vector_layer)
- # if self.current_raster_layer:
- # del self.current_raster_layer
- # if self.current_vector_layer:
- # del self.current_vector_layer
-
- QgsProject.instance().addMapLayer(raster_layer)
- self.current_raster_layer = raster_layer
- # self.current_vector_layer = vector_layer
- self.setExtent(raster_layer.extent())
- # self.setLayers([vector_layer, raster_layer])
- self.zoomToFeatureExtent(raster_layer.extent())
- self.have_current_image.emit(True)
-
- def load_result_from_txt(self, path) -> None:
- if not Path(path).exists():
- return
- # vector_layer = QgsVectorLayer("Polygon?field=category:string(20)&field=confidence:double", Path(path).name, "memory")
- vector_layer = QgsVectorLayer("Polygon?field=category:string(20)&field=confidence:double&field=renderkey:string(32)&field=isman:boolean&field=isauto:boolean&field=label:string(64)", Path(path).name + ' outline', "memory")
-
- if not vector_layer.isValid():
- print("矢量图层加载失败!")
- vector_layer.setLabelsEnabled(True)
- lyr = QgsPalLayerSettings()
- lyr.enabled = True
- lyr.fieldName = 'label' # default in data sources
- # lyr.textFont = self._TestFont
- lyr.textNamedStyle = 'Medium'
- text_format = QgsTextFormat()
- text_format.color = QColor('#ffffff')
- text_format.background().color = QColor('#000000')
- text_format.buffer().setEnabled(True)
- text_format.buffer().setSize(1)
- text_format.buffer().setOpacity(0.5)
- lyr.setFormat(text_format)
- self.label_pal = lyr
- root = QgsRuleBasedLabeling.Rule(QgsPalLayerSettings())
- rule = QgsRuleBasedLabeling.Rule(lyr)
- rule.setDescription('label')
- root.appendChild(rule)
- #Apply label configuration
- rules = QgsRuleBasedLabeling(root)
- vector_layer.setLabeling(rules)
- vector_layer.triggerRepaint()
- # lyr.writeToLayer(vector_layer)
- vector_layer.setRenderer(self.__get_categorical_renderer("renderkey"))
- QgsProject.instance().addMapLayer(vector_layer)
- self.current_vector_layer = vector_layer
- # provider = self.current_vector_layer.dataProvider()
- # provider.truncate()
- self.current_vector_layer.startEditing()
- # objects = []
- features = []
- with open(path) as f:
- for line in f.readlines():
- item_data = line.split("\n")[0].split(" ")
- if len(item_data) == 1 + 4 * 2:
- cls_name = item_data[0]
- item_data[2] = -1.0 * float(item_data[2])
- item_data[4] = -1.0 * float(item_data[4])
- item_data[6] = -1.0 * float(item_data[6])
- item_data[8] = -1.0 * float(item_data[8])
- wkt = "POLYGON (({} {}, {} {}, {} {}, {} {}))".format(*item_data[1:])
- conf = 1.0
- else:
- cls_name = item_data[8]
- # print(cls_name)
- # print(cls_name[0])
- # print(cls_name[0].isalpha())
- if cls_name[0].isalpha():
- item_data[1] = -1.0 * float(item_data[1])
- item_data[3] = -1.0 * float(item_data[3])
- item_data[5] = -1.0 * float(item_data[5])
- item_data[7] = -1.0 * float(item_data[7])
- conf = 1.0
- wkt = "POLYGON (({} {}, {} {}, {} {}, {} {}))".format(*item_data[:8])
- else:
- cls_name = item_data[0]
- conf = float(item_data[1])
- item_data[3] = -1.0 * float(item_data[3])
- item_data[5] = -1.0 * float(item_data[5])
- item_data[7] = -1.0 * float(item_data[7])
- item_data[9] = -1.0 * float(item_data[9])
- wkt = "POLYGON (({} {}, {} {}, {} {}, {} {}))".format(*item_data[2:])
-
- feat = QgsFeature(self.current_vector_layer.fields())
- feat.setGeometry(QgsGeometry.fromWkt(wkt))
- feat.setAttribute('category', cls_name)
- feat.setAttribute('confidence', conf)
- feat.setAttribute('renderkey', cls_name)
- feat.setAttribute('isman', False)
- feat.setAttribute('isauto', True)
- feat.setAttribute('label', f'{ cls_name},{conf:.3f}')
- features.append(feat)
- # objects.append({
- # "category": item_data[0],
- # "confidence": item_data[1],
- # "fid": feat.id()
- # })
- self.current_vector_layer.addFeatures(features)
- self.current_vector_layer.commitChanges()
- self.have_current_vector.emit(True)
- self.layer_update()
-
- def clear_vector(self):
- if self.current_vector_layer is not None:
- provider = self.current_vector_layer.dataProvider()
- provider.truncate()
- self.layer_update()
-
- def change_current_vector_layer(self, vector_layer):
- if self.current_vector_layer is not None:
- self.current_vector_layer.removeSelection()
- self.current_vector_layer = vector_layer
-
- self.layer_update()
-
- def layer_update(self):
- if self.current_vector_layer is None:
- self.object_updated.emit([])
- return
- self.current_vector_layer.updateExtents()
- self.refresh()
- objects = []
- for feature in self.current_vector_layer.getFeatures():
- objects.append({
- "category": feature['category'],
- "confidence": feature['confidence'],
- "renderkey": feature['renderkey'],
- 'isman': feature['isman'],
- 'isauto': feature['isauto'],
- "fid": feature.id()
- })
- self.object_updated.emit(objects)
-
- def selectd_changed(self, items:list):
- if len(items) == 0:
- self.current_vector_layer.removeSelection()
- else:
- self.current_vector_layer.selectByIds(list(item['fid'] for item in items))
-
- def item_change(self, items:list):
- self.current_vector_layer.startEditing()
- features = list(self.current_vector_layer.getFeatures())
- for f in features:
- has_f = False
- for item in items:
- if f.id() == item['fid']:
- # f = QgsFeature(f)
- has_f = True
- f.setAttribute('category', item['category'])
- f.setAttribute('confidence', item['confidence'])
- f.setAttribute('renderkey', item['renderkey'])
- f.setAttribute('isman', item['isman'])
- f.setAttribute('isauto', item['isauto'])
- self.current_vector_layer.updateFeature(f)
- break
- if has_f:
- continue
-
- self.current_vector_layer.deleteFeature(f.id())
-
- self.current_vector_layer.commitChanges()
- self.current_vector_layer.updateExtents()
- # print(self.current_vector_layer.fields())
-
- self.refresh()
-
- def zoom_to_full_extent(self) -> None:
- if self.current_raster_layer:
- self.zoomToFeatureExtent(self.current_raster_layer.extent())
-
- def __get_categorical_renderer(self, fieldname:str) -> QgsCategorizedSymbolRenderer:
- settings = QSettings(self)
-
- category_keys = settings.value("keys", get_default_category_keys())
- category_colors = settings.value("colors", get_default_category_colors())
-
- settings.beginGroup("Category")
- if len(category_colors) < len(category_keys):
- for _ in range(len(category_keys) - len(category_colors)):
- category_colors.append(random_color())
- settings.setValue('colors', category_colors)
- settings.endGroup()
- categorized_renderer = QgsCategorizedSymbolRenderer()
- for key, color in zip(category_keys, category_colors):
- fill_color = QColor(color)
- fill_color.setAlphaF(0.3)
- categorized_renderer.addCategory(\
- QgsRendererCategory(
- key,
- QgsFillSymbol.createSimple(
- {"color":fill_color.name(QColor.HexArgb),"outline_color":color, "outline_width":"1"}), ''))
- categorized_renderer.setClassAttribute(fieldname)
- return categorized_renderer
-
- def export_to_raster(self, path) -> None:
- if self.current_vector_layer is None:
- return
-
- def load_extract_result(self, res):
- r = self.current_raster_layer
- vector_layer = QgsVectorLayer("Polygon?field=category:string(20)&field=confidence:double&field=renderkey:string(32)&field=isman:boolean&field=isauto:boolean", Path(r.file_path).name + ' outline', "memory")
- # vector_layer = QgsVectorLayer(tempfile)
- if not vector_layer.isValid():
- print("矢量图层加载失败!")
-
- vector_layer.setRenderer(self.__get_categorical_renderer("renderkey"))
- lyr = QgsPalLayerSettings()
- lyr.enabled = True
- lyr.fieldName = 'label' # default in data sources
- # lyr.textFont = self._TestFont
- lyr.textNamedStyle = 'Medium'
- text_format = QgsTextFormat()
- text_format.color = QColor('#ffffff')
- text_format.background().color = QColor('#000000')
- text_format.buffer().setEnabled(True)
- text_format.buffer().setSize(1)
- text_format.buffer().setOpacity(0.5)
- lyr.setFormat(text_format)
- self.label_pal = lyr
- root = QgsRuleBasedLabeling.Rule(QgsPalLayerSettings())
- rule = QgsRuleBasedLabeling.Rule(lyr)
- rule.setDescription('label')
- root.appendChild(rule)
- #Apply label configuration
- rules = QgsRuleBasedLabeling(root)
- vector_layer.setLabeling(rules)
- vector_layer.triggerRepaint()
- vector_layer.startEditing()
- features = []
- for f in res:
- pts = f[0]
- prop = f[1]
- # pts = grubcut(img_path, pts, False, True, False )
- pts = list( f'{p[0]} {p[1]}' for p in pts )
- wkt = f'POLYGON (( {",".join(pts)} ))'
- # geometry = QgsGeometry.fromWkt(wkt)
- feat = QgsFeature(vector_layer.fields())
- feat.setGeometry(QgsGeometry.fromWkt(wkt))
- feat.setAttribute('category', prop['category'])
- feat.setAttribute('confidence', prop['confidence'])
- feat.setAttribute('renderkey', prop['category'])
- feat.setAttribute('isman', False)
- feat.setAttribute('isauto', True)
- features.append(feat)
-
- vector_layer.addFeatures(features)
- vector_layer.commitChanges()
- QgsProject.instance().addMapLayer(vector_layer)
- self.process_end.emit()
- r.has_extract = True
- self.start_extract = False
- r.extract_layer = vector_layer
- self.layer_update()
-
- def run_thread(self, conn, pp):
- all_ok = False
- # print(pp.is_alive)
- while pp.is_alive:
- r = conn.recv()
- # print(r)
- if all_ok:
- self.extract_end.emit(r)
- break
- if int(r) == self.total_f - 1:
- all_ok = True
- self.process_update.emit(r)
- # print(conn.recv())
- def grubcut(self, v, r):
- # for f in v.getFeatures():
- if self.start_extract:
- return
- self.current_raster_layer = r
- img_path = r.file_path
- if getattr(r, 'has_extract', False):
- vector_layer = r.extract_layer
- try:
- QgsProject.instance().removeMapLayer(vector_layer)
- except:
- pass
-
- # self.current_vector_layer = vector_layer
- features = []
- points = []
- for f in v.getFeatures():
- pts = f.geometry().vertices()
- pts = list([ vr.x(), vr.y() ] for vr in pts)
- points.append(pts)
- features.append({
- 'category': f['category'],
- 'confidence': f['confidence']
- })
- self.total_f = len(points)
- self.start_extract = True
- self.process_start.emit([0, self.total_f])
- parent_conn, child_conn = multiprocessing.Pipe()
- t = GrabCut(child_conn, img_path, points, features)
- p = threading.Thread(target=self.run_thread, args=(parent_conn,t))
- t.start()
- p.start()
-
- def export_to(self, path, filter_name) -> None:
- if filter_name == 'Shp (*.shp)':
- if self.current_vector_layer is None:
- return
- ls = LayerSelect(self)
- ls.show()
- ls.exec()
- if ls.result() == LayerSelect.OK:
- save_options = QgsVectorFileWriter.SaveVectorOptions()
- save_options.driverName = "ESRI Shapefile"
- save_options.fileEncoding = "UTF-8"
- transform_context = QgsProject.instance().transformContext()
- error = QgsVectorFileWriter.writeAsVectorFormatV2(ls.value,
- path,
- transform_context,
- save_options)
- if error[0] == QgsVectorFileWriter.NoError:
- print("又成功了!")
- else:
- print(error)
-
- if filter_name == 'JPEG Images(*.jpg)':
- file_name = path + '.tif'
- extent = self.current_raster_layer.extent()
- width, height = self.current_raster_layer.width(), self.current_raster_layer.height()
-
- pipe = QgsRasterPipe()
- provider = self.current_raster_layer.dataProvider()
- pipe.set(provider.clone())
-
- file_writer = QgsRasterFileWriter(file_name)
- error = file_writer.writeRaster(pipe,
- width,
- height,
- extent,
- self.current_raster_layer.crs())
-
- target_img = cv2.imread(file_name)
- jpg_file_name = path + '.jpg'
- cv2.imwrite(jpg_file_name, target_img)
- os.remove(file_name)
- if error == QgsRasterFileWriter.NoError:
- QMessageBox.about(self, 'Export Files', '导出JPEG图像成功!')
- else:
- QMessageBox.about(self, 'Export Files', '导出JPEG图像失败!')
-
- if filter_name == 'TIFF Images(*.tif)':
- file_name = path + '.tif'
- extent = self.current_raster_layer.extent()
- width, height = self.current_raster_layer.width(), self.current_raster_layer.height()
-
- pipe = QgsRasterPipe()
- provider = self.current_raster_layer.dataProvider()
- pipe.set(provider.clone())
-
- file_writer = QgsRasterFileWriter(file_name)
- error = file_writer.writeRaster(pipe,
- width,
- height,
- extent,
- self.current_raster_layer.crs())
- if error == QgsRasterFileWriter.NoError:
- QMessageBox.about(self, 'Export Files', '导出TIFF图像成功!')
- else:
- QMessageBox.about(self, 'Export Files', '导出TIFF图像失败!')
- if filter_name == 'PNG Images(*.png)':
- file_name = path + '.tif'
- extent = self.current_raster_layer.extent()
- width, height = self.current_raster_layer.width(), self.current_raster_layer.height()
-
- pipe = QgsRasterPipe()
- provider = self.current_raster_layer.dataProvider()
- pipe.set(provider.clone())
-
- file_writer = QgsRasterFileWriter(file_name)
- error = file_writer.writeRaster(pipe,
- width,
- height,
- extent,
- self.current_raster_layer.crs())
- target_img = cv2.imread(file_name)
- jpg_file_name = path + '.png'
- cv2.imwrite(jpg_file_name, target_img)
- os.remove(file_name)
- if error == QgsRasterFileWriter.NoError:
- QMessageBox.about(self, 'Export Files', '导出PNG图像成功!')
- else:
- QMessageBox.about(self, 'Export Files', '导出PNG图像失败!')
\ No newline at end of file
+ self.scaleChanged.connect(lambda _ : self.update_scale_text.emit("1 : {:.3f}".format(self.scale())))
\ No newline at end of file
diff --git a/rscder/gui/messagebox.py b/rscder/gui/messagebox.py
index 56da67e..b06c0d9 100644
--- a/rscder/gui/messagebox.py
+++ b/rscder/gui/messagebox.py
@@ -1,6 +1,6 @@
from PyQt5.QtWidgets import QTextEdit
from PyQt5 import QtWidgets
-from PyQt5.QtGui import QTextCursor
+from PyQt5.QtGui import QTextCursor, QIcon
from PyQt5.QtCore import Qt
from datetime import datetime, time
class MessageBox(QTextEdit):
@@ -24,7 +24,7 @@ class MessageBox(QTextEdit):
def right_menu_show(self, position):
rightMenu = QtWidgets.QMenu(self)
# QAction = QtWidgets.QAction(self.menuBar1)
- action = QtWidgets.QAction('清空')
+ action = QtWidgets.QAction(QIcon(':/icons/exit.png'), '清空')
action.triggered.connect(self.clear)
rightMenu.addAction(action)
diff --git a/rscder/gui/plugins.py b/rscder/gui/plugins.py
index 0a93405..bd9d01a 100644
--- a/rscder/gui/plugins.py
+++ b/rscder/gui/plugins.py
@@ -1,3 +1,4 @@
+import logging
import os
import shutil
from PyQt5.QtWidgets import *
@@ -11,7 +12,7 @@ class PluginDialog(QDialog):
def __init__(self, parent=None):
super().__init__(parent)
self.setWindowTitle('Plugins')
- self.setWindowIcon(QIcon(":/icons/logo.svg"))
+ self.setWindowIcon(QIcon(":/icons/logo.png"))
self.setMinimumWidth(900)
self.setMinimumHeight(600)
self.plugins = list(Settings.Plugin().plugins)
@@ -57,7 +58,7 @@ class PluginDialog(QDialog):
plugin_directory = QFileDialog.getExistingDirectory(self, 'Select Plugin Directory', '.')
if plugin_directory is not None:
info = PluginLoader.load_plugin_info(plugin_directory)
- print(info)
+ logging.info(info)
if info is not None:
try:
@@ -73,6 +74,7 @@ class PluginDialog(QDialog):
self.plugin_table.insertRow(self.plugin_table.rowCount())
name_item = QTableWidgetItem(info['name'])
+ name_item.setIcon(QIcon(':/icons/tools.png'))
module_item = QTableWidgetItem(info['module'])
enabled_item = QTableWidgetItem('启用')
enabled_item.setCheckState(Qt.Checked)
@@ -94,7 +96,8 @@ class PluginDialog(QDialog):
try:
shutil.rmtree(info['path'])
except Exception as e:
- print(e)
+ # logging
+ logging.info(e)
pass
# for idx in self.plugins
diff --git a/rscder/gui/result.py b/rscder/gui/result.py
index 8464cf1..097ac65 100644
--- a/rscder/gui/result.py
+++ b/rscder/gui/result.py
@@ -1,4 +1,5 @@
+import logging
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtCore import Qt,QModelIndex, pyqtSignal
from PyQt5.QtGui import QStandardItemModel, QStandardItem
@@ -47,7 +48,8 @@ class ResultTable(QtWidgets.QWidget):
self.tablewidget.item(row, col).setBackground(Qt.yellow)
else:
self.tablewidget.item(row, col).setBackground(Qt.green)
- print(item_idx, item_status)
+ # logging
+ logging.info(item_idx, item_status)
self.result.update({'row':item_idx, 'value':item_status})
self.no_change = False
diff --git a/rscder/mul/mulstart.py b/rscder/mul/mulstart.py
index e0a4717..55b4838 100644
--- a/rscder/mul/mulstart.py
+++ b/rscder/mul/mulstart.py
@@ -39,12 +39,16 @@ class MulStart:
sys.exit(0)
# Create and display the splash screen
splash_pix = QPixmap(':/icons/splash.png')
+ # splash_pix.scaledToWidth(800)
+ # splash_pix.scaledToHeight(600)
splash = QSplashScreen(splash_pix, Qt.WindowStaysOnTopHint)
+ # splash
+ # splash.setFixedSize(800, 600)
progressBar = QProgressBar(splash)
progressBar.setMaximum(10)
progressBar.setTextVisible(False)
- progressBar.setGeometry(46, splash_pix.height() - 60, splash_pix.width()-92, 10)
+ progressBar.setGeometry(106, splash_pix.height() - 60, splash_pix.width()-212, 10)
splash.show()
for i in range(1, 11):
diff --git a/rscder/plugins/loader.py b/rscder/plugins/loader.py
index 635e133..985da81 100644
--- a/rscder/plugins/loader.py
+++ b/rscder/plugins/loader.py
@@ -1,3 +1,4 @@
+import logging
import shutil
from rscder.utils.setting import Settings
from PyQt5.QtWidgets import QMessageBox
@@ -34,12 +35,13 @@ class PluginLoader(QObject):
module = importlib.import_module(os.path.basename(path))
mes = inspect.getmembers(module)
for name, obj in mes:
- print(name, obj)
+ # logging
+ logging.info(name, obj)
if inspect.isclass(obj) and issubclass(obj, BasicPlugin):
info = obj.info()
break
except Exception as e:
- print(e)
+ logging.info(str(e))
QMessageBox.critical(None, 'Error', f'{path} load error: {e}')
finally:
sys.path.pop(0)
diff --git a/rscder/utils/license.py b/rscder/utils/license.py
index c731d90..c280516 100644
--- a/rscder/utils/license.py
+++ b/rscder/utils/license.py
@@ -1,4 +1,5 @@
import base64
+import logging
from Crypto.Cipher import AES
import uuid
import hashlib
@@ -78,7 +79,7 @@ def get_aes():
class LicenseHelper(object):
def generate_license(self, end_date, mac_addr):
- print("Received end_date: {}, mac_addr: {}".format(end_date, mac_addr))
+ logging.info("Received end_date: {}, mac_addr: {}".format(end_date, mac_addr))
psw = self.hash_msg('smartant' + str(mac_addr))
license_str = {}
license_str['mac'] = mac_addr
@@ -110,8 +111,8 @@ class LicenseHelper(object):
lic_date_array = datetime.datetime.strptime(lic_date, "%Y-%m-%d %H:%M:%S")
remain_days = lic_date_array - current_time_array
remain_days = remain_days.days
- print('lic data:{}'.format(lic_date))
- print('remain_days: {}'.format(remain_days))
+ logging.info('lic data:{}'.format(lic_date))
+ logging.info('remain_days: {}'.format(remain_days))
if remain_days < 0 or remain_days == 0:
return False
else:
@@ -138,6 +139,6 @@ if __name__ == '__main__':
license_dic = LicenseHelper().read_license(license_result)
- print(license_dic)
+ logging.info(license_dic)
\ No newline at end of file
diff --git a/使用手册.txt b/使用手册.txt
new file mode 100644
index 0000000..6bc28e8
--- /dev/null
+++ b/使用手册.txt
@@ -0,0 +1,19 @@
+1. lic文件生成
+点击RSCDer.exe,复制所显示的mac地址
+点击keygen.exe,粘贴mac地址,设置截止日期,并选择保存路径(无需输入后缀名)
+点击Generate
+
+2. lic文件导入
+点击RSCDer.exe,点击Open,选择生成的lic文件
+点击OK
+
+3. 新建项目与数据导入
+点击RSCDer.exe
+点击新建项目
+选择路径、名称
+将会在路径下看到与名称相同的文件夹
+
+点击载入数据
+选择两幅不同时相的影像
+
+4. 基本变化检测
\ No newline at end of file
diff --git a/未命名.prj b/未命名.prj
deleted file mode 100644
index 35c901f..0000000
--- a/未命名.prj
+++ /dev/null
@@ -1,8 +0,0 @@
-cell_size:
-- 100
-- 100
-layers: []
-max_memory: 100
-max_threads: 4
-results: []
-root: F:\LZY_DATA\p122r032