Ejemplo n.º 1
0
def _padded_ft_op(space, padded_size):
    """Create zero-padding fft setting

    Parameters
    ----------
    space : the space needs to do FT
    padding_size : the percent for zero padding
    """
    padding_op = ResizingOperator(
        space, ran_shp=[padded_size for _ in range(space.ndim)])
    shifts = [not s % 2 for s in space.shape]
    ft_op = FourierTransform(padding_op.range, halfcomplex=False, shift=shifts)

    return ft_op * padding_op
Ejemplo n.º 2
0
def _padded_ft_op(space, padded_size):
    """Create zero-padding Fourier transform.

    Parameters
    ----------
    space : the space needed to do Fourier transform.
    padded_size : the padded size in each axis.

    Returns
    -------
    padded_ft_op : `operator`
        Composed operator of Fourier transform composing with padded operator.
    """
    padded_op = ResizingOperator(
        space, ran_shp=[padded_size for _ in range(space.ndim)])
    shifts = [not s % 2 for s in space.shape]
    ft_op = FourierTransform(padded_op.range,
                             halfcomplex=False,
                             shift=shifts,
                             impl='pyfftw')

    return ft_op * padded_op
Ejemplo n.º 3
0
import scipy

##%%

## Load data

space_init = odl.uniform_discr(min_pt=[-16, -16],
                               max_pt=[16, 16],
                               shape=[256, 256],
                               dtype='float32',
                               interp='linear')
fac_smooth = 0.8
template_init = odl.phantom.shepp_logan(space_init, modified=True)

padded_op = ResizingOperator(
    space_init,
    ran_shp=[int(2 * template_init.shape[0]) for _ in range(space_init.ndim)])
template = padded_op(template_init)
space = template.space

path_data = 'data/'
name_target = 'Trans2Rot'
target = np.loadtxt(path_data + name_target)

ground_truth = space.element(target).copy()

padded_op = ResizingOperator(space_init,
                             ran_shp=[
                                 int(1.2 * template_init.shape[0])
                                 for _ in range(space_init.ndim)
                             ])
Ejemplo n.º 4
0
def fbp_filter_op(ray_trafo, padding=True, filter_type='Ram-Lak',
                  frequency_scaling=1.0):
    """Create a filter operator for FBP from a `RayTransform`.

    Parameters
    ----------
    ray_trafo : `RayTransform`
        The ray transform (forward operator) whose approximate inverse should
        be computed. Its geometry has to be any of the following

        `Parallel2DGeometry` : Exact reconstruction

        `Parallel3dAxisGeometry` : Exact reconstruction

        `FanFlatGeometry` : Approximate reconstruction, correct in limit of
        fan angle = 0.

        `ConeFlatGeometry`, pitch = 0 (circular) : Approximate reconstruction,
        correct in the limit of fan angle = 0 and cone angle = 0.

        `ConeFlatGeometry`, pitch > 0 (helical) : Very approximate unless a
        `tam_danielson_window` is used. Accurate with the window.

        Other geometries: Not supported

    padding : bool, optional
        If the data space should be zero padded. Without padding, the data may
        be corrupted due to the circular convolution used. Using padding makes
        the algorithm slower.
    filter_type : string, optional
        The type of filter to be used. The options are, approximate order from
        most noise senstive to least noise sensitive: 'Ram-Lak', 'Shepp-Logan',
        'Cosine', 'Hamming' and 'Hann'.
    frequency_scaling : float, optional
        Relative cutoff frequency for the filter.
        The normalized frequencies are rescaled so that they fit into the range
        [0, frequency_scaling]. Any frequency above ``frequency_scaling`` is
        set to zero.

    Returns
    -------
    filter_op : `Operator`
        Filtering operator for FBP based on ``ray_trafo``.

    See Also
    --------
    tam_danielson_window : Windowing for helical data
    """
    impl = 'pyfftw' if PYFFTW_AVAILABLE else 'numpy'
    alen = ray_trafo.geometry.motion_params.length

    if ray_trafo.domain.ndim == 2:
        # Define ramp filter
        def fourier_filter(x):
            abs_freq = np.abs(x[1])
            norm_freq = abs_freq / np.max(abs_freq)
            filt = _fbp_filter(norm_freq, filter_type, frequency_scaling)
            scaling = 1 / (2 * alen)
            return filt * abs_freq * scaling

        # Define (padded) fourier transform
        if padding:
            # Define padding operator
            ran_shp = (ray_trafo.range.shape[0],
                       ray_trafo.range.shape[1] * 2 - 1)
            resizing = ResizingOperator(ray_trafo.range, ran_shp=ran_shp)

            fourier = FourierTransform(resizing.range, axes=1, impl=impl)
            fourier = fourier * resizing
        else:
            fourier = FourierTransform(ray_trafo.range, axes=1, impl=impl)

    elif ray_trafo.domain.ndim == 3:
        # Find the direction that the filter should be taken in
        rot_dir = _rotation_direction_in_detector(ray_trafo.geometry)

        # Find what axes should be used in the fourier transform
        used_axes = (rot_dir != 0)
        if used_axes[0] and not used_axes[1]:
            axes = [1]
        elif not used_axes[0] and used_axes[1]:
            axes = [2]
        else:
            axes = [1, 2]

        # Add scaling for cone-beam case
        if hasattr(ray_trafo.geometry, 'src_radius'):
            scale = (ray_trafo.geometry.src_radius /
                     (ray_trafo.geometry.src_radius +
                      ray_trafo.geometry.det_radius))

            if ray_trafo.geometry.pitch != 0:
                # In helical geometry the whole volume is not in each
                # projection and we need to use another weighting.
                # Ideally each point in the volume effects only
                # the projections in a half rotation, so we assume that that
                # is the case.
                scale *= alen / (np.pi)
        else:
            scale = 1.0

        # Define ramp filter
        def fourier_filter(x):
            # If axis is aligned to a coordinate axis, save some memory and
            # time by using broadcasting
            if not used_axes[0]:
                abs_freq = np.abs(rot_dir[1] * x[2])
            elif not used_axes[1]:
                abs_freq = np.abs(rot_dir[0] * x[1])
            else:
                abs_freq = np.abs(rot_dir[0] * x[1] + rot_dir[1] * x[2])
            norm_freq = abs_freq / np.max(abs_freq)
            filt = _fbp_filter(norm_freq, filter_type, frequency_scaling)
            scaling = scale / (2 * alen)
            return filt * abs_freq * scaling

        # Define (padded) fourier transform
        if padding:
            # Define padding operator
            if used_axes[0]:
                padded_shape_u = ray_trafo.range.shape[1] * 2 - 1
            else:
                padded_shape_u = ray_trafo.range.shape[1]

            if used_axes[1]:
                padded_shape_v = ray_trafo.range.shape[2] * 2 - 1
            else:
                padded_shape_v = ray_trafo.range.shape[2]

            ran_shp = (ray_trafo.range.shape[0],
                       padded_shape_u,
                       padded_shape_v)
            resizing = ResizingOperator(ray_trafo.range, ran_shp=ran_shp)

            fourier = FourierTransform(resizing.range, axes=axes, impl=impl)
            fourier = fourier * resizing
        else:
            fourier = FourierTransform(ray_trafo.range, axes=axes, impl=impl)
    else:
        raise NotImplementedError('FBP only implemented in 2d and 3d')

    # Create ramp in the detector direction
    ramp_function = fourier.range.element(fourier_filter)

    weight = 1
    if not ray_trafo.range.is_weighted:
        # Compensate for potentially unweighted range of the ray transform
        weight *= ray_trafo.range.cell_volume

    if not ray_trafo.domain.is_weighted:
        # Compensate for potentially unweighted domain of the ray transform
        weight /= ray_trafo.domain.cell_volume

    ramp_function *= weight

    # Create ramp filter via the convolution formula with fourier transforms
    return fourier.inverse * ramp_function * fourier
Ejemplo n.º 5
0
def loadimages(images):
    if images == 'jv':
        # J to V
        I1name = 'v.png'
        I0name = 'j.png'
        I0 = np.rot90(plt.imread(I0name).astype('float'), -1)
        I1 = np.rot90(plt.imread(I1name).astype('float'), -1)
        ran = (100, 100)

    elif images == 'shapes':
        I0 = 1 - plt.imread('shape1.jpeg').astype('float')[:, :, 0] / 255
        I1 = 1 - plt.imread('shape2.jpeg').astype('float')[:, :, 0] / 255
        ran = (150, 150)

    elif images == 'translation':
        I0 = np.zeros((100, 100))
        I1 = I0.copy()
        I0[30:50, 30:55] = 1
        I1[30:50, 40:65] = 1
        ran = (100, 100)

    elif images == 'square':
        I0 = np.zeros((100, 100))
        I1 = I0.copy()
        I0[40:60, 40:60] = 1
        I1[40:65, 40:75] = 1
        ran = (100, 100)

    elif images == 'shepp-logan':
        # Shepp-Logan
        rec_space = odl.uniform_discr(min_pt=[-16, -16],
                                      max_pt=[16, 16],
                                      shape=[100, 100],
                                      dtype='float32',
                                      interp='linear')
        # Create the template as the deformed Shepp-Logan phantom
        I0 = odl.phantom.transmission.shepp_logan(rec_space, modified=True)
        # Create the template for Shepp-Logan phantom
        deform_field_space = rec_space.tangent_bundle
        disp_func = [
            lambda x: 16.0 * np.sin(0.2 * np.pi * x[0] / 10.0),
            lambda x: 1 * 16.0 * np.sin(np.pi * x[1] / 16.0)
        ]
        deform_field = deform_field_space.element(disp_func)
        rec_space.element(odl.deform.linear_deform(I0,
                                                   0.2 * deform_field)).show()

        I1 = rec_space.element(odl.deform.linear_deform(
            I0, 0.2 * deform_field))
        ran = (150, 150)

    space = odl.uniform_discr(min_pt=[-16, -16],
                              max_pt=[16, 16],
                              shape=I0.shape,
                              dtype='float32',
                              interp='linear')

    # The images need to be resized in case the deformation will be too big and exceed the image boundary
    resize_op = ResizingOperator(space, ran_shp=ran)
    I0 = resize_op(I0)
    I1 = resize_op(I1)

    return I0, I1