Skip to content

Nimbus tiled inference can produce empty stitched prediction when right/bottom padding is zero #59

Description

@EspressoTonic

Summary

I ran into a reproducible failure during Nimbus inference where tiled prediction produces an empty stitched output along one spatial axis, which then fails inside OpenCV resize:

cv2.error: OpenCV(...) error: (-215:Assertion failed) !ssize.empty() in function 'resize'

The input image and segmentation mask are both valid and non-empty. The failure appears to come from an edge case in tile stitching when the computed right or bottom padding is exactly zero.

Environment

Package: Nimbus-Inference
Version observed: 0.0.5
Device: CUDA GPU
Input type: multiplexed OME-TIFF image with matching segmentation mask
Nimbus dataset magnification: 20
Nimbus model magnification: 10
Default input_shape: [1024, 1024]

What happened

A valid multiplexed image and valid cell segmentation mask failed during Nimbus inference with:

cv2.error: (-215:Assertion failed) !ssize.empty() in function 'resize'

After debugging, the image was being scaled from approximately 3532 x 3327 at dataset magnification 20 to approximately 1766 x 1663 at model magnification 10.

Because the default input_shape was [1024, 1024], Nimbus used tiled inference.

The computed tile/stitch parameters produced padding where one of the ending padding values was exactly zero. Conceptually, the problematic case looks like this:

padding = [top_pad, bottom_pad, left_pad, right_pad]
# example:
# [365, 365, 1, 0]

The stitch crop then effectively does something like:

stitched[:, :, padding[0]:-padding[1], padding[2]:-padding[3]]

When padding[3] == 0, Python evaluates -padding[3] as 0, not as “no end bound”.

So the width slice becomes equivalent to:

stitched[:, :, ..., 1:0]

That produces an empty spatial dimension. In my debugging, the prediction shape immediately before resize was effectively:

(height, width) = (1766, 0)

Then OpenCV fails because it receives an empty source image.

Expected behavior

If right or bottom padding is zero, the crop should preserve the rest of that axis instead of slicing to index 0.

For example:

h_end = None if bottom_pad == 0 else -bottom_pad
w_end = None if right_pad == 0 else -right_pad

stitched[:, :, top_pad:h_end, left_pad:w_end]

Actual behavior

When right or bottom padding is zero, the current slicing can produce an empty output axis because -0 == 0 in Python.

This causes downstream resize to fail with:

cv2.error: (-215:Assertion failed) !ssize.empty() in function 'resize'

Why this seems data-dimension dependent

The failure does not appear to be caused by corrupt input files, empty masks, missing channels, or GPU memory limits.

It seems to depend on the combination of:

  • original image dimensions
  • dataset magnification
  • model magnification
  • input_shape
  • tile padding/crop calculations
    Changing input_shape from [1024, 1024] to [2048, 2048] avoided the failure for this case because the scaled image fit without entering the same tiled stitching path. However, that is only a workaround. The underlying tiled stitching edge case can still occur for other image sizes.

Suggested fix

In the tile stitching crop logic, handle zero ending padding explicitly.

Instead of slicing with negative zero:

padding[0]:-padding[1]
padding[2]:-padding[3]

use None when the ending padding is zero:

h_end = None if padding[1] == 0 else -padding[1]
w_end = None if padding[3] == 0 else -padding[3]

stitched = stitched[:, :, padding[0]:h_end, padding[2]:w_end]

This preserves the intended crop behavior while avoiding empty slices when the end padding is zero.

Minimal synthetic reproduction idea

This should be reproducible without private data by using any valid multiplexed image and segmentation mask whose scaled dimensions and tile padding produce zero right or bottom padding.

The important condition is not the biological content, but the spatial dimensions after magnification scaling. A case similar to:

original image: about 3532 x 3327
dataset magnification: 20
model magnification: 10
scaled image: about 1766 x 1663
input_shape: [1024, 1024]

can trigger tiled inference and produce a zero ending pad on one axis.

Workaround

Using a larger input shape, for example:

input_shape = [2048, 2048]

avoided tiled inference for the observed case and allowed inference to complete successfully.

But this is not a complete fix because larger images can still enter the tiled path and hit the same zero-padding edge case.

Version information


cv2 4.11.0
nimbus_inference 0.0.5
numpy 1.26.4
pandas 2.3.3
scipy 1.15.2
session_info v1.0.1
skimage 0.25.2
tifffile 2025.5.10
torch 2.5.1

PIL 12.0.0
alpineer NA
anyio NA
asciitree NA
certifi 2026.04.22
click 8.3.3
cycler 0.12.1
cython_runtime NA
dateutil 2.9.0.post0
dill 0.3.8
exceptiongroup 1.3.1
filelock 3.29.0
h11 0.16.0
httpcore 1.0.9
httpx 0.28.1
huggingface_hub 1.13.0
idna 3.13
imagecodecs 2025.3.30
imageio 2.37.0
joblib 1.5.3
kiwisolver 1.5.0
lazy_loader 0.5
lmdb 2.2.0
lxml 5.4.0
matplotlib 3.10.9
mpl_toolkits NA
numcodecs 0.13.1
packaging 26.2
pyarrow 24.0.0
pygments 2.20.0
pyometiff 1.1.4
pyparsing 3.3.2
pytz 2026.1.post1
rich NA
six 1.17.0
torchgen NA
tqdm 4.67.3
typing_extensions NA
yaml 6.0.3
zarr 2.18.3
zoneinfo NA

Python 3.10.20 | packaged by conda-forge | (main, Mar 5 2026, 16:42:22) [GCC 14.3.0]
Linux-5.15.0-171-generic-x86_64-with-glibc2.36

Session information updated at 2026-05-04 16:07

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions