Skip to content

Commit 6bb1d6b

Browse files
author
jeroenwannijn
committed
add function to fill missing bands
1 parent ed11ac1 commit 6bb1d6b

1 file changed

Lines changed: 37 additions & 2 deletions

File tree

src/eo_processing/resources/udf_catboost_inference.py

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -297,6 +297,37 @@ def create_output_xarray(probabilities: np.ndarray, input_xr: xr.DataArray) -> x
297297
)
298298

299299

300+
def fill_missing_bands(cube: xr.DataArray, required_bands: List[str], fill_value: float = np.nan) -> xr.DataArray:
301+
"""
302+
Ensure `cube` contains all `required_bands` along the 'bands' dimension.
303+
Missing bands are appended, filled with a constant `fill_value`.
304+
:param cube: Input xarray DataArray with a 'bands' dimension (plus spatial/time dims).
305+
:param required_bands: The list of band names needed.
306+
:param fill_value: Scalar value to use for missing bands (default: NaN).
307+
:return: DataArray containing all bands; newly added bands are filled with `fill_value`.
308+
"""
309+
existing = set(cube.coords["bands"].values)
310+
missing = [b for b in required_bands if b not in existing]
311+
if not missing:
312+
inspect(message=f"No missing bands")
313+
return cube
314+
315+
inspect(message=f"Missing bands: {missing}. Filling with {fill_value}.")
316+
# Get shape and coordinates excluding 'bands'
317+
sample = cube.isel(bands=0)
318+
data_shape = sample.shape
319+
dims = sample.dims
320+
coords = {dim: cube.coords[dim] for dim in dims}
321+
# Create fill array
322+
fill_data = np.full((len(missing), *data_shape), fill_value, dtype=cube.dtype)
323+
fill_array = xr.DataArray(
324+
data=fill_data,
325+
coords={"bands": missing, **coords},
326+
dims=("bands",) + dims,
327+
)
328+
return xr.concat([cube, fill_array], dim="bands")
329+
330+
300331
def apply_datacube(cube: xr.DataArray, context: Dict) -> xr.DataArray:
301332
"""
302333
Applies multiple ONNX models on a given data cube for inference. The function ensures that the input
@@ -329,11 +360,14 @@ def apply_datacube(cube: xr.DataArray, context: Dict) -> xr.DataArray:
329360

330361
# load the ONNX model and extract metadata
331362
ort_session, metadata = load_onnx_model(url, cache_dir="/tmp/cache")
332-
input_band = metadata["input_features"]
363+
input_bands = metadata["input_features"]
364+
365+
# Fill missing bands before subsetting
366+
cube = fill_missing_bands(cube, required_bands=input_bands, fill_value=0)
333367

334368
# Subset the data array using the selected indices
335369
inspect(message=f"Subsetting the feature datacube by needed input features.")
336-
subsampled_data_array = cube.sel(bands=input_band)
370+
subsampled_data_array = cube.sel(bands=input_bands)
337371

338372
# preprocess input array to numpy array in correct shape
339373
input_np, input_shape = preprocess_input(subsampled_data_array, ort_session)
@@ -354,6 +388,7 @@ def apply_datacube(cube: xr.DataArray, context: Dict) -> xr.DataArray:
354388
else:
355389
# Append to output_cube starting from the second iteration
356390
output_cube = xr.concat([output_cube, model_output_cube], dim="bands")
391+
357392
# make sure output Xarray has the correct dtype
358393
output_cube = output_cube.astype("uint8")
359394

0 commit comments

Comments
 (0)