buteo.raster.shift

Shift rasters.

Module to shift the location of rasters in geographic coordinates.

  1"""### Shift rasters. ###
  2
  3Module to shift the location of rasters in geographic coordinates.
  4"""
  5
  6# Standard library
  7from typing import Union, Optional, List
  8
  9# External
 10import numpy as np
 11from osgeo import gdal
 12
 13# Internal
 14from buteo.utils import (
 15    utils_base,
 16    utils_gdal,
 17    utils_path,
 18    utils_io,
 19)
 20from buteo.raster import core_raster, core_raster_io
 21from buteo.array.convolution import convolve_array_simple
 22from buteo.array.convolution_kernels import kernel_shift
 23
 24
 25
 26def _raster_shift(
 27    raster: Union[str, gdal.Dataset],
 28    shift_list: List[Union[int, float]],
 29    out_path: Optional[str] = None,
 30    *,
 31    overwrite: bool = True,
 32    creation_options: Optional[List[str]] = None,
 33) -> Union[str, gdal.Dataset]:
 34    """Internal."""
 35    assert isinstance(shift_list, (list, tuple)), f"shift_list must be a list or a tuple. {shift_list}"
 36    assert len(shift_list) == 2, f"shift_list must be a list or tuple with len 2 (x_shift, y_shift): {shift_list}"
 37
 38    for shift in shift_list:
 39        assert isinstance(shift, (int, float)), f"shift must be an int or a float: {shift}"
 40
 41    ref = core_raster._raster_open(raster)
 42    metadata = core_raster._get_basic_metadata_raster(ref)
 43
 44    x_shift, y_shift = shift_list
 45
 46    if out_path is None:
 47        out_path = utils_path._get_temp_filepath("shifted_raster.tif")
 48    else:
 49        if not utils_path._check_is_valid_output_filepath(out_path, overwrite=overwrite):
 50            raise ValueError(f"out_path is not a valid output path: {out_path}")
 51
 52    utils_path._delete_if_required(out_path, overwrite)
 53
 54    driver = gdal.GetDriverByName(utils_gdal._get_raster_driver_name_from_path(out_path))
 55
 56    shifted = driver.Create(
 57        out_path,  # Location of the saved raster, ignored if driver is memory.
 58        metadata["width"],  # Dataframe width in pixels (e.g. 1920px).
 59        metadata["height"],  # Dataframe height in pixels (e.g. 1280px).
 60        metadata["bands"],  # The number of bands required.
 61        metadata["dtype_gdal"],  # Datatype of the destination.
 62        utils_gdal._get_default_creation_options(creation_options),
 63    )
 64
 65    new_transform = list(metadata["geotransform"])
 66    new_transform[0] += x_shift
 67    new_transform[3] += y_shift
 68
 69    shifted.SetGeoTransform(new_transform)
 70    shifted.SetProjection(metadata["projection_wkt"])
 71
 72    src_nodata = metadata["nodata_value"]
 73
 74    for band in range(metadata["bands"]):
 75        origin_raster_band = ref.GetRasterBand(band + 1)
 76        target_raster_band = shifted.GetRasterBand(band + 1)
 77
 78        target_raster_band.WriteArray(origin_raster_band.ReadAsArray())
 79
 80        if src_nodata is not None:
 81            if utils_base._check_variable_is_int(src_nodata):
 82                target_raster_band.SetNoDataValue(int(src_nodata))
 83            else:
 84                target_raster_band.SetNoDataValue(float(src_nodata))
 85
 86    shifted.FlushCache()
 87    shifted = None
 88    ref = None
 89
 90    return out_path
 91
 92
 93def raster_shift(
 94    raster: Union[str, gdal.Dataset, List],
 95    shift_list: List[Union[int, float]],
 96    out_path: Optional[str] = None,
 97    *,
 98    overwrite: bool = True,
 99    prefix: str = "",
100    suffix: str = "",
101    add_uuid: bool = False,
102    add_timestamp: bool = False,
103    creation_options: Optional[List[str]] = None,
104) -> Union[str, List[str], gdal.Dataset]:
105    """Shifts a raster in a given direction. (The frame is shifted)
106
107    Parameters
108    ----------
109    raster : Union[str, List, gdal.Dataset]
110        The raster(s) to be shifted.
111
112    shift_list : List[Union[int, float]]
113        The shift in x and y direction.
114
115    out_path : Optional[str], optional
116        The path to the output raster. If None, the raster is created in memory., default: None
117
118    overwrite : bool, optional
119        If True, the output raster will be overwritten if it already exists., default: True
120
121    prefix : str, optional
122        The prefix to be added to the output raster name., default: ""
123
124    suffix : str, optional
125        The suffix to be added to the output raster name., default: ""
126
127    add_uuid : bool, optional
128        If True, a unique identifier will be added to the output raster name., default: False
129
130    add_timestamp : bool, optional
131        If True, a timestamp will be added to the output raster name., default: False
132
133    creation_options : Optional[List[str]], optional
134        The creation options to be used when creating the output., default: None
135
136    Returns
137    -------
138    Union[str, List[str]]
139        The path(s) to the shifted raster(s).
140    """
141    utils_base._type_check(raster, [str, gdal.Dataset, [str, gdal.Dataset]], "raster")
142    utils_base._type_check(shift_list, [[int, float], tuple], "shift_list")
143    utils_base._type_check(out_path, [str, [str], None], "out_path")
144    utils_base._type_check(overwrite, [bool], "overwrite")
145    utils_base._type_check(creation_options, [[str], None], "creation_options")
146    utils_base._type_check(prefix, [str], "prefix")
147    utils_base._type_check(suffix, [str], "suffix")
148    utils_base._type_check(add_uuid, [bool], "add_uuid")
149    utils_base._type_check(add_timestamp, [bool], "add_timestamp")
150
151    input_is_list = isinstance(raster, list)
152
153    input_list = utils_io._get_input_paths(raster, "raster")
154    output_list = utils_io._get_output_paths(
155        input_list,
156        out_path,
157        overwrite=overwrite,
158        prefix=prefix,
159        suffix=suffix,
160        add_uuid=add_uuid,
161        add_timestamp=add_timestamp,
162        change_ext="tif",
163    )
164
165    utils_path._delete_if_required_list(output_list, overwrite)
166
167    shifted_rasters = []
168    for idx, in_raster in enumerate(input_list):
169        shifted_rasters.append(
170            _raster_shift(
171                in_raster,
172                shift_list,
173                out_path=output_list[idx],
174                overwrite=overwrite,
175                creation_options=creation_options,
176            )
177        )
178
179    if input_is_list:
180        return shifted_rasters
181
182    return shifted_rasters[0]
183
184
185def raster_shift_pixel(
186    raster: Union[str, gdal.Dataset],
187    shift_list: List[Union[int, float]],
188    out_path: Optional[str] = None,
189) -> str:
190    """Shifts a raster in a given direction. (The pixels are shifted, not the frame)
191
192    Parameters
193    ----------
194    raster : Union[str, gdal.Dataset]
195        The raster to be shifted.
196
197    shift_list : List[Union[int, float]]
198        The shift in x and y direction.
199
200    out_path : Optional[str], optional
201        The path to the output raster. If None, the raster is created in memory., default: None
202
203    Returns
204    -------
205    str
206        The path to the shifted raster.
207    """
208    utils_base._type_check(raster, [str, gdal.Dataset], "raster")
209    utils_base._type_check(shift_list, [[int, float], tuple], "shift_list")
210    utils_base._type_check(out_path, [str, None], "out_path")
211
212    arr = core_raster_io.raster_to_array(raster)
213
214    offsets, weights = kernel_shift(shift_list[0], shift_list[1])
215
216    arr_float32 = arr.astype(np.float32, copy=False)
217
218    for channel in range(arr.shape[2]):
219        arr[:, :, channel] = convolve_array_simple(
220            arr_float32[:, :, channel], offsets, weights,
221        )
222
223    if out_path is None:
224        out_path = utils_path._get_temp_filepath("shifted_raster.tif")
225    else:
226        if not utils_path._check_is_valid_output_filepath(out_path):
227            raise ValueError(f"out_path is not a valid output path: {out_path}")
228
229    utils_path._delete_if_required(out_path, overwrite=True)
230
231    return core_raster_io.array_to_raster(
232        arr,
233        reference=raster,
234        out_path=out_path,
235    )
def raster_shift( raster: Union[str, osgeo.gdal.Dataset, List], shift_list: List[Union[int, float]], out_path: Optional[str] = None, *, overwrite: bool = True, prefix: str = '', suffix: str = '', add_uuid: bool = False, add_timestamp: bool = False, creation_options: Optional[List[str]] = None) -> Union[str, List[str], osgeo.gdal.Dataset]:
 94def raster_shift(
 95    raster: Union[str, gdal.Dataset, List],
 96    shift_list: List[Union[int, float]],
 97    out_path: Optional[str] = None,
 98    *,
 99    overwrite: bool = True,
100    prefix: str = "",
101    suffix: str = "",
102    add_uuid: bool = False,
103    add_timestamp: bool = False,
104    creation_options: Optional[List[str]] = None,
105) -> Union[str, List[str], gdal.Dataset]:
106    """Shifts a raster in a given direction. (The frame is shifted)
107
108    Parameters
109    ----------
110    raster : Union[str, List, gdal.Dataset]
111        The raster(s) to be shifted.
112
113    shift_list : List[Union[int, float]]
114        The shift in x and y direction.
115
116    out_path : Optional[str], optional
117        The path to the output raster. If None, the raster is created in memory., default: None
118
119    overwrite : bool, optional
120        If True, the output raster will be overwritten if it already exists., default: True
121
122    prefix : str, optional
123        The prefix to be added to the output raster name., default: ""
124
125    suffix : str, optional
126        The suffix to be added to the output raster name., default: ""
127
128    add_uuid : bool, optional
129        If True, a unique identifier will be added to the output raster name., default: False
130
131    add_timestamp : bool, optional
132        If True, a timestamp will be added to the output raster name., default: False
133
134    creation_options : Optional[List[str]], optional
135        The creation options to be used when creating the output., default: None
136
137    Returns
138    -------
139    Union[str, List[str]]
140        The path(s) to the shifted raster(s).
141    """
142    utils_base._type_check(raster, [str, gdal.Dataset, [str, gdal.Dataset]], "raster")
143    utils_base._type_check(shift_list, [[int, float], tuple], "shift_list")
144    utils_base._type_check(out_path, [str, [str], None], "out_path")
145    utils_base._type_check(overwrite, [bool], "overwrite")
146    utils_base._type_check(creation_options, [[str], None], "creation_options")
147    utils_base._type_check(prefix, [str], "prefix")
148    utils_base._type_check(suffix, [str], "suffix")
149    utils_base._type_check(add_uuid, [bool], "add_uuid")
150    utils_base._type_check(add_timestamp, [bool], "add_timestamp")
151
152    input_is_list = isinstance(raster, list)
153
154    input_list = utils_io._get_input_paths(raster, "raster")
155    output_list = utils_io._get_output_paths(
156        input_list,
157        out_path,
158        overwrite=overwrite,
159        prefix=prefix,
160        suffix=suffix,
161        add_uuid=add_uuid,
162        add_timestamp=add_timestamp,
163        change_ext="tif",
164    )
165
166    utils_path._delete_if_required_list(output_list, overwrite)
167
168    shifted_rasters = []
169    for idx, in_raster in enumerate(input_list):
170        shifted_rasters.append(
171            _raster_shift(
172                in_raster,
173                shift_list,
174                out_path=output_list[idx],
175                overwrite=overwrite,
176                creation_options=creation_options,
177            )
178        )
179
180    if input_is_list:
181        return shifted_rasters
182
183    return shifted_rasters[0]

