diff --git a/eotimeseriesviewer/externals/qps/enmap.tif b/eotimeseriesviewer/externals/qps/enmap.tif index dd38499ac4bb8ce9d97bce3322873de8052db411..1f1efbe42830587a7c094b3a8c0642f9dfe25380 100644 Binary files a/eotimeseriesviewer/externals/qps/enmap.tif and b/eotimeseriesviewer/externals/qps/enmap.tif differ diff --git a/eotimeseriesviewer/externals/qps/speclib/core.py b/eotimeseriesviewer/externals/qps/speclib/core.py index da93a76481985a37264e223c5e4af3e3516c7b85..5c7987d5c295b2a2fedaf5e2b364b0525f54fa55 100644 --- a/eotimeseriesviewer/externals/qps/speclib/core.py +++ b/eotimeseriesviewer/externals/qps/speclib/core.py @@ -35,7 +35,7 @@ import uuid from osgeo import osr from ..speclib import SpectralLibrarySettingsKey from PyQt5.QtWidgets import * -from qgis.core import \ +from qgis.core import QgsApplication, \ QgsRenderContext, QgsFeature, QgsVectorLayer, QgsMapLayer, QgsRasterLayer, \ QgsAttributeTableConfig, QgsField, QgsFields, QgsCoordinateReferenceSystem, QgsCoordinateTransform, \ QgsVectorFileWriter, QgsActionManager, QgsFeatureIterator, QgsFeatureRequest, \ @@ -43,7 +43,7 @@ from qgis.core import \ QgsRaster, QgsDefaultValue, QgsReadWriteContext, \ QgsCategorizedSymbolRenderer, QgsMapLayerProxyModel, \ QgsSymbol, QgsNullSymbolRenderer, QgsMarkerSymbol, QgsLineSymbol, QgsFillSymbol, \ - QgsEditorWidgetSetup, QgsAction, QgsTask, QgsMessageLog + QgsEditorWidgetSetup, QgsAction, QgsTask, QgsMessageLog, QgsFileUtils from qgis.gui import \ QgsGui, QgsMapCanvas, QgsDualView, QgisInterface, QgsEditorConfigWidget, \ @@ -1388,10 +1388,10 @@ class SpectralProfileRenderer(object): pass else: style.setVisibility(False) - #symbol = renderer.sourceSymbol() + # symbol = renderer.sourceSymbol() elif isinstance(symbol, (QgsMarkerSymbol, QgsLineSymbol, QgsFillSymbol)): color: QColor = symbol.color() - color.setAlpha(int(symbol.opacity()*100)) + color.setAlpha(int(symbol.opacity() * 100)) style.setLineColor(color) style.setMarkerColor(color) @@ -2157,8 +2157,8 @@ class SpectralLibrary(QgsVectorLayer): path: str = None, baseName: str = DEFAULT_NAME, options: QgsVectorLayer.LayerOptions = None, - uri: str = None, # deprectated - name: str = None # deprectated + uri: str = None, # deprectated + name: str = None # deprectated ): if isinstance(uri, str): @@ -2623,10 +2623,10 @@ class SpectralLibrary(QgsVectorLayer): msg = super(SpectralLibrary, self).exportNamedStyle(doc, context=context, categories=categories) if msg == '': qgsNode = doc.documentElement().toElement() - #speclibNode = doc.createElement(XMLNODE_PROFILE_RENDERER) + # speclibNode = doc.createElement(XMLNODE_PROFILE_RENDERER) if isinstance(self.mProfileRenderer, SpectralProfileRenderer): self.mProfileRenderer.writeXml(qgsNode, doc) - #qgsNode.appendChild(speclibNode) + # qgsNode.appendChild(speclibNode) return msg @@ -2648,7 +2648,8 @@ class SpectralLibrary(QgsVectorLayer): warnings.warn('Use SpectralLibrary.write() instead', DeprecationWarning) return self.write(*args, **kwds) - def writeRasterImages(self, pathOne: typing.Union[str, pathlib.Path], drv:str='GTiff') -> typing.List[pathlib.Path]: + def writeRasterImages(self, pathOne: typing.Union[str, pathlib.Path], drv: str = 'GTiff') -> typing.List[ + pathlib.Path]: """ Writes the SpectralLibrary into images of same spectral properties :return: list of image paths @@ -2659,7 +2660,7 @@ class SpectralLibrary(QgsVectorLayer): basename, ext = os.path.splitext(pathOne.name) assert pathOne.parent.is_dir() - results = [] + imageFiles = [] for k, profiles in self.groupBySpectralProperties().items(): xValues, xUnit, yUnit = k ns: int = len(profiles) @@ -2667,26 +2668,29 @@ class SpectralLibrary(QgsVectorLayer): ref_profile = np.asarray(profiles[0].yValues()) dtype = ref_profile.dtype - imageArray = np.empty((nb, ns, 1), dtype=dtype) - imageArray[:,0,0] = ref_profile + imageArray = np.empty((nb, 1, ns), dtype=dtype) + imageArray[:, 0, 0] = ref_profile + for i in range(1, len(profiles)): - imageArray[:, i, 0] = np.asarray(profiles[i].yValues(), dtype=dtype) - if len(results) == 0: + imageArray[:, 0, i] = np.asarray(profiles[i].yValues(), dtype=dtype) + + if len(imageFiles) == 0: pathDst = pathOne.parent / f'{basename}{ext}' else: - pathDst = pathOne.parent / f'{basename}{i}{ext}' + pathDst = pathOne.parent / f'{basename}{len(imageFiles)}{ext}' dsDst: gdal.Dataset = gdal_array.SaveArray(imageArray, pathDst.as_posix(), format=drv) fakeProjection: osr.SpatialReference = osr.SpatialReference() fakeProjection.SetFromUserInput('EPSG:3857') dsDst.SetProjection(fakeProjection.ExportToWkt()) - dsDst.SetGeoTransform([0.0, 1.0, 0.0, 0.0, 0.0, -1.0]) + # north-up project, 1 px above equator, starting at 0°, n pixels = n profiles towards east + dsDst.SetGeoTransform([0.0, 1.0, 0.0, 1.0, 0.0, -1.0]) dsDst.SetMetadataItem('wavelength units', xUnit) dsDst.SetMetadataItem('wavelength', ','.join(f'{v}' for v in xValues)) dsDst.FlushCache() - results.append(pathDst) + imageFiles.append(pathDst) del dsDst - return results + return imageFiles def write(self, path: str, **kwds) -> typing.List[str]: """ @@ -2703,7 +2707,7 @@ class SpectralLibrary(QgsVectorLayer): if path is None: path, filter = QFileDialog.getSaveFileName(parent=kwds.get('parent'), caption='Save Spectral Library', - directory='speclib', + directory=QgsFileUtils.stringToSafeFilename(self.name()), filter=FILTERS) if isinstance(path, pathlib.Path): @@ -2724,41 +2728,46 @@ class SpectralLibrary(QgsVectorLayer): return [] - def yRange(self): - profiles = self.profiles() - minY = min([min(p.yValues()) for p in profiles]) - maxY = max([max(p.yValues()) for p in profiles]) + def yRange(self) -> typing.List[float]: + """ + Returns the maximum y range + :return: + :rtype: + """ + + minY = maxY = 0 + + for p in self.profiles(): + yValues = p.yValues() + minY = min(minY, min(yValues)) + maxY = max(maxY, max(yValues)) + return minY, maxY def __repr__(self): return str(self.__class__) + '"{}" {} feature(s)'.format(self.name(), self.dataProvider().featureCount()) - def plot(self): + def plot(self) -> QWidget: """Create a plot widget and shows all SpectralProfile in this SpectralLibrary.""" - from ..externals import pyqtgraph as pg - pg.mkQApp() - win = pg.GraphicsWindow(title="Spectral Library") - win.resize(1000, 600) + app = None + if not isinstance(QgsApplication.instance(), QgsApplication): + from ..testing import start_app + app = start_app() - # Enable antialiasing for prettier plots - pg.setConfigOptions(antialias=True) + from .gui import SpectralLibraryWidget - # Create a plot with some random data - p1 = win.addPlot(title="Spectral Library {}".format(self.name()), pen=0.5) - yMin, yMax = self.yRange() - p1.setYRange(yMin, yMax) + w = SpectralLibraryWidget(speclib=self) + w.show() - # Add three infinite lines with labels - for p in self: - pi = pg.PlotDataItem(p.xValues(), p.yValues()) - p1.addItem(pi) + if app: + app.exec_() - pg.QAPP.exec_() + return w def fieldNames(self) -> list: """ - Retunrs the field names. Shortcut from self.fields().names() + Returns the field names. Shortcut from self.fields().names() :return: [list-of-str] """ return self.fields().names() diff --git a/eotimeseriesviewer/externals/qps/speclib/gui.py b/eotimeseriesviewer/externals/qps/speclib/gui.py index 57d87f8a78b2ba03069536ee72037705e7691fe4..dcfd60224fbd099ace691f09900e40174328b343 100644 --- a/eotimeseriesviewer/externals/qps/speclib/gui.py +++ b/eotimeseriesviewer/externals/qps/speclib/gui.py @@ -42,7 +42,7 @@ from qgis.core import \ QgsFeature, QgsRenderContext, QgsNullSymbolRenderer, \ QgsRasterLayer, QgsMapLayer, QgsVectorLayer, \ QgsSymbol, QgsMarkerSymbol, QgsLineSymbol, QgsFillSymbol, \ - QgsAttributeTableConfig, QgsField, QgsMapLayerProxyModel + QgsAttributeTableConfig, QgsField, QgsMapLayerProxyModel, QgsFileUtils from qgis.gui import \ QgsEditorWidgetWrapper, QgsAttributeTableView, \ QgsActionMenu, QgsEditorWidgetFactory, QgsStatusBar, \ @@ -808,8 +808,7 @@ class SpectralLibraryPlotWidget(pg.PlotWidget): self.mXAxis: SpectralXAxis = pi.getAxis('bottom') assert isinstance(self.mXAxis, SpectralXAxis) - self.mSpeclib: SpectralLibrary - self.mSpeclib = None + self.mSpeclib: SpectralLibrary = None self.mSpeclibSignalConnections = [] self.mXUnitInitialized = False @@ -2155,7 +2154,7 @@ class SpectralLibraryWidget(AttributeTableWidget): from .io.specchio import SPECCHIOSpectralLibraryIO from .io.artmo import ARTMOSpectralLibraryIO from .io.vectorsources import VectorSourceSpectralLibraryIO - + from .io.rastersources import RasterSourceSpectralLibraryIO self.mSpeclibIOInterfaces = [ EnviSpectralLibraryIO(), CSVSpectralLibraryIO(), @@ -2164,6 +2163,7 @@ class SpectralLibraryWidget(AttributeTableWidget): EcoSISSpectralLibraryIO(), SPECCHIOSpectralLibraryIO(), VectorSourceSpectralLibraryIO(), + RasterSourceSpectralLibraryIO(), ] self.mSpeclibIOInterfaces = sorted(self.mSpeclibIOInterfaces, key=lambda c: c.__class__.__name__) @@ -2233,6 +2233,7 @@ class SpectralLibraryWidget(AttributeTableWidget): self.actionExportSpeclib = QAction('Export Spectral Profiles') self.actionExportSpeclib.setToolTip('Export spectral profiles to other data formats') self.actionExportSpeclib.setIcon(QIcon(':/qps/ui/icons/speclib_save.svg')) + m = QMenu() self.createSpeclibExportMenu(m) self.actionExportSpeclib.setMenu(m) @@ -2337,17 +2338,39 @@ class SpectralLibraryWidget(AttributeTableWidget): """ :return: QMenu with QActions and submenus to import SpectralProfiles """ + separated = [] + from .io.rastersources import RasterSourceSpectralLibraryIO + for iface in self.mSpeclibIOInterfaces: assert isinstance(iface, AbstractSpectralLibraryIO), iface - iface.addImportActions(self.speclib(), menu) + if isinstance(iface, RasterSourceSpectralLibraryIO): + separated.append(iface) + else: + iface.addImportActions(self.speclib(), menu) + + if len(separated) > 0: + menu.addSeparator() + for iface in separated: + iface.addImportActions(self.speclib(), menu) def createSpeclibExportMenu(self, menu: QMenu): """ - :return: QMenu with QActions and submenus to export SpectralProfiles + :return: QMenu with QActions and submenus to export the SpectralLibrary """ + separated = [] + from .io.rastersources import RasterSourceSpectralLibraryIO for iface in self.mSpeclibIOInterfaces: assert isinstance(iface, AbstractSpectralLibraryIO) - iface.addExportActions(self.speclib(), menu) + if isinstance(iface, RasterSourceSpectralLibraryIO): + separated.append(iface) + else: + iface.addExportActions(self.speclib(), menu) + + if len(separated) > 0: + menu.addSeparator() + for iface in separated: + iface.addExportActions(self.speclib(), menu) + def plotWidget(self) -> SpectralLibraryPlotWidget: return self.mPlotWidget @@ -2529,7 +2552,7 @@ class SpectralLibraryWidget(AttributeTableWidget): self.speclib().startEditing() def onExportSpectra(self, *args): - files = self.mSpeclib.write(None) + files = self.speclib().write(None) if len(files) > 0: self.sigFilesCreated.emit(files) diff --git a/eotimeseriesviewer/externals/qps/speclib/io/rastersources.py b/eotimeseriesviewer/externals/qps/speclib/io/rastersources.py index 48129861ebaf70e6cda0770b776b3ab42479e020..5e89f7926291725eeb4268d2bb42f20a3c278029 100644 --- a/eotimeseriesviewer/externals/qps/speclib/io/rastersources.py +++ b/eotimeseriesviewer/externals/qps/speclib/io/rastersources.py @@ -24,19 +24,21 @@ along with this software. If not, see <http://www.gnu.org/licenses/>. *************************************************************************** """ - +import os import sys import typing - +from osgeo import gdal +import numpy as np from qgis.PyQt import sip from qgis.PyQt.QtGui import * from qgis.PyQt.QtWidgets import * from qgis.PyQt.QtCore import * from qgis.core import QgsTask, QgsMapLayer, QgsVectorLayer, QgsRasterLayer, QgsWkbTypes, \ - QgsTaskManager, QgsMapLayerProxyModel, QgsApplication -from ..core import SpectralProfile, SpectralLibrary -from ...utils import SelectMapLayersDialog + QgsTaskManager, QgsMapLayerProxyModel, QgsApplication, QgsFileUtils +from ..core import SpectralProfile, SpectralLibrary, AbstractSpectralLibraryIO, ProgressHandler +from ...utils import SelectMapLayersDialog, gdalDataset, parseWavelength, parseFWHM, parseBadBandList +PIXEL_LIMIT = 100*100 class SpectralProfileLoadingTask(QgsTask): @@ -240,3 +242,133 @@ class SpectralProfileImportPointsDialog(SelectMapLayersDialog): :return: QgsVectorLayer """ return self.mapLayers()[1] + + +class RasterSourceSpectralLibraryIO(AbstractSpectralLibraryIO): + """ + I/O Interface for Raster files. + """ + + @classmethod + def canRead(cls, path: str) -> bool: + """ + Returns true if it can read the source defined by path + :param path: source uri + :return: True, if source is readable. + """ + path = str(path) + try: + ds = gdalDataset(path) + return True + except: + return False + return False + + @classmethod + def readFrom(cls, path, + progressDialog: typing.Union[QProgressDialog, ProgressHandler] = None, + addAttributes: bool = True) -> SpectralLibrary: + + ds: gdal.Dataset = gdalDataset(path) + if not isinstance(ds, gdal.Dataset): + return None + + speclib = SpectralLibrary() + assert isinstance(speclib, SpectralLibrary) + sourcepath = ds.GetDescription() + basename = os.path.basename(ds.GetDescription()) + speclib.setName(basename) + assert speclib.startEditing() + + wl, wlu = parseWavelength(ds) + fwhm = parseFWHM(ds) + bbl = parseBadBandList(ds) + + # each none-masked pixel is a profile + array = ds.ReadAsArray() + + ref_band: gdal.Band = ds.GetRasterBand(1) + no_data = ref_band.GetNoDataValue() + valid = np.isfinite(array[0, :]) + if no_data: + valid = valid * (array[0, :] != no_data) + valid = np.where(valid) + + n_profiles = len(valid[0]) + if n_profiles > PIXEL_LIMIT: + raise Exception(f'Number of raster image pixels {n_profiles} exceeds PIXEL_LIMIT {PIXEL_LIMIT}') + + if wl is not None: + xvalues = wl.tolist() + else: + xvalues = (np.arange(ds.RasterCount) + 1).tolist() + + profiles = [] + for y, x in zip(*valid): + yvalues = array[:, y, x] + p = SpectralProfile(fields=speclib.fields()) + p.setName(f'Profile {x},{y}') + p.setSource(basename) + p.setValues(xvalues, yvalues, xUnit=wlu) + profiles.append(p) + speclib.addProfiles(profiles) + speclib.commitChanges() + return speclib + + @classmethod + def write(cls, speclib: SpectralLibrary, + path: str, + progressDialog: typing.Union[QProgressDialog, ProgressHandler] = None): + """ + Writes the SpectralLibrary to path and returns a list of written files that can be used to open the spectral library with readFrom + """ + speclib.writeRasterImages(path) + + return [path] + + @classmethod + def addImportActions(cls, spectralLibrary: SpectralLibrary, menu: QMenu) -> list: + + def read(speclib: SpectralLibrary): + + path, filter = QFileDialog.getOpenFileName(caption='Raster Image', + filter='All types (*.*)') + if os.path.isfile(path): + + if not RasterSourceSpectralLibraryIO.canRead(path): + QMessageBox.critical(None, 'Raster image as SpectralLibrary', f'Unable to reads {path}') + + try: + sl = RasterSourceSpectralLibraryIO.readFrom(path) + if isinstance(sl, SpectralLibrary): + speclib.startEditing() + speclib.beginEditCommand('Add Spectral Library from {}'.format(path)) + speclib.addSpeclib(sl, addMissingFields=True) + speclib.endEditCommand() + speclib.commitChanges() + except Exception as ex: + QMessageBox.critical(None, 'Raster image as SpectralLibrary', str(ex)) + return + m = menu.addAction('Raster Image') + m.setToolTip('Import all pixels as spectral profiles which are not masked. ' + 'Use careful and not with large images!') + m.triggered.connect(lambda *args, sl=spectralLibrary: read(sl)) + + @classmethod + def addExportActions(cls, spectralLibrary: SpectralLibrary, menu: QMenu) -> list: + + def write(speclib: SpectralLibrary): + # https://gdal.org/drivers/vector/index.html + LUT_Files = {'GeoTiff (*.tif)': 'GTiff', + 'ENVI Raster (*.bsq)': 'ENVI', + } + + path, filter = QFileDialog.getSaveFileName(caption='Write as raster image', + filter=';;'.join(LUT_Files.keys()), + directory=QgsFileUtils.stringToSafeFilename(speclib.name())) + if isinstance(path, str) and len(path) > 0: + speclib.writeRasterImages(path, drv=LUT_Files.get(filter, 'GTiff')) + + a = menu.addAction('Raster Image') + a.setToolTip('Write profiles as raster image(s), grouped by wavelengths.') + a.triggered.connect(lambda *args, sl=spectralLibrary: write(sl)) diff --git a/eotimeseriesviewer/externals/qps/speclib/io/vectorsources.py b/eotimeseriesviewer/externals/qps/speclib/io/vectorsources.py index 4d424bbbca66a9807963be57bb9747602b3eacd0..477d944e3870d3876fe452b2c7e1a9667cea7c97 100644 --- a/eotimeseriesviewer/externals/qps/speclib/io/vectorsources.py +++ b/eotimeseriesviewer/externals/qps/speclib/io/vectorsources.py @@ -34,9 +34,9 @@ import typing from qgis.PyQt.QtCore import * from qgis.PyQt.QtWidgets import * -from qgis.core import * -from qgis.gui import * -from qgis.core import QgsField, QgsVectorLayer, QgsVectorFileWriter, QgsProviderRegistry, QgsProject + +from qgis.core import QgsField, QgsVectorLayer, QgsVectorFileWriter, QgsProviderRegistry, \ + QgsProject, QgsProviderMetadata, QgsFileUtils from ..core import SpectralProfile, SpectralLibrary, AbstractSpectralLibraryIO, \ decodeProfileValueDict, encodeProfileValueDict, \ @@ -82,8 +82,7 @@ class VectorSourceFieldValueConverter(QgsVectorFileWriter.FieldValueConverter): class VectorSourceSpectralLibraryIO(AbstractSpectralLibraryIO): """ - I/O Interface for the EcoSIS spectral library format. - See https://ecosis.org for details. + I/O Interface for Vector File Formats. """ @classmethod @@ -118,6 +117,8 @@ class VectorSourceSpectralLibraryIO(AbstractSpectralLibraryIO): addAttributes: bool = True) -> SpectralLibrary: """ Returns the SpectralLibrary read from "path" + :param progressDialog: + :type progressDialog: :param path: source of SpectralLibrary :return: SpectralLibrary """ @@ -252,7 +253,9 @@ class VectorSourceSpectralLibraryIO(AbstractSpectralLibraryIO): def read(speclib: SpectralLibrary): path, filter = QFileDialog.getOpenFileName(caption='Vector File', - filter='All type (*.*)') + filter='All type (*.*)', + directory=QgsFileUtils.stringToSafeFilename(speclib.name()) + ) if os.path.isfile(path) and VectorSourceSpectralLibraryIO.canRead(path): sl = VectorSourceSpectralLibraryIO.readFrom(path) if isinstance(sl, SpectralLibrary): @@ -269,7 +272,7 @@ class VectorSourceSpectralLibraryIO(AbstractSpectralLibraryIO): @classmethod def addExportActions(cls, spectralLibrary: SpectralLibrary, menu: QMenu) -> list: - + """ def write_new(speclib: SpectralLibrary): # this is not available in Python. Why? from qgis.gui import QgsVectorLayerSaveAsDialog @@ -282,7 +285,7 @@ class VectorSourceSpectralLibraryIO(AbstractSpectralLibraryIO): d = QgsVectorLayerSaveAsDialog(speclib, options=options) d.show() - s = "" + """ def write(speclib: SpectralLibrary): # https://gdal.org/drivers/vector/index.html diff --git a/eotimeseriesviewer/externals/qps/testing.py b/eotimeseriesviewer/externals/qps/testing.py index ec3ea1235779a9a421fcc56b650170e490a39a28..6b645d4e503a44b2f5ed562839894badc10726d5 100644 --- a/eotimeseriesviewer/externals/qps/testing.py +++ b/eotimeseriesviewer/externals/qps/testing.py @@ -129,7 +129,8 @@ def start_app(cleanup=True, options=StartOptions.Minimized, resources: list = [] qgsApp.addLibraryPath(candidate.as_posix()) assert QgsProviderRegistry.instance().libraryDirectory().exists(), \ - 'Directory: {} does not exist'.format(QgsProviderRegistry.instance().libraryDirectory().path()) + 'Directory: {} does not exist. Please check if QGIS_PREFIX_PATH correct'.format( + QgsProviderRegistry.instance().libraryDirectory().path()) # initiate a PythonRunner instance if None exists if StartOptions.PythonRunner in options and not QgsPythonRunner.isValid(): @@ -518,9 +519,16 @@ class TestObjects(): coredata, wl, wlu, gt, wkt = TestObjects.coreData() cnb, cnl, cns = coredata.shape assert n > 0 + if not isinstance(n_bands, list): + n_bands = [n_bands] assert isinstance(n_bands, list) - for nb in n_bands: - assert nb == -1 or nb > 0 and nb <= cnb + for i in range(len(n_bands)): + nb = n_bands[i] + if nb == -1: + n_bands[i] = cnb + else: + assert 0 < nb <= cnb, f'Number of bands need to be in range 0 < nb <= {cnb}.' + n_bands = [nb if nb > 0 else cnb for nb in n_bands] for nb in n_bands: @@ -544,7 +552,7 @@ class TestObjects(): for (data, wl, data_wlu) in TestObjects.spectralProfileData(n, n_bands=n_bands): if wlu is None: wlu = data_wlu - if wlu != data_wlu: + elif wlu != data_wlu: wl = UnitLookup.convertMetricUnit(wl, data_wlu, wlu) profile = SpectralProfile(fields=fields) @@ -564,6 +572,8 @@ class TestObjects(): wlu: str = None): """ Creates an Spectral Library + :param n_bands: + :type n_bands: :param wlu: :type wlu: :param n: total number of profiles @@ -717,7 +727,9 @@ class TestObjects(): wl = core_wl[:nb].tolist() assert len(wl) == nb - if wlu != core_wlu: + if wlu is None: + wlu = core_wlu + elif wlu != core_wlu: wl = UnitLookup.convertMetricUnit(wl, core_wlu, wlu) domain = None diff --git a/tests/test_stackedbandinput.py b/tests/test_stackedbandinput.py index f7e87a2eaee27188b12f960969ea31871a82e138..a2884764e19ccaf7e3f437f099c8583594563f67 100644 --- a/tests/test_stackedbandinput.py +++ b/tests/test_stackedbandinput.py @@ -19,20 +19,18 @@ # noinspection PyPep8Naming import os import sys +import unittest import xmlrunner +from qgis.PyQt.QtWidgets import QApplication +from qgis.core import QgsRasterLayer from eotimeseriesviewer.tests import start_app, EOTSVTestCase from eotimeseriesviewer.utils import nextColor -from osgeo import gdal_array -from qgis.PyQt.QtGui import * -from qgis.PyQt.QtCore import * -import unittest, tempfile - - - +from osgeo import gdal_array, osr from eotimeseriesviewer.stackedbandinput import * -from example.Images import Img_2014_06_16_LE72270652014167CUB00_BOA, Img_2014_05_07_LC82270652014127LGN00_BOA + from eotimeseriesviewer.main import EOTimeSeriesViewer + class TestStackedInputs(EOTSVTestCase): def setUp(self): @@ -42,7 +40,6 @@ class TestStackedInputs(EOTSVTestCase): eotsv.close() QApplication.processEvents() - def createTestDatasets(self): vsiDir = r'/vsimem/tmp' @@ -60,7 +57,7 @@ class TestStackedInputs(EOTSVTestCase): assert isinstance(drv, gdal.Driver) datasets = [] for i, r in enumerate([r1, r2]): - p = '{}tmpstack{}.bsq'.format(vsiDir, i+1) + p = '{}tmpstack{}.bsq'.format(vsiDir, i + 1) nb = len(r) ds = drv.Create(p, ns, nl, nb, eType=gdal.GDT_Float32) assert isinstance(ds, gdal.Dataset) @@ -74,33 +71,32 @@ class TestStackedInputs(EOTSVTestCase): for b, date in enumerate(r): decimalYear = date2num(date) - band = ds.GetRasterBand(b+1) + band = ds.GetRasterBand(b + 1) assert isinstance(band, gdal.Band) band.Fill(decimalYear) ds.FlushCache() datasets.append(p) - if i == 0: - #create a classification image stack + # create a classification image stack nc = nb data = np.ones((nb, ns, nl), dtype=np.uint8) classNames = ['unclassified'] colorTable = gdal.ColorTable() - colorTable.SetColorEntry(0, (0,0,0)) + colorTable.SetColorEntry(0, (0, 0, 0)) assert isinstance(colorTable, gdal.ColorTable) color = QColor('green') for j, date in enumerate(r): - c = j+1 + c = j + 1 data[j, j:-1, 0:j] = c classNames.append('Class {}'.format(date)) colorTable.SetColorEntry(c, color.getRgb()) color = nextColor(color) p = '{}tmpClassificationStack.bsq'.format(vsiDir) - ds = gdal_array.SaveArray(data,p, format='ENVI', prototype=datasets[0]) + ds = gdal_array.SaveArray(data, p, format='ENVI', prototype=datasets[0]) ds.GetRasterBand(1).SetColorTable(colorTable) ds.GetRasterBand(1).SetCategoryNames(classNames) @@ -110,7 +106,6 @@ class TestStackedInputs(EOTSVTestCase): datasets.append(ds) return datasets - def test_FORCEStacks(self): pathStack = r'T:\4BJ\2018-2018_000-000_LEVEL4_TSA_SEN2L_EVI_C0_S0_TSS.tif' @@ -122,7 +117,6 @@ class TestStackedInputs(EOTSVTestCase): self.showGui() - def test_inputmodel(self): testData = self.createTestDatasets() m = InputStackTableModel() @@ -135,7 +129,6 @@ class TestStackedInputs(EOTSVTestCase): self.assertTrue(len(dIntersecton) > 0) self.assertTrue(len(dTotal) > len(dIntersecton)) - def test_outputmodel(self): m = OutputImageModel() @@ -168,7 +161,6 @@ class TestStackedInputs(EOTSVTestCase): eTree = m.vrtXML(outInfo, asElementTree=True) self.assertIsInstance(eTree, ElementTree.Element) - def test_dialog(self): d = StackedBandInputDialog() d.addSources(self.createTestDatasets()) @@ -195,8 +187,6 @@ class TestStackedInputs(EOTSVTestCase): def test_withTSV(self): - - testImages = self.createTestDatasets() from eotimeseriesviewer.main import EOTimeSeriesViewer TSV = EOTimeSeriesViewer()