修改字体
保存图层 恢复数据
This commit is contained in:
parent
b6a31e2e53
commit
274f6a3a10
@ -34,9 +34,9 @@ python setup.py
|
||||
|
||||
1. 证书检查与生成
|
||||
1. 基于MAC地址与过期时间进行证书生成,启动时检查证书,过期则退出
|
||||
2. 项目管理
|
||||
1. 以项目为单位进行数据管理与生产
|
||||
2. 提供项目保存与导入功能
|
||||
2. 工程管理
|
||||
1. 以工程为单位进行数据管理与生产
|
||||
2. 提供工程保存与导入功能
|
||||
3. 提供多种格式的栅格数据导入(TIF、PNG、BMP、JPG)等
|
||||
4. 提供矢量数据导入
|
||||
3. 基本工具
|
||||
|
@ -5,7 +5,7 @@ import os
|
||||
import pdb
|
||||
from threading import Thread
|
||||
import numpy as np
|
||||
from plugins.basic_change.main import MyDialog
|
||||
# from plugins.basic_change.main import MyDialog
|
||||
from rscder.gui.actions import ActionManager
|
||||
from rscder.plugins.basic import BasicPlugin
|
||||
from PyQt5.QtWidgets import QAction, QDialog, QHBoxLayout, QVBoxLayout, QPushButton,QWidget,QLabel,QLineEdit,QPushButton,QComboBox
|
||||
|
@ -1 +0,0 @@
|
||||
from basic_change.main import *
|
@ -1,116 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>Dialog</class>
|
||||
<widget class="QDialog" name="Dialog">
|
||||
<property name="windowModality">
|
||||
<enum>Qt::ApplicationModal</enum>
|
||||
</property>
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>700</width>
|
||||
<height>531</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>差分法</string>
|
||||
</property>
|
||||
<property name="sizeGripEnabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="0" column="0">
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QTabWidget" name="tabWidget">
|
||||
<property name="tabPosition">
|
||||
<enum>QTabWidget::West</enum>
|
||||
</property>
|
||||
<property name="currentIndex">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="elideMode">
|
||||
<enum>Qt::ElideNone</enum>
|
||||
</property>
|
||||
<property name="usesScrollButtons">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="documentMode">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="tabsClosable">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="movable">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<widget class="QWidget" name="tab">
|
||||
<attribute name="title">
|
||||
<string>基础设置</string>
|
||||
</attribute>
|
||||
<layout class="QGridLayout" name="gridLayout_2">
|
||||
<item row="0" column="0">
|
||||
<layout class="QFormLayout" name="formLayout_5">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="1Label">
|
||||
<property name="text">
|
||||
<string>时相1影像</string>
|
||||
</property>
|
||||
<property name="margin">
|
||||
<number>7</number>
|
||||
</property>
|
||||
<property name="indent">
|
||||
<number>5</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="2Label">
|
||||
<property name="text">
|
||||
<string>时相2影像</string>
|
||||
</property>
|
||||
<property name="margin">
|
||||
<number>7</number>
|
||||
</property>
|
||||
<property name="indent">
|
||||
<number>5</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QLineEdit" name="2LineEdit"/>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLineEdit" name="1LineEdit">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="tab_2">
|
||||
<attribute name="title">
|
||||
<string>后处理</string>
|
||||
</attribute>
|
||||
</widget>
|
||||
<widget class="QWidget" name="tab_3">
|
||||
<attribute name="title">
|
||||
<string>阈值化</string>
|
||||
</attribute>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
@ -1,191 +0,0 @@
|
||||
import math
|
||||
import os
|
||||
from rscder.gui.actions import ActionManager
|
||||
from rscder.plugins.basic import BasicPlugin
|
||||
from PyQt5.QtWidgets import QAction, QDialog, QHBoxLayout, QVBoxLayout, QPushButton
|
||||
from PyQt5.QtCore import pyqtSignal
|
||||
from PyQt5.QtGui import QIcon
|
||||
from rscder.utils.icons import IconInstance
|
||||
from rscder.utils.project import BasicLayer, Project, RasterLayer, SingleBandRasterLayer
|
||||
from rscder.gui.layercombox import PairLayerCombox
|
||||
from osgeo import gdal
|
||||
from threading import Thread
|
||||
import numpy as np
|
||||
|
||||
class MyDialog(QDialog):
|
||||
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent)
|
||||
|
||||
self.setWindowTitle('差分法')
|
||||
self.setWindowIcon(IconInstance().LOGO)
|
||||
|
||||
# self.setFixedWidth(500)
|
||||
|
||||
self.layer_select = PairLayerCombox(self)
|
||||
|
||||
# self.number_input = QLineEdit(self)
|
||||
|
||||
self.ok_button = QPushButton('确定', self)
|
||||
self.ok_button.setIcon(IconInstance().OK)
|
||||
self.ok_button.clicked.connect(self.on_ok)
|
||||
|
||||
self.cancel_button = QPushButton('取消', self)
|
||||
self.cancel_button.setIcon(IconInstance().CANCEL)
|
||||
self.cancel_button.clicked.connect(self.on_cancel)
|
||||
|
||||
self.button_layout = QHBoxLayout()
|
||||
self.button_layout.addWidget(self.ok_button)
|
||||
self.button_layout.addWidget(self.cancel_button)
|
||||
|
||||
self.main_layout = QVBoxLayout()
|
||||
self.main_layout.addWidget(self.layer_select)
|
||||
|
||||
self.main_layout.addLayout(self.button_layout)
|
||||
self.setLayout(self.main_layout)
|
||||
|
||||
def on_ok(self):
|
||||
if self.layer_select.layer1 is None or self.layer_select.layer2 is None:
|
||||
self.reject()
|
||||
return
|
||||
self.accept()
|
||||
|
||||
def on_cancel(self):
|
||||
self.reject()
|
||||
|
||||
|
||||
|
||||
class BasicMethod(BasicPlugin):
|
||||
|
||||
result_ok = pyqtSignal(dict)
|
||||
|
||||
@staticmethod
|
||||
def info():
|
||||
return {
|
||||
'name': 'BasicMethod',
|
||||
'description': 'BasicMethod',
|
||||
'author': 'RSCDER',
|
||||
'version': '1.0.0',
|
||||
}
|
||||
|
||||
def set_action(self):
|
||||
|
||||
basic_diff_method = QAction('差分法')
|
||||
ActionManager().unsupervised_menu.addAction(basic_diff_method)
|
||||
basic_diff_method.setEnabled(False)
|
||||
self.basic_diff_method = basic_diff_method
|
||||
basic_diff_method.triggered.connect(self.basic_diff_alg)
|
||||
|
||||
def setup(self):
|
||||
self.basic_diff_method.setEnabled(True)
|
||||
|
||||
def run_basic_diff_alg(self, layer1:RasterLayer, layer2:RasterLayer):
|
||||
|
||||
pth1 = layer1.path
|
||||
pth2 = layer2.path
|
||||
|
||||
|
||||
|
||||
cell_size = layer1.layer_parent.cell_size
|
||||
|
||||
self.send_message.emit('开始计算差分法')
|
||||
|
||||
ds1 = gdal.Open(pth1)
|
||||
ds2 = gdal.Open(pth2)
|
||||
if not layer1.compare(layer2):
|
||||
self.send_message.emit('两个图层的尺寸不同')
|
||||
return
|
||||
xsize = ds1.RasterXSize
|
||||
ysize = ds1.RasterYSize
|
||||
band = ds1.RasterCount
|
||||
yblocks = ysize // cell_size[1]
|
||||
|
||||
driver = gdal.GetDriverByName('GTiff')
|
||||
out_tif = os.path.join(Project().cmi_path, 'temp.tif')
|
||||
out_ds = driver.Create(out_tif, xsize, ysize, 1, gdal.GDT_Float32)
|
||||
out_ds.SetGeoTransform(ds1.GetGeoTransform())
|
||||
out_ds.SetProjection(ds1.GetProjection())
|
||||
max_diff = 0
|
||||
min_diff = math.inf
|
||||
for j in range(yblocks + 1):
|
||||
|
||||
self.send_message.emit(f'计算{j}/{yblocks}')
|
||||
block_xy = (0, j * cell_size[1])
|
||||
if block_xy[1] > ysize:
|
||||
break
|
||||
block_size = (xsize, cell_size[1])
|
||||
if block_xy[1] + block_size[1] > ysize:
|
||||
block_size = (xsize, ysize - block_xy[1])
|
||||
block_data1 = ds1.ReadAsArray(*block_xy, *block_size)
|
||||
block_data2 = ds2.ReadAsArray(*block_xy, *block_size)
|
||||
|
||||
if band == 1:
|
||||
block_data1 = block_data1[None, ...]
|
||||
block_data2 = block_data2[None, ...]
|
||||
# pdb.set_trace()
|
||||
block_diff = block_data1.sum(0) - block_data2.sum(0)
|
||||
block_diff = block_diff.astype(np.float32)
|
||||
block_diff = np.abs(block_diff)
|
||||
|
||||
min_diff = min(min_diff, block_diff[block_diff > 0].min())
|
||||
max_diff = max(max_diff, block_diff.max())
|
||||
out_ds.GetRasterBand(1).WriteArray(block_diff, *block_xy)
|
||||
|
||||
self.send_message.emit(f'完成{j}/{yblocks}')
|
||||
|
||||
out_ds.FlushCache()
|
||||
del out_ds
|
||||
self.send_message.emit('归一化概率中...')
|
||||
temp_in_ds = gdal.Open(out_tif)
|
||||
|
||||
out_normal_tif = os.path.join(Project().cmi_path, '{}_{}_cmi.tif'.format(layer1.layer_parent.name, int(np.random.rand() * 100000)))
|
||||
out_normal_ds = driver.Create(out_normal_tif, xsize, ysize, 1, gdal.GDT_Byte)
|
||||
out_normal_ds.SetGeoTransform(ds1.GetGeoTransform())
|
||||
out_normal_ds.SetProjection(ds1.GetProjection())
|
||||
# hist = np.zeros(256, dtype=np.int32)
|
||||
for j in range(yblocks+1):
|
||||
block_xy = (0, j * cell_size[1])
|
||||
if block_xy[1] > ysize:
|
||||
break
|
||||
block_size = (xsize, cell_size[1])
|
||||
if block_xy[1] + block_size[1] > ysize:
|
||||
block_size = (xsize, ysize - block_xy[1])
|
||||
block_data = temp_in_ds.ReadAsArray(*block_xy, *block_size)
|
||||
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, range=(0, 256))
|
||||
# hist += hist_t
|
||||
# print(hist)
|
||||
del temp_in_ds
|
||||
del out_normal_ds
|
||||
try:
|
||||
os.remove(out_tif)
|
||||
except:
|
||||
pass
|
||||
|
||||
raster_result_layer = SingleBandRasterLayer(None, True, out_normal_tif, BasicLayer.BOATH_VIEW)
|
||||
|
||||
# layer1.layer_parent.add_result_layer(point_result_lalyer)
|
||||
layer1.layer_parent.add_result_layer(raster_result_layer)
|
||||
|
||||
# self.send_message.emit('完成计算变化表格')
|
||||
|
||||
self.send_message.emit('差分法计算完成')
|
||||
|
||||
def basic_diff_alg(self):
|
||||
# layer_select =
|
||||
|
||||
layer_select = MyDialog(self.mainwindow)
|
||||
if layer_select.exec_():
|
||||
layer1 = layer_select.layer_select.layer1
|
||||
layer2 = layer_select.layer_select.layer2
|
||||
else:
|
||||
return
|
||||
# layer:PairLayer = list(self.project.layers.values())[0]
|
||||
|
||||
t = Thread(target=self.run_basic_diff_alg, args=(layer1, layer2))
|
||||
t.start()
|
||||
|
||||
|
||||
|
@ -50,12 +50,28 @@ class RateSetdialog(QDialog):
|
||||
vlayout.addLayout(h2)
|
||||
vlayout.addLayout(self.button_layout)
|
||||
self.setLayout(vlayout)
|
||||
|
||||
self.old_data = None
|
||||
|
||||
def on_ok(self):
|
||||
self.onclose()
|
||||
self.accept()
|
||||
|
||||
def on_cancel(self):
|
||||
if self.layer_select.current_layer is not None:
|
||||
self.layer_select.current_layer.data = self.layer_select.current_layer.old_data
|
||||
self.layer_select.current_layer.update_point_layer(-1)
|
||||
self.reject()
|
||||
|
||||
def onclose(self) -> None:
|
||||
if self.layer_select.current_layer is not None:
|
||||
self.layer_select.current_layer.save()
|
||||
|
||||
def closeEvent(self, a0) -> None:
|
||||
if self.layer_select.current_layer is not None:
|
||||
self.layer_select.current_layer.data = self.layer_select.current_layer.old_data
|
||||
self.layer_select.current_layer.update_point_layer(-1)
|
||||
|
||||
|
||||
class RateSetPlugin(BasicPlugin):
|
||||
current_layer=None
|
||||
@ -81,6 +97,9 @@ class RateSetPlugin(BasicPlugin):
|
||||
dialog.show()
|
||||
def currentLayer(self,layer):
|
||||
self.current_layer=layer
|
||||
if not isinstance(layer,ResultPointLayer):
|
||||
return
|
||||
layer.old_data = layer.data.copy()
|
||||
|
||||
|
||||
def setrate(self,input:int):
|
||||
@ -96,4 +115,4 @@ class RateSetPlugin(BasicPlugin):
|
||||
layer.update_point_layer(-1)
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -5,13 +5,6 @@
|
||||
name: "\u5173\u4E8E"
|
||||
path: ./plugin\about
|
||||
version: 1.0.0
|
||||
- author: RSCDER
|
||||
description: BasicMethod
|
||||
enabled: false
|
||||
module: basic_change
|
||||
name: BasicMethod
|
||||
path: ./plugin\basic_change
|
||||
version: 1.0.0
|
||||
- author: RSCDER
|
||||
description: ExportTo
|
||||
enabled: true
|
||||
@ -26,20 +19,6 @@
|
||||
name: MeanFilter
|
||||
path: ./plugin\some_filter
|
||||
version: 1.0.0
|
||||
- author: RSCDER
|
||||
description: OTSU
|
||||
enabled: false
|
||||
module: threshold
|
||||
name: OTSU
|
||||
path: ./plugin\threshold
|
||||
version: 1.0.0
|
||||
- author: RSCDER
|
||||
description: TableResult
|
||||
enabled: true
|
||||
module: table_result
|
||||
name: TableResult
|
||||
path: ./plugin\table_result
|
||||
version: 1.0.0
|
||||
- author: RSCDER
|
||||
description: Evaluation
|
||||
enabled: true
|
||||
|
@ -1 +0,0 @@
|
||||
from table_result.main import *
|
@ -1,112 +0,0 @@
|
||||
import os
|
||||
from threading import Thread
|
||||
from rscder.gui.actions import ActionManager
|
||||
from rscder.gui.layercombox import RasterLayerCombox, ResultLayercombox
|
||||
from rscder.plugins.basic import BasicPlugin
|
||||
from PyQt5.QtWidgets import QAction, QDialog, QLabel, QHBoxLayout, QVBoxLayout, QPushButton
|
||||
from PyQt5.QtCore import pyqtSignal
|
||||
from PyQt5.QtGui import QIcon
|
||||
from rscder.utils.icons import IconInstance
|
||||
|
||||
from rscder.utils.project import Project, ResultPointLayer, SingleBandRasterLayer
|
||||
from osgeo import gdal
|
||||
class TableResultDialog(QDialog):
|
||||
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent)
|
||||
|
||||
self.setWindowTitle('表格结果')
|
||||
self.setWindowIcon(IconInstance().LOGO)
|
||||
|
||||
self.layer_select = ResultLayercombox(self)
|
||||
hbox = QHBoxLayout()
|
||||
hbox.addWidget(QLabel('二值化结果图层:'))
|
||||
hbox.addWidget(self.layer_select)
|
||||
|
||||
self.ok_button = QPushButton('确定', self)
|
||||
self.ok_button.setIcon(IconInstance().OK)
|
||||
self.ok_button.clicked.connect(self.on_ok)
|
||||
|
||||
self.cancel_button = QPushButton('取消', self)
|
||||
self.cancel_button.setIcon(IconInstance().CANCEL)
|
||||
self.cancel_button.clicked.connect(self.on_cancel)
|
||||
|
||||
self.button_layout = QHBoxLayout()
|
||||
self.button_layout.addWidget(self.ok_button)
|
||||
self.button_layout.addWidget(self.cancel_button)
|
||||
|
||||
self.main_layout = QVBoxLayout()
|
||||
self.main_layout.addLayout(hbox)
|
||||
self.main_layout.addLayout(self.button_layout)
|
||||
self.setLayout(self.main_layout)
|
||||
|
||||
def on_ok(self):
|
||||
self.accept()
|
||||
|
||||
def on_cancel(self):
|
||||
self.reject()
|
||||
|
||||
|
||||
class TableResultPlugin(BasicPlugin):
|
||||
|
||||
@staticmethod
|
||||
def info():
|
||||
return {
|
||||
'name': 'TableResult',
|
||||
'author': 'RSC',
|
||||
'version': '1.0.0',
|
||||
'description': '表格结果'
|
||||
}
|
||||
|
||||
def set_action(self):
|
||||
self.action = QAction(IconInstance().VECTOR, '表格结果', self.mainwindow)
|
||||
self.action.triggered.connect(self.show_dialog)
|
||||
ActionManager().position_menu.addAction(self.action)
|
||||
|
||||
def run(self, layer:SingleBandRasterLayer):
|
||||
self.send_message.emit('正在计算表格结果...')
|
||||
if not isinstance(layer, SingleBandRasterLayer):
|
||||
self.send_message.emit('请选择一个单波段栅格图层')
|
||||
return
|
||||
|
||||
cell_size = layer.layer_parent.cell_size
|
||||
ds = gdal.Open(layer.path)
|
||||
xsize = ds.RasterXSize
|
||||
ysize = ds.RasterYSize
|
||||
geo = ds.GetGeoTransform()
|
||||
|
||||
out_csv = os.path.join(Project().other_path, f'{layer.name}_table_result.csv')
|
||||
yblocks = ysize // cell_size[1] + 1
|
||||
xblocks = xsize // cell_size[0] + 1
|
||||
with open(out_csv, 'w') as f:
|
||||
f.write('x,y,diff,status\n')
|
||||
for j in range(yblocks):
|
||||
block_xy = (0, j * cell_size[1])
|
||||
block_size = (xsize, cell_size[1])
|
||||
if block_xy[1] + block_size[1] > ysize:
|
||||
block_size = (xsize, ysize - block_xy[1])
|
||||
block_data = ds.ReadAsArray(*block_xy, *block_size)
|
||||
for i in range(xblocks):
|
||||
start_x = i * cell_size[0]
|
||||
end_x = start_x + cell_size[0]
|
||||
if end_x > xsize:
|
||||
end_x = xsize
|
||||
block_data_xy = block_data[:, start_x:end_x]
|
||||
if block_data_xy.mean() > 0.5:
|
||||
center_x = start_x + cell_size[0] // 2
|
||||
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() * 100},1\n')
|
||||
|
||||
result_layer = ResultPointLayer(out_csv, enable=True, proj=layer.proj, geo=layer.geo)
|
||||
layer.layer_parent.add_result_layer(result_layer)
|
||||
self.send_message.emit('计算完成')
|
||||
|
||||
|
||||
def show_dialog(self):
|
||||
dialog = TableResultDialog()
|
||||
if dialog.exec_() == QDialog.Accepted:
|
||||
if dialog.layer_select.current_layer is not None:
|
||||
t = Thread(target=self.run, args=(dialog.layer_select.current_layer,))
|
||||
t.start()
|
@ -1 +0,0 @@
|
||||
from threshold.main import *
|
@ -1,163 +0,0 @@
|
||||
import os
|
||||
import pdb
|
||||
from threading import Thread
|
||||
import numpy as np
|
||||
from rscder.gui.actions import ActionManager
|
||||
from rscder.plugins.basic import BasicPlugin
|
||||
from PyQt5.QtWidgets import QAction, QDialog, QHBoxLayout, QVBoxLayout, QPushButton
|
||||
from PyQt5.QtGui import QIcon
|
||||
from PyQt5.QtCore import Qt
|
||||
from rscder.gui.layercombox import RasterLayerCombox
|
||||
from rscder.utils.icons import IconInstance
|
||||
from rscder.utils.project import Project, RasterLayer, SingleBandRasterLayer
|
||||
from threshold.otsu import OTSU
|
||||
from osgeo import gdal
|
||||
class OTSUDialog(QDialog):
|
||||
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent)
|
||||
|
||||
self.setWindowTitle('OTSU阈值')
|
||||
self.setWindowIcon(IconInstance().LOGO)
|
||||
|
||||
self.setFixedWidth(500)
|
||||
|
||||
self.layercombox = RasterLayerCombox(self)
|
||||
|
||||
|
||||
|
||||
self.ok_button = QPushButton('确定', self)
|
||||
self.ok_button.setIcon(IconInstance().OK)
|
||||
self.ok_button.clicked.connect(self.on_ok)
|
||||
|
||||
self.cancel_button = QPushButton('取消', self)
|
||||
self.cancel_button.setIcon(IconInstance().CANCEL)
|
||||
self.cancel_button.clicked.connect(self.on_cancel)
|
||||
|
||||
self.button_layout = QHBoxLayout()
|
||||
self.button_layout.addWidget(self.ok_button)
|
||||
self.button_layout.addWidget(self.cancel_button)
|
||||
|
||||
self.main_layout = QVBoxLayout()
|
||||
self.main_layout.addWidget(self.layercombox)
|
||||
self.main_layout.addLayout(self.button_layout)
|
||||
self.setLayout(self.main_layout)
|
||||
|
||||
def on_ok(self):
|
||||
self.accept()
|
||||
|
||||
def on_cancel(self):
|
||||
self.reject()
|
||||
|
||||
|
||||
class OTSUPlugin(BasicPlugin):
|
||||
|
||||
@staticmethod
|
||||
def info():
|
||||
return {
|
||||
"name": "OTSU",
|
||||
"description": "OTSU阈值",
|
||||
"author": "rscder",
|
||||
"version": "1.0.0"
|
||||
}
|
||||
|
||||
def set_action(self):
|
||||
self.action = QAction('OTSU阈值', self.mainwindow)
|
||||
self.action.triggered.connect(self.run)
|
||||
ActionManager().postop_menu.addAction(self.action)
|
||||
|
||||
def run(self):
|
||||
dialog = OTSUDialog(self.mainwindow)
|
||||
if dialog.exec_() == QDialog.Accepted:
|
||||
t = Thread(target=self.run_alg, args=(dialog.layercombox.current_layer,))
|
||||
t.start()
|
||||
|
||||
def run_alg(self, layer:RasterLayer):
|
||||
if layer is None or layer.path is None:
|
||||
return
|
||||
ds = gdal.Open(layer.path)
|
||||
band = ds.GetRasterBand(1)
|
||||
band_count = ds.RasterCount
|
||||
if band_count > 1:
|
||||
self.message_box.error('请选择符合要求的图层')
|
||||
return
|
||||
hist = np.zeros(256, dtype=np.int)
|
||||
xsize = ds.RasterXSize
|
||||
ysize = ds.RasterYSize
|
||||
|
||||
max_pixels = 1e7
|
||||
max_rows = max_pixels // xsize
|
||||
if max_rows < 1:
|
||||
max_rows = 1
|
||||
if max_rows > ysize:
|
||||
max_rows = ysize
|
||||
block_count = ysize // max_rows + 1
|
||||
for i in range(block_count):
|
||||
start_row = i * max_rows
|
||||
end_row = min((i + 1) * max_rows, ysize)
|
||||
block = band.ReadAsArray(0, start_row, xsize, end_row - start_row)
|
||||
hist += np.histogram(block.flatten(), bins=256, range=(0, 255))[0]
|
||||
hist = hist.astype(np.float32)
|
||||
gap = OTSU(hist)
|
||||
self.send_message.emit('阈值为:{}'.format(gap))
|
||||
|
||||
out_th = os.path.join(Project().bcdm_path, '{}_otsu_bcdm.tif'.format(layer.name))
|
||||
out_ds = gdal.GetDriverByName('GTiff').Create(out_th, xsize, ysize, 1, gdal.GDT_Byte)
|
||||
out_ds.SetGeoTransform(ds.GetGeoTransform())
|
||||
out_ds.SetProjection(ds.GetProjection())
|
||||
out_band = out_ds.GetRasterBand(1)
|
||||
|
||||
for i in range(block_count):
|
||||
start_row = i * max_rows
|
||||
end_row = min((i + 1) * max_rows, ysize)
|
||||
block = band.ReadAsArray(0, start_row, xsize, end_row - start_row)
|
||||
out_band.WriteArray(block > gap, 0, start_row)
|
||||
out_band.FlushCache()
|
||||
out_ds = None
|
||||
ds = None
|
||||
self.send_message.emit('OTSU阈值完成')
|
||||
|
||||
otsu_layer = SingleBandRasterLayer(path = out_th, style_info={})
|
||||
layer.layer_parent.add_result_layer(otsu_layer)
|
||||
|
||||
|
||||
# otsu_method = QAction('OTSU阈值分割')
|
||||
# postop_menu = self.ctx['postop_menu']
|
||||
# postop_menu.addAction(otsu_method)
|
||||
# otsu_method.setEnabled(False)
|
||||
# point_result_lalyer = ResultPointLayer(out_csv, enable=False, proj = layer1.proj, geo = layer1.geo)
|
||||
# self.gap = OTSU(hist)
|
||||
|
||||
# self.message_send.emit('OTSU:' + str(self.gap))
|
||||
|
||||
# out_normal_ds.FlushCache()
|
||||
# del out_normal_ds
|
||||
# self.message_send.emit('完成归一化概率')
|
||||
|
||||
# self.message_send.emit('计算变化表格中...')
|
||||
# out_csv = os.path.join(Project().bcdm_path, '{}-{}.csv'.format(layer1.layer_parent.name, int(np.random.rand() * 100000)))
|
||||
# xblocks = xsize // cell_size[0]
|
||||
|
||||
# normal_in_ds = gdal.Open(out_normal_tif)
|
||||
|
||||
# with open(out_csv, 'w') as f:
|
||||
# f.write('x,y,diff,status\n')
|
||||
# for j in range(yblocks):
|
||||
# block_xy = (0, j * cell_size[1])
|
||||
# block_size = (xsize, cell_size[1])
|
||||
# if block_xy[1] + block_size[1] > ysize:
|
||||
# block_size = (xsize, ysize - block_xy[1])
|
||||
# block_data = normal_in_ds.ReadAsArray(*block_xy, *block_size)
|
||||
# for i in range(xblocks):
|
||||
# start_x = i * cell_size[0]
|
||||
# end_x = start_x + cell_size[0]
|
||||
# if end_x > xsize:
|
||||
# end_x = xsize
|
||||
# block_data_xy = block_data[:, start_x:end_x]
|
||||
# if block_data_xy.mean() > self.gap:
|
||||
# center_x = start_x + cell_size[0] // 2
|
||||
# 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 * 100},1\n')
|
||||
|
@ -1,42 +0,0 @@
|
||||
import numpy as np
|
||||
|
||||
def OTSU(hist):
|
||||
|
||||
u1=0.0#背景像素的平均灰度值
|
||||
u2=0.0#前景像素的平均灰度值
|
||||
th=0.0
|
||||
|
||||
#总的像素数目
|
||||
PixSum= np.sum(hist)
|
||||
#各灰度值所占总像素数的比例
|
||||
PixRate=hist / PixSum
|
||||
#统计各个灰度值的像素个数
|
||||
Max_var = 0
|
||||
#确定最大类间方差对应的阈值
|
||||
GrayScale = len(hist)
|
||||
for i in range(1,len(hist)):#从1开始是为了避免w1为0.
|
||||
u1_tem=0.0
|
||||
u2_tem=0.0
|
||||
#背景像素的比列
|
||||
w1=np.sum(PixRate[:i])
|
||||
#前景像素的比例
|
||||
w2=1.0-w1
|
||||
if w1==0 or w2==0:
|
||||
pass
|
||||
else:#背景像素的平均灰度值
|
||||
for m in range(i):
|
||||
u1_tem=u1_tem+PixRate[m]*m
|
||||
u1 = u1_tem * 1.0 / w1
|
||||
#前景像素的平均灰度值
|
||||
for n in range(i,GrayScale):
|
||||
u2_tem = u2_tem + PixRate[n]*n
|
||||
u2 = u2_tem / w2
|
||||
#print(u1)
|
||||
#类间方差公式:G=w1*w2*(u1-u2)**2
|
||||
tem_var=w1*w2*np.power((u1-u2),2)
|
||||
#print(tem_var)
|
||||
#判断当前类间方差是否为最大值。
|
||||
if Max_var<tem_var:
|
||||
Max_var=tem_var#深拷贝,Max_var与tem_var占用不同的内存空间。
|
||||
th=i
|
||||
return th
|
@ -194,17 +194,17 @@ class ActionManager(QtCore.QObject):
|
||||
project.cell_size = projec_create.cell_size
|
||||
project.max_memory = projec_create.max_memory
|
||||
project.save()
|
||||
self.message_box.info('项目创建成功')
|
||||
self.message_box.info('工程创建成功')
|
||||
|
||||
def project_init(self, state):
|
||||
# self.message_box.info('项目初始化完成')
|
||||
# self.message_box.info('工程初始化完成')
|
||||
for group in self.action_groups.keys():
|
||||
# self.message_box.info('%s:' % (group))
|
||||
for action in self.action_groups[group].actions():
|
||||
action.setEnabled(state)
|
||||
# self.message_box.info('\t%s' % (action.text()))
|
||||
|
||||
self.message_box.info('项目初始化完成')
|
||||
self.message_box.info('工程初始化完成')
|
||||
|
||||
def project_open(self):
|
||||
if Project().is_init:
|
||||
|
@ -10,7 +10,7 @@ class Create(QDialog):
|
||||
|
||||
def __init__(self, parent=None) -> None:
|
||||
super().__init__(parent)
|
||||
self.setWindowTitle(self.tr('创建项目'))
|
||||
self.setWindowTitle(self.tr('创建工程'))
|
||||
self.setWindowIcon(IconInstance().LOGO)
|
||||
|
||||
self.file = str(Path(Settings.General().last_path))
|
||||
@ -18,11 +18,11 @@ class Create(QDialog):
|
||||
self.max_memory = Settings.Project().max_memory
|
||||
self.cell_size = Settings.Project().cell_size
|
||||
|
||||
file_label = QLabel('项目目录:')
|
||||
file_label = QLabel('工程目录:')
|
||||
file_label.setFixedWidth(100)
|
||||
file_input = QLineEdit()
|
||||
file_input.setPlaceholderText('项目目录')
|
||||
file_input.setToolTip('项目目录')
|
||||
file_input.setPlaceholderText('工程目录')
|
||||
file_input.setToolTip('工程目录')
|
||||
file_input.setReadOnly(True)
|
||||
file_input.setText(self.file)
|
||||
self.file_input = file_input
|
||||
@ -32,11 +32,11 @@ class Create(QDialog):
|
||||
file_open.clicked.connect(self.open_file)
|
||||
|
||||
|
||||
name_label = QLabel('项目名称:')
|
||||
name_label = QLabel('工程名称:')
|
||||
name_label.setFixedWidth(100)
|
||||
name_input = QLineEdit()
|
||||
name_input.setPlaceholderText('项目名称')
|
||||
name_input.setToolTip('项目名称')
|
||||
name_input.setPlaceholderText('工程名称')
|
||||
name_input.setToolTip('工程名称')
|
||||
name_input.setText(self.name)
|
||||
self.name_input = name_input
|
||||
|
||||
@ -116,7 +116,7 @@ class Create(QDialog):
|
||||
self.max_memory = self.max_memory_input.text()
|
||||
self.cell_size = (self.cell_size_x_input.text(), self.cell_size_y_input.text())
|
||||
if self.name == '':
|
||||
QMessageBox.warning(self, 'Warning', '请选择项目目录!')
|
||||
QMessageBox.warning(self, 'Warning', '请选择工程目录!')
|
||||
return
|
||||
if self.max_memory == '':
|
||||
QMessageBox.warning(self, 'Warning', '请输入最大文件大小!')
|
||||
|
@ -109,7 +109,7 @@ class Project(QObject):
|
||||
self.file = path
|
||||
self.root = os.path.split(path)[0]
|
||||
else:
|
||||
self.message_box.error('打开或创建项目失败')
|
||||
self.message_box.error('打开或创建工程失败')
|
||||
try:
|
||||
if not os.path.exists(self.root):
|
||||
os.makedirs(self.root, exist_ok=True)
|
||||
@ -122,7 +122,7 @@ class Project(QObject):
|
||||
self.is_init = True
|
||||
self.project_init.emit(True)
|
||||
except:
|
||||
self.message_box.error('打开或创建项目失败')
|
||||
self.message_box.error('打开或创建工程失败')
|
||||
|
||||
def save(self):
|
||||
data_dict = {
|
||||
@ -461,7 +461,7 @@ class VectorLayer(BasicLayer):
|
||||
|
||||
class ResultPointLayer(BasicLayer):
|
||||
|
||||
def __init__(self, path, name=None, enable = False, proj = None, geo = None,result_path={},dsort=True ):
|
||||
def __init__(self, path, name=None, enable = False, proj = None, geo = None,result_path={},dsort=False ):
|
||||
if name is None:
|
||||
name = os.path.splitext(os.path.basename(path))[0]
|
||||
super().__init__(name, enable, icon=IconInstance().VECTOR, path=path, path_mode = BasicLayer.IN_FILE, view_mode=BasicLayer.BOATH_VIEW )
|
||||
@ -470,6 +470,7 @@ class ResultPointLayer(BasicLayer):
|
||||
self.geo = geo
|
||||
self.dsort=dsort
|
||||
self.result_path=result_path
|
||||
|
||||
self.load_point_file()
|
||||
|
||||
def save(self):
|
||||
@ -492,12 +493,13 @@ class ResultPointLayer(BasicLayer):
|
||||
lyr.enabled = True
|
||||
lyr.fieldName = 'prob'
|
||||
lyr.placement = QgsPalLayerSettings.OverPoint
|
||||
lyr.xOffset = 2
|
||||
lyr.xOffset = 25
|
||||
lyr.yOffset = -2
|
||||
lyr.textFont = QFont('Times New Roman', 100)
|
||||
text_format = QgsTextFormat()
|
||||
text_format.setFont(lyr.textFont)
|
||||
text_format.color = QColor('#000000')
|
||||
text_format.setSize(50)
|
||||
text_format.setColor(QColor('#FF0000'))
|
||||
# text_format.background().color = QColor('#000000')
|
||||
text_format.buffer().setEnabled(True)
|
||||
text_format.buffer().setSize(1)
|
||||
@ -530,7 +532,7 @@ class ResultPointLayer(BasicLayer):
|
||||
if self.dsort:
|
||||
data=data[data[:,-2].argsort()]
|
||||
else:
|
||||
data=data[-(data[:,-2]).argsort()]
|
||||
data=data[(-data[:,-2]).argsort()]
|
||||
self.data = data
|
||||
self.make_point_layer()
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user