Skip to content

Add nibabel volume conversions and tests#411

Open
mccle wants to merge 8 commits into
v0.28.0devfrom
feature/nibabel_volume_conversion
Open

Add nibabel volume conversions and tests#411
mccle wants to merge 8 commits into
v0.28.0devfrom
feature/nibabel_volume_conversion

Conversation

@mccle

@mccle mccle commented May 19, 2026

Copy link
Copy Markdown
Collaborator

No description provided.

Comment thread src/highdicom/volume.py Outdated
' Casting to float64 is not possible.'
)

nifti = nib.Nifti1Image(

@mccle mccle May 19, 2026

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nibabel has several other image classes that I believe could represent a volume, listed here. Not all of them are relevant, but the MINC and MGH formats seem worth consideration. I think at the very least, we should support both Nifti1Image and Nifti2Image, meaning the to_nib method should already be changed to allow the user to specify the class to which they wish to convert. Additionally, several of these classes can accept an array, affine, and dtype exactly as the Nifti1Image class or with extremely minor changes.

However, I do not think all of the formats support the same data types. Are you interested in supporting other formats @CPBridge? If so, would it be best to group different classes into separate to_* methods or have any branching logic be included in a single to_nib method?

@mccle mccle marked this pull request as ready for review June 11, 2026 19:21

@CPBridge CPBridge left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Few suggestions

Comment thread pyproject.toml Outdated
Comment thread src/highdicom/volume.py
Comment on lines +3925 to +3932
image_class: Literal[
'Nifti1Image',
'Nifti2Image',
'MGHImage',
'Minc1Image',
'Minc2Image',
'AnalyzeImage'
] = 'Nifti1Image'

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Elsewhere in the library, we use enum.Enums for a defined set of options. I think it would be better to stick to that convention here. Literal is only useful for type checking. It does nothing at runtime.

Comment thread src/highdicom/volume.py Outdated
Comment thread src/highdicom/volume.py
self = self.astype(np.uint8)

dtype = self.dtype
image_class = getattr(nib, image_class)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would guard this with a check on the values, and issue a more helpful error message if an inappropriate value is passed. As noted above, this would probably be better handled with an enum (there are examples of this all over the library, for example the segmentation_type parameter of the Segmentation constructor)

Comment thread src/highdicom/volume.py
Comment on lines +4053 to +4054
else:
dtype_map = {}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will just cause confusion downstream I would think

@mccle mccle Jun 12, 2026

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This branch covers Minc1Image and Minc2Image, as the dtypes are all supported and do not need to be remapped. Would elif image_class in [nib.Minc1Image, nib.Minc2Image] be preferable as it is more explicit?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah okay, that's fine, I misunderstood

Comment thread src/highdicom/volume.py Outdated
Comment thread src/highdicom/volume.py Outdated
Comment thread src/highdicom/volume.py Outdated
Comment thread tests/test_nib.py
Comment on lines +34 to +36
def read_multiframe_ct_volume():
im = imread(get_testdata_file('eCT_Supplemental.dcm'))
return im.get_volume()

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's some repetition in some of these functions I think. It might make sense to factor these out into the tests/utils.py file?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, I can factor a few of these out from the sitk and itk tests as well. I believe some of them may be in the original volume tests as well.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should I also update these in this PR or keep it focused on purely nibabel and standardize these changes in a followup PR after all of the initial external dependency PRs are merged?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this PR is fine unless you think that will create problems

mccle and others added 5 commits June 12, 2026 09:04
Co-authored-by: Chris Bridge <chrisbridge44@googlemail.com>
Co-authored-by: Chris Bridge <chrisbridge44@googlemail.com>
Co-authored-by: Chris Bridge <chrisbridge44@googlemail.com>
Co-authored-by: Chris Bridge <chrisbridge44@googlemail.com>
Co-authored-by: Chris Bridge <chrisbridge44@googlemail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants