-
Notifications
You must be signed in to change notification settings - Fork 75
Transfert functions for reorient #1295
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
Open
frheault
wants to merge
35
commits into
scilus:dev_3.0.x
Choose a base branch
from
frheault:fix_init_strides
base: dev_3.0.x
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from 21 commits
Commits
Show all changes
35 commits
Select commit
Hold shift + click to select a range
3a30883
Add maximum operation in volume_math
CHrlS98 40bbc7a
Merge branch 'master' into volume-operation
CHrlS98 e83596a
Transfert functions for reorient
frheault c55dd1b
Add pathspec==0.12.* to dependencies
arnaudbore 0588741
Update paper figures with better resolution
EmmaRenauld d2558c1
Merge branch 'master' into volume-operation
CHrlS98 b4555cc
Merge pull request #1296 from EmmaRenauld/update_figs
arnaudbore 30304ea
Small fix in checking files in explore_bundleseg
EmmaRenauld 5bcba00
Option -v did nothing in compute_density_map. Added loggings
EmmaRenauld ecc0388
Verify dir exists in bundleseg
EmmaRenauld f950a6f
Value args.tractogram_clustering_thr was never used in recobundles
EmmaRenauld c6a8a5e
Merge pull request #1293 from CHrlS98/volume-operation
arnaudbore ff44804
Merge pull request #1297 from EmmaRenauld/small_changes_from_my_tests
arnaudbore 97b440b
Merge branch 'master' of https://github.com/scilus/scilpy into fix_in…
frheault 60e5dbb
Conversion to to state class
frheault dc30357
New attribtutes
frheault d4485fe
Fix tests 3.12
frheault bda03f4
fix install and tests
arnaudbore 0ba0902
Merge pull request #1299 from arnaudbore/fix_test_
arnaudbore c7c26d2
Merge branch 'master' of https://github.com/scilus/scilpy into fix_in…
frheault c260249
Added basic tests to verify SFI behaves normally
frheault efd61de
Improved tests
frheault 7eb3311
Additionnal tests and flake8
frheault a23efeb
Update src/scilpy/io/tests/test_stateful_image.py
frheault 9d420b9
Update src/scilpy/io/tests/test_stateful_image.py
frheault 917901e
Copilot comments
frheault a6c4fae
Remove hasattr check
frheault 26e4ff5
Incorporation to scripts
frheault cc1ff82
Fix conflict
frheault 262c527
Fix conflict
frheault 52d5617
allequal to allclose
frheault 44e4d3a
New voxels order modification script
frheault efbd0a8
feat: Add 4D support for voxel order modification
frheault 4cc1860
Fixes due to switch to static functions and changes apply_transform s…
frheault 37ae49b
Last fixes for comments and full testing with Arnaud
frheault File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,182 @@ | ||
| # -*- coding: utf-8 -*- | ||
|
|
||
| import nibabel as nib | ||
| import numpy as np | ||
| from dipy.io.utils import get_reference_info | ||
|
|
||
| class StatefulImage(nib.Nifti1Image): | ||
| """ | ||
| A class that extends nib.Nifti1Image to manage image orientation state. | ||
|
|
||
| This class ensures that image data loaded into memory is always in a | ||
| consistent orientation (RAS by default), while preserving the original | ||
| on-disk orientation information. When saving, the image is automatically | ||
| reverted to its original orientation, ensuring non-destructive operations. | ||
| """ | ||
|
|
||
| def __init__(self, dataobj, affine, header=None, extra=None, | ||
| file_map=None, original_affine=None, | ||
| original_dimensions=None, original_voxel_sizes=None, | ||
| original_axcodes=None): | ||
| """ | ||
| Initialize a StatefulImage object. | ||
|
|
||
| Extends the Nifti1Image constructor to store original orientation info. | ||
| """ | ||
| super().__init__(dataobj, affine, header, extra, file_map) | ||
|
|
||
| # Store original image information | ||
| self._original_affine = original_affine | ||
| self._original_dimensions = original_dimensions | ||
| self._original_voxel_sizes = original_voxel_sizes | ||
| self._original_axcodes = original_axcodes | ||
|
|
||
| @classmethod | ||
| def load(cls, filename, to_orientation='RAS'): | ||
| """ | ||
| Load a NIfTI image, store its original orientation, and reorient it. | ||
|
|
||
| Parameters | ||
| ---------- | ||
| filename : str | ||
| Path to the NIfTI file. | ||
| to_orientation : str or tuple, optional | ||
| The target orientation for the in-memory data. Default is 'RAS'. | ||
|
|
||
| Returns | ||
| ------- | ||
| StatefulImage | ||
| An instance of StatefulImage with data in the target orientation. | ||
| """ | ||
| img = nib.load(filename) | ||
|
|
||
| original_affine = img.affine.copy() | ||
| original_axcodes = nib.orientations.aff2axcodes(img.affine) | ||
| original_dims = img.header.get_data_shape() | ||
| original_voxel_sizes = img.header.get_zooms() | ||
|
|
||
| if to_orientation: | ||
| start_ornt = nib.orientations.io_orientation(img.affine) | ||
| target_ornt = nib.orientations.axcodes2ornt(to_orientation) | ||
| transform = nib.orientations.ornt_transform(start_ornt, | ||
| target_ornt) | ||
| reoriented_img = img.as_reoriented(transform) | ||
| else: | ||
| reoriented_img = img | ||
|
|
||
| return cls(reoriented_img.dataobj, reoriented_img.affine, | ||
| reoriented_img.header, original_affine=original_affine, | ||
| original_dimensions=original_dims, | ||
| original_voxel_sizes=original_voxel_sizes, | ||
| original_axcodes=original_axcodes) | ||
|
|
||
| def save(self, filename): | ||
| """ | ||
| Save the image to a file, reverting to its original orientation. | ||
|
|
||
| Parameters | ||
| ---------- | ||
| filename : str | ||
| Path to save the NIfTI file. | ||
| """ | ||
frheault marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| self.reorient_to_original() | ||
| nib.save(self, filename) | ||
|
|
||
| def reorient_to_original(self): | ||
| """ | ||
| Get a Nifti1Image object reoriented to its original orientation. | ||
|
|
||
| Returns | ||
| ------- | ||
| nib.Nifti1Image | ||
| A new Nifti1Image instance in the original orientation. | ||
| """ | ||
frheault marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
frheault marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| self.reorient(self._original_axcodes) | ||
|
|
||
|
|
||
| def reorient(self, target_axcodes): | ||
| """ | ||
| Reorient the in-memory image to a target orientation. | ||
|
|
||
| Parameters | ||
| ---------- | ||
| target_axcodes : str or tuple | ||
| The target orientation axis codes (e.g., 'LPS', ('R', 'A', 'S')). | ||
| """ | ||
| if target_axcodes is None: | ||
| raise ValueError("Target axis codes cannot be None.") | ||
|
|
||
| current_axcodes = nib.orientations.aff2axcodes(self.affine) | ||
| if current_axcodes == tuple(target_axcodes): | ||
| return | ||
|
|
||
| # Check unique are only valid axis codes | ||
| valid_codes = {'L', 'R', 'A', 'P', 'S', 'I'} | ||
| for code in target_axcodes: | ||
| if code not in valid_codes: | ||
| raise ValueError(f"Invalid axis code '{code}' in target.") | ||
|
|
||
| # Check L/R, A/P, S/I pairs are not both present | ||
| pairs = [('L', 'R'), ('A', 'P'), ('S', 'I')] | ||
| for pair in pairs: | ||
| if pair[0] in target_axcodes and pair[1] in target_axcodes: | ||
| raise ValueError(f"Conflicting axis codes '{pair[0]}' and " | ||
| f"'{pair[1]}' in target.") | ||
|
|
||
| # Check no repeated axis codes (LL, RR, etc.) | ||
| if len(set(target_axcodes)) != 3: | ||
| raise ValueError("Target axis codes must be unique.") | ||
|
|
||
| start_ornt = nib.orientations.axcodes2ornt(current_axcodes) | ||
| target_ornt = nib.orientations.axcodes2ornt(target_axcodes) | ||
| transform = nib.orientations.ornt_transform(start_ornt, target_ornt) | ||
|
|
||
| reoriented_img = self.as_reoriented(transform) | ||
| self.__init__(reoriented_img.dataobj, reoriented_img.affine, | ||
| reoriented_img.header, | ||
| original_affine=self._original_affine, | ||
| original_dimensions=self._original_dimensions, | ||
| original_voxel_sizes=self._original_voxel_sizes, | ||
| original_axcodes=self._original_axcodes) | ||
|
|
||
| def to_ras(self): | ||
| """Convenience method to reorient in-memory data to RAS.""" | ||
| self.reorient(('R', 'A', 'S')) | ||
|
|
||
| def to_lps(self): | ||
| """Convenience method to reorient in-memory data to LPS.""" | ||
| self.reorient(('L', 'P', 'S')) | ||
|
|
||
| def to_reference(self, obj): | ||
| """Reorient the in-memory image to match the orientation of a reference | ||
| object.""" | ||
frheault marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| if isinstance(obj, StatefulImage): | ||
| raise TypeError('Reference object must not be a StatefulImage.') | ||
|
|
||
| _, _, _, voxel_order = get_reference_info(obj) | ||
| self.reorient(voxel_order) | ||
|
|
||
| @property | ||
| def axcodes(self): | ||
| """Get the axis codes for the current image orientation.""" | ||
| return nib.orientations.aff2axcodes(self.affine) | ||
|
|
||
| @property | ||
| def original_axcodes(self): | ||
| """Get the axis codes for the original image orientation.""" | ||
| return self._original_axcodes | ||
|
|
||
| def __str__(self): | ||
| """Return a string representation of the image, including orientation.""" | ||
| base_str = super().__str__() | ||
| current_axcodes = self.axcodes | ||
| reoriented = current_axcodes != self._original_axcodes | ||
|
|
||
| orientation_info = ( | ||
| f"Reorientation Information:\n" | ||
| f" Original axis codes: {self._original_axcodes}\n" | ||
| f" Current axis codes: {current_axcodes}\n" | ||
| f" Reoriented from original: {reoriented}" | ||
| ) | ||
|
|
||
| return f"{base_str}\n{orientation_info}" | ||
Empty file.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.