Shifts a raster in a given direction. (The frame is shifted)

Parameters

raster : Union[str, List, gdal.Dataset] The raster(s) to be shifted.

shift_list : List[Union[int, float]] The shift in x and y direction.

out_path : Optional[str], optional The path to the output raster. If None, the raster is created in memory., default: None

overwrite : bool, optional If True, the output raster will be overwritten if it already exists., default: True

prefix : str, optional The prefix to be added to the output raster name., default: ""

suffix : str, optional The suffix to be added to the output raster name., default: ""

add_uuid : bool, optional If True, a unique identifier will be added to the output raster name., default: False

add_timestamp : bool, optional If True, a timestamp will be added to the output raster name., default: False

creation_options : Optional[List[str]], optional The creation options to be used when creating the output., default: None

Returns

Union[str, List[str]] The path(s) to the shifted raster(s).

def raster_shift_pixel( raster: Union[str, osgeo.gdal.Dataset], shift_list: List[Union[int, float]], out_path: Optional[str] = None) -> str:
186def raster_shift_pixel(
187    raster: Union[str, gdal.Dataset],
188    shift_list: List[Union[int, float]],
189    out_path: Optional[str] = None,
190) -> str:
191    """Shifts a raster in a given direction. (The pixels are shifted, not the frame)
192
193    Parameters
194    ----------
195    raster : Union[str, gdal.Dataset]
196        The raster to be shifted.
197
198    shift_list : List[Union[int, float]]
199        The shift in x and y direction.
200
201    out_path : Optional[str], optional
202        The path to the output raster. If None, the raster is created in memory., default: None
203
204    Returns
205    -------
206    str
207        The path to the shifted raster.
208    """
209    utils_base._type_check(raster, [str, gdal.Dataset], "raster")
210    utils_base._type_check(shift_list, [[int, float], tuple], "shift_list")
211    utils_base._type_check(out_path, [str, None], "out_path")
212
213    arr = core_raster_io.raster_to_array(raster)
214
215    offsets, weights = kernel_shift(shift_list[0], shift_list[1])
216
217    arr_float32 = arr.astype(np.float32, copy=False)
218
219    for channel in range(arr.shape[2]):
220        arr[:, :, channel] = convolve_array_simple(
221            arr_float32[:, :, channel], offsets, weights,
222        )
223
224    if out_path is None:
225        out_path = utils_path._get_temp_filepath("shifted_raster.tif")
226    else:
227        if not utils_path._check_is_valid_output_filepath(out_path):
228            raise ValueError(f"out_path is not a valid output path: {out_path}")
229
230    utils_path._delete_if_required(out_path, overwrite=True)
231
232    return core_raster_io.array_to_raster(
233        arr,
234        reference=raster,
235        out_path=out_path,
236    )

Shifts a raster in a given direction. (The pixels are shifted, not the frame)

Parameters

raster : Union[str, gdal.Dataset] The raster to be shifted.

shift_list : List[Union[int, float]] The shift in x and y direction.

out_path : Optional[str], optional The path to the output raster. If None, the raster is created in memory., default: None

Returns

str The path to the shifted raster.