diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5a6cc51..bcadfed 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -13,7 +13,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - python-version: [3.11] + python-version: ["3.10"] steps: - name: Checkout repository diff --git a/pyproject.toml b/pyproject.toml index c7ae8fa..ed03433 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "rasters" -version = "1.4.6" +version = "1.5.0" description = "raster processing toolkit" readme = "README.md" authors = [ diff --git a/rasters/bias_correct.py b/rasters/bias_correct.py new file mode 100644 index 0000000..1b4263a --- /dev/null +++ b/rasters/bias_correct.py @@ -0,0 +1,23 @@ +from .raster import Raster +from .where import where + +DEFAULT_UPSAMPLING = "average" +DEFAULT_DOWNSAMPLING = "linear" + +def bias_correct( + coarse_image: Raster, + fine_image: Raster, + upsampling: str = "average", + downsampling: str = "linear", + return_bias: bool = False): + fine_geometry = fine_image.geometry + coarse_geometry = coarse_image.geometry + upsampled = fine_image.to_geometry(coarse_geometry, resampling=upsampling) + bias_coarse = upsampled - coarse_image + bias_fine = bias_coarse.to_geometry(fine_geometry, resampling=downsampling) + bias_corrected_fine = fine_image - bias_fine + + if return_bias: + return bias_corrected_fine, bias_fine + else: + return bias_corrected_fine diff --git a/rasters/linear_downscale.py b/rasters/linear_downscale.py new file mode 100644 index 0000000..e5063cb --- /dev/null +++ b/rasters/linear_downscale.py @@ -0,0 +1,53 @@ +from .raster import Raster +from .where import where + +DEFAULT_UPSAMPLING = "average" +DEFAULT_DOWNSAMPLING = "linear" + +def linear_downscale( + coarse_image: Raster, + fine_image: Raster, + upsampling: str = "average", + downsampling: str = "cubic", + use_gap_filling: bool = False, + apply_scale: bool = True, + apply_bias: bool = True, + return_scale_and_bias: bool = False) -> Raster: + if upsampling is None: + upsampling = DEFAULT_UPSAMPLING + + if downsampling is None: + downsampling = DEFAULT_DOWNSAMPLING + + coarse_geometry = coarse_image.geometry + fine_geometry = fine_image.geometry + upsampled = fine_image.to_geometry(coarse_geometry, resampling=upsampling) + + if apply_scale: + scale_coarse = coarse_image / upsampled + scale_coarse = where(coarse_image == 0, 0, scale_coarse) + scale_coarse = where(upsampled == 0, 0, scale_coarse) + scale_fine = scale_coarse.to_geometry(fine_geometry, resampling=downsampling) + scale_corrected_fine = fine_image * scale_fine + fine_image = scale_corrected_fine + else: + scale_fine = fine_image * 0 + 1 + + if apply_bias: + upsampled = fine_image.to_geometry(coarse_geometry, resampling=upsampling) + bias_coarse = upsampled - coarse_image + bias_fine = bias_coarse.to_geometry(fine_geometry, resampling=downsampling) + bias_corrected_fine = fine_image - bias_fine + fine_image = bias_corrected_fine + else: + bias_fine = fine_image * 0 + + if use_gap_filling: + gap_fill = coarse_image.to_geometry(fine_geometry, resampling=downsampling) + fine_image = fine_image.fill(gap_fill) + + if return_scale_and_bias: + fine_image["scale"] = scale_fine + fine_image["bias"] = bias_fine + + return fine_image diff --git a/rasters/rasters.py b/rasters/rasters.py index 6b39d67..57aabcb 100644 --- a/rasters/rasters.py +++ b/rasters/rasters.py @@ -24,5 +24,7 @@ from .clip import clip from .center_aeqd import center_aeqd from .local_UTM_proj4 import local_UTM_proj4 +from .linear_downscale import linear_downscale +from .bias_correct import bias_correct __author__ = "Gregory Halverson" diff --git a/rasters/version.txt b/rasters/version.txt index c514bd8..bc80560 100644 --- a/rasters/version.txt +++ b/rasters/version.txt @@ -1 +1 @@ -1.4.6 +1.5.0