def display_feedback(regu_match, data_match, k, model): """Display feedback window with objective function values and images""" # 2D feedback windows fig = plt.figure('Optimization', figsize=(16, 10)) plt.clf() for i in range(2): # original input images fig.add_subplot(2, 3, i + 1) plt.imshow(np.rot90(model.dc.J[i]), cmap=cm.gray) plt.axis('off') # template and match to target fig.add_subplot(2, 3, i + 4) plt.imshow(np.rot90(model.dc.Ifr[i]), cmap=cm.gray) plt.axis('off') # objective function values fig.add_subplot(2, 3, 3) colors = ['blue', 'green', 'red'] for i in range(2): dm = [x[i] for x in data_match] plt.plot(range(k), dm, color=colors[i]) # TODO: add color fig.add_subplot(2, 3, 3) plt.plot(range(k), regu_match, color=colors[-1]) # jacobian determinants fig.add_subplot(2, 3, 6) jd = la.det(vcalc.jacobian(model.get_warp(-1), model.get_current_voxel())) jd = np.log10(jd) plt.imshow(np.rot90(jd)) plt.axis('off') plt.colorbar() # show plot plt.pause(0.001) plt.draw()
def _solve_forward(self): """Shoot the geodesic forward given initial conditions""" # cut down on all the self calls dc = self.dc # check cfl condition dc.satisfy_cfl() # compute initial velocity from initial momentum dI = vcalc.gradient(dc.I[0], dc.curr_vox) m = dI * dc.P[0][..., np.newaxis] dc.v = -self._r.regularize(m) # compute magnitude of initial momentum field P0_mag = -np.prod(dc.curr_vox) * np.sum(m * dc.v) P0_mag *= dc.params['sigma'] # Initial min number of time steps due to CFL condition dc.cfl_nums[0] = abs(dc.v * dc.T[-1] / dc.curr_vox).max() i = 1 while i < dc.params['timesteps']: # Forward Euler dc.uf[i] = (dc.uf[i - 1] + (dc.t[i] - dc.t[i - 1]) * self._t.apply_transform( dc.v, dc.curr_vox, dc.uf[i - 1], vec=True)) # Advance backward transformation, ctu dc.ub[i] = fvm.solve_advection_ctu(dc.ub[i - 1], dc.v, dc.curr_vox, dc.t[i] - dc.t[i - 1], self._t) # Advance the image with group action dc.I[i] = self._t.apply_transform(dc.Ifr[0], dc.full_vox, dc.ub[i]) # Advance the momentum with coadjoint transport jdet = la.det(vcalc.jacobian(dc.ub[i], dc.curr_vox)) dc.P[i] = jdet * self._t.apply_transform(dc.P[0], dc.curr_vox, dc.ub[i]) # Compute velocity from momentum dI = vcalc.gradient(dc.I[i], dc.curr_vox) dc.v = -self._r.regularize(dI * dc.P[i][..., np.newaxis]) # Store new CFL min number of time steps dc.cfl_nums[i] = abs(dc.v * dc.T[-1] / dc.curr_vox).max() i += 1 # Compute full resolution version of final image txm = self._t.resample(dc.ub[-1], dc.curr_vox, dc.full_res, vec=True) dc.Ifr[1] = self._t.apply_transform(dc.Ifr[0], dc.full_vox, txm) # compute image matching functionals at both ends obj_func = [] obj_func.append(self._m.dist(dc.Ifr[0], dc.J[0])) obj_func.append(self._m.dist(dc.Ifr[1], dc.J[1])) # return complete evaluation of objective function return [P0_mag] + [obj_func]
def _solve_backward(self): """Solve the adjoint system backward to get gradient""" # cut down on all the self calls dc = self.dc # initialize the adjoint momentum dc.Pa = 0 # initialize the adjoint image (which contains residuals) m = self._m.residual(dc.J[-1], dc.Ifr[-1]) jdet = la.det(vcalc.jacobian(dc.uf[-1], dc.curr_vox)) mtil = jdet * self._t.apply_transform(m, dc.full_vox, dc.uf[-1]) dc.Ia = mtil # initialize adjoint velocity m = self._t.resample(m, dc.full_vox, dc.curr_res) dI = vcalc.gradient(dc.I[-1], dc.curr_vox) va = -self._r.regularize(dI * m[..., np.newaxis]) i = dc.params['timesteps'] - 2 while i > -1: # advance the adjoint momentum dIva = np.einsum('...i,...i', dI, va) # forward Euler dc.Pa -= ((dc.t[i + 1] - dc.t[i]) * self._t.apply_transform(dIva, dc.curr_vox, dc.uf[i + 1])) # advance the adjoint image Pv = va * dc.P[i + 1][..., np.newaxis] divPv = vcalc.divergence(Pv, dc.curr_vox) jdet = la.det(vcalc.jacobian(dc.uf[i + 1], dc.curr_vox)) # Forward Euler dc.Ia += ( (dc.t[i + 1] - dc.t[i]) * jdet * self._t.apply_transform(divPv, dc.curr_vox, dc.uf[i + 1])) # advance adjoint velocity Phat = self._t.apply_transform(dc.Pa, dc.curr_vox, dc.ub[i]) dPhat = vcalc.gradient(Phat, dc.curr_vox) A = dPhat * dc.P[i][..., np.newaxis] jdet = la.det(vcalc.jacobian(dc.ub[i], dc.curr_vox)) Ihat = jdet * self._t.apply_transform(dc.Ia, dc.curr_vox, dc.ub[i]) dI = vcalc.gradient(dc.I[i], dc.curr_vox) B = dI * Ihat[..., np.newaxis] va = self._r.regularize(A - B) i -= 1 # compute the gradient A = self._r.regularize(dI * dc.P[0][..., np.newaxis]) A = dc.params['sigma'] * np.einsum('...i,...i', dI, A) grad = A - dc.Pa # compute the gradient magnitude # TODO: explore speeding this up (less copies, preallocated output?) sd = np.copy(grad) ksd = self._r.regularize(np.copy(sd)[..., np.newaxis]).squeeze() grad_mag = np.prod(dc.curr_vox) * np.sum(sd * ksd) # return gradient and its magnitude return [grad, grad_mag]
# -*- coding: utf-8 -*- """ Created on Wed Dec 16 13:00:38 2015 @author: gfleishman """ import sys import numpy as np import nibabel as nib import pyrpl.image_tools.vcalc as vcalc path = sys.argv[1] wPath = sys.argv[2] vox = np.array([1., 1., 1.]) uf1 = np.empty((220, 220, 220, 3)) for i in range(3): p = path + str(i + 1) + '.nii.gz' uf1[..., i] = nib.load(p).get_data().squeeze() jd = np.linalg.det(vcalc.jacobian(uf1, vox)) jd = nib.Nifti1Image(jd, np.eye(4)) nib.save(jd, wPath)