Coverage for py_tools_ds/io/raster/gdal.py: 67%
Shortcuts on this page
r m x toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
Shortcuts on this page
r m x toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1# -*- coding: utf-8 -*-
3# py_tools_ds - A collection of geospatial data analysis tools that simplify standard
4# operations when handling geospatial raster and vector data as well as projections.
5#
6# Copyright (C) 2016-2021
7# - Daniel Scheffler (GFZ Potsdam, daniel.scheffler@gfz-potsdam.de)
8# - Helmholtz Centre Potsdam - GFZ German Research Centre for Geosciences Potsdam,
9# Germany (https://www.gfz-potsdam.de/)
10#
11# This software was developed within the context of the GeoMultiSens project funded
12# by the German Federal Ministry of Education and Research
13# (project grant code: 01 IS 14 010 A-C).
14#
15# Licensed under the Apache License, Version 2.0 (the "License");
16# you may not use this file except in compliance with the License.
17# You may obtain a copy of the License at
18#
19# http://www.apache.org/licenses/LICENSE-2.0
20#
21# Unless required by applicable law or agreed to in writing, software
22# distributed under the License is distributed on an "AS IS" BASIS,
23# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
24# See the License for the specific language governing permissions and
25# limitations under the License.
27__author__ = "Daniel Scheffler"
29import time
30import os
32import numpy as np
33from pandas import DataFrame
34from osgeo import gdal, gdal_array
35from pyproj import CRS
37from ...dtypes.conversion import dTypeDic_NumPy2GDALcompatible
40def get_GDAL_ds_inmem(array, gt=None, prj=None, nodata=None):
41 """Convert a numpy array into a GDAL dataset.
43 NOTE: Possibly the data type has to be automatically changed in order ensure GDAL compatibility!
45 :param array: <numpy.ndarray> in the shape (rows, columns, bands)
46 :param gt:
47 :param prj:
48 :param nodata: <int> nodata value to be set (GDAL seems to have issues with non-int nodata values.)
49 :return:
50 """
51 # FIXME does not respect different nodata values for each band
53 if len(array.shape) == 3:
54 array = np.rollaxis(array, 2) # rows,cols,bands => bands,rows,cols
56 # convert data type to GDAL compatible data type
57 if gdal_array.NumericTypeCodeToGDALTypeCode(array.dtype) is None:
58 array = array.astype(dTypeDic_NumPy2GDALcompatible[str(np.dtype(array.dtype))])
60 ds = gdal_array.OpenArray(array) # uses interleave='band' by default
62 if ds is None:
63 raise Exception(gdal.GetLastErrorMsg())
64 if gt:
65 ds.SetGeoTransform(gt)
66 if prj:
67 if int(gdal.__version__[0]) < 3:
68 # noinspection PyTypeChecker
69 prj = CRS(prj).to_wkt(version="WKT1_GDAL")
71 ds.SetProjection(prj)
73 if nodata is not None:
74 for i in range(ds.RasterCount):
75 band = ds.GetRasterBand(i + 1)
76 try:
77 # band.SetNoDataValue does not support numpy data types
78 if isinstance(nodata, np.bool_):
79 nodata = bool(nodata)
80 elif isinstance(nodata, np.integer):
81 nodata = int(nodata)
82 elif isinstance(nodata, np.floating):
83 nodata = float(nodata)
85 band.SetNoDataValue(nodata)
86 except TypeError:
87 raise TypeError(type(nodata), 'TypeError while trying to set NoDataValue to %s. ' % nodata)
88 del band
90 ds.FlushCache() # Write to disk.
91 return ds
94def get_GDAL_driverList():
95 count = gdal.GetDriverCount()
96 df = DataFrame(np.full((count, 5), np.nan), columns=['drvCode', 'drvLongName', 'ext1', 'ext2', 'ext3'])
97 for i in range(count):
98 drv = gdal.GetDriver(i)
99 if drv.GetMetadataItem(gdal.DCAP_RASTER):
100 meta = drv.GetMetadataItem(gdal.DMD_EXTENSIONS)
101 extensions = meta.split() if meta else []
102 df.loc[i] = [drv.GetDescription(),
103 drv.GetMetadataItem(gdal.DMD_LONGNAME),
104 extensions[0] if len(extensions) > 0 else np.nan,
105 extensions[1] if len(extensions) > 1 else np.nan,
106 extensions[2] if len(extensions) > 2 else np.nan]
107 df = df.dropna(how='all')
108 return df
111def wait_if_used(path_file, lockfile, timeout=100, try_kill=0):
112 globs = globals()
113 same_gdalRefs = [k for k, v in globs.items() if
114 isinstance(globs[k], gdal.Dataset) and globs[k].GetDescription() == path_file]
115 t0 = time.time()
117 def update_same_gdalRefs(sRs):
118 return [sR for sR in sRs if sR in globals() and globals()[sR] is not None]
120 while same_gdalRefs != [] or os.path.exists(lockfile):
121 if os.path.exists(lockfile):
122 continue
124 if time.time() - t0 > timeout:
125 if try_kill:
126 for sR in same_gdalRefs:
127 globals()[sR] = None
128 print('had to kill %s' % sR)
129 else:
130 if os.path.exists(lockfile):
131 os.remove(lockfile)
133 raise TimeoutError('The file %s is permanently used by another variable.' % path_file)
135 same_gdalRefs = update_same_gdalRefs(same_gdalRefs)