Newer
Older
from __future__ import absolute_import
import six, sys, os, gc, re, collections, site, inspect, time, traceback, copy
import logging
logger = logging.getLogger(__name__)

benjamin.jakimow@geo.hu-berlin.de
committed
import bisect, datetime
from osgeo import gdal, ogr
from qgis import *
from qgis.core import *
from qgis.gui import *
from PyQt4.QtGui import *
from PyQt4.QtCore import *
from PyQt4.QtXml import *
from osgeo import gdal, ogr, gdal_array

benjamin.jakimow@geo.hu-berlin.de
committed
gdal.SetConfigOption('VRT_SHARED_SOURCE', '0') #!important. really. do not change this.
from timeseriesviewer import DIR_REPO, DIR_EXAMPLES, jp, SETTINGS
from timeseriesviewer.dateparser import parseDateFromDataSet
def transformGeometry(geom, crsSrc, crsDst, trans=None):
if trans is None:
assert isinstance(crsSrc, QgsCoordinateReferenceSystem)
assert isinstance(crsDst, QgsCoordinateReferenceSystem)
return transformGeometry(geom, None, None, trans=QgsCoordinateTransform(crsSrc, crsDst))
else:
assert isinstance(trans, QgsCoordinateTransform)
return trans.transform(geom)
METRIC_EXPONENTS = {
"nm":-9,"um": -6, "mm":-3, "cm":-2, "dm":-1, "m": 0,"hm":2, "km":3
}
#add synonyms
METRIC_EXPONENTS['nanometers'] = METRIC_EXPONENTS['nm']
METRIC_EXPONENTS['micrometers'] = METRIC_EXPONENTS['um']
METRIC_EXPONENTS['millimeters'] = METRIC_EXPONENTS['mm']
METRIC_EXPONENTS['centimeters'] = METRIC_EXPONENTS['cm']
METRIC_EXPONENTS['decimeters'] = METRIC_EXPONENTS['dm']
METRIC_EXPONENTS['meters'] = METRIC_EXPONENTS['m']
METRIC_EXPONENTS['hectometers'] = METRIC_EXPONENTS['hm']
METRIC_EXPONENTS['kilometers'] = METRIC_EXPONENTS['km']
def convertMetricUnit(value, u1, u2):
assert u1 in METRIC_EXPONENTS.keys()
assert u2 in METRIC_EXPONENTS.keys()
e1 = METRIC_EXPONENTS[u1]
e2 = METRIC_EXPONENTS[u2]
return value * 10**(e1-e2)
def getDS(pathOrDataset):
if isinstance(pathOrDataset, gdal.Dataset):
return pathOrDataset
else:
ds = gdal.Open(pathOrDataset)
assert isinstance(ds, gdal.Dataset)
return ds
class SensorInstrument(QObject):
SensorNameSettingsPrefix = 'SensorName.'
sigNameChanged = pyqtSignal(str)
LUT_Wavelengths = dict({'B':480,
'G':570,
'R':660,
'nIR':850,
'swIR':1650,
'swIR1':1650,
'swIR2':2150
})
def __init__(self, pathImg, sensor_name=None):
super(SensorInstrument, self).__init__()
ds = getDS(pathImg)
self.nb, nl, ns, crs, self.px_size_x, self.px_size_y = getSpatialPropertiesFromDataset(ds)
self.bandDataType = ds.GetRasterBand(1).DataType
self.pathImg = ds.GetFileList()[0]
self.bandNames = [ds.GetRasterBand(b+1).GetDescription() for b in range(self.nb)]
self.TS = None
assert self.px_size_x > 0
assert self.px_size_y > 0
wl, wlu = parseWavelengthFromDataSet(ds)
if wl is None:
self.wavelengths = None
self.wavelengthUnits = None
else:
self.wavelengths = np.asarray(wl)
self.wavelengthUnits = wlu
self._id = '{}b{}m'.format(self.nb, self.px_size_x)
if wl is not None:
self._id += ';'.join([str(w) for w in self.wavelengths])+wlu
if wlu is None:
wlu = ''
if sensor_name is None:
sensor_name = '{}bands@{}m'.format(self.nb, self.px_size_x)
sensor_name = SETTINGS.value(self._sensorSettingsKey(), sensor_name)
self.setName(sensor_name)
def id(self):
return self._id
def _sensorSettingsKey(self):
return SensorInstrument.SensorNameSettingsPrefix+self._id
def setName(self, name):
self._name = name
SETTINGS.setValue(self._sensorSettingsKey(), name)
self.sigNameChanged.emit(self.name())
def name(self):
return self._name
def dataType(self, p_int):
return self.bandDataType
def bandClosestToWavelength(self, wl, wl_unit='nm'):
"""

benjamin.jakimow@geo.hu-berlin.de
committed
Returns the band index (>=0) of the band closest to wavelength wl
:param wl:
:param wl_unit:
:return:
"""
if not self.wavelengthsDefined():
return None
if wl in SensorInstrument.LUT_Wavelengths.keys():
wl = SensorInstrument.LUT_Wavelengths[wl]
wl = float(wl)
if self.wavelengthUnits != wl_unit:
wl = convertMetricUnit(wl, wl_unit, self.wavelengthUnits)

