From f93a97e6a684fea27338c8d2658c3581344219fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=9F=B3=E6=B2=88=E6=98=8A?= Date: Tue, 12 Jul 2022 19:28:36 +0800 Subject: [PATCH 1/3] =?UTF-8?q?=E7=89=88=E6=9C=AC=E4=B8=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- rscder/gui/load.py | 32 ++++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/rscder/gui/load.py b/rscder/gui/load.py index fae616b..fc5468f 100644 --- a/rscder/gui/load.py +++ b/rscder/gui/load.py @@ -148,8 +148,8 @@ class loader(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.AlignRight) main_layout = QVBoxLayout() main_layout.addLayout(path1_layout) @@ -169,14 +169,14 @@ class loader(QDialog): self.path1_input.setText(self.path1) result=QMessageBox.question(self, '提示', '是否创建图像金字塔', QMessageBox.Yes | QMessageBox.No, QMessageBox.No) #默认关闭界面选择No if result==QMessageBox.Yes: - progress1=progressDialog(self,'加载时相一') + 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) + t1=GdalPreviewImage(self.path1,self.temp1,1024,self.parent()) # t1.started.connect(progress1.show) t1.finished.connect(self.loadfile1) - t1.finished.connect(lambda :progress1.setlabel('创建影像金字塔..')) - t2=build_pyramids_overviews(self.path1,self) + 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) @@ -186,7 +186,7 @@ class loader(QDialog): progress1=progressDialog(self,'加载时相一') progress1.setModal(False) self.temp1=os.path.join(Project().other_path,'temp1.tif') - t1=GdalPreviewImage(self.path1,self.temp1,1024) + t1=GdalPreviewImage(self.path1,self.temp1,1024,self.parent()) # t1.started.connect(progress1.show) t1.finished.connect(self.loadfile1) t1.finished.connect(progress1.hide) @@ -217,11 +217,12 @@ class loader(QDialog): progress2.setModal(False) # progress1.show self.temp2=os.path.join(Project().other_path,'temp2.tif') - t1=GdalPreviewImage(self.path2,self.temp2,1024,self) + t1=GdalPreviewImage(self.path2,self.temp2,1024,self.parent()) + # t1.started.connect(progress1.show) t1.finished.connect(self.loadfile2) - t1.finished.connect(lambda :progress2.setlabel('创建影像金字塔..')) - t2=build_pyramids_overviews(self.path2,self) + t1.finished.connect(lambda :self.setlabel(progress2)) + t2=build_pyramids_overviews(self.path2,self.parent()) t2.finished.connect(progress2.hide) t1.start() t1.finished.connect(t2.start) @@ -230,7 +231,7 @@ class loader(QDialog): progress2=progressDialog(self,'加载时相二') progress2.setModal(False) self.temp2=os.path.join(Project().other_path,'temp2.tif') - t1=GdalPreviewImage(self.path2,self.temp2,1024) + t1=GdalPreviewImage(self.path2,self.temp2,1024,self.parent()) # t1.started.connect(progress1.show) t1.finished.connect(self.loadfile2) t1.finished.connect(progress2.hide) @@ -266,7 +267,11 @@ class loader(QDialog): def open_alg(self,path): pass - + def setlabel(self,s): + try: + s.setlabel('创建影像金字塔..') + except: + pass def set_style1(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]} @@ -335,6 +340,7 @@ class GdalPreviewImage(QThread): del outDataset except: pass + # return outFilePath @@ -346,11 +352,9 @@ class build_pyramids_overviews(QThread): try: filename=self.filename image:gdal.Dataset = gdal.Open(filename, 0) - # 如果第二个参数设置为0,则金字塔文件建立在外面 - # 如果第二个参数缺省或者为1,则金字塔文件建立在文件内 gdal.SetConfigOption('COMPRESS_OVERVIEW', 'DEFLATE') ov_list = [2, 4,6, 8, 12,16,24, 32, 48,64,96,128] - image.BuildOverviews("NEAREST", len(ov_list),overviewlist=ov_list) + image.BuildOverviews("NEAREST",overviewlist=ov_list) del image except: pass From 4a63fa0e2f6b7dee9453523994f335998e8e3f5a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=9F=B3=E6=B2=88=E6=98=8A?= Date: Tue, 12 Jul 2022 19:47:05 +0800 Subject: [PATCH 2/3] =?UTF-8?q?=E9=B9=B0=E7=9C=BC=E5=9B=BE=E4=B8=BB?= =?UTF-8?q?=E5=83=8F=E8=B7=9F=E9=9A=8F=E4=B8=BB=E8=A7=86=E5=9B=BE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- rscder/gui/eagle_eye.py | 3 ++- rscder/utils/project.py | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/rscder/gui/eagle_eye.py b/rscder/gui/eagle_eye.py index de367f5..823c4ae 100644 --- a/rscder/gui/eagle_eye.py +++ b/rscder/gui/eagle_eye.py @@ -57,7 +57,8 @@ class eagleEye(QgsMapCanvas): self.setLayers(layer_list_1) if len(layer_list_1) > 0: self.zoomToFeatureExtent(layer_list_1[0].extent()) - + def zoom(self,layer): + self.zoomToFeatureExtent(layer.extent()) def draw_extent(self,extent): self.Extent=extent self.rubber.draw_extent(self.Extent) diff --git a/rscder/utils/project.py b/rscder/utils/project.py index fdd43f1..d651a21 100644 --- a/rscder/utils/project.py +++ b/rscder/utils/project.py @@ -89,6 +89,7 @@ class Project(QObject): self.layer_tree = layer_tree self.message_box = message_box self.result_table = result_table + self.eye=eye IconInstance(self) self.layer_tree_update.connect(layer_tree.update_layer) self.layer_show_update.connect(pair_canvas.update_layer) @@ -176,6 +177,7 @@ class Project(QObject): def zoom_to_layer(self, data): self.pair_canvas.zoom_to_layer(data['layer']) + self.eye.zoom(data['layer']) @property def cmi_path(self): From 0d566b261875a044e68ece2cdce414e007510e78 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=9F=B3=E6=B2=88=E6=98=8A?= Date: Fri, 22 Jul 2022 19:39:19 +0800 Subject: [PATCH 3/3] =?UTF-8?q?=E6=9F=A5=E7=9C=8B=E5=9B=BE=E5=B1=82?= =?UTF-8?q?=E5=B1=9E=E6=80=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- plugins/In_one/main.py | 14 ++--- rscder/gui/info.py | 29 ++++++++++ rscder/utils/project.py | 122 +++++++++++++++++++++++++++++++++++++--- 3 files changed, 149 insertions(+), 16 deletions(-) create mode 100644 rscder/gui/info.py diff --git a/plugins/In_one/main.py b/plugins/In_one/main.py index c6f47ce..f2ccb3f 100644 --- a/plugins/In_one/main.py +++ b/plugins/In_one/main.py @@ -241,6 +241,7 @@ class InOnePlugin(BasicPlugin): 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 @@ -248,18 +249,18 @@ class InOnePlugin(BasicPlugin): 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 + dict['变化检测算法']=['差分法',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) + thpth,gap=otsu(cdpth,w.layer_combox.layer1.layer_parent.name,self.send_message) name+='_otsu' - dict[name]=thpth + 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[name+'_thresh_{:.1f}'.format(float(w.threshold_input.text()))] + dict['后处理']=['手动阈值',[float(w.threshold_input.text())],thpth] else: pass @@ -417,7 +418,7 @@ def otsu(pth,name,send_message): out_ds = None ds = None send_message.emit('OTSU阈值完成') - return out_th + return out_th,gap #otsu_layer = SingleBandRasterLayer(path = out_th, style_info={}) #layer.layer_parent.add_result_layer(otsu_layer) @@ -496,8 +497,7 @@ def table_layer(pth,layer,name,send_message,dict): 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 + result_layer = ResultPointLayer(out_csv, enable=True, proj=layer.proj, geo=layer.geo,result_path=dict) # print(result_layer.result_path) layer.layer_parent.add_result_layer(result_layer) send_message.emit('计算完成') diff --git a/rscder/gui/info.py b/rscder/gui/info.py new file mode 100644 index 0000000..551dbd1 --- /dev/null +++ b/rscder/gui/info.py @@ -0,0 +1,29 @@ +from distutils.log import info +from PyQt5.QtWidgets import QHBoxLayout,QDialog,QLabel,QVBoxLayout +from PyQt5.QtGui import QColor, QDragEnterEvent, QDropEvent,QPixmap +from PyQt5.QtCore import QSize,Qt +import yaml + + + +class InfoBox(QDialog): + def __init__(self,infodic:dict,parent=None): + super(InfoBox,self).__init__(parent=parent) + v=QVBoxLayout() + if 'prewmap' in infodic.keys(): + + pmap=infodic.pop('prewmap') + label=QLabel(yaml.dump(infodic,allow_unicode=True,sort_keys=False)) + label.setWordWrap(True)#过长自动换行,主要是wkt过长 + v.addWidget(label) + + maplabel=QLabel() + maplabel.setPixmap(QPixmap.fromImage(pmap)) + v.addWidget(maplabel,0,Qt.AlignHCenter) + else: + label=QLabel(yaml.dump(infodic,allow_unicode=True,sort_keys=False)) + label.setWordWrap(True)#过长自动换行,主要是wkt过长 + v.addWidget(label) + self.setLayout(v) + self.show() + \ No newline at end of file diff --git a/rscder/utils/project.py b/rscder/utils/project.py index d651a21..67754c0 100644 --- a/rscder/utils/project.py +++ b/rscder/utils/project.py @@ -1,16 +1,21 @@ from cgitb import enable from collections import OrderedDict +from email.message import Message +import imp import inspect import os from pathlib import Path +from pydoc import render_doc import shutil +from statistics import stdev from threading import Thread from time import sleep, time from typing import Dict, List import uuid import numpy as np -from osgeo import gdal, gdal_array +from osgeo import gdal, gdal_array,osr from rscder.utils.icons import IconInstance +from rscder.gui.info import InfoBox from rscder.utils.setting import Settings from qgis.core import (\ QgsRasterLayer, QgsMarkerSymbol, QgsUnitTypes, @@ -19,12 +24,12 @@ from qgis.core import (\ QgsLineSymbol, QgsSingleSymbolRenderer, QgsSimpleLineSymbolLayer, QgsVectorLayer, QgsCoordinateReferenceSystem, QgsFeature, QgsGeometry, QgsPointXY, QgsMultiBandColorRenderer) -from PyQt5.QtCore import QObject, pyqtSignal, Qt, QThread -from PyQt5.QtWidgets import QTreeWidgetItem, QAction +from PyQt5.QtCore import QObject, pyqtSignal, Qt, QThread,QSize +from PyQt5.QtWidgets import QTreeWidgetItem, QAction,QMessageBox from PyQt5.QtGui import QColor, QIcon, QFont import yaml -from .misc import singleton +from .misc import singleton def relative_path(path: str, root:str) -> str: return os.path.relpath(path, root) @@ -318,8 +323,22 @@ class BasicLayer(QObject): del_action.triggered.connect(del_layer) actions.append(del_action) + if self.info: + show_info=QAction(IconInstance().HELP,'属性信息') + actions.append(show_info) + def showIofn(info): + #print(info) + a=InfoBox(info) + a.exec_() + + show_info.triggered.connect(lambda :showIofn(self.info)) return actions + return actions + @property + def info(self): + return None + class GridLayer(BasicLayer): def set_render(self): @@ -390,7 +409,7 @@ class GridLayer(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':3}): + def __init__(self, name=None, enable=False, path=None, view_mode=BasicLayer.BOATH_VIEW,style_info={'r':3,'g':2,'b':1,'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) @@ -438,11 +457,44 @@ class RasterLayer(BasicLayer): return s def apply_style(self): pass + + @property + def bandinfo(self): + ds :gdal.Dataset= gdal.Open(self.path) + bands=ds.RasterCount + bandinfo_={} + for i in range(1,bands+1) : + min,max,mean,stdev=ds.GetRasterBand(i).ComputeStatistics(True) + bandinfo_['波段{}'.format(i)]=['最小值:{}'.format(min),'最大值:{}'.format(max),'均值:{}'.format(mean),'方差:{}'.format(stdev)] + ds=None + return bandinfo_ def set_stlye(self,style_info): self.style_info=style_info self.apply_style() + @property + def info(self): + #基础属性 + basic={} + basic['文件名']=self.path + + basic['文件大小']="{} Mb".format(os.path.getsize(self.path)//(1024*1024)) + basic['波段信息']=self.bandinfo + #渲染属性 + render=self.style_info + + mapinfo={ + '基础属性':basic, + '渲染属性':render, + 'prewmap':self.preview + } + return mapinfo + @property + def preview(self,width=400): + w=self.layer.width() + h=self.layer.height() + return self.layer.previewAsImage(QSize(width,int(width*h/w))) class MultiBandRasterLayer(RasterLayer): @@ -450,7 +502,10 @@ 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['渲染属性']['波段']='单波段' class SingleBandRasterLayer(RasterLayer): def apply_style(self): @@ -463,7 +518,7 @@ class VectorLayer(BasicLayer): class ResultPointLayer(BasicLayer): - def __init__(self, path, name=None, enable = False, proj = None, geo = None,result_path={},dsort=False ): + def __init__(self, path, name=None, enable = False, proj = None, geo = None,result_path={},dsort=False): if name is None: name = os.path.splitext(os.path.basename(path))[0] super().__init__(name, enable, icon=IconInstance().VECTOR, path=path, path_mode = BasicLayer.IN_FILE, view_mode=BasicLayer.BOATH_VIEW ) @@ -471,8 +526,8 @@ class ResultPointLayer(BasicLayer): self.wkt = proj self.geo = geo self.dsort=dsort - self.result_path=result_path - + self.result_path:dict=result_path + # self.methods= self.load_point_file() def save(self): @@ -619,8 +674,23 @@ class ResultPointLayer(BasicLayer): return actions # def load_file(self, path): + + @property + def info(self): + #基础属性 + basic={} + basic['文件路径']=self.path + #中间算法信息: + methods={ k:v[0] for k ,v in self.result_path.items()} + basic['变化检测算法']=methods + #渲染信息 + render={} + render['标注字体大小']=2 + render['标注颜色']='#ffff00' + render['阈值']=self.result_path['后处理'][1] + return {'基础属性':basic,'渲染属性':render} class PairLayer(BasicLayer): def __init__(self, pth1, pth2,style_info1,style_info2) -> None: @@ -694,7 +764,41 @@ class PairLayer(BasicLayer): ) return data + @property + def info(self): + + ds= gdal.Open(self.main_l1.path) + srs= osr.SpatialReference(ds.GetProjectionRef()) + metadata={} + # 空间参考系统 + metadata['proj4'] = srs.ExportToProj4() + metadata['wkt'] = srs.ExportToWkt() + # 地理坐标系 + metadata['geocs'] = srs.GetAttrValue('GEOGCS') + metadata['uom'] = srs.GetAttrValue('UNIT') + # 投影坐标系 + metadata['projcs'] = srs.GetAttrValue('PROJCS') # if projected + metadata['epsg'] = srs.GetAuthorityCode(None) + ds=None + #格网信息 + gridData={} + gridData['格网大小']='{}像素'.format(self.grid.cell_size) + gridData['格网线']=['宽度:1像素', '颜色:白色'] + + #公共掩模 + maskData={} + + + mapinfo={ + '坐标系':metadata, + '格网':gridData, + '公共掩膜':maskData + } + + return mapinfo + + @staticmethod def from_dict(data): player = PairLayer(data['pth1'], data['pth2'], data['style_info1'], data['style_info2'])