From 33b66a6b6147830e4df9e9e55df892e567fd9835 Mon Sep 17 00:00:00 2001 From: Matic Lubej Date: Wed, 12 Jun 2024 17:01:15 +0200 Subject: [PATCH 01/10] return early if no data --- eolearn/mask/snow_mask.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/eolearn/mask/snow_mask.py b/eolearn/mask/snow_mask.py index 239cea65..269e5844 100644 --- a/eolearn/mask/snow_mask.py +++ b/eolearn/mask/snow_mask.py @@ -66,6 +66,10 @@ def _apply_dilation(self, snow_masks: np.ndarray) -> np.ndarray: def execute(self, eopatch: EOPatch) -> EOPatch: bands = eopatch[self.bands_feature][..., self.band_indices] + if bands.shape[0] == 0: + eopatch[self.mask_feature] = np.zeros((*bands.shape[:-1], 1), dtype=bool) + return eopatch + with np.errstate(divide="ignore", invalid="ignore"): # (B03 - B11) / (B03 + B11) ndsi = (bands[..., 0] - bands[..., 3]) / (bands[..., 0] + bands[..., 3]) From fbddfa168e66f0731e44982ee1c7585591a3437d Mon Sep 17 00:00:00 2001 From: Matic Lubej Date: Wed, 12 Jun 2024 17:24:10 +0200 Subject: [PATCH 02/10] pylint ignore cv2 --- eolearn/coregistration/coregistration.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eolearn/coregistration/coregistration.py b/eolearn/coregistration/coregistration.py index 1a9603d1..0fc2bbb2 100644 --- a/eolearn/coregistration/coregistration.py +++ b/eolearn/coregistration/coregistration.py @@ -117,7 +117,7 @@ def register( valid_mask, # type: ignore[arg-type] self.gauss_kernel_size, ) - except cv2.error as cv2err: + except cv2.error as cv2err: # pylint: disable=catching-non-exception warnings.warn(f"Could not calculate the warp matrix: {cv2err}", EORuntimeWarning) return warp_matrix From 8f095cfeb271b15f5b63fb8fbb77bb2c33492e49 Mon Sep 17 00:00:00 2001 From: Matic Lubej Date: Thu, 13 Jun 2024 11:14:11 +0200 Subject: [PATCH 03/10] fix mypy cv2 errors --- eolearn/coregistration/coregistration.py | 2 +- eolearn/features/utils.py | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/eolearn/coregistration/coregistration.py b/eolearn/coregistration/coregistration.py index 0fc2bbb2..a3e430b8 100644 --- a/eolearn/coregistration/coregistration.py +++ b/eolearn/coregistration/coregistration.py @@ -114,7 +114,7 @@ def register( warp_matrix, warp_mode, criteria, - valid_mask, # type: ignore[arg-type] + valid_mask, self.gauss_kernel_size, ) except cv2.error as cv2err: # pylint: disable=catching-non-exception diff --git a/eolearn/features/utils.py b/eolearn/features/utils.py index 94ad5c5d..ea01890d 100644 --- a/eolearn/features/utils.py +++ b/eolearn/features/utils.py @@ -162,6 +162,7 @@ def spatially_resize_image( if resize_library is ResizeLib.CV2: resize_function = partial(cv2.resize, dsize=size, interpolation=resize_method.get_cv2_method(data.dtype)) else: + # type: ignore[arg-type] resize_function = partial(_pil_resize_ndarray, size=size, method=resize_method.get_pil_method()) resized_data = _apply_to_spatial_axes(resize_function, data, spatial_axes) From 9db5efe485dea75aacc9403d0a91fc7057b5cd4f Mon Sep 17 00:00:00 2001 From: Matic Lubej Date: Thu, 13 Jun 2024 11:14:49 +0200 Subject: [PATCH 04/10] enforce shape always --- eolearn/mask/snow_mask.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/eolearn/mask/snow_mask.py b/eolearn/mask/snow_mask.py index 269e5844..6ccc5305 100644 --- a/eolearn/mask/snow_mask.py +++ b/eolearn/mask/snow_mask.py @@ -61,15 +61,12 @@ def _apply_dilation(self, snow_masks: np.ndarray) -> np.ndarray: """Apply binary dilation for each mask in the series""" if self.disk_size > 0: disk = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (self.disk_size, self.disk_size)) - snow_masks = np.array([cv2.dilate(mask.astype(np.uint8), disk) for mask in snow_masks]) + dilated_masks = np.array([cv2.dilate(mask.astype(np.uint8), disk) for mask in snow_masks]) + snow_masks = dilated_masks.reshape(snow_masks.shape) # edge case where data is empty return snow_masks.astype(bool) def execute(self, eopatch: EOPatch) -> EOPatch: bands = eopatch[self.bands_feature][..., self.band_indices] - if bands.shape[0] == 0: - eopatch[self.mask_feature] = np.zeros((*bands.shape[:-1], 1), dtype=bool) - return eopatch - with np.errstate(divide="ignore", invalid="ignore"): # (B03 - B11) / (B03 + B11) ndsi = (bands[..., 0] - bands[..., 3]) / (bands[..., 0] + bands[..., 3]) From 8a8e4ad8d208a833402a67679091db17f2b51574 Mon Sep 17 00:00:00 2001 From: Matic Lubej Date: Thu, 13 Jun 2024 11:30:12 +0200 Subject: [PATCH 05/10] add test for empty eopatch --- tests/mask/test_snow_mask.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/tests/mask/test_snow_mask.py b/tests/mask/test_snow_mask.py index ab7e1724..001f2081 100644 --- a/tests/mask/test_snow_mask.py +++ b/tests/mask/test_snow_mask.py @@ -10,7 +10,7 @@ import numpy as np import pytest -from eolearn.core import FeatureType +from eolearn.core import FeatureType, EOPatch from eolearn.mask import SnowMaskTask @@ -33,3 +33,12 @@ def test_snow_coverage(task, result, test_eopatch): snow_pixels = np.sum(output, axis=(1, 2, 3)) assert np.sum(snow_pixels) == result[0], "Sum of snowy pixels does not match" assert snow_pixels[-4] == result[1], "Snowy pixels on specified frame do not match" + + +def test_snow_empty_eopatch(test_eopatch): + bands = test_eopatch.data["BANDS-S2-L1C"] + empty_bands_array = np.array([], dtype=bands.dtype).reshape((0, *bands.shape[1:])) + empty_eopatch = EOPatch(bbox=test_eopatch.bbox, timestamps=[], data={"BANDS-S2-L1C": empty_bands_array}) + task = SnowMaskTask((FeatureType.DATA, "BANDS-S2-L1C"), [2, 3, 7, 11], mask_name="TEST_SNOW_MASK") + resulting_eopatch = task(empty_eopatch) # checks if the task runs without errors + assert resulting_eopatch.mask["TEST_SNOW_MASK"].shape[0] == 0 From 2f892ca4c2e7c71fa1e41c978ad38edd193a6b33 Mon Sep 17 00:00:00 2001 From: Matic Lubej Date: Thu, 13 Jun 2024 11:33:01 +0200 Subject: [PATCH 06/10] pre-commit fixes --- tests/mask/test_snow_mask.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/mask/test_snow_mask.py b/tests/mask/test_snow_mask.py index 001f2081..f689a4d0 100644 --- a/tests/mask/test_snow_mask.py +++ b/tests/mask/test_snow_mask.py @@ -10,7 +10,7 @@ import numpy as np import pytest -from eolearn.core import FeatureType, EOPatch +from eolearn.core import EOPatch, FeatureType from eolearn.mask import SnowMaskTask @@ -40,5 +40,5 @@ def test_snow_empty_eopatch(test_eopatch): empty_bands_array = np.array([], dtype=bands.dtype).reshape((0, *bands.shape[1:])) empty_eopatch = EOPatch(bbox=test_eopatch.bbox, timestamps=[], data={"BANDS-S2-L1C": empty_bands_array}) task = SnowMaskTask((FeatureType.DATA, "BANDS-S2-L1C"), [2, 3, 7, 11], mask_name="TEST_SNOW_MASK") - resulting_eopatch = task(empty_eopatch) # checks if the task runs without errors + resulting_eopatch = task(empty_eopatch) # checks if the task runs without errors assert resulting_eopatch.mask["TEST_SNOW_MASK"].shape[0] == 0 From cd96dc01527164d1043868f7efa5d5288bb05485 Mon Sep 17 00:00:00 2001 From: Matic Lubej Date: Thu, 13 Jun 2024 11:34:34 +0200 Subject: [PATCH 07/10] test full shape --- tests/mask/test_snow_mask.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/mask/test_snow_mask.py b/tests/mask/test_snow_mask.py index f689a4d0..a0d6e9c2 100644 --- a/tests/mask/test_snow_mask.py +++ b/tests/mask/test_snow_mask.py @@ -41,4 +41,4 @@ def test_snow_empty_eopatch(test_eopatch): empty_eopatch = EOPatch(bbox=test_eopatch.bbox, timestamps=[], data={"BANDS-S2-L1C": empty_bands_array}) task = SnowMaskTask((FeatureType.DATA, "BANDS-S2-L1C"), [2, 3, 7, 11], mask_name="TEST_SNOW_MASK") resulting_eopatch = task(empty_eopatch) # checks if the task runs without errors - assert resulting_eopatch.mask["TEST_SNOW_MASK"].shape[0] == 0 + assert resulting_eopatch.mask["TEST_SNOW_MASK"].shape == (*empty_bands_array.shape[:-1], 1) From 5f3cae7ad06d48b8b19548144e5a81d3418a9328 Mon Sep 17 00:00:00 2001 From: Matic Lubej Date: Thu, 13 Jun 2024 11:42:48 +0200 Subject: [PATCH 08/10] make test a bit more pretty --- tests/mask/test_snow_mask.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/tests/mask/test_snow_mask.py b/tests/mask/test_snow_mask.py index a0d6e9c2..c9d73c8a 100644 --- a/tests/mask/test_snow_mask.py +++ b/tests/mask/test_snow_mask.py @@ -36,9 +36,10 @@ def test_snow_coverage(task, result, test_eopatch): def test_snow_empty_eopatch(test_eopatch): - bands = test_eopatch.data["BANDS-S2-L1C"] - empty_bands_array = np.array([], dtype=bands.dtype).reshape((0, *bands.shape[1:])) - empty_eopatch = EOPatch(bbox=test_eopatch.bbox, timestamps=[], data={"BANDS-S2-L1C": empty_bands_array}) + _, h, w, c = test_eopatch.data["BANDS-S2-L1C"].shape + empty_eopatch = EOPatch(bbox=test_eopatch.bbox, timestamps=[]) + empty_eopatch.data["BANDS-S2-L1C"] = np.array([], dtype=np.float32).reshape((0, h, w, c)) + task = SnowMaskTask((FeatureType.DATA, "BANDS-S2-L1C"), [2, 3, 7, 11], mask_name="TEST_SNOW_MASK") resulting_eopatch = task(empty_eopatch) # checks if the task runs without errors - assert resulting_eopatch.mask["TEST_SNOW_MASK"].shape == (*empty_bands_array.shape[:-1], 1) + assert resulting_eopatch.mask["TEST_SNOW_MASK"].shape == (0, h, w, 1) From eadd54b99c5b900f4ce3958d37a3e4aeb4f690e9 Mon Sep 17 00:00:00 2001 From: Matic Lubej Date: Thu, 13 Jun 2024 11:45:49 +0200 Subject: [PATCH 09/10] mypy ignore last try --- eolearn/features/utils.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/eolearn/features/utils.py b/eolearn/features/utils.py index ea01890d..0c67d167 100644 --- a/eolearn/features/utils.py +++ b/eolearn/features/utils.py @@ -162,8 +162,11 @@ def spatially_resize_image( if resize_library is ResizeLib.CV2: resize_function = partial(cv2.resize, dsize=size, interpolation=resize_method.get_cv2_method(data.dtype)) else: - # type: ignore[arg-type] - resize_function = partial(_pil_resize_ndarray, size=size, method=resize_method.get_pil_method()) + resize_function = partial( + _pil_resize_ndarray, # type: ignore[arg-type] + size=size, + method=resize_method.get_pil_method(), + ) resized_data = _apply_to_spatial_axes(resize_function, data, spatial_axes) From 34e2d1c4fbdf8104929f6b9d8e3c1f9130111ae9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=BDiga=20Luk=C5=A1i=C4=8D?= <31988337+zigaLuksic@users.noreply.github.com> Date: Wed, 19 Jun 2024 11:46:59 +0200 Subject: [PATCH 10/10] Prepare release of 1.5.5 (#794) * Adjust changelog * update version * update hooks --------- Co-authored-by: Tamara Suligoj --- .pre-commit-config.yaml | 2 +- CHANGELOG.md | 4 ++++ eolearn/__init__.py | 2 +- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 1d99c8d6..fd66ebdc 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -19,7 +19,7 @@ repos: language_version: python3 - repo: https://github.com/charliermarsh/ruff-pre-commit - rev: "v0.4.4" + rev: "v0.4.9" hooks: - id: ruff diff --git a/CHANGELOG.md b/CHANGELOG.md index 014cb73a..9e2ccf1c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +## [Version 1.5.5] - 2024-06-19 + +- `SnowMaskTask` now correctly handles temporally empty eopatches. + ## [Version 1.5.4] - 2024-05-13 - Minor fixes for documentation diff --git a/eolearn/__init__.py b/eolearn/__init__.py index b4d97ac9..ee64776c 100644 --- a/eolearn/__init__.py +++ b/eolearn/__init__.py @@ -1,6 +1,6 @@ """Main module of the `eolearn` package.""" -__version__ = "1.5.4" +__version__ = "1.5.5" import importlib.util import warnings