Beispiel #1
0
def test_discrete_gradient():
    """Discretized spatial gradient operator."""

    discr_space = Rn(1)
    with pytest.raises(TypeError):
        DiscreteGradient(discr_space)

    # Check result of operator with explicit summation
    # phantom data
    data = np.array([[0., 1., 2., 3., 4.],
                     [1., 2., 3., 4., 5.],
                     [2., 3., 4., 5., 6.]])

    data = np.array([[0., 1., 2., 3., 4.],
                     [0., 1., 2., 3., 4.],
                     [0., 1., 2., 3., 4.]])

    # DiscreteLp Vector
    discr_space = uniform_discr([0, 0], [6, 2.5], data.shape)
    dom_vec = discr_space.element(data)

    # computation of gradient components with helper function
    dx0, dx1 = discr_space.grid.stride
    df0 = finite_diff(data, axis=0, dx=dx0, zero_padding=True, edge_order=2)
    df1 = finite_diff(data, axis=1, dx=dx1, zero_padding=True, edge_order=2)

    # gradient
    grad = DiscreteGradient(discr_space)
    grad_vec = grad(dom_vec)
    assert len(grad_vec) == data.ndim
    assert all_equal(grad_vec[0].asarray(), df0)
    assert all_equal(grad_vec[1].asarray(), df1)

    # adjoint operator
    ran_vec = grad.range.element([data, data ** 2])
    adj_vec = grad.adjoint(ran_vec)
    lhs = ran_vec.inner(grad_vec)
    rhs = dom_vec.inner(adj_vec)
    assert lhs != 0
    assert rhs != 0
    assert lhs == rhs

    # higher dimensional arrays
    lin_size = 3
    for ndim in range(1, 6):

        # DiscreteLp Vector
        discr_space = uniform_discr([0.] * ndim, [lin_size] * ndim,
                                    [lin_size] * ndim)
        dom_vec = discr_space.element(ndvolume(lin_size, ndim))

        # gradient
        grad = DiscreteGradient(discr_space)
        grad(dom_vec)
Beispiel #2
0
def test_discrete_divergence():
    """Discretized spatial divergence operator."""

    # Invalid arguments
    discr_space = Rn(1)
    with pytest.raises(TypeError):
        DiscreteDivergence(discr_space)

    # Check result of operator with explicit summation
    data = np.array([[0., 1., 2., 3., 4.],
                     [1., 2., 3., 4., 5.],
                     [2., 3., 4., 5., 6.]])

    # DiscreteLp
    discr_space = uniform_discr([0, 0], [6, 2.5], data.shape)

    # Operator instance
    div = DiscreteDivergence(discr_space)

    # Apply operator
    dom_vec = div.domain.element([data, data])
    div_dom_vec = div(dom_vec)

    # computation of divergence with helper function
    dx0, dx1 = discr_space.grid.stride
    df0 = finite_diff(data, axis=0, dx=dx0, zero_padding=True, edge_order=2)
    df1 = finite_diff(data, axis=1, dx=dx1, zero_padding=True, edge_order=2)

    assert all_equal(df0 + df1, div_dom_vec.asarray())

    # Adjoint operator
    adj_div = div.adjoint
    ran_vec = div.range.element(data ** 2)
    adj_div_ran_vec = adj_div(ran_vec)

    # Adjoint condition
    lhs = ran_vec.inner(div_dom_vec)
    rhs = dom_vec.inner(adj_div_ran_vec)
    assert lhs != 0
    assert rhs != 0
    assert almost_equal(lhs, rhs)

    # Higher dimensional arrays
    for ndim in range(1, 6):
        # DiscreteLp Vector
        lin_size = 3
        discr_space = uniform_discr([0.] * ndim, [lin_size] * ndim,
                                    [lin_size] * ndim)
        # Divergence
        div = DiscreteDivergence(discr_space)
        dom_vec = div.domain.element([ndvolume(lin_size, ndim)] * ndim)
        div(dom_vec)
