9
9
"""Linear transforms."""
10
10
import sys
11
11
import numpy as np
12
- from scipy import ndimage as ndi
13
12
from pathlib import Path
14
- import warnings
15
13
16
14
from nibabel .loadsave import load as loadimg
17
15
from nibabel .affines import from_matvec , voxel_sizes , obliquity
18
- from .base import TransformBase
16
+ from .base import TransformBase , _as_homogeneous
19
17
from .patched import shape_zoom_affine
20
18
from . import io
21
19
@@ -74,110 +72,6 @@ def matrix(self):
74
72
"""Access the internal representation of this affine."""
75
73
return self ._matrix
76
74
77
- def resample (self , moving , order = 3 , mode = 'constant' , cval = 0.0 , prefilter = True ,
78
- output_dtype = None ):
79
- """
80
- Resample the moving image in reference space.
81
-
82
- Parameters
83
- ----------
84
- moving : `spatialimage`
85
- The image object containing the data to be resampled in reference
86
- space
87
- order : int, optional
88
- The order of the spline interpolation, default is 3.
89
- The order has to be in the range 0-5.
90
- mode : {'reflect', 'constant', 'nearest', 'mirror', 'wrap'}, optional
91
- Determines how the input image is extended when the resamplings overflows
92
- a border. Default is 'constant'.
93
- cval : float, optional
94
- Constant value for ``mode='constant'``. Default is 0.0.
95
- prefilter: bool, optional
96
- Determines if the moving image's data array is prefiltered with
97
- a spline filter before interpolation. The default is ``True``,
98
- which will create a temporary *float64* array of filtered values
99
- if *order > 1*. If setting this to ``False``, the output will be
100
- slightly blurred if *order > 1*, unless the input is prefiltered,
101
- i.e. it is the result of calling the spline filter on the original
102
- input.
103
-
104
- Returns
105
- -------
106
- moved_image : `spatialimage`
107
- The moving imaged after resampling to reference space.
108
-
109
- Examples
110
- --------
111
- >>> a = Affine()
112
- >>> a.matrix
113
- array([[[1., 0., 0., 0.],
114
- [0., 1., 0., 0.],
115
- [0., 0., 1., 0.],
116
- [0., 0., 0., 1.]]])
117
-
118
- >>> xfm = Affine([[1, 0, 0, 4], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]])
119
- >>> ref = nb.load(testfile)
120
- >>> xfm.reference = ref
121
- >>> refdata = ref.get_fdata()
122
- >>> np.allclose(refdata, 0)
123
- True
124
-
125
- >>> refdata[5, 5, 5] = 1 # Set a one in the middle voxel
126
- >>> moving = nb.Nifti1Image(refdata, ref.affine, ref.header)
127
- >>> resampled = xfm.resample(moving, order=0).get_fdata()
128
- >>> resampled[1, 5, 5]
129
- 1.0
130
-
131
- """
132
- if output_dtype is None :
133
- output_dtype = moving .header .get_data_dtype ()
134
-
135
- try :
136
- reference = self .reference
137
- except ValueError :
138
- warnings .warn ('No reference space defined, using moving as reference' )
139
- reference = moving
140
-
141
- nvols = 1
142
- if len (moving .shape ) > 3 :
143
- nvols = moving .shape [3 ]
144
-
145
- movaff = moving .affine
146
- movingdata = np .asanyarray (moving .dataobj )
147
- if nvols == 1 :
148
- movingdata = movingdata [..., np .newaxis ]
149
-
150
- nmats = self ._matrix .shape [0 ]
151
- if nvols != nmats and nmats > 1 :
152
- raise ValueError ("""\
153
- The moving image contains {0} volumes, while the transform is defined for \
154
- {1} volumes""" .format (nvols , nmats ))
155
-
156
- singlemat = None
157
- if nmats == 1 :
158
- singlemat = np .linalg .inv (movaff ).dot (self ._matrix [0 ].dot (reference .affine ))
159
-
160
- if singlemat is not None and nvols > nmats :
161
- warnings .warn ('Resampling a 4D volume with a single affine matrix' )
162
-
163
- # Compose an index to index affine matrix
164
- moved = []
165
- for i in range (nvols ):
166
- i2imat = singlemat if singlemat is not None else np .linalg .inv (
167
- movaff ).dot (self ._matrix [i ].dot (reference .affine ))
168
- mdata = movingdata [..., i ]
169
- moved += [ndi .affine_transform (
170
- mdata , matrix = i2imat [:- 1 , :- 1 ],
171
- offset = i2imat [:- 1 , - 1 ],
172
- output_shape = reference .shape , order = order , mode = mode ,
173
- cval = cval , prefilter = prefilter )]
174
-
175
- moved_image = moving .__class__ (
176
- np .squeeze (np .stack (moved , - 1 )), reference .affine , moving .header )
177
- moved_image .header .set_data_dtype (output_dtype )
178
-
179
- return moved_image
180
-
181
75
def map (self , x , inverse = False , index = 0 ):
182
76
r"""
183
77
Apply :math:`y = f(x)`.
@@ -200,45 +94,17 @@ def map(self, x, inverse=False, index=0):
200
94
--------
201
95
>>> xfm = Affine([[1, 0, 0, 1], [0, 1, 0, 2], [0, 0, 1, 3], [0, 0, 0, 1]])
202
96
>>> xfm.map((0,0,0))
203
- array([1 , 2, 3])
97
+ array([[1. , 2. , 3.] ])
204
98
205
99
>>> xfm.map((0,0,0), inverse=True)
206
- array([-1., -2., -3.])
100
+ array([[ -1., -2., -3.] ])
207
101
208
102
"""
209
- coords = np .array (x )
210
- if coords .shape [0 ] == self ._matrix [index ].shape [0 ] - 1 :
211
- coords = np .append (coords , [1 ])
103
+ coords = _as_homogeneous (x , dim = self ._matrix [0 ].shape [0 ] - 1 ).T
212
104
affine = self ._matrix [index ]
213
-
214
105
if inverse is True :
215
106
affine = np .linalg .inv (self ._matrix [index ])
216
-
217
- return affine .dot (coords )[:- 1 ]
218
-
219
- def _map_voxel (self , index , nindex = 0 , moving = None ):
220
- """Apply ijk' = f_ijk((i, j, k)), equivalent to the above with indexes."""
221
- try :
222
- reference = self .reference
223
- except ValueError :
224
- print ('Warning: no reference space defined, using moving as reference' ,
225
- file = sys .stderr )
226
- reference = moving
227
- else :
228
- if moving is None :
229
- moving = reference
230
- finally :
231
- if reference is None :
232
- raise ValueError ('Reference and moving spaces are both undefined' )
233
-
234
- index = np .array (index )
235
- if index .shape [0 ] == self ._matrix [nindex ].shape [0 ] - 1 :
236
- index = np .append (index , [1 ])
237
-
238
- matrix = reference .affine .dot (
239
- self ._matrix [nindex ].dot (np .linalg .inv (moving .affine ))
240
- )
241
- return tuple (matrix .dot (index )[:- 1 ])
107
+ return affine .dot (coords ).T [..., :- 1 ]
242
108
243
109
def _to_hdf5 (self , x5_root ):
244
110
"""Serialize this object into the x5 file format."""
0 commit comments