From 66ce6d828a0a5a00a3001eae05698104c93cd69d Mon Sep 17 00:00:00 2001 From: f-PLT Date: Wed, 1 May 2024 19:12:25 -0400 Subject: [PATCH 1/3] Add resample script --- .pre-commit-config.yaml | 1 + poetry.lock | 19 +++++++- pyproject.toml | 1 + scripts/resample_tiff_raster.py | 83 +++++++++++++++++++++++++++++++++ 4 files changed, 103 insertions(+), 1 deletion(-) create mode 100644 scripts/resample_tiff_raster.py diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 81bead6..6cc6658 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -31,6 +31,7 @@ repos: rev: 7.0.0 hooks: - id: flake8 + additional_dependencies: [flake8-pyproject] - repo: https://github.com/ikamensh/flynt rev: 1.0.1 diff --git a/poetry.lock b/poetry.lock index 20df836..0701b5b 100644 --- a/poetry.lock +++ b/poetry.lock @@ -817,6 +817,23 @@ mccabe = ">=0.7.0,<0.8.0" pycodestyle = ">=2.11.0,<2.12.0" pyflakes = ">=3.2.0,<3.3.0" +[[package]] +name = "flake8-pyproject" +version = "1.2.3" +description = "Flake8 plug-in loading the configuration from pyproject.toml" +optional = false +python-versions = ">= 3.6" +files = [ + {file = "flake8_pyproject-1.2.3-py3-none-any.whl", hash = "sha256:6249fe53545205af5e76837644dc80b4c10037e73a0e5db87ff562d75fb5bd4a"}, +] + +[package.dependencies] +Flake8 = ">=5" +TOMLi = {version = "*", markers = "python_version < \"3.11\""} + +[package.extras] +dev = ["pyTest", "pyTest-cov"] + [[package]] name = "flynt" version = "1.0.1" @@ -3216,4 +3233,4 @@ test = ["websockets"] [metadata] lock-version = "2.0" python-versions = ">=3.10,<3.12" -content-hash = "792803e0b07600089d6d09cc0d156714c508d3d2f269e89dfdb07467ec68412b" +content-hash = "99eb98239afcaecb4615b0fc7feb14544df5edbbfdb0746d6be7a5571761e908" diff --git a/pyproject.toml b/pyproject.toml index 1e992d6..c8db897 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -23,6 +23,7 @@ tox = "^4.12.0" flynt = "^1.0.1" flake8 = "^7.0.0" pre-commit = "^3.7.0" +flake8-pyproject = "^1.2.3" [tool.poetry.group.lab] optional = true diff --git a/scripts/resample_tiff_raster.py b/scripts/resample_tiff_raster.py new file mode 100644 index 0000000..8ea9a58 --- /dev/null +++ b/scripts/resample_tiff_raster.py @@ -0,0 +1,83 @@ +import os +import pathlib + +import click +import rasterio +from rasterio.warp import Resampling +from rasterio.windows import from_bounds + +from geospatial_tools import DATA_DIR + +PROJECT_DATA_DIR = pathlib.Path(os.getenv("BASE_DATA_PATH", DATA_DIR)) + + +def get_source_information(source_image): + with rasterio.open(source_image) as source: + # Save a lot of the information that is needed, so ortho image can be closed and + # we can save space + source_transform = source.transform + source_crs = source.crs + source_height = source.height + source_width = source.width + source_bounds = source.bounds + return source_bounds, source_crs, source_height, source_transform, source_width + + +@click.command(context_settings={"show_default": True}) +@click.option( + "--source-image", + type=str, + help="Path of the source/reference image", +) +@click.option( + "--resample-target", + type=str, + help="Path of the resampled image", +) +@click.option( + "--output-path", + type=str, + help="Base output path", + default=PROJECT_DATA_DIR, +) +def resample_tiff(source_image: str, resample_target: str, output_path: str): + source_image = pathlib.Path(source_image) + resample_target = pathlib.Path(resample_target) + output_path = pathlib.Path(output_path) + + source_bounds, source_crs, source_height, source_transform, source_width = get_source_information(source_image) + + with rasterio.open(resample_target) as resample: + resample_target_crs = resample.crs + + print("Check if CRS match") + # Check if CRS match + if resample_target_crs != source_crs: + raise ValueError("CRS does not match, reproject 'source' to match 'target'") + + print("Creating window to clip dsm ortho") + window = from_bounds(*source_bounds, transform=resample.transform) + + # Prepare to resample the source image + kwargs = resample.meta.copy() + kwargs.update( + {"crs": resample_target_crs, "transform": source_transform, "width": source_width, "height": source_height} + ) + + print("Resampling dsm ortho") + with rasterio.open(output_path / "resampled_dsm_ortho.tif", "w", **kwargs) as resampled: + # Sample didn't include more than 1 band, but just in case... + for i in range(1, resample.count + 1): + # Read each band from the source and resample it + resampled_band = resample.read( + i, + window=window, + out_shape=(source_height, source_width), + resampling=Resampling.nearest, + out_dtype="float32", + ) + resampled.write(resampled_band, i) + + +if __name__ == "__main__": + resample_tiff() # pylint: disable=no-value-for-parameter From 44fa29752ec599962f7b805a0565e89d1290b581 Mon Sep 17 00:00:00 2001 From: f-PLT Date: Wed, 1 May 2024 19:14:44 -0400 Subject: [PATCH 2/3] Update CHANGES.md --- CHANGES.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGES.md b/CHANGES.md index 5b4b76d..5d71ba9 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -3,4 +3,4 @@ [Unreleased](https://github.com/RolnickLab/geospatial-tools/tree/main) (latest) ------------------------------------------------------------------------------------- -[//]: # (New changes here in list form) \ No newline at end of file +- Add `resample_tiff_raster.py` script \ No newline at end of file From 17140712becf584d830706b4b12a4b6b6b1fbbcc Mon Sep 17 00:00:00 2001 From: f-PLT Date: Thu, 2 May 2024 11:27:50 -0400 Subject: [PATCH 3/3] Update documentation --- scripts/README.md | 8 +++++++- scripts/resample_tiff_raster.py | 6 +++--- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/scripts/README.md b/scripts/README.md index 57056ea..8daa125 100644 --- a/scripts/README.md +++ b/scripts/README.md @@ -5,4 +5,10 @@ This folder is dedicated to scripts, whether python, bash or sbatch. Generally, scripts are more for standalone processes while figuring them out. Once a script is more mature, it should be generalized and integrated into the package -itself. \ No newline at end of file +itself. + +## Scripts + +| Scripts | Description | +|---------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `resample_tiff_raster.py` | Script to resample a target tiff image, so it matches a source image's grid size and area. Resampling strategy is using a Nearest Neighbor algorythm to keep original values.

Use the scripts CLI for more information : `python3 resample_tiff_raster.py --help` | diff --git a/scripts/resample_tiff_raster.py b/scripts/resample_tiff_raster.py index 8ea9a58..83c17ef 100644 --- a/scripts/resample_tiff_raster.py +++ b/scripts/resample_tiff_raster.py @@ -11,10 +11,10 @@ PROJECT_DATA_DIR = pathlib.Path(os.getenv("BASE_DATA_PATH", DATA_DIR)) -def get_source_information(source_image): +def get_source_information(source_image: pathlib.Path): with rasterio.open(source_image) as source: - # Save a lot of the information that is needed, so ortho image can be closed and - # we can save space + # Save a lot of the information that is needed, so ortho image can be closed, and + # we can save memory use source_transform = source.transform source_crs = source.crs source_height = source.height