From 8b4fa60fade5b83f5896ebf9f44a51e98063695e Mon Sep 17 00:00:00 2001 From: Oscar Esteban Date: Tue, 7 Oct 2025 11:27:28 +0200 Subject: [PATCH 1/3] maint: update nitransforms pin --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 07c44056..b66db6b4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -24,7 +24,7 @@ dependencies = [ "dipy>=1.5.0", "joblib", "nipype>=1.5.1,<2.0", - "nitransforms>=22.0.0,<24", + "nitransforms>=25.0.0", "nireports", "numpy>=1.21.3", "nest-asyncio>=1.5.1", From 7befff3ce8fd709374897d35015e8fa1133f203c Mon Sep 17 00:00:00 2001 From: Oscar Esteban Date: Tue, 7 Oct 2025 13:20:53 +0200 Subject: [PATCH 2/3] fix: update calls to ``nitransforms.resampling.apply()`` --- scripts/optimize_registration.py | 2 +- src/nifreeze/data/base.py | 3 ++- src/nifreeze/data/pet.py | 3 ++- src/nifreeze/data/utils.py | 4 +++- src/nifreeze/registration/ants.py | 3 ++- test/conftest.py | 4 ++-- test/test_integration.py | 5 +++-- test/test_registration.py | 2 +- 8 files changed, 16 insertions(+), 10 deletions(-) diff --git a/scripts/optimize_registration.py b/scripts/optimize_registration.py index 7cf38ae3..ff84ba4e 100644 --- a/scripts/optimize_registration.py +++ b/scripts/optimize_registration.py @@ -125,7 +125,7 @@ async def train_coro( index = i * len(REFERENCES) + j moving_path = tmp_folder / f"test-{index:04d}.nii.gz" - (~xfm).apply(refnii, reference=refnii).to_filename(moving_path) + nt.resampling.apply(~xfm, refnii, reference=refnii).to_filename(moving_path) _kwargs = {"output_transform_prefix": f"conversion-{index:04d}", **align_kwargs} diff --git a/src/nifreeze/data/base.py b/src/nifreeze/data/base.py index de060605..64719e9f 100644 --- a/src/nifreeze/data/base.py +++ b/src/nifreeze/data/base.py @@ -35,6 +35,7 @@ import nibabel as nb import numpy as np from nitransforms.linear import LinearTransformsMapping +from nitransforms.resampling import apply from typing_extensions import Self, TypeVarTuple, Unpack Ts = TypeVarTuple("Ts") @@ -265,7 +266,7 @@ def to_nifti( datamoving = nb.Nifti1Image(frame[0], self.affine, self.datahdr) # resample at index resampled[..., i] = np.asanyarray( - xform.apply(datamoving, order=order).dataobj, + apply(xform, datamoving, order=order).dataobj, dtype=self.dataobj.dtype, ) diff --git a/src/nifreeze/data/pet.py b/src/nifreeze/data/pet.py index 5777753a..d903f6a9 100644 --- a/src/nifreeze/data/pet.py +++ b/src/nifreeze/data/pet.py @@ -35,6 +35,7 @@ import numpy as np from nibabel.spatialimages import SpatialImage from nitransforms.linear import Affine +from nitransforms.resampling import apply from typing_extensions import Self from nifreeze.data.base import BaseDataset, _cmp, _data_repr @@ -137,7 +138,7 @@ def set_transform(self, index: int, affine: np.ndarray, order: int = 3) -> None: # resample and update orientation at index self.dataobj[..., index] = np.asanyarray( - xform.apply(dmoving, order=order).dataobj, + apply(xform, dmoving, order=order).dataobj, dtype=self.dataobj.dtype, ) diff --git a/src/nifreeze/data/utils.py b/src/nifreeze/data/utils.py index f0f128b9..576258fb 100644 --- a/src/nifreeze/data/utils.py +++ b/src/nifreeze/data/utils.py @@ -28,7 +28,9 @@ def apply_affines(nii, em_affines, output_filename=None): for ii, bvecnii in enumerate(nb.four_to_three(nii)): xfms = nt.linear.Affine(em_affines[ii]) - transformed_nii[..., ii] = np.asanyarray((~xfms).apply(bvecnii, reference=nii).dataobj) + transformed_nii[..., ii] = np.asanyarray( + nt.resampling.apply(~xfms, bvecnii, reference=nii).dataobj + ) nii_t_img = nii.__class__(transformed_nii, nii.affine, nii.header) diff --git a/src/nifreeze/registration/ants.py b/src/nifreeze/registration/ants.py index 786ec1e0..c9e3bf02 100644 --- a/src/nifreeze/registration/ants.py +++ b/src/nifreeze/registration/ants.py @@ -35,6 +35,7 @@ import numpy as np from nipype.interfaces.ants.registration import Registration from nitransforms.linear import Affine +from nitransforms.resampling import apply PARAMETERS_SINGLE_VALUE = { "collapse_output_transforms", @@ -494,7 +495,7 @@ def _run_registration( ), ) # debugging: generate aligned file for testing - xform.apply(moving_path, reference=fixed_path).to_filename( + apply(xform, moving_path, reference=fixed_path).to_filename( dirname / f"dbg_{vol_idx:05d}.nii.gz" ) diff --git a/test/conftest.py b/test/conftest.py index e8e9caf9..173f4cfe 100644 --- a/test/conftest.py +++ b/test/conftest.py @@ -113,13 +113,13 @@ def motion_data(tmp_path_factory, datadir): ) # Induce motion into dataset (i.e., apply the inverse transforms) - moved_nii = (~xfms).apply(b0nii, reference=b0nii) + moved_nii = nt.resampling.apply(~xfms, b0nii, reference=b0nii) # Save the moved dataset for debugging or further processing moved_path = tmp_path / "test.nii.gz" ground_truth_path = tmp_path / "ground_truth.nii.gz" moved_nii.to_filename(moved_path) - xfms.apply(moved_nii).to_filename(ground_truth_path) + nt.resampling.apply(xfms, moved_nii).to_filename(ground_truth_path) # Wrap into dataset object dwi_motion = DWI( diff --git a/test/test_integration.py b/test/test_integration.py index 95831099..b52202c0 100644 --- a/test/test_integration.py +++ b/test/test_integration.py @@ -49,10 +49,11 @@ def test_proximity_estimator_trivial_model(motion_data, tmp_path): ) # Uncomment to see the realigned dataset - nt.linear.LinearTransformsMapping( + xfm = nt.linear.LinearTransformsMapping( dwi_motion.motion_affines, reference=b0nii, - ).apply(moved_nii).to_filename(tmp_path / "realigned.nii.gz") + ) + nt.resampling.apply(xfm, moved_nii).to_filename(tmp_path / "realigned.nii.gz") # For each moved b0 volume for i, est in enumerate(dwi_motion.motion_affines): diff --git a/test/test_registration.py b/test/test_registration.py index 5e106d2b..4d5b30ea 100644 --- a/test/test_registration.py +++ b/test/test_registration.py @@ -58,7 +58,7 @@ def test_ANTs_config_b0(datadir, tmp_path, dataset, r_x, r_y, r_z, t_x, t_y, t_z T = from_matvec(euler2mat(x=r_x, y=r_y, z=r_z), (t_x, t_y, t_z)) xfm = nt.linear.Affine(T, reference=b0nii) - (~xfm).apply(b0nii, reference=b0nii).to_filename(moving) + nt.resampling.apply(~xfm, b0nii, reference=b0nii).to_filename(moving) registration = Registration( terminal_output="file", From 01700d1db0d6358501c965d593787741e01fc7e9 Mon Sep 17 00:00:00 2001 From: Oscar Esteban Date: Mon, 27 Oct 2025 10:30:00 +0100 Subject: [PATCH 3/3] fix: pacify mypy --- scripts/compute_nufo.py | 2 +- src/nifreeze/model/_dipy.py | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/scripts/compute_nufo.py b/scripts/compute_nufo.py index 1d59c426..10fbcf06 100755 --- a/scripts/compute_nufo.py +++ b/scripts/compute_nufo.py @@ -164,7 +164,7 @@ def main() -> None: _, brain_mask = median_otsu(dwi_data, vol_idx=[0]) dwi_data_masked = dwi_data.copy() - dwi_data_masked[~brain_mask, :] = 0 + dwi_data_masked[~brain_mask.astype(bool), :] = 0 # Create a CSD model response, ratio = auto_response_ssst( diff --git a/src/nifreeze/model/_dipy.py b/src/nifreeze/model/_dipy.py index 1ae40b6f..748de9b5 100644 --- a/src/nifreeze/model/_dipy.py +++ b/src/nifreeze/model/_dipy.py @@ -24,8 +24,6 @@ from __future__ import annotations -from typing import Any - import numpy as np from dipy.core.gradients import GradientTable from dipy.reconst.base import ReconstModel @@ -139,7 +137,7 @@ def fit( self, data: np.ndarray, gtab: GradientTable | np.ndarray, - mask: np.ndarray[bool, Any] | None = None, + mask: np.ndarray | None = None, random_state: int = 0, ) -> GPFit: """Fit method of the DTI model class