更新了不同尺度图像的变化检测

This commit is contained in:
石沈昊 2022-08-12 17:14:29 +08:00
parent 0d566b2618
commit 872e45937a
11 changed files with 527 additions and 427 deletions

View File

@ -1,5 +1,7 @@
import copy as cp
from asyncio.windows_events import NULL from asyncio.windows_events import NULL
from concurrent.futures import thread from concurrent.futures import thread
from copy import copy
from email.policy import default from email.policy import default
import os import os
import pdb import pdb
@ -13,260 +15,16 @@ from PyQt5.QtGui import QIcon,QPixmap
from PyQt5.QtCore import Qt from PyQt5.QtCore import Qt
from rscder.gui.layercombox import LayerCombox,PairLayerCombox from rscder.gui.layercombox import LayerCombox,PairLayerCombox
from rscder.utils.icons import IconInstance from rscder.utils.icons import IconInstance
from rscder.utils.project import Project, RasterLayer, SingleBandRasterLayer,ResultPointLayer from rscder.utils.geomath import geo2imageRC, imageRC2geo
from rscder.utils.project import Project, RasterLayer, PairLayer,ResultPointLayer,MultiBandRasterLayer
from In_one.otsu import OTSU from In_one.otsu import OTSU
from osgeo import gdal from osgeo import gdal
from plugins.In_one import pic from plugins.In_one import pic
import math import math
from skimage.filters import rank from skimage.filters import rank
from skimage.morphology import disk, rectangle 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) def Meanfilter(x_size,y_size,layer:MultiBandRasterLayer):
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) x_size = int(x_size)
y_size = int(y_size) y_size = int(y_size)
pth = layer.path pth = layer.path
@ -294,34 +52,53 @@ def Meanfilter(x_size,y_size,layer:RasterLayer):
del ds del ds
return out_path return out_path
def basic_cd(pth1,pth2,layer_parent,send_message): def basic_cd(pth1:str,pth2:str,layer_parent:PairLayer,send_message):
ds1:gdal.Dataset=gdal.Open(pth1)
ds2:gdal.Dataset=gdal.Open(pth2)
ds1 = gdal.Open(pth1)
ds2 = gdal.Open(pth2)
cell_size = layer_parent.cell_size cell_size = layer_parent.cell_size
xsize = ds1.RasterXSize xsize = layer_parent.size[0]
ysize = ds1.RasterYSize ysize = layer_parent.size[1]
band = ds1.RasterCount band = ds1.RasterCount
yblocks = ysize // cell_size[1] yblocks = ysize // cell_size[1]
driver = gdal.GetDriverByName('GTiff') driver = gdal.GetDriverByName('GTiff')
out_tif = os.path.join(Project().cmi_path, 'temp.tif') out_tif = os.path.join(Project().cmi_path, 'temp.tif')
out_ds = driver.Create(out_tif, xsize, ysize, 1, gdal.GDT_Float32) out_ds = driver.Create(out_tif, xsize, ysize, 1, gdal.GDT_Float32)
out_ds.SetGeoTransform(ds1.GetGeoTransform()) geo=layer_parent.grid.geo
out_ds.SetProjection(ds1.GetProjection()) proj=layer_parent.grid.proj
out_ds.SetGeoTransform(geo)
out_ds.SetProjection(proj)
max_diff = 0 max_diff = 0
min_diff = math.inf min_diff = math.inf
for j in range(yblocks + 1):
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):#该改这里了
send_message.emit(f'计算{j}/{yblocks}') 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]) block_xy=(0,j * cell_size[1])
if block_xy[1] > ysize: if block_xy1[1] > end1y or block_xy2[1] > end2y:
break break
block_size=(xsize, cell_size[1]) 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: if block_xy[1] + block_size[1] > ysize:
block_size = (xsize, ysize - block_xy[1]) block_size = (xsize, ysize - block_xy[1])
block_data1 = ds1.ReadAsArray(*block_xy, *block_size) if block_xy1[1] + block_size1[1] > end1y:
block_data2 = ds2.ReadAsArray(*block_xy, *block_size) 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: if band == 1:
block_data1 = block_data1[None, ...] block_data1 = block_data1[None, ...]
@ -336,7 +113,8 @@ def basic_cd(pth1,pth2,layer_parent,send_message):
out_ds.GetRasterBand(1).WriteArray(block_diff, *block_xy) out_ds.GetRasterBand(1).WriteArray(block_diff, *block_xy)
send_message.emit(f'完成{j}/{yblocks}') send_message.emit(f'完成{j}/{yblocks}')
del ds2
del ds1
out_ds.FlushCache() out_ds.FlushCache()
del out_ds del out_ds
send_message.emit('归一化概率中...') send_message.emit('归一化概率中...')
@ -344,8 +122,8 @@ def basic_cd(pth1,pth2,layer_parent,send_message):
out_normal_tif = os.path.join(Project().cmi_path, '{}_{}_cmi.tif'.format(layer_parent.name, int(np.random.rand() * 100000))) 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 = driver.Create(out_normal_tif, xsize, ysize, 1, gdal.GDT_Byte)
out_normal_ds.SetGeoTransform(ds1.GetGeoTransform()) out_normal_ds.SetGeoTransform(geo)
out_normal_ds.SetProjection(ds1.GetProjection()) out_normal_ds.SetProjection(proj)
# hist = np.zeros(256, dtype=np.int32) # hist = np.zeros(256, dtype=np.int32)
for j in range(yblocks+1): for j in range(yblocks+1):
block_xy = (0, j * cell_size[1]) block_xy = (0, j * cell_size[1])
@ -501,3 +279,270 @@ def table_layer(pth,layer,name,send_message,dict):
# print(result_layer.result_path) # print(result_layer.result_path)
layer.layer_parent.add_result_layer(result_layer) layer.layer_parent.add_result_layer(result_layer)
send_message.emit('计算完成') send_message.emit('计算完成')
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,0,alignment=Qt.AlignHCenter)
oklayout.addWidget(self.cancel_button,0,alignment=Qt.AlignHCenter)
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)
@property
def param(self):
class param(object):
pass
p=param()
p.pre=self.pre
p.cd=self.cd
p.threshold=self.threshold
p.layer_combox=self.layer_combox
p.pre_select=self.pre_select
p.x_size_input=self.x_size_input
p.y_size_input=self.y_size_input
p.threshold_select=self.threshold_select
p.threshold_input=self.threshold_input
p.cd_select=self.cd_select
return p
class InOnePlugin(BasicPlugin):
pre={"均值滤波":Meanfilter}#可添加其他方法
cd={'差分法':basic_cd}#可添加其他方法
threshold={'OTSU阈值':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(list(self.pre.keys()),list(self.cd.keys()),list(self.threshold.keys()),self.mainwindow)
myDialog.show()
if myDialog.exec_()==QDialog.Accepted:
w=myDialog.param
t=Thread(target=self.run_alg,args=(w,))
t.start()
def run_alg(self,w:AllInOne):
dict={}
layer1=w.layer_combox.layer1
pth1 = w.layer_combox.layer1.path
pth2 = w.layer_combox.layer2.path
name=layer1.layer_parent.name
# 预处理
# 若添加的预处理函数接口相同,则无需判断是哪种方法
# if w.pre_select.choose==self.pre.keys()[0]:
# pass
# el
preKey=w.pre_select.choose
pth1=self.pre[preKey](w.x_size_input.text(),w.y_size_input.text(),w.layer_combox.layer1)
self.send_message.emit('{}图像{}'.format(preKey,w.layer_combox.layer1.name))
pth2=self.pre[preKey](w.x_size_input.text(),w.y_size_input.text(),w.layer_combox.layer2)
self.send_message.emit('{}图像{}'.format(preKey,w.layer_combox.layer2.name))
name=name+'_mean_filter'
dict['预处理']=[preKey,'|'.format(pth1,pth2)]
cdpth=None
#变化检测
# if w.cd_select.choose==self.cd[0]:
cdKey=w.cd_select.choose
cdpth=self.cd[cdKey](pth1,pth2,w.layer_combox.layer1.layer_parent,self.send_message)
name += '_basic_cd'
dict['变化检测算法']=[cdKey,cdpth]
#阈值处理
#例如手动阈值和otsu参数不同则要做区分
thpth=None
if 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:
thpth,gap=otsu(cdpth,w.layer_combox.layer1.layer_parent.name,self.send_message)
name+='_otsu'
dict['后处理']=['OTSU阈值',gap,cdpth]
table_layer(thpth,layer1,name,self.send_message,dict)

View File

@ -42,8 +42,13 @@ class RateSetdialog(QDialog):
self.cancel_button.clicked.connect(self.on_cancel) self.cancel_button.clicked.connect(self.on_cancel)
self.button_layout = QHBoxLayout() self.button_layout = QHBoxLayout()
self.button_layout.addWidget(self.ok_button) okl=QHBoxLayout()
self.button_layout.addWidget(self.cancel_button) okl.addWidget(self.ok_button,alignment=Qt.AlignCenter)
cll=QHBoxLayout()
cll.addWidget(self.cancel_button,alignment=Qt.AlignCenter)
self.button_layout.addLayout(okl)
self.button_layout.addLayout(cll)
vlayout=QVBoxLayout() vlayout=QVBoxLayout()
vlayout.addLayout(h1) vlayout.addLayout(h1)
vlayout.addWidget(QLabel('设置阈值')) vlayout.addWidget(QLabel('设置阈值'))

View File

@ -53,10 +53,9 @@ class EvalutationDialog(QDialog):
self.cancel_button = QPushButton('取消', self) self.cancel_button = QPushButton('取消', self)
self.cancel_button.setIcon(IconInstance().CANCEL) self.cancel_button.setIcon(IconInstance().CANCEL)
self.cancel_button.clicked.connect(self.on_cancel) self.cancel_button.clicked.connect(self.on_cancel)
self.button_layout = QHBoxLayout() self.button_layout = QHBoxLayout()
self.button_layout.addWidget(self.ok_button) self.button_layout.addWidget(self.ok_button,0,alignment=Qt.AlignHCenter)
self.button_layout.addWidget(self.cancel_button) self.button_layout.addLayout(self.cancel_button,0,alignment=Qt.AlignHCenter)
self.main_layout = QVBoxLayout() self.main_layout = QVBoxLayout()
self.main_layout.addLayout(hbox1) 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 rscder.plugins.basic import BasicPlugin
from PyQt5.QtWidgets import QDialog, QHBoxLayout, QFileDialog, QComboBox, QVBoxLayout, QPushButton, QLabel, QLineEdit, QAction from PyQt5.QtWidgets import QDialog, QHBoxLayout, QFileDialog, QComboBox, QVBoxLayout, QPushButton, QLabel, QLineEdit, QAction
from PyQt5.QtGui import QIcon from PyQt5.QtGui import QIcon
from PyQt5.QtCore import Qt
class ExportDialog(QDialog): class ExportDialog(QDialog):
def __init__(self, parent=None): def __init__(self, parent=None):
@ -60,8 +61,8 @@ class ExportDialog(QDialog):
hbox2.addWidget(out_path_btn) hbox2.addWidget(out_path_btn)
hbox3 = QHBoxLayout() hbox3 = QHBoxLayout()
hbox3.addWidget(ok_btn) hbox3.addWidget(ok_btn,0,alignment=Qt.AlignHCenter)
hbox3.addWidget(cancel_btn) hbox3.addWidget(cancel_btn,0,alignment=Qt.AlignHCenter)
vbox = QVBoxLayout() vbox = QVBoxLayout()
vbox.addLayout(hbox1) vbox.addLayout(hbox1)

View File

@ -61,8 +61,8 @@ class FilterSetting(QDialog):
cancel_button.clicked.connect(self.reject) cancel_button.clicked.connect(self.reject)
hlayout2 = QtWidgets.QHBoxLayout() hlayout2 = QtWidgets.QHBoxLayout()
hlayout2.addWidget(ok_button) hlayout2.addWidget(ok_button,0,alignment=Qt.AlignHCenter)
hlayout2.addWidget(cancel_button) hlayout2.addWidget(cancel_button,0,alignment=Qt.AlignHCenter)
vlayout = QtWidgets.QVBoxLayout() vlayout = QtWidgets.QVBoxLayout()
vlayout.addLayout(hbox) vlayout.addLayout(hbox)

View File

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

View File

@ -1,10 +1,11 @@
from colorsys import hls_to_rgb from colorsys import hls_to_rgb
import os import os
from turtle import width
from osgeo import gdal from osgeo import gdal
from PyQt5.QtWidgets import QWidget, QApplication, QMainWindow, QToolBox 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
from PyQt5.QtCore import Qt, QSize,QSettings,pyqtSignal,QThread 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 PyQt5 import QtGui
from threading import Thread from threading import Thread
from rscder.utils.icons import IconInstance from rscder.utils.icons import IconInstance
@ -38,6 +39,8 @@ class loader(QDialog):
signal1=pyqtSignal(str) signal1=pyqtSignal(str)
def __init__(self, parent=None) -> None: def __init__(self, parent=None) -> None:
super().__init__(parent) super().__init__(parent)
self.left_layer=None
self.right_layer=None
self.setWindowTitle('载入数据') self.setWindowTitle('载入数据')
self.setWindowIcon(IconInstance().DATA_LOAD) self.setWindowIcon(IconInstance().DATA_LOAD)
self.pyramid:bool=False self.pyramid:bool=False
@ -46,18 +49,20 @@ class loader(QDialog):
self.path1='' self.path1=''
self.path2='' self.path2=''
self.bands=['red:','green:','blue:','NIR:'] self.bands=['red:','green:','blue:','NIR:']
self.bandsorder=[3,2,1,4] self.bandsorder=[1,2,3,4]
self.mapcanva1 = QgsMapCanvas(self)
self.mapcanva2 = QgsMapCanvas(self) self.left_map=QLabel()
self.mapcanva1.setCanvasColor(QColor(0, 0, 0)) self.left_map.setFixedSize(200,200)
self.mapcanva2.setCanvasColor(QColor(0, 0, 0)) self.left_map.setAutoFillBackground(True)
self.mapcanva1.setFixedWidth(200) self.left_map.setBackgroundRole(QPalette.Dark)
self.mapcanva1.setFixedHeight(200)
self.mapcanva2.setFixedWidth(200) self.right_map=QLabel()
self.mapcanva2.setFixedHeight(200) self.right_map.setFixedSize(200,200)
self.right_map.setAutoFillBackground(True)
self.right_map.setBackgroundRole(QPalette.Dark)
maplayout=QHBoxLayout() maplayout=QHBoxLayout()
maplayout.addWidget(self.mapcanva1) maplayout.addWidget(self.left_map)
maplayout.addWidget(self.mapcanva2) maplayout.addWidget(self.right_map)
path1_label = QLabel('时相1影像:') path1_label = QLabel('时相1影像:')
path1_label.setFixedWidth(60) path1_label.setFixedWidth(60)
@ -148,8 +153,8 @@ class loader(QDialog):
button_layout = QHBoxLayout() button_layout = QHBoxLayout()
button_layout.setDirection(QHBoxLayout.RightToLeft) button_layout.setDirection(QHBoxLayout.RightToLeft)
button_layout.addWidget(cancel_button, 0, Qt.AlignRight) button_layout.addWidget(cancel_button, 0, Qt.AlignCenter)
button_layout.addWidget(ok_button, 0, Qt.AlignRight) button_layout.addWidget(ok_button, 0, Qt.AlignCenter)
main_layout = QVBoxLayout() main_layout = QVBoxLayout()
main_layout.addLayout(path1_layout) main_layout.addLayout(path1_layout)
@ -171,24 +176,23 @@ class loader(QDialog):
if result==QMessageBox.Yes: if result==QMessageBox.Yes:
progress1:QDialog=progressDialog(self,'加载时相一') progress1:QDialog=progressDialog(self,'加载时相一')
progress1.setModal(False) progress1.setModal(False)
self.temp1=os.path.join(Project().other_path,'temp1.tif') self.left_layer=MultiBandRasterLayer(path=self.path1)
t1=GdalPreviewImage(self.path1,self.temp1,1024,self.parent()) 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.setlabel(progress1)) t1.finished.connect(lambda :self.setlabel(progress1))
t2=build_pyramids_overviews(self.path1,self.parent()) t2=build_pyramids_overviews(self.path1,self.parent())
t2.finished.connect(progress1.hide) t2.finished.connect(progress1.hide)
t1.start()
t1.finished.connect(t2.start) t1.finished.connect(t2.start)
t1.finished.connect(lambda : self.open1.setEnabled(True))
t1.start()
# t2.start() # t2.start()
progress1.show() progress1.show()
else: else:
progress1=progressDialog(self,'加载时相一') progress1=progressDialog(self,'加载时相一')
progress1.setModal(False) progress1.setModal(False)
self.temp1=os.path.join(Project().other_path,'temp1.tif') self.left_layer=MultiBandRasterLayer(path=self.path1)
t1=GdalPreviewImage(self.path1,self.temp1,1024,self.parent()) t1=GdalPreviewImage(self.left_layer,self.left_map,width=200,parent=self.parent())
# t1.started.connect(progress1.show) # t1.started.connect(progress1.show)
t1.finished.connect(self.loadfile1) t1.finished.connect(lambda : self.open1.setEnabled(True))
t1.finished.connect(progress1.hide) t1.finished.connect(progress1.hide)
t1.start() t1.start()
progress1.show() progress1.show()
@ -196,14 +200,7 @@ class loader(QDialog):
except: except:
return 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): def open_file2(self):
path2 = QFileDialog.getOpenFileNames(self, '打开数据2', Settings.General().last_path, '*.*') path2 = QFileDialog.getOpenFileNames(self, '打开数据2', Settings.General().last_path, '*.*')
if path2[0]!='': if path2[0]!='':
@ -216,12 +213,14 @@ class loader(QDialog):
progress2=progressDialog(self,'加载时相二') progress2=progressDialog(self,'加载时相二')
progress2.setModal(False) progress2.setModal(False)
# progress1.show # progress1.show
self.temp2=os.path.join(Project().other_path,'temp2.tif') self.right_layer=MultiBandRasterLayer(path=self.path2)
t1=GdalPreviewImage(self.path2,self.temp2,1024,self.parent())
t1=GdalPreviewImage(self.right_layer,self.right_map,width=200,parent=self.parent())
# t1.started.connect(progress1.show) # 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)) t1.finished.connect(lambda :self.setlabel(progress2))
t2=build_pyramids_overviews(self.path2,self.parent()) t2=build_pyramids_overviews(self.path2,self.parent())
t2.finished.connect(progress2.hide) t2.finished.connect(progress2.hide)
t1.start() t1.start()
@ -230,24 +229,15 @@ class loader(QDialog):
else: else:
progress2=progressDialog(self,'加载时相二') progress2=progressDialog(self,'加载时相二')
progress2.setModal(False) progress2.setModal(False)
self.temp2=os.path.join(Project().other_path,'temp2.tif') self.right_layer=MultiBandRasterLayer(path=self.path2)
t1=GdalPreviewImage(self.path2,self.temp2,1024,self.parent()) t1=GdalPreviewImage(self.right_layer,self.right_map,width=200,parent=self.parent())
# t1.started.connect(progress1.show) # t1.started.connect(progress1.show)
t1.finished.connect(self.loadfile2) t1.finished.connect(lambda :self.open2.setEnabled(True))
t1.finished.connect(progress2.hide) t1.finished.connect(progress2.hide)
t1.start() t1.start()
progress2.show() 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): def ok(self):
self.bandsorder1=[int(q.text()) for q in self.style1_inputs ] 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.style1={'r':self.bandsorder1[0],'g':self.bandsorder1[1],'b':self.bandsorder1[2],'NIR':self.bandsorder1[3]}
@ -265,8 +255,7 @@ class loader(QDialog):
def cancel(self): def cancel(self):
self.reject() self.reject()
def open_alg(self,path):
pass
def setlabel(self,s): def setlabel(self,s):
try: try:
s.setlabel('创建影像金字塔..') s.setlabel('创建影像金字塔..')
@ -276,72 +265,22 @@ class loader(QDialog):
self.bandsorder1=[int(q.text()) for q in self.style1_inputs ] 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.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_layer.set_stlye(self.style1)
self.left_map.setPixmap(self.left_layer.previewAsPixmapo(width=200))
def set_style2(self): def set_style2(self):
self.bandsorder2=[int(q.text()) for q in self.style2_inputs ] 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.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_layer.set_stlye(self.style2)
self.right_map.setPixmap(self.right_layer.previewAsPixmapo(width=200))
class GdalPreviewImage(QThread): 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) super(GdalPreviewImage,self).__init__(parent)
self.srcFile=srcFile self.layer=layer
self.tarFilename=tarFilename self.map=map
self.width=width self.width=width
def run(self): def run(self):
try: self.map.setPixmap(self.layer.previewAsPixmapo(width=self.width))
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
class build_pyramids_overviews(QThread): class build_pyramids_overviews(QThread):

