This commit is contained in:
copper 2022-05-12 20:39:32 +08:00
parent 30ceccbd49
commit 4bb6417131
27 changed files with 323 additions and 477 deletions

View File

View File

@ -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 REM Win7 with console

BIN
icons/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 997 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 93 KiB

After

Width:  |  Height:  |  Size: 699 KiB

9
keygen.py Normal file
View File

@ -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_())

View File

@ -1 +1 @@
pGZJMmJtule8fwDCz4mnyHoQa7N6pl5GRdLqfoXREBqG4Xb1jbvgf7RmC8f1+sNpiCFSIt7NgvU362tKhB5UBXn/vUAadG1lOGC70dUhprGzBoqJN7VkAHkNGg0XjoE8H0SCVynr8To7ciwcnmK6HJXre6i+mBdTjACmKseTMlWp480XOt7uHysltORbTA3J IieXktda+1nRK9zLwe87uPPn2VpCwmUrEOPfyenaW/Sek70/CqqbCr7nangL1+pVXSkzDELia7Qq8e+pDMuHCXzxyJOALRj4j3bhFVExwqSTLuXwdev1e26nr7vnECl7H0SCVynr8To7ciwcnmK6HJXre6i+mBdTjACmKseTMlWp480XOt7uHysltORbTA3J

1
lic_t.lic Normal file
View File

@ -0,0 +1 @@
IieXktda+1nRK9zLwe87uPPn2VpCwmUrEOPfyenaW/Sek70/CqqbCr7nangL1+pVXSkzDELia7Qq8e+pDMuHCXzxyJOALRj4j3bhFVExwqSTLuXwdev1e26nr7vnECl7H0SCVynr8To7ciwcnmK6HJXre6i+mBdTjACmKseTMlWp480XOt7uHysltORbTA3J

BIN
logo.ico

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

After

Width:  |  Height:  |  Size: 4.2 KiB

View File

@ -63,6 +63,6 @@ class AboutPlugin(BasicPlugin):
menu.addAction(action) menu.addAction(action)
def on_about(self): def on_about(self):
print('on_about') # print('on_about')
dialog = AboutDialog(self.ctx['mainwindow']) dialog = AboutDialog(self.ctx['mainwindow'])
dialog.show() dialog.show()

View File

