comparison land_cover.py @ 0:828c02027180 draft default tip

planemo upload for repository https://github.com/galaxyecology/tools-ecology/tree/master/tools/earth commit 4cbace8c3a71b7a1638cfd44a21f5d4b84d2fd15
author ecology
date Mon, 21 Oct 2024 16:47:10 +0000
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:828c02027180
1 # Land Cover TE Algorithm Without GEE
2
3 # How to Execute:
4 # - Load the two images (.TIFF) of the rasters
5 # to be processed in the "/data/land_cover/input" folder
6 # - Setting the two filenames in the specific cell of this script (0)
7 # - Run all cells of the script
8 # - Check the script results in the "/data/land_cover/output" folder
9 # - Land Cover Degradation "/data/land_cover/output/lc_dg.tiff"
10 # - Land Cover Transition "/data/land_cover/output/lc_tr.tiff"
11
12 # Librairies import
13 import argparse
14 import json
15 import os
16 import sys
17
18 import matplotlib.pyplot as plt
19
20 import numpy as np
21
22 import rasterio
23 from rasterio.plot import show
24
25 from te_schemas.land_cover import LCLegendNesting
26 from te_schemas.land_cover import LCTransitionDefinitionDeg
27
28 # Methods to manage Rasters
29
30
31 def remap(raster, problem_numbers, alternative_numbers):
32 n_min, n_max = raster.min(), raster.max()
33 replacer = np.arange(n_min, n_max + 1)
34 mask = (problem_numbers >= n_min) & (problem_numbers <= n_max)
35 replacer[problem_numbers[mask] - n_min] = alternative_numbers[mask]
36 raster_replaced = replacer[raster - n_min]
37 return raster_replaced
38
39
40 def saveRaster(dataset, datasetPath, cols, rows, projection, namedataset=None):
41 if namedataset:
42 rasterSet = rasterio.open(datasetPath,
43 'w',
44 driver='GTiff',
45 height=rows,
46 width=cols,
47 count=1,
48 dtype=np.int8,
49 crs=projection,
50 transform=transform, )
51 rasterSet.write(dataset, 1)
52 rasterSet.close()
53 else:
54 rasterSet = rasterio.open(datasetPath,
55 'w',
56 driver='GTiff',
57 height=rows,
58 width=cols,
59 count=1,
60 dtype=np.int8,
61 crs=projection,
62 transform=transform, )
63 rasterSet.write(dataset, 1)
64 rasterSet.set_band_description(1, namedataset)
65 rasterSet.close()
66
67
68 def plot(ndviImage, cmap):
69 src = rasterio.open(ndviImage, 'r')
70 fig, ax = plt.subplots(1, figsize=(12, 12))
71 show(src, cmap=cmap, ax=ax)
72 ax.set_xlabel('Est')
73 ax.set_ylabel('Nord')
74 plt.show()
75
76
77 def plotContour(ndviImage, cmap):
78 src = rasterio.open(ndviImage, 'r')
79 fig, ax = plt.subplots(1, figsize=(12, 12))
80 show(src, cmap=cmap, contour=True, ax=ax)
81 ax.set_xlabel('Est')
82 ax.set_ylabel('Nord')
83 plt.show()
84
85
86 # Setting inputs
87 command_line_args = sys.argv[1:]
88
89
90 parser = argparse.ArgumentParser(description="landcover inputs and outputs")
91 # Add arguments
92 parser.add_argument("--raster_1", help="raster 1")
93 parser.add_argument("--raster_2", help="raster 2")
94 parser.add_argument("--json", help="json")
95
96 args = parser.parse_args(command_line_args)
97
98 # Parse the command line arguments
99
100 # Import data
101
102 path_raster_yi = args.raster_1
103 path_raster_yf = args.raster_2
104 fjson = args.json
105 # Input Rasters
106
107 # Outputs
108 out_dir = os.path.join(os.getcwd(), "data/land_cover/output/")
109 if not os.path.exists(out_dir):
110 os.makedirs(out_dir)
111
112 # Output Rasters
113 path_lc_tr = os.path.join(out_dir, 'lc_tr.tiff')
114 path_lc_bl = os.path.join(out_dir, 'lc_bl.tiff')
115 path_lc_dg = os.path.join(out_dir, 'lc_dg.tiff')
116 path_lc_tg = os.path.join(out_dir, 'lc_tg.tiff')
117 path_change_yf_yi = os.path.join(out_dir, 'change_yf_yi.tiff')
118 path_lc_baseline_esa = os.path.join(out_dir, 'lc_baseline_esa.tiff')
119 path_lc_target_esa = os.path.join(out_dir, 'lc_target_esa.tiff')
120 path_out_img = os.path.join(out_dir, 'stack.tiff')
121
122 # Contours
123 contours_change_yf_yi = os.path.join(out_dir, '/change_yf_yi0.shp')
124
125
126 # Parsing Inputs
127 # Load static inputs
128 # Transition Matrix, ESA Legend, IPCC Legend
129 # Input Raster and Vector Paths
130 params = json.load(open(fjson))
131
132 crs = params.get("crs")
133
134 trans_matrix_val = params.get("trans_matrix")
135 trans_matrix = LCTransitionDefinitionDeg.Schema().load(trans_matrix_val)
136
137 esa_to_custom_nesting = LCLegendNesting.Schema().load(
138 params.get("legend_nesting_esa_to_custom")
139 )
140
141 ipcc_nesting = LCLegendNesting.Schema().load(
142 params.get("legend_nesting_custom_to_ipcc")
143 )
144
145 class_codes = sorted([c.code for c in esa_to_custom_nesting.parent.key])
146 class_positions = [*range(1, len(class_codes) + 1)]
147
148 # Load dynamic inputs
149 # Baseline ESA Raster
150 raster_yi = rasterio.open(path_raster_yi)
151 lc_baseline_esa = raster_yi.read(1)
152 yi_dict_profile = dict(raster_yi.profile)
153
154 for k in yi_dict_profile:
155 print(k.upper(), yi_dict_profile[k])
156
157 # Target ESA Raster
158 raster_yf = rasterio.open(path_raster_yf)
159 lc_target_esa = raster_yf.read(1)
160 yf_dict_profile = dict(raster_yf.profile)
161
162 for k in yf_dict_profile:
163 print(k.upper(), yf_dict_profile[k])
164
165 cols = raster_yi.width
166 rows = raster_yf.height
167 transform = raster_yi.transform
168 projection = raster_yi.crs
169
170 # Setting up output
171 saveRaster(lc_baseline_esa.astype('int8'),
172 path_lc_baseline_esa,
173 cols,
174 rows,
175 projection,
176 "Land_cover_yi")
177
178 saveRaster(lc_target_esa.astype('int8'),
179 path_lc_target_esa,
180 cols,
181 rows,
182 projection,
183 "Land_cover_yf")
184
185 # Algorithm execution
186 # Transition codes are based on the class code indices
187 # (i.e. their order when sorted by class code) -
188 # not the class codes themselves.
189 # So need to reclass the land cover used for the transition calculations
190 # from the raw class codes to the positional indices of those class codes.
191 # And before doing that, need to reclassified initial and
192 # final layers to the IPCC (or custom) classes.
193
194 # Processing baseline raster
195 bl_remap_1 = remap(lc_baseline_esa,
196 np.asarray(esa_to_custom_nesting.get_list()[0]),
197 np.asarray(esa_to_custom_nesting.get_list()[1]))
198 lc_bl = remap(bl_remap_1, np.asarray(class_codes), np.asarray(class_positions))
199
200 saveRaster(lc_bl.astype('int8'),
201 path_lc_bl,
202 cols,
203 rows,
204 projection,
205 "Land_cover_yi")
206
207 # Processing Target Raster
208 tg_remap_1 = remap(lc_target_esa,
209 np.asarray(esa_to_custom_nesting.get_list()[0]),
210 np.asarray(esa_to_custom_nesting.get_list()[1]))
211 lc_tg = remap(tg_remap_1, np.asarray(class_codes), np.asarray(class_positions))
212
213 saveRaster(lc_tg.astype('int8'),
214 path_lc_tg,
215 cols,
216 rows,
217 projection,
218 "Land_cover_yf")
219
220 # Processing Transition Map
221 # Compute transition map (first digit for baseline land cover,
222 # and second digit for target year land cover)
223 lc_tr = (lc_bl * esa_to_custom_nesting.parent.get_multiplier()) + lc_tg
224
225 # Compute land cover transition
226 # Remap persistence classes so they are sequential.
227 # This makes it easier to assign a clear color ramp in QGIS.
228 lc_tr_pre_remap = remap(lc_tr,
229 np.asarray(trans_matrix.get_persistence_list()[0]),
230 np.asarray(trans_matrix.get_persistence_list()[1]))
231
232 saveRaster(lc_tr_pre_remap.astype('int8'),
233 path_lc_tr,
234 cols,
235 rows,
236 projection,
237 "Land_cover_transitions_yi-yf")
238
239 # Compute land cover degradation
240 # definition of land cover transitions as degradation (-1),
241 # improvement (1), or no relevant change (0)
242 lc_dg = remap(lc_tr,
243 np.asarray(trans_matrix.get_list()[0]),
244 np.asarray(trans_matrix.get_list()[1]))
245
246 saveRaster(lc_dg.astype('int8'),
247 path_lc_dg,
248 cols,
249 rows,
250 projection,
251 "Land_cover_degradation")
252
253 # Compute Mutlibands stack
254 # Land Cover Degradation + Baseline ESA
255 # + Target ESA + Land Cover Transition
256 dg_raster = rasterio.open(path_lc_dg, "r")
257 dg = dg_raster.read(1, masked=True)
258 baseline_esa = rasterio.open(path_lc_baseline_esa, "r").read(1, masked=True)
259 target_esa = rasterio.open(path_lc_target_esa, "r").read(1, masked=True)
260 tr = rasterio.open(path_lc_tr, "r").read(1, masked=True)
261
262 band_list = [dg, lc_baseline_esa, lc_target_esa, tr]
263 out_meta = dg_raster.meta.copy()
264 out_meta.update({"count": 4})
265
266 with rasterio.open(path_out_img, 'w', **out_meta) as dest:
267 for band_nr, src in enumerate(band_list, start=1):
268 dest.write(src, band_nr)