View File

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

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 from pydoc import render_doc
import shutil import shutil
from statistics import stdev from statistics import stdev
from tabnanny import check
from threading import Thread from threading import Thread
from time import sleep, time from time import sleep, time
from typing import Dict, List from typing import Dict, List
@ -26,9 +27,9 @@ from qgis.core import (\
QgsGeometry, QgsPointXY, QgsMultiBandColorRenderer) QgsGeometry, QgsPointXY, QgsMultiBandColorRenderer)
from PyQt5.QtCore import QObject, pyqtSignal, Qt, QThread,QSize from PyQt5.QtCore import QObject, pyqtSignal, Qt, QThread,QSize
from PyQt5.QtWidgets import QTreeWidgetItem, QAction,QMessageBox from PyQt5.QtWidgets import QTreeWidgetItem, QAction,QMessageBox
from PyQt5.QtGui import QColor, QIcon, QFont from PyQt5.QtGui import QColor, QIcon, QFont,QPixmap
import yaml import yaml
from rscder.utils.geomath import geo2imageRC,imageRC2geo
from .misc import singleton from .misc import singleton
def relative_path(path: str, root:str) -> str: def relative_path(path: str, root:str) -> str:
return os.path.relpath(path, root) 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(): if cls_type is not None and cls_type in globals():
return globals()[cls_type](**data) return globals()[cls_type](**data)
class BasicLayer(QObject): class BasicLayer(QObject):
LEFT_VIEW=1 LEFT_VIEW=1
@ -372,13 +374,13 @@ class GridLayer(BasicLayer):
self.x_lines = [] self.x_lines = []
for xi in range(self.x_size // self.cell_size[0] +1): 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]) 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.pop()
self.x_lines.append(self.x_max) self.x_lines.append(self.x_max)
self.y_lines = [] self.y_lines = []
for yi in range(self.y_size // self.cell_size[1]+1): 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]) 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.pop()
self.y_lines.append(self.y_max) self.y_lines.append(self.y_max)
crs = QgsCoordinateReferenceSystem() crs = QgsCoordinateReferenceSystem()
@ -405,11 +407,13 @@ class GridLayer(BasicLayer):
self.set_render() self.set_render()
class Mask(object):
def __init__(self,geoxy) -> None:
super().__init__()
self.xy=geoxy
class RasterLayer(BasicLayer): 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: if name is None:
name = os.path.splitext(os.path.basename(path))[0] name = os.path.splitext(os.path.basename(path))[0]
super().__init__(name, enable, IconInstance().RASTER, path, BasicLayer.IN_FILE, view_mode) super().__init__(name, enable, IconInstance().RASTER, path, BasicLayer.IN_FILE, view_mode)
@ -417,18 +421,68 @@ class RasterLayer(BasicLayer):
self.style_info=style_info self.style_info=style_info
self.apply_style() self.apply_style()
def compare(self, other:'RasterLayer'): 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: if ds1 is None or ds2 is None:
Project().message_box.error('图层打开失败') Project().message_box.error('图层打开失败')
return False return -1
if not ds1.GetProjection()==ds2.GetProjection():
if ds1.RasterXSize != ds2.RasterXSize or ds1.RasterYSize != ds2.RasterYSize: Project().message_box.error('投影不一致')
Project().message_box.error('图层尺寸不一致') return -1
return False 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 True 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 @property
def geo(self): def geo(self):
ds = gdal.Open(self.path) ds = gdal.Open(self.path)
@ -490,6 +544,13 @@ class RasterLayer(BasicLayer):
'prewmap':self.preview 'prewmap':self.preview
} }
return mapinfo 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 @property
def preview(self,width=400): def preview(self,width=400):
w=self.layer.width() w=self.layer.width()
@ -502,16 +563,30 @@ class MultiBandRasterLayer(RasterLayer):
renderer=QgsMultiBandColorRenderer(self.layer.dataProvider(),self.style_info['r'],self.style_info['g'],self.style_info['b']) renderer=QgsMultiBandColorRenderer(self.layer.dataProvider(),self.style_info['r'],self.style_info['g'],self.style_info['b'])
self.layer.setRenderer(renderer) self.layer.setRenderer(renderer)
self.layer.triggerRepaint() self.layer.triggerRepaint()
# @property def toArray(self,mask=None,band:list=None):
# def info(self): ds:gdal.Dataset=gdal.Open(self.path)
# mapinfo=super().info res=None
# mapinfo['渲染属性']['波段']='单波段' 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): class SingleBandRasterLayer(RasterLayer):
def apply_style(self): def apply_style(self):
pass pass
class VectorLayer(BasicLayer): class VectorLayer(BasicLayer):
pass pass
@ -693,7 +768,7 @@ class ResultPointLayer(BasicLayer):
return {'基础属性':basic,'渲染属性':render} return {'基础属性':basic,'渲染属性':render}
class PairLayer(BasicLayer): 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.layers:List[BasicLayer] = []
self.id = str(uuid.uuid1()) self.id = str(uuid.uuid1())
@ -705,25 +780,38 @@ class PairLayer(BasicLayer):
self.grid = None self.grid = None
self.cell_size = Project().cell_size self.cell_size = Project().cell_size
name = os.path.basename(pth1)[:4] + '-' + os.path.basename(pth2)[:4] name = os.path.basename(pth1)[:4] + '-' + os.path.basename(pth2)[:4]
self.mask=mask
# self.layer_update.connect(Project().layer_updated) # self.layer_update.connect(Project().layer_updated)
super().__init__(name, True, IconInstance().DOCUMENT) super().__init__(name, True, IconInstance().DOCUMENT)
self.layer = self.main_l1.layer self.layer = self.main_l1.layer
if self.check(): 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_l1)
self.layers.append(self.main_l2) 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) # 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): def check(self):
if self.checked: if self.checked:
return self.checked return self.checked
self.checked = self.main_l1.compare(self.main_l2) 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): def add_result_layer(self, result):
result.set_layer_parent(self) result.set_layer_parent(self)
@ -760,10 +848,12 @@ class PairLayer(BasicLayer):
pth2=self.main_l2.path, pth2=self.main_l2.path,
style_info1=self.main_l1.style_info, style_info1=self.main_l1.style_info,
style_info2=self.main_l2.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 return data
@property @property
def info(self): def info(self):
@ -788,7 +878,9 @@ class PairLayer(BasicLayer):
#公共掩模 #公共掩模
maskData={} maskData={}
if self.mask:
maskData['左上角坐标']=self.mask.xy[0:2]
maskData['右下角坐标']=self.mask.xy[2:]
mapinfo={ mapinfo={
'坐标系':metadata, '坐标系':metadata,