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