benjamin.jakimow@geo.hu-berlin.de
committed
return np.argmin(np.abs(self.wavelengths - wl))
def wavelengthsDefined(self):
return self.wavelengths is not None and \
self.wavelengthUnits is not None

Benjamin Jakimow
committed
if not isinstance(other, SensorInstrument):
return False
return self.nb == other.nb and \
self.px_size_x == other.px_size_x and \
self.px_size_y == other.px_size_y
def __hash__(self):
return hash(self.id())
return str(self.__class__) +' ' + self.name()
info.append(self.name())
info.append('{} Bands'.format(self.nb))
info.append('Band\tName\tWavelength')
for b in range(self.nb):
if self.wavelengths is not None:
wl = str(self.wavelengths[b])
else:
wl = 'unknown'
info.append('{}\t{}\t{}'.format(b + 1, self.bandNames[b], wl))
return '\n'.join(info)
def verifyInputImage(path, vrtInspection=''):
if path is None or not type(path) in [str, unicode]:
return None

benjamin.jakimow@geo.hu-berlin.de
committed
logger.error('{}GDAL unable to open: '.format(vrtInspection, path))

benjamin.jakimow@geo.hu-berlin.de
committed
if ds.RasterCount == 0 and len(ds.GetSubDatasets()) > 0:
logger.error('Can not open container {}.\nPlease specify a subdataset'.format(path))
if ds.GetDriver().ShortName == 'VRT':
vrtInspection = 'VRT Inspection {}\n'.format(path)

benjamin.jakimow@geo.hu-berlin.de
committed
nextFiles = set(ds.GetFileList()) - set([path])
validSrc = [verifyInputImage(p, vrtInspection=vrtInspection) for p in nextFiles]
if not all(validSrc):
return False
from timeseriesviewer.dateparser import parseDateFromDataSet
date = parseDateFromDataSet(ds)
if date is None:
return False

benjamin.jakimow@geo.hu-berlin.de
committed
return True
def pixel2coord(gt, x, y):
"""Returns global coordinates from pixel x, y coords"""
"""https://scriptndebug.wordpress.com/2014/11/24/latitudelongitude-of-each-pixel-using-python-and-gdal/"""
xoff, a, b, yoff, d, e = gt
xp = a * x + b * y + xoff
yp = d * x + e * y + yoff
return (xp, yp)
class TimeSeriesDatum(QObject):
@staticmethod
def createFromPath(path):
"""
Creates a valid TSD or returns None if this is impossible
:param path:
:return:
"""
if verifyInputImage(path):
tsd = TimeSeriesDatum(None, path)
except :
pass
return tsd
"""
Collects all data sets related to one sensor
"""
sigVisibilityChanged = pyqtSignal(bool)
sigRemoveMe = pyqtSignal()
def __init__(self, timeSeries, pathImg):
super(TimeSeriesDatum,self).__init__()
ds = getDS(pathImg)
self.pathImg = ds.GetFileList()[0] if isinstance(pathImg, gdal.Dataset) else pathImg
self.timeSeries = timeSeries
self.nb, self.nl, self.ns, self.crs, px_x, px_y = getSpatialPropertiesFromDataset(ds)
self.sensor = SensorInstrument(ds)
self.date = parseDateFromDataSet(ds)
assert self.date is not None, 'Unable to find acquisition date of {}'.format(pathImg)
from timeseriesviewer.dateparser import DOYfromDatetime64
self.doy = DOYfromDatetime64(self.date)
gt = ds.GetGeoTransform()
UL = QgsPoint(*pixel2coord(gt, 0, 0))
LR = QgsPoint(*pixel2coord(gt, self.ns, self.nl))
from timeseriesviewer.main import SpatialExtent
self._spatialExtent = SpatialExtent(self.crs, UL, LR)
self.srs_wkt = str(self.crs.toWkt())
def rank(self):
return self.timeSeries.index(self)
def setVisibility(self, b):
old = self.mVisibility
self.mVisibility = b
if old != self.mVisibility:
self.sigVisibilityChanged.emit(b)
def isVisible(self):
return self.mVisibility
def getDate(self):
return np.datetime64(self.date)
def getSpatialReference(self):
return self.crs
return self._spatialExtent
def __repr__(self):
return 'TS Datum {} {}'.format(self.date, str(self.sensor))
def __eq__(self, other):
return self.date == other.date and self.sensor.id() == other.sensor.id()
def __lt__(self, other):
if self.date < other.date:
return True

