def tgv(operator, data, alpha, beta, grad=None, nonneg=True, datafit=None):

    space = operator.domain

    if grad is None:
        grad = gradient(space)

    E = symm_derivative(space)
    I = odl.IdentityOperator(grad.range)

    A1 = odl.ReductionOperator(operator,
                               odl.ZeroOperator(grad.range, operator.range))
    A2 = odl.ReductionOperator(grad, -I)
    A3 = odl.ReductionOperator(odl.ZeroOperator(space, E.range), E)
    A = odl.BroadcastOperator(*[A1, A2, A3])

    F1 = get_data_fit(datafit, data)
    F2 = alpha * odl.solvers.GroupL1Norm(grad.range)
    F3 = alpha * beta * odl.solvers.GroupL1Norm(E.range)
    F = odl.solvers.SeparableSum(F1, F2, F3)

    if nonneg:
        G = odl.solvers.SeparableSum(odl.solvers.ZeroFunctional(space),
                                     odl.solvers.ZeroFunctional(E.domain))

    else:
        G = odl.solvers.SeparableSum(odl.solvers.IndicatorNonnegativity(space),
                                     odl.solvers.ZeroFunctional(E.domain))

    return G, F, A
コード例 #2
0
def mri_head_reco_op_4_channel():
    """Reconstruction operator for 4 channel MRI of a head.

    This is a T2 weighted TSE scan of a healthy volunteer.

    The reconstruction operator is the sum of the modulus of each channel.

    See the data source with DOI `10.5281/zenodo.800525`_ or the
    `project webpage`_ for further information.

    See Also
    --------
    mri_head_data_4_channel

    References
    ----------
    .. _10.5281/zenodo.800525: https://zenodo.org/record/800525
    .. _project webpage: http://imsc.uni-graz.at/mobis/internal/\
platform_aktuell.html
    """
    # To get the same rotation as in the reference article
    space = odl.uniform_discr(min_pt=[-115.2, -115.2],
                              max_pt=[115.2, 115.2],
                              shape=[256, 256],
                              dtype=complex)

    trafo = odl.trafos.FourierTransform(space)

    return odl.ReductionOperator(odl.ComplexModulus(space) * trafo.inverse, 4)
コード例 #3
0
def mri_knee_reco_op_8_channel():
    """Reconstruction operator for 8 channel MRI of a knee.

    This is an SE measurement of the knee of a healthy volunteer.

    The reconstruction operator is the sum of the modulus of each channel.

    See the data source with DOI `10.5281/zenodo.800529`_ or the
    `project webpage`_ for further information.

    See Also
    --------
    mri_knee_data_8_channel

    References
    ----------
    .. _10.5281/zenodo.800529: https://zenodo.org/record/800529
    .. _project webpage: http://imsc.uni-graz.at/mobis/internal/\
platform_aktuell.html
    """
    # To get the same rotation as in the reference article
    space = odl.uniform_discr(min_pt=[-74.88, -74.88],
                              max_pt=[74.88, 74.88],
                              shape=[192, 192],
                              dtype=complex)

    trafo = odl.trafos.FourierTransform(space)

    return odl.ReductionOperator(odl.ComplexModulus(space) * trafo.inverse, 8)
コード例 #4
0
def get_fbp(A, use_2D=False):
    if use_2D:
        fbp = odl.tomo.fbp_op(A,
                              padding=True,
                              filter_type='Hamming',
                              frequency_scaling=0.8)
    else:
        # This only works for A a BroadcastOperator, and as long as the
        # Tam-Danielsson window is a vector/matrix and not an operator
        if isinstance(A[0], odl.OperatorLeftVectorMult):
            ops = [Ai.operator for Ai in A]
            vecs = [Ai.vector for Ai in A]
        else:
            ops = A
            vecs = [
                odl.tomo.tam_danielson_window(Ai,
                                              smoothing_width=0.1,
                                              n_half_rot=3) for Ai in A
            ]

        fbp = odl.ReductionOperator(*[
            (
                odl.tomo.fbp_op(
                    opi,
                    padding=True,
                    filter_type='Hamming',  # Hann
                    frequency_scaling=0.8) * wi) for opi, wi in zip(ops, vecs)
        ])

    return fbp
