1
1
""" Shared utilities for registration methods """
2
2
3
- import numpy as np
4
3
from numpy import ndarray
5
4
6
5
from thunder .rdds .images import Images
@@ -110,6 +109,7 @@ def zeroBorder(vol, border=1, cval=0.0):
110
109
border: scalar or tuple containing borders for each dimension
111
110
cval: constant value to replace boundary voxels with, default is 0.0
112
111
"""
112
+ import numpy as np # sorry
113
113
vol = vol .copy () # create new copy so we don't overwrite vol
114
114
dims = np .array (vol .shape )
115
115
if np .size (border ) == 1 :
@@ -130,62 +130,6 @@ def zeroBorder(vol, border=1, cval=0.0):
130
130
return vol
131
131
132
132
133
- def imageGradients (im , sigma = None ):
134
- """Compute gradients of volume in each dimension using a Sobel filter.
135
-
136
- Parameters
137
- ----------
138
- im : ndarray
139
- single volume
140
- sigma : float or tuple, optional, default = None
141
- smoothing amount to apply to volume before computing gradients
142
- """
143
- from scipy .ndimage .filters import gaussian_filter , sobel
144
- if sigma is not None :
145
- im = gaussian_filter (im , sigma )
146
- grads = [sobel (im , axis = dim , mode = 'constant' ) / 8.0 for dim in xrange (im .ndim )]
147
- return grads
148
-
149
-
150
- def imageJacobian (vol , tfm , grid = None , sigma = None , normalize = True , border = 1 , order = 1 ):
151
- """Compute Jacobian of volume w.r.t. transformation parameters
152
-
153
- Args:
154
- I: volume
155
- tfm: Transform object
156
- sigma: smoothing bandwidth for gradients (None for no smoothing)
157
- normalize: Whether to normalize images before aligning.
158
- border: Number or tuple of border sizes to zero after transforming.
159
- Returns:
160
- It: vectorized version of transformed volume
161
- J: nvoxels x nparameters Jacobian matrix
162
- """
163
- # Compute gradients
164
- # Transform image and gradients
165
- # Note: does not work if we compute gradients after transforming (borders?)
166
- #It = zeroBorder(tfm.apply(I), border)
167
- #TODO(ben): check that tfm then grad works
168
- # It = transform_vol(I, tfm, grid, order=order)
169
- # grads = [transform_vol(grad, tfm, grid, order=order) for grad in grads]
170
- if grid is None :
171
- grid = GridTransformer (vol .shape )
172
- grads = imageGradients (vol , sigma )
173
- It = tfm .apply (vol , grid , order = order )
174
- It = zeroBorder (It , border )
175
- grads = [tfm .apply (grad , grid , order = order ) for grad in grads ]
176
- grads = [zeroBorder (grad , border ) for grad in grads ]
177
-
178
- if normalize :
179
- normI = np .linalg .norm (It .ravel ())
180
- if normI == 0.0 :
181
- raise ValueError ('Transform yields volume of zeroes.' )
182
- grads = [(1. / normI ) * I - (I * It ).sum () / (normI ** 3 ) * It for I in grads ]
183
- It /= normI
184
-
185
- jacobianVols = tfm .jacobian (grads , grid .homo_points )
186
- return It , jacobianVols
187
-
188
-
189
133
def solveLinearized (vec , jacobian , reference , robust = False ):
190
134
"""Solve linearized registration problem for change in transformation parameters and weighting on reference basis.
191
135
@@ -214,22 +158,100 @@ def solveLinearized(vec, jacobian, reference, robust=False):
214
158
model = QuantReg (vec , A ).fit (q = quantile )
215
159
params = model .params
216
160
else :
217
- model = np .linalg .lstsq (A , vec )
161
+ from numpy .linalg import lstsq
162
+ model = lstsq (A , vec )
218
163
params = model [0 ]
219
- deltaTransform , coeff = np .split (params , [jacobian .shape [1 ]])
164
+ from numpy import split
165
+ deltaTransform , coeff = split (params , [jacobian .shape [1 ]])
220
166
return deltaTransform , coeff
221
167
222
168
223
- def volumesToMatrix (vols ):
224
- if not isinstance (vols , list ):
225
- return v2v (vols )
226
- else :
227
- return np .column_stack ([v2v (v ) for v in vols ]).squeeze ()
228
-
229
169
def v2v (v , dims = None ):
170
+ """Convert vector to volume or volume to vector.
171
+
172
+ Parameters
173
+ ----------
174
+ v : array
175
+ volume or vectorized version of volume
176
+ dims : tuple, optional
177
+ shape of volume, must be set to reshape vectors into volumes
178
+
179
+ Returns
180
+ -------
181
+ volume if input is a vector, and vector if input is a volume
182
+ """
230
183
if v .ndim == 1 :
184
+ from numpy import prod
231
185
assert dims
232
186
assert v .size == np .prod (dims )
233
187
return v .reshape (dims )
234
188
else :
235
- return v .ravel ()
189
+ return v .ravel ()
190
+
191
+
192
+ def volumesToMatrix (vols ):
193
+ """Convert list of volumes to a matrix.
194
+
195
+ Parameters
196
+ ----------
197
+ vols : list of arrays
198
+
199
+ Returns
200
+ -------
201
+ array with size nvoxels by number of volumes
202
+ """
203
+ from numpy import column_stack
204
+ if not isinstance (vols , list ):
205
+ return v2v (vols )
206
+ else :
207
+ return column_stack ([v2v (v ) for v in vols ]).squeeze ()
208
+
209
+
210
+ def imageGradients (im , sigma = None ):
211
+ """Compute gradients of volume in each dimension using a Sobel filter.
212
+
213
+ Parameters
214
+ ----------
215
+ im : ndarray
216
+ single volume
217
+ sigma : float or tuple, optional, default = None
218
+ smoothing amount to apply to volume before computing gradients
219
+ """
220
+ from scipy .ndimage .filters import gaussian_filter , sobel
221
+ if sigma is not None :
222
+ im = gaussian_filter (im , sigma )
223
+ grads = [sobel (im , axis = dim , mode = 'constant' ) / 8.0 for dim in xrange (im .ndim )]
224
+ return grads
225
+
226
+
227
+ def imageJacobian (vol , tfm , grid = None , sigma = None , normalize = True , border = 1 , order = 1 ):
228
+ """Compute Jacobian of volume w.r.t. transformation parameters
229
+
230
+ Args:
231
+ vol: volume
232
+ tfm: Transform object
233
+ sigma: smoothing bandwidth for gradients (None for no smoothing)
234
+ normalize: Whether to normalize images before aligning.
235
+ border: Number or tuple of border sizes to zero after transforming.
236
+ order: interpolation order used by map_coordinates
237
+ Returns:
238
+ tvol : array
239
+ transformed volume
240
+ jacobianVols : list of arrays
241
+ list of volume Jacobians, one for each parameter of the transformation
242
+ """
243
+ if grid is None :
244
+ from thunder .imgprocessing .transformation import GridTransformer
245
+ grid = GridTransformer (vol .shape )
246
+ grads = imageGradients (vol , sigma )
247
+ tvol = zeroBorder (tfm .apply (vol , grid , order = order ))
248
+ grads = [zeroBorder (tfm .apply (grad , grid , order = order )) for grad in grads ]
249
+ if normalize :
250
+ norm = np .linalg .norm (tvol .ravel ())
251
+ if norm == 0.0 :
252
+ raise ValueError ('Transform yields volume of zeroes.' )
253
+ # Update gradients to reflect normalization
254
+ grads = [grad / norm - (grad * tvol ).sum () / (norm ** 3 ) * tvol for grad in grads ]
255
+ tvol /= norm
256
+ jacobianVols = tfm .jacobian (grads , grid .homo_points )
257
+ return tvol , jacobianVols
0 commit comments