Merge branch 'dev-pyramid'

This commit is contained in:
copper 2022-09-30 17:26:27 +08:00
commit 7380f5d94a
55 changed files with 127468 additions and 789 deletions

3
ECD.py
View File

@ -1,13 +1,10 @@
import os
import sys
import argparse
sys.path.insert(0, os.path.join(os.path.dirname(__file__), 'libs'))
os.environ['PROJ_LIB'] = os.path.join(os.path.dirname(__file__), 'share/proj')
os.environ['GDAL_DATA'] = os.path.join(os.path.dirname(__file__), 'share')
os.environ['ECD_BASEDIR'] = os.path.dirname(__file__)
BASE_DIR = os.path.dirname(__file__)
import distutils
import distutils.version
from rscder import MulStart
import logging

View File

@ -4,62 +4,30 @@ channels:
- defaults
dependencies:
- cryptography=3.4.7=py37h20c650d_0
- curl=7.79.0=h789b8ee_0
- cycler=0.10.0=py_2
- cytoolz=0.11.0=py37hcc03f2d_3
- dask-core=2021.9.1=pyhd8ed1ab_0
- decorator=5.1.0=pyhd8ed1ab_0
- future=0.18.2=py37h03978a9_3
- gdal=3.3.1=py37hb11e9a8_2
- geos=3.9.1=h39d44d4_2
- geotiff=1.6.0=ha8a8a2d_6
- gettext=0.19.8.1=ha2e2712_1006
- giflib=5.2.1=h8d14728_2
- gsl=2.7=hdfb1a43_0
- m2w64-gcc-libgfortran=5.3.0=6
- m2w64-gcc-libs=5.3.0=7
- m2w64-gcc-libs-core=5.3.0=7
- m2w64-gmp=6.1.0=2
- m2w64-libwinpthread-git=5.0.0.4634.697f757=2
- markupsafe=2.0.1=py37hcc03f2d_0
- numpy=1.21.2=py37h940b05c_0
- opencv=4.5.3=py37h03978a9_1
- pip=21.2.4=pyhd8ed1ab_0
- proj=8.0.1=h1cfcee9_0
- psycopg2=2.9.1=py37hd8e9650_0
- py-opencv=4.5.3=py37h4038f58_1
- pycodestyle=2.7.0=pyhd8ed1ab_0
- pycparser=2.20=pyh9f0ad1d_2
- pygments=2.10.0=pyhd8ed1ab_0
- pylint=2.11.1=pyhd8ed1ab_0
- pyproj=3.2.1=py37h9f67652_0
- pyqt=5.12.3=py37h03978a9_7
- pysnooper=0.5.0=pyhd8ed1ab_0
- pysocks=1.7.1=py37h03978a9_3
- python=3.7.10=h7840368_101_cpython
- python-dateutil=2.8.2=pyhd8ed1ab_0
- python_abi=3.7=2_cp37m
- pytz=2021.1=pyhd8ed1ab_0
- pywavelets=1.1.1=py37hec80d1f_3
- pywin32=301=py37hcc03f2d_0
- pyyaml=5.4.1=py37hcc03f2d_1
- qgis=3.18.3=py37h3dc7164_2
- qt=5.12.9=h5909a2a_4
- qtkeychain=0.12.0=h552f0f6_0
- qtlocation=5.12.9=ha925a31_0
- qtpy=1.11.1=pyhd8ed1ab_0
- scikit-image=0.18.3=py37h9386db6_0
- scipy=1.7.1=py37hb6553fb_0
- setuptools=58.0.4=py37h03978a9_1
- six=1.16.0=pyh6c4a22f_0
- snappy=1.1.8=ha925a31_3
- sqlite=3.36.0=h8ffe710_1
- tenacity=8.0.1=pyhd8ed1ab_0
- typed-ast=1.4.3=py37hcc03f2d_0
- typing-extensions=3.10.0.2=hd8ed1ab_0
- typing_extensions=3.10.0.2=pyha770c72_0
- ucrt=10.0.20348.0=h57928b3_0
- urllib3=1.26.6=pyhd8ed1ab_0
- yaml=0.2.5=he774522_0
- pip:
- attrs==21.4.0

View File

@ -1 +1 @@
IieXktda+1nRK9zLwe87uPPn2VpCwmUrEOPfyenaW/Sek70/CqqbCr7nangL1+pVXSkzDELia7Qq8e+pDMuHCXzxyJOALRj4j3bhFVExwqSTLuXwdev1e26nr7vnECl7H0SCVynr8To7ciwcnmK6HJXre6i+mBdTjACmKseTMlWp480XOt7uHysltORbTA3J
vd4FiYncytyziGH9GNCAA8hGGr1/79Xmphtc5+PHPJDpxvqj1hP7+985QMojYO4M5Qn/aqEAvFgeDN3CA8x1YAK8SdCgSXSBJpRBK8wqPQjBY1ak96QfdPCrTLunr+xuPxK3Gxe772adTTsee2+ot7WePYUsC4y4NcS5+rlP1if87xtYqVeSwx3c64cOmAGP

View File

@ -1 +1 @@
pGZJMmJtule8fwDCz4mnyHoQa7N6pl5GRdLqfoXREBqG4Xb1jbvgf7RmC8f1+sNpiCFSIt7NgvU362tKhB5UBXn/vUAadG1lOGC70dUhprGzBoqJN7VkAHkNGg0XjoE8H0SCVynr8To7ciwcnmK6HJXre6i+mBdTjACmKseTMlWp480XOt7uHysltORbTA3J
vd4FiYncytyziGH9GNCAA8hGGr1/79Xmphtc5+PHPJDpxvqj1hP7+985QMojYO4M5Qn/aqEAvFgeDN3CA8x1YAK8SdCgSXSBJpRBK8wqPQjBY1ak96QfdPCrTLunr+xuPxK3Gxe772adTTsee2+ot7WePYUsC4y4NcS5+rlP1if87xtYqVeSwx3c64cOmAGP

View File

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

View File