benjamin.jakimow@geo.hu-berlin.de
committed
elif self.date > other.date:
return False
return self.sensor.id() < other.sensor.id()
def __hash__(self):
return hash((self.date,self.sensor.id()))
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
class TimeSeriesTableView(QTableView):
def __init__(self, parent=None):
super(TimeSeriesTableView, self).__init__(parent)
def contextMenuEvent(self, event):
menu = QMenu(self)
menu.addAction('Check selected observation')
menu.addAction('Uncheck selected observation')
menu.popup(QCursor.pos())
def selectSelectedObservations(b):
assert isinstance(b, bool)
from timeseriesviewer.ui.docks import TsvDockWidgetBase
from timeseriesviewer.utils import loadUi
class TimeSeriesDockUI(TsvDockWidgetBase, loadUi('timeseriesdock.ui')):
def __init__(self, parent=None):
super(TimeSeriesDockUI, self).__init__(parent)
self.setupUi(self)
self.btnAddTSD.setDefaultAction(parent.actionAddTSD)
self.btnRemoveTSD.setDefaultAction(parent.actionRemoveTSD)
self.btnLoadTS.setDefaultAction(parent.actionLoadTS)
self.btnSaveTS.setDefaultAction(parent.actionSaveTS)
self.btnClearTS.setDefaultAction(parent.actionClearTS)
self.progressBar.setMinimum(0)
self.setProgressInfo(0,100, 'Add images to fill time series')
self.progressBar.setValue(0)
self.progressInfo.setText(None)
self.frameFilters.setVisible(False)
self.connectTimeSeries(None)
def setStatus(self):
from timeseriesviewer.timeseries import TimeSeries
if isinstance(self.TS, TimeSeries):
ndates = len(self.TS)
nsensors = len(set([tsd.sensor for tsd in self.TS]))
msg = '{} scene(s) from {} sensor(s)'.format(ndates, nsensors)
if ndates > 1:
msg += ', {} to {}'.format(str(self.TS[0].date), str(self.TS[-1].date))
self.progressInfo.setText(msg)
def setProgressInfo(self, nDone, nMax, message=None):
if self.progressBar.maximum() != nMax:
self.progressBar.setMaximum(nMax)
self.progressBar.setValue(nDone)
self.progressInfo.setText(message)
QgsApplication.processEvents()
if nDone == nMax:
QTimer.singleShot(3000, lambda: self.setStatus())
def onSelectionChanged(self, *args):
self.btnRemoveTSD.setEnabled(self.SM is not None and len(self.SM.selectedRows()) > 0)
def selectedTimeSeriesDates(self):
if self.SM is not None:
return [self.TSM.data(idx, Qt.UserRole) for idx in self.SM.selectedRows()]
return []
def connectTimeSeries(self, TS):
from timeseriesviewer.timeseries import TimeSeries
self.TS = TS
self.TSM = None
self.SM = None
self.timeSeriesInitialized = False
if isinstance(TS, TimeSeries):
from timeseriesviewer.timeseries import TimeSeriesTableModel
self.TSM = TimeSeriesTableModel(self.TS)
self.tableView_TimeSeries.setModel(self.TSM)
self.SM = QItemSelectionModel(self.TSM)
self.tableView_TimeSeries.setSelectionModel(self.SM)
self.SM.selectionChanged.connect(self.onSelectionChanged)
self.tableView_TimeSeries.horizontalHeader().setResizeMode(QHeaderView.ResizeToContents)
TS.sigLoadingProgress.connect(self.setProgressInfo)
self.onSelectionChanged()
sigTimeSeriesDatesAdded = pyqtSignal(list)
sigTimeSeriesDatesRemoved = pyqtSignal(list)
sigLoadingProgress = pyqtSignal(int, int, str)
sigSensorAdded = pyqtSignal(SensorInstrument)
sigSensorRemoved = pyqtSignal(SensorInstrument)
sigRuntimeStats = pyqtSignal(dict)
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
def __init__(self, imageFiles=None, maskFiles=None):
QObject.__init__(self)
#define signals
#fire when a new TSD is added
#self.data = collections.OrderedDict()
self.data = list()
self.shape = None
self.Sensors = collections.OrderedDict()
self.Pool = None
if imageFiles is not None:
self.addFiles(imageFiles)
if maskFiles is not None:
self.addMasks(maskFiles)
_sep = ';'
images = []
masks = []
with open(path, 'r') as f:
lines = f.readlines()
for l in lines:
if re.match('^[ ]*[;#&]', l):
continue
parts = re.split('[\n'+TimeSeries._sep+']', l)
parts = [p for p in parts if p != '']
images.append(parts[0])
if len(parts) > 1:
masks.append(parts[1])
if n_max:
n_max = min([len(images), n_max])
self.addFiles(images[0:n_max])
else:
self.addFiles(images)
#self.addMasks(masks)
def saveToFile(self, path):
if path is None or len(path) == 0:
return
lines = []
lines.append('#Time series definition file: {}'.format(np.datetime64('now').astype(str)))
lines.append('#<image path>[;<mask path>]')
line = TSD.pathImg
lines.append(line)
lines = [l+'\n' for l in lines]
print('Write {}'.format(path))
with open(path, 'w') as f:
f.writelines(lines)