Beispiel #3
0
def stir_projector_from_file(volume_file, projection_file):
    """Create a STIR projector from given template files.

    Parameters
    ----------
    volume_file : `str`
        Full file path to the STIR input file containing information on the
        volume. This is usually a '.hv' file. For STIR reasons,
        a '.v' file is also needed.
    projection_file : `str`
        Full file path to the STIR input file with information on the
        projection data. This is usually a '.hs' file. For STIR reasons,
        a '.s' file is also needed.

    Returns
    -------
    projector : `ForwardProjectorByBinWrapper`
        A STIR forward projector.
    """
    volume = stir.FloatVoxelsOnCartesianGrid.read_from_file(volume_file)

    proj_data_in = stir.ProjData.read_from_file(projection_file)
    proj_data = stir.ProjDataInMemory(proj_data_in.get_exam_info(),
                                      proj_data_in.get_proj_data_info())

    origin = volume.get_origin()
    grid_spacing = volume.get_grid_spacing()
    grid_shape = [
        volume.get_z_size(),
        volume.get_y_size(),
        volume.get_x_size()
    ]
    min_corner = [origin[1], origin[2], origin[3]]
    max_corner = [
        origin[1] + grid_spacing[1] * grid_shape[0],
        origin[2] + grid_spacing[2] * grid_shape[1],
        origin[3] + grid_spacing[3] * grid_shape[2]
    ]

    # reverse to handle STIR bug? See:
    # https://github.com/UCL/STIR/issues/7
    recon_sp = uniform_discr(min_corner,
                             max_corner,
                             grid_shape,
                             dtype='float32')

    # TODO: set correct projection space. Currently, a default grid with
    # stride (1, 1, 1) is used.
    proj_shape = proj_data.to_array().shape()
    data_sp = uniform_discr([0, 0, 0], proj_shape, proj_shape, dtype='float32')

    return ForwardProjectorByBinWrapper(recon_sp, data_sp, volume, proj_data)
Beispiel #4
0
def test_discrete_gradient_cuda():
    """Discretized spatial gradient operator using CUDA."""

    # Check result of operator with explicit summation
    # phantom data
    data = np.array([[0., 1., 2., 3., 4.],
                     [1., 2., 3., 4., 5.],
                     [2., 3., 4., 5., 6.]])

    # DiscreteLp Vector
    discr_space = uniform_discr([0, 0], [6, 2.5], data.shape, impl='cuda')
    dom_vec = discr_space.element(data)

    # computation of gradient components with helper function
    dx0, dx1 = discr_space.grid.stride
    df0 = finite_diff(data, axis=0, dx=dx0, zero_padding=True, edge_order=2)
    df1 = finite_diff(data, axis=1, dx=dx1, zero_padding=True, edge_order=2)

    # gradient
    grad = DiscreteGradient(discr_space)
    grad_vec = grad(dom_vec)
    assert len(grad_vec) == data.ndim
    assert all_equal(grad_vec[0].asarray(), df0)
    assert all_equal(grad_vec[1].asarray(), df1)

    # adjoint operator
    ran_vec = grad.range.element([data, data ** 2])
    adj_vec = grad.adjoint(ran_vec)
    lhs = ran_vec.inner(grad_vec)
    rhs = dom_vec.inner(adj_vec)
    assert lhs != 0
    assert rhs != 0
    assert lhs == rhs
Beispiel #5
0
def test_discr_part_deriv_cuda():
    """Discretized partial derivative using CUDA."""

    # phantom data
    data = np.array([0., 1., 2., 3., 4., 16., 25., 36.])

    # explicit calculation of finite difference
    dfe = np.zeros_like(data)
    # interior: second-order accurate differences
    dfe[1:-1] = (data[2:] - data[:-2]) / 2.0
    # boundary: second-order accurate central differences with zero padding
    dfe[0] = data[1] / 2.0
    dfe[-1] = -data[-2] / 2.0

    # discretized space using CUDA
    discr_space = uniform_discr(0, data.size, data.shape, impl='cuda')

    # operator
    partial = DiscretePartDeriv(discr_space, zero_padding=True)

    # discretized space vector
    discr_vec = partial.domain.element(data)

    # apply operator
    partial_vec = partial(discr_vec)

    assert all_equal(partial_vec, dfe)
Beispiel #6
0
    def __init__(self, min_pt=None, max_pt=None, return_val='mu_normed'):
        """Construct the ellipses dataset.

        Parameters
        ----------
        return_val : str, optional
            Values to return. Options are

                ``'mu_normed'``
                    Normalized linear attenuation, values are in [0, 1].
                ``'mu'``
                    Linear attenuation in m^-1, values are in ~[-0.46, 81.4].
                ``'hu'``
                    Values in Hounsfield unit in [-1024, 3071].

            The default is ``'mu_normed'``.
        min_pt : [int, int], optional
            Minimum values of the lp space. Default: [-181, -181].
        max_pt : [int, int], optional
            Maximum values of the lp space. Default: [181, 181].
        """
        self.return_val = return_val
        self.shape = (362, 362)
        if min_pt is None:
            min_pt = [-self.shape[0] / 2, -self.shape[1] / 2]
        if max_pt is None:
            max_pt = [self.shape[0] / 2, self.shape[1] / 2]
        space = uniform_discr(min_pt, max_pt, self.shape, dtype=np.float32)
        with open(FILE_LIST_FILE, 'r') as json_file:
            self.dcm_files_dict = json.load(json_file)
        self.train_len = len(self.dcm_files_dict['train'])
        self.validation_len = len(self.dcm_files_dict['validation'])
        self.test_len = len(self.dcm_files_dict['test'])
        super().__init__(space=space)
Beispiel #7
0
def test_discrete_divergence_cuda():
    """Discretized spatial divergence operator using CUDA."""

    # Check result of operator with explicit summation
    # phantom data
    data = np.array([[0.0, 1.0, 2.0, 3.0, 4.0], [1.0, 2.0, 3.0, 4.0, 5.0], [2.0, 3.0, 4.0, 5.0, 6.0]])

    # DiscreteLp
    discr_space = uniform_discr([0, 0], [1.5, 10], data.shape, impl="cuda")

    # operator instance
    div = DiscreteDivergence(discr_space)

    # apply operator
    dom_vec = div.domain.element([data, data])
    div_dom_vec = div(dom_vec)

    # computation of divergence with helper function
    dx0, dx1 = discr_space.grid.stride
    df0 = finite_diff(data, axis=0, dx=dx0, zero_padding=True, edge_order=2)
    df1 = finite_diff(data, axis=1, dx=dx1, zero_padding=True, edge_order=2)

    assert all_equal(df0 + df1, div_dom_vec.asarray())

    # Adjoint operator
    adj_div = div.adjoint
    ran_vec = div.range.element(data ** 2)
    adj_div_ran_vec = adj_div(ran_vec)

    # Adjoint condition
    lhs = ran_vec.inner(div_dom_vec)
    rhs = dom_vec.inner(adj_div_ran_vec)
    assert lhs != 0
    assert rhs != 0
    assert almost_equal(lhs, rhs)
Beispiel #8
0
def stir_projector_from_file(volume_file, projection_file):
    """Create a STIR projector from given template files.

    Parameters
    ----------
    volume_file : `str`
        Full file path to the STIR input file containing information on the
        volume. This is usually a '.hv' file. For STIR reasons,
        a '.v' file is also needed.
    projection_file : `str`
        Full file path to the STIR input file with information on the
        projection data. This is usually a '.hs' file. For STIR reasons,
        a '.s' file is also needed.

    Returns
    -------
    projector : `ForwardProjectorByBinWrapper`
        A STIR forward projector.
    """
    volume = stir.FloatVoxelsOnCartesianGrid.read_from_file(volume_file)

    proj_data_in = stir.ProjData.read_from_file(projection_file)
    proj_data = stir.ProjDataInMemory(proj_data_in.get_exam_info(),
                                      proj_data_in.get_proj_data_info())

    origin = volume.get_origin()
    grid_spacing = volume.get_grid_spacing()
    grid_shape = [volume.get_z_size(),
                  volume.get_y_size(),
                  volume.get_x_size()]
    min_corner = [origin[1], origin[2], origin[3]]
    max_corner = [origin[1] + grid_spacing[1] * grid_shape[0],
                  origin[2] + grid_spacing[2] * grid_shape[1],
                  origin[3] + grid_spacing[3] * grid_shape[2]]

    # reverse to handle STIR bug? See:
    # https://github.com/UCL/STIR/issues/7
    recon_sp = uniform_discr(min_corner, max_corner, grid_shape,
                             dtype='float32')

    # TODO: set correct projection space. Currently, a default grid with
    # stride (1, 1, 1) is used.
    proj_shape = proj_data.to_array().shape()
    data_sp = uniform_discr([0, 0, 0], proj_shape, proj_shape, dtype='float32')

    return ForwardProjectorByBinWrapper(recon_sp, data_sp, volume, proj_data)
Beispiel #9
0
def test_discr_part_deriv():
    """Discretized partial derivative."""

    discr_space = Rn(1)
    with pytest.raises(TypeError):
        DiscretePartDeriv(discr_space)

    # phantom data
    data = np.array([[0., 1., 2., 3., 4.],
                     [1., 2., 3., 4., 5.],
                     [2., 3., 4., 5., 6.]])

    # explicit calculation of finite difference
    # axis: 0
    dfe0 = np.zeros_like(data)
    # interior: second-order accurate differences
    dfe0[1:-1, :] = (data[2:, :] - data[:-2, :]) / 2.0
    # boundary: second-order accurate central differences with zero padding
    dfe0[0, :] = data[1, :] / 2.0
    dfe0[-1, :] = -data[-2, :] / 2.0
    # axis: 1
    dfe1 = np.zeros_like(data)
    # interior: second-order accurate differences
    dfe1[:, 1:-1] = (data[:, 2:] - data[:, :-2]) / 2.0
    # boundary: second-order accurate central differences with zero padding
    dfe1[:, 0] = data[:, 1] / 2.0
    dfe1[:, -1] = -data[:, -2] / 2.0

    # assert `dfe0` and `dfe1` do differ
    assert (dfe0 != dfe1).any()

    # discretized space
    discr_space = uniform_discr([0, 0], [2, 1], data.shape)

    # operator
    partial_0 = DiscretePartDeriv(discr_space, axis=0, zero_padding=True)
    partial_1 = DiscretePartDeriv(discr_space, axis=1, zero_padding=True)

    # discretized space vector
    vec = partial_0.domain.element(data)

    # partial derivative
    partial_vec_0 = partial_0(vec)
    partial_vec_1 = partial_1(vec)

    assert partial_vec_0 != partial_vec_1
    assert all_equal(partial_vec_0.asarray(), dfe0)
    assert all_equal(partial_vec_1.asarray(), dfe1)

    # operator
    partial_0 = DiscretePartDeriv(discr_space, axis=1, dx=0.2, edge_order=2,
                                  zero_padding=True)

    # adjoint not implemented
    with pytest.raises(NotImplementedError):
        partial_0.adjoint
Beispiel #10
0
 def __init__(self,
              image_size=128,
              min_pt=None,
              max_pt=None,
              train_len=32000,
              validation_len=3200,
              test_len=3200,
              fixed_seeds=False):
     """
     Parameters
     ----------
     image_size : int, optional
         Number of pixels per image dimension. Default: ``128``.
     min_pt : [int, int], optional
         Minimum values of the lp space.
         Default: ``[-image_size/2, -image_size/2]``.
     max_pt : [int, int], optional
         Maximum values of the lp space.
         Default: ``[image_size/2, image_size/2]``.
     train_len : int or `None`, optional
         Length of training set. Default: ``32000``.
         If `None`, infinitely many samples could be generated.
     validation_len : int, optional
         Length of training set. Default: ``3200``.
     test_len : int, optional
         Length of test set. Default: ``3200``.
     fixed_seeds : dict or bool, optional
         Seeds to use for random generation.
         The values of the keys ``'train'``, ``'validation'`` and ``'test'``
         are used. If a seed is `None` or omitted, it is choosen randomly.
         If ``True`` is passed, the seeds
         ``fixed_seeds={'train': 42, 'validation': 2, 'test': 1}`` are used.
         If ``False`` is passed (the default), all seeds are chosen
         randomly.
     """
     self.shape = (image_size, image_size)
     if min_pt is None:
         min_pt = [-self.shape[0] / 2, -self.shape[1] / 2]
     if max_pt is None:
         max_pt = [self.shape[0] / 2, self.shape[1] / 2]
     space = uniform_discr(min_pt, max_pt, self.shape, dtype=np.float32)
     self.train_len = train_len
     self.validation_len = validation_len
     self.test_len = test_len
     self.random_access = False
     if isinstance(fixed_seeds, bool):
         if fixed_seeds:
             self.fixed_seeds = {'train': 42, 'validation': 2, 'test': 1}
         else:
             self.fixed_seeds = {}
     else:
         self.fixed_seeds = fixed_seeds.copy()
     super().__init__(space=space)
Beispiel #11
0
def uniform_discr_element(inp, space=None):
    """Generate an element of a ODL space from an array-like.

    Parameters
    ----------
    inp : array-like
        The input data from which the element is generated.
    space : :class:`odl.discr.DiscretizedSpace`, optional
        The space which the element will belong to. If not given, a uniform
        discretization space with cell size 1 centered around the origin is
        generated.
    """
    inp = np.asarray(inp)
    if space is None:
        space = uniform_discr(-np.array(inp.shape) / 2,
                              np.array(inp.shape) / 2, inp.shape)
    element = space.element(inp)
    return element
Beispiel #12
0
    def __init__(self, min_pt=None, max_pt=None):
        """Construct the ellipses dataset.

        Parameters
        ----------
        min_pt : [int, int], optional
            Minimum values of the lp space. Default: [-64, -64].
        max_pt : [int, int], optional
            Maximum values of the lp space. Default: [64, 64].
        """
        self.shape = (128, 128)
        if min_pt is None:
            min_pt = [-self.shape[0] / 2, -self.shape[1] / 2]
        if max_pt is None:
            max_pt = [self.shape[0] / 2, self.shape[1] / 2]
        space = uniform_discr(min_pt, max_pt, self.shape, dtype=np.float32)
        self.train_len = 50000
        self.validation_len = 5000
        self.test_len = 5000
        super().__init__(space=space)
Beispiel #13
0
    def __init__(self,
                 min_pt=None,
                 max_pt=None,
                 observation_model='post-log',
                 min_photon_count=None,
                 impl='astra_cuda'):
        """
        Parameters
        ----------
        min_pt : [float, float], optional
            Minimum values of the lp space. Default: ``[-0.13, -0.13]``.
        max_pt : [float, float], optional
            Maximum values of the lp space. Default: ``[0.13, 0.13]``.
        observation_model : {'post-log', 'pre-log'}, optional
            The observation model to use.
            The default is ``'post-log'``.

            ``'post-log'``
                Observations are linearly related to the normalized ground
                truth via the ray transform, ``obs = ray_trafo(gt) + noise``.
                Note that the scaling of the observations matches the
                normalized ground truth, i.e., they are divided by the linear
                attenuation of 3071 HU.
            ``'pre-log'``
                Observations are non-linearly related to the ground truth, as
                given by the Beer-Lambert law.
                The model is
                ``obs = exp(-ray_trafo(gt * MU(3071 HU))) + noise``,
                where `MU(3071 HU)` is the factor, by which the ground truth
                was normalized.
        min_photon_count : float, optional
            Replacement value for a simulated photon count of zero.
            If ``observation_model == 'post-log'``, a value greater than zero
            is required in order to avoid undefined values. The default is 0.1,
            both for ``'post-log'`` and ``'pre-log'`` model.
        impl : {``'skimage'``, ``'astra_cpu'``, ``'astra_cuda'``},\
                optional
            Implementation passed to :class:`odl.tomo.RayTransform` to
            construct :attr:`ray_trafo`.
        """
        global DATA_PATH
        NUM_ANGLES = 1000
        NUM_DET_PIXELS = 513
        self.shape = ((NUM_ANGLES, NUM_DET_PIXELS), (362, 362))
        self.num_elements_per_sample = 2
        if min_pt is None:
            min_pt = MIN_PT
        if max_pt is None:
            max_pt = MAX_PT
        domain = uniform_discr(min_pt, max_pt, self.shape[1], dtype=np.float32)
        if observation_model == 'post-log':
            self.post_log = True
        elif observation_model == 'pre-log':
            self.post_log = False
        else:
            raise ValueError("`observation_model` must be 'post-log' or "
                             "'pre-log', not '{}'".format(observation_model))
        if min_photon_count is None or min_photon_count <= 1.:
            self.min_photon_count = min_photon_count
        else:
            self.min_photon_count = 1.
            warn('`min_photon_count` changed from {} to 1.'.format(
                min_photon_count))
        self.train_len = 35820
        self.validation_len = 3522
        self.test_len = 3553
        self.random_access = True

        while not self.check_for_lodopab():
            print('The LoDoPaB-CT dataset could not be found under the '
                  "configured path '{}'.".format(
                      CONFIG['lodopab_dataset']['data_path']))
            print('Do you want to download it now? (y: download, n: input '
                  'other path)')
            download = input_yes_no()
            if download:
                success = download_lodopab()
                if not success:
                    raise RuntimeError('lodopab dataset not available, '
                                       'download failed')
            else:
                print('Path to LoDoPaB dataset:')
                DATA_PATH = input()
                set_config('lodopab_dataset/data_path', DATA_PATH)

        self.geometry = odl.tomo.parallel_beam_geometry(
            domain, num_angles=NUM_ANGLES, det_shape=(NUM_DET_PIXELS, ))
        range_ = uniform_discr(self.geometry.partition.min_pt,
                               self.geometry.partition.max_pt,
                               self.shape[0],
                               dtype=np.float32)
        super().__init__(space=(range_, domain))
        self.ray_trafo = self.get_ray_trafo(impl=impl)