コード例 #5
0
    def derivative(self, x):
        Ax = self(x)
        tmp = self.range.element()

        scale0 = self.range.zero()
        scale1 = self.range.zero()
        for I, E in zip(self.spectrum, self.energies):
            tmp.lincomb(1, Ax, -mu0(E), x[0])
            tmp.lincomb(1, tmp, -mu1(E), x[1])
            tmp.ufunc.exp(out=tmp)
            scale0.lincomb(1, scale0, I * mu0(E), tmp)
            scale1.lincomb(1, scale1, I * mu1(E), tmp)

        return odl.ReductionOperator(odl.MultiplyOperator(scale0),
                                     odl.MultiplyOperator(scale1))
コード例 #6
0
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.
g = odl.solvers.ZeroFunctional(op.domain)

# Create functionals for the dual variable

# l2-squared data matching
l2_norm = odl.solvers.L2NormSquared(ray_trafo.range).translated(data)

# The l1-norms scaled by regularization paramters
l1_norm_1 = 0.001 * odl.solvers.L1Norm(gradient.range)
l1_norm_2 = 1e-4 * odl.solvers.L1Norm(eps.range)

# Combine functionals, order must correspond to the operator K
コード例 #7
0
                              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
data_sum += odl.phantom.white_noise(data_sum.space) * scale_white_noise
コード例 #8
0
insert_discr2 = odl.uniform_discr_fromdiscr(fine_discr,
                                            min_pt=insert_min_pt2,
                                            max_pt=insert_max_pt2,
                                            cell_sides=fine_discr.cell_sides)

# Ray trafo on the insert discretization only
insert_ray_trafo1 = odl.tomo.RayTransform(insert_discr1,
                                          geometry,
                                          impl='astra_cuda')
insert_ray_trafo2 = odl.tomo.RayTransform(insert_discr2,
                                          geometry,
                                          impl='astra_cuda')

# Forward operator = sum of masked coarse ray trafo and insert ray trafo
sum_ray_trafo = odl.ReductionOperator(masked_coarse_ray_trafo,
                                      insert_ray_trafo1, insert_ray_trafo2)

# Make phantom in the product space
pspace = sum_ray_trafo.domain

reco = sum_ray_trafo.domain.zero()
data = sum_ray_trafo.range.element(sino * 1000)

# %% Reconstruction
callback = odl.solvers.CallbackShow()
odl.solvers.conjugate_gradient_normal(sum_ray_trafo,
                                      reco,
                                      data,
                                      niter=10,
                                      callback=callback)
コード例 #9
0
#    [[Dx, 0], [0, Dy], [0.5*Dy, 0.5*Dx]], range=W)
E = odl.operator.ProductSpaceOperator(
    [[Dx, 0], [0, Dy], [0.5*Dy, 0.5*Dx], [0.5*Dy, 0.5*Dx]])
W = E.range

# Create the domain of the problem, given by the reconstruction space and the
# range of the gradient on the reconstruction space.
domain = odl.ProductSpace(U, V)

# Column vector of three operators defined as:
# 1. Computes ``Ax``
# 2. Computes ``Gx - y``
# 3. Computes ``Ey``
op = odl.BroadcastOperator(
    A * odl.ComponentProjection(domain, 0),
    odl.ReductionOperator(G, odl.ScalingOperator(V, -1)),
    E * odl.ComponentProjection(domain, 1))

# Do not use the g functional, set it to zero.
g = odl.solvers.ZeroFunctional(domain)

# l2-squared data matching
l2_norm = odl.solvers.L2NormSquared(A.range).translated(data)

# parameters
alpha = 1e-1
beta = 1

# The l1-norms scaled by regularization paramters
l1_norm_1 = alpha * odl.solvers.L1Norm(V)
l1_norm_2 = alpha * beta * odl.solvers.L1Norm(W)
コード例 #10
0
# Mask
coarse_mask = multigrid.operators.MaskingOperator(coarse_discr, fine_min,
                                                  fine_max)
ray_trafo_coarse = odl.tomo.RayTransform(coarse_discr,
                                         geometry,
                                         impl='astra_cuda')
masked_ray_trafo_coarse = ray_trafo_coarse * coarse_mask

# Phantom
phantom_c = odl.phantom.shepp_logan(coarse_discr, modified=True)
phantom_f = odl.phantom.shepp_logan(fine_discr, modified=True)

# Ray trafo
ray_trafo_fine = odl.tomo.RayTransform(fine_discr, geometry, impl='astra_cuda')
pspace_ray_trafo = odl.ReductionOperator(masked_ray_trafo_coarse,
                                         ray_trafo_fine)
pspace = pspace_ray_trafo.domain

phantom = pspace.element([phantom_c, phantom_f])

data = pspace_ray_trafo([phantom_c, phantom_f])
data.show('data')

noisy_data = data + odl.phantom.white_noise(ray_trafo_coarse.range, stddev=0.1)
noisy_data.show('noisy data')

reco = pspace_ray_trafo.domain.zero()
multigrid.graphics.show_both(phantom_c, phantom_f)

# %% Reconstruction
reco_method = 'TV'
コード例 #11
0
wave_op = wave_op / wave_op.norm(estimate=True)

# 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,
コード例 #12
0
ファイル: pspace_ops_test.py プロジェクト: zwq1230/odl
# This file is part of ODL.
#
# 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
コード例 #13
0
ファイル: rat_skull_reco.py プロジェクト: kohr-h/misc
# S2 = (alpha2 * L12-Norm): X2^3 -> R, for isotropic TV

# Operators
# A = broadcasting forward operator: X1 x X2 -> Y
# G1 = spatial gradient: X1 -> X1^2
# G2 = spatial gradient: X2 -> X2^2
# B1 = G1 extended to X1 x X2, B1(f1, f2) = G1(f1)
# B2 = G2 extended to X1 x X2, B2(f1, f2) = G2(f2)

R1 = odl.tomo.RayTransform(X1, geometry)
R2 = odl.tomo.RayTransform(X2, geometry)
M = odl_multigrid.MaskingOperator(X1, roi_min_pt, roi_max_pt)

A1 = R1 * M
A2 = R2
A = odl.ReductionOperator(A1, A2)

G1 = odl.Gradient(X1, pad_mode='symmetric')
G2 = odl.Gradient(X2, pad_mode='order1')

alpha1 = 1e0
alpha2 = 5e-2
S1 = alpha1 * odl.solvers.L2NormSquared(G1.range)
S2 = alpha2 * odl.solvers.GroupL1Norm(G2.range)

B1 = G1 * odl.ComponentProjection(X1 * X2, 0)
B2 = G2 * odl.ComponentProjection(X1 * X2, 1)

D = odl.solvers.L2NormSquared(A.range).translated(y)

# We check how much we gained regarding runtimes:
コード例 #14
0
space_detail = odl.uniform_discr(detail_min_pt, detail_max_pt, detail_shape)
ray_trafo_detail = odl.tomo.RayTransform(space_detail,
                                         geometry,
                                         impl='astra_cuda')

# Masking operator for the detail part in the low-resolution space
mask = multigrid.operators.MaskingOperator(space_lowres, detail_min_pt,
                                           detail_max_pt)
ray_trafo_lowres = odl.tomo.RayTransform(space_lowres,
                                         geometry,
                                         impl='astra_cuda')
ray_trafo_lowres_masked = ray_trafo_lowres * mask

# Combine both ray transforms via summation (=reduction)
ray_trafo_combined = odl.ReductionOperator(ray_trafo_lowres_masked,
                                           ray_trafo_detail)
pspace = ray_trafo_combined.domain

# %% Reconstruction
reco_method = 'TV'
timing = True

if reco_method == 'CG':
    callback = (odl.solvers.CallbackPrintIteration(step=2)
                & odl.solvers.CallbackShow(step=2))
    niter_cg = 10
    reco = pspace.zero()
    if timing:
        callback = None
        with odl.util.Timer(reco_method):
            odl.solvers.conjugate_gradient_normal(ray_trafo_combined,