Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Resize sometimes adds a dimension to LabelMap images #1023

Closed
1 task done
Bigsealion opened this issue Feb 9, 2023 · 5 comments
Closed
1 task done

Resize sometimes adds a dimension to LabelMap images #1023

Bigsealion opened this issue Feb 9, 2023 · 5 comments
Labels
question Further information is requested

Comments

@Bigsealion
Copy link

Is there an existing issue for this?

  • I have searched the existing issues

Bug summary

After re-storing the tio.DATA and applying tio.Resize, the following error occurs

But I have done the same for many images and only this one has an error

For a subject with ["img", "mask"], resized image shape is (320, 320, 112) but mask shape is (320, 320, 113)

There is already a similar issue but I will provide a sample data

img
mask

Code for reproduction

# 2023.02.09 tio resize bug test
import torchio as tio
import os

# set parameters
source_dir = "source_dir"

img_path = os.path.join(source_dir, "img1.nii.gz")
mask_path = os.path.join(source_dir, "mask1.nii.gz")

tar_shape = (320, 320, 112)

# load as tio, and get transform
# my outputs is: torchio version: 0.18.71
print("torchio version: {}".format(tio.__version__))

subj_tio = tio.Subject(
    img=tio.ScalarImage(img_path),
    mask=tio.LabelMap(mask_path),
)

transform = tio.Compose([
    tio.Resize(target_shape=tar_shape)
])

# remove 0 board, and replace raw tio.DATA
nz = subj_tio["img"][tio.DATA].nonzero()  # nz means non-zeros
ind = (
    nz[:, 0].min(), nz[:, 0].max() + 1,
    nz[:, 1].min(), nz[:, 1].max() + 1,
    nz[:, 2].min(), nz[:, 2].max() + 1,
    nz[:, 3].min(), nz[:, 3].max() + 1)

subj_tio["img"][tio.DATA] = subj_tio["img"][tio.DATA][ind[0]: ind[1], ind[2]: ind[3], ind[4]: ind[5], ind[6]: ind[7]]
subj_tio["mask"][tio.DATA] = subj_tio["mask"][tio.DATA][ind[0]: ind[1], ind[2]: ind[3], ind[4]: ind[5], ind[6]: ind[7]]

print("img shape: {}, mask shape: {}".format(subj_tio["img"].shape, subj_tio["mask"].shape))

# resize --------------> get ERROR
subj_tio = transform(subj_tio)

Actual outcome

For a subject with ["img", "mask"], resized image shape is (320, 320, 112) but mask shape is (320, 320, 113)

like this:
{'img': (320, 320, 112), 'mask': (320, 320, 113)}

Error messages

---------------------------------------------------------------------------
RuntimeError                              Traceback (most recent call last)
Cell In [16], line 1
----> 1 m3=transform(i)

File /gpfs/lab/liangmeng/members/liyifan/anaconda3/envs/py39/lib/python3.9/site-packages/torchio/transforms/transform.py:140, in Transform.__call__(self, data)
    138     subject = copy.copy(subject)
    139 with np.errstate(all='raise', under='ignore'):
--> 140     transformed = self.apply_transform(subject)
    141 if self.keep is not None:
    142     for name, image in images_to_keep.items():

File /gpfs/lab/liangmeng/members/liyifan/anaconda3/envs/py39/lib/python3.9/site-packages/torchio/transforms/augmentation/composition.py:47, in Compose.apply_transform(self, subject)
     45 def apply_transform(self, subject: Subject) -> Subject:
     46     for transform in self.transforms:
---> 47         subject = transform(subject)
     48     return subject

File /gpfs/lab/liangmeng/members/liyifan/anaconda3/envs/py39/lib/python3.9/site-packages/torchio/transforms/transform.py:140, in Transform.__call__(self, data)
    138     subject = copy.copy(subject)
    139 with np.errstate(all='raise', under='ignore'):
--> 140     transformed = self.apply_transform(subject)
    141 if self.keep is not None:
    142     for name, image in images_to_keep.items():

File /gpfs/lab/liangmeng/members/liyifan/anaconda3/envs/py39/lib/python3.9/site-packages/torchio/transforms/preprocessing/spatial/resize.py:59, in Resize.apply_transform(self, subject)
     56 resampled = resample(subject)
     57 # Sometimes, the output shape is one voxel too large
     58 # Probably because Resample uses np.ceil to compute the shape
---> 59 if not resampled.spatial_shape == tuple(shape_out):
     60     message = (
     61         f'Output shape {resampled.spatial_shape}'
     62         f' != target shape {tuple(shape_out)}. Fixing with CropOrPad'
     63     )
     64     warnings.warn(message)

File /gpfs/lab/liangmeng/members/liyifan/anaconda3/envs/py39/lib/python3.9/site-packages/torchio/data/subject.py:118, in Subject.spatial_shape(self)
    104 @property
    105 def spatial_shape(self):
    106     """Return spatial shape of first image in subject.
    107 
    108     Consistency of spatial shapes across images in the subject is checked
   (...)
    116         (181, 217, 181)
    117     """
--> 118     self.check_consistent_spatial_shape()
    119     return self.get_first_image().spatial_shape

File /gpfs/lab/liangmeng/members/liyifan/anaconda3/envs/py39/lib/python3.9/site-packages/torchio/data/subject.py:296, in Subject.check_consistent_spatial_shape(self)
    295 def check_consistent_spatial_shape(self) -> None:
--> 296     self.check_consistent_attribute('spatial_shape')

File /gpfs/lab/liangmeng/members/liyifan/anaconda3/envs/py39/lib/python3.9/site-packages/torchio/data/subject.py:284, in Subject.check_consistent_attribute(self, attribute, relative_tolerance, absolute_tolerance, message)
    277         if not all_close:
    278             message = message.format(
    279                 pprint.pformat({
    280                     first_image: first_attribute,
    281                     image_name: current_attribute
    282                 }),
    283             )
--> 284             raise RuntimeError(message)
    285 except TypeError:
    286     # fallback for non-numeric values
    287     values_dict = {}

RuntimeError: More than one value for "spatial_shape" found in subject images:
{'img': (320, 320, 112), 'mask': (320, 320, 113)}

Expected outcome

no error info

System info

Platform:   Linux-3.10.0-957.el7.x86_64-x86_64-with-glibc2.17
TorchIO:    0.18.71
PyTorch:    1.10.1
SimpleITK:  2.1.1 (ITK 5.2)
NumPy:      1.21.2
Python:     3.9.7 | packaged by conda-forge | (default, Sep 29 2021, 19:20:46) 
[GCC 9.4.0]
@Bigsealion Bigsealion added the bug Something isn't working label Feb 9, 2023
@fepegar
Copy link
Owner

fepegar commented Feb 11, 2023

Hi, @Bigsealion. Thanks for reporting and for sharing the data. How strange. I will investigate this.

@fepegar
Copy link
Owner

fepegar commented Feb 11, 2023

I'm getting this warning. It might be causing the issue.

WARNING: In /tmp/SimpleITK-build/ITK/Modules/IO/NIFTI/src/itkNiftiImageIO.cxx, line 1934
NiftiImageIO (0x38b4ad0): /tmp/img1.nii.gz has unexpected scales in sform

@fepegar
Copy link
Owner

fepegar commented Feb 11, 2023

That warning is raised by ITK here.

@fepegar
Copy link
Owner

fepegar commented Feb 11, 2023

image

Given that your images seem to be meant to share physical space, that their metadata is similar and that your img1 seems to be the problematic one, maybe you can use tio.CopyAffine('mask') before tio.Resize. I added it in your snippet and didn't get an error.

transform = tio.Compose([
    tio.CopyAffine('mask'),
    tio.Resize(target_shape=tar_shape)
])

Would that work for you?

@fepegar fepegar added question Further information is requested and removed bug Something isn't working labels Feb 11, 2023
@Bigsealion
Copy link
Author

Thanks! It works!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question Further information is requested
Projects
None yet
Development

No branches or pull requests

2 participants