@ -10,7 +10,7 @@ from rscder.gui.layercombox import LayerCombox
from osgeo import gdal, gdal_array from osgeo import gdal, gdal_array
from threading import Thread from threading import Thread
import numpy as np import numpy as np
from basic_change.otsu import OTSU
class MyDialog(QDialog): class MyDialog(QDialog):
def __init__(self, parent=None): 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_tif = os.path.join(out, 'diff_0_255.tif')
out_normal_ds = driver.Create(out_normal_tif, xsize, ysize, 1, gdal.GDT_Byte) 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): for j in range(yblocks):
block_xy = (0, j * cell_size[1]) block_xy = (0, j * cell_size[1])
block_size = (xsize, cell_size[1]) block_size = (xsize, cell_size[1])
@ -164,6 +164,12 @@ class BasicMethod(BasicPlugin):
block_data = (block_data - min_diff) / (max_diff - min_diff) * 255 block_data = (block_data - min_diff) / (max_diff - min_diff) * 255
block_data = block_data.astype(np.uint8) block_data = block_data.astype(np.uint8)
out_normal_ds.GetRasterBand(1).WriteArray(block_data, *block_xy) 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() out_normal_ds.FlushCache()
del out_normal_ds del out_normal_ds
@ -194,7 +200,7 @@ class BasicMethod(BasicPlugin):
center_y = j * cell_size[1] + cell_size[1] // 2 center_y = j * cell_size[1] + cell_size[1] // 2
center_x = center_x * geo[1] + geo [0] center_x = center_x * geo[1] + geo [0]
center_y = center_y * geo[5] + geo [3] 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({ self.result_ok.emit({

View File

@ -0,0 +1 @@
from export_to.main import *

100
plugins/export_to/main.py Normal file
View File

@ -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('导出成功')

View File

@ -3,12 +3,19 @@
enabled: true enabled: true
module: about module: about
name: "\u5173\u4E8E" name: "\u5173\u4E8E"
path: ./plugin-build\about path: ./plugin\about
version: 1.0.0 version: 1.0.0
- author: RSCDER - author: RSCDER
description: BasicMethod description: BasicMethod
enabled: true enabled: true
module: basic_change module: basic_change
name: BasicMethod 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 version: 1.0.0

View File

@ -28,7 +28,7 @@
<file>icons\zoom_out.png</file> <file>icons\zoom_out.png</file>
<file>icons\zoom_to.png</file> <file>icons\zoom_to.png</file>
<file>icons\load.svg</file> <file>icons\load.svg</file>
<file>icons\logo.svg</file> <file>icons\logo.png</file>
<file>icons\model.svg</file> <file>icons\model.svg</file>
<file>icons\ok.svg</file> <file>icons\ok.svg</file>
<file>icons\outline.svg</file> <file>icons\outline.svg</file>

83
rscder/gui/keygen.py Normal file
View File

@ -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")

View File

@ -1,8 +1,9 @@
import logging
import pdb import pdb
from PyQt5 import QtCore, QtGui, QtWidgets from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtCore import Qt,QModelIndex 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 PyQt5.QtWidgets import (QTreeView, QTreeWidgetItem, QAbstractItemView, QHeaderView, QStyleFactory)
from rscder.gui.actions import get_action_manager from rscder.gui.actions import get_action_manager
@ -18,6 +19,7 @@ class LayerTree(QtWidgets.QWidget):
GRID = 3 GRID = 3
tree_changed = QtCore.pyqtSignal(str) tree_changed = QtCore.pyqtSignal(str)
zoom_to_layer_signal = QtCore.pyqtSignal(str)
result_clicked = QtCore.pyqtSignal(str, int) result_clicked = QtCore.pyqtSignal(str, int)
def __init__(self, parent=None): def __init__(self, parent=None):
super().__init__(parent) super().__init__(parent)
@ -52,6 +54,7 @@ class LayerTree(QtWidgets.QWidget):
self.setLayout(layout) self.setLayout(layout)
self.setLayoutDirection(Qt.LeftToRight) self.setLayoutDirection(Qt.LeftToRight)
self.is_in_add_layer = False self.is_in_add_layer = False
self.current_item = None
def onItemClicked(self, item:QtWidgets.QTreeWidgetItem, column): def onItemClicked(self, item:QtWidgets.QTreeWidgetItem, column):
if item == self.root: if item == self.root:
@ -153,7 +156,7 @@ class LayerTree(QtWidgets.QWidget):
if item_root.data(0, Qt.UserRole + 1) == layer.id: if item_root.data(0, Qt.UserRole + 1) == layer.id:
layer_root = item_root layer_root = item_root
break break
print(layer_root.text(0)) logging.info(layer_root.text(0))
if layer_root is None: if layer_root is None:
self.add_layer(layer.id) self.add_layer(layer.id)
return return
@ -172,37 +175,71 @@ class LayerTree(QtWidgets.QWidget):
self.root.setText(0,'图层') self.root.setText(0,'图层')
self.tree.addTopLevelItem(self.root) 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): def right_menu_show(self, position):
rightMenu = QtWidgets.QMenu(self) rightMenu = QtWidgets.QMenu(self)
# QAction = QtWidgets.QAction(self.menuBar1) # QAction = QtWidgets.QAction(self.menuBar1)
item = self.tree.itemAt(position) item = self.tree.itemAt(position)
self.current_item = item
action_manager = get_action_manager() action_manager = get_action_manager()
actions = [] actions = []
data_load_action = action_manager.get_action('&数据加载', 'File') data_load_action = action_manager.get_action('&数据加载', 'File')
actions.append(data_load_action) 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: if item is None:
print('nothing') logging.info('nothing')
else: else:
if item == self.root: if item == self.root:
pass pass
elif item.data(0, Qt.UserRole) == LayerTree.LAYER_TOOT: 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(QtWidgets.QAction('&删除', self)) actions.append(del_action)
elif item.data(0, Qt.UserRole) == LayerTree.SUB_RASTER: 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))
actions.append(QtWidgets.QAction('&删除', self))
elif item.data(0, Qt.UserRole) == LayerTree.RESULT: 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)
actions.append(QtWidgets.QAction('&删除', self))
for action in actions: for action in actions:

View File

@ -11,7 +11,7 @@ class License(QtWidgets.QDialog):
def __init__(self, parent = None, flags = QtCore.Qt.WindowFlags() ) -> None: def __init__(self, parent = None, flags = QtCore.Qt.WindowFlags() ) -> None:
super().__init__(parent, flags) super().__init__(parent, flags)
self.setWindowTitle("License") self.setWindowTitle("License")
self.setWindowIcon(QIcon(':/icons/license.png')) self.setWindowIcon(QIcon(':/icons/logo.png'))
self.setWindowFlags(QtCore.Qt.WindowCloseButtonHint) self.setWindowFlags(QtCore.Qt.WindowCloseButtonHint)
self.setFixedSize(600, 400) self.setFixedSize(600, 400)

View File

@ -37,6 +37,7 @@ class MainWindow(QMainWindow):
self.layer_tree.result_clicked.connect(self.result_box.on_result) 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_click.connect(self.double_map.zoom_to_result)
self.result_box.on_item_changed.connect(Project().change_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.action_manager = ActionManager(
self.double_map, self.double_map,

View File

@ -1,6 +1,7 @@
# from alg.utils import random_color # from alg.utils import random_color
# from mul.mulgrubcut import GrabCut # from mul.mulgrubcut import GrabCut
import logging
import multiprocessing import multiprocessing
# from alg.grubcut import grubcut # from alg.grubcut import grubcut
# from gui.layerselect import LayerSelect # from gui.layerselect import LayerSelect
@ -82,24 +83,27 @@ class DoubleCanvas(QWidget):
zoom_out.triggered.connect( self.set_zoom_out) zoom_out.triggered.connect( self.set_zoom_out)
def set_pan_tool(self, s): def set_pan_tool(self, s):
print('set pan tool') # print('set pan tool')
if s: if s:
self.mapcanva1.setMapTool(QgsMapToolPan(self.mapcanva1)) self.mapcanva1.setMapTool(QgsMapToolPan(self.mapcanva1))
self.mapcanva2.setMapTool(QgsMapToolPan(self.mapcanva2)) self.mapcanva2.setMapTool(QgsMapToolPan(self.mapcanva2))
def set_zoom_in(self, s): def set_zoom_in(self, s):
print('set zoom in') # print('set zoom in')
if s: if s:
self.mapcanva1.setMapTool(QgsMapToolZoom(self.mapcanva1, False)) self.mapcanva1.setMapTool(QgsMapToolZoom(self.mapcanva1, False))
self.mapcanva2.setMapTool(QgsMapToolZoom(self.mapcanva2, False)) self.mapcanva2.setMapTool(QgsMapToolZoom(self.mapcanva2, False))
def set_zoom_out(self, s): def set_zoom_out(self, s):
print('set zoom out') # print('set zoom out')
if s: if s:
self.mapcanva1.setMapTool(QgsMapToolZoom(self.mapcanva1, True)) self.mapcanva1.setMapTool(QgsMapToolZoom(self.mapcanva1, True))
self.mapcanva2.setMapTool(QgsMapToolZoom(self.mapcanva2, True)) self.mapcanva2.setMapTool(QgsMapToolZoom(self.mapcanva2, True))
def add_layer(self, layer:str): def add_layer(self, layer:str):
if not layer in Project().layers:
self.clear()
return
layer:PairLayer = Project().layers[layer] layer:PairLayer = Project().layers[layer]
if not layer.enable: if not layer.enable:
return return
@ -210,430 +214,3 @@ class CanvasWidget(QgsMapCanvas):
return self.update_coordinates_text.emit("X: {:.5f}, Y: {:.5f}".format(pt.x(), pt.y())) return self.update_coordinates_text.emit("X: {:.5f}, Y: {:.5f}".format(pt.x(), pt.y()))
self.xyCoordinates.connect(coordinates2text) self.xyCoordinates.connect(coordinates2text)
self.scaleChanged.connect(lambda _ : self.update_scale_text.emit("1 : {:.3f}".format(self.scale()))) 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图像失败')

View File

@ -1,6 +1,6 @@
from PyQt5.QtWidgets import QTextEdit from PyQt5.QtWidgets import QTextEdit
from PyQt5 import QtWidgets from PyQt5 import QtWidgets
from PyQt5.QtGui import QTextCursor from PyQt5.QtGui import QTextCursor, QIcon
from PyQt5.QtCore import Qt from PyQt5.QtCore import Qt
from datetime import datetime, time from datetime import datetime, time
class MessageBox(QTextEdit): class MessageBox(QTextEdit):
@ -24,7 +24,7 @@ class MessageBox(QTextEdit):
def right_menu_show(self, position): def right_menu_show(self, position):
rightMenu = QtWidgets.QMenu(self) rightMenu = QtWidgets.QMenu(self)
# QAction = QtWidgets.QAction(self.menuBar1) # QAction = QtWidgets.QAction(self.menuBar1)
action = QtWidgets.QAction('清空') action = QtWidgets.QAction(QIcon(':/icons/exit.png'), '清空')
action.triggered.connect(self.clear) action.triggered.connect(self.clear)
rightMenu.addAction(action) rightMenu.addAction(action)

View File

@ -1,3 +1,4 @@
import logging
import os import os
import shutil import shutil
from PyQt5.QtWidgets import * from PyQt5.QtWidgets import *
@ -11,7 +12,7 @@ class PluginDialog(QDialog):
def __init__(self, parent=None): def __init__(self, parent=None):
super().__init__(parent) super().__init__(parent)
self.setWindowTitle('Plugins') self.setWindowTitle('Plugins')
self.setWindowIcon(QIcon(":/icons/logo.svg")) self.setWindowIcon(QIcon(":/icons/logo.png"))
self.setMinimumWidth(900) self.setMinimumWidth(900)
self.setMinimumHeight(600) self.setMinimumHeight(600)
self.plugins = list(Settings.Plugin().plugins) self.plugins = list(Settings.Plugin().plugins)
@ -57,7 +58,7 @@ class PluginDialog(QDialog):
plugin_directory = QFileDialog.getExistingDirectory(self, 'Select Plugin Directory', '.') plugin_directory = QFileDialog.getExistingDirectory(self, 'Select Plugin Directory', '.')
if plugin_directory is not None: if plugin_directory is not None:
info = PluginLoader.load_plugin_info(plugin_directory) info = PluginLoader.load_plugin_info(plugin_directory)
print(info) logging.info(info)
if info is not None: if info is not None:
try: try:
@ -73,6 +74,7 @@ class PluginDialog(QDialog):
self.plugin_table.insertRow(self.plugin_table.rowCount()) self.plugin_table.insertRow(self.plugin_table.rowCount())
name_item = QTableWidgetItem(info['name']) name_item = QTableWidgetItem(info['name'])
name_item.setIcon(QIcon(':/icons/tools.png'))
module_item = QTableWidgetItem(info['module']) module_item = QTableWidgetItem(info['module'])
enabled_item = QTableWidgetItem('启用') enabled_item = QTableWidgetItem('启用')
enabled_item.setCheckState(Qt.Checked) enabled_item.setCheckState(Qt.Checked)
@ -94,7 +96,8 @@ class PluginDialog(QDialog):
try: try:
shutil.rmtree(info['path']) shutil.rmtree(info['path'])
except Exception as e: except Exception as e:
print(e) # logging
logging.info(e)
pass pass
# for idx in self.plugins # for idx in self.plugins

View File

@ -1,4 +1,5 @@
import logging
from PyQt5 import QtCore, QtGui, QtWidgets from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtCore import Qt,QModelIndex, pyqtSignal from PyQt5.QtCore import Qt,QModelIndex, pyqtSignal
from PyQt5.QtGui import QStandardItemModel, QStandardItem from PyQt5.QtGui import QStandardItemModel, QStandardItem
@ -47,7 +48,8 @@ class ResultTable(QtWidgets.QWidget):
self.tablewidget.item(row, col).setBackground(Qt.yellow) self.tablewidget.item(row, col).setBackground(Qt.yellow)
else: else:
self.tablewidget.item(row, col).setBackground(Qt.green) 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.result.update({'row':item_idx, 'value':item_status})
self.no_change = False self.no_change = False

View File

@ -39,12 +39,16 @@ class MulStart:
sys.exit(0) sys.exit(0)
# Create and display the splash screen # Create and display the splash screen
splash_pix = QPixmap(':/icons/splash.png') splash_pix = QPixmap(':/icons/splash.png')
# splash_pix.scaledToWidth(800)
# splash_pix.scaledToHeight(600)
splash = QSplashScreen(splash_pix, Qt.WindowStaysOnTopHint) splash = QSplashScreen(splash_pix, Qt.WindowStaysOnTopHint)
# splash
# splash.setFixedSize(800, 600)
progressBar = QProgressBar(splash) progressBar = QProgressBar(splash)
progressBar.setMaximum(10) progressBar.setMaximum(10)
progressBar.setTextVisible(False) 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() splash.show()
for i in range(1, 11): for i in range(1, 11):

View File

@ -1,3 +1,4 @@
import logging
import shutil import shutil
from rscder.utils.setting import Settings from rscder.utils.setting import Settings
from PyQt5.QtWidgets import QMessageBox from PyQt5.QtWidgets import QMessageBox
@ -34,12 +35,13 @@ class PluginLoader(QObject):
module = importlib.import_module(os.path.basename(path)) module = importlib.import_module(os.path.basename(path))
mes = inspect.getmembers(module) mes = inspect.getmembers(module)
for name, obj in mes: for name, obj in mes:
print(name, obj) # logging
logging.info(name, obj)
if inspect.isclass(obj) and issubclass(obj, BasicPlugin): if inspect.isclass(obj) and issubclass(obj, BasicPlugin):
info = obj.info() info = obj.info()
break break
except Exception as e: except Exception as e:
print(e) logging.info(str(e))
QMessageBox.critical(None, 'Error', f'{path} load error: {e}') QMessageBox.critical(None, 'Error', f'{path} load error: {e}')
finally: finally:
sys.path.pop(0) sys.path.pop(0)

View File

@ -1,4 +1,5 @@
import base64 import base64
import logging
from Crypto.Cipher import AES from Crypto.Cipher import AES
import uuid import uuid
import hashlib import hashlib
@ -78,7 +79,7 @@ def get_aes():
class LicenseHelper(object): class LicenseHelper(object):
def generate_license(self, end_date, mac_addr): 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)) psw = self.hash_msg('smartant' + str(mac_addr))
license_str = {} license_str = {}
license_str['mac'] = mac_addr 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") lic_date_array = datetime.datetime.strptime(lic_date, "%Y-%m-%d %H:%M:%S")
remain_days = lic_date_array - current_time_array remain_days = lic_date_array - current_time_array
remain_days = remain_days.days remain_days = remain_days.days
print('lic data:{}'.format(lic_date)) logging.info('lic data:{}'.format(lic_date))
print('remain_days: {}'.format(remain_days)) logging.info('remain_days: {}'.format(remain_days))
if remain_days < 0 or remain_days == 0: if remain_days < 0 or remain_days == 0:
return False return False
else: else:
@ -138,6 +139,6 @@ if __name__ == '__main__':
license_dic = LicenseHelper().read_license(license_result) license_dic = LicenseHelper().read_license(license_result)
print(license_dic) logging.info(license_dic)

19
使用手册.txt Normal file
View File

@ -0,0 +1,19 @@
1. lic文件生成
点击RSCDer.exe,复制所显示的mac地址
点击keygen.exe,粘贴mac地址设置截止日期并选择保存路径无需输入后缀名
点击Generate
2. lic文件导入
点击RSCDer.exe点击Open选择生成的lic文件
点击OK
3. 新建项目与数据导入
点击RSCDer.exe
点击新建项目
选择路径、名称
将会在路径下看到与名称相同的文件夹
点击载入数据
选择两幅不同时相的影像
4. 基本变化检测

View File

@ -1,8 +0,0 @@
cell_size:
- 100
- 100
layers: []
max_memory: 100
max_threads: 4
results: []
root: F:\LZY_DATA\p122r032