@ -1,503 +0,0 @@
from asyncio.windows_events import NULL
from concurrent.futures import thread
from email.policy import default
import os
import pdb
from threading import Thread
import numpy as np
# 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
from PyQt5.QtGui import QIcon,QPixmap
from PyQt5.QtCore import Qt
from rscder.gui.layercombox import LayerCombox,PairLayerCombox
from rscder.utils.icons import IconInstance
from rscder.utils.project import Project, RasterLayer, SingleBandRasterLayer,ResultPointLayer
from In_one.otsu import OTSU
from osgeo import gdal
from plugins.In_one import pic
import math
from skimage.filters import rank
from skimage.morphology import disk, rectangle
class LockerButton(QPushButton):
def __init__(self,parent=NULL):
super(LockerButton,self).__init__(parent)
m_imageLabel = QLabel(self)
m_imageLabel.setFixedWidth(20)
m_imageLabel.setScaledContents(True)
m_imageLabel.setStyleSheet("QLabel{background-color:transparent;}")
m_textLabel = QLabel(self)
m_textLabel.setStyleSheet("QLabel{background-color:transparent;}")
self.m_imageLabel=m_imageLabel
self.m_textLabel=m_textLabel
self.hide_=1
mainLayout = QHBoxLayout()
mainLayout.addWidget(self.m_imageLabel)
mainLayout.addWidget(self.m_textLabel)
mainLayout.setContentsMargins(0,0,0,0)
mainLayout.setSpacing(0)
self.setLayout(mainLayout)
def SetImageLabel(self, pixmap:QPixmap):
self.m_imageLabel.setPixmap(pixmap)
def SetTextLabel(self, text):
self.m_textLabel.setText(text)
class selectCombox(QComboBox):
def __init__(self, parent,list:list,default='--') :
super(selectCombox,self).__init__(parent)
self.choose=None
self.list=list
self.default=default
self.addItem(default, None)
self.addItems(list)
self.currentIndexChanged.connect(self.on_change)
def on_change(self,index):
if index == 0:
self.choose=self.default
else:
self.choose=self.list[index-1]
# print(self.choose)
class AllInOne(QDialog):
def __init__(self, pre,cd,threshold,parent=None):
super(AllInOne, self).__init__(parent)
self.setWindowTitle('变化检测')
self.setWindowIcon(IconInstance().LOGO)
self.pre=pre#['均值滤波','test滤波']
self.cd=cd#['差分法','test法']
self.threshold=threshold#['OTSU']
self.initUI()
def initUI(self):
#图层
self.layer_combox = PairLayerCombox(self)
layerbox = QHBoxLayout()
layerbox.addWidget(self.layer_combox)
#预处理
filterWeight=QWidget(self)
filterlayout=QVBoxLayout()
filerButton =LockerButton(filterWeight)
filerButton.setObjectName("filerButton")
filerButton.SetTextLabel("预处理")
filerButton.SetImageLabel(QPixmap('plugins/In_one/pic/箭头_列表展开.png'))
filerButton.setStyleSheet("#filerButton{background-color:transparent;border:none;}"
"#filerButton:hover{background-color:rgba(195,195,195,0.4);border:none;}")
self.pre_select=selectCombox(self,self.pre)
x_size_input = QLineEdit(self)
x_size_input.setText('3')
y_size_input = QLineEdit(self)
y_size_input.setText('3')
size_label = QLabel(self)
size_label.setText('窗口大小:')
time_label = QLabel(self)
time_label.setText('X')
self.x_size_input = x_size_input
self.y_size_input = y_size_input
hlayout1 = QHBoxLayout()
hlayout1.addWidget(size_label)
hlayout1.addWidget(x_size_input)
hlayout1.addWidget(time_label)
hlayout1.addWidget(y_size_input)
vlayout = QVBoxLayout()
vlayout.addWidget(self.pre_select)
vlayout.addLayout(hlayout1)
filterWeight.setLayout(vlayout)
filterlayout.addWidget(filerButton)
filterlayout.addWidget(filterWeight)
#变化检测
changelayout=QVBoxLayout()
changeWeight=QWidget(self)
changeButton =LockerButton(changeWeight)
changeButton.setObjectName("changeButton")
changeButton.SetTextLabel("变化检测")
changeButton.SetImageLabel(QPixmap('plugins/In_one/pic/箭头_列表展开.png'))
changeButton.setStyleSheet("#changeButton{background-color:transparent;border:none;}"
"#changeButton:hover{background-color:rgba(195,195,195,0.4);border:none;}")
changeWeightlayout=QVBoxLayout()
self.cd_select=selectCombox(self,self.cd)
changeWeightlayout.addWidget(self.cd_select)
changeWeight.setLayout(changeWeightlayout)
changelayout.addWidget(changeButton)
changelayout.addWidget(changeWeight)
#阈值处理
thresholdlayout=QVBoxLayout()
thresholdWeight=QWidget(self)
thresholdButton =LockerButton(thresholdWeight)
thresholdButton.setObjectName("thresholdButton")
thresholdButton.SetTextLabel("阈值处理")
thresholdButton.SetImageLabel(QPixmap('plugins/In_one/pic/箭头_列表展开.png'))
thresholdButton.setStyleSheet("#thresholdButton{background-color:transparent;border:none;}"
"#thresholdButton:hover{background-color:rgba(195,195,195,0.4);border:none;}")
self.threshold_select=selectCombox(self,self.threshold,default='手动阈值')
self.threshold_input=QLineEdit(self)
self.threshold_input.setText('0.5')
self.threshold_select.currentIndexChanged.connect(lambda index:self.hide_(self.threshold_input,index==0))
thresholdWeightlayout=QVBoxLayout()
thresholdWeightlayout.addWidget(self.threshold_select)
thresholdWeightlayout.addWidget(self.threshold_input)
thresholdWeight.setLayout(thresholdWeightlayout)
thresholdlayout.addWidget(thresholdButton)
thresholdlayout.addWidget(thresholdWeight)
#确认
oklayout=QHBoxLayout()
self.ok_button = QPushButton('确定', self)
self.ok_button.setIcon(IconInstance().OK)
self.ok_button.clicked.connect(self.accept)
self.cancel_button = QPushButton('取消', self)
self.cancel_button.setIcon(IconInstance().CANCEL)
self.cancel_button.clicked.connect(self.reject)
oklayout.addWidget(self.ok_button)
oklayout.addWidget(self.cancel_button)
totalvlayout=QVBoxLayout()
totalvlayout.addLayout(layerbox)
totalvlayout.addLayout(filterlayout)
totalvlayout.addLayout(changelayout)
totalvlayout.addLayout(thresholdlayout)
totalvlayout.addLayout(oklayout)
totalvlayout.addStretch()
self.setLayout(totalvlayout)
filerButton.clicked.connect(lambda: self.hide(filerButton,filterWeight))
changeButton.clicked.connect(lambda: self.hide(changeButton,changeWeight))
thresholdButton.clicked.connect(lambda: self.hide(thresholdButton,thresholdWeight))
def hide(self,button:LockerButton,weight:QWidget):
if ((button.hide_)%2)==1:
weight.setVisible(False)
button.SetImageLabel(QPixmap('plugins/In_one/pic/箭头_列表向右.png'))
else:
weight.setVisible(True)
button.SetImageLabel(QPixmap('plugins/In_one/pic/箭头_列表展开.png'))
button.hide_=(button.hide_)%2+1
def hide_(self,widget:QWidget,h:bool):
if h:
widget.setVisible(True)
else:
widget.setVisible(False)
def hideWidget(self,widget:QWidget):
if widget.isVisible:
widget.setVisible(False)
else:
widget.setVisible(True)
class InOnePlugin(BasicPlugin):
pre=['均值滤波']
cd=['差分法']
threshold=['OTSU阈值']
@staticmethod
def info():
return {
'name': 'AllinOne',
'description': 'AllinOne',
'author': 'RSCDER',
'version': '1.0.0',
}
def set_action(self):
basic_diff_method_in_one = QAction('差分法')
# ActionManager().change_detection_menu.addAction(basic_diff_method_in_one)
ActionManager().unsupervised_menu.addAction(basic_diff_method_in_one)
self.basic_diff_method_in_one = basic_diff_method_in_one
basic_diff_method_in_one.triggered.connect(self.run)
def run(self):
myDialog=AllInOne(self.pre,self.cd,self.threshold,self.mainwindow)
myDialog.show()
if myDialog.exec_()==QDialog.Accepted:
t=Thread(target=self.run_alg,args=(myDialog,))
t.start()
def run_alg(self,w:AllInOne):
dict={}
layer1=w.layer_combox.layer1
layer2=w.layer_combox.layer2
if not layer1.compare(layer2):
self.send_message.emit('两个图层的尺寸不同')
return
pth1 = w.layer_combox.layer1.path
pth2 = w.layer_combox.layer2.path
name=layer1.layer_parent.name
if w.pre_select.choose==self.pre[0]:
pth1=Meanfilter(w.x_size_input.text(),w.y_size_input.text(),w.layer_combox.layer1)
self.send_message.emit('均值滤波图像{}'.format(w.layer_combox.layer1.name))
pth2=Meanfilter(w.x_size_input.text(),w.y_size_input.text(),w.layer_combox.layer2)
self.send_message.emit('均值滤波图像{}'.format(w.layer_combox.layer2.name))
name=name+'_mean_filter'
dict['预处理']=['均值滤波','|'.format(pth1,pth2)]
else:
pass
cdpth=None
if w.cd_select.choose==self.cd[0]:
cdpth=basic_cd(pth1,pth2,w.layer_combox.layer1.layer_parent,self.send_message)
name += '_basic_cd'
dict['变化检测算法']=['差分法',cdpth]
else:
pass
thpth=None
if w.threshold_select.choose==self.threshold[0]:
thpth,gap=otsu(cdpth,w.layer_combox.layer1.layer_parent.name,self.send_message)
name+='_otsu'
dict['后处理']=['OTSU阈值',gap,cdpth]
elif w.threshold_select.choose=='手动阈值':
thpth=thresh(cdpth,float(w.threshold_input.text()),w.layer_combox.layer1.layer_parent.name,self.send_message)
dict['后处理']=['手动阈值',[float(w.threshold_input.text())],thpth]
else:
pass
table_layer(thpth,layer1,name,self.send_message,dict)
def Meanfilter(x_size,y_size,layer:RasterLayer):
x_size = int(x_size)
y_size = int(y_size)
pth = layer.path
if pth is None:
return
ds = gdal.Open(pth)
band_count = ds.RasterCount
out_path = os.path.join(Project().other_path, '{}_mean_filter.tif'.format(layer.name))
out_ds = gdal.GetDriverByName('GTiff').Create(out_path, ds.RasterXSize, ds.RasterYSize, band_count, ds.GetRasterBand(1).DataType)
out_ds.SetProjection(ds.GetProjection())
out_ds.SetGeoTransform(ds.GetGeoTransform())
for i in range(band_count):
band = ds.GetRasterBand(i+1)
data = band.ReadAsArray()
data = rank.mean(data, rectangle(y_size, x_size))
out_band = out_ds.GetRasterBand(i+1)
out_band.WriteArray(data)
out_ds.FlushCache()
del out_ds
del ds
return out_path
def basic_cd(pth1,pth2,layer_parent,send_message):
ds1 = gdal.Open(pth1)
ds2 = gdal.Open(pth2)
cell_size = layer_parent.cell_size
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):
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)
send_message.emit(f'完成{j}/{yblocks}')
out_ds.FlushCache()
del out_ds
send_message.emit('归一化概率中...')
temp_in_ds = gdal.Open(out_tif)
out_normal_tif = os.path.join(Project().cmi_path, '{}_{}_cmi.tif'.format(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('完成计算变化表格')
send_message.emit('差分法计算完成')
return out_normal_tif
def otsu(pth,name,send_message):
ds = gdal.Open(pth)
band = ds.GetRasterBand(1)
# band_count = ds.RasterCount
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)
send_message.emit('阈值为:{}'.format(gap))
out_th = os.path.join(Project().bcdm_path, '{}_otsu_bcdm.tif'.format(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
send_message.emit('OTSU阈值完成')
return out_th,gap
#otsu_layer = SingleBandRasterLayer(path = out_th, style_info={})
#layer.layer_parent.add_result_layer(otsu_layer)
def thresh(pth,gap,name,send_message):
ds = gdal.Open(pth)
band = ds.GetRasterBand(1)
# band_count = ds.RasterCount
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)
send_message.emit('阈值为:{}'.format(gap))
out_th = os.path.join(Project().bcdm_path, '{}_thresh{}_bcdm.tif'.format(name,gap))
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
send_message.emit('自定义阈值分割完成')
return out_th
#otsu_layer = SingleBandRasterLayer(path = out_th, style_info={})
#layer.layer_parent.add_result_layer(otsu_layer)
def table_layer(pth,layer,name,send_message,dict):
send_message.emit('正在计算表格结果...')
cell_size = layer.layer_parent.cell_size
ds = gdal.Open(pth)
xsize = ds.RasterXSize
ysize = ds.RasterYSize
geo = ds.GetGeoTransform()
out_csv = os.path.join(Project().other_path, f'{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]
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},{int(block_data_xy.mean() > 0.5)}\n')
result_layer = ResultPointLayer(out_csv, enable=True, proj=layer.proj, geo=layer.geo,result_path=dict)
# print(result_layer.result_path)
layer.layer_parent.add_result_layer(result_layer)
send_message.emit('计算完成')

View File

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

View File

@ -1,2 +0,0 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1655105353713" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2292" xmlns:xlink="http://www.w3.org/1999/xlink" width="128" height="128"><defs><style type="text/css">@font-face { font-family: feedback-iconfont; src: url("//at.alicdn.com/t/font_1031158_u69w8yhxdu.woff2?t=1630033759944") format("woff2"), url("//at.alicdn.com/t/font_1031158_u69w8yhxdu.woff?t=1630033759944") format("woff"), url("//at.alicdn.com/t/font_1031158_u69w8yhxdu.ttf?t=1630033759944") format("truetype"); }
</style></defs><path d="M517.688889 796.444444c-45.511111 0-85.333333-17.066667-119.466667-51.2L73.955556 381.155556c-22.755556-22.755556-17.066667-56.888889 5.688888-79.644445 22.755556-22.755556 56.888889-17.066667 79.644445 5.688889l329.955555 364.088889c5.688889 5.688889 17.066667 11.377778 28.444445 11.377778s22.755556-5.688889 34.133333-17.066667l312.888889-364.088889c22.755556-22.755556 56.888889-28.444444 79.644445-5.688889 22.755556 22.755556 28.444444 56.888889 5.688888 79.644445L637.155556 739.555556c-28.444444 39.822222-68.266667 56.888889-119.466667 56.888888 5.688889 0 0 0 0 0z" p-id="2293"></path></svg>

Before

Width:  |  Height:  |  Size: 1.3 KiB

View File

@ -1,2 +0,0 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1655105348118" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2137" xmlns:xlink="http://www.w3.org/1999/xlink" width="128" height="128"><defs><style type="text/css">@font-face { font-family: feedback-iconfont; src: url("//at.alicdn.com/t/font_1031158_u69w8yhxdu.woff2?t=1630033759944") format("woff2"), url("//at.alicdn.com/t/font_1031158_u69w8yhxdu.woff?t=1630033759944") format("woff"), url("//at.alicdn.com/t/font_1031158_u69w8yhxdu.ttf?t=1630033759944") format("truetype"); }
</style></defs><path d="M312.888889 995.555556c-17.066667 0-28.444444-5.688889-39.822222-17.066667-22.755556-22.755556-17.066667-56.888889 5.688889-79.644445l364.088888-329.955555c11.377778-11.377778 17.066667-22.755556 17.066667-34.133333 0-11.377778-5.688889-22.755556-17.066667-34.133334L273.066667 187.733333c-22.755556-22.755556-28.444444-56.888889-5.688889-79.644444 22.755556-22.755556 56.888889-28.444444 79.644444-5.688889l364.088889 312.888889c34.133333 28.444444 56.888889 73.955556 56.888889 119.466667s-17.066667 85.333333-51.2 119.466666l-364.088889 329.955556c-11.377778 5.688889-28.444444 11.377778-39.822222 11.377778z" p-id="2138"></path></svg>

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

View File

@ -1,9 +1,10 @@
import os
from pickle import TRUE
from threading import Thread
from rscder.gui.actions import ActionManager
from rscder.gui.layercombox import ResultPointLayerCombox
from rscder.plugins.basic import BasicPlugin
from PyQt5.QtWidgets import QAction, QDialog, QLabel, QHBoxLayout, QVBoxLayout, QPushButton,QSlider,QSpinBox,QSpacerItem
from PyQt5.QtWidgets import QAction, QDialog, QLabel, QHBoxLayout, QVBoxLayout, QPushButton,QSlider,QSpinBox,QSpacerItem,QDialogButtonBox
from PyQt5.QtCore import pyqtSignal,Qt
from PyQt5.QtGui import QIcon
from rscder.utils.icons import IconInstance
@ -36,19 +37,20 @@ class RateSetdialog(QDialog):
self.ok_button = QPushButton('确定', self)
self.ok_button.setIcon(IconInstance().OK)
self.ok_button.clicked.connect(self.on_ok)
self.ok_button.setDefault(True)
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.cancel_button.setDefault(False)
self.buttonbox=QDialogButtonBox(self)
self.buttonbox.addButton(self.ok_button,QDialogButtonBox.NoRole)
self.buttonbox.addButton(self.cancel_button,QDialogButtonBox.NoRole)
self.buttonbox.setCenterButtons(True)
vlayout=QVBoxLayout()
vlayout.addLayout(h1)
vlayout.addWidget(QLabel('设置阈值'))
vlayout.addLayout(h2)
vlayout.addLayout(self.button_layout)
vlayout.addWidget(self.buttonbox)
self.setLayout(vlayout)
self.old_data = None

View File

@ -7,7 +7,7 @@ import numpy as np
from rscder.gui.actions import ActionManager
from rscder.plugins.basic import BasicPlugin
from rscder.gui.layercombox import RasterLayerCombox,ResultLayercombox, ResultPointLayerCombox
from PyQt5.QtWidgets import QAction, QFileDialog, QDialog, QLabel, QHBoxLayout, QVBoxLayout, QPushButton
from PyQt5.QtWidgets import QAction, QFileDialog, QDialog, QLabel, QHBoxLayout, QVBoxLayout, QPushButton,QDialogButtonBox
from PyQt5.QtGui import QIcon
from PyQt5.QtCore import Qt
from osgeo import gdal
@ -49,14 +49,19 @@ class EvalutationDialog(QDialog):
self.ok_button = QPushButton('确定', self)
self.ok_button.setIcon(IconInstance().OK)
self.ok_button.clicked.connect(self.on_ok)
self.ok_button.setDefault(True)
self.cancel_button = QPushButton('取消', self)
self.cancel_button.setIcon(IconInstance().CANCEL)
self.cancel_button.clicked.connect(self.on_cancel)
self.cancel_button.setDefault(False)
self.buttonbox=QDialogButtonBox(self)
self.buttonbox.addButton(self.ok_button,QDialogButtonBox.NoRole)
self.buttonbox.addButton(self.cancel_button,QDialogButtonBox.NoRole)
self.buttonbox.setCenterButtons(True)
self.button_layout = QHBoxLayout()
self.button_layout.addWidget(self.ok_button)
self.button_layout.addWidget(self.cancel_button)
self.button_layout.addWidget(self.ok_button,0,alignment=Qt.AlignHCenter)
self.button_layout.addLayout(self.cancel_button,0,alignment=Qt.AlignHCenter)
self.main_layout = QVBoxLayout()
self.main_layout.addLayout(hbox1)

View File

@ -5,6 +5,7 @@ from rscder.utils.project import Project, PairLayer, ResultPointLayer
from rscder.plugins.basic import BasicPlugin
from PyQt5.QtWidgets import QDialog, QHBoxLayout, QFileDialog, QComboBox, QVBoxLayout, QPushButton, QLabel, QLineEdit, QAction
from PyQt5.QtGui import QIcon
from PyQt5.QtCore import Qt
class ExportDialog(QDialog):
def __init__(self, parent=None):
@ -60,9 +61,9 @@ class ExportDialog(QDialog):
hbox2.addWidget(out_path_btn)
hbox3 = QHBoxLayout()
hbox3.addWidget(ok_btn)
hbox3.addWidget(cancel_btn)
hbox3.addWidget(ok_btn,0,alignment=Qt.AlignHCenter)
hbox3.addWidget(cancel_btn,0,alignment=Qt.AlignHCenter)
vbox = QVBoxLayout()
vbox.addLayout(hbox1)
vbox.addLayout(hbox2)

View File

@ -0,0 +1,5 @@
from misc import Register
FILTER = Register('滤波处理算法')
from filter_collection.main import *

View File

@ -1,3 +1,4 @@
from datetime import datetime
import os
from threading import Thread
from PyQt5.QtWidgets import QDialog, QAction
@ -10,19 +11,98 @@ from rscder.plugins.basic import BasicPlugin
from rscder.gui.layercombox import RasterLayerCombox
from osgeo import gdal, gdal_array
from skimage.filters import rank
from skimage.morphology import disk, rectangle
from skimage.morphology import rectangle
from filter_collection import FILTER
from misc import AlgFrontend
@FILTER.register
class MainFilter(AlgFrontend):
@staticmethod
def get_name():
return '均值滤波'
@staticmethod
def get_widget(parent=None):
widget = QtWidgets.QWidget(parent)
x_size_input = QtWidgets.QLineEdit(widget)
x_size_input.setText('3')
x_size_input.setValidator(QtGui.QIntValidator())
x_size_input.setObjectName('xinput')
y_size_input = QtWidgets.QLineEdit(widget)
y_size_input.setValidator(QtGui.QIntValidator())
y_size_input.setObjectName('yinput')
y_size_input.setText('3')
size_label = QtWidgets.QLabel(widget)
size_label.setText('窗口大小:')
time_label = QtWidgets.QLabel(widget)
time_label.setText('X')
hlayout1 = QtWidgets.QHBoxLayout()
hlayout1.addWidget(size_label)
hlayout1.addWidget(x_size_input)
hlayout1.addWidget(time_label)
hlayout1.addWidget(y_size_input)
widget.setLayout(hlayout1)
return widget
@staticmethod
def get_params(widget:QtWidgets.QWidget=None):
if widget is None:
return dict(x_size=3, y_size=3)
x_input = widget.findChild(QtWidgets.QLineEdit, 'xinput')
y_input = widget.findChild(QtWidgets.QLineEdit, 'yinput')
if x_input is None or y_input is None:
return dict(x_size=3, y_size=3)
x_size = int(x_input.text())
y_size = int(y_input.text())
return dict(x_size=x_size, y_size=y_size)
@staticmethod
def run_alg(pth, x_size, y_size, *args, **kargs):
x_size = int(x_size)
y_size = int(y_size)
# pth = layer.path
if pth is None:
return
ds = gdal.Open(pth)
band_count = ds.RasterCount
out_path = os.path.join(Project().other_path, 'mean_filter_{}.tif'.format(int(datetime.now().timestamp() * 1000)))
out_ds = gdal.GetDriverByName('GTiff').Create(out_path, ds.RasterXSize, ds.RasterYSize, band_count, ds.GetRasterBand(1).DataType)
out_ds.SetProjection(ds.GetProjection())
out_ds.SetGeoTransform(ds.GetGeoTransform())
for i in range(band_count):
band = ds.GetRasterBand(i+1)
data = band.ReadAsArray()
data = rank.mean(data, rectangle(y_size, x_size))
out_band = out_ds.GetRasterBand(i+1)
out_band.WriteArray(data)
out_ds.FlushCache()
del out_ds
del ds
return out_path
class FilterSetting(QDialog):
def __init__(self, parent=None):
super(FilterSetting, self).__init__(parent)
self.setWindowTitle('滤波设置')
# self.setWindowFlags(Qt.WindowStaysOnTopHint)
# self.setFixedSize(300, 200)
# self.setStyleSheet("QDialog{background-color:rgb(255,255,255);}")
self.setWindowIcon(IconInstance().FILTER)
# self.setWindowIconText('Filter Setting')
# self.setWindowModality(Qt.ApplicationModal)
self.initUI()
# self.show()
def initUI(self):
self.layer_combox = RasterLayerCombox(self)
@ -61,8 +141,8 @@ class FilterSetting(QDialog):
cancel_button.clicked.connect(self.reject)
hlayout2 = QtWidgets.QHBoxLayout()
hlayout2.addWidget(ok_button)
hlayout2.addWidget(cancel_button)
hlayout2.addWidget(ok_button,0,alignment=Qt.AlignHCenter)
hlayout2.addWidget(cancel_button,0,alignment=Qt.AlignHCenter)
vlayout = QtWidgets.QVBoxLayout()
vlayout.addLayout(hbox)
@ -78,10 +158,10 @@ class MainPlugin(BasicPlugin):
@staticmethod
def info():
return {
'name': 'mean_filter',
'name': 'FilterCollection',
'author': 'rscder',
'version': '0.0.1',
'description': 'Mean Filter'
'description': 'Filter Collections'
}
def set_action(self):

View File

@ -0,0 +1,5 @@
from misc import Register
FOLLOW = Register('流程')
from follow.main import *

165
plugins/follow/main.py Normal file
View File

@ -0,0 +1,165 @@
from functools import partial
from threading import Thread
from rscder.plugins.basic import BasicPlugin
from rscder.utils.icons import IconInstance
from rscder.gui.actions import ActionManager
from PyQt5 import QtWidgets, QtGui
from follow import FOLLOW
from misc import AlgFrontend
class FollowDialog(QtWidgets.QDialog):
def __init__(self, parent=None, alg:AlgFrontend=None) -> None:
super().__init__(parent)
if alg is None:
return
self.setMinimumWidth(700)
# self.setMinimumHeight(500)
vbox = QtWidgets.QVBoxLayout()
self.widget = alg.get_widget(self)
vbox.addWidget(self.widget)
self.ok_button = QtWidgets.QPushButton('确定', self)
self.ok_button.setIcon(IconInstance().OK)
self.ok_button.clicked.connect(self.accept)
self.ok_button.setDefault(True)
self.cancel_button = QtWidgets.QPushButton('取消', self)
self.cancel_button.setIcon(IconInstance().CANCEL)
self.cancel_button.clicked.connect(self.reject)
self.cancel_button.setDefault(False)
buttonbox= QtWidgets.QDialogButtonBox()
buttonbox.addButton(self.ok_button,QtWidgets.QDialogButtonBox.NoRole)
buttonbox.addButton(self.cancel_button,QtWidgets.QDialogButtonBox.NoRole)
buttonbox.setCenterButtons(True)
vbox.addWidget(buttonbox)
vbox.addStretch()
self.setLayout(vbox)
class FollowPlugin(BasicPlugin):
@staticmethod
def get_info():
return {
'name': 'Follow',
'version': '1.0.0'
}
def set_action(self):
follow_box:QtWidgets.QWidget = ActionManager().follow_box
toolbar = ActionManager().add_toolbar('Follow')
vbox = QtWidgets.QVBoxLayout(follow_box)
combox = QtWidgets.QComboBox(follow_box)
# print(FOLLOW.keys())
for key in FOLLOW.keys():
alg:AlgFrontend = FOLLOW[key]
if alg.get_name() is None:
name = key
else:
name = alg.get_name()
combox.addItem(name, key)
action = QtWidgets.QAction(alg.get_icon(), name, self.mainwindow)
func = partial(self.run_dialog, alg)
action.triggered.connect(func)
toolbar.addAction(action)
combox.currentIndexChanged.connect(self.on_change)
vbox.addWidget(combox)
self.current_widget = None
self.combox = combox
self.layout = vbox
self.ok_button = QtWidgets.QPushButton('运行')
self.ok_button.setIcon(IconInstance().OK)
self.ok_button.clicked.connect(self.run)
self.ok_button.setDefault(True)
self.cancel_button = QtWidgets.QPushButton('重置')
self.cancel_button.setIcon(IconInstance().CANCEL)
self.cancel_button.clicked.connect(self.reset)
self.cancel_button.setDefault(False)
buttonbox= QtWidgets.QDialogButtonBox()
buttonbox.addButton(self.ok_button,QtWidgets.QDialogButtonBox.NoRole)
buttonbox.addButton(self.cancel_button,QtWidgets.QDialogButtonBox.NoRole)
buttonbox.setCenterButtons(True)
self.btn_box = buttonbox
follow_box.setLayout(vbox)
# vbox.addStretch()
self.on_change(0)
def on_change(self, index):
print(self.combox.currentData())
if self.current_widget is not None:
self.current_widget.setParent(None)
self.btn_box.setParent(None)
self.layout.removeWidget(self.current_widget)
self.layout.removeWidget(self.btn_box)
self.current_widget = None
alg:AlgFrontend = FOLLOW[self.combox.currentData()]
if alg.get_widget() is None:
return
self.current_widget = alg.get_widget(ActionManager().follow_box)
self.layout.addWidget(self.current_widget)
self.layout.addWidget(self.btn_box)
def run(self):
alg:AlgFrontend = FOLLOW[self.combox.currentData()]
if alg is None:
return
params = alg.get_params(self.current_widget)
t = Thread(target=self.run_alg, args=(params,))
t.start()
def run_dialog(self, alg:AlgFrontend):
dialog = FollowDialog(self.mainwindow, alg)
dialog.show()
if dialog.exec_() == QtWidgets.QDialog.Accepted:
params = alg.get_params(dialog.widget)
t = Thread(target=self.run_alg, args = (alg, params,))
t.start()
def run_alg(self, alg:AlgFrontend, p):
alg.run_alg(**p, send_message=self.send_message)
def reset(self):
if self.current_widget is None:
return
self.current_widget.setParent(None)
self.btn_box.setParent(None)
self.layout.removeWidget(self.current_widget)
self.layout.removeWidget(self.btn_box)
self.current_widget = FOLLOW[self.combox.currentData()].get_widget(ActionManager().follow_box)
self.layout.addWidget(self.current_widget)
self.layout.addLayout(self.btn_box)

3
plugins/misc/__init__.py Normal file
View File

@ -0,0 +1,3 @@
from misc.main import *
from misc.utils import *
from misc.table_layer import *

92
plugins/misc/main.py Normal file
View File

@ -0,0 +1,92 @@
from threading import Thread
from plugins.misc.utils import Register
from rscder.plugins.basic import BasicPlugin
from PyQt5.QtWidgets import QGroupBox, QWidget, QComboBox, QVBoxLayout
class MISCPlugin(BasicPlugin):
@staticmethod
def info():
return {
'name': 'MISC Plugin',
'description': '基本开发工具',
'author': 'Wangtong',
'version': '1.0.0',
}
def set_action(self):
pass
class AlgFrontend(object):
@staticmethod
def get_name():
return None
@staticmethod
def get_icon():
return None
@staticmethod
def get_widget(parent=None):
return QWidget(parent)
@staticmethod
def get_params(widget=None):
return dict()
@staticmethod
def run_alg(*args, **kargs):
pass
class AlgSelectWidget(QGroupBox):
def __init__(self, parent= None, registery:Register = None) -> None:
super().__init__(parent)
self.reg = registery
if registery is None:
return
self.setTitle(registery.name)
self.selectbox = QComboBox(self)
self.selectbox.addItem('--', None)
for key in self.reg.keys():
alg:AlgFrontend = self.reg[key]
if alg.get_name() is None:
name = key
else:
name = alg.get_name()
self.selectbox.addItem(name, key)
self.vbox = QVBoxLayout(self)
self.vbox.addWidget(self.selectbox)
self.params_widget = QWidget()
self.vbox.addWidget(self.params_widget)
self.selectbox.currentIndexChanged.connect(self.on_changed)
def on_changed(self, index):
if index == 0:
self.alg = None
self.params_widget.setParent(None)
self.vbox.removeWidget(self.params_widget)
self.params_widget = QWidget(self)
self.vbox.addWidget(self.params_widget)
return
self.alg:AlgFrontend = self.reg[self.selectbox.itemData(index)]
self.params_widget.setParent(None)
self.vbox.removeWidget(self.params_widget)
self.params_widget = self.alg.get_widget(self)
self.vbox.addWidget(self.params_widget)
def get_alg_and_params(self):
if self.selectbox.currentIndex() == 0:
return None, None
return self.alg, self.alg.get_params(self.params_widget)

View File

@ -0,0 +1,46 @@
from datetime import datetime
import math
from random import random
from osgeo import gdal
from rscder.utils.project import Project
import os
from rscder.utils.project import BasicLayer, ResultPointLayer
def table_layer(pth:str,layer:BasicLayer, name, send_message = None):
if send_message is not None:
send_message.emit('正在计算表格结果...')
cell_size = layer.layer_parent.cell_size
ds = gdal.Open(pth)
xsize = ds.RasterXSize
ysize = ds.RasterYSize
geo = ds.GetGeoTransform()
out_csv = os.path.join(Project().other_path, f'{name}_table_result_{ int(datetime.now().timestamp() * 1000) }.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]
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},{int(block_data_xy.mean() > 0.5)}\n')
result_layer = ResultPointLayer(out_csv, enable=True, proj=layer.proj, geo=layer.geo,result_path={})
# print(result_layer.result_path)
layer.layer_parent.add_result_layer(result_layer)
if send_message is not None:
send_message.emit('计算完成')

46
plugins/misc/utils.py Normal file
View File

@ -0,0 +1,46 @@
import os
import random
import logging
# def generate_temp_file
class Register:
def __init__(self, registry_name):
self._dict = {}
self._name = registry_name
@property
def name(self):
return self._name
def __setitem__(self, key, value):
if not callable(value):
raise Exception(f"Value of a Registry must be a callable!\nValue: {value}")
if key is None:
key = value.__name__
if key in self._dict:
logging.warning("Key %s already in registry %s." % (key, self._name))
self._dict[key] = value
def register(self, target):
"""Decorator to register a function or class."""
def add(key, value):
self[key] = value
return value
if callable(target):
# @reg.register
return add(None, target)
# @reg.register('alias')
return lambda x: add(target, x)
def __getitem__(self, key):
return self._dict[key]
def __contains__(self, key):
return key in self._dict
def keys(self):
"""key"""
return self._dict.keys()

View File

@ -13,11 +13,11 @@
path: ./plugin\export_to
version: 1.0.0
- author: RSCDER
description: MeanFilter
description: FilterCollection
enabled: true
module: some_filter
name: MeanFilter
path: ./plugin\some_filter
module: filter_collection
name: FilterCollection
path: ./plugin\filter_collection
version: 1.0.0
- author: RSCDER
description: Evaluation
@ -27,11 +27,18 @@
path: ./plugin\evaluation
version: 1.0.0
- author: RSCDER
description: AllinOne
description: UnsupervisedPlugin
enabled: true
module: In_one
name: basic_diff_AllinOne
path: ./plugin\In_one
module: unsupervised_method
name: UnsupervisedPlugin
path: ./plugin\unsupervsied_method
version: 1.0.0
- author: RSCDER
description: VegatationPlugin
enabled: true
module: veg_method
name: VegatationPlugin
path: ./plugin\veg_method
version: 1.0.0
- author: RSCDER
description: set Change Rate
@ -39,4 +46,11 @@
module: change_rate
name: set_change_rate
path: ./plugin\change_rate
version: 1.0.0
- author: RSCDER
description: Follow box
enabled: true
module: follow
name: FollowPlugin
path: ./plugin\follow
version: 1.0.0

View File

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

View File

@ -0,0 +1,5 @@
from misc import Register
THRES = Register('阈值方法')
from thres.main import *

178
plugins/thres/main.py Normal file
View File

@ -0,0 +1,178 @@
from osgeo import gdal, gdalconst
from rscder.utils.project import Project
import os
from misc import AlgFrontend
from thres import THRES
from PyQt5.QtWidgets import QWidget, QLabel, QHBoxLayout, QLineEdit
from PyQt5.QtGui import QIntValidator, QDoubleValidator
@THRES.register
class ManulGapAlg(AlgFrontend):
@staticmethod
def get_name():
return '手动阈值'
@staticmethod
def get_params(widget:QWidget=None):
if widget is None:
return dict(gap=125)
lineedit:QLineEdit = widget.layout().findChild(QLineEdit, 'lineedit')
if lineedit is None:
return dict(gap=125)
gap = int(lineedit.text())
return dict(gap=gap)
@staticmethod
def get_widget(parent=None):
widget = QWidget(parent)
lineedit = QLineEdit(widget)
lineedit.setObjectName('lineedit')
lineedit.setValidator(QIntValidator(1, 254))
# lineedit.
label = QLabel('阈值:')
layout = QHBoxLayout()
layout.addWidget(label)
layout.addWidget(lineedit)
widget.setLayout(layout)
return widget
@staticmethod
def run_alg(pth,name = '',gap = 125, send_message = None):
ds = gdal.Open(pth)
band = ds.GetRasterBand(1)
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
if send_message is not None:
send_message.emit('阈值为:{}'.format(gap))
out_th = os.path.join(Project().bcdm_path, '{}_thresh{}_bcdm.tif'.format(name,gap))
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
if send_message is not None:
send_message.emit('自定义阈值分割完成')
return out_th
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
@THRES.register
class OTSUAlg(AlgFrontend):
@staticmethod
def get_name():
return 'OTSU阈值'
@staticmethod
def run_alg(pth,name='',send_message=None):
ds = gdal.Open(pth)
band = ds.GetRasterBand(1)
# band_count = ds.RasterCount
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)
send_message.emit('阈值为:{}'.format(gap))
out_th = os.path.join(Project().bcdm_path, '{}_otsu_bcdm.tif'.format(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
send_message.emit('OTSU阈值完成')
return out_th
# ManulGapAlg.run_alg

View File

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

View File

@ -0,0 +1,227 @@
from functools import partial
from threading import Thread
from plugins.misc.main import AlgFrontend
from rscder.gui.actions import ActionManager
from rscder.plugins.basic import BasicPlugin
from PyQt5.QtWidgets import QAction, QToolBar, QMenu, QDialog, QHBoxLayout, QVBoxLayout, QPushButton,QWidget,QLabel,QLineEdit,QPushButton,QComboBox,QDialogButtonBox
from rscder.gui.layercombox import PairLayerCombox
from rscder.utils.icons import IconInstance
from filter_collection import FILTER
from .scripts import UNSUPER_CD
from thres import THRES
from misc import table_layer, AlgSelectWidget
from follow import FOLLOW
class UnsupervisedCDMethod(QDialog):
def __init__(self,parent=None, alg:AlgFrontend=None):
super(UnsupervisedCDMethod, self).__init__(parent)
self.alg = alg
self.setWindowTitle('无监督变化检测:{}'.format(alg.get_name()))
self.setWindowIcon(IconInstance().LOGO)
self.initUI()
self.setMinimumWidth(500)
def initUI(self):
#图层
self.layer_combox = PairLayerCombox(self)
layerbox = QHBoxLayout()
layerbox.addWidget(self.layer_combox)
self.filter_select = AlgSelectWidget(self, FILTER)
self.param_widget = self.alg.get_widget(self)
self.unsupervised_menu = self.param_widget
self.thres_select = AlgSelectWidget(self, THRES)
self.ok_button = QPushButton('确定', self)
self.ok_button.setIcon(IconInstance().OK)
self.ok_button.clicked.connect(self.accept)
self.ok_button.setDefault(True)
self.cancel_button = QPushButton('取消', self)
self.cancel_button.setIcon(IconInstance().CANCEL)
self.cancel_button.clicked.connect(self.reject)
self.cancel_button.setDefault(False)
buttonbox=QDialogButtonBox(self)
buttonbox.addButton(self.ok_button,QDialogButtonBox.NoRole)
buttonbox.addButton(self.cancel_button,QDialogButtonBox.NoRole)
buttonbox.setCenterButtons(True)
totalvlayout=QVBoxLayout()
totalvlayout.addLayout(layerbox)
totalvlayout.addWidget(self.filter_select)
if self.param_widget is not None:
totalvlayout.addWidget(self.param_widget)
totalvlayout.addWidget(self.thres_select)
totalvlayout.addStretch(1)
hbox = QHBoxLayout()
hbox.addStretch(1)
hbox.addWidget(buttonbox)
totalvlayout.addLayout(hbox)
# totalvlayout.addStretch()
self.setLayout(totalvlayout)
@FOLLOW.register
class UnsupervisedCDFollow(AlgFrontend):
@staticmethod
def get_name():
return '无监督变化检测'
@staticmethod
def get_icon():
return IconInstance().UNSUPERVISED
@staticmethod
def get_widget(parent=None):
widget = QWidget(parent)
layer_combox = PairLayerCombox(widget)
layer_combox.setObjectName('layer_combox')
filter_select = AlgSelectWidget(widget, FILTER)
filter_select.setObjectName('filter_select')
unsupervised_select = AlgSelectWidget(widget, UNSUPER_CD)
unsupervised_select.setObjectName('unsupervised_select')
thres_select = AlgSelectWidget(widget, THRES)
thres_select.setObjectName('thres_select')
totalvlayout=QVBoxLayout()
totalvlayout.addWidget(layer_combox)
totalvlayout.addWidget(filter_select)
totalvlayout.addWidget(unsupervised_select)
totalvlayout.addWidget(thres_select)
totalvlayout.addStretch()
widget.setLayout(totalvlayout)
return widget
@staticmethod
def get_params(widget:QWidget=None):
if widget is None:
return dict()
layer_combox = widget.findChild(PairLayerCombox, 'layer_combox')
filter_select = widget.findChild(AlgSelectWidget, 'filter_select')
unsupervised_select = widget.findChild(AlgSelectWidget, 'unsupervised_select')
thres_select = widget.findChild(AlgSelectWidget, 'thres_select')
layer1=layer_combox.layer1
pth1 = layer_combox.layer1.path
pth2 = layer_combox.layer2.path
falg, fparams = filter_select.get_alg_and_params()
cdalg, cdparams = unsupervised_select.get_alg_and_params()
thalg, thparams = thres_select.get_alg_and_params()
if cdalg is None or thalg is None:
return dict()
return dict(
layer1=layer1,
pth1 = pth1,
pth2 = pth2,
falg = falg,
fparams = fparams,
cdalg = cdalg,
cdparams = cdparams,
thalg = thalg,
thparams = thparams,
)
@staticmethod
def run_alg(layer1=None,
pth1 = None,
pth2 = None,
falg = None,
fparams = None,
cdalg = None,
cdparams = None,
thalg = None,
thparams = None,
send_message = None):
if cdalg is None or thalg is None:
return
name = layer1.name
if falg is not None:
pth1 = falg.run_alg(pth1, name=name, send_message= send_message, **fparams)
pth2 = falg.run_alg(pth2, name=name, send_message= send_message, **fparams)
cdpth = cdalg.run_alg(pth1, pth2, layer1.layer_parent, send_message= send_message,**cdparams)
thpth = thalg.run_alg(cdpth, name=name, send_message= send_message, **thparams)
table_layer(thpth,layer1,name, send_message)
class UnsupervisedPlugin(BasicPlugin):
@staticmethod
def info():
return {
'name': 'UnsupervisedPlugin',
'description': 'UnsupervisedPlugin',
'author': 'RSCDER',
'version': '1.0.0',
}
def set_action(self):
unsupervised_menu = QMenu('&无监督变化检测', self.mainwindow)
unsupervised_menu.setIcon(IconInstance().UNSUPERVISED)
ActionManager().change_detection_menu.addMenu(unsupervised_menu)
for key in UNSUPER_CD.keys():
alg:AlgFrontend = UNSUPER_CD[key]
if alg.get_name() is None:
name = key
else:
name = alg.get_name()
action = QAction(name, unsupervised_menu)
func = partial(self.run_cd, alg)
action.triggered.connect(func)
unsupervised_menu.addAction(action)
def run_cd(self, alg):
print(alg.get_name())
dialog = UnsupervisedCDMethod(self.mainwindow, alg)
dialog.show()
if dialog.exec_() == QDialog.Accepted:
t = Thread(target=self.run_cd_alg, args=(dialog,))
t.start()
def run_cd_alg(self, w:UnsupervisedCDMethod):
layer1=w.layer_combox.layer1
pth1 = w.layer_combox.layer1.path
pth2 = w.layer_combox.layer2.path
name = layer1.layer_parent.name
falg, fparams = w.filter_select.get_alg_and_params()
cdalg = w.alg
cdparams = w.alg.get_params(w.param_widget)
thalg, thparams = w.thres_select.get_alg_and_params()
if cdalg is None or thalg is None:
return
if falg is not None:
pth1 = falg.run_alg(pth1, name=name, send_message=self.send_message, **fparams)
pth2 = falg.run_alg(pth2, name=name, send_message=self.send_message, **fparams)
cdpth = cdalg.run_alg(pth1, pth2, layer1.layer_parent, send_message=self.send_message,**cdparams)
thpth = thalg.run_alg(cdpth, name=name, send_message=self.send_message, **thparams)
table_layer(thpth,layer1,name,self.send_message)

View File

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,690 @@
from datetime import datetime
from osgeo import gdal
import math,os
import time
from PyQt5 import QtWidgets
from sklearn.cluster import k_means
from rscder.utils.geomath import geo2imageRC, imageRC2geo
from rscder.utils.project import Project, PairLayer
from misc import Register, AlgFrontend
UNSUPER_CD = Register('无监督变化检测方法')
import numpy as np
from .ACD import ACD
from .AHT import AHT
from .OCD import OCD
from .LHBA import LHBA
from .SH import SH
def warp(file,ds:gdal.Dataset,srcWin=[0,0,0,0]):
driver = gdal.GetDriverByName('GTiff')
xsize=ds.RasterXSize
ysize=ds.RasterYSize
geo=ds.GetGeoTransform()
orj=ds.GetProjection()
band=ds.RasterCount
if os.path.exists(file):
os.remove(file)
out_ds:gdal.Dataset=driver.Create(file, xsize, ysize, band, gdal.GDT_Byte)
out_ds.SetGeoTransform(geo)
out_ds.SetProjection(orj)
for b in range(1,band+1):
out_ds.GetRasterBand(b).WriteArray(ds.ReadAsArray(*srcWin,band_list=[b]),*(0,0))
del out_ds
@UNSUPER_CD.register
class BasicCD(AlgFrontend):
@staticmethod
def get_name():
return '差分法'
@staticmethod
def run_alg(pth1:str,pth2:str,layer_parent:PairLayer,send_message = None,*args, **kargs):
ds1:gdal.Dataset=gdal.Open(pth1)
ds2:gdal.Dataset=gdal.Open(pth2)
cell_size = layer_parent.cell_size
xsize = layer_parent.size[0]
ysize = layer_parent.size[1]
band = ds1.RasterCount
yblocks = ysize // cell_size[1]
driver = gdal.GetDriverByName('GTiff')
out_tif = os.path.join(Project().other_path, 'temp.tif')
out_ds = driver.Create(out_tif, xsize, ysize, 1, gdal.GDT_Float32)
geo=layer_parent.grid.geo
proj=layer_parent.grid.proj
out_ds.SetGeoTransform(geo)
out_ds.SetProjection(proj)
max_diff = 0
min_diff = math.inf
start1x,start1y=geo2imageRC(ds1.GetGeoTransform(),layer_parent.mask.xy[0],layer_parent.mask.xy[1])
end1x,end1y=geo2imageRC(ds1.GetGeoTransform(),layer_parent.mask.xy[2],layer_parent.mask.xy[3])
start2x,start2y=geo2imageRC(ds2.GetGeoTransform(),layer_parent.mask.xy[0],layer_parent.mask.xy[1])
end2x,end2y=geo2imageRC(ds2.GetGeoTransform(),layer_parent.mask.xy[2],layer_parent.mask.xy[3])
for j in range(yblocks + 1):#该改这里了
if send_message is not None:
send_message.emit(f'计算{j}/{yblocks}')
block_xy1 = (start1x, start1y+j * cell_size[1])
block_xy2 = (start2x,start2y+j*cell_size[1])
block_xy=(0,j * cell_size[1])
if block_xy1[1] > end1y or block_xy2[1] > end2y:
break
block_size=(xsize, cell_size[1])
block_size1 = (xsize, cell_size[1])
block_size2 = (xsize,cell_size[1])
if block_xy[1] + block_size[1] > ysize:
block_size = (xsize, ysize - block_xy[1])
if block_xy1[1] + block_size1[1] > end1y:
block_size1 = (xsize,end1y - block_xy1[1])
if block_xy2[1] + block_size2[1] > end2y:
block_size2 = (xsize, end2y - block_xy2[1])
block_data1 = ds1.ReadAsArray(*block_xy1, *block_size1)
block_data2 = ds2.ReadAsArray(*block_xy2, *block_size2)
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)
if send_message is not None:
send_message.emit(f'完成{j}/{yblocks}')
del ds2
del ds1
out_ds.FlushCache()
del out_ds
if send_message is not None:
send_message.emit('归一化概率中...')
temp_in_ds = gdal.Open(out_tif)
out_normal_tif = os.path.join(Project().cmi_path, '{}_{}_cmi.tif'.format(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(geo)
out_normal_ds.SetProjection(proj)
# 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
if send_message is not None:
send_message.emit('差分法计算完成')
return out_normal_tif
@UNSUPER_CD.register
class LSTS(AlgFrontend):
@staticmethod
def get_name():
return 'LSTS'
@staticmethod
def get_widget(parent=None):
widget = QtWidgets.QWidget(parent)
return widget
@staticmethod
def get_params(widget=None):
return dict(n=5, w_size=(3,3))
@staticmethod
def run_alg(pth1:str,pth2:str,layer_parent:PairLayer,send_message=None,n=5,w_size=(3,3), *args, **kws):
ds1:gdal.Dataset=gdal.Open(pth1)
ds2:gdal.Dataset=gdal.Open(pth2)
cell_size = layer_parent.cell_size
xsize = layer_parent.size[0]
ysize = layer_parent.size[1]
band = ds1.RasterCount
yblocks = ysize // cell_size[1]
driver = gdal.GetDriverByName('GTiff')
out_tif = os.path.join(Project().other_path, '%d.tif'%(int(datetime.now().timestamp() * 1000)))
out_ds = driver.Create(out_tif, xsize, ysize, 1, gdal.GDT_Float32)
geo=layer_parent.grid.geo
proj=layer_parent.grid.proj
out_ds.SetGeoTransform(geo)
out_ds.SetProjection(proj)
pixnum=w_size[0]*w_size[1]
# send_message.emit('pixnum:'pixnum)
max_diff = 0
min_diff = math.inf
win_h=w_size[0]//2 #half hight of window
win_w=w_size[1]//2 #half width of window
a=[[(i+1)**j for j in range(n+1)] for i in range(pixnum)]
A=np.array(a).astype(np.float64)#
k_=np.array(range(1,n+1))
df1=np.zeros(pixnum).astype(np.float64)
df2=np.zeros(pixnum).astype(np.float64)
start1x,start1y=geo2imageRC(ds1.GetGeoTransform(),layer_parent.mask.xy[0],layer_parent.mask.xy[1])
end1x,end1y=geo2imageRC(ds1.GetGeoTransform(),layer_parent.mask.xy[2],layer_parent.mask.xy[3])
start2x,start2y=geo2imageRC(ds2.GetGeoTransform(),layer_parent.mask.xy[0],layer_parent.mask.xy[1])
end2x,end2y=geo2imageRC(ds2.GetGeoTransform(),layer_parent.mask.xy[2],layer_parent.mask.xy[3])
for j in range(yblocks + 1):
if send_message is not None:
send_message.emit(f'计算{j}/{yblocks}')
block_xy1 = (start1x, start1y+j * cell_size[1])
block_xy2 = (start2x,start2y+j*cell_size[1])
block_xy=(0,j * cell_size[1])
if block_xy1[1] > end1y or block_xy2[1] > end2y:
break
block_size=(xsize, cell_size[1])
block_size1 = (xsize, cell_size[1])
block_size2 = (xsize,cell_size[1])
if block_xy[1] + block_size[1] > ysize:
block_size = (xsize, ysize - block_xy[1])
if block_xy1[1] + block_size1[1] > end1y:
block_size1 = (xsize,end1y - block_xy1[1])
if block_xy2[1] + block_size2[1] > end2y:
block_size2 = (xsize, end2y - block_xy2[1])
block_data1 = ds1.ReadAsArray(*block_xy1, *block_size1)
block_data2 = ds2.ReadAsArray(*block_xy2, *block_size2)
if band == 1:
block_data1 = block_data1[None, ...]
block_data2 = block_data2[None, ...]
# pdb.set_trace()
else:
block_data1=np.mean(block_data1,0)
block_data2=np.mean(block_data2,0)
block_diff=np.zeros(block_data1.shape).astype(np.float64)
for i in range(win_h,block_size1[1]-win_h):
for j_ in range(win_w,block_size1[0]-win_w):
pix=0
#get b
# b1=block_data[i+win_h:i+win_h] c in range(j_-win_w,j_+win_w+1)
b1=block_data1[i-win_h:i+win_h+1,j_-win_w:j_+win_w+1]
b2=block_data2[i-win_h:i+win_h+1,j_-win_w:j_+win_w+1]
b1=[b if (r+1)//2 else b[::-1] for r,b in enumerate(b1)]
b2=[b if (r+1)//2 else b[::-1] for r,b in enumerate(b2)]
b1=np.expand_dims(np.concatenate(b1,0),1)
b2=np.expand_dims(np.concatenate(b2,0),1)
x1=np.squeeze(np.linalg.pinv(A).dot(b1))
x2=np.squeeze(np.linalg.pinv(A).dot(b2))
#df
k_=range(1,n+1)
for pix in range(1,pixnum+1):
df1[pix-1]=x1[1:n+1].dot(np.array([k*(pix**(k-1)) for k in k_]))
df2[pix-1]=x2[1:n+1].dot(np.array([k*(pix**(k-1)) for k in k_]))
#distance 欧式距离
block_diff[i][j_]=np.dot(df1-df2,df1-df2)**0.5
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)
send_message.emit(f'完成{j}/{yblocks}')
del ds2
del ds1
out_ds.FlushCache()
del out_ds
if send_message is not None:
send_message.emit('归一化概率中...')
temp_in_ds = gdal.Open(out_tif)
out_normal_tif = os.path.join(Project().cmi_path, '{}_{}_cmi.tif'.format(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(geo)
out_normal_ds.SetProjection(proj)
# 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
if send_message is not None:
send_message.emit('LSTS法计算完成')
return out_normal_tif
@UNSUPER_CD.register
class CVAAlg(AlgFrontend):
@staticmethod
def get_name():
return 'CVA'
@staticmethod
def run_alg(pth1:str,pth2:str,layer_parent:PairLayer,send_message = None, *args, **kargs):
ds1:gdal.Dataset=gdal.Open(pth1)
ds2:gdal.Dataset=gdal.Open(pth2)
cell_size = layer_parent.cell_size
xsize = layer_parent.size[0]
ysize = layer_parent.size[1]
band = ds1.RasterCount
yblocks = ysize // cell_size[1]
driver = gdal.GetDriverByName('GTiff')
out_tif = os.path.join(Project().other_path, 'temp.tif')
out_ds = driver.Create(out_tif, xsize, ysize, 1, gdal.GDT_Float32)
geo=layer_parent.grid.geo
proj=layer_parent.grid.proj
out_ds.SetGeoTransform(geo)
out_ds.SetProjection(proj)
max_diff = 0
min_diff = math.inf
start1x,start1y=geo2imageRC(ds1.GetGeoTransform(),layer_parent.mask.xy[0],layer_parent.mask.xy[1])
end1x,end1y=geo2imageRC(ds1.GetGeoTransform(),layer_parent.mask.xy[2],layer_parent.mask.xy[3])
start2x,start2y=geo2imageRC(ds2.GetGeoTransform(),layer_parent.mask.xy[0],layer_parent.mask.xy[1])
end2x,end2y=geo2imageRC(ds2.GetGeoTransform(),layer_parent.mask.xy[2],layer_parent.mask.xy[3])
for j in range(yblocks + 1):
if send_message is not None:
send_message.emit(f'计算{j}/{yblocks}')
block_xy1 = (start1x, start1y+j * cell_size[1])
block_xy2 = (start2x,start2y+j*cell_size[1])
block_xy=(0,j * cell_size[1])
if block_xy1[1] > end1y or block_xy2[1] > end2y:
break
block_size=(xsize, cell_size[1])
block_size1 = (xsize, cell_size[1])
block_size2 = (xsize,cell_size[1])
if block_xy[1] + block_size[1] > ysize:
block_size = (xsize, ysize - block_xy[1])
if block_xy1[1] + block_size1[1] > end1y:
block_size1 = (xsize,end1y - block_xy1[1])
if block_xy2[1] + block_size2[1] > end2y:
block_size2 = (xsize, end2y - block_xy2[1])
block_data1 = ds1.ReadAsArray(*block_xy1, *block_size1)
block_data2 = ds2.ReadAsArray(*block_xy2, *block_size2)
if band == 1:
block_data1 = block_data1[None, ...]
block_data2 = block_data2[None, ...]
# pdb.set_trace()
block_diff=np.sum((block_data1-block_data2)**2,0)**0.5
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)
if send_message is not None:
send_message.emit(f'完成{j}/{yblocks}')
del ds2
del ds1
out_ds.FlushCache()
del out_ds
if send_message is not None:
send_message.emit('归一化概率中...')
temp_in_ds = gdal.Open(out_tif)
out_normal_tif = os.path.join(Project().cmi_path, '{}_{}_cmi.tif'.format(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(geo)
out_normal_ds.SetProjection(proj)
# 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
if send_message is not None:
send_message.emit('欧式距离计算完成')
return out_normal_tif
@UNSUPER_CD.register
class ACDAlg(AlgFrontend):
@staticmethod
def get_name():
return 'ACD'
@staticmethod
def run_alg(pth1:str,pth2:str,layer_parent:PairLayer,send_message = None, *args, **kargs):
if send_message is None:
class Empty:
def emit(self, *args, **kws):
print(args)
send_message = Empty()
# send_message.emit = print
xsize = layer_parent.size[0]
ysize = layer_parent.size[1]
geo=layer_parent.grid.geo
proj=layer_parent.grid.proj
#提取公共部分
send_message.emit('提取重叠区域数据.....')
ds2:gdal.Dataset=gdal.Open(pth2)
temp_tif2 = os.path.join(Project().other_path,'temp2.tif')
start2x,start2y=geo2imageRC(ds2.GetGeoTransform(),layer_parent.mask.xy[0],layer_parent.mask.xy[1])
end2x,end2y=geo2imageRC(ds2.GetGeoTransform(),layer_parent.mask.xy[2],layer_parent.mask.xy[3])
warp(temp_tif2,ds2,srcWin=[start2x,start2y,xsize,ysize])
del ds2
send_message.emit('图像二提取完成')
ds1:gdal.Dataset=gdal.Open(pth1)
temp_tif1 = os.path.join(Project().other_path, 'temp1.tif')
start1x,start1y=geo2imageRC(ds1.GetGeoTransform(),layer_parent.mask.xy[0],layer_parent.mask.xy[1])
end1x,end1y=geo2imageRC(ds1.GetGeoTransform(),layer_parent.mask.xy[2],layer_parent.mask.xy[3])
warp(temp_tif1,ds1,srcWin=[start1x,start1y,xsize,ysize])
del ds1
send_message.emit('图像一提取完成')
#运算
send_message.emit('开始ACD计算.....')
time.sleep(0.1)
out_normal_tif = os.path.join(Project().cmi_path, '{}_{}_cmi.tif'.format(layer_parent.name, int(np.random.rand() * 100000)))
ACD(temp_tif1,temp_tif2,out_normal_tif)
#添加投影
send_message.emit('录入投影信息.....')
time.sleep(0.1)
ds=gdal.Open(out_normal_tif,1)
ds.SetGeoTransform(geo)
ds.SetProjection(proj)
del ds
return out_normal_tif
@UNSUPER_CD.register
class AHTAlg(AlgFrontend):
@staticmethod
def get_name():
return 'AHT'
@staticmethod
def run_alg(pth1:str,pth2:str,layer_parent:PairLayer,send_message = None, *args, **kargs):
if send_message is None:
class Empty:
def emit(self, *args, **kws):
print(args)
send_message = Empty()
xsize = layer_parent.size[0]
ysize = layer_parent.size[1]
geo=layer_parent.grid.geo
proj=layer_parent.grid.proj
#提取公共部分
send_message.emit('提取重叠区域数据.....')
ds2:gdal.Dataset=gdal.Open(pth2)
temp_tif2 = os.path.join(Project().other_path,'temp2.tif')
start2x,start2y=geo2imageRC(ds2.GetGeoTransform(),layer_parent.mask.xy[0],layer_parent.mask.xy[1])
end2x,end2y=geo2imageRC(ds2.GetGeoTransform(),layer_parent.mask.xy[2],layer_parent.mask.xy[3])
warp(temp_tif2,ds2,srcWin=[start2x,start2y,xsize,ysize])
del ds2
send_message.emit('图像二提取完成')
ds1:gdal.Dataset=gdal.Open(pth1)
temp_tif1 = os.path.join(Project().other_path, 'temp1.tif')
start1x,start1y=geo2imageRC(ds1.GetGeoTransform(),layer_parent.mask.xy[0],layer_parent.mask.xy[1])
end1x,end1y=geo2imageRC(ds1.GetGeoTransform(),layer_parent.mask.xy[2],layer_parent.mask.xy[3])
warp(temp_tif1,ds1,srcWin=[start1x,start1y,xsize,ysize])
del ds1
send_message.emit('图像一提取完成')
#运算
send_message.emit('开始AHT计算.....')
time.sleep(0.1)
out_normal_tif = os.path.join(Project().cmi_path, '{}_{}_cmi.tif'.format(layer_parent.name, int(np.random.rand() * 100000)))
AHT(temp_tif1,temp_tif2,out_normal_tif)
#添加投影
send_message.emit('录入投影信息.....')
time.sleep(0.1)
ds=gdal.Open(out_normal_tif,1)
ds.SetGeoTransform(geo)
ds.SetProjection(proj)
del ds
return out_normal_tif
@UNSUPER_CD.register
class OCDAlg(AlgFrontend):
@staticmethod
def get_name():
return 'OCD'
@staticmethod
def run_alg(pth1:str,pth2:str,layer_parent:PairLayer,send_message = None, *args, **kargs):
if send_message is None:
class Empty:
def emit(self, *args, **kws):
print(args)
send_message = Empty()
xsize = layer_parent.size[0]
ysize = layer_parent.size[1]
geo=layer_parent.grid.geo
proj=layer_parent.grid.proj
#提取公共部分
send_message.emit('提取重叠区域数据.....')
ds2:gdal.Dataset=gdal.Open(pth2)
temp_tif2 = os.path.join(Project().other_path,'temp2.tif')
start2x,start2y=geo2imageRC(ds2.GetGeoTransform(),layer_parent.mask.xy[0],layer_parent.mask.xy[1])
end2x,end2y=geo2imageRC(ds2.GetGeoTransform(),layer_parent.mask.xy[2],layer_parent.mask.xy[3])
warp(temp_tif2,ds2,srcWin=[start2x,start2y,xsize,ysize])
del ds2
send_message.emit('图像二提取完成')
ds1:gdal.Dataset=gdal.Open(pth1)
temp_tif1 = os.path.join(Project().other_path, 'temp1.tif')
start1x,start1y=geo2imageRC(ds1.GetGeoTransform(),layer_parent.mask.xy[0],layer_parent.mask.xy[1])
end1x,end1y=geo2imageRC(ds1.GetGeoTransform(),layer_parent.mask.xy[2],layer_parent.mask.xy[3])
warp(temp_tif1,ds1,srcWin=[start1x,start1y,xsize,ysize])
del ds1
send_message.emit('图像一提取完成')
#运算
send_message.emit('开始OCD计算.....')
time.sleep(0.1)
out_normal_tif = os.path.join(Project().cmi_path, '{}_{}_cmi.tif'.format(layer_parent.name, int(np.random.rand() * 100000)))
OCD(temp_tif1,temp_tif2,out_normal_tif,Project().other_path)
#添加投影
send_message.emit('录入投影信息.....')
time.sleep(0.1)
ds=gdal.Open(out_normal_tif,1)
ds.SetGeoTransform(geo)
ds.SetProjection(proj)
del ds
return out_normal_tif
@UNSUPER_CD.register
class LHBAAlg(AlgFrontend):
@staticmethod
def get_name():
return 'LHBA'
@staticmethod
def run_alg(pth1:str,pth2:str,layer_parent:PairLayer,send_message = None, *args, **kargs):
if send_message is None:
class Empty:
def emit(self, *args, **kws):
print(args)
send_message = Empty()
xsize = layer_parent.size[0]
ysize = layer_parent.size[1]
geo=layer_parent.grid.geo
proj=layer_parent.grid.proj
#提取公共部分
send_message.emit('提取重叠区域数据.....')
ds2:gdal.Dataset=gdal.Open(pth2)
temp_tif2 = os.path.join(Project().other_path,'temp2.tif')
start2x,start2y=geo2imageRC(ds2.GetGeoTransform(),layer_parent.mask.xy[0],layer_parent.mask.xy[1])
end2x,end2y=geo2imageRC(ds2.GetGeoTransform(),layer_parent.mask.xy[2],layer_parent.mask.xy[3])
warp(temp_tif2,ds2,srcWin=[start2x,start2y,xsize,ysize])
del ds2
send_message.emit('图像二提取完成')
ds1:gdal.Dataset=gdal.Open(pth1)
temp_tif1 = os.path.join(Project().other_path, 'temp1.tif')
start1x,start1y=geo2imageRC(ds1.GetGeoTransform(),layer_parent.mask.xy[0],layer_parent.mask.xy[1])
end1x,end1y=geo2imageRC(ds1.GetGeoTransform(),layer_parent.mask.xy[2],layer_parent.mask.xy[3])
warp(temp_tif1,ds1,srcWin=[start1x,start1y,xsize,ysize])
del ds1
send_message.emit('图像一提取完成')
#运算
send_message.emit('开始LHBA计算.....')
time.sleep(0.1)
out_normal_tif = os.path.join(Project().cmi_path, '{}_{}_cmi.tif'.format(layer_parent.name, int(np.random.rand() * 100000)))
LHBA(temp_tif1,temp_tif2,out_normal_tif)
#添加投影
send_message.emit('录入投影信息.....')
time.sleep(0.1)
ds=gdal.Open(out_normal_tif,1)
ds.SetGeoTransform(geo)
ds.SetProjection(proj)
del ds
return out_normal_tif
@UNSUPER_CD.register
class SHAlg(AlgFrontend):
@staticmethod
def get_name():
return 'SH'
@staticmethod
def run_alg(pth1:str,pth2:str,layer_parent:PairLayer,send_message = None, *args, **kargs):
if send_message is None:
class Empty:
def emit(self, *args, **kws):
print(args)
send_message = Empty()
xsize = layer_parent.size[0]
ysize = layer_parent.size[1]
geo=layer_parent.grid.geo
proj=layer_parent.grid.proj
#提取公共部分
send_message.emit('提取重叠区域数据.....')
ds2:gdal.Dataset=gdal.Open(pth2)
temp_tif2 = os.path.join(Project().other_path,'temp2.tif')
start2x,start2y=geo2imageRC(ds2.GetGeoTransform(),layer_parent.mask.xy[0],layer_parent.mask.xy[1])
end2x,end2y=geo2imageRC(ds2.GetGeoTransform(),layer_parent.mask.xy[2],layer_parent.mask.xy[3])
warp(temp_tif2,ds2,srcWin=[start2x,start2y,xsize,ysize])
del ds2
send_message.emit('图像二提取完成')
ds1:gdal.Dataset=gdal.Open(pth1)
temp_tif1 = os.path.join(Project().other_path, 'temp1.tif')
start1x,start1y=geo2imageRC(ds1.GetGeoTransform(),layer_parent.mask.xy[0],layer_parent.mask.xy[1])
end1x,end1y=geo2imageRC(ds1.GetGeoTransform(),layer_parent.mask.xy[2],layer_parent.mask.xy[3])
warp(temp_tif1,ds1,srcWin=[start1x,start1y,xsize,ysize])
del ds1
send_message.emit('图像一提取完成')
#运算
send_message.emit('开始SH计算.....')
time.sleep(0.1)
out_normal_tif = os.path.join(Project().cmi_path, '{}_{}_cmi.tif'.format(layer_parent.name, int(np.random.rand() * 100000)))
SH(temp_tif1,temp_tif2,out_normal_tif)
#添加投影
send_message.emit('录入投影信息.....')
time.sleep(0.1)
ds=gdal.Open(out_normal_tif,1)
ds.SetGeoTransform(geo)
ds.SetProjection(proj)
del ds
return out_normal_tif

View File

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

226
plugins/veg_method/main.py Normal file
View File

@ -0,0 +1,226 @@
from functools import partial
from threading import Thread
from plugins.misc.main import AlgFrontend
from rscder.gui.actions import ActionManager
from rscder.plugins.basic import BasicPlugin
from PyQt5.QtWidgets import QAction, QToolBar, QMenu, QDialog, QHBoxLayout, QVBoxLayout, QPushButton,QWidget,QLabel,QLineEdit,QPushButton,QComboBox,QDialogButtonBox
from rscder.gui.layercombox import PairLayerCombox
from rscder.utils.icons import IconInstance
from filter_collection import FILTER
from .scripts import VEG_CD
from thres import THRES
from misc import table_layer, AlgSelectWidget
from follow import FOLLOW
class VegtationCDMethod(QDialog):
def __init__(self,parent=None, alg:AlgFrontend=None):
super(VegtationCDMethod, self).__init__(parent)
self.alg = alg
self.setWindowTitle('植被变化检测:{}'.format(alg.get_name()))
self.setWindowIcon(IconInstance().LOGO)
self.initUI()
self.setMinimumWidth(500)
def initUI(self):
#图层
self.layer_combox = PairLayerCombox(self)
layerbox = QHBoxLayout()
layerbox.addWidget(self.layer_combox)
self.filter_select = AlgSelectWidget(self, FILTER)
self.param_widget = self.alg.get_widget(self)
self.unsupervised_menu = self.param_widget
self.thres_select = AlgSelectWidget(self, THRES)
self.ok_button = QPushButton('确定', self)
self.ok_button.setIcon(IconInstance().OK)
self.ok_button.clicked.connect(self.accept)
self.ok_button.setDefault(True)
self.cancel_button = QPushButton('取消', self)
self.cancel_button.setIcon(IconInstance().CANCEL)
self.cancel_button.clicked.connect(self.reject)
self.cancel_button.setDefault(False)
buttonbox=QDialogButtonBox(self)
buttonbox.addButton(self.ok_button,QDialogButtonBox.NoRole)
buttonbox.addButton(self.cancel_button,QDialogButtonBox.NoRole)
buttonbox.setCenterButtons(True)
totalvlayout=QVBoxLayout()
totalvlayout.addLayout(layerbox)
totalvlayout.addWidget(self.filter_select)
if self.param_widget is not None:
totalvlayout.addWidget(self.param_widget)
totalvlayout.addWidget(self.thres_select)
totalvlayout.addStretch(1)
hbox = QHBoxLayout()
hbox.addStretch(1)
hbox.addWidget(buttonbox)
totalvlayout.addLayout(hbox)
# totalvlayout.addStretch()
self.setLayout(totalvlayout)
@FOLLOW.register
class VegetationCDFollow(AlgFrontend):
@staticmethod
def get_name():
return '植被变化检测'
@staticmethod
def get_icon():
return IconInstance().UNSUPERVISED
@staticmethod
def get_widget(parent=None):
widget = QWidget(parent)
layer_combox = PairLayerCombox(widget)
layer_combox.setObjectName('layer_combox')
filter_select = AlgSelectWidget(widget, FILTER)
filter_select.setObjectName('filter_select')
unsupervised_select = AlgSelectWidget(widget, VEG_CD)
unsupervised_select.setObjectName('unsupervised_select')
thres_select = AlgSelectWidget(widget, THRES)
thres_select.setObjectName('thres_select')
totalvlayout=QVBoxLayout()
totalvlayout.addWidget(layer_combox)
totalvlayout.addWidget(filter_select)
totalvlayout.addWidget(unsupervised_select)
totalvlayout.addWidget(thres_select)
totalvlayout.addStretch()
widget.setLayout(totalvlayout)
return widget
@staticmethod
def get_params(widget:QWidget=None):
if widget is None:
return dict()
layer_combox = widget.findChild(PairLayerCombox, 'layer_combox')
filter_select = widget.findChild(AlgSelectWidget, 'filter_select')
unsupervised_select = widget.findChild(AlgSelectWidget, 'unsupervised_select')
thres_select = widget.findChild(AlgSelectWidget, 'thres_select')
layer1=layer_combox.layer1
pth1 = layer_combox.layer1.path
pth2 = layer_combox.layer2.path
falg, fparams = filter_select.get_alg_and_params()
cdalg, cdparams = unsupervised_select.get_alg_and_params()
thalg, thparams = thres_select.get_alg_and_params()
if cdalg is None or thalg is None:
return dict()
return dict(
layer1=layer1,
pth1 = pth1,
pth2 = pth2,
falg = falg,
fparams = fparams,
cdalg = cdalg,
cdparams = cdparams,
thalg = thalg,
thparams = thparams,
)
@staticmethod
def run_alg(layer1=None,
pth1 = None,
pth2 = None,
falg = None,
fparams = None,
cdalg = None,
cdparams = None,
thalg = None,
thparams = None,
send_message = None):
if cdalg is None or thalg is None:
return
name = layer1.name
if falg is not None:
pth1 = falg.run_alg(pth1, name=name, send_message= send_message, **fparams)
pth2 = falg.run_alg(pth2, name=name, send_message= send_message, **fparams)
cdpth = cdalg.run_alg(pth1, pth2, layer1.layer_parent, send_message= send_message,**cdparams)
thpth = thalg.run_alg(cdpth, name=name, send_message= send_message, **thparams)
table_layer(thpth,layer1,name, send_message)
class VegtationPlugin(BasicPlugin):
@staticmethod
def info():
return {
'name': 'VegtationPlugin',
'description': 'VegtationPlugin',
'author': 'RSCDER',
'version': '1.0.0',
}
def set_action(self):
veg_menu = ActionManager().veg_menu
# veg_menu.setIcon(IconInstance().UNSUPERVISED)
# ActionManager().veg_menu.addMenu(veg_menu)
for key in VEG_CD.keys():
alg:AlgFrontend = VEG_CD[key]
if alg.get_name() is None:
name = key
else:
name = alg.get_name()
action = QAction(name, veg_menu)
func = partial(self.run_cd, alg)
action.triggered.connect(func)
veg_menu.addAction(action)
def run_cd(self, alg):
dialog = VegtationCDMethod(self.mainwindow, alg)
dialog.show()
if dialog.exec_() == QDialog.Accepted:
t = Thread(target=self.run_cd_alg, args=(dialog,))
t.start()
def run_cd_alg(self, w:VegtationCDMethod):
layer1=w.layer_combox.layer1
pth1 = w.layer_combox.layer1.path
pth2 = w.layer_combox.layer2.path
name = layer1.layer_parent.name
falg, fparams = w.filter_select.get_alg_and_params()
cdalg = w.alg
cdparams = w.alg.get_params()
thalg, thparams = w.thres_select.get_alg_and_params()
if cdalg is None or thalg is None:
return
if falg is not None:
pth1 = falg.run_alg(pth1, name=name, send_message=self.send_message, **fparams)
pth2 = falg.run_alg(pth2, name=name, send_message=self.send_message, **fparams)
cdpth = cdalg.run_alg(pth1, pth2, layer1.layer_parent, send_message=self.send_message,**cdparams)
thpth = thalg.run_alg(cdpth, name=name, send_message=self.send_message, **thparams)
table_layer(thpth,layer1,name,self.send_message)

455
plugins/veg_method/pic.py Normal file
View File

@ -0,0 +1,455 @@
# -*- coding: utf-8 -*-
# Resource object code
#
# Created by: The Resource Compiler for PyQt5 (Qt v5.12.9)
#
# WARNING! All changes made in this file will be lost!
from PyQt5 import QtCore
qt_resource_data = b"\
\x00\x00\x05\x32\
\x3c\
\x3f\x78\x6d\x6c\x20\x76\x65\x72\x73\x69\x6f\x6e\x3d\x22\x31\x2e\
\x30\x22\x20\x73\x74\x61\x6e\x64\x61\x6c\x6f\x6e\x65\x3d\x22\x6e\
\x6f\x22\x3f\x3e\x3c\x21\x44\x4f\x43\x54\x59\x50\x45\x20\x73\x76\
\x67\x20\x50\x55\x42\x4c\x49\x43\x20\x22\x2d\x2f\x2f\x57\x33\x43\
\x2f\x2f\x44\x54\x44\x20\x53\x56\x47\x20\x31\x2e\x31\x2f\x2f\x45\
\x4e\x22\x20\x22\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\x77\x2e\x77\
\x33\x2e\x6f\x72\x67\x2f\x47\x72\x61\x70\x68\x69\x63\x73\x2f\x53\
\x56\x47\x2f\x31\x2e\x31\x2f\x44\x54\x44\x2f\x73\x76\x67\x31\x31\
\x2e\x64\x74\x64\x22\x3e\x3c\x73\x76\x67\x20\x74\x3d\x22\x31\x36\
\x35\x35\x31\x30\x35\x33\x34\x38\x31\x31\x38\x22\x20\x63\x6c\x61\
\x73\x73\x3d\x22\x69\x63\x6f\x6e\x22\x20\x76\x69\x65\x77\x42\x6f\
\x78\x3d\x22\x30\x20\x30\x20\x31\x30\x32\x34\x20\x31\x30\x32\x34\
\x22\x20\x76\x65\x72\x73\x69\x6f\x6e\x3d\x22\x31\x2e\x31\x22\x20\
\x78\x6d\x6c\x6e\x73\x3d\x22\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\
\x77\x2e\x77\x33\x2e\x6f\x72\x67\x2f\x32\x30\x30\x30\x2f\x73\x76\
\x67\x22\x20\x70\x2d\x69\x64\x3d\x22\x32\x31\x33\x37\x22\x20\x78\
\x6d\x6c\x6e\x73\x3a\x78\x6c\x69\x6e\x6b\x3d\x22\x68\x74\x74\x70\
\x3a\x2f\x2f\x77\x77\x77\x2e\x77\x33\x2e\x6f\x72\x67\x2f\x31\x39\
\x39\x39\x2f\x78\x6c\x69\x6e\x6b\x22\x20\x77\x69\x64\x74\x68\x3d\
\x22\x31\x32\x38\x22\x20\x68\x65\x69\x67\x68\x74\x3d\x22\x31\x32\
\x38\x22\x3e\x3c\x64\x65\x66\x73\x3e\x3c\x73\x74\x79\x6c\x65\x20\
\x74\x79\x70\x65\x3d\x22\x74\x65\x78\x74\x2f\x63\x73\x73\x22\x3e\
\x40\x66\x6f\x6e\x74\x2d\x66\x61\x63\x65\x20\x7b\x20\x66\x6f\x6e\
\x74\x2d\x66\x61\x6d\x69\x6c\x79\x3a\x20\x66\x65\x65\x64\x62\x61\
\x63\x6b\x2d\x69\x63\x6f\x6e\x66\x6f\x6e\x74\x3b\x20\x73\x72\x63\
\x3a\x20\x75\x72\x6c\x28\x22\x2f\x2f\x61\x74\x2e\x61\x6c\x69\x63\
\x64\x6e\x2e\x63\x6f\x6d\x2f\x74\x2f\x66\x6f\x6e\x74\x5f\x31\x30\
\x33\x31\x31\x35\x38\x5f\x75\x36\x39\x77\x38\x79\x68\x78\x64\x75\
\x2e\x77\x6f\x66\x66\x32\x3f\x74\x3d\x31\x36\x33\x30\x30\x33\x33\
\x37\x35\x39\x39\x34\x34\x22\x29\x20\x66\x6f\x72\x6d\x61\x74\x28\
\x22\x77\x6f\x66\x66\x32\x22\x29\x2c\x20\x75\x72\x6c\x28\x22\x2f\
\x2f\x61\x74\x2e\x61\x6c\x69\x63\x64\x6e\x2e\x63\x6f\x6d\x2f\x74\
\x2f\x66\x6f\x6e\x74\x5f\x31\x30\x33\x31\x31\x35\x38\x5f\x75\x36\
\x39\x77\x38\x79\x68\x78\x64\x75\x2e\x77\x6f\x66\x66\x3f\x74\x3d\
\x31\x36\x33\x30\x30\x33\x33\x37\x35\x39\x39\x34\x34\x22\x29\x20\
\x66\x6f\x72\x6d\x61\x74\x28\x22\x77\x6f\x66\x66\x22\x29\x2c\x20\
\x75\x72\x6c\x28\x22\x2f\x2f\x61\x74\x2e\x61\x6c\x69\x63\x64\x6e\
\x2e\x63\x6f\x6d\x2f\x74\x2f\x66\x6f\x6e\x74\x5f\x31\x30\x33\x31\
\x31\x35\x38\x5f\x75\x36\x39\x77\x38\x79\x68\x78\x64\x75\x2e\x74\
\x74\x66\x3f\x74\x3d\x31\x36\x33\x30\x30\x33\x33\x37\x35\x39\x39\
\x34\x34\x22\x29\x20\x66\x6f\x72\x6d\x61\x74\x28\x22\x74\x72\x75\
\x65\x74\x79\x70\x65\x22\x29\x3b\x20\x7d\x0a\x3c\x2f\x73\x74\x79\
\x6c\x65\x3e\x3c\x2f\x64\x65\x66\x73\x3e\x3c\x70\x61\x74\x68\x20\
\x64\x3d\x22\x4d\x33\x31\x32\x2e\x38\x38\x38\x38\x38\x39\x20\x39\
\x39\x35\x2e\x35\x35\x35\x35\x35\x36\x63\x2d\x31\x37\x2e\x30\x36\
\x36\x36\x36\x37\x20\x30\x2d\x32\x38\x2e\x34\x34\x34\x34\x34\x34\
\x2d\x35\x2e\x36\x38\x38\x38\x38\x39\x2d\x33\x39\x2e\x38\x32\x32\
\x32\x32\x32\x2d\x31\x37\x2e\x30\x36\x36\x36\x36\x37\x2d\x32\x32\
\x2e\x37\x35\x35\x35\x35\x36\x2d\x32\x32\x2e\x37\x35\x35\x35\x35\
\x36\x2d\x31\x37\x2e\x30\x36\x36\x36\x36\x37\x2d\x35\x36\x2e\x38\
\x38\x38\x38\x38\x39\x20\x35\x2e\x36\x38\x38\x38\x38\x39\x2d\x37\
\x39\x2e\x36\x34\x34\x34\x34\x35\x6c\x33\x36\x34\x2e\x30\x38\x38\
\x38\x38\x38\x2d\x33\x32\x39\x2e\x39\x35\x35\x35\x35\x35\x63\x31\
\x31\x2e\x33\x37\x37\x37\x37\x38\x2d\x31\x31\x2e\x33\x37\x37\x37\
\x37\x38\x20\x31\x37\x2e\x30\x36\x36\x36\x36\x37\x2d\x32\x32\x2e\
\x37\x35\x35\x35\x35\x36\x20\x31\x37\x2e\x30\x36\x36\x36\x36\x37\
\x2d\x33\x34\x2e\x31\x33\x33\x33\x33\x33\x20\x30\x2d\x31\x31\x2e\
\x33\x37\x37\x37\x37\x38\x2d\x35\x2e\x36\x38\x38\x38\x38\x39\x2d\
\x32\x32\x2e\x37\x35\x35\x35\x35\x36\x2d\x31\x37\x2e\x30\x36\x36\
\x36\x36\x37\x2d\x33\x34\x2e\x31\x33\x33\x33\x33\x34\x4c\x32\x37\
\x33\x2e\x30\x36\x36\x36\x36\x37\x20\x31\x38\x37\x2e\x37\x33\x33\
\x33\x33\x33\x63\x2d\x32\x32\x2e\x37\x35\x35\x35\x35\x36\x2d\x32\
\x32\x2e\x37\x35\x35\x35\x35\x36\x2d\x32\x38\x2e\x34\x34\x34\x34\
\x34\x34\x2d\x35\x36\x2e\x38\x38\x38\x38\x38\x39\x2d\x35\x2e\x36\
\x38\x38\x38\x38\x39\x2d\x37\x39\x2e\x36\x34\x34\x34\x34\x34\x20\
\x32\x32\x2e\x37\x35\x35\x35\x35\x36\x2d\x32\x32\x2e\x37\x35\x35\
\x35\x35\x36\x20\x35\x36\x2e\x38\x38\x38\x38\x38\x39\x2d\x32\x38\
\x2e\x34\x34\x34\x34\x34\x34\x20\x37\x39\x2e\x36\x34\x34\x34\x34\
\x34\x2d\x35\x2e\x36\x38\x38\x38\x38\x39\x6c\x33\x36\x34\x2e\x30\
\x38\x38\x38\x38\x39\x20\x33\x31\x32\x2e\x38\x38\x38\x38\x38\x39\
\x63\x33\x34\x2e\x31\x33\x33\x33\x33\x33\x20\x32\x38\x2e\x34\x34\
\x34\x34\x34\x34\x20\x35\x36\x2e\x38\x38\x38\x38\x38\x39\x20\x37\
\x33\x2e\x39\x35\x35\x35\x35\x36\x20\x35\x36\x2e\x38\x38\x38\x38\
\x38\x39\x20\x31\x31\x39\x2e\x34\x36\x36\x36\x36\x37\x73\x2d\x31\
\x37\x2e\x30\x36\x36\x36\x36\x37\x20\x38\x35\x2e\x33\x33\x33\x33\
\x33\x33\x2d\x35\x31\x2e\x32\x20\x31\x31\x39\x2e\x34\x36\x36\x36\
\x36\x36\x6c\x2d\x33\x36\x34\x2e\x30\x38\x38\x38\x38\x39\x20\x33\
\x32\x39\x2e\x39\x35\x35\x35\x35\x36\x63\x2d\x31\x31\x2e\x33\x37\
\x37\x37\x37\x38\x20\x35\x2e\x36\x38\x38\x38\x38\x39\x2d\x32\x38\
\x2e\x34\x34\x34\x34\x34\x34\x20\x31\x31\x2e\x33\x37\x37\x37\x37\
\x38\x2d\x33\x39\x2e\x38\x32\x32\x32\x32\x32\x20\x31\x31\x2e\x33\
\x37\x37\x37\x37\x38\x7a\x22\x20\x70\x2d\x69\x64\x3d\x22\x32\x31\
\x33\x38\x22\x3e\x3c\x2f\x70\x61\x74\x68\x3e\x3c\x2f\x73\x76\x67\
\x3e\
\x00\x00\x04\xf8\
\x89\
\x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52\x00\
\x00\x00\x80\x00\x00\x00\x80\x08\x06\x00\x00\x00\xc3\x3e\x61\xcb\
\x00\x00\x00\x01\x73\x52\x47\x42\x00\xae\xce\x1c\xe9\x00\x00\x04\
\xb2\x49\x44\x41\x54\x78\x5e\xed\x99\xef\x8e\x15\x45\x10\xc5\xab\
\xf7\x71\xf0\x31\xa6\x7b\xdf\x40\xfc\x13\x10\x54\xa2\x04\x95\x68\
\x50\x09\x2a\x51\x09\x2a\x41\x45\x09\x2a\x41\x82\x88\x4a\x80\x7d\
\x85\xa9\x7e\x0c\x7d\x9c\x5b\x66\xd4\xd5\x05\x2e\x5b\x3b\xe5\x07\
\xee\x9c\x3a\xfd\x75\xeb\x64\x73\xce\xf9\xa5\x7a\x66\x6e\x11\x9e\
\xd4\x09\x94\xd4\xee\x69\x5e\x08\x40\x72\x08\x08\x00\x01\x48\x9e\
\x40\x72\xfb\xdc\x00\x04\x20\x79\x02\xc9\xed\x73\x03\x10\x80\xe4\
\x09\x24\xb7\xcf\x0d\x40\x00\x92\x27\x90\xdc\x3e\x37\x00\x01\x48\
\x9e\x40\x72\xfb\xdc\x00\x04\x20\x79\x02\xc9\xed\x73\x03\x10\x80\
\xe4\x09\x24\xb7\xcf\x0d\x40\x00\x92\x27\x90\xdc\x3e\x37\x00\x01\
\x48\x9e\x40\x72\xfb\xdc\x00\x04\x20\x79\x02\xc9\xed\x73\x03\x10\
\x80\xe4\x09\x24\xb7\xcf\x0d\x40\x00\x92\x27\x90\xdc\x3e\x37\x00\
\x01\x48\x9e\x40\x72\xfb\xdc\x00\x04\x20\x79\x02\xc9\xed\x43\x6f\
\x80\x61\x18\x0e\xf5\xde\xff\x48\xde\xf1\xbe\xf6\x61\x01\x98\xca\
\xdf\xda\xda\xda\x59\xad\x56\x87\x09\xc1\x93\x19\x80\x04\x60\xb7\
\x7c\x33\x7b\xa6\x94\xf2\x3b\x21\x48\x04\xc0\xde\xf2\x77\x6d\x13\
\x82\x24\x00\xac\x2b\x9f\x10\xec\xff\x04\x04\x73\x05\xec\x57\x3e\
\x21\x00\xdf\x00\x07\x29\x9f\x10\xac\x87\x60\xf1\x1b\x60\x4e\xf9\
\x84\xe0\x71\x08\x16\x0d\x40\xa4\x7c\x42\xf0\x30\x04\x8b\x06\x60\
\xb2\x42\x08\xfe\xdf\x67\xae\xc5\x03\x40\x08\x08\xc0\x5f\x09\x70\
\x13\xc4\x40\x80\xd8\x00\xbb\xd6\x09\xc1\x7c\x08\xa0\x00\xe0\x26\
\x20\x00\xbc\x0e\x66\x32\x00\xb7\x01\x78\x1d\xcc\x23\x00\x16\x00\
\x5e\x07\x07\x03\x01\x1a\x00\x42\xe0\x43\x00\x0f\x00\x21\x48\xf2\
\x6b\xa0\xc7\x3a\x5f\x11\x41\x7f\x0c\xf2\x8a\xdf\xfb\x77\x42\x00\
\xf6\x63\xd0\x9c\xf2\xf9\x76\xc0\x0d\xf0\x6f\x02\xdc\x04\xff\xc1\
\x90\xe2\x21\x70\x1d\xfb\x84\xe0\xef\x54\xd2\x02\xc0\xb7\x03\x02\
\xc0\xcf\xc6\xd9\x37\x00\x1f\x0c\x93\x5f\x01\x7c\x45\x24\x00\x0f\
\x3d\x1f\x66\x7c\x30\x4c\xfd\x10\xc8\xb7\x03\x6e\x80\xb5\x5f\x47\
\x6a\xad\x1f\x8b\xc8\x27\x91\x0f\x4d\x22\xf2\xa9\xaa\x46\xb5\xc1\
\x7f\x19\x97\x71\x03\x3c\x92\xdd\x30\x0c\xe7\x4b\x29\x17\x22\x91\
\x9a\xd9\x85\xde\xfb\x04\xcf\x62\x0e\x01\xd8\x53\x55\xad\xf5\x43\
\x11\xb9\x18\x6c\xef\xa2\xaa\x9e\x0f\x6a\x9f\x9a\x8c\x00\xfc\x13\
\xfd\x30\x0c\xe7\x4a\x29\x9f\x07\x9b\xf8\x4c\x55\x3f\x0a\x6a\x9f\
\xaa\x8c\x00\x88\x48\x6b\xed\xac\x99\x5d\x8a\x34\x51\x4a\xf9\x62\
\x1c\xc7\x0f\x22\xda\x4d\xd0\xa4\x07\xa0\xd6\xfa\x9e\x88\x5c\x0e\
\x96\x71\x49\x55\xcf\x05\xb5\x1b\x21\x4b\x0d\x40\x6b\xed\x8c\x99\
\x7d\x15\x69\xc2\xcc\x2e\xf7\xde\xcf\x46\xb4\x9b\xa4\x49\x0b\x40\
\xad\xf5\x1d\x11\xb9\x12\x2c\xe3\x4b\x55\x7d\x3f\xa8\xdd\x28\x59\
\x4a\x00\x6a\xad\x6f\x8b\xc8\x37\x91\x26\xcc\xec\xeb\xde\xfb\xbb\
\x11\xed\x26\x6a\xd2\x01\x30\x0c\xc3\xe9\x52\xca\xd5\x48\x19\xa5\
\x94\x2b\xe3\x38\x9e\x89\x68\x37\x55\x93\x0a\x80\x5a\xeb\x9b\x22\
\x72\x2d\x58\xc6\xb7\xaa\x3a\x5d\x1b\x50\x27\x0d\x00\xc3\x30\x9c\
\x2a\xa5\x7c\x1f\x69\xcf\xcc\xae\xf6\xde\xa7\x6b\x03\xee\xa4\x00\
\xa0\xb5\x76\xd2\xcc\xae\x07\xdb\xbb\xa6\xaa\xa7\x83\xda\x8d\x97\
\xc1\x03\x50\x6b\x7d\x4d\x44\x6e\x04\x9b\xf8\x4e\x55\xdf\x0a\x6a\
\x17\x21\x83\x06\xa0\xb5\x76\xc2\xcc\x6e\x06\x9b\xf8\x41\x55\xdf\
\x08\x6a\x17\x23\x83\x05\xa0\xd6\xfa\x8a\x88\xdc\x0a\x36\x71\x5d\
\x55\x4f\x05\xb5\x8b\x92\x41\x02\xd0\x5a\x3b\x6e\x66\xb7\x23\x4d\
\x98\xd9\x8d\xde\xfb\xc9\x88\x76\x89\x1a\x38\x00\x6a\xad\x2f\x89\
\xc8\x9d\x60\x19\x3f\xaa\xea\xeb\x41\xed\x22\x65\x50\x00\xb4\xd6\
\x8e\x98\xd9\xaf\xc1\x26\x6e\xaa\xea\xf4\xc0\x98\xea\xc0\x00\x50\
\x6b\x7d\x51\x44\xee\x46\xda\x2b\xa5\xdc\x1a\xc7\xf1\x44\x44\xbb\
\x74\x0d\x04\x00\xdb\xdb\xdb\xcf\xaf\x56\xab\x7b\xc1\x32\x7e\x52\
\xd5\x57\x83\xda\xc5\xcb\x16\x0f\x40\xad\xf5\xb0\x88\x3c\x88\x34\
\x61\x66\x3f\xf7\xde\x5f\x8e\x68\x51\x34\x08\x00\xec\x88\xc8\xb3\
\x73\x0b\x29\xa5\xdc\x19\xc7\xf1\xf8\x5c\x1d\xda\xfc\xe2\x01\x98\
\x0a\xa9\xb5\xce\x85\xe0\x17\x55\x3d\x86\x56\x66\xc4\x0f\x04\x00\
\x73\x20\x30\xb3\xdf\x7a\xef\x47\x23\x61\x21\x6a\x60\x00\x38\x20\
\x04\x77\x55\xf5\x08\x62\x91\x51\x4f\x50\x00\x38\x10\xdc\x53\xd5\
\xe9\x55\x91\x67\x4f\x02\x70\x00\xac\x83\xa0\x94\x72\x7f\x1c\xc7\
\x17\xd8\xfc\xe3\x09\x40\x02\xf0\x08\x04\x3b\xaa\xfa\x1c\xcb\x5f\
\x9f\x00\x2c\x00\xbb\x10\xa8\xea\xf4\x9d\x80\xe7\x09\x09\x40\x03\
\xc0\xd6\xfd\x04\x08\x80\x9f\x11\xf4\x04\x01\x80\xae\xd7\x37\x47\
\x00\xfc\x8c\xa0\x27\x08\x00\x74\xbd\xbe\x39\x02\xe0\x67\x04\x3d\
\x41\x00\xa0\xeb\xf5\xcd\x11\x00\x3f\x23\xe8\x09\x02\x00\x5d\xaf\
\x6f\x8e\x00\xf8\x19\x41\x4f\x10\x00\xe8\x7a\x7d\x73\x04\xc0\xcf\
\x08\x7a\x82\x00\x40\xd7\xeb\x9b\x23\x00\x7e\x46\xd0\x13\x04\x00\
\xba\x5e\xdf\x1c\x01\xf0\x33\x82\x9e\x20\x00\xd0\xf5\xfa\xe6\x08\
\x80\x9f\x11\xf4\x04\x01\x80\xae\xd7\x37\x47\x00\xfc\x8c\xa0\x27\
\x08\x00\x74\xbd\xbe\x39\x02\xe0\x67\x04\x3d\x41\x00\xa0\xeb\xf5\
\xcd\x11\x00\x3f\x23\xe8\x09\x02\x00\x5d\xaf\x6f\x8e\x00\xf8\x19\
\x41\x4f\x10\x00\xe8\x7a\x7d\x73\x04\xc0\xcf\x08\x7a\x82\x00\x40\
\xd7\xeb\x9b\x23\x00\x7e\x46\xd0\x13\x04\x00\xba\x5e\xdf\x1c\x01\
\xf0\x33\x82\x9e\x20\x00\xd0\xf5\xfa\xe6\x08\x80\x9f\x11\xf4\x04\
\x01\x80\xae\xd7\x37\x47\x00\xfc\x8c\xa0\x27\x08\x00\x74\xbd\xbe\
\xb9\x3f\x01\xc2\xa1\x1b\x9f\x9b\x5d\x0e\x95\x00\x00\x00\x00\x49\
\x45\x4e\x44\xae\x42\x60\x82\
\x00\x00\x05\x0d\
\x3c\
\x3f\x78\x6d\x6c\x20\x76\x65\x72\x73\x69\x6f\x6e\x3d\x22\x31\x2e\
\x30\x22\x20\x73\x74\x61\x6e\x64\x61\x6c\x6f\x6e\x65\x3d\x22\x6e\
\x6f\x22\x3f\x3e\x3c\x21\x44\x4f\x43\x54\x59\x50\x45\x20\x73\x76\
\x67\x20\x50\x55\x42\x4c\x49\x43\x20\x22\x2d\x2f\x2f\x57\x33\x43\
\x2f\x2f\x44\x54\x44\x20\x53\x56\x47\x20\x31\x2e\x31\x2f\x2f\x45\
\x4e\x22\x20\x22\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\x77\x2e\x77\
\x33\x2e\x6f\x72\x67\x2f\x47\x72\x61\x70\x68\x69\x63\x73\x2f\x53\
\x56\x47\x2f\x31\x2e\x31\x2f\x44\x54\x44\x2f\x73\x76\x67\x31\x31\
\x2e\x64\x74\x64\x22\x3e\x3c\x73\x76\x67\x20\x74\x3d\x22\x31\x36\
\x35\x35\x31\x30\x35\x33\x35\x33\x37\x31\x33\x22\x20\x63\x6c\x61\
\x73\x73\x3d\x22\x69\x63\x6f\x6e\x22\x20\x76\x69\x65\x77\x42\x6f\
\x78\x3d\x22\x30\x20\x30\x20\x31\x30\x32\x34\x20\x31\x30\x32\x34\
\x22\x20\x76\x65\x72\x73\x69\x6f\x6e\x3d\x22\x31\x2e\x31\x22\x20\
\x78\x6d\x6c\x6e\x73\x3d\x22\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\
\x77\x2e\x77\x33\x2e\x6f\x72\x67\x2f\x32\x30\x30\x30\x2f\x73\x76\
\x67\x22\x20\x70\x2d\x69\x64\x3d\x22\x32\x32\x39\x32\x22\x20\x78\
\x6d\x6c\x6e\x73\x3a\x78\x6c\x69\x6e\x6b\x3d\x22\x68\x74\x74\x70\
\x3a\x2f\x2f\x77\x77\x77\x2e\x77\x33\x2e\x6f\x72\x67\x2f\x31\x39\
\x39\x39\x2f\x78\x6c\x69\x6e\x6b\x22\x20\x77\x69\x64\x74\x68\x3d\
\x22\x31\x32\x38\x22\x20\x68\x65\x69\x67\x68\x74\x3d\x22\x31\x32\
\x38\x22\x3e\x3c\x64\x65\x66\x73\x3e\x3c\x73\x74\x79\x6c\x65\x20\
\x74\x79\x70\x65\x3d\x22\x74\x65\x78\x74\x2f\x63\x73\x73\x22\x3e\
\x40\x66\x6f\x6e\x74\x2d\x66\x61\x63\x65\x20\x7b\x20\x66\x6f\x6e\
\x74\x2d\x66\x61\x6d\x69\x6c\x79\x3a\x20\x66\x65\x65\x64\x62\x61\
\x63\x6b\x2d\x69\x63\x6f\x6e\x66\x6f\x6e\x74\x3b\x20\x73\x72\x63\
\x3a\x20\x75\x72\x6c\x28\x22\x2f\x2f\x61\x74\x2e\x61\x6c\x69\x63\
\x64\x6e\x2e\x63\x6f\x6d\x2f\x74\x2f\x66\x6f\x6e\x74\x5f\x31\x30\
\x33\x31\x31\x35\x38\x5f\x75\x36\x39\x77\x38\x79\x68\x78\x64\x75\
\x2e\x77\x6f\x66\x66\x32\x3f\x74\x3d\x31\x36\x33\x30\x30\x33\x33\
\x37\x35\x39\x39\x34\x34\x22\x29\x20\x66\x6f\x72\x6d\x61\x74\x28\
\x22\x77\x6f\x66\x66\x32\x22\x29\x2c\x20\x75\x72\x6c\x28\x22\x2f\
\x2f\x61\x74\x2e\x61\x6c\x69\x63\x64\x6e\x2e\x63\x6f\x6d\x2f\x74\
\x2f\x66\x6f\x6e\x74\x5f\x31\x30\x33\x31\x31\x35\x38\x5f\x75\x36\
\x39\x77\x38\x79\x68\x78\x64\x75\x2e\x77\x6f\x66\x66\x3f\x74\x3d\
\x31\x36\x33\x30\x30\x33\x33\x37\x35\x39\x39\x34\x34\x22\x29\x20\
\x66\x6f\x72\x6d\x61\x74\x28\x22\x77\x6f\x66\x66\x22\x29\x2c\x20\
\x75\x72\x6c\x28\x22\x2f\x2f\x61\x74\x2e\x61\x6c\x69\x63\x64\x6e\
\x2e\x63\x6f\x6d\x2f\x74\x2f\x66\x6f\x6e\x74\x5f\x31\x30\x33\x31\
\x31\x35\x38\x5f\x75\x36\x39\x77\x38\x79\x68\x78\x64\x75\x2e\x74\
\x74\x66\x3f\x74\x3d\x31\x36\x33\x30\x30\x33\x33\x37\x35\x39\x39\
\x34\x34\x22\x29\x20\x66\x6f\x72\x6d\x61\x74\x28\x22\x74\x72\x75\
\x65\x74\x79\x70\x65\x22\x29\x3b\x20\x7d\x0a\x3c\x2f\x73\x74\x79\
\x6c\x65\x3e\x3c\x2f\x64\x65\x66\x73\x3e\x3c\x70\x61\x74\x68\x20\
\x64\x3d\x22\x4d\x35\x31\x37\x2e\x36\x38\x38\x38\x38\x39\x20\x37\
\x39\x36\x2e\x34\x34\x34\x34\x34\x34\x63\x2d\x34\x35\x2e\x35\x31\
\x31\x31\x31\x31\x20\x30\x2d\x38\x35\x2e\x33\x33\x33\x33\x33\x33\
\x2d\x31\x37\x2e\x30\x36\x36\x36\x36\x37\x2d\x31\x31\x39\x2e\x34\
\x36\x36\x36\x36\x37\x2d\x35\x31\x2e\x32\x4c\x37\x33\x2e\x39\x35\
\x35\x35\x35\x36\x20\x33\x38\x31\x2e\x31\x35\x35\x35\x35\x36\x63\
\x2d\x32\x32\x2e\x37\x35\x35\x35\x35\x36\x2d\x32\x32\x2e\x37\x35\
\x35\x35\x35\x36\x2d\x31\x37\x2e\x30\x36\x36\x36\x36\x37\x2d\x35\
\x36\x2e\x38\x38\x38\x38\x38\x39\x20\x35\x2e\x36\x38\x38\x38\x38\
\x38\x2d\x37\x39\x2e\x36\x34\x34\x34\x34\x35\x20\x32\x32\x2e\x37\
\x35\x35\x35\x35\x36\x2d\x32\x32\x2e\x37\x35\x35\x35\x35\x36\x20\
\x35\x36\x2e\x38\x38\x38\x38\x38\x39\x2d\x31\x37\x2e\x30\x36\x36\
\x36\x36\x37\x20\x37\x39\x2e\x36\x34\x34\x34\x34\x35\x20\x35\x2e\
\x36\x38\x38\x38\x38\x39\x6c\x33\x32\x39\x2e\x39\x35\x35\x35\x35\
\x35\x20\x33\x36\x34\x2e\x30\x38\x38\x38\x38\x39\x63\x35\x2e\x36\
\x38\x38\x38\x38\x39\x20\x35\x2e\x36\x38\x38\x38\x38\x39\x20\x31\
\x37\x2e\x30\x36\x36\x36\x36\x37\x20\x31\x31\x2e\x33\x37\x37\x37\
\x37\x38\x20\x32\x38\x2e\x34\x34\x34\x34\x34\x35\x20\x31\x31\x2e\
\x33\x37\x37\x37\x37\x38\x73\x32\x32\x2e\x37\x35\x35\x35\x35\x36\
\x2d\x35\x2e\x36\x38\x38\x38\x38\x39\x20\x33\x34\x2e\x31\x33\x33\
\x33\x33\x33\x2d\x31\x37\x2e\x30\x36\x36\x36\x36\x37\x6c\x33\x31\
\x32\x2e\x38\x38\x38\x38\x38\x39\x2d\x33\x36\x34\x2e\x30\x38\x38\
\x38\x38\x39\x63\x32\x32\x2e\x37\x35\x35\x35\x35\x36\x2d\x32\x32\
\x2e\x37\x35\x35\x35\x35\x36\x20\x35\x36\x2e\x38\x38\x38\x38\x38\
\x39\x2d\x32\x38\x2e\x34\x34\x34\x34\x34\x34\x20\x37\x39\x2e\x36\
\x34\x34\x34\x34\x35\x2d\x35\x2e\x36\x38\x38\x38\x38\x39\x20\x32\
\x32\x2e\x37\x35\x35\x35\x35\x36\x20\x32\x32\x2e\x37\x35\x35\x35\
\x35\x36\x20\x32\x38\x2e\x34\x34\x34\x34\x34\x34\x20\x35\x36\x2e\
\x38\x38\x38\x38\x38\x39\x20\x35\x2e\x36\x38\x38\x38\x38\x38\x20\
\x37\x39\x2e\x36\x34\x34\x34\x34\x35\x4c\x36\x33\x37\x2e\x31\x35\
\x35\x35\x35\x36\x20\x37\x33\x39\x2e\x35\x35\x35\x35\x35\x36\x63\
\x2d\x32\x38\x2e\x34\x34\x34\x34\x34\x34\x20\x33\x39\x2e\x38\x32\
\x32\x32\x32\x32\x2d\x36\x38\x2e\x32\x36\x36\x36\x36\x37\x20\x35\
\x36\x2e\x38\x38\x38\x38\x38\x39\x2d\x31\x31\x39\x2e\x34\x36\x36\
\x36\x36\x37\x20\x35\x36\x2e\x38\x38\x38\x38\x38\x38\x20\x35\x2e\
\x36\x38\x38\x38\x38\x39\x20\x30\x20\x30\x20\x30\x20\x30\x20\x30\
\x7a\x22\x20\x70\x2d\x69\x64\x3d\x22\x32\x32\x39\x33\x22\x3e\x3c\
\x2f\x70\x61\x74\x68\x3e\x3c\x2f\x73\x76\x67\x3e\
\x00\x00\x07\x08\
\x89\
\x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52\x00\
\x00\x00\x80\x00\x00\x00\x80\x08\x06\x00\x00\x00\xc3\x3e\x61\xcb\
\x00\x00\x00\x01\x73\x52\x47\x42\x00\xae\xce\x1c\xe9\x00\x00\x06\
\xc2\x49\x44\x41\x54\x78\x5e\xed\x9b\x7b\x68\x1c\x55\x14\xc6\xcf\
\xc9\x6c\x51\x50\x50\xa2\x28\xa8\x28\x28\x28\x28\x28\x28\x28\x28\
\xe8\xec\xce\xce\x2e\x0a\x0a\x2a\xe6\x61\xd3\x52\x69\xf1\x51\xd1\
\xfa\x2a\x4a\x8b\x62\x8b\x5a\xd1\x2a\x5a\x14\x2b\x6a\x8b\x5a\xa3\
\x35\x54\xc5\x77\x66\xee\x4d\x57\x22\x0d\xc5\x42\xb1\x50\x28\x15\
\x25\x50\x14\x4a\x45\xa9\x18\x34\x66\x33\x47\x46\x6e\x30\x94\x24\
\xdd\xb9\xfb\x9a\xd9\x73\xf6\xaf\x40\xee\x77\x77\xbe\xef\xfc\xf6\
\xbb\xb3\xbb\x09\x82\x3c\x58\x27\x80\xac\xdd\x8b\x79\x10\x00\x98\
\x43\x20\x00\x08\x00\xcc\x13\x60\x6e\x5f\x1a\x40\x00\x60\x9e\x00\
\x73\xfb\xd2\x00\x02\x00\xf3\x04\x98\xdb\x97\x06\x10\x00\x98\x27\
\xc0\xdc\xbe\x34\x80\x00\xc0\x3c\x01\xe6\xf6\xa5\x01\x04\x00\xe6\
\x09\x30\xb7\x2f\x0d\x20\x00\x30\x4f\x80\xb9\x7d\x69\x00\x01\x80\
\x79\x02\xcc\xed\x4b\x03\x08\x00\xcc\x13\x60\x6e\x5f\x1a\x40\x00\
\x60\x9e\x00\x73\xfb\xd2\x00\x02\x00\xf3\x04\x98\xdb\x97\x06\x10\
\x00\x98\x27\xc0\xdc\xbe\x34\x80\x00\xc0\x3c\x01\xe6\xf6\xa5\x01\
\x04\x00\xe6\x09\x30\xb7\x2f\x0d\x20\x00\x30\x4f\x80\xb9\x7d\x69\
\x00\x01\x80\x79\x02\xcc\xed\x4b\x03\x08\x00\xcc\x13\x60\x6e\x5f\
\x1a\x40\x00\x60\x9e\x00\x73\xfb\xd2\x00\x02\x00\xf3\x04\x98\xdb\
\x97\x06\x10\x00\x98\x27\xc0\xdc\x7e\xe6\x1a\xc0\xf7\xfd\xf5\xd5\
\x6a\x75\xc7\xce\x9d\x3b\xbf\x4f\xfb\xec\x5c\xd7\xcd\xe5\x72\xb9\
\x41\xa5\x54\x4f\x5a\xaf\x35\x53\x00\x78\x9e\xb7\x11\x11\x1f\x06\
\x80\x83\x44\x34\xa0\xb5\xfe\x2e\xad\xc1\xba\xae\x7b\xa2\xe3\x38\
\x83\x88\x78\x33\x00\x0c\xa5\x15\x82\xcc\x00\x50\x2c\x16\x5f\x05\
\x80\x95\x33\x03\x27\xa2\x71\xc7\x71\x16\x07\x41\xb0\x2b\x6d\x10\
\xb8\xae\x7b\xb2\x19\xfe\x8d\xb3\xae\x2d\x95\x10\x64\x02\x00\xcf\
\xf3\xb6\x22\xe2\xb2\x39\x06\xfd\x33\x00\x0c\x28\xa5\x2a\x69\x81\
\xc0\x75\xdd\x53\xcd\xf0\xaf\x9f\xe3\x9a\x52\x07\x41\xaa\x01\x88\
\x6b\x34\x97\xcb\x6d\x03\x80\x5b\x17\x18\xf0\x11\x44\x1c\x08\xc3\
\x30\x68\x37\x04\xae\xeb\x9e\xbe\x68\xd1\xa2\x41\x22\xf2\x17\xb8\
\x96\x54\x41\x90\x5a\x00\xca\xe5\x72\xf7\xf4\xf4\xf4\x20\x00\x94\
\x6b\x18\xec\x51\x73\x4f\xf0\x79\x0d\x6b\x9b\xb2\xc4\xf3\xbc\x33\
\x11\xf1\x7d\x00\xc8\xd7\xf0\x04\xa9\x81\x20\x95\x00\xb8\xae\x7b\
\x8e\xe3\x38\xdb\x11\xf1\xea\x1a\xc2\x9c\x59\xf2\x97\x39\x0e\x3e\
\x4a\xa0\x69\xc8\xd2\x42\xa1\x70\x76\x5c\xfb\x44\x74\x6d\x82\x0d\
\x53\x01\x41\xea\x00\xc8\xe7\xf3\x17\x39\x8e\xf3\x21\x00\x5c\x9a\
\x20\xcc\x99\xa5\xd3\x44\xb4\x58\x6b\xbd\xdd\x42\x6b\x25\x29\x14\
\x0a\xe7\x99\xe1\x27\x81\x75\xe6\xb9\xda\x0e\x41\xea\x00\x88\x93\
\xf1\x7d\xff\x09\x22\x5a\x67\x35\x11\x00\x40\xc4\xa5\x61\x18\xbe\
\x6b\xab\xaf\x55\x57\x28\x14\x2e\x30\xc3\xbf\xb2\x56\xcd\xac\x75\
\x11\x00\xf4\x28\xa5\x76\x58\x68\x1b\x26\x49\x25\x00\xb1\x3b\xcf\
\xf3\x1e\x47\xc4\xf5\xb6\x4e\x89\x68\x85\xd6\xfa\x2d\x5b\xfd\xf1\
\x74\xa6\xa9\xe2\x7b\x94\xcb\x8f\xb7\x76\x8e\xdf\x4f\x11\x51\x8f\
\xd6\xfa\x13\x0b\x6d\x43\x25\xa9\x05\x20\x76\x59\x2c\x16\xd7\x02\
\xc0\x53\x75\x38\x5e\xa9\x94\x7a\xad\x0e\xfd\x9c\xd2\x7c\x3e\x7f\
\x49\xfc\xca\xb7\x3c\xa6\xfe\xee\xea\xea\xea\x09\x82\xe0\xb3\x46\
\x5f\x97\xcd\x7e\xa9\x06\xc0\x1c\x07\x6b\x88\xe8\x69\x1b\x73\xb1\
\x86\x88\x1e\xd0\x5a\xbf\x6c\xab\x3f\x56\x57\x2e\x97\x2f\x33\xef\
\x4e\x2e\xb6\xd8\x73\x02\x11\x7b\xc2\x30\xfc\xd2\x42\xdb\x14\x49\
\xea\x01\x30\x4d\xf0\x18\x00\x6c\xa8\x23\x81\xd5\x4a\xa9\x8d\x75\
\xe8\xff\x93\x96\x4a\xa5\x2b\xa2\x28\x8a\x5f\xf9\x17\x5a\xec\xf5\
\x07\x11\xf5\x6a\xad\xbf\xb6\xd0\x36\x4d\x92\x09\x00\x4c\x13\x3c\
\x4a\x44\xcf\xda\x26\x81\x88\x6b\xc3\x30\x7c\xc6\x56\x5f\x2a\x95\
\xae\x32\xc3\x3f\x3f\xe9\x1e\x88\xf8\x7b\x14\x45\xf1\xf0\xc3\xa4\
\xda\x66\xaf\xcf\x0c\x00\xa6\x09\x56\x03\xc0\x73\x75\x84\xb2\x4e\
\x29\xf5\x64\x52\xbd\xef\xfb\xd7\x10\x51\xfc\xca\x3f\x37\xa9\x16\
\x00\x7e\xed\xea\xea\xea\x0d\x82\x60\xc4\x42\xdb\x74\x49\xa6\x00\
\x30\x10\x3c\x02\x00\xcf\xdb\x26\x83\x88\x1b\xc2\x30\x5c\x53\xab\
\xde\xf7\xfd\xeb\xcc\xf0\xcf\xaa\x55\x33\x6b\xdd\x61\x44\xec\x0d\
\xc3\xf0\x1b\x0b\x6d\x4b\x24\x99\x03\xc0\x1c\x07\x0f\x11\xd1\x0b\
\xb6\x09\xc5\x5a\xad\x75\x0c\xd2\x82\x8f\x52\xa9\x54\x88\xa2\x28\
\xfe\x78\xf7\x8c\xe3\xad\x9d\xe3\xf7\xbf\x00\x40\xaf\x52\xea\x5b\
\x0b\x6d\xcb\x24\x99\x04\xc0\x34\xc1\x83\x00\xf0\xa2\x6d\x52\x88\
\xb8\x29\x0c\xc3\x55\xf3\xe9\x7d\xdf\x2f\x99\x57\xfe\x69\x16\xcf\
\x71\xc8\xdc\xf0\x8d\x59\x68\x5b\x2a\xc9\x2c\x00\xa6\x09\x56\x11\
\xd1\x4b\x75\x24\xb6\x59\x29\x75\xcf\xb1\x7a\xdf\xf7\x6f\x30\xc3\
\x3f\x25\xe9\xde\x88\x38\x8e\x88\x7d\x41\x10\xec\x4e\xaa\x6d\xc7\
\xfa\x4c\x03\x10\x07\xe6\x79\xde\xfd\x88\x58\xcf\xfb\xfc\x2d\x4a\
\xa9\xe5\x33\xe1\xfb\xbe\x7f\x93\x19\xfe\x49\x16\x03\xf9\xc9\x9c\
\xf9\x7b\x2c\xb4\x6d\x91\x64\x1e\x00\x73\x1c\xdc\x07\x00\x9b\x6c\
\x13\x24\xa2\x6d\x5a\xeb\x25\xc5\x62\xf1\x16\x00\x88\xef\xf6\x4f\
\xb0\xd8\xeb\x07\x73\xe6\xef\xb5\xd0\xb6\x4d\xd2\x11\x00\x98\xe3\
\xe0\x5e\x22\x7a\xa5\x8e\x24\xe3\x6f\x20\xe3\x3f\x3c\x71\x2c\xf6\
\x38\x60\xce\xfc\x7d\x16\xda\xb6\x4a\x3a\x06\x00\x73\x1c\xac\x44\
\xc4\xf8\x6f\x07\x5b\xf6\x20\xa2\xfd\xb9\x5c\xae\x77\x78\x78\x78\
\x7f\xcb\x9e\xb4\x81\x4f\xd4\x51\x00\x98\x26\xb8\x9b\x88\x1a\xfe\
\x05\xd0\x3c\x99\xef\x33\x1f\xf2\x1c\x68\xe0\x4c\x5a\xba\x55\xc7\
\x01\x60\x9a\xe0\x2e\x44\xdc\xdc\xe4\x24\xf7\x12\x51\x9f\xd6\xfa\
\x60\x93\x9f\xa7\xa9\xdb\x77\x24\x00\xe6\xc6\xf0\x4e\x00\x78\xbd\
\x49\xe9\xed\x89\xa2\xa8\x6f\x64\x64\xe4\xc7\x26\xed\xdf\xb2\x6d\
\x3b\x16\x00\x73\x1c\xac\x20\xa2\x37\x1a\x9c\xe6\xee\x6a\xb5\xda\
\x57\xa9\x54\xc6\x1b\xbc\x6f\x5b\xb6\xeb\x68\x00\xcc\x71\xb0\x1c\
\x11\xdf\x6c\x44\xba\x88\xb8\xcb\x7c\xc8\x73\xa8\x11\xfb\xa5\x61\
\x8f\x8e\x07\xc0\x1c\x07\x77\x00\xc0\x96\x3a\x03\x1f\x8d\x87\x1f\
\x86\x61\xfc\x19\x7f\xc7\x3c\x58\x00\x60\x8e\x83\x65\x44\xb4\xd5\
\x72\x72\x15\x73\xc3\x77\xd8\x52\x9f\x5a\x19\x1b\x00\x4c\x13\x2c\
\x05\x80\xb7\x13\x4e\x43\x4f\x4e\x4e\xf6\x8f\x8e\x8e\x1e\x49\xa8\
\xcb\xc4\x72\x56\x00\x98\x26\x58\x42\x44\xef\xd4\x38\x9d\xc0\x71\
\x9c\xfe\xe1\xe1\xe1\xdf\x6a\x5c\x9f\xb9\x65\xec\x00\x30\x37\x86\
\x03\x88\xb8\xe0\xff\x0d\x20\xe2\x57\x44\xd4\xaf\x94\x3a\x9a\xb9\
\xa9\x26\xb8\x60\x96\x00\x98\xe3\xe0\x76\x00\x78\x6f\x9e\xac\xbe\
\x30\x6f\xf5\xfe\x4c\x90\x65\x26\x97\xb2\x05\xc0\x1c\x07\xfd\xe6\
\xab\xdf\xd9\xc3\xfb\x74\x62\x62\xa2\x6f\x6c\x6c\x2c\xfe\x5f\xc3\
\x8e\x7f\xb0\x06\xc0\x1c\x07\xbd\x88\xf8\x41\xfc\x33\x11\x7d\xdc\
\xdd\xdd\xdd\x37\x34\x34\xf4\x4f\xc7\x4f\xde\x18\x64\x0f\x80\x39\
\x0e\x7a\x10\xf1\xb6\xa9\xa9\xa9\xfe\x4a\xa5\x52\xe5\x32\xfc\xd8\
\xa7\x00\xf0\xff\xb4\xe3\x2c\x88\xd3\xf0\x05\x00\x6e\xd3\x9e\xc3\
\xaf\x34\x00\x73\x08\x04\x00\x01\x80\x79\x02\xcc\xed\x4b\x03\x08\
\x00\xcc\x13\x60\x6e\x5f\x1a\x40\x00\x60\x9e\x00\x73\xfb\xd2\x00\
\x02\x00\xf3\x04\x98\xdb\x97\x06\x10\x00\x98\x27\xc0\xdc\xbe\x34\
\x80\x00\xc0\x3c\x01\xe6\xf6\xa5\x01\x04\x00\xe6\x09\x30\xb7\x2f\
\x0d\x20\x00\x30\x4f\x80\xb9\x7d\x69\x00\x01\x80\x79\x02\xcc\xed\
\x4b\x03\x08\x00\xcc\x13\x60\x6e\x5f\x1a\x40\x00\x60\x9e\x00\x73\
\xfb\xd2\x00\x02\x00\xf3\x04\x98\xdb\x97\x06\x10\x00\x98\x27\xc0\
\xdc\xbe\x34\x80\x00\xc0\x3c\x01\xe6\xf6\xa5\x01\x04\x00\xe6\x09\
\x30\xb7\x2f\x0d\x20\x00\x30\x4f\x80\xb9\x7d\x69\x00\x01\x80\x79\
\x02\xcc\xed\x4b\x03\x08\x00\xcc\x13\x60\x6e\x5f\x1a\x40\x00\x60\
\x9e\x00\x73\xfb\xd2\x00\x02\x00\xf3\x04\x98\xdb\x97\x06\x10\x00\
\x98\x27\xc0\xdc\xbe\x34\x80\x00\xc0\x3c\x01\xe6\xf6\xa5\x01\x98\
\x03\xf0\x2f\x1a\xf0\xdc\x90\x9e\x40\x3c\x9b\x00\x00\x00\x00\x49\
\x45\x4e\x44\xae\x42\x60\x82\
"
qt_resource_name = b"\
\x00\x07\
\x07\x3b\xe0\xb3\
\x00\x70\
\x00\x6c\x00\x75\x00\x67\x00\x69\x00\x6e\x00\x73\
\x00\x06\
\x05\x04\x66\x45\
\x00\x49\
\x00\x6e\x00\x5f\x00\x6f\x00\x6e\x00\x65\
\x00\x03\
\x00\x00\x76\xf3\
\x00\x70\
\x00\x69\x00\x63\
\x00\x08\
\x09\xe6\x72\x67\
\x7b\xad\
\x59\x34\x00\x20\x53\xf3\x00\x2e\x00\x73\x00\x76\x00\x67\
\x00\x0b\
\x0f\x8a\xc9\x87\
\x7b\xad\
\x59\x34\x00\x5f\x52\x17\x88\x68\x54\x11\x53\xf3\x00\x2e\x00\x70\x00\x6e\x00\x67\
\x00\x08\
\x04\x1e\x72\x67\
\x7b\xad\
\x59\x34\x00\x20\x4e\x0b\x00\x2e\x00\x73\x00\x76\x00\x67\
\x00\x0b\
\x0e\xdf\xc8\xa7\
\x7b\xad\
\x59\x34\x00\x5f\x52\x17\x88\x68\x5c\x55\x5f\x00\x00\x2e\x00\x70\x00\x6e\x00\x67\
"
qt_resource_struct_v1 = b"\
\x00\x00\x00\x00\x00\x02\x00\x00\x00\x01\x00\x00\x00\x01\
\x00\x00\x00\x00\x00\x02\x00\x00\x00\x01\x00\x00\x00\x02\
\x00\x00\x00\x14\x00\x02\x00\x00\x00\x01\x00\x00\x00\x03\
\x00\x00\x00\x26\x00\x02\x00\x00\x00\x04\x00\x00\x00\x04\
\x00\x00\x00\x64\x00\x00\x00\x00\x00\x01\x00\x00\x0a\x32\
\x00\x00\x00\x32\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\
\x00\x00\x00\x7a\x00\x00\x00\x00\x00\x01\x00\x00\x0f\x43\
\x00\x00\x00\x48\x00\x00\x00\x00\x00\x01\x00\x00\x05\x36\
"
qt_resource_struct_v2 = b"\
\x00\x00\x00\x00\x00\x02\x00\x00\x00\x01\x00\x00\x00\x01\
\x00\x00\x00\x00\x00\x00\x00\x00\
\x00\x00\x00\x00\x00\x02\x00\x00\x00\x01\x00\x00\x00\x02\
\x00\x00\x00\x00\x00\x00\x00\x00\
\x00\x00\x00\x14\x00\x02\x00\x00\x00\x01\x00\x00\x00\x03\
\x00\x00\x00\x00\x00\x00\x00\x00\
\x00\x00\x00\x26\x00\x02\x00\x00\x00\x04\x00\x00\x00\x04\
\x00\x00\x00\x00\x00\x00\x00\x00\
\x00\x00\x00\x64\x00\x00\x00\x00\x00\x01\x00\x00\x0a\x32\
\x00\x00\x01\x81\x5b\xf7\x7e\xef\
\x00\x00\x00\x32\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\
\x00\x00\x01\x81\x5b\xf7\x72\x92\
\x00\x00\x00\x7a\x00\x00\x00\x00\x00\x01\x00\x00\x0f\x43\
\x00\x00\x01\x81\x5b\xfc\x68\x05\
\x00\x00\x00\x48\x00\x00\x00\x00\x00\x01\x00\x00\x05\x36\
\x00\x00\x01\x81\x5b\xfc\x85\xb4\
"
qt_version = [int(v) for v in QtCore.qVersion().split('.')]
if qt_version < [5, 8, 0]:
rcc_version = 1
qt_resource_struct = qt_resource_struct_v1
else:
rcc_version = 2
qt_resource_struct = qt_resource_struct_v2
def qInitResources():
QtCore.qRegisterResourceData(rcc_version, qt_resource_struct, qt_resource_name, qt_resource_data)
def qCleanupResources():
QtCore.qUnregisterResourceData(rcc_version, qt_resource_struct, qt_resource_name, qt_resource_data)
qInitResources()

View File

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,690 @@
from datetime import datetime
from osgeo import gdal
import math,os
import time
from PyQt5 import QtWidgets
from sklearn.cluster import k_means
from rscder.utils.geomath import geo2imageRC, imageRC2geo
from rscder.utils.project import Project, PairLayer
from misc import Register, AlgFrontend
VEG_CD = Register('植被变化检测方法')
import numpy as np
from .ACD import ACD
from .AHT import AHT
from .OCD import OCD
from .LHBA import LHBA
from .SH import SH
def warp(file,ds:gdal.Dataset,srcWin=[0,0,0,0]):
driver = gdal.GetDriverByName('GTiff')
xsize=ds.RasterXSize
ysize=ds.RasterYSize
geo=ds.GetGeoTransform()
orj=ds.GetProjection()
band=ds.RasterCount
if os.path.exists(file):
os.remove(file)
out_ds:gdal.Dataset=driver.Create(file, xsize, ysize, band, gdal.GDT_Byte)
out_ds.SetGeoTransform(geo)
out_ds.SetProjection(orj)
for b in range(1,band+1):
out_ds.GetRasterBand(b).WriteArray(ds.ReadAsArray(*srcWin,band_list=[b]),*(0,0))
del out_ds
@VEG_CD.register
class BasicCD(AlgFrontend):
@staticmethod
def get_name():
return '差分法'
@staticmethod
def run_alg(pth1:str,pth2:str,layer_parent:PairLayer,send_message = None,*args, **kargs):
ds1:gdal.Dataset=gdal.Open(pth1)
ds2:gdal.Dataset=gdal.Open(pth2)
cell_size = layer_parent.cell_size
xsize = layer_parent.size[0]
ysize = layer_parent.size[1]
band = ds1.RasterCount
yblocks = ysize // cell_size[1]
driver = gdal.GetDriverByName('GTiff')
out_tif = os.path.join(Project().other_path, 'temp.tif')
out_ds = driver.Create(out_tif, xsize, ysize, 1, gdal.GDT_Float32)
geo=layer_parent.grid.geo
proj=layer_parent.grid.proj
out_ds.SetGeoTransform(geo)
out_ds.SetProjection(proj)
max_diff = 0
min_diff = math.inf
start1x,start1y=geo2imageRC(ds1.GetGeoTransform(),layer_parent.mask.xy[0],layer_parent.mask.xy[1])
end1x,end1y=geo2imageRC(ds1.GetGeoTransform(),layer_parent.mask.xy[2],layer_parent.mask.xy[3])
start2x,start2y=geo2imageRC(ds2.GetGeoTransform(),layer_parent.mask.xy[0],layer_parent.mask.xy[1])
end2x,end2y=geo2imageRC(ds2.GetGeoTransform(),layer_parent.mask.xy[2],layer_parent.mask.xy[3])
for j in range(yblocks + 1):#该改这里了
if send_message is not None:
send_message.emit(f'计算{j}/{yblocks}')
block_xy1 = (start1x, start1y+j * cell_size[1])
block_xy2 = (start2x,start2y+j*cell_size[1])
block_xy=(0,j * cell_size[1])
if block_xy1[1] > end1y or block_xy2[1] > end2y:
break
block_size=(xsize, cell_size[1])
block_size1 = (xsize, cell_size[1])
block_size2 = (xsize,cell_size[1])
if block_xy[1] + block_size[1] > ysize:
block_size = (xsize, ysize - block_xy[1])
if block_xy1[1] + block_size1[1] > end1y:
block_size1 = (xsize,end1y - block_xy1[1])
if block_xy2[1] + block_size2[1] > end2y:
block_size2 = (xsize, end2y - block_xy2[1])
block_data1 = ds1.ReadAsArray(*block_xy1, *block_size1)
block_data2 = ds2.ReadAsArray(*block_xy2, *block_size2)
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)
if send_message is not None:
send_message.emit(f'完成{j}/{yblocks}')
del ds2
del ds1
out_ds.FlushCache()
del out_ds
if send_message is not None:
send_message.emit('归一化概率中...')
temp_in_ds = gdal.Open(out_tif)
out_normal_tif = os.path.join(Project().cmi_path, '{}_{}_cmi.tif'.format(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(geo)
out_normal_ds.SetProjection(proj)
# 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
if send_message is not None:
send_message.emit('差分法计算完成')
return out_normal_tif
@VEG_CD.register
class LSTS(AlgFrontend):
@staticmethod
def get_name():
return 'LSTS'
@staticmethod
def get_widget(parent=None):
widget = QtWidgets.QWidget(parent)
return widget
@staticmethod
def get_params(widget=None):
return dict(n=5, w_size=(3,3))
@staticmethod
def run_alg(pth1:str,pth2:str,layer_parent:PairLayer,send_message=None,n=5,w_size=(3,3), *args, **kws):
ds1:gdal.Dataset=gdal.Open(pth1)
ds2:gdal.Dataset=gdal.Open(pth2)
cell_size = layer_parent.cell_size
xsize = layer_parent.size[0]
ysize = layer_parent.size[1]
band = ds1.RasterCount
yblocks = ysize // cell_size[1]
driver = gdal.GetDriverByName('GTiff')
out_tif = os.path.join(Project().other_path, '%d.tif'%(int(datetime.now().timestamp() * 1000)))
out_ds = driver.Create(out_tif, xsize, ysize, 1, gdal.GDT_Float32)
geo=layer_parent.grid.geo
proj=layer_parent.grid.proj
out_ds.SetGeoTransform(geo)
out_ds.SetProjection(proj)
pixnum=w_size[0]*w_size[1]
# send_message.emit('pixnum:'pixnum)
max_diff = 0
min_diff = math.inf
win_h=w_size[0]//2 #half hight of window
win_w=w_size[1]//2 #half width of window
a=[[(i+1)**j for j in range(n+1)] for i in range(pixnum)]
A=np.array(a).astype(np.float64)#
k_=np.array(range(1,n+1))
df1=np.zeros(pixnum).astype(np.float64)
df2=np.zeros(pixnum).astype(np.float64)
start1x,start1y=geo2imageRC(ds1.GetGeoTransform(),layer_parent.mask.xy[0],layer_parent.mask.xy[1])
end1x,end1y=geo2imageRC(ds1.GetGeoTransform(),layer_parent.mask.xy[2],layer_parent.mask.xy[3])
start2x,start2y=geo2imageRC(ds2.GetGeoTransform(),layer_parent.mask.xy[0],layer_parent.mask.xy[1])
end2x,end2y=geo2imageRC(ds2.GetGeoTransform(),layer_parent.mask.xy[2],layer_parent.mask.xy[3])
for j in range(yblocks + 1):
if send_message is not None:
send_message.emit(f'计算{j}/{yblocks}')
block_xy1 = (start1x, start1y+j * cell_size[1])
block_xy2 = (start2x,start2y+j*cell_size[1])
block_xy=(0,j * cell_size[1])
if block_xy1[1] > end1y or block_xy2[1] > end2y:
break
block_size=(xsize, cell_size[1])
block_size1 = (xsize, cell_size[1])
block_size2 = (xsize,cell_size[1])
if block_xy[1] + block_size[1] > ysize:
block_size = (xsize, ysize - block_xy[1])
if block_xy1[1] + block_size1[1] > end1y:
block_size1 = (xsize,end1y - block_xy1[1])
if block_xy2[1] + block_size2[1] > end2y:
block_size2 = (xsize, end2y - block_xy2[1])
block_data1 = ds1.ReadAsArray(*block_xy1, *block_size1)
block_data2 = ds2.ReadAsArray(*block_xy2, *block_size2)
if band == 1:
block_data1 = block_data1[None, ...]
block_data2 = block_data2[None, ...]
# pdb.set_trace()
else:
block_data1=np.mean(block_data1,0)
block_data2=np.mean(block_data2,0)
block_diff=np.zeros(block_data1.shape).astype(np.float64)
for i in range(win_h,block_size1[1]-win_h):
for j_ in range(win_w,block_size1[0]-win_w):
pix=0
#get b
# b1=block_data[i+win_h:i+win_h] c in range(j_-win_w,j_+win_w+1)
b1=block_data1[i-win_h:i+win_h+1,j_-win_w:j_+win_w+1]
b2=block_data2[i-win_h:i+win_h+1,j_-win_w:j_+win_w+1]
b1=[b if (r+1)//2 else b[::-1] for r,b in enumerate(b1)]
b2=[b if (r+1)//2 else b[::-1] for r,b in enumerate(b2)]
b1=np.expand_dims(np.concatenate(b1,0),1)
b2=np.expand_dims(np.concatenate(b2,0),1)
x1=np.squeeze(np.linalg.pinv(A).dot(b1))
x2=np.squeeze(np.linalg.pinv(A).dot(b2))
#df
k_=range(1,n+1)
for pix in range(1,pixnum+1):
df1[pix-1]=x1[1:n+1].dot(np.array([k*(pix**(k-1)) for k in k_]))
df2[pix-1]=x2[1:n+1].dot(np.array([k*(pix**(k-1)) for k in k_]))
#distance 欧式距离
block_diff[i][j_]=np.dot(df1-df2,df1-df2)**0.5
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)
send_message.emit(f'完成{j}/{yblocks}')
del ds2
del ds1
out_ds.FlushCache()
del out_ds
if send_message is not None:
send_message.emit('归一化概率中...')
temp_in_ds = gdal.Open(out_tif)
out_normal_tif = os.path.join(Project().cmi_path, '{}_{}_cmi.tif'.format(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(geo)
out_normal_ds.SetProjection(proj)
# 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
if send_message is not None:
send_message.emit('LSTS法计算完成')
return out_normal_tif
@VEG_CD.register
class CVAAlg(AlgFrontend):
@staticmethod
def get_name():
return 'CVA'
@staticmethod
def run_alg(pth1:str,pth2:str,layer_parent:PairLayer,send_message = None, *args, **kargs):
ds1:gdal.Dataset=gdal.Open(pth1)
ds2:gdal.Dataset=gdal.Open(pth2)
cell_size = layer_parent.cell_size
xsize = layer_parent.size[0]
ysize = layer_parent.size[1]
band = ds1.RasterCount
yblocks = ysize // cell_size[1]
driver = gdal.GetDriverByName('GTiff')
out_tif = os.path.join(Project().other_path, 'temp.tif')
out_ds = driver.Create(out_tif, xsize, ysize, 1, gdal.GDT_Float32)
geo=layer_parent.grid.geo
proj=layer_parent.grid.proj
out_ds.SetGeoTransform(geo)
out_ds.SetProjection(proj)
max_diff = 0
min_diff = math.inf
start1x,start1y=geo2imageRC(ds1.GetGeoTransform(),layer_parent.mask.xy[0],layer_parent.mask.xy[1])
end1x,end1y=geo2imageRC(ds1.GetGeoTransform(),layer_parent.mask.xy[2],layer_parent.mask.xy[3])
start2x,start2y=geo2imageRC(ds2.GetGeoTransform(),layer_parent.mask.xy[0],layer_parent.mask.xy[1])
end2x,end2y=geo2imageRC(ds2.GetGeoTransform(),layer_parent.mask.xy[2],layer_parent.mask.xy[3])
for j in range(yblocks + 1):
if send_message is not None:
send_message.emit(f'计算{j}/{yblocks}')
block_xy1 = (start1x, start1y+j * cell_size[1])
block_xy2 = (start2x,start2y+j*cell_size[1])
block_xy=(0,j * cell_size[1])
if block_xy1[1] > end1y or block_xy2[1] > end2y:
break
block_size=(xsize, cell_size[1])
block_size1 = (xsize, cell_size[1])
block_size2 = (xsize,cell_size[1])
if block_xy[1] + block_size[1] > ysize:
block_size = (xsize, ysize - block_xy[1])
if block_xy1[1] + block_size1[1] > end1y:
block_size1 = (xsize,end1y - block_xy1[1])
if block_xy2[1] + block_size2[1] > end2y:
block_size2 = (xsize, end2y - block_xy2[1])
block_data1 = ds1.ReadAsArray(*block_xy1, *block_size1)
block_data2 = ds2.ReadAsArray(*block_xy2, *block_size2)
if band == 1:
block_data1 = block_data1[None, ...]
block_data2 = block_data2[None, ...]
# pdb.set_trace()
block_diff=np.sum((block_data1-block_data2)**2,0)**0.5
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)
if send_message is not None:
send_message.emit(f'完成{j}/{yblocks}')
del ds2
del ds1
out_ds.FlushCache()
del out_ds
if send_message is not None:
send_message.emit('归一化概率中...')
temp_in_ds = gdal.Open(out_tif)
out_normal_tif = os.path.join(Project().cmi_path, '{}_{}_cmi.tif'.format(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(geo)
out_normal_ds.SetProjection(proj)
# 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
if send_message is not None:
send_message.emit('欧式距离计算完成')
return out_normal_tif
@VEG_CD.register
class ACDAlg(AlgFrontend):
@staticmethod
def get_name():
return 'ACD'
@staticmethod
def run_alg(pth1:str,pth2:str,layer_parent:PairLayer,send_message = None, *args, **kargs):
if send_message is None:
class Empty:
def emit(self, *args, **kws):
print(args)
send_message = Empty()
# send_message.emit = print
xsize = layer_parent.size[0]
ysize = layer_parent.size[1]
geo=layer_parent.grid.geo
proj=layer_parent.grid.proj
#提取公共部分
send_message.emit('提取重叠区域数据.....')
ds2:gdal.Dataset=gdal.Open(pth2)
temp_tif2 = os.path.join(Project().other_path,'temp2.tif')
start2x,start2y=geo2imageRC(ds2.GetGeoTransform(),layer_parent.mask.xy[0],layer_parent.mask.xy[1])
end2x,end2y=geo2imageRC(ds2.GetGeoTransform(),layer_parent.mask.xy[2],layer_parent.mask.xy[3])
warp(temp_tif2,ds2,srcWin=[start2x,start2y,xsize,ysize])
del ds2
send_message.emit('图像二提取完成')
ds1:gdal.Dataset=gdal.Open(pth1)
temp_tif1 = os.path.join(Project().other_path, 'temp1.tif')
start1x,start1y=geo2imageRC(ds1.GetGeoTransform(),layer_parent.mask.xy[0],layer_parent.mask.xy[1])
end1x,end1y=geo2imageRC(ds1.GetGeoTransform(),layer_parent.mask.xy[2],layer_parent.mask.xy[3])
warp(temp_tif1,ds1,srcWin=[start1x,start1y,xsize,ysize])
del ds1
send_message.emit('图像一提取完成')
#运算
send_message.emit('开始ACD计算.....')
time.sleep(0.1)
out_normal_tif = os.path.join(Project().cmi_path, '{}_{}_cmi.tif'.format(layer_parent.name, int(np.random.rand() * 100000)))
ACD(temp_tif1,temp_tif2,out_normal_tif)
#添加投影
send_message.emit('录入投影信息.....')
time.sleep(0.1)
ds=gdal.Open(out_normal_tif,1)
ds.SetGeoTransform(geo)
ds.SetProjection(proj)
del ds
return out_normal_tif
@VEG_CD.register
class AHTAlg(AlgFrontend):
@staticmethod
def get_name():
return 'AHT'
@staticmethod
def run_alg(pth1:str,pth2:str,layer_parent:PairLayer,send_message = None, *args, **kargs):
if send_message is None:
class Empty:
def emit(self, *args, **kws):
print(args)
send_message = Empty()
xsize = layer_parent.size[0]
ysize = layer_parent.size[1]
geo=layer_parent.grid.geo
proj=layer_parent.grid.proj
#提取公共部分
send_message.emit('提取重叠区域数据.....')
ds2:gdal.Dataset=gdal.Open(pth2)
temp_tif2 = os.path.join(Project().other_path,'temp2.tif')
start2x,start2y=geo2imageRC(ds2.GetGeoTransform(),layer_parent.mask.xy[0],layer_parent.mask.xy[1])
end2x,end2y=geo2imageRC(ds2.GetGeoTransform(),layer_parent.mask.xy[2],layer_parent.mask.xy[3])
warp(temp_tif2,ds2,srcWin=[start2x,start2y,xsize,ysize])
del ds2
send_message.emit('图像二提取完成')
ds1:gdal.Dataset=gdal.Open(pth1)
temp_tif1 = os.path.join(Project().other_path, 'temp1.tif')
start1x,start1y=geo2imageRC(ds1.GetGeoTransform(),layer_parent.mask.xy[0],layer_parent.mask.xy[1])
end1x,end1y=geo2imageRC(ds1.GetGeoTransform(),layer_parent.mask.xy[2],layer_parent.mask.xy[3])
warp(temp_tif1,ds1,srcWin=[start1x,start1y,xsize,ysize])
del ds1
send_message.emit('图像一提取完成')
#运算
send_message.emit('开始AHT计算.....')
time.sleep(0.1)
out_normal_tif = os.path.join(Project().cmi_path, '{}_{}_cmi.tif'.format(layer_parent.name, int(np.random.rand() * 100000)))
AHT(temp_tif1,temp_tif2,out_normal_tif)
#添加投影
send_message.emit('录入投影信息.....')
time.sleep(0.1)
ds=gdal.Open(out_normal_tif,1)
ds.SetGeoTransform(geo)
ds.SetProjection(proj)
del ds
return out_normal_tif
@VEG_CD.register
class OCDAlg(AlgFrontend):
@staticmethod
def get_name():
return 'OCD'
@staticmethod
def run_alg(pth1:str,pth2:str,layer_parent:PairLayer,send_message = None, *args, **kargs):
if send_message is None:
class Empty:
def emit(self, *args, **kws):
print(args)
send_message = Empty()
xsize = layer_parent.size[0]
ysize = layer_parent.size[1]
geo=layer_parent.grid.geo
proj=layer_parent.grid.proj
#提取公共部分
send_message.emit('提取重叠区域数据.....')
ds2:gdal.Dataset=gdal.Open(pth2)
temp_tif2 = os.path.join(Project().other_path,'temp2.tif')
start2x,start2y=geo2imageRC(ds2.GetGeoTransform(),layer_parent.mask.xy[0],layer_parent.mask.xy[1])
end2x,end2y=geo2imageRC(ds2.GetGeoTransform(),layer_parent.mask.xy[2],layer_parent.mask.xy[3])
warp(temp_tif2,ds2,srcWin=[start2x,start2y,xsize,ysize])
del ds2
send_message.emit('图像二提取完成')
ds1:gdal.Dataset=gdal.Open(pth1)
temp_tif1 = os.path.join(Project().other_path, 'temp1.tif')
start1x,start1y=geo2imageRC(ds1.GetGeoTransform(),layer_parent.mask.xy[0],layer_parent.mask.xy[1])
end1x,end1y=geo2imageRC(ds1.GetGeoTransform(),layer_parent.mask.xy[2],layer_parent.mask.xy[3])
warp(temp_tif1,ds1,srcWin=[start1x,start1y,xsize,ysize])
del ds1
send_message.emit('图像一提取完成')
#运算
send_message.emit('开始OCD计算.....')
time.sleep(0.1)
out_normal_tif = os.path.join(Project().cmi_path, '{}_{}_cmi.tif'.format(layer_parent.name, int(np.random.rand() * 100000)))
OCD(temp_tif1,temp_tif2,out_normal_tif,Project().other_path)
#添加投影
send_message.emit('录入投影信息.....')
time.sleep(0.1)
ds=gdal.Open(out_normal_tif,1)
ds.SetGeoTransform(geo)
ds.SetProjection(proj)
del ds
return out_normal_tif
@VEG_CD.register
class LHBAAlg(AlgFrontend):
@staticmethod
def get_name():
return 'LHBA'
@staticmethod
def run_alg(pth1:str,pth2:str,layer_parent:PairLayer,send_message = None, *args, **kargs):
if send_message is None:
class Empty:
def emit(self, *args, **kws):
print(args)
send_message = Empty()
xsize = layer_parent.size[0]
ysize = layer_parent.size[1]
geo=layer_parent.grid.geo
proj=layer_parent.grid.proj
#提取公共部分
send_message.emit('提取重叠区域数据.....')
ds2:gdal.Dataset=gdal.Open(pth2)
temp_tif2 = os.path.join(Project().other_path,'temp2.tif')
start2x,start2y=geo2imageRC(ds2.GetGeoTransform(),layer_parent.mask.xy[0],layer_parent.mask.xy[1])
end2x,end2y=geo2imageRC(ds2.GetGeoTransform(),layer_parent.mask.xy[2],layer_parent.mask.xy[3])
warp(temp_tif2,ds2,srcWin=[start2x,start2y,xsize,ysize])
del ds2
send_message.emit('图像二提取完成')
ds1:gdal.Dataset=gdal.Open(pth1)
temp_tif1 = os.path.join(Project().other_path, 'temp1.tif')
start1x,start1y=geo2imageRC(ds1.GetGeoTransform(),layer_parent.mask.xy[0],layer_parent.mask.xy[1])
end1x,end1y=geo2imageRC(ds1.GetGeoTransform(),layer_parent.mask.xy[2],layer_parent.mask.xy[3])
warp(temp_tif1,ds1,srcWin=[start1x,start1y,xsize,ysize])
del ds1
send_message.emit('图像一提取完成')
#运算
send_message.emit('开始LHBA计算.....')
time.sleep(0.1)
out_normal_tif = os.path.join(Project().cmi_path, '{}_{}_cmi.tif'.format(layer_parent.name, int(np.random.rand() * 100000)))
LHBA(temp_tif1,temp_tif2,out_normal_tif)
#添加投影
send_message.emit('录入投影信息.....')
time.sleep(0.1)
ds=gdal.Open(out_normal_tif,1)
ds.SetGeoTransform(geo)
ds.SetProjection(proj)
del ds
return out_normal_tif
@VEG_CD.register
class SHAlg(AlgFrontend):
@staticmethod
def get_name():
return 'SH'
@staticmethod
def run_alg(pth1:str,pth2:str,layer_parent:PairLayer,send_message = None, *args, **kargs):
if send_message is None:
class Empty:
def emit(self, *args, **kws):
print(args)
send_message = Empty()
xsize = layer_parent.size[0]
ysize = layer_parent.size[1]
geo=layer_parent.grid.geo
proj=layer_parent.grid.proj
#提取公共部分
send_message.emit('提取重叠区域数据.....')
ds2:gdal.Dataset=gdal.Open(pth2)
temp_tif2 = os.path.join(Project().other_path,'temp2.tif')
start2x,start2y=geo2imageRC(ds2.GetGeoTransform(),layer_parent.mask.xy[0],layer_parent.mask.xy[1])
end2x,end2y=geo2imageRC(ds2.GetGeoTransform(),layer_parent.mask.xy[2],layer_parent.mask.xy[3])
warp(temp_tif2,ds2,srcWin=[start2x,start2y,xsize,ysize])
del ds2
send_message.emit('图像二提取完成')
ds1:gdal.Dataset=gdal.Open(pth1)
temp_tif1 = os.path.join(Project().other_path, 'temp1.tif')
start1x,start1y=geo2imageRC(ds1.GetGeoTransform(),layer_parent.mask.xy[0],layer_parent.mask.xy[1])
end1x,end1y=geo2imageRC(ds1.GetGeoTransform(),layer_parent.mask.xy[2],layer_parent.mask.xy[3])
warp(temp_tif1,ds1,srcWin=[start1x,start1y,xsize,ysize])
del ds1
send_message.emit('图像一提取完成')
#运算
send_message.emit('开始SH计算.....')
time.sleep(0.1)
out_normal_tif = os.path.join(Project().cmi_path, '{}_{}_cmi.tif'.format(layer_parent.name, int(np.random.rand() * 100000)))
SH(temp_tif1,temp_tif2,out_normal_tif)
#添加投影
send_message.emit('录入投影信息.....')
time.sleep(0.1)
ds=gdal.Open(out_normal_tif,1)
ds.SetGeoTransform(geo)
ds.SetProjection(proj)
del ds
return out_normal_tif

View File

@ -2,7 +2,8 @@ import logging
import os
from pathlib import Path
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtWidgets import QAction, QActionGroup, QLabel, QFileDialog, QMenuBar
from PyQt5.QtCore import Qt, QSize, QSettings, pyqtSignal
from PyQt5.QtWidgets import QAction, QActionGroup, QLabel, QFileDialog, QMenuBar, QToolBar, QVBoxLayout, QComboBox
from rscder.gui import project
from rscder.gui.project import Create
from rscder.utils.icons import IconInstance
@ -20,18 +21,20 @@ class ActionManager(QtCore.QObject):
instance = None
def __init__(self,
double_map,
layer_tree,
follow_box,
result_box,
message_box,
parent=None):
double_map,
layer_tree,
follow_box,
result_box,
message_box,
parent=None):
super().__init__(parent)
self.w_parent = parent
self.actions = {}
self.action_groups = {}
self.action_group_actions = {}
self.toolbars = {}
self.double_map = double_map
self.layer_tree = layer_tree
self.follow_box = follow_box
@ -52,7 +55,7 @@ class ActionManager(QtCore.QObject):
self.basic_menu = menubar.addMenu( '&基础工具')
self.filter_menu = self.basic_menu.addMenu(IconInstance().FILTER, '&滤波处理')
self.change_detection_menu = menubar.addMenu('&通用变化检测')
self.unsupervised_menu = self.change_detection_menu.addMenu(IconInstance().UNSUPERVISED, '&无监督变化检测')
# self.unsupervised_menu = self.change_detection_menu.addMenu(IconInstance().UNSUPERVISED, '&无监督变化检测')
self.supervised_menu = self.change_detection_menu.addMenu(IconInstance().SUPERVISED,'&监督变化检测')
self.ai_menu = self.change_detection_menu.addMenu(IconInstance().AI_DETECT,'&AI变化检测')
self.special_chagne_detec_menu = menubar.addMenu( '&专题变化检测')
@ -73,10 +76,28 @@ class ActionManager(QtCore.QObject):
self.plugin_menu = menubar.addMenu('&插件')
self.help_menu = menubar.addMenu( '&帮助')
# vbox = QVBoxLayout()
# follow_combox = QComboBox(self.follow_box)
# vbox.addWidget(follow_combox)
# self.follow_box.setLayout(vbox)
def set_toolbar(self, toolbar):
self.toolbar = toolbar
self.toolbar:QToolBar = toolbar
self.toolbar.setIconSize(QtCore.QSize(24, 24))
def add_toolbar(self, name=None):
toolbar = self.w_parent.addToolBar(name)
toolbar.setMovable(True)
toolbar.setFloatable(False)
toolbar.setIconSize(QSize(32, 32))
toolbar.setToolButtonStyle(Qt.ToolButtonTextBesideIcon)
toolbar.setContextMenuPolicy(Qt.PreventContextMenu)
toolbar.setLayoutDirection(Qt.LeftToRight)
return toolbar
def set_status_bar(self, status_bar):
self.status_bar = status_bar
@ -131,6 +152,9 @@ class ActionManager(QtCore.QObject):
zomm_out.setChecked(False)
zomm_in.setCheckable(True)
zomm_in.setChecked(False)
toolbar = self.add_toolbar('Map')
toolbar.addActions([pan, zomm_out, zomm_in, locate])
self.double_map.connect_map_tool(pan, zomm_in, zomm_out)
# self.double_map.connect_grid_show(grid_line)
@ -148,6 +172,9 @@ class ActionManager(QtCore.QObject):
plugin_list = self.add_action(QAction(IconInstance().PLUGINS,'&插件列表', self.w_parent), 'Plugin')
plugin_list.triggered.connect(self.plugin_list)
# toolbar = self.add_toolbar('Plugin')
# toolbar.addAction(plugin_list)
self.plugin_menu.addAction(plugin_list)
self.message_box.info('菜单初始化完成')

View File

@ -47,8 +47,8 @@ class LicenseGen(QDialog):
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)
hbox4.addWidget(self.btn_generate, alignment = QtCore.Qt.AlignCenter, stretch= 0)
hbox4.addWidget(self.btn_cancel, alignment = QtCore.Qt.AlignCenter, stretch= 0)
vbox = QVBoxLayout()
vbox.addLayout(hbox1)

View File

@ -1,5 +1,6 @@
from PyQt5.QtWidgets import QComboBox, QWidget, QLabel, QHBoxLayout, QVBoxLayout
from PyQt5.QtGui import QIcon
from PyQt5.QtCore import Qt
from rscder.utils.icons import IconInstance
from rscder.utils.project import PairLayer, Project, RasterLayer, ResultPointLayer,SingleBandRasterLayer
class LayerCombox(QComboBox):
@ -7,6 +8,7 @@ class LayerCombox(QComboBox):
def __init__(self, parent=None):
super().__init__(parent)
self.addItem('---', None)
self.setMinimumWidth(200)
for layer in Project().layers.values():
self.addItem(IconInstance().LAYER, layer.name, layer.id)
@ -34,8 +36,9 @@ class PairLayerCombox(QWidget):
layer_label = QLabel('图层组:')
hbox = QHBoxLayout()
hbox.setAlignment(Qt.AlignLeft)
hbox.addWidget(layer_label)
hbox.addWidget(self.layer_combox)
hbox.addWidget(self.layer_combox, 2)
self.raster_layer1 = QComboBox(self)
self.raster_layer1.addItem('---', None)
@ -49,12 +52,14 @@ class PairLayerCombox(QWidget):
self.layer_combox.currentIndexChanged.connect(self.on_group_changed)
hbox1 = QHBoxLayout()
hbox1.setAlignment(Qt.AlignLeft)
hbox1.addWidget(QLabel('时相1:'))
hbox1.addWidget(self.raster_layer1)
hbox1.addWidget(self.raster_layer1, 2)
hbox2 = QHBoxLayout()
hbox2.setAlignment(Qt.AlignLeft)
hbox2.addWidget(QLabel('时相2:'))
hbox2.addWidget(self.raster_layer2)
hbox2.addWidget(self.raster_layer2, 2)
vbox = QVBoxLayout()
vbox.addLayout(hbox)

View File

@ -1,10 +1,11 @@
from colorsys import hls_to_rgb
import os
from turtle import width
from osgeo import gdal
from PyQt5.QtWidgets import QWidget, QApplication, QMainWindow, QToolBox
from PyQt5.QtWidgets import QDialog, QFileDialog, QLineEdit, QPushButton, QVBoxLayout, QHBoxLayout, QLabel, QMessageBox,QSpacerItem
from PyQt5.QtWidgets import QDialog, QFileDialog, QLineEdit, QPushButton, QVBoxLayout, QHBoxLayout, QLabel, QMessageBox,QSpacerItem,QDialogButtonBox
from PyQt5.QtCore import Qt, QSize,QSettings,pyqtSignal,QThread
from PyQt5.QtGui import QIcon,QColor
from PyQt5.QtGui import QIcon,QColor,QPalette,QPixmap
from PyQt5 import QtGui
from threading import Thread
from rscder.utils.icons import IconInstance
@ -38,6 +39,8 @@ class loader(QDialog):
signal1=pyqtSignal(str)
def __init__(self, parent=None) -> None:
super().__init__(parent)
self.left_layer=None
self.right_layer=None
self.setWindowTitle('载入数据')
self.setWindowIcon(IconInstance().DATA_LOAD)
self.pyramid:bool=False
@ -46,18 +49,20 @@ class loader(QDialog):
self.path1=''
self.path2=''
self.bands=['red:','green:','blue:','NIR:']
self.bandsorder=[3,2,1,4]
self.mapcanva1 = QgsMapCanvas(self)
self.mapcanva2 = QgsMapCanvas(self)
self.mapcanva1.setCanvasColor(QColor(0, 0, 0))
self.mapcanva2.setCanvasColor(QColor(0, 0, 0))
self.mapcanva1.setFixedWidth(200)
self.mapcanva1.setFixedHeight(200)
self.mapcanva2.setFixedWidth(200)
self.mapcanva2.setFixedHeight(200)
self.bandsorder=[1,2,3,4]
self.left_map=QLabel()
self.left_map.setFixedSize(200,200)
self.left_map.setAutoFillBackground(True)
self.left_map.setBackgroundRole(QPalette.Dark)
self.right_map=QLabel()
self.right_map.setFixedSize(200,200)
self.right_map.setAutoFillBackground(True)
self.right_map.setBackgroundRole(QPalette.Dark)
maplayout=QHBoxLayout()
maplayout.addWidget(self.mapcanva1)
maplayout.addWidget(self.mapcanva2)
maplayout.addWidget(self.left_map)
maplayout.addWidget(self.right_map)
path1_label = QLabel('时相1影像:')
path1_label.setFixedWidth(60)
@ -145,11 +150,16 @@ class loader(QDialog):
ok_button.clicked.connect(self.ok)
cancel_button.clicked.connect(self.cancel)
button_layout = QHBoxLayout()
button_layout.setDirection(QHBoxLayout.RightToLeft)
button_layout.addWidget(cancel_button, 0, Qt.AlignRight)
button_layout.addWidget(ok_button, 0, Qt.AlignRight)
ok_button.setDefault(True)
cancel_button.setDefault(False)
buttonbox=QDialogButtonBox(self)
buttonbox.addButton(ok_button,QDialogButtonBox.NoRole)
buttonbox.addButton(cancel_button,QDialogButtonBox.NoRole)
buttonbox.setCenterButtons(True)
# button_layout = QHBoxLayout()
# button_layout.setDirection(QHBoxLayout.RightToLeft)
# button_layout.addWidget(cancel_button, 0, Qt.AlignCenter)
# button_layout.addWidget(ok_button, 0, Qt.AlignCenter)
main_layout = QVBoxLayout()
main_layout.addLayout(path1_layout)
@ -157,7 +167,8 @@ class loader(QDialog):
main_layout.addLayout(path2_layout)
main_layout.addLayout(style2_layout)
main_layout.addLayout(maplayout)
main_layout.addLayout(button_layout)
main_layout.addWidget(buttonbox)
# main_layout.addLayout(button_layout)
self.setLayout(main_layout)
def open_file1(self):
@ -171,24 +182,23 @@ class loader(QDialog):
if result==QMessageBox.Yes:
progress1:QDialog=progressDialog(self,'加载时相一')
progress1.setModal(False)
self.temp1=os.path.join(Project().other_path,'temp1.tif')
t1=GdalPreviewImage(self.path1,self.temp1,1024,self.parent())
# t1.started.connect(progress1.show)
t1.finished.connect(self.loadfile1)
t1.finished.connect(lambda :self.setlabel(progress1) )
self.left_layer=MultiBandRasterLayer(path=self.path1)
t1=GdalPreviewImage(self.left_layer,self.left_map,width=200,parent=self.parent())
t1.finished.connect(lambda :self.setlabel(progress1))
t2=build_pyramids_overviews(self.path1,self.parent())
t2.finished.connect(progress1.hide)
t1.start()
t1.finished.connect(t2.start)
t1.finished.connect(lambda : self.open1.setEnabled(True))
t1.start()
# t2.start()
progress1.show()
else:
progress1=progressDialog(self,'加载时相一')
progress1.setModal(False)
self.temp1=os.path.join(Project().other_path,'temp1.tif')
t1=GdalPreviewImage(self.path1,self.temp1,1024,self.parent())
self.left_layer=MultiBandRasterLayer(path=self.path1)
t1=GdalPreviewImage(self.left_layer,self.left_map,width=200,parent=self.parent())
# t1.started.connect(progress1.show)
t1.finished.connect(self.loadfile1)
t1.finished.connect(lambda : self.open1.setEnabled(True))
t1.finished.connect(progress1.hide)
t1.start()
progress1.show()
@ -196,14 +206,7 @@ class loader(QDialog):
except:
return
def loadfile1(self):
try:
self.left_layer=MultiBandRasterLayer(path=self.temp1)
self.mapcanva1.setLayers([self.left_layer.layer])
self.mapcanva1.zoomToFeatureExtent(self.left_layer.layer.extent())
self.open1.setEnabled(True)
except:
return
def open_file2(self):
path2 = QFileDialog.getOpenFileNames(self, '打开数据2', Settings.General().last_path, '*.*')
if path2[0]!='':
@ -216,12 +219,14 @@ class loader(QDialog):
progress2=progressDialog(self,'加载时相二')
progress2.setModal(False)
# progress1.show
self.temp2=os.path.join(Project().other_path,'temp2.tif')
t1=GdalPreviewImage(self.path2,self.temp2,1024,self.parent())
self.right_layer=MultiBandRasterLayer(path=self.path2)
t1=GdalPreviewImage(self.right_layer,self.right_map,width=200,parent=self.parent())
# t1.started.connect(progress1.show)
t1.finished.connect(self.loadfile2)
t1.finished.connect(lambda :self.open2.setEnabled(True))
t1.finished.connect(lambda :self.setlabel(progress2))
t2=build_pyramids_overviews(self.path2,self.parent())
t2.finished.connect(progress2.hide)
t1.start()
@ -230,24 +235,15 @@ class loader(QDialog):
else:
progress2=progressDialog(self,'加载时相二')
progress2.setModal(False)
self.temp2=os.path.join(Project().other_path,'temp2.tif')
t1=GdalPreviewImage(self.path2,self.temp2,1024,self.parent())
self.right_layer=MultiBandRasterLayer(path=self.path2)
t1=GdalPreviewImage(self.right_layer,self.right_map,width=200,parent=self.parent())
# t1.started.connect(progress1.show)
t1.finished.connect(self.loadfile2)
t1.finished.connect(lambda :self.open2.setEnabled(True))
t1.finished.connect(progress2.hide)
t1.start()
progress2.show()
def loadfile2(self):
try:
self.right_layer=MultiBandRasterLayer(path=self.temp2)
self.mapcanva2.setLayers([self.right_layer.layer])
self.mapcanva2.zoomToFeatureExtent(self.right_layer.layer.extent())
self.open2.setEnabled(True)
except:
return
def ok(self):
self.bandsorder1=[int(q.text()) for q in self.style1_inputs ]
self.style1={'r':self.bandsorder1[0],'g':self.bandsorder1[1],'b':self.bandsorder1[2],'NIR':self.bandsorder1[3]}
@ -265,8 +261,7 @@ class loader(QDialog):
def cancel(self):
self.reject()
def open_alg(self,path):
pass
def setlabel(self,s):
try:
s.setlabel('创建影像金字塔..')
@ -276,72 +271,22 @@ class loader(QDialog):
self.bandsorder1=[int(q.text()) for q in self.style1_inputs ]
self.style1={'r':self.bandsorder1[0],'g':self.bandsorder1[1],'b':self.bandsorder1[2],'NIR':self.bandsorder1[3]}
self.left_layer.set_stlye(self.style1)
self.left_map.setPixmap(self.left_layer.previewAsPixmapo(width=200))
def set_style2(self):
self.bandsorder2=[int(q.text()) for q in self.style2_inputs ]
self.style2={'r':self.bandsorder2[0],'g':self.bandsorder2[1],'b':self.bandsorder2[2],'NIR':self.bandsorder2[3]}
self.right_layer.set_stlye(self.style2)
self.right_map.setPixmap(self.right_layer.previewAsPixmapo(width=200))
class GdalPreviewImage(QThread):
def __init__(self,srcFile,tarFilename,width=1024.0,parent=None) -> None:
def __init__(self,layer,map,width=200,parent=None) -> None:
super(GdalPreviewImage,self).__init__(parent)
self.srcFile=srcFile
self.tarFilename=tarFilename
self.layer=layer
self.map=map
self.width=width
def run(self):
try:
srcFile=self.srcFile
tarFilename=self.tarFilename
width=self.width
p=tarFilename
dataset = gdal.Open(srcFile, gdal.GA_ReadOnly)
srcProjection = dataset.GetProjection()
srcGeoTransform = dataset.GetGeoTransform()
srcWidth = dataset.RasterXSize
srcHeight = dataset.RasterYSize
srcBandCount = dataset.RasterCount
# srcNoDatas = [
# dataset.GetRasterBand(bandIndex).GetNoDataValue()
# for bandIndex in range(1, srcBandCount+1)
# ]
# print(srcNoDatas)
srcBandDataType = dataset.GetRasterBand(1).DataType
# 创建重采样后的栅格
outFilePath = p
resampleFactor=width/srcWidth
driver = gdal.GetDriverByName('GTiff')
outWidth = int(srcWidth * resampleFactor)
outHeight = int(srcHeight * resampleFactor)
outDataset = driver.Create(
outFilePath,
outWidth,
outHeight,
srcBandCount,
srcBandDataType
)
print(outDataset)
geoTransforms = list(srcGeoTransform)
geoTransforms[1] = geoTransforms[1]/resampleFactor
geoTransforms[5] = geoTransforms[5]/resampleFactor
outGeoTransform = tuple(geoTransforms)
outDataset.SetGeoTransform(outGeoTransform)
outDataset.SetProjection(srcProjection)
# for bandIndex in range(1, srcBandCount+1):
# band = outDataset.GetRasterBand(bandIndex)
# band.SetNoDataValue(srcNoDatas[bandIndex-1])
gdal.ReprojectImage(
dataset,
outDataset,
srcProjection,
srcProjection,
gdal.gdalconst.GRA_NearestNeighbour,
0.0, 0.0,
)
del outDataset
except:
pass
# return outFilePath
self.map.setPixmap(self.layer.previewAsPixmapo(width=self.width))
class build_pyramids_overviews(QThread):

View File

@ -15,10 +15,7 @@ from rscder.utils.icons import IconInstance
from rscder.utils.project import Project
from rscder.gui.layercombox import LayerCombox
from rscder.gui.eagle_eye import eagleEye
import skimage
import numpy as np
import sys
import scipy
class MainWindow(QMainWindow):
closed = pyqtSignal()

View File

@ -92,8 +92,8 @@ class Create(QDialog):
button_layout = QHBoxLayout()
button_layout.setDirection(QHBoxLayout.RightToLeft)
button_layout.addWidget(ok_button, 0, Qt.AlignRight)
button_layout.addWidget(cancel_button, 0, Qt.AlignRight)
button_layout.addWidget(ok_button, 0, Qt.AlignHCenter)
button_layout.addWidget(cancel_button, 0, Qt.AlignHCenter)
main_layout = QVBoxLayout()
main_layout.addLayout(file_input_layout)

View File

@ -62,7 +62,10 @@ class PluginLoader(QObject):
self.plugins.append(obj(self.ctx))
break
except Exception as e:
# import traceback
# traceback.print_exc()
self.ctx['message_box'].error(f'{plugin["name"]} load error: {e}')
self.plugin_loaded.emit()

19
rscder/utils/geomath.py Normal file
View File

@ -0,0 +1,19 @@
def imageRC2geo(geo:list,x,y):
'''
根据GDAL的六参数模型将影像图上坐标行列号转为投影坐标或地理坐标根据具体数据的坐标系统转换
:param geo: GDAL地理数据,getGeotransform
'''
trans = geo
px = trans[0] + x * trans[1] + y * trans[2]
py = trans[3] + x * trans[4] + y * trans[5]
return [px, py]
def geo2imageRC(geo:list,px,py):
'''
根据GDAL的六 参数模型将给定的投影或地理坐标转为影像图上坐标行列号,return x,y
'''
dTemp = geo[1] * geo[5] - geo[2] *geo[4]
x= int((geo[5] * (px - geo[0]) -geo[2] * (py - geo[3])) / dTemp + 0.5)
y = int((geo[1] * (py - geo[3]) -geo[4] * (px - geo[0])) / dTemp + 0.5)
return [x,y]

View File

@ -8,6 +8,7 @@ from pathlib import Path
from pydoc import render_doc
import shutil
from statistics import stdev
from tabnanny import check
from threading import Thread
from time import sleep, time
from typing import Dict, List
@ -26,9 +27,9 @@ from qgis.core import (\
QgsGeometry, QgsPointXY, QgsMultiBandColorRenderer)
from PyQt5.QtCore import QObject, pyqtSignal, Qt, QThread,QSize
from PyQt5.QtWidgets import QTreeWidgetItem, QAction,QMessageBox
from PyQt5.QtGui import QColor, QIcon, QFont
from PyQt5.QtGui import QColor, QIcon, QFont,QPixmap
import yaml
from rscder.utils.geomath import geo2imageRC,imageRC2geo
from .misc import singleton
def relative_path(path: str, root:str) -> str:
return os.path.relpath(path, root)
@ -235,6 +236,7 @@ def from_dict(data:dict):
if cls_type is not None and cls_type in globals():
return globals()[cls_type](**data)
class BasicLayer(QObject):
LEFT_VIEW=1
@ -375,13 +377,13 @@ class GridLayer(BasicLayer):
self.x_lines = []
for xi in range(self.x_size // self.cell_size[0] +1):
self.x_lines.append(self.x_min + self.x_res * xi * self.cell_size[0])
if self.x_lines[-1] == self.x_max:
if self.x_lines[-1] > self.x_max:
self.x_lines.pop()
self.x_lines.append(self.x_max)
self.y_lines = []
for yi in range(self.y_size // self.cell_size[1]+1):
self.y_lines.append(self.y_min + self.y_res * yi * self.cell_size[1])
if self.y_lines[-1] == self.y_max:
if self.y_lines[-1] < self.y_max:
self.y_lines.pop()
self.y_lines.append(self.y_max)
crs = QgsCoordinateReferenceSystem()
@ -408,11 +410,13 @@ class GridLayer(BasicLayer):
self.set_render()
class Mask(object):
def __init__(self,geoxy) -> None:
super().__init__()
self.xy=geoxy
class RasterLayer(BasicLayer):
def __init__(self, name=None, enable=False, path=None, view_mode=BasicLayer.BOATH_VIEW,style_info={'r':3,'g':2,'b':1,'NIR':0}):
def __init__(self, name=None, enable=False, path=None, view_mode=BasicLayer.BOATH_VIEW,style_info={'r':1,'g':2,'b':3,'NIR':0}):
if name is None:
name = os.path.splitext(os.path.basename(path))[0]
super().__init__(name, enable, IconInstance().RASTER, path, BasicLayer.IN_FILE, view_mode)
@ -420,18 +424,68 @@ class RasterLayer(BasicLayer):
self.style_info=style_info
self.apply_style()
def compare(self, other:'RasterLayer'):
ds1 = gdal.Open(self.path)
ds2 = gdal.Open(other.path)
'''
与其他图像比较看是否处于同一投影,有无重叠区域,能否进行变化检测
other:其它同类图层
return:-1,无法进行比较;0,有重叠区域;1,完全重叠
'''
ds1:gdal.Dataset = gdal.Open(self.path)
ds2 :gdal.Dataset = gdal.Open(other.path)
geo1=ds1.GetGeoTransform()
geo2=ds2.GetGeoTransform()
map1xy=[imageRC2geo(geo1,0,0),imageRC2geo(geo1,ds1.RasterXSize,ds1.RasterYSize)]
map2xy=[imageRC2geo(geo2,0,0),imageRC2geo(geo2,ds2.RasterXSize,ds2.RasterYSize)]
map1xx=[map1xy[0][0],map1xy[1][0]]
map1yy=[map1xy[0][1],map1xy[1][1]]
map2xx=[map2xy[0][0],map2xy[1][0]]
map2yy=[map2xy[0][1],map2xy[1][1]]
map1xx.sort()
map1yy.sort()
map2yy.sort()
map2xx.sort()
if ds1 is None or ds2 is None:
Project().message_box.error('图层打开失败')
return False
if ds1.RasterXSize != ds2.RasterXSize or ds1.RasterYSize != ds2.RasterYSize:
Project().message_box.error('图层尺寸不一致')
return False
return True
return -1
if not ds1.GetProjection()==ds2.GetProjection():
Project().message_box.error('投影不一致')
return -1
elif (map1xx[0]>map2xx[1] or map1xx[1]<map2xx[0])or(map1yy[0]>map2yy[1] or map1yy[1]<map2yy[0] ):
Project().message_box.error('图层无重叠区域')
return -1
elif ds1.RasterXSize == ds2.RasterXSize and ds1.RasterYSize == ds2.RasterYSize and geo1==geo2:
# Project().message_box.error('两图一致')
return 1
#图层尺寸相同
Project().message_box.warning('图层不完全重叠')
del ds1
del ds2
return 0
def overlap(self,other:'RasterLayer'):
'''
与其他图像比较看是否处于同一投影,有无重叠区域,能否进行变化检测
other:其它同类图层
return:[重叠区域左上点xy,重叠区域右下点xy]
'''
ds1:gdal.Dataset = gdal.Open(self.path)
ds2 :gdal.Dataset = gdal.Open(other.path)
geo1=ds1.GetGeoTransform()
geo2=ds2.GetGeoTransform()
#地理投影坐标y向下变小
map1xy=[imageRC2geo(geo1,0,0),imageRC2geo(geo1,ds1.RasterXSize,ds1.RasterYSize)]
map2xy=[imageRC2geo(geo2,0,0),imageRC2geo(geo2,ds2.RasterXSize,ds2.RasterYSize)]
xx=[map1xy[0][0],map1xy[1][0],map2xy[0][0],map2xy[1][0]]
yy=[map1xy[0][1],map1xy[1][1],map2xy[0][1],map2xy[1][1]]
xx.sort()
yy.sort()
return [xx[1],yy[2],xx[2],yy[1]]
@property
def band(self):
ds:gdal.Dataset = gdal.Open(self.path)
if ds is None:
return None
band = ds.RasterCount
del ds
return band
@property
def geo(self):
ds = gdal.Open(self.path)
@ -493,6 +547,13 @@ class RasterLayer(BasicLayer):
'prewmap':self.preview
}
return mapinfo
def previewAsPixmapo(self,width,height=None):
w=self.layer.width()
h=self.layer.height()
if height:
return QPixmap.fromImage(self.layer.previewAsImage(QSize(width,height)))
return QPixmap.fromImage(self.layer.previewAsImage(QSize(width,int(width*h/w))))
@property
def preview(self,width=400):
w=self.layer.width()
@ -505,16 +566,30 @@ class MultiBandRasterLayer(RasterLayer):
renderer=QgsMultiBandColorRenderer(self.layer.dataProvider(),self.style_info['r'],self.style_info['g'],self.style_info['b'])
self.layer.setRenderer(renderer)
self.layer.triggerRepaint()
# @property
# def info(self):
# mapinfo=super().info
# mapinfo['渲染属性']['波段']='单波段'
def toArray(self,mask=None,band:list=None):
ds:gdal.Dataset=gdal.Open(self.path)
res=None
startx=0
starty=0
xsize=ds.RasterXSize
ysize=ds.RasterYSize
if mask:
#转为图像坐标
startx,starty=geo2imageRC(self.geo,mask[0],mask[1])
x2,y2=geo2imageRC(self.geo,mask[2],mask[3])
xsize=x2-startx
ysize=y2-starty
res=ds.ReadAsArray(startx,starty,xsize,ysize,band_list=band)
del ds
return res
def readAsArray(self,xoff: int = 0, yoff: int = 0, xsize= None, ysize = None, buf_obj= None, buf_xsize= None, buf_ysize = None, buf_type= None, callback = None, callback_data = None, interleave = 'band', band_list = None):
ds:gdal.Dataset = gdal.Open(self.path)
array=ds.ReadAsArray(xoff= 0, yoff= 0, xsize= None, ysize = None, buf_obj= None, buf_xsize= None, buf_ysize = None, buf_type= None, callback = None, callback_data = None, interleave= 'band', band_list = None)
return array
class SingleBandRasterLayer(RasterLayer):
def apply_style(self):
pass
class VectorLayer(BasicLayer):
pass
@ -696,7 +771,7 @@ class ResultPointLayer(BasicLayer):
return {'基础属性':basic,'渲染属性':render}
class PairLayer(BasicLayer):
def __init__(self, pth1, pth2,style_info1,style_info2) -> None:
def __init__(self, pth1, pth2,style_info1,style_info2,mask=None) -> None:
self.layers:List[BasicLayer] = []
self.id = str(uuid.uuid1())
@ -708,26 +783,39 @@ class PairLayer(BasicLayer):
self.grid = None
self.cell_size = Project().cell_size
name = os.path.basename(pth1)[:4] + '-' + os.path.basename(pth2)[:4]
self.mask=mask
# self.layer_update.connect(Project().layer_updated)
super().__init__(name, True, IconInstance().DOCUMENT)
self.layer = self.main_l1.layer
if self.check():
self.geo = self.main_l1.geo
self.proj = self.main_l1.proj
self.size = self.main_l1.size
self.layers.append(self.main_l1)
self.layers.append(self.main_l2)
self.grid = GridLayer(self.proj, self.geo, self.size[0], self.size[1], cell_size=Project().cell_size)
self.grid.set_layer_parent(self)
# self.layers.append(self.grid)
@property
def l1_geo(self):
return self.main_l1.geo
@property
def l2_geo(self):
return self.main_l2.geo
def check(self):
if self.checked:
return self.checked
self.checked = self.main_l1.compare(self.main_l2)
return self.checked
if not self.checked==-1:#重叠
self.mask=Mask(self.main_l1.overlap(self.main_l2))
x1,y1=geo2imageRC(self.l1_geo,*self.mask.xy[0:2])
x2,y2=geo2imageRC(self.l1_geo,*self.mask.xy[2:])
self.size=[x2-x1,y2-y1]
self.geo = self.main_l1.geo
self.proj = self.main_l1.proj
gridgeo=[self.mask.xy[0],self.l1_geo[1],self.l1_geo[2],self.mask.xy[1],self.l1_geo[4],self.l1_geo[5]]
self.grid = GridLayer(self.proj, gridgeo , self.size[0], self.size[1], cell_size=Project().cell_size)
self.grid.set_layer_parent(self)
return self.checked!=-1
def add_result_layer(self, result):
result.set_layer_parent(self)
self.layers.insert(0, result)
@ -763,13 +851,15 @@ class PairLayer(BasicLayer):
pth2=self.main_l2.path,
style_info1=self.main_l1.style_info,
style_info2=self.main_l2.style_info,
layers=[to_dict(l) for l in self.layers if not (l is self.grid or l is self.main_l1 or l is self.main_l2) ]
layers=[to_dict(l) for l in self.layers if not (l is self.grid or l is self.main_l1 or l is self.main_l2) ],
)
return data
@property
def info(self):
ds= gdal.Open(self.main_l1.path)
srs= osr.SpatialReference(ds.GetProjectionRef())
metadata={}
@ -791,7 +881,9 @@ class PairLayer(BasicLayer):
#公共掩模
maskData={}
if self.mask:
maskData['左上角坐标']=self.mask.xy[0:2]
maskData['右下角坐标']=self.mask.xy[2:]
mapinfo={
'坐标系':metadata,
@ -801,7 +893,7 @@ class PairLayer(BasicLayer):
return mapinfo
@staticmethod
def from_dict(data):
player = PairLayer(data['pth1'], data['pth2'], data['style_info1'], data['style_info2'])