From 22792f756a0dad940f4911e49e66f750bfa567f6 Mon Sep 17 00:00:00 2001 From: BRAUN REMI Date: Tue, 3 Sep 2024 18:11:45 +0200 Subject: [PATCH] OPTIM: Save nodata of DIMAP V2 products on disk to avoid recomputing it (`features.rasetrize` could be a heavy computation that shouldn't be done twice) --- CHANGES.md | 1 + eoreader/products/optical/dimap_v2_product.py | 28 +++++++++++++------ 2 files changed, 21 insertions(+), 8 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index b330adbe..33f82c0a 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -7,6 +7,7 @@ - FIX: Resolve the inversion of resolution and pixel size between `stripmap` and `sliding_spotlight` types for `Capella` products - FIX: Get better window name (if available) when writing bands on disk (in tmp folder) - OPTIM: Use default (and optimized) predictor in `rasters.write` if SNAP is version 10 or higher ([#173](https://github.com/sertit/eoreader/issues/173)) +- OPTIM: Save nodata of DIMAP V2 products on disk to avoid recomputing it (`features.rasetrize` could be a heavy computation that shouldn't be done twice) - COMPAT: EOReader works correctly with SNAP 10 ([#165](https://github.com/sertit/eoreader/issues/165)) ## 0.21.2 (2024-07-30) diff --git a/eoreader/products/optical/dimap_v2_product.py b/eoreader/products/optical/dimap_v2_product.py index 8962f25f..c6deb320 100644 --- a/eoreader/products/optical/dimap_v2_product.py +++ b/eoreader/products/optical/dimap_v2_product.py @@ -737,8 +737,10 @@ def _manage_nodata( ) # Get detector footprint to deduce the outside nodata + LOGGER.debug("Load nodata") nodata = self._load_nodata(width, height, vec_tr, **kwargs) + LOGGER.debug("Set nodata mask") return self._set_nodata_mask(band_arr, nodata) @cache @@ -1086,15 +1088,25 @@ def _load_nodata( if all(nodata_det.is_empty): return np.zeros((1, height, width), dtype=np.uint8) else: - # Rasterize nodata - return features.rasterize( - nodata_det.geometry, - out_shape=(height, width), - fill=self._mask_true, # Outside ROI = nodata (inverted compared to the usual) - default_value=self._mask_false, # Inside ROI = not nodata - transform=trf, - dtype=np.uint8, + nodata_path, nodata_exists = self._get_out_path( + f"{self.condensed_name}_nodata_{int(width)}x{int(height)}.npy" ) + if not nodata_exists: + LOGGER.debug("Rasterizing ROI mask to the extent of ") + # Rasterize nodata + nodata = features.rasterize( + nodata_det.geometry, + out_shape=(height, width), + fill=self._mask_true, # Outside ROI = nodata (inverted compared to the usual) + default_value=self._mask_false, # Inside ROI = not nodata + transform=trf, + dtype=np.uint8, + ) + np.save(str(nodata_path), nodata) + else: + nodata = np.load(str(nodata_path)) + + return nodata def _get_tile_path(self) -> AnyPathType: """