diff --git a/plugins/In_one/main.py b/plugins/In_one/main.py index c08f0b8..c6f47ce 100644 --- a/plugins/In_one/main.py +++ b/plugins/In_one/main.py @@ -500,4 +500,4 @@ def table_layer(pth,layer,name,send_message,dict): result_layer.result_path=dict # print(result_layer.result_path) layer.layer_parent.add_result_layer(result_layer) - send_message.emit('计算完成') \ No newline at end of file + send_message.emit('计算完成') diff --git a/rscder/gui/actions.py b/rscder/gui/actions.py index 0a140b8..a0d50b0 100644 --- a/rscder/gui/actions.py +++ b/rscder/gui/actions.py @@ -225,6 +225,7 @@ class ActionManager(QtCore.QObject): if Project().is_init: Project().save() file_loader=loader(self.w_parent) + file_loader.setModal(True) if(file_loader.exec_()): Project().add_layer(file_loader.path1,file_loader.path2,file_loader.style1,file_loader.style2) self.message_box.info('Data loaded') diff --git a/rscder/gui/load.py b/rscder/gui/load.py index 70322ad..fae616b 100644 --- a/rscder/gui/load.py +++ b/rscder/gui/load.py @@ -1,19 +1,48 @@ -from tkinter.ttk import Style +from colorsys import hls_to_rgb +import os +from osgeo import gdal from PyQt5.QtWidgets import QWidget, QApplication, QMainWindow, QToolBox -from PyQt5.QtWidgets import QDialog, QFileDialog, QLineEdit, QPushButton, QVBoxLayout, QHBoxLayout, QLabel, QMessageBox -from PyQt5.QtCore import Qt, QSize, QSettings +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 import QtGui +from threading import Thread from rscder.utils.icons import IconInstance from rscder.utils.setting import Settings -from rscder.gui.mapcanvas import DoubleCanvas from qgis.gui import QgsMapCanvas -from rscder.utils.project import MultiBandRasterLayer, RasterLayer +from rscder.utils.project import MultiBandRasterLayer, Project, RasterLayer +from rscder.gui.progress_bar import MetroCircleProgress + +class progressDialog(QDialog): + def __init__(self, parent=None,name='default') -> None: + super(progressDialog,self).__init__(parent) + self.setWindowTitle(name) + self.setWindowIcon(IconInstance().RASTER) + self.setFixedSize(300,80) + # self.setWindowIcon(IconInstance().RASTER) + tlayout=QVBoxLayout() + tlayout.setContentsMargins(10,0,0,0) + hlayout=QHBoxLayout() + h2layout=QHBoxLayout() + self.label=QLabel('加载影像...') + hlayout.addWidget(self.label) + hlayout.addItem(QSpacerItem(30,0)) + tlayout.addLayout(hlayout) + h2layout.addWidget(MetroCircleProgress(self, radius=7)) + tlayout.addLayout(h2layout) + self.setLayout(tlayout) + def setlabel(self,content:str): + self.label.setText(content) + class loader(QDialog): + signal1=pyqtSignal(str) def __init__(self, parent=None) -> None: super().__init__(parent) self.setWindowTitle('载入数据') self.setWindowIcon(IconInstance().DATA_LOAD) + self.pyramid:bool=False + self.temp1='' + self.temp2='' self.path1='' self.path2='' self.bands=['red:','green:','blue:','NIR:'] @@ -41,6 +70,7 @@ class loader(QDialog): path1_open = QPushButton('...', self) + # path1_open.setEnabled(False) path1_open.setFixedWidth(30) path1_open.clicked.connect(self.open_file1) @@ -50,7 +80,7 @@ class loader(QDialog): path1_layout.addWidget(path1_input) path1_layout.addWidget(path1_open) - + labels1=[QLabel() for i in range(4)] style1_inputs=[QLineEdit() for i in range(4)] for i in range(4): @@ -62,7 +92,7 @@ class loader(QDialog): style1_set = QPushButton(self.tr('确定'), self) style1_set.setFixedWidth(40) style1_set.clicked.connect(self.set_style1) - + style1_set.setEnabled(False) style1_layout=QHBoxLayout() for i in range(4): style1_layout.addWidget(labels1[i]) @@ -80,6 +110,7 @@ class loader(QDialog): path2_open = QPushButton('...', self) path2_open.setFixedWidth(30) + # path2_open.setEnabled(False) path2_open.clicked.connect(self.open_file2) path2_layout=QHBoxLayout() @@ -89,7 +120,7 @@ class loader(QDialog): labels2=[QLabel() for i in range(4)] - + style2_inputs=[QLineEdit() for i in range(4)] for i in range(4): labels2[i].setText(self.bands[i]) @@ -100,7 +131,9 @@ class loader(QDialog): style2_set = QPushButton(self.tr('确定'), self) style2_set.setFixedWidth(40) style2_set.clicked.connect(self.set_style2) - + style2_set.setEnabled(False) + self.open1=style1_set + self.open2=style2_set style2_layout=QHBoxLayout() for i in range(4): style2_layout.addWidget(labels2[i]) @@ -112,7 +145,7 @@ class loader(QDialog): ok_button.clicked.connect(self.ok) cancel_button.clicked.connect(self.cancel) - + button_layout = QHBoxLayout() button_layout.setDirection(QHBoxLayout.RightToLeft) button_layout.addWidget(ok_button, 0, Qt.AlignRight) @@ -129,21 +162,91 @@ class loader(QDialog): def open_file1(self): path1 = QFileDialog.getOpenFileNames(self, '打开数据1', Settings.General().last_path, '*.*') - if path1: - self.path1 = path1[0][0] - self.path1_input.setText(self.path1) - self.left_layer=MultiBandRasterLayer(path=self.path1) - self.mapcanva1.setLayers([self.left_layer.layer]) - self.mapcanva1.zoomToFeatureExtent(self.left_layer.layer.extent()) + if path1[0]!='': + try: + self.path1 = path1[0][0] + 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.setModal(False) + self.temp1=os.path.join(Project().other_path,'temp1.tif') + t1=GdalPreviewImage(self.path1,self.temp1,1024,self) + # t1.started.connect(progress1.show) + t1.finished.connect(self.loadfile1) + t1.finished.connect(lambda :progress1.setlabel('创建影像金字塔..')) + t2=build_pyramids_overviews(self.path1,self) + t2.finished.connect(progress1.hide) + t1.start() + t1.finished.connect(t2.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) + # t1.started.connect(progress1.show) + t1.finished.connect(self.loadfile1) + t1.finished.connect(progress1.hide) + t1.start() + progress1.show() + + + 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: + if path2[0]!='': + self.path2 = path2[0][0] self.path2_input.setText(self.path2) - self.right_layer=MultiBandRasterLayer(path=self.path2) - self.mapcanva2.setLayers([self.right_layer.layer]) - self.mapcanva2.zoomToFeatureExtent(self.right_layer.layer.extent()) + result=QMessageBox.question(self, '提示', '是否创建图像金字塔', QMessageBox.Yes | QMessageBox.No, QMessageBox.No) #默认关闭界面选择No + + if result==QMessageBox.Yes: + 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) + # t1.started.connect(progress1.show) + t1.finished.connect(self.loadfile2) + t1.finished.connect(lambda :progress2.setlabel('创建影像金字塔..')) + t2=build_pyramids_overviews(self.path2,self) + t2.finished.connect(progress2.hide) + t1.start() + t1.finished.connect(t2.start) + progress2.show() + else: + progress2=progressDialog(self,'加载时相二') + progress2.setModal(False) + self.temp2=os.path.join(Project().other_path,'temp2.tif') + t1=GdalPreviewImage(self.path2,self.temp2,1024) + # t1.started.connect(progress1.show) + t1.finished.connect(self.loadfile2) + 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]} @@ -161,6 +264,9 @@ class loader(QDialog): def cancel(self): self.reject() + def open_alg(self,path): + 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]} @@ -169,4 +275,90 @@ class loader(QDialog): 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) \ No newline at end of file + self.right_layer.set_stlye(self.style2) + +class GdalPreviewImage(QThread): + def __init__(self,srcFile,tarFilename,width=1024.0,parent=None) -> None: + super(GdalPreviewImage,self).__init__(parent) + self.srcFile=srcFile + self.tarFilename=tarFilename + 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 + + +class build_pyramids_overviews(QThread): + def __init__(self,filename,parent=None) -> None: + super(build_pyramids_overviews,self).__init__(parent) + self.filename=filename + def run(self): + 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) + del image + except: + pass + +if __name__ == '__main__': + import sys + + app = QApplication(sys.argv) + w = progressDialog() + w.show() + sys.exit(app.exec_()) \ No newline at end of file diff --git a/rscder/gui/progress_bar.py b/rscder/gui/progress_bar.py new file mode 100644 index 0000000..a788e45 --- /dev/null +++ b/rscder/gui/progress_bar.py @@ -0,0 +1,210 @@ +""" +Created on 2018年9月日 +@author: Irony +@site: https://pyqt.site , https://github.com/PyQt5 +@email: 892768447@qq.com +@file: MetroCircleProgress +@description: +""" + +try: + from PyQt5.QtCore import QSequentialAnimationGroup, QPauseAnimation, QPropertyAnimation, \ + QParallelAnimationGroup, QObject, QSize, Qt, QRectF, pyqtSignal, pyqtProperty + from PyQt5.QtGui import QPainter, QColor + from PyQt5.QtWidgets import QApplication, QWidget, QVBoxLayout,QDialog,QHBoxLayout,QLabel,QSpacerItem +except ImportError: + from PySide2.QtCore import QSequentialAnimationGroup, QPauseAnimation, QPropertyAnimation, \ + QParallelAnimationGroup, QObject, QSize, Qt, QRectF, Signal as pyqtSignal, Property as pyqtProperty + from PySide2.QtGui import QPainter, QColor + from PySide2.QtWidgets import QApplication, QWidget, QVBoxLayout + + +class CircleItem(QObject): + X = 0 # x坐标 + Opacity = 1 # 透明度0~1 + valueChanged = pyqtSignal() + + @pyqtProperty(float) + def x(self) -> float: + return self.X + + @x.setter + def x(self, x: float): + self.X = x + self.valueChanged.emit() + + @pyqtProperty(float) + def opacity(self) -> float: + return self.Opacity + + @opacity.setter + def opacity(self, opacity: float): + self.Opacity = opacity + + +def qBound(miv, cv, mxv): + return max(min(cv, mxv), miv) + + +class MetroCircleProgress(QWidget): + Radius = 5 # 半径 + Color = QColor(24, 189, 155) # 圆圈颜色 + BackgroundColor = QColor(Qt.transparent) # 背景颜色 + + def __init__(self, *args, radius=5, color=QColor(24, 189, 155), + backgroundColor=QColor(Qt.transparent), **kwargs): + super(MetroCircleProgress, self).__init__(*args, **kwargs) + self.Radius = radius + self.Color = color + self.BackgroundColor = backgroundColor + self._items = [] + self._initAnimations() + + @pyqtProperty(int) + def radius(self) -> int: + return self.Radius + + @radius.setter + def radius(self, radius: int): + if self.Radius != radius: + self.Radius = radius + self.update() + + @pyqtProperty(QColor) + def color(self) -> QColor: + return self.Color + + @color.setter + def color(self, color: QColor): + if self.Color != color: + self.Color = color + self.update() + + @pyqtProperty(QColor) + def backgroundColor(self) -> QColor: + return self.BackgroundColor + + @backgroundColor.setter + def backgroundColor(self, backgroundColor: QColor): + if self.BackgroundColor != backgroundColor: + self.BackgroundColor = backgroundColor + self.update() + + def paintEvent(self, event): + super(MetroCircleProgress, self).paintEvent(event) + painter = QPainter(self) + painter.setRenderHint(QPainter.Antialiasing) + painter.fillRect(self.rect(), self.BackgroundColor) + painter.setPen(Qt.NoPen) + + for item, _ in self._items: + painter.save() + color = self.Color.toRgb() + color.setAlphaF(item.opacity) + painter.setBrush(color) + # 5<= radius <=10 + radius = qBound(self.Radius, self.Radius / 200 * + self.height(), 2 * self.Radius) + diameter = 2 * radius + painter.drawRoundedRect( + QRectF( + item.x / 100 * self.width() - diameter, + (self.height() - radius) / 2, + diameter, diameter + ), radius, radius) + painter.restore() + + def _initAnimations(self): + for index in range(5): # 5个小圆 + item = CircleItem(self) + item.valueChanged.connect(self.update) + # 串行动画组 + seqAnimation = QSequentialAnimationGroup(self) + seqAnimation.setLoopCount(-1) + self._items.append((item, seqAnimation)) + + # 暂停延迟动画 + seqAnimation.addAnimation(QPauseAnimation(150 * index, self)) + + # 加速,并行动画组1 + parAnimation1 = QParallelAnimationGroup(self) + # 透明度 + parAnimation1.addAnimation(QPropertyAnimation( + item, b'opacity', self, duration=400, startValue=0, endValue=1.0)) + # x坐标 + parAnimation1.addAnimation(QPropertyAnimation( + item, b'x', self, duration=400, startValue=0, endValue=25.0)) + seqAnimation.addAnimation(parAnimation1) + ## + + # 匀速 + seqAnimation.addAnimation(QPropertyAnimation( + item, b'x', self, duration=2000, startValue=25.0, endValue=75.0)) + + # 加速,并行动画组2 + parAnimation2 = QParallelAnimationGroup(self) + # 透明度 + parAnimation2.addAnimation(QPropertyAnimation( + item, b'opacity', self, duration=400, startValue=1.0, endValue=0)) + # x坐标 + parAnimation2.addAnimation(QPropertyAnimation( + item, b'x', self, duration=400, startValue=75.0, endValue=100.0)) + seqAnimation.addAnimation(parAnimation2) + ## + + # 暂停延迟动画 + seqAnimation.addAnimation( + QPauseAnimation((5 - index - 1) * 150, self)) + + for _, animation in self._items: + animation.start() + + def sizeHint(self): + return QSize(100, self.Radius * 2) + + +class Window(QWidget): + + def __init__(self, *args, **kwargs): + super(Window, self).__init__(*args, **kwargs) + self.resize(800, 600) + layout = QVBoxLayout(self, spacing=0) + layout.setContentsMargins(0, 0, 0, 0) + layout.addWidget(MetroCircleProgress(self)) + layout.addWidget(MetroCircleProgress(self, radius=10)) + layout.addWidget(MetroCircleProgress(self, styleSheet=""" + qproperty-color: rgb(255, 0, 0); + """)) + layout.addWidget(MetroCircleProgress(self, styleSheet=""" + qproperty-color: rgb(0, 0, 255); + qproperty-backgroundColor: rgba(180, 180, 180, 180); + """)) + + +class progressDialog(QDialog): + def __init__(self, parent=None,name='default') -> None: + super().__init__(parent) + self.setWindowTitle(name) + self.setFixedSize(300,80) + # self.setWindowIcon(IconInstance().RASTER) + tlayout=QVBoxLayout() + tlayout.setContentsMargins(10,0,0,0) + hlayout=QHBoxLayout() + h2layout=QHBoxLayout() + self.label=QLabel('加载影像...') + hlayout.addWidget(self.label) + hlayout.addItem(QSpacerItem(30,0)) + tlayout.addLayout(hlayout) + h2layout.addWidget(MetroCircleProgress(self, radius=7)) + tlayout.addLayout(h2layout) + self.setLayout(tlayout) + + def setlabel(self,content:str): + self.label.setText(content) +if __name__ == '__main__': + import sys + + app = QApplication(sys.argv) + w = progressDialog() + w.show() + sys.exit(app.exec_()) \ No newline at end of file diff --git a/rscder/gui/project.py b/rscder/gui/project.py index 9fc7690..fb28dd5 100644 --- a/rscder/gui/project.py +++ b/rscder/gui/project.py @@ -102,7 +102,7 @@ class Create(QDialog): main_layout.addLayout(button_layout) self.setLayout(main_layout) - + def open_file(self): file = QFileDialog.getExistingDirectory(self, '选择文件夹', self.file)