Skip to content

Commit 750e070

Browse files
committed
more doc, cleanup
1 parent 0f38bd0 commit 750e070

File tree

1 file changed

+88
-66
lines changed
  • python/thunder/imgprocessing/regmethods

1 file changed

+88
-66
lines changed

python/thunder/imgprocessing/regmethods/utils.py

+88-66
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
""" Shared utilities for registration methods """
22

3-
import numpy as np
43
from numpy import ndarray
54

65
from thunder.rdds.images import Images
@@ -110,6 +109,7 @@ def zeroBorder(vol, border=1, cval=0.0):
110109
border: scalar or tuple containing borders for each dimension
111110
cval: constant value to replace boundary voxels with, default is 0.0
112111
"""
112+
import numpy as np # sorry
113113
vol = vol.copy() # create new copy so we don't overwrite vol
114114
dims = np.array(vol.shape)
115115
if np.size(border) == 1:
@@ -130,62 +130,6 @@ def zeroBorder(vol, border=1, cval=0.0):
130130
return vol
131131

132132

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-
189133
def solveLinearized(vec, jacobian, reference, robust=False):
190134
"""Solve linearized registration problem for change in transformation parameters and weighting on reference basis.
191135
@@ -214,22 +158,100 @@ def solveLinearized(vec, jacobian, reference, robust=False):
214158
model = QuantReg(vec, A).fit(q=quantile)
215159
params = model.params
216160
else:
217-
model = np.linalg.lstsq(A, vec)
161+
from numpy.linalg import lstsq
162+
model = lstsq(A, vec)
218163
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]])
220166
return deltaTransform, coeff
221167

222168

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-
229169
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+
"""
230183
if v.ndim == 1:
184+
from numpy import prod
231185
assert dims
232186
assert v.size == np.prod(dims)
233187
return v.reshape(dims)
234188
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

Comments
 (0)