def transl_op_fixed_vf(self, disp): deform_op = defm.LinDeformFixedDispAffine(self.embedding(disp), disp) if isinstance(self.image_space, odl.ProductSpace): deform_op = odl.DiagonalOperator(deform_op, len(self.image_space)) return deform_op
def gradient(space, sinfo=None, mode=None, gamma=1, eta=1e-2, show_sinfo=False, prefix=None): grad = odl.Gradient(space, method='forward', pad_mode='symmetric') if sinfo is not None: if mode == 'direction': norm = odl.PointwiseNorm(grad.range) grad_sinfo = grad(sinfo) ngrad_sinfo = norm(grad_sinfo) for i in range(len(grad_sinfo)): grad_sinfo[i] /= ngrad_sinfo.ufuncs.max() ngrad_sinfo = norm(grad_sinfo) ngrad_sinfo_eta = np.sqrt(ngrad_sinfo**2 + eta**2) xi = grad.range.element([g / ngrad_sinfo_eta for g in grad_sinfo]) # UGLY Id = odl.operator.IdentityOperator(grad.range) xiT = odl.PointwiseInner(grad.range, xi) xixiT = odl.BroadcastOperator(*[x * xiT for x in xi]) grad = (Id - gamma * xixiT) * grad if show_sinfo: misc.save_image(ngrad_sinfo, prefix + '_sinfo_norm') misc.save_vfield(xi.asarray(), filename=prefix + '_sinfo_xi') misc.save_vfield_cmap(filename=prefix + '_sinfo_xi_cmap') elif mode == 'location': norm = odl.PointwiseNorm(grad.range) ngrad_sinfo = norm(grad(sinfo)) ngrad_sinfo /= ngrad_sinfo.ufuncs.max() w = eta / np.sqrt(ngrad_sinfo**2 + eta**2) grad = odl.DiagonalOperator(odl.MultiplyOperator(w), 2) * grad if show_sinfo: misc.save_image(ngrad_sinfo, prefix + '_sinfo_norm') misc.save_image(w, prefix + '_w') else: grad = None return grad
detector_partition, axis=[1, 0, 0]) # Ray transform (= forward projection). We use ASTRA CUDA backend. ray_trafo = odl.tomo.RayTransform(space, geometry, impl='astra_cuda') # Create phantom ellipses = odl.phantom.shepp_logan_ellipses(ndim, modified=True)[::4] domain = odl.ProductSpace(space, len(ellipses)) phantom = domain.element( [odl.phantom.ellipse_phantom(space, [e]) for e in ellipses]) phantom = phantom.ufunc.absolute() phantom.show('phantom', indices=np.s_[:]) diagop = odl.DiagonalOperator(ray_trafo, domain.size) redop = odl.ReductionOperator(ray_trafo, domain.size) # Assemble all operators data = diagop(phantom) data_sum = redop(phantom) # Create functionals as needed f = odl.solvers.IndicatorNonnegativity(domain) alpha = 0.8 g_kl = [(1 - alpha) * odl.solvers.KullbackLeibler(ray_trafo.range, prior=d) for d in data] g_l2 = alpha * odl.solvers.L2NormSquared(ray_trafo.range).translated(data_sum) g = [odl.solvers.SeparableSum(*g_kl), g_l2]
# [-20, 20]^2 with 100 samples per dimension. space = odl.uniform_discr(min_pt=[-20, -20], max_pt=[20, 20], shape=[100, 100], dtype='float32') # Make a parallel beam geometry with flat detector # Angles: uniformly spaced, n = 300, min = 0, max = pi angle_partition = odl.uniform_partition(0, np.pi, 300) # Detector: uniformly sampled, n = 300, min = -30, max = 30 detector_partition = odl.uniform_partition(-30, 30, 300) geometry = odl.tomo.Parallel2dGeometry(angle_partition, detector_partition) # Create the forward operator, and also the vectorial forward operator. ray_trafo = odl.tomo.RayTransform(space, geometry) forward_op = odl.DiagonalOperator(ray_trafo, 2) # Create phantom where the first component contains only part of the # information in the second component. # We do this by using a sub-set of the ellipses in the well known Shepp-Logan # phantom. ellipses = odl.phantom.shepp_logan_ellipsoids(space.ndim, modified=True) phantom = forward_op.domain.element([ odl.phantom.ellipsoid_phantom(space, ellipses[:2]), odl.phantom.ellipsoid_phantom(space, ellipses) ]) phantom.show('phantom') # Create data where second channel is highly noisy (SNR = 1) data = forward_op(phantom) data[1] += odl.phantom.white_noise(forward_op.range[1]) * np.mean(data[1])
for i in range(self.domain.size): for j in range(self.domain[0].size): result[i][j] += self.arr[k][i] * x[k][j] return result @property def adjoint(self): return LamOp(self.domain, self.arr.T) data, geometry, crlb = load_fan_data(return_crlb=True) space = odl.uniform_discr([-129, -129], [129, 129], [400, 400]) ray_trafo = odl.tomo.RayTransform(space, geometry, impl='astra_cuda') A = odl.DiagonalOperator(ray_trafo, 2) grad = odl.Gradient(space) grad_vec = odl.DiagonalOperator(grad, 2) cross_terms = True c = 0.5 if not cross_terms: crlb[1, 0, ...] = 0 crlb[0, 1, ...] = 0 mat_sqrt_inv = inverse_sqrt_matrix(crlb) re = ray_trafo.range.element
# Functionals sol_space = space ** 2 l1norm_wave = odl.solvers.L1Norm(wave_op.range) l1norm_shear = odl.solvers.L1Norm(shear_op.range) data_matching = 1000 * odl.solvers.L2NormSquared(space) data_matching = data_matching.translated(noisy_data) f = odl.solvers.ZeroFunctional(sol_space) penalizer = odl.solvers.SeparableSum(0.05 * l1norm_wave, l1norm_shear) # Forward operators sum_op = odl.ReductionOperator( odl.IdentityOperator(space), 2) coeff_op = odl.DiagonalOperator(wave_op, shear_op) # Solve using douglas_rachford_pd g = [data_matching, penalizer] L = [sum_op, coeff_op] tau = 1 opnorms = [odl.power_method_opnorm(op) for op in L] sigma = [1 / opnorm ** 2 for opnorm in opnorms] callback = odl.solvers.CallbackShow(step=10) images = sol_space.zero() odl.solvers.douglas_rachford_pd( images, f, g, L, tau, sigma, niter=1000, callback=callback)
v = disp_func[1]([x,y]) plt.quiver(x,y,u,v,color='yellow') plt.axis('equal'), plt.axis([-1.3,1.3,-1.3,1.3]), # plt.axis('off'), plt.gca().set_aspect('equal', adjustable='box'), plt.savefig(folder_out + '/deformation_field.png', bbox_inches='tight', pad_inches=0, transparent=True, dpi=600,format='png') deform_op = defm.LinDeformFixedDisp(vf) deformed_gt = odl.DiagonalOperator(deform_op, deform_op)(gt) # Forward operator if unitary is True: F = ops.UnitaryRealFourierTransform(X) else: F = ops.RealFourierTransform(X) sampling_parts = sampling.split('-') if sampling_parts[0] == 'cartesian': r = int(sampling_parts[1]) sampling_op, mask = ops.get_cartesian_sampling(F.range[0], r) elif sampling_parts[0] == 'random': p = float(sampling_parts[1]) sampling_op, mask = ops.get_random_sampling(F.range[0], p) elif sampling_parts[0] == 'radial':
# # This Source Code Form is subject to the terms of the Mozilla Public License, # v. 2.0. If a copy of the MPL was not distributed with this file, You can # obtain one at https://mozilla.org/MPL/2.0/. from __future__ import division import pytest import odl from odl.util.testutils import all_almost_equal, simple_fixture base_op = simple_fixture('base_op', [ odl.IdentityOperator(odl.rn(3)), odl.BroadcastOperator(odl.IdentityOperator(odl.rn(3)), 2), odl.ReductionOperator(odl.IdentityOperator(odl.rn(3)), 2), odl.DiagonalOperator(odl.IdentityOperator(odl.rn(3)), 2), ], fmt=' {name}={value.__class__.__name__}') def test_pspace_op_init(base_op): """Test initialization with different base operators.""" A = base_op op = odl.ProductSpaceOperator([[A]]) assert op.domain == A.domain**1 assert op.range == A.range**1 op = odl.ProductSpaceOperator([[A, A]]) assert op.domain == A.domain**2 assert op.range == A.range**1
noise_proj_data = proj_data + noise # Compute the signal-to-noise ratio snr = SNR(proj_data, noise, impl='dB') # Output the signal-to-noise ratio print('snr = {!r}'.format(snr)) # Do the backprojection reconstruction backproj = xray_trafo_op.adjoint(noise_proj_data) # FFT setting for regularization shape term, 1 means 100% padding # FFT setting for data matching term, 1 means 100% padding padded_size = 2 * cptsspace.shape[0] padded_ft_shape_op = padded_ft_op(cptsspace, padded_size) vectorial_ft_shape_op = odl.DiagonalOperator(*([padded_ft_shape_op] * cptsspace.ndim)) # FFT setting for data matching term, 1 means 100% padding padded_ft_fit_op = padded_ft_op(discr_space, padded_size) vectorial_ft_fit_op = odl.DiagonalOperator(*([padded_ft_fit_op] * discr_space.ndim)) # Initialize deformation vector field momenta = vspace.zero() # Fix the sigma parameter in the kernel sigma = 4.0 # Compute Fourier trasform of the kernel function in data matching term ft_kernel_fitting = fitting_kernel_ft(kernel)
where A is the ray transform, || . ||_W is the weighted l2 norm, grad is the gradient and || . ||_* is the nuclear norm. """ import odl import numpy as np import scipy.linalg as spl from util import cov_matrix, load_data, load_fan_data, inverse_sqrt_matrix data, geometry, crlb = load_fan_data(return_crlb=True) space = odl.uniform_discr([-129, -129], [129, 129], [400, 400]) ray_trafo = odl.tomo.RayTransform(space, geometry, impl='astra_cuda') A = odl.DiagonalOperator(ray_trafo, 2) grad = odl.Gradient(space) L = odl.DiagonalOperator(grad, 2) # Compute covariance matrix and matrix power, this is slow. mat_sqrt_inv = inverse_sqrt_matrix(crlb) re = ray_trafo.range.element W = odl.ProductSpaceOperator([[ odl.MultiplyOperator(re(mat_sqrt_inv[0, 0])), odl.MultiplyOperator(re(mat_sqrt_inv[0, 1])) ], [ odl.MultiplyOperator(re(mat_sqrt_inv[1, 0])), odl.MultiplyOperator(re(mat_sqrt_inv[1, 1]))
The nuclear norm introduces a coupling between the channels, and hence we expect that edges should coincide in the optimal solution. """ import odl # Create space that the function should live in. Here, we want a vector valued # function, so we create the tuple of two spaces. space = odl.uniform_discr(0, 1, 100) pspace = odl.ProductSpace(space, 2) # Create the gradient operator on the set of vector-valued functions. # We select pad_mode='order1' so that we have a Neumann-style boundary # condition. Here we assume the gradient is continuous at the boundary. gradient = odl.Gradient(space, pad_mode='order1') pgradient = odl.DiagonalOperator(gradient, 2) # Create the data. The first part is a linear function, the second is a step # function at x=0.6 data = pspace.element([lambda x: x, lambda x: x > 0.6]) data.show('data') # Create functionals for the data discrepancy (L2 squared) and for the # regularizer (nuclear norm). The nuclear norm is defined on the range of # the vectorial gradient, which is vector valued. l2err = odl.solvers.L2NormSquared(pspace).translated(data) nuc_norm = 0.02 * odl.solvers.NuclearNorm(pgradient.range) # Assemble operators and functionals for the solver routine lin_ops = [odl.IdentityOperator(pspace), pgradient] g = [l2err, nuc_norm]
where A is the vectorial ray transform, W is the correlation matrix and grad is the gradient. """ import odl import numpy as np import scipy.linalg as spl from util import cov_matrix, load_data, load_fan_data data, geometry = load_fan_data() space = odl.uniform_discr([-129, -129], [129, 129], [200, 200]) ray_trafo = odl.tomo.RayTransform(space, geometry, impl='astra_cuda') A = odl.DiagonalOperator(ray_trafo, ray_trafo) # Compute covariance matrix and matrix power cov_mat = cov_matrix(data) w_mat = spl.fractional_matrix_power(cov_mat, -0.5) I = odl.IdentityOperator(ray_trafo.range) W = odl.ProductSpaceOperator(np.multiply(w_mat, I)) A_corr = W * A grad = odl.Gradient(space) L = odl.DiagonalOperator(grad, grad) op = A_corr.adjoint * A_corr + 10 * L.adjoint * L fbp_op = odl.tomo.fbp_op(ray_trafo, filter_type='Hann', frequency_scaling=0.7)
def inf_action(self, lie_alg_element): assert lie_alg_element in self.lie_group.associated_algebra subops = [ac.inf_action(lie_alg_element) for ac in self.actions] return odl.DiagonalOperator(*subops)
def action(self, lie_grp_element): assert lie_grp_element in self.lie_group subops = [ac.action(lie_grp_element) for ac in self.actions] return odl.DiagonalOperator(*subops)
phantom = domain.element([odl.phantom.ellipse_phantom(space, [e]) for e in ellipses]) phantom = phantom.ufunc.absolute() elif phantom_type == 'circles': ellipses = [[1, 0.8, 0.8, 0, 0, 0], [1, 0.4, 0.4, 0.2, 0.2, 0]] domain = odl.ProductSpace(space, len(ellipses)) phantom = domain.element() phantom[0] = odl.phantom.ellipse_phantom(space, [ellipses[0]]) phantom[1] = odl.phantom.ellipse_phantom(space, [ellipses[1]]) phantom[0] -= phantom[1] phantom.show('phantom', indices=np.s_[:]) diagop = odl.DiagonalOperator(ray_trafo, domain.size) redop = odl.ReductionOperator(ray_trafo, domain.size) # gradient grad = odl.Gradient(ray_trafo.domain) grad_n = odl.DiagonalOperator(grad, domain.size) # Create data data = diagop(phantom) data_sum = redop(phantom) # Add noise to data scale_poisson = 1 / np.mean(data) # 1 quanta per pixel, on avg data += odl.phantom.poisson_noise(data * scale_poisson) / scale_poisson scale_white_noise = 0.1 * np.mean(data_sum) # 10% white noise
detector_partition, axis=[1, 0, 0]) # Ray transform (= forward projection). We use ASTRA CUDA backend. ray_trafo = odl.tomo.RayTransform(space, geometry, impl='astra_cuda') # Create phantom ellipses = odl.phantom.shepp_logan_ellipses(3, modified=True)[::4] domain = odl.ProductSpace(space, len(ellipses)) phantom = domain.element( [odl.phantom.ellipse_phantom(space, [e]) for e in ellipses]) phantom.show('phantom', indices=np.s_[:]) alpha = 0.8 diagop = (1 - alpha) * odl.DiagonalOperator(ray_trafo, domain.size) redop = alpha * odl.ReductionOperator(ray_trafo, domain.size) op = odl.BroadcastOperator(diagop, redop) data = op(phantom) data.show('data') callback = (odl.solvers.CallbackShow('iterates', display_step=5) & odl.solvers.CallbackPrintIteration()) x = op.domain.zero() odl.solvers.conjugate_gradient_normal(op, x, data, niter=100, callback=callback)
# Forward operator (in the form of a broadcast operator) ray_trafo = adutils.get_ray_trafo(reco_space, use_2D=True) # Data data = adutils.get_data(ray_trafo, use_2D=True) # --- Set up the inverse problem --- # # Initialize gradient operator gradient = odl.Gradient(reco_space, method='forward') gradient_back = odl.Gradient(reco_space, method='backward') eps = odl.DiagonalOperator(gradient_back, reco_space.ndim) # Create the domain of the problem, given by the reconstruction space and the # range of the gradient on the reconstruction space. domain = odl.ProductSpace(reco_space, gradient.range) # Column vector of three operators defined as: # 1. Computes ``A(x)`` # 2. Computes ``grad(x) - y`` # 3. Computes ``eps(y)`` op = odl.BroadcastOperator( ray_trafo * odl.ComponentProjection(domain, 0), odl.ReductionOperator(gradient, odl.ScalingOperator(gradient.range, -1)), eps * odl.ComponentProjection(domain, 1)) # Do not use the g functional, set it to zero.
v = disp_func[1]([x,y]) plt.quiver(x,y,u,v,color='yellow') plt.axis('equal'), plt.axis([-1.3,1.3,-1.3,1.3]), # plt.axis('off'), plt.gca().set_aspect('equal', adjustable='box'), plt.savefig(folder_out + '/deformation_field.png', bbox_inches='tight', pad_inches=0, transparent=True, dpi=600,format='png') deform_op = defm.LinDeformFixedDisp(vf) deformed_gt = odl.DiagonalOperator(deform_op, deform_op)(gt) # Forward operator if unitary is True: F = ops.UnitaryRealFourierTransform(X) else: F = ops.RealFourierTransform(X) sampling_parts = sampling.split('-') if sampling_parts[0] == 'cartesian': r = int(sampling_parts[1]) sampling_op, mask = ops.get_cartesian_sampling(F.range[0], r) elif sampling_parts[0] == 'random': p = float(sampling_parts[1])