diff --git a/timeseriesviewer/ui/icons/icon.png b/timeseriesviewer/ui/icons/icon.png index c0d802915cae1e3eb14b24e988a0f7833401f023..2b55fc08c55705329159aceaf26b3cf3d81f3207 100644 Binary files a/timeseriesviewer/ui/icons/icon.png and b/timeseriesviewer/ui/icons/icon.png differ diff --git a/timeseriesviewer/ui/icons/icon.svg b/timeseriesviewer/ui/icons/icon.svg new file mode 100644 index 0000000000000000000000000000000000000000..43ee2e2e8612b5f9361504310fc15210a343ac5f --- /dev/null +++ b/timeseriesviewer/ui/icons/icon.svg @@ -0,0 +1,204 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + height="19.500002" + width="19.500002" + id="svg2" + version="1.1" + inkscape:version="0.91 r13725" + sodipodi:docname="icon.svg" + inkscape:export-filename="/Users/benjamin.jakimow/Repositories/QGIS_Plugins/hub-timeseriesviewer/timeseriesviewer/ui/icons/icon.png" + inkscape:export-xdpi="119.99998" + inkscape:export-ydpi="119.99998"> + <metadata + id="metadata10"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + <dc:title></dc:title> + </cc:Work> + </rdf:RDF> + </metadata> + <defs + id="defs8"> + <inkscape:perspective + id="perspective3486" + inkscape:persp3d-origin="16 : 10.666667 : 1" + inkscape:vp_z="32 : 16 : 1" + inkscape:vp_y="0 : 1000 : 0" + inkscape:vp_x="0 : 16 : 1" + sodipodi:type="inkscape:persp3d" /> + <inkscape:perspective + sodipodi:type="inkscape:persp3d" + inkscape:vp_x="0 : 0.5 : 1" + inkscape:vp_y="0 : 1000 : 0" + inkscape:vp_z="1 : 0.5 : 1" + inkscape:persp3d-origin="0.5 : 0.33333333 : 1" + id="perspective3496" /> + <inkscape:perspective + sodipodi:type="inkscape:persp3d" + inkscape:vp_x="0 : 0.5 : 1" + inkscape:vp_y="0 : 1000 : 0" + inkscape:vp_z="1 : 0.5 : 1" + inkscape:persp3d-origin="0.5 : 0.33333333 : 1" + id="perspective3600" /> + <inkscape:perspective + sodipodi:type="inkscape:persp3d" + inkscape:vp_x="0 : 0.5 : 1" + inkscape:vp_y="0 : 1000 : 0" + inkscape:vp_z="1 : 0.5 : 1" + inkscape:persp3d-origin="0.5 : 0.33333333 : 1" + id="perspective7871" /> + <inkscape:perspective + sodipodi:type="inkscape:persp3d" + inkscape:vp_x="0 : 0.5 : 1" + inkscape:vp_y="0 : 1000 : 0" + inkscape:vp_z="1 : 0.5 : 1" + inkscape:persp3d-origin="0.5 : 0.33333333 : 1" + id="perspective8710" /> + <inkscape:perspective + sodipodi:type="inkscape:persp3d" + inkscape:vp_x="0 : 0.5 : 1" + inkscape:vp_y="0 : 1000 : 0" + inkscape:vp_z="1 : 0.5 : 1" + inkscape:persp3d-origin="0.5 : 0.33333333 : 1" + id="perspective9811" /> + <inkscape:perspective + sodipodi:type="inkscape:persp3d" + inkscape:vp_x="0 : 0.5 : 1" + inkscape:vp_y="0 : 1000 : 0" + inkscape:vp_z="1 : 0.5 : 1" + inkscape:persp3d-origin="0.5 : 0.33333333 : 1" + id="perspective4762" /> + <clipPath + id="clipPath26"> + <path + d="M 2362.38,3289.96 3754.11,6.80078 3641.8,151.695 2640.37,2534.35 3412.13,445.691 3334.48,520.086 2556,2631.38 3172.66,695.02 l -18.02,-0.004 -48.52,39.734 -622.04,1973.96 477.78,-1855.796 -59.5,44.93 -489.59,1907.296 353.27,-1804.34 -55.73,34.08 -355.81,1835.76 209.8,-1746.44 -51.89,28.52 -207.45,1766.52 72.29,-1692.23 -53.51,24.09 -66.25,1704.29 -86.87,-1635.36 -48.91,16.08 94.6,1658.46 -257.22,-1604.98 -45.65,12.57 259.68,1627.16 -445.14,-1576.09 -50.91,8.91 455.88,1590.29 -656.68,-1555.14 -53.13,2.14 666.01,1572.08 -928.64,-1561.46 -47.53,1.93 1056.19,1777.98 193.21,0 z" + inkscape:connector-curvature="0" + id="path28" /> + </clipPath> + </defs> + <sodipodi:namedview + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1" + objecttolerance="10" + gridtolerance="10" + guidetolerance="10" + inkscape:pageopacity="0" + inkscape:pageshadow="2" + inkscape:window-width="1276" + inkscape:window-height="756" + id="namedview6" + showgrid="false" + inkscape:zoom="6.6775233" + inkscape:cx="5.9280981" + inkscape:cy="7.5000031" + inkscape:window-x="4" + inkscape:window-y="0" + inkscape:window-maximized="1" + inkscape:current-layer="svg2" + fit-margin-top="0" + fit-margin-left="0" + fit-margin-right="0" + fit-margin-bottom="0" /> + <rect + style="fill:none;stroke:none" + id="rect6554" + width="19.499998" + height="19.499998" + x="0" + y="0" /> + <rect + style="fill:#6e97c4;fill-opacity:1;fill-rule:nonzero;stroke:none" + id="rect6419" + width="6.499999" + height="6.499999" + x="6.5" + y="0" /> + <rect + style="display:inline;fill:#253e5b;fill-opacity:1;fill-rule:nonzero;stroke:none" + id="rect6419-6" + width="6.499999" + height="6.499999" + x="13.000004" + y="0" /> + <rect + style="display:inline;fill:#253e5b;fill-opacity:1;fill-rule:nonzero;stroke:none" + id="rect6419-6-9" + width="6.499999" + height="6.499999" + x="6.5" + y="6.5" + inkscape:transform-center-x="-3.2499991" + inkscape:transform-center-y="-4.3333322" /> + <rect + style="display:inline;fill:#6d97c4;fill-opacity:1;fill-rule:nonzero;stroke:none" + id="rect6419-0" + width="6.499999" + height="6.499999" + x="13.000004" + y="6.5" /> + <rect + style="display:inline;fill:#253e5b;fill-opacity:1;fill-rule:nonzero;stroke:none" + id="rect6419-6-7" + width="6.499999" + height="6.499999" + x="0" + y="0" /> + <rect + style="display:inline;fill:#6d97c4;fill-opacity:1;fill-rule:nonzero;stroke:none" + id="rect6419-3" + width="6.499999" + height="6.499999" + x="0" + y="6.5" /> + <rect + style="display:inline;fill:#6d97c4;fill-opacity:1;fill-rule:nonzero;stroke:none" + id="rect6419-5" + width="6.499999" + height="6.499999" + x="6.5" + y="13.000004" /> + <rect + style="display:inline;fill:#253e5b;fill-opacity:1;fill-rule:nonzero;stroke:none" + id="rect6419-6-6" + width="6.499999" + height="6.499999" + x="0" + y="13.000004" /> + <rect + y="13.000004" + x="13.000004" + height="6.499999" + width="6.499999" + id="rect8225" + style="display:inline;fill:#253e5b;fill-opacity:1;fill-rule:nonzero;stroke:none" /> + <g + id="g5821" + transform="translate(0.00243209,-0.24814311)" + style="fill:none;stroke:#ffffff;stroke-opacity:1"> + <ellipse + ry="6.8272738" + rx="7.0345278" + cy="9.75" + cx="9.75" + id="path8227" + style="opacity:1;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0.89999998;stroke-opacity:1" /> + <path + sodipodi:nodetypes="ccc" + inkscape:connector-curvature="0" + id="path8235" + d="m 12.364602,11.360681 -2.331606,0 -2.901555,-3.212435" + style="fill:none;fill-rule:evenodd;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /> + </g> +</svg> diff --git a/timeseriesviewer/virtualrasters.py b/timeseriesviewer/virtualrasters.py index d59059e823d06f7a77bf0140f66d150e52fb365a..3dfb050f99195c50c4b9692d7098ecc23d5d9940 100644 --- a/timeseriesviewer/virtualrasters.py +++ b/timeseriesviewer/virtualrasters.py @@ -21,7 +21,20 @@ class VirtualBand(object): def addSourceBand(self, path, bandIndex): self.sources.append(VirtualBandInputSource(path, bandIndex)) + def removeSourceBand(self, bandOrIndex): + """ + Removes a virtual band + :param bandOrIndex: int | VirtualBand + :return: The VirtualBand that was removed + """ + if not isinstance(bandOrIndex, VirtualBand): + bandOrIndex = self.sources[bandOrIndex] + return self.sources.remove(bandOrIndex) + def sourceFiles(self): + """ + :return: list of file-paths to all source files + """ files = set([inputSource.path for inputSource in self.sources]) return sorted(list(files)) @@ -38,19 +51,85 @@ class VirtualRasterBuilder(object): self.vBands = [] self.vMetadata = dict() + def addVirtualBand(self, virtualBand): + """ + Adds a virtual band + :param virtualBand: the VirtualBand to be added + :return: VirtualBand + """ assert isinstance(virtualBand, VirtualBand) self.vBands.append(virtualBand) + return self[-1] + def insertVirtualBand(self, i, virtualBand): + """ + Inserts a VirtualBand + :param i: the insert position + :param virtualBand: the VirtualBand to be inserted + :return: the VirtualBand + """ assert isinstance(virtualBand, VirtualBand) self.vBands.insert(i, virtualBand) + return self[i] + + + + def removeVirtualBands(self, bandsOrIndices): + assert isinstance(bandsOrIndices, list) + to_remove = [] + for bandOrIndex in bandsOrIndices: + if not isinstance(bandOrIndex, VirtualBand): + bandOrIndex = self.vBands[bandOrIndex] + to_remove.append(bandOrIndex) + + for band in to_remove: + self.vBands.remove(band) + return to_remove + + + def removeVirtualBand(self, bandOrIndex): + r = self.removeVirtualBands([bandOrIndex]) + return r[0] def addFilesAsMosaic(self, files): - pass + """ + Shortcut to mosaic all input files. All bands will maintain their band position in the virtual file. + :param files: [list-of-file-paths] + """ + + for file in files: + ds = gdal.Open(file) + assert isinstance(ds, gdal.Dataset) + nb = ds.RasterCount + for b in range(nb): + if b+1 < len(self): + #add new virtual band + self.addVirtualBand(VirtualBand()) + vBand = self[b] + assert isinstance(vBand, VirtualBand) + vBand.addSourceBand(file, b) + return self def addFilesAsStack(self, files): - pass + """ + Shortcut to stack all input files, i.e. each band of an input file will be a new virtual band. + Bands in the virtual file will be ordered as file1-band1, file1-band n, file2-band1, file2-band,... + :param files: [list-of-file-paths] + :return: self + """ + for file in files: + ds = gdal.Open(file) + assert isinstance(ds, gdal.Dataset) + nb = ds.RasterCount + ds = None + for b in range(nb): + #each new band is a new virtual band + vBand = self.addVirtualBand(VirtualBand()) + assert isinstance(vBand, VirtualBand) + vBand.addSourceBand(file, b) + return self def sourceFiles(self): files = set() @@ -59,7 +138,32 @@ class VirtualRasterBuilder(object): files.update(set(vBand.sourceFiles())) return sorted(list(files)) - def saveVRT(self, pathVRT): + def saveVRT(self, pathVRT, **kwds): + """ + :param pathVRT: path to VRT that is created + :param options --- can be be an array of strings, a string or let empty and filled from other keywords.. + :param resolution --- 'highest', 'lowest', 'average', 'user'. + :param outputBounds --- output bounds as (minX, minY, maxX, maxY) in target SRS. + :param xRes, yRes --- output resolution in target SRS. + :param targetAlignedPixels --- whether to force output bounds to be multiple of output resolution. + :param bandList --- array of band numbers (index start at 1). + :param addAlpha --- whether to add an alpha mask band to the VRT when the source raster have none. + :param resampleAlg --- resampling mode. + :param outputSRS --- assigned output SRS. + :param allowProjectionDifference --- whether to accept input datasets have not the same projection. Note: they will *not* be reprojected. + :param srcNodata --- source nodata value(s). + :param callback --- callback method. + :param callback_data --- user data for callback. + :return: gdal.DataSet(pathVRT) + """ + + _kwds = dict() + supported = ['options','resolution','outputBounds','xRes','yRes','targetAlignedPixels','addAlpha','resampleAlg', + 'outputSRS','allowProjectionDifference','srcNodata','VRTNodata','hideNodata','callback', 'callback_data'] + for k in kwds.keys(): + if k in supported: + _kwds[k] = kwds[k] + dn = os.path.dirname(pathVRT) if not os.path.isdir(dn): @@ -74,8 +178,7 @@ class VirtualRasterBuilder(object): if noData and srcNodata is None: srcNodata = noData - vro = gdal.BuildVRTOptions(separate=True, - srcNodata=srcNodata) + vro = gdal.BuildVRTOptions(separate=True, **_kwds) #1. build a temporary VRT that described the spatial shifts of all input sources gdal.BuildVRT(pathVRT, srcFiles, options=vro) dsVRTDst = gdal.Open(pathVRT) @@ -142,6 +245,22 @@ class VirtualRasterBuilder(object): info.append(str(vBand)) return '\n'.join(info) + def __len__(self): + return len(self.vBands) + + def __getitem__(self, slice): + return self.vBands[slice] + + def __delitem__(self, slice): + self.removeVirtualBands(self[slice]) + + def __contains__(self, item): + return item in self.vBands + + + def __iter__(self): + return iter(self.mClasses) + def createVirtualBandMosaic(bandFiles, pathVRT): drv = gdal.GetDriverByName('VRT') @@ -175,7 +294,7 @@ def createVirtualBandStack(bandFiles, pathVRT): vrtOptions = gdal.BuildVRTOptions( # here we can use the options known from http://www.gdal.org/gdalbuildvrt.html - separate=True + separate=True, ) vrtDS = gdal.BuildVRT(pathVRT, bandFiles, options=vrtOptions) vrtDS.FlushCache() @@ -193,102 +312,3 @@ def createVirtualBandStack(bandFiles, pathVRT): return vrtDS - -def groupRapidEyeTiles(dirIn, dirOut): - """ - - :param dirIn: - :param dirOut: - :return: - """ - - files = file_search(dirIn, '*_RE*_3A_*2.tif', recursive=True) - - if not os.path.exists(dirOut): - os.mkdir(dirOut) - - sources = dict() - for file in files: - if not file.endswith('.tif'): - continue - dn = os.path.dirname(file) - bn = os.path.basename(file) - print(bn) - id, date, sensor, product, _ = tuple(bn.split('_')) - - if not date in sources.keys(): - sources[date] = [] - sources[date].append(file) - for date, files in sources.items(): - pathVRT = os.path.join(dirOut, 're_{}.vrt'.format(date)) - createVirtualBandMosaic(files, pathVRT) - -def groupCBERS(dirIn, dirOut): - files = file_search(dirIn, 'CBERS*.tif', recursive=True) - - if not os.path.exists(dirOut): - os.mkdir(dirOut) - - CONTAINERS = dict() - for file in files: - dn = os.path.dirname(file) - bn = os.path.basename(file) - #basenames like CBERS_4_MUX_20150603_167_107_L4_BAND5_GRID_SURFACE.tif - splitted = bn.split('_') - id = '_'.join(splitted[:4]) - bandName = splitted[7] - - if id not in CONTAINERS.keys(): - CONTAINERS[id] = dict() - - bandSources = CONTAINERS[id] - if bandName not in bandSources.keys(): - bandSources[bandName] = list() - bandSources[bandName].append(file) - - #mosaic all scenes of same date - # and stack all bands related to the same channel - for id, bandSources in CONTAINERS.items(): - - pathVRT = id + '.vrt' - pathVRT = os.path.join(dirOut, pathVRT) - V = VirtualRasterBuilder() - - #vrt = createVirtualBandStack(bandSources, pathVRT) - #add bands in sorted order - for bandName in sorted(bandSources.keys()): - vBandSources = bandSources[bandName] - VB = VirtualBand(name=bandName) - for path in vBandSources: - VB.addSourceBand(path, 0) #it's always one band only - - V.addVirtualBand(VB) - #print(V) - V.saveVRT(pathVRT) - s = "" - #add ISO time stamp - - pass - -def groupLandsat(dirIn, dirOut): - - pass - - -if __name__ == '__main__': - if True: - dirIn = r'H:\CBERS\hugo\Download20170523' - dirOut = r'H:\CBERS\VRTs' - - groupCBERS(dirIn, dirOut) - exit(0) - - if True: - dirIn = r'H:\CBERS\hugo\Download20170523' - dirOut = r'H:\CBERS\VRTs' - groupCBERS(dirIn, dirOut) - - if True: - dirIn = r'H:\RapidEye\3A' - dirOut = r'H:\RapidEye\VRTs' - groupRapidEyeTiles(dirIn, dirOut) \ No newline at end of file