benjamin.jakimow@geo.hu-berlin.de
committed
def getPixelSizes(self):
r = []
for sensor in self.Sensors.keys():
r.append((QgsRectangle(sensor.px_size_x, sensor.px_size_y)))
return r
return None
def getMaxSpatialExtent(self, crs=None):
if len(self.data) == 0:
return None
extent = self.data[0].spatialExtent()
if len(self.data) > 1:
for TSD in self.data[1:]:
extent.combineExtentWith(TSD.spatialExtent())

benjamin.jakimow@geo.hu-berlin.de
committed
def tsdFromPath(self, path):
for tsd in self.data:
if tsd.pathImg == path:
return tsd
return False
def getObservationDates(self):
return [tsd.getDate() for tsd in self.data]

benjamin.jakimow@geo.hu-berlin.de
committed
def getTSD(self, pathOfInterest):
for tsd in self.data:
if tsd.pathImg == pathOfInterest:
return tsd
return None
def getTSDs(self, dateOfInterest=None, sensorOfInterest=None):

benjamin.jakimow@geo.hu-berlin.de
committed
tsds = self.data[:]
if dateOfInterest:

benjamin.jakimow@geo.hu-berlin.de
committed
tsds = [tsd for tsd in tsds if tsd.getDate() == dateOfInterest]
if sensorOfInterest:
tsds = [tsd for tsd in tsds if tsd.sensor == sensorOfInterest]
self.removeDates(self[:])
assert type(TSD) is TimeSeriesDatum
self.data.remove(TSD)
TSD.timeSeries = None
removed.append(TSD)
self.Sensors[S].remove(TSD)
if len(self.Sensors[S]) == 0:
self.Sensors.pop(S)
self.sigSensorRemoved.emit(S)
self.sigTimeSeriesDatesRemoved.emit(removed)
def addTimeSeriesDates(self, timeSeriesDates):
assert isinstance(timeSeriesDates, list)
added = list()
for TSD in timeSeriesDates:
try:
sensorAdded = False
existingSensors = list(self.Sensors.keys())
if TSD.sensor not in existingSensors:
self.Sensors[TSD.sensor] = list()
sensorAdded = True
else:
TSD.sensor = existingSensors[existingSensors.index(TSD.sensor)]
if TSD in self.data:
six.print_('Time series date-time already added ({} {}). \nPlease use VRTs to mosaic images with same acquisition date-time.'.format(str(TSD), TSD.pathImg), file=sys.stderr)
else:
self.Sensors[TSD.sensor].append(TSD)
#insert sorted
bisect.insort(self.data, TSD)
TSD.timeSeries = self
TSD.sigRemoveMe.connect(lambda : self.removeDates([TSD]))
added.append(TSD)
if sensorAdded:
self.sigSensorAdded.emit(TSD.sensor)
except:
exc_type, exc_value, exc_traceback = sys.exc_info()
traceback.print_exception(exc_type, exc_value, exc_traceback, limit=2)
six.print_('Unable to add {}'.format(file), file=sys.stderr)
pass
if len(added) > 0:
self.sigTimeSeriesDatesAdded.emit(added)
def addFiles(self, files):
assert isinstance(files, list)
files = [f for f in files if f is not None]
nMax = len(files)
nDone = 0
self.sigLoadingProgress.emit(0,nMax, 'Start loading {} files...'.format(nMax))
t0 = np.datetime64('now')
tsd = TimeSeriesDatum.createFromPath(file)
if tsd is None:
msg = 'Unable to add: {}'.format(os.path.basename(file))
logger.error(msg)
self.addTimeSeriesDates([tsd])
msg = 'Added {}'.format(os.path.basename(file))
self.sigRuntimeStats.emit({'dt_addTSD':np.datetime64('now')-t0})
nDone += 1
self.sigLoadingProgress.emit(nDone, nMax, msg)
def __len__(self):
return len(self.data)
def __iter__(self):
return iter(self.data)
def __getitem__(self, slice):
return self.data[slice]
def __delitem__(self, slice):
self.removeDates(slice)
def __contains__(self, item):
return item in self.data
def __repr__(self):
info = []
info.append('TimeSeries:')
l = len(self)
info.append(' Scenes: {}'.format(l))
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
class TimeSeriesTableModel(QAbstractTableModel):
columnames = ['date', 'sensor', 'ns', 'nl', 'nb', 'image']
def __init__(self, TS, parent=None, *args):
super(TimeSeriesTableModel, self).__init__()
assert isinstance(TS, TimeSeries)
self.TS = TS
self.sensors = set()
self.TS.sigTimeSeriesDatesRemoved.connect(self.removeTSDs)
self.TS.sigTimeSeriesDatesAdded.connect(self.addTSDs)
self.items = []
self.sortColumnIndex = 0
self.sortOrder = Qt.AscendingOrder
self.addTSDs([tsd for tsd in self.TS])
def removeTSDs(self, tsds):
#self.TS.removeDates(tsds)
for tsd in tsds:
if tsd in self.TS:
#remove from TimeSeries first.
self.TS.removeDates([tsd])
elif tsd in self.items:
idx = self.getIndexFromDate(tsd)
self.removeRows(idx.row(), 1)
#self.sort(self.sortColumnIndex, self.sortOrder)
def tsdChanged(self, tsd):
idx = self.getIndexFromDate(tsd)
self.dataChanged.emit(idx, idx)
def addTSDs(self, tsds):
self.items.extend(tsds)
self.sort(self.sortColumnIndex, self.sortOrder)
for tsd in tsds:
assert isinstance(tsd, TimeSeriesDatum)
tsd.sigVisibilityChanged.connect(lambda: self.tsdChanged(tsd))
for sensor in set([tsd.sensor for tsd in tsds]):
if sensor not in self.sensors:
self.sensors.add(sensor)
sensor.sigNameChanged.connect(lambda: self.reset())
def sort(self, col, order):
if self.rowCount() == 0:
return
self.layoutAboutToBeChanged.emit()
colName = self.columnames[col]
r = order != Qt.AscendingOrder
if colName in ['date','ns','nl','sensor']:
self.items.sort(key = lambda d:d.__dict__[colName], reverse=r)
self.layoutChanged.emit()
s = ""
def rowCount(self, parent = QModelIndex()):
return len(self.items)
def removeRows(self, row, count , parent=QModelIndex()):
self.beginRemoveRows(parent, row, row+count-1)
toRemove = self.items[row:row+count]
for tsd in toRemove:
self.items.remove(tsd)
self.endRemoveRows()
def getIndexFromDate(self, tsd):
return self.createIndex(self.items.index(tsd),0)
def getDateFromIndex(self, index):
if index.isValid():
return self.items[index.row()]
return None
def getTimeSeriesDatumFromIndex(self, index):
if index.isValid():
i = index.row()
if i >= 0 and i < len(self.items):
return self.items[i]
return None
def columnCount(self, parent = QModelIndex()):
return len(self.columnames)
def data(self, index, role = Qt.DisplayRole):
if role is None or not index.isValid():
return None
value = None
columnName = self.columnames[index.column()]
TSD = self.getTimeSeriesDatumFromIndex(index)
keys = list(TSD.__dict__.keys())
if role == Qt.DisplayRole or role == Qt.ToolTipRole:
if columnName == 'name':
value = os.path.basename(TSD.pathImg)
elif columnName == 'sensor':
if role == Qt.ToolTipRole:
value = TSD.sensor.getDescription()
else:
value = TSD.sensor.name()
elif columnName == 'date':
value = '{}'.format(TSD.date)
elif columnName == 'image':
value = TSD.pathImg
elif columnName in keys:
value = TSD.__dict__[columnName]
else:
s = ""
elif role == Qt.CheckStateRole:
if columnName == 'date':
value = Qt.Checked if TSD.isVisible() else Qt.Unchecked
elif role == Qt.BackgroundColorRole:
value = None
elif role == Qt.UserRole:
value = TSD
return value
def setData(self, index, value, role=None):
if role is None or not index.isValid():
return None
if role is Qt.UserRole:
s = ""
columnName = self.columnames[index.column()]
TSD = self.getTimeSeriesDatumFromIndex(index)
if columnName == 'date' and role == Qt.CheckStateRole:
TSD.setVisibility(value != Qt.Unchecked)
return True
else:
return False
return False
def flags(self, index):
if index.isValid():
columnName = self.columnames[index.column()]
flags = Qt.ItemIsEnabled | Qt.ItemIsSelectable
if columnName == 'date': #allow check state
flags = flags | Qt.ItemIsUserCheckable
return flags
#return item.qt_flags(index.column())
return None
def headerData(self, col, orientation, role):
if Qt is None:
return None
if orientation == Qt.Horizontal and role == Qt.DisplayRole:
return self.columnames[col]
elif orientation == Qt.Vertical and role == Qt.DisplayRole:
return col
return None
def getSpatialPropertiesFromDataset(ds):
assert isinstance(ds, gdal.Dataset)
nb = ds.RasterCount
nl = ds.RasterYSize
ns = ds.RasterXSize
proj = ds.GetGeoTransform()
px_x = float(abs(proj[1]))
px_y = float(abs(proj[5]))
crs = QgsCoordinateReferenceSystem(ds.GetProjection())
return nb, nl, ns, crs, px_x, px_y
def parseWavelengthFromDataSet(ds):
assert isinstance(ds, gdal.Dataset)
wl = None
wlu = None
#see http://www.harrisgeospatial.com/docs/ENVIHeaderFiles.html for supported wavelength units
regWLkey = re.compile('.*wavelength[_ ]*$', re.I)
regWLUkey = re.compile('.*wavelength[_ ]*units?$', re.I)
regNumeric = re.compile(r"([-+]?\d*\.\d+|[-+]?\d+)", re.I)
regWLU = re.compile('((micro|nano|centi)meters)|(um|nm|mm|cm|m|GHz|MHz)', re.I)
for domain in ds.GetMetadataDomainList():
md = ds.GetMetadata_Dict(domain)
for key, value in md.items():
if wl is None and regWLkey.search(key):
numbers = regNumeric.findall(value)
if len(numbers) == ds.RasterCount:
wl = [float(n) for n in numbers]
if wlu is None and regWLUkey.search(key):
match = regWLU.search(value)
if match:
names = ['nanometers', 'micrometers', 'millimeters', 'centimeters', 'decimeters']
si = ['nm', 'um', 'mm', 'cm', 'dm']
if wlu in names:
wlu = si[names.index(wlu)]
return wl, wlu
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
def parseWavelength(lyr):
wl = None
wlu = None
assert isinstance(lyr, QgsRasterLayer)
md = [l.split('=') for l in str(lyr.metadata()).splitlines() if 'wavelength' in l.lower()]
#see http://www.harrisgeospatial.com/docs/ENVIHeaderFiles.html for supported wavelength units
regWLU = re.compile('((micro|nano|centi)meters)|(um|nm|mm|cm|m|GHz|MHz)')
for kv in md:
key, value = kv
key = key.lower()
if key == 'center wavelength':
tmp = re.findall('\d*\.\d+|\d+', value) #find floats
if len(tmp) == 0:
tmp = re.findall('\d+', value) #find integers
if len(tmp) == lyr.bandCount():
wl = [float(w) for w in tmp]
if key == 'wavelength units':
match = regWLU.search(value)
if match:
wlu = match.group()
names = ['nanometers','micrometers','millimeters','centimeters','decimenters']
si = ['nm','um','mm','cm','dm']
if wlu in names:
wlu = si[names.index(wlu)]
return wl, wlu
if __name__ == '__main__':

benjamin.jakimow@geo.hu-berlin.de
committed
print convertMetricUnit(100, 'cm', 'm')
print convertMetricUnit(1, 'm', 'um')