Skip to content

Commit 27598fb

Browse files
committed
feat: Add affine converter interface
1 parent f3464b5 commit 27598fb

File tree

1 file changed

+101
-0
lines changed

1 file changed

+101
-0
lines changed

fmriprep/interfaces/nitransforms.py

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
# emacs: -*- mode: python; py-indent-offset: 4; indent-tabs-mode: nil -*-
2+
# vi: set ft=python sts=4 ts=4 sw=4 et:
3+
#
4+
# Copyright 2025 The NiPreps Developers <[email protected]>
5+
#
6+
# Licensed under the Apache License, Version 2.0 (the "License");
7+
# you may not use this file except in compliance with the License.
8+
# You may obtain a copy of the License at
9+
#
10+
# http://www.apache.org/licenses/LICENSE-2.0
11+
#
12+
# Unless required by applicable law or agreed to in writing, software
13+
# distributed under the License is distributed on an "AS IS" BASIS,
14+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
# See the License for the specific language governing permissions and
16+
# limitations under the License.
17+
#
18+
# We support and encourage derived works from this project, please read
19+
# about our expectations at
20+
#
21+
# https://www.nipreps.org/community/licensing/
22+
#
23+
"""Wrappers of NiTransforms."""
24+
25+
from pathlib import Path
26+
27+
from nipype.interfaces.base import (
28+
BaseInterfaceInputSpec,
29+
File,
30+
SimpleInterface,
31+
TraitedSpec,
32+
traits,
33+
)
34+
from nipype.utils.filemanip import fname_presuffix
35+
36+
37+
class _ConvertAffineInputSpec(BaseInterfaceInputSpec):
38+
in_xfm = File(exists=True, desc='input transform piles')
39+
inverse = traits.Bool(False, usedefault=True, desc='generate inverse')
40+
in_fmt = traits.Enum('auto', 'itk', 'fs', 'fsl', usedefault=True, desc='input format')
41+
out_fmt = traits.Enum('itk', 'fs', 'fsl', usedefault=True, desc='output format')
42+
reference = File(exists=True, desc='reference file')
43+
moving = File(exists=True, desc='moving file')
44+
45+
46+
class _ConvertAffineOutputSpec(TraitedSpec):
47+
out_xfm = File(exists=True, desc='output, combined transform')
48+
out_inv = File(desc='output, combined transform')
49+
50+
51+
class ConvertAffine(SimpleInterface):
52+
"""Write a single, flattened transform file."""
53+
54+
input_spec = _ConvertAffineInputSpec
55+
output_spec = _ConvertAffineOutputSpec
56+
57+
def _run_interface(self, runtime):
58+
from nitransforms.linear import load as load_affine
59+
60+
ext = {
61+
'fs': 'lta',
62+
'itk': 'txt',
63+
'fsl': 'mat',
64+
}[self.inputs.out_fmt]
65+
66+
in_fmt = self.inputs.in_xfm
67+
if in_fmt == 'auto':
68+
in_fmt = {
69+
'.lta': 'fs',
70+
'.mat': 'fsl',
71+
'.txt': 'itk',
72+
}[Path(self.inputs.in_xfm).suffix]
73+
74+
reference = self.inputs.reference or None
75+
moving = self.inputs.moving or None
76+
affine = load_affine(self.inputs.in_xfm, fmt=in_fmt, reference=reference, moving=moving)
77+
78+
out_file = fname_presuffix(
79+
self.inputs.in_xfm,
80+
suffix=f'_fwd.{ext}',
81+
newpath=runtime.cwd,
82+
use_ext=False,
83+
)
84+
self._results['out_xfm'] = out_file
85+
affine.to_filename(out_file, moving=moving, fmt=self.inputs.out_fmt)
86+
87+
if self.inputs.inverse:
88+
inv_affine = ~affine
89+
if moving is not None:
90+
inv_affine.reference = moving
91+
92+
out_inv = fname_presuffix(
93+
self.inputs.in_xfm,
94+
suffix=f'_inv.{ext}',
95+
newpath=runtime.cwd,
96+
use_ext=False,
97+
)
98+
self._results['out_inv'] = out_inv
99+
inv_affine.to_filename(out_inv, moving=reference, fmt=self.inputs.out_fmt)
100+
101+
return runtime

0 commit comments

Comments
 (0)