Esempio n. 1
0
 def test_get_samples(self):
     # TODO: use dataset that is always available instead of lodopab
     if not LoDoPaBDataset.check_for_lodopab():
         return
     d = LoDoPaBDataset(impl='skimage')
     angle_indices = range(0, d.shape[0][0], 2)
     asd = AngleSubsetDataset(d, angle_indices)
     obs_arr_asd, gt_arr_asd = asd.get_samples(range(3))
     obs_arr, gt_arr = d.get_samples(range(3))
     obs_arr_subset = np.asarray(obs_arr)[:, np.asarray(angle_indices), :]
     self.assertEqual(obs_arr_asd.shape, obs_arr_subset.shape)
     self.assertEqual(gt_arr_asd.shape, gt_arr.shape)
     self.assertTrue(np.all(np.asarray(obs_arr_asd) == obs_arr_subset))
     self.assertTrue(np.all(np.asarray(gt_arr_asd) == np.asarray(gt_arr)))
Esempio n. 2
0
 def test_generator(self):
     if not LoDoPaBDataset.check_for_lodopab():
         return
     NUM_SAMPLES = 3
     d = LoDoPaBDataset(impl='skimage')
     for part in ['train', 'validation', 'test']:
         samples = [d.get_sample(i, part) for i in range(NUM_SAMPLES)]
         samples2 = [s for s in islice(d.generator(part), NUM_SAMPLES)]
         for (s_obs, s_gt), (s2_obs, s2_gt) in zip(samples, samples2):
             self.assertTrue(np.all(np.asarray(s_obs) == s2_obs))
             self.assertTrue(np.all(np.asarray(s_gt) == s2_gt))
     if d.rel_patient_ids is not None:
         d2 = LoDoPaBDataset(sorted_by_patient=True, impl='skimage')
         for part in ['train', 'validation', 'test']:
             samples = [d2.get_sample(i, part) for i in range(NUM_SAMPLES)]
             samples2 = [s for s in islice(d2.generator(part), NUM_SAMPLES)]
             for (s_obs, s_gt), (s2_obs, s2_gt) in zip(samples, samples2):
                 self.assertTrue(np.all(np.asarray(s_obs) == s2_obs))
                 self.assertTrue(np.all(np.asarray(s_gt) == s2_gt))
Esempio n. 3
0
 def test_get_samples(self):
     if not LoDoPaBDataset.check_for_lodopab():
         return
     KEY = range(420, 423)
     d = LoDoPaBDataset(impl='skimage')
     for part in ['train', 'validation', 'test']:
         samples = [d.get_sample(i, part) for i in KEY]
         samples2 = d.get_samples(KEY, part)
         for (s_obs, s_gt), s2_obs, s2_gt in zip(samples, samples2[0],
                                                 samples2[1]):
             self.assertTrue(np.all(np.asarray(s_obs) == s2_obs))
             self.assertTrue(np.all(np.asarray(s_gt) == s2_gt))
     if d.rel_patient_ids is not None:
         d2 = LoDoPaBDataset(sorted_by_patient=True, impl='skimage')
         for part in ['train', 'validation', 'test']:
             samples = [d2.get_sample(i, part) for i in KEY]
             samples2 = d2.get_samples(KEY, part)
             for (s_obs, s_gt), s2_obs, s2_gt in zip(samples, samples2[0],
                                                     samples2[1]):
                 self.assertTrue(np.all(np.asarray(s_obs) == s2_obs))
                 self.assertTrue(np.all(np.asarray(s_gt) == s2_gt))
Esempio n. 4
0
 def test_patient_ids(self):
     if not LoDoPaBDataset.check_for_lodopab():
         return
     d = LoDoPaBDataset(impl='skimage')
     if d.rel_patient_ids is not None:
         for part in ['train', 'validation', 'test']:
             self.assertEqual(len(d.rel_patient_ids[part]), d.get_len(part))
             self.assertTrue(
                 np.all(
                     np.unique(d.rel_patient_ids[part]) == range(
                         d.get_num_patients(part))))
             self.assertTrue(
                 np.all(
                     np.diff(d.rel_patient_ids[part][
                         LoDoPaBDataset.get_idx_sorted_by_patient()[part]])
                     >= 0))
         d2 = LoDoPaBDataset(sorted_by_patient=True, impl='skimage')
         REL_PATIENT_ID = 42
         ifp = d.get_indices_for_patient(REL_PATIENT_ID, part)
         ifp2 = d2.get_indices_for_patient(REL_PATIENT_ID, part)
         self.assertGreater(len(ifp), 0)
         self.assertEqual(len(ifp), len(ifp2))
         for i, i2 in zip(ifp[:3], ifp2[:3]):
             self.assertEqual(d.get_sample(i, part),
                              d2.get_sample(i2, part))
Esempio n. 5
0
def get_standard_dataset(name, **kwargs):
    """
    Return a standard dataset by name.

    The standard datasets are (currently):

        ``'ellipses'``
            A typical synthetical CT dataset with ellipse phantoms.

            `EllipsesDataset` is used as ground truth dataset, a ray
            transform with parallel beam geometry using 30 angles is applied,
            and white gaussian noise with a standard deviation of 2.5% (i.e.
            ``0.025 * mean(abs(observation))``) is added.

            The ray transform that corresponds to the (noiseless) forward
            operator is stored in the attribute `ray_trafo` of the dataset.

            In order to avoid the inverse crime, the ground truth images of
            shape (128, 128) are upscaled by bilinear interpolation to a
            resolution of (400, 400) before the ray transform is applied (whose
            discretization is different from the one of `ray_trafo`).

        ``'lodopab'``
            The LoDoPaB-CT dataset, which is documented in the
            preprint `<https://arxiv.org/abs/1910.01113>`_ hosted on
            `<https://zenodo.org/record/3384092>`_.
            It is a simulated low dose CT dataset based on real reconstructions
            from the `LIDC-IDRI
            <https://wiki.cancerimagingarchive.net/display/Public/LIDC-IDRI>`_
            dataset.

            The dataset contains 42895 pairs of images and projection data.
            For simulation, a ray transform with parallel beam geometry using
            1000 angles and 513 detector pixels is used. Poisson noise
            corresponding to 4096 incident photons per pixel before attenuation
            is applied to the projection data.

            A ray transform that corresponds to the noiseless forward operator
            is available via
            :meth:`~dival.datasets.LoDoPaBDataset.get_ray_trafo` from this
            dataset.

    Parameters
    ----------
    name : str
        Name of the dataset.
    kwargs : dict
        Keyword arguments.
        Supported parameters for the datasets are:

            ``'ellipses'``
                impl : {``'skimage'``, ``'astra_cpu'``, ``'astra_cuda'``},\
                        optional
                    Implementation passed to :class:`odl.tomo.RayTransform`
                fixed_seeds : dict or bool, optional
                    Seeds to use for random ellipse generation, passed to
                    :class:`.EllipsesDataset`.
            ``'lodopab'``
                observation_model : {``'post-log'``, ``'pre-log'``}, optional
                    The observation model to use. Default is ``'post-log'``.
                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.

    Returns
    -------
    dataset : :class:`.Dataset`
        The standard dataset.
        It has an attribute `standard_dataset_name` that stores its name.
    """
    name = name.lower()
    if name == 'ellipses':
        fixed_seeds = kwargs.pop('fixed_seeds', False)
        ellipses_dataset = EllipsesDataset(image_size=128,
                                           fixed_seeds=fixed_seeds)

        NUM_ANGLES = 30
        # image shape for simulation
        IM_SHAPE = (400, 400)  # images will be scaled up from (128, 128)

        reco_space = ellipses_dataset.space
        space = odl.uniform_discr(min_pt=reco_space.min_pt,
                                  max_pt=reco_space.max_pt,
                                  shape=IM_SHAPE,
                                  dtype=np.float32)

        reco_geometry = odl.tomo.parallel_beam_geometry(reco_space,
                                                        num_angles=NUM_ANGLES)
        geometry = odl.tomo.parallel_beam_geometry(
            space,
            num_angles=NUM_ANGLES,
            det_shape=reco_geometry.detector.shape)

        impl = kwargs.pop('impl', 'astra_cuda')
        ray_trafo = odl.tomo.RayTransform(space, geometry, impl=impl)

        def get_reco_ray_trafo(impl=impl):
            return odl.tomo.RayTransform(reco_space, reco_geometry, impl=impl)

        reco_ray_trafo = get_reco_ray_trafo(impl=impl)

        class _ResizeOperator(odl.Operator):
            def __init__(self):
                super().__init__(reco_space, space)

            def _call(self, x, out):
                out.assign(space.element(resize(x, IM_SHAPE, order=1)))

        # forward operator
        resize_op = _ResizeOperator()
        forward_op = ray_trafo * resize_op

        dataset = ellipses_dataset.create_pair_dataset(forward_op=forward_op,
                                                       noise_type='white',
                                                       noise_kwargs={
                                                           'relative_stddev':
                                                           True,
                                                           'stddev': 0.025
                                                       },
                                                       noise_seeds={
                                                           'train': 1,
                                                           'validation': 2,
                                                           'test': 3
                                                       })

        dataset.get_ray_trafo = get_reco_ray_trafo
        dataset.ray_trafo = reco_ray_trafo

    elif name == 'lodopab':
        dataset = LoDoPaBDataset(**kwargs)

    else:
        raise ValueError(
            "unknown dataset '{}'. Known standard datasets are {}".format(
                name, STANDARD_DATASET_NAMES))

    dataset.standard_dataset_name = name
    return dataset
Esempio n. 6
0
    help='noise model: mse, uncalib, gaussian, poisson, poissongaussian')
parser.add_argument('--reg',
                    type=float,
                    default=10,
                    help='regularization weight on prior std. dev.')

args = parser.parse_args()

# %% [markdown]
# ### Load Data

# %%
# update dival config file with correct path to data
dival.config.set_config('/lodopab_dataset/data_path', args.path)

dataset = LoDoPaBDataset(observation_model=args.obsmodel, impl='astra_cpu')
fbp = FBPReconstructor(dataset.get_ray_trafo(impl='astra_cpu'))

# compute padded (height, width) for sinograms to ensure they are multiples of 32
height, width = dataset.shape[0]
input_height = (height // 32 + 1) * 32 + 256
input_width = (width // 32 + 1) * 32 + 256
#input_height = (height // args.crop + 1) * args.crop
#input_width = (width // args.crop + 1) * args.crop
#pad_bottom = input_height - height
#pad_right = input_width - width
hdiff = input_height - height
wdiff = input_width - width
pad_top = hdiff // 2
pad_left = wdiff // 2
pad_bottom = hdiff - hdiff // 2
Esempio n. 7
0
def get_standard_dataset(name, **kwargs):
    """
    Return a standard dataset by name.

    The standard datasets are (currently):

        ``'ellipses'``
            A typical synthetical CT dataset with ellipse phantoms.

            `EllipsesDataset` is used as ground truth dataset, a ray
            transform with parallel beam geometry using 30 angles is applied,
            and white gaussian noise with a standard deviation of 2.5% (i.e.
            ``0.025 * mean(abs(observation))``) is added.

            In order to avoid the inverse crime, the ground truth images of
            shape (128, 128) are upscaled by bilinear interpolation to a
            resolution of (400, 400) before the ray transform is applied (whose
            discretization is different from the one of :attr:`ray_trafo`).
            
            Attributes of the returned dataset:
                `ray_trafo` : :class:`odl.tomo.RayTransform`
                    Ray transform corresponding to the noiseless forward
                    operator.
                ``get_ray_trafo(**kwargs)`` : function
                    Function that returns a ray transform corresponding to the
                    noiseless forward operator. Keyword arguments (e.g. `impl`)
                    are forwarded to the :class:`RayTransform` constructor.

        ``'lodopab'``
            The LoDoPaB-CT dataset, which is documented in the Data Descriptor
            article `<https://www.nature.com/articles/s41597-021-00893-z>`_ and
            hosted on `<https://zenodo.org/record/3384092>`_.
            It is a simulated low dose CT dataset based on real reconstructions
            from the `LIDC-IDRI
            <https://wiki.cancerimagingarchive.net/display/Public/LIDC-IDRI>`_
            dataset.

            The dataset contains 42895 pairs of images and projection data.
            For simulation, a ray transform with parallel beam geometry using
            1000 angles and 513 detector pixels is used. Poisson noise
            corresponding to 4096 incident photons per pixel before attenuation
            is applied to the projection data.
            
            Attributes of the returned dataset:
                `ray_trafo` : :class:`odl.tomo.RayTransform`
                    Ray transform corresponding to the noiseless forward
                    operator.
            Methods of the returned dataset:
                ``get_ray_trafo(**kwargs)``
                    Function that returns a ray transform corresponding to the
                    noiseless forward operator. Keyword arguments (e.g. `impl`)
                    are forwarded to the :class:`RayTransform` constructor.

    Parameters
    ----------
    name : str
        Name of the dataset.
    kwargs : dict
        Keyword arguments.
        Supported parameters for the datasets are:

            ``'ellipses'``
                impl : {``'skimage'``, ``'astra_cpu'``, ``'astra_cuda'``},\
                        optional
                    Implementation passed to :class:`odl.tomo.RayTransform`
                    Default: ``'astra_cuda'``.
                fixed_seeds : dict or bool, optional
                    Seeds to use for random ellipse generation, passed to
                    :meth:`.EllipsesDataset.__init__`.
                    Default: ``False``.
                fixed_noise_seeds : dict or bool, optional
                    Seeds to use for noise generation, passed as `noise_seeds`
                    to :meth:`.GroundTruthDataset.create_pair_dataset`.
                    If ``True`` is passed (the default), the seeds
                    ``{'train': 1, 'validation': 2, 'test': 3}`` are used.
            ``'lodopab'``
                num_angles : int, optional
                    Number of angles to use from the full 1000 angles.
                    Must be a divisor of 1000.
                observation_model : {``'post-log'``, ``'pre-log'``}, optional
                    The observation model to use. Default is ``'post-log'``.
                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.
                sorted_by_patient : bool, optional
                    Whether to sort the samples by patient id.
                    Useful to resplit the dataset.
                    Default: ``False``.
                impl : {``'skimage'``, ``'astra_cpu'``, ``'astra_cuda'``},\
                        optional
                    Implementation passed to :class:`odl.tomo.RayTransform`
                    Default: ``'astra_cuda'``.

    Returns
    -------
    dataset : :class:`.Dataset`
        The standard dataset.
        It has an attribute `standard_dataset_name` that stores its name.
    """
    name = name.lower()
    if name == 'ellipses':
        fixed_seeds = kwargs.pop('fixed_seeds', False)
        ellipses_dataset = EllipsesDataset(image_size=128,
                                           fixed_seeds=fixed_seeds)

        NUM_ANGLES = 30
        # image shape for simulation
        IM_SHAPE = (400, 400)  # images will be scaled up from (128, 128)

        reco_space = ellipses_dataset.space
        space = odl.uniform_discr(min_pt=reco_space.min_pt,
                                  max_pt=reco_space.max_pt,
                                  shape=IM_SHAPE,
                                  dtype=np.float32)

        reco_geometry = odl.tomo.parallel_beam_geometry(reco_space,
                                                        num_angles=NUM_ANGLES)
        geometry = odl.tomo.parallel_beam_geometry(
            space,
            num_angles=NUM_ANGLES,
            det_shape=reco_geometry.detector.shape)

        impl = kwargs.pop('impl', 'astra_cuda')
        ray_trafo = odl.tomo.RayTransform(space, geometry, impl=impl)

        reco_ray_trafo = odl.tomo.RayTransform(reco_space,
                                               reco_geometry,
                                               impl=impl)

        # forward operator
        resize_op = ResizeOperator(reco_space, space)
        forward_op = ray_trafo * resize_op

        noise_seeds = kwargs.pop('fixed_noise_seeds', True)
        if isinstance(noise_seeds, bool):
            noise_seeds = ({
                'train': 1,
                'validation': 2,
                'test': 3
            } if noise_seeds else None)

        dataset = ellipses_dataset.create_pair_dataset(forward_op=forward_op,
                                                       noise_type='white',
                                                       noise_kwargs={
                                                           'relative_stddev':
                                                           True,
                                                           'stddev': 0.025
                                                       },
                                                       noise_seeds=noise_seeds)

        dataset.get_ray_trafo = partial(odl.tomo.RayTransform, reco_space,
                                        reco_geometry)
        dataset.ray_trafo = reco_ray_trafo

    elif name == 'lodopab':

        num_angles = kwargs.pop('num_angles', None)
        lodopab_kwargs = {}
        for k in [
                'observation_model', 'min_photon_count', 'sorted_by_patient',
                'impl'
        ]:
            if k in kwargs:
                lodopab_kwargs[k] = kwargs.pop(k)

        dataset = LoDoPaBDataset(**lodopab_kwargs)

        if num_angles is not None:
            dataset = get_angle_subset_dataset(dataset,
                                               num_angles,
                                               impl=kwargs.get(
                                                   'impl', 'astra_cuda'))

    else:
        raise ValueError(
            "unknown dataset '{}'. Known standard datasets are {}".format(
                name, STANDARD_DATASET_NAMES))

    if kwargs:
        warn('unused keyword arguments: {}'.format(', '.join(kwargs.keys())))

    dataset.standard_dataset_name = name
    return dataset
Esempio n. 8
0
parser.add_argument('--crop', type=int, default=128, help='crop size')
parser.add_argument('--batch', type=int, default=4, help='batch size')
parser.add_argument('--epoch', type=int, default=300, help='num epochs')
parser.add_argument('--steps', type=int, default=50, help='steps per epoch')
parser.add_argument('--lr', type=float, default=0.0003, help='learning rate')

args = parser.parse_args()

if args.mode != "samplepoisson":
    raise ValueError("Only support samplepoisson mode")
""" Load training and validation datasets """

# update dival config file with correct path to data
dival.config.set_config('/lodopab_dataset/data_path', args.path)

dataset = LoDoPaBDataset(observation_model=args.obsmodel, impl='skimage')

#sinogram, _ = dataset.get_sample(0, part='train', out=(True,False))
#height, width = sinogram.shape[0:2]
#y_crop = 32*(height//32)
#x_crop = 32*(width//32)
#print('crop: ',y_crop,x_crop)
#crop_size = [y_crop,x_crop]
crop_size = [args.crop, args.crop]


def load_train_sinograms(batch_size, crop_size):
    indices = np.arange(dataset.train_len)
    batch = np.zeros((batch_size, crop_size[0], crop_size[1], 1))

    while True: