Skip to content

Commit 5680031

Browse files
committed
fix(unify-rasters): Fix unify raster grids copying dtype and other unwanted metadata from base raster
1 parent 5c8d32e commit 5680031

File tree

1 file changed

+47
-40
lines changed

1 file changed

+47
-40
lines changed

eis_toolkit/raster_processing/unifying.py

+47-40
Original file line numberDiff line numberDiff line change
@@ -4,83 +4,90 @@
44
from beartype.typing import List, Literal, Sequence, Tuple
55
from rasterio import warp
66
from rasterio.enums import Resampling
7+
from rasterio.profiles import Profile
78

89
from eis_toolkit.exceptions import InvalidParameterValueException
910
from eis_toolkit.raster_processing.resampling import RESAMPLE_METHOD_MAP
1011

1112

13+
def _calculate_snapped_grid(
14+
raster: rasterio.io.DatasetReader, dst_crs: rasterio.crs.CRS, dst_resolution: Tuple[float, float]
15+
) -> Tuple[warp.Affine, int, int]:
16+
dst_transform, dst_width, dst_height = warp.calculate_default_transform(
17+
raster.crs, dst_crs, raster.width, raster.height, *raster.bounds, resolution=dst_resolution
18+
)
19+
# The created transform might not be aligned with the base raster grid, so
20+
# we still need to snap/align the transformation to closest grid corner
21+
x_distance_to_grid = dst_transform.c % dst_resolution[0]
22+
y_distance_to_grid = dst_transform.f % dst_resolution[1]
23+
24+
if x_distance_to_grid > dst_resolution[0] / 2: # Snap towards right
25+
c = dst_transform.c - x_distance_to_grid + dst_resolution[0]
26+
else: # Snap towards left
27+
c = dst_transform.c - x_distance_to_grid
28+
29+
if y_distance_to_grid > dst_resolution[1] / 2: # Snap towards up
30+
f = dst_transform.f - y_distance_to_grid + dst_resolution[1]
31+
else: # Snap towards bottom
32+
f = dst_transform.f - y_distance_to_grid
33+
34+
# Create new transform with updated corner coordinates
35+
dst_transform = warp.Affine(
36+
dst_transform.a, # Pixel size x
37+
dst_transform.b, # Shear parameter
38+
c, # Up-left corner x-coordinate
39+
dst_transform.d, # Shear parameter
40+
dst_transform.e, # Pixel size y
41+
f, # Up-left corner y-coordinate
42+
)
43+
return dst_transform, dst_width, dst_height
44+
45+
1246
def _unify_raster_grids(
1347
base_raster: rasterio.io.DatasetReader,
1448
rasters_to_unify: Sequence[rasterio.io.DatasetReader],
1549
resampling_method: Resampling,
1650
same_extent: bool,
17-
) -> List[Tuple[np.ndarray, dict]]:
51+
) -> List[Tuple[np.ndarray, Profile]]:
1852

1953
dst_crs = base_raster.crs
2054
dst_width = base_raster.width
2155
dst_height = base_raster.height
2256
dst_transform = base_raster.transform
2357
dst_resolution = (base_raster.transform.a, abs(base_raster.transform.e))
2458

25-
out_rasters = [(base_raster.read(), base_raster.meta.copy())]
26-
out_meta = base_raster.meta.copy()
59+
out_rasters = [(base_raster.read(), base_raster.profile.copy())]
2760

2861
for raster in rasters_to_unify:
62+
out_profile = raster.profile.copy()
2963

3064
# If we unify without clipping, things are more complicated and we need to
3165
# calculate corner coordinates, width and height, and snap the grid to nearest corner
3266
if not same_extent:
33-
dst_transform, dst_width, dst_height = warp.calculate_default_transform(
34-
raster.crs, dst_crs, raster.width, raster.height, *raster.bounds, resolution=dst_resolution
35-
)
36-
# The created transform might not be aligned with the base raster grid, so
37-
# we still need to snap/align the transformation to closest grid corner
38-
x_distance_to_grid = dst_transform.c % dst_resolution[0]
39-
y_distance_to_grid = dst_transform.f % dst_resolution[1]
40-
41-
if x_distance_to_grid > dst_resolution[0] / 2: # Snap towards right
42-
c = dst_transform.c - x_distance_to_grid + dst_resolution[0]
43-
else: # Snap towards left
44-
c = dst_transform.c - x_distance_to_grid
45-
46-
if y_distance_to_grid > dst_resolution[1] / 2: # Snap towards up
47-
f = dst_transform.f - y_distance_to_grid + dst_resolution[1]
48-
else: # Snap towards bottom
49-
f = dst_transform.f - y_distance_to_grid
50-
51-
# Create new transform with updated corner coordinates
52-
dst_transform = warp.Affine(
53-
dst_transform.a, # Pixel size x
54-
dst_transform.b, # Shear parameter
55-
c, # Up-left corner x-coordinate
56-
dst_transform.d, # Shear parameter
57-
dst_transform.e, # Pixel size y
58-
f, # Up-left corner y-coordinate
59-
)
60-
61-
out_meta["transform"] = dst_transform
62-
out_meta["width"] = dst_width
63-
out_meta["height"] = dst_height
67+
dst_transform, dst_width, dst_height = _calculate_snapped_grid(raster, dst_crs, dst_resolution)
6468

6569
# Initialize output raster arrary
6670
dst_array = np.empty((base_raster.count, dst_height, dst_width))
67-
dst_array.fill(base_raster.meta["nodata"])
71+
nodata = out_profile["nodata"]
72+
dst_array.fill(nodata)
6873

6974
src_array = raster.read()
7075

7176
out_image = warp.reproject(
7277
source=src_array,
7378
src_crs=raster.crs,
7479
src_transform=raster.transform,
75-
src_nodata=raster.meta["nodata"],
80+
src_nodata=nodata,
7681
destination=dst_array,
7782
dst_crs=dst_crs,
7883
dst_transform=dst_transform,
79-
dst_nodata=base_raster.meta["nodata"],
84+
dst_nodata=nodata,
8085
resampling=resampling_method,
8186
)[0]
8287

83-
out_rasters.append((out_image, out_meta))
88+
out_profile.update({"transform": dst_transform, "width": dst_width, "height": dst_height, "crs": dst_crs})
89+
90+
out_rasters.append((out_image, out_profile))
8491

8592
return out_rasters
8693

@@ -91,7 +98,7 @@ def unify_raster_grids(
9198
rasters_to_unify: Sequence[rasterio.io.DatasetReader],
9299
resampling_method: Literal["nearest", "bilinear", "cubic", "average", "gauss", "max", "min"] = "nearest",
93100
same_extent: bool = False,
94-
) -> List[Tuple[np.ndarray, dict]]:
101+
) -> List[Tuple[np.ndarray, Profile]]:
95102
"""Unifies (reprojects, resamples, aligns and optionally clips) given rasters relative to base raster.
96103
97104
Args:
@@ -104,7 +111,7 @@ def unify_raster_grids(
104111
as the base raster. Expands smaller rasters with nodata cells. Defaults to False.
105112
106113
Returns:
107-
List of unified rasters' data and metadata. First element is the base raster.
114+
List of unified rasters' data and profiles. First element is the base raster.
108115
109116
Raises:
110117
InvalidParameterValueException: Rasters to unify is empty.

0 commit comments

Comments
 (0)