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

67 statements  

1# -*- coding: utf-8 -*- 

2 

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. 

26 

27__author__ = "Daniel Scheffler" 

28 

29import time 

30import os 

31 

32import numpy as np 

33from pandas import DataFrame 

34from osgeo import gdal, gdal_array 

35from pyproj import CRS 

36 

37from ...dtypes.conversion import dTypeDic_NumPy2GDALcompatible 

38 

39 

40def get_GDAL_ds_inmem(array, gt=None, prj=None, nodata=None): 

41 """Convert a numpy array into a GDAL dataset. 

42 

43 NOTE: Possibly the data type has to be automatically changed in order ensure GDAL compatibility! 

44 

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 

52 

53 if len(array.shape) == 3: 

54 array = np.rollaxis(array, 2) # rows,cols,bands => bands,rows,cols 

55 

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))]) 

59 

60 ds = gdal_array.OpenArray(array) # uses interleave='band' by default 

61 

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") 

70 

71 ds.SetProjection(prj) 

72 

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) 

84 

85 band.SetNoDataValue(nodata) 

86 except TypeError: 

87 raise TypeError(type(nodata), 'TypeError while trying to set NoDataValue to %s. ' % nodata) 

88 del band 

89 

90 ds.FlushCache() # Write to disk. 

91 return ds 

92 

93 

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 

109 

110 

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() 

116 

117 def update_same_gdalRefs(sRs): 

118 return [sR for sR in sRs if sR in globals() and globals()[sR] is not None] 

119 

120 while same_gdalRefs != [] or os.path.exists(lockfile): 

121 if os.path.exists(lockfile): 

122 continue 

123 

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) 

132 

133 raise TimeoutError('The file %s is permanently used by another variable.' % path_file) 

134 

135 same_gdalRefs = update_same_gdalRefs(same_gdalRefs)