更新了不同尺度图像的变化检测
This commit is contained in:
parent
0d566b2618
commit
872e45937a
@ -1,5 +1,7 @@
|
||||
import copy as cp
|
||||
from asyncio.windows_events import NULL
|
||||
from concurrent.futures import thread
|
||||
from copy import copy
|
||||
from email.policy import default
|
||||
import os
|
||||
import pdb
|
||||
@ -13,260 +15,16 @@ 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 rscder.utils.geomath import geo2imageRC, imageRC2geo
|
||||
from rscder.utils.project import Project, RasterLayer, PairLayer,ResultPointLayer,MultiBandRasterLayer
|
||||
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):
|
||||
def Meanfilter(x_size,y_size,layer:MultiBandRasterLayer):
|
||||
x_size = int(x_size)
|
||||
y_size = int(y_size)
|
||||
pth = layer.path
|
||||
@ -294,34 +52,53 @@ def Meanfilter(x_size,y_size,layer:RasterLayer):
|
||||
del ds
|
||||
return out_path
|
||||
|
||||
def basic_cd(pth1,pth2,layer_parent,send_message):
|
||||
|
||||
ds1 = gdal.Open(pth1)
|
||||
ds2 = gdal.Open(pth2)
|
||||
def basic_cd(pth1:str,pth2:str,layer_parent:PairLayer,send_message):
|
||||
ds1:gdal.Dataset=gdal.Open(pth1)
|
||||
ds2:gdal.Dataset=gdal.Open(pth2)
|
||||
|
||||
cell_size = layer_parent.cell_size
|
||||
xsize = ds1.RasterXSize
|
||||
ysize = ds1.RasterYSize
|
||||
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().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())
|
||||
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
|
||||
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}')
|
||||
block_xy = (0, j * cell_size[1])
|
||||
if block_xy[1] > ysize:
|
||||
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_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])
|
||||
block_data1 = ds1.ReadAsArray(*block_xy, *block_size)
|
||||
block_data2 = ds2.ReadAsArray(*block_xy, *block_size)
|
||||
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, ...]
|
||||
@ -336,16 +113,17 @@ def basic_cd(pth1,pth2,layer_parent,send_message):
|
||||
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
|
||||
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())
|
||||
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])
|
||||
@ -501,3 +279,270 @@ def table_layer(pth,layer,name,send_message,dict):
|
||||
# print(result_layer.result_path)
|
||||
layer.layer_parent.add_result_layer(result_layer)
|
||||
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)
|
||||
|
||||
|
@ -42,8 +42,13 @@ class RateSetdialog(QDialog):
|
||||
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)
|
||||
okl=QHBoxLayout()
|
||||
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.addLayout(h1)
|
||||
vlayout.addWidget(QLabel('设置阈值'))
|
||||
|
@ -53,10 +53,9 @@ class EvalutationDialog(QDialog):
|
||||
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.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)
|
||||
|
@ -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)
|
||||
|
@ -61,8 +61,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)
|
||||
|
@ -20,12 +20,12 @@ 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 = {}
|
||||
|
@ -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)
|
||||
|
@ -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.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)
|
||||
@ -148,8 +153,8 @@ class loader(QDialog):
|
||||
|
||||
button_layout = QHBoxLayout()
|
||||
button_layout.setDirection(QHBoxLayout.RightToLeft)
|
||||
button_layout.addWidget(cancel_button, 0, Qt.AlignRight)
|
||||
button_layout.addWidget(ok_button, 0, Qt.AlignRight)
|
||||
button_layout.addWidget(cancel_button, 0, Qt.AlignCenter)
|
||||
button_layout.addWidget(ok_button, 0, Qt.AlignCenter)
|
||||
|
||||
main_layout = QVBoxLayout()
|
||||
main_layout.addLayout(path1_layout)
|
||||
@ -171,24 +176,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 +200,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 +213,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 +229,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 +255,7 @@ class loader(QDialog):
|
||||
def cancel(self):
|
||||
self.reject()
|
||||
|
||||
def open_alg(self,path):
|
||||
pass
|
||||
|
||||
def setlabel(self,s):
|
||||
try:
|
||||
s.setlabel('创建影像金字塔..')
|
||||
@ -276,72 +265,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):
|
||||
|
@ -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)
|
||||
|
19
rscder/utils/geomath.py
Normal file
19
rscder/utils/geomath.py
Normal 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]
|
@ -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
|
||||
@ -372,13 +374,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()
|
||||
@ -405,11 +407,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)
|
||||
@ -417,18 +421,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)
|
||||
@ -490,6 +544,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()
|
||||
@ -502,16 +563,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
|
||||
|
||||
@ -693,7 +768,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())
|
||||
@ -705,26 +780,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)
|
||||
@ -760,13 +848,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={}
|
||||
@ -788,7 +878,9 @@ class PairLayer(BasicLayer):
|
||||
|
||||
#公共掩模
|
||||
maskData={}
|
||||
|
||||
if self.mask:
|
||||
maskData['左上角坐标']=self.mask.xy[0:2]
|
||||
maskData['右下角坐标']=self.mask.xy[2:]
|
||||
|
||||
mapinfo={
|
||||
'坐标系':metadata,
|
||||
@ -798,7 +890,7 @@ class PairLayer(BasicLayer):
|
||||
|
||||
return mapinfo
|
||||
|
||||
|
||||
|
||||
@staticmethod
|
||||
def from_dict(data):
|
||||
player = PairLayer(data['pth1'], data['pth2'], data['style_info1'], data['style_info2'])
|
||||
|
Loading…
x
Reference in New Issue
Block a user