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

Issue with Origin Values Changing After Saving and Re-Loading an Image #582

Closed
tomo-akiyama opened this issue Mar 18, 2024 · 10 comments · Fixed by #588
Closed

Issue with Origin Values Changing After Saving and Re-Loading an Image #582

tomo-akiyama opened this issue Mar 18, 2024 · 10 comments · Fixed by #588
Assignees
Labels

Comments

@tomo-akiyama
Copy link

tomo-akiyama commented Mar 18, 2024

Hello,

I'm new to using ANTsPy and have encountered an issue across multiple image processing functions, including n4_bias_field_correction, ants.resample_image, and ants.denoise_image, that I'm hoping to get some insights on. After applying these functions to MRA images and saving the processed images using ants.image_write, then reloading them with ants.image_read, I've noticed that the Origin values of the images are altered.

Here is a simplified example of my workflow:

import ants

Image processing (example with n4_bias_field_correction)

img_processed = ants.n4_bias_field_correction(img, rescale_intensities=True, shrink_factor=2)

Saving the processed image

output_path = "path/to/save/image.nii"
ants.image_write(img_processed, output_path)

Reloading the processed image

img_reloaded = ants.image_read(output_path)

Observing the change

print(img_processed)

ANTsImage (RPI)
Pixel Type : float (float32)
Components : 1
Dimensions : (480, 480, 480)
Spacing : (0.5, 0.5, 0.5)
Origin : (-120.0739, 112.3748, 0.857)
Direction : [ 0.9999 0. -0.0169 -0.0021 -0.9923 -0.1241 0.0168 -0.1242 0.9921]

print(img_reloaded)

ANTsImage (RPI)
Pixel Type : float (float32)
Components : 1
Dimensions : (480, 480, 480)
Spacing : (0.5, 0.5, 0.5)
Origin : (-118.7191, 122.3064, -78.5125)
Direction : [ 0.9999 0. -0.0169 -0.0021 -0.9923 -0.1241 0.0168 -0.1242 0.9921]

This issue doesn't seem to be isolated to n4_bias_field_correction but also occurs with ants.resample_image and ants.denoise_image. Each time, the Origin values before saving and after reloading do not match, leading to alignment problems in subsequent processing steps.

Any advice, insights, or workarounds to maintain consistent Origin values through the image processing pipeline would be greatly appreciated.
Thank you very much for your time and assistance.

Best regards,

@cookpa
Copy link
Member

cookpa commented Mar 18, 2024

It is likely something particular to your data.

>>> im = ants.image_read(ants.get_data('mni'))
>>> im_n4 = ants.n4_bias_field_correction(im)
>>> ants.image_write(im_n4, 'mni_n4.nii.gz')
>>> im_n4_read = ants.image_read('mni_n4.nii.gz')
>>> im_n4_read.origin
(-90.0, 126.0, -72.0)
>>> im_n4.origin
(-90.0, 126.0, -72.0)
>>> im.origin
(-90.0, 126.0, -72.0)

I will look into it if you can share data. It's fine if you want to blank out the voxel values, an image of zeros that can reproduce the problem is OK.

Also, please let us know the details of your system and ANTsPy version

@gdevenyi
Copy link

Round trips through ITK with non-standards compliant Nifti files can cause issues.

In addition, make sure to test things with an itk compliant viewer such as itk snap to confirm things actually changed, rather than it being due to a viewer which uses different conventions.

@tomo-akiyama
Copy link
Author

@cookpa

Thank you for your response. I'm using Python 3.10.8 with antspyx version 0.3.8, mainly for VMTK purposes. The MRI data in question comes from the freely available dataset (https://brain-development.org/ixi-dataset/). I also tested with Python 3.11.2 and antspyx version 0.4.2, but encountered the same issue with the origin shifting.

IXI002-Guys-0828-MRA.nii.gz

@gdevenyi
Thank you for your suggestion. I haven't used ITK-SNAP before and encountered an error while attempting to download it, so I haven't been able to confirm the issue yet. Interestingly, when using ants.plot to overlay images, there doesn't seem to be a misalignment. However, when trying to perform calculations directly between antspy arrays, I encounter errors.
ants.plot(img_processed, overlay=img_reloaded, overlay_alpha=0.5)
4c8e3781-1869-4c34-8a0c-cb9940e4d3a0
img_processed * img_reloaded

463 if isinstance(other, ANTsImage):
464 if not image_physical_space_consistency(self, other):
--> 465 raise ValueError('images do not occupy same physical space')
466 other = other.numpy()
468 new_array = this_array * other

ValueError: images do not occupy same physical space

@ncullen93
Copy link
Member

The ants.plot function will resample the overlay to the main image if they are not in the same physical space. I guess it's a bit stricter for math operations.

@tomo-akiyama
Copy link
Author

@ncullen93
I see, so it automatically resamples to match. Considering that math operations are not working well, it does suggest that the origin changes after reloading.

@cookpa
Copy link
Member

cookpa commented Mar 19, 2024

ANTsPy 0.5.0 on Mac OS 12.7:

>>> img = ants.image_read('IXI002-Guys-0828-MRA.nii.gz')
>>> img_processed = ants.n4_bias_field_correction(img, rescale_intensities=True, shrink_factor=2)
>>> ants.image_write(img_processed, 'corrected.nii')
>>> corrected = ants.image_read('corrected.nii')
>>> corrected.origin
(-120.07392120361328, 112.37480163574219, 0.8570172786712646)
>>> img.origin
(-120.07392120361328, 112.37480163574219, 0.8570172786712646)
>>> img_processed.origin
(-120.07392120361328, 112.37480163574219, 0.8570172786712646)

0.4.2:

>>> img = ants.image_read('/Users/pcook/Downloads/IXI002-Guys-0828-MRA.nii.gz')
>>> img_processed = ants.n4_bias_field_correction(img, rescale_intensities=True, shrink_factor=2)
>>> ants.image_write(img_processed, 'corrected.nii')
>>> corrected = ants.image_read('corrected.nii')
>>> corrected.origin
(-120.07392120361328, 112.37480163574219, 0.8570172786712646)
>>> img.origin
(-120.07392120361328, 112.37480163574219, 0.8570172786712646)
>>> img_processed.origin
(-120.07392120361328, 112.37480163574219, 0.8570172786712646)

@tomo-akiyama I notice this image IXI002-Guys-0828-MRA.nii.gz has different dimensions to the one you posted earlier

ANTsImage (RPI)
Pixel Type : float (float32)
Components : 1
Dimensions : (480, 480, 480)
Spacing : (0.5, 0.5, 0.5)
Origin : (-120.0739, 112.3748, 0.857)
Direction : [ 0.9999 0. -0.0169 -0.0021 -0.9923 -0.1241 0.0168 -0.1242 0.9921]

is perhaps resampled, when I load the image, I see

>>> img
ANTsImage (RPI)
	 Pixel Type : float (float32)
	 Components : 1
	 Dimensions : (512, 512, 100)
	 Spacing    : (0.4688, 0.4688, 0.8)
	 Origin     : (-120.0739, 112.3748, 0.857)
	 Direction  : [ 0.9999  0.     -0.0169 -0.0021 -0.9923 -0.1241  0.0168 -0.1242  0.9921]

Can you please provide a single code snippet with all the commands you ran to produce the issue?

@tomo-akiyama
Copy link
Author

tomo-akiyama commented Mar 20, 2024

@cookpa

The environment I'm using is Python 3.10.8, macOS 13.6.5, and antspyx 0.4.2.

I overlooked this point. As you pointed out, for future image processing, I had resampled my data to isotropic 0.5mm resolution and additionally added padding. It seems that after adding padding and then writing and reloading the data, the origin has shifted.

While it may seem natural for the origin to shift when adding padding, I'm curious as to why simply adding padding doesn't cause the origin to shift, but writing and reloading does.
スクリーンショット 2024-03-20 12 43 11
スクリーンショット 2024-03-20 12 43 21

@cookpa
Copy link
Member

cookpa commented Mar 20, 2024

Finally, a reproducible example

>>> im = ants.image_read('/Users/pcook/Downloads/IXI002-Guys-0828-MRA.nii.gz')
>>> im
ANTsImage (RPI)
	 Pixel Type : float (float32)
	 Components : 1
	 Dimensions : (512, 512, 100)
	 Spacing    : (0.4688, 0.4688, 0.8)
	 Origin     : (-120.0739, 112.3748, 0.857)
	 Direction  : [ 0.9999  0.     -0.0169 -0.0021 -0.9923 -0.1241  0.0168 -0.1242  0.9921]

>>> padded = ants.pad_image(im, shape=(512,512,512))
>>> padded
ANTsImage (RPI)
	 Pixel Type : float (float32)
	 Components : 1
	 Dimensions : (512, 512, 512)
	 Spacing    : (0.5, 0.5, 0.5)
	 Origin     : (-120.0739, 112.3748, 0.857)
	 Direction  : [ 0.9999  0.     -0.0169 -0.0021 -0.9923 -0.1241  0.0168 -0.1242  0.9921]

>>> ants.image_write(padded, '/tmp/padded.nii.gz')
>>> pad_read = ants.image_read('/tmp/padded.nii.gz')
>>> pad_read
ANTsImage (RPI)
	 Pixel Type : float (float32)
	 Components : 1
	 Dimensions : (512, 512, 512)
	 Spacing    : (0.5, 0.5, 0.5)
	 Origin     : (-126.5826, 131.2544, -85.5906)
	 Direction  : [ 0.9999  0.     -0.0169 -0.0021 -0.9923 -0.1241  0.0168 -0.1242  0.9921]

@cookpa
Copy link
Member

cookpa commented Mar 20, 2024

Immediate workaround: write and re-read the image after padding. The updated origin will keep physical space aligned to the original.

image

@tomo-akiyama
Copy link
Author

@cookpa
I will try in your way.
Thank you.

Thank you, everybody.

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

Successfully merging a pull request may close this issue.

4 participants