-
-
Notifications
You must be signed in to change notification settings - Fork 17
/
dem2terrainrgb.py
135 lines (110 loc) · 3.67 KB
/
dem2terrainrgb.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
import subprocess
import os
import shutil
import glob
from PIL import Image
from tqdm import tqdm
class Dem2TerrainRgb(object):
"""
Class for converting DEM file to terrain RGB raster tilesets.
This source code was inspired from the below repository.
https://github.com/syncpoint/terrain-rgb
"""
def __init__(self, dem, dist, tmp, zoom="5-15") -> None:
"""Constructor
Args:
dem (str): DEM file path. The DEM file must be reprojected to EPSG:3857 before converting.
dist (str): Output directory for terrain RGB tiles
tmp (str): Temporary directory for work
zoom (str): Min and Max zoom levels for tiles. Default is 5-15.
"""
self.dem = dem
self.dist = dist
self.tmp = tmp
self.zoom = zoom
def fill_nodata(self):
"""
Fill NO DATA value. Before we rgbify, all of NO DATA values need to be filled.
After this process, you may validate the converted tiff by following command.
$ rio info --indent 2 ./data/rwanda_dem_EPSG3857_10m_without_nodata.tif
Returns:
str: Filled DEM file path
"""
if not os.path.exists(self.tmp):
os.makedirs(self.tmp)
filename = os.path.splitext(os.path.basename(self.dem))[0]
filled_file = f"{self.tmp}/{filename}_without_nodata.tif"
if os.path.exists(filled_file):
os.remove(filled_file)
cmd = f"gdalwarp \
-t_srs EPSG:3857 \
-dstnodata None \
-co TILED=YES \
-co COMPRESS=DEFLATE \
-co BIGTIFF=IF_NEEDED \
{self.dem} \
{filled_file}"
subprocess.check_output(cmd, shell=True)
print(f"filled NODATA value successfully: {filled_file}")
return filled_file
def rgbify(self, filled_dem):
"""
transform the greyscale data into the RGB data. The formula used to calculate the elevation is
height = -10000 + ((R * 256 * 256 + G * 256 + B) * 0.1)
So the base value is -10000 and the interval (precision of the output) is 0.1.
After rgbfying, you can validate by following command.
$ gdallocationinfo -wgs84 ./data/rwanda_dem_EPSG3857_10m_RGB.tif 29.7363 -2.2313
Report:
Location: (8617P,13218L)
Band 1:
Value: 1
Band 2:
Value: 199
Band 3:
Value: 250
(rwanda_terrain)
Args:
filled_dem ([type]): [description]
Returns:
[type]: [description]
"""
filename = os.path.splitext(os.path.basename(self.dem))[0]
rgbified_dem = f"{self.tmp}/{filename}_RGB.tif"
if os.path.exists(rgbified_dem):
os.remove(rgbified_dem)
cmd = f"rio rgbify \
-b -10000 \
-i 0.1 \
{filled_dem} \
{rgbified_dem}"
subprocess.check_output(cmd, shell=True)
print(f"rgbified successfully: {rgbified_dem}")
return rgbified_dem
def gdal2tiles(self, rgbified_dem):
"""Generate tiles as PNG format.
see about gdal2tiles:
https://gdal.org/programs/gdal2tiles.html
Args:
rgbified_dem (str): Rgbified DEM file path
Returns:
str: Output directory path
"""
if os.path.exists(self.dist):
shutil.rmtree(self.dist)
cmd = f"gdal2tiles.py \
--zoom={self.zoom} \
--resampling=near \
--tilesize=512 \
--processes=8 \
--xyz {rgbified_dem} \
{self.dist}"
subprocess.check_output(cmd, shell=True)
print(f"created tileset successfully: {self.dist}")
return self.dist
def png2webp(self, removePNG=False):
files = glob.glob(self.dist + '/**/*.png', recursive=True)
for file in tqdm(files):
img = Image.open(file)
img.save(file.replace('.png','.webp'), "WEBP", lossless=True)
if removePNG:
os.remove(file)