コード例 #1
0
class TestAstraSimple(unittest.TestCase):
    def setUp(self): 

        N = 128
        angles = np.linspace(0, np.pi, 180, dtype='float32')

        ag = AcquisitionGeometry.create_Parallel2D()\
                                .set_angles(angles, angle_unit='radian')\
                                .set_panel(N, 0.1)\
                                .set_labels(['angle', 'horizontal'])
        
        ig = ag.get_ImageGeometry()

        
        ag3 = AcquisitionGeometry.create_Parallel3D()\
                                .set_angles(angles, angle_unit='radian')\
                                .set_panel((N, N), (0.1, 0.1))\
                                .set_labels(['vertical', 'angle', 'horizontal'])

        ig3 = ag3.get_ImageGeometry()

        self.ig = ig
        self.ag = ag
        self.ig3 = ig3
        self.ag3 = ag3
        self.norm = 14.85

    @unittest.skipUnless(has_astra and astra.use_cuda(), "Astra not built with CUDA")
    def test_norm_simple2D_gpu(self):
        # test exists
        # Create projection operator using Astra-Toolbox. Available CPU/CPU
        device = 'gpu'
        A = AstraProjectorSimple(self.ig, self.ag, device = device)

        n = A.norm()
        print ("norm A GPU", n)
        self.assertTrue(True)
        self.assertAlmostEqual(n, self.norm, places=2)
    @unittest.skipUnless(has_astra, "Astra not built with CUDA")
    def test_norm_simple2D_cpu(self):
        # test exists
        # Create projection operator using Astra-Toolbox. Available CPU/CPU
        device = 'cpu'
        A = AstraProjectorSimple(self.ig, self.ag, device = device)

        n = A.norm()
        print ("norm A CPU", n)
        self.assertTrue(True)
        self.assertAlmostEqual(n, self.norm, places=2)
    
    @unittest.skipUnless(has_astra and astra.use_cuda(), "Astra not built with CUDA")
    def test_norm_simple3D_gpu(self):
        # test exists
        A3 = AstraProjector3DSimple(self.ig3, self.ag3)
        n = A3.norm()
        print ("norm A3", n)
        self.assertTrue(True)
        self.assertAlmostEqual(n, self.norm, places=2)
コード例 #2
0
ファイル: tests.py プロジェクト: astra-toolbox/astra-toolbox
def test():
  """Perform a very basic functionality test"""

  import astra
  if astra.use_cuda():
    test_CUDA()
  else:
    print("No GPU support available")
    test_noCUDA()
コード例 #3
0
def test():
    """Perform a very basic functionality test"""

    import astra
    if astra.use_cuda():
        test_CUDA()
    else:
        print("No GPU support available")
        test_noCUDA()
コード例 #4
0
class BasicAstraTests(unittest.TestCase):
    @unittest.skipUnless(has_astra and astra.use_cuda(), "Astra not built with CUDA")
    def test_CUDA(self):
        astra.test_CUDA()
        assert True
    @unittest.skipUnless(has_astra, "Astra not built with CUDA")
    def test_noCUDA(self):
        astra.test_noCUDA()
        assert True
コード例 #5
0
ファイル: pytvlib.py プロジェクト: zhenghh04/tomo_TV
def check_cuda():
    try:
        import astra
        import sys
        if not astra.use_cuda():
            print('No GPU support available')
            print('Please have a GPU to run these scripts')
            exit(1)
    except:
        print('Please have ASTRA installed!')
コード例 #6
0
ファイル: torch_utility.py プロジェクト: MBaltz/dival
def get_torch_ray_trafo_parallel_2d_adjoint(ray_trafo, z_shape=1):
    """
    Create a torch autograd-enabled function from a 2D parallel-beam
    :class:`odl.tomo.RayTransform` using tomosipo that calls the direct
    backward projection routine of astra, which avoids copying between GPU and
    CPU (available in 1.9.9.dev4).

    Parameters
    ----------
    ray_trafo : :class:`odl.tomo.RayTransform`
        Ray transform
    z_shape : int, optional
        Batch dimension.
        Default: ``1``.

    Returns
    -------
    torch_ray_trafo_adjoint : callable
        Torch autograd-enabled function applying the parallel-beam backward
        projection.
        Input and output have a trivial leading batch dimension and a channel
        dimension specified by `z_shape` (default ``1``), i.e. the
        input shape is ``(1, z_shape) + ray_trafo.range.shape`` and the
        output shape is ``(1, z_shape) + ray_trafo.domain.shape``.
    """
    if not TOMOSIPO_AVAILABLE:
        raise ImportError(MISSING_TOMOSIPO_MESSAGE)
    if not ASTRA_AVAILABLE:
        raise RuntimeError('Astra is not available.')
    if not astra.use_cuda():
        raise RuntimeError('Astra is not able to use CUDA.')
    vg = from_odl(discretized_space_2d_to_3d(ray_trafo.domain,
                                             z_shape=z_shape))
    pg = from_odl(
        parallel_2d_to_3d_geometry(ray_trafo.geometry, det_z_shape=z_shape))
    ts_op = ts.operator(vg, pg)
    torch_ray_trafo_adjoint_ts = to_autograd(ts_op.T)
    scaling_factor = astra_cuda_bp_scaling_factor(ray_trafo.range,
                                                  ray_trafo.domain,
                                                  ray_trafo.geometry)

    def torch_ray_trafo_adjoint(y):
        return scaling_factor * torch_ray_trafo_adjoint_ts(y)

    return torch_ray_trafo_adjoint
コード例 #7
0
ファイル: torch_utility.py プロジェクト: MBaltz/dival
 def __init__(self, ray_trafo, init_z_shape=1):
     """
     Parameters
     ----------
     ray_trafo : :class:`odl.tomo.RayTransform`
         Ray transform
     init_z_shape : int, optional
         Initial guess for the number of 2D transforms per batch, i.e. the
         product of batch and channel dimensions.
     """
     if not TOMOSIPO_AVAILABLE:
         raise ImportError(MISSING_TOMOSIPO_MESSAGE)
     if not ASTRA_AVAILABLE:
         raise RuntimeError('Astra is not available.')
     if not astra.use_cuda():
         raise RuntimeError('Astra is not able to use CUDA.')
     super().__init__()
     self.ray_trafo = ray_trafo
     self._construct_operator(init_z_shape)
コード例 #8
0
    TORCH_AVAILABLE = True
    from dival.util.torch_utility import (
        RandomAccessTorchDataset, GeneratorTorchDataset,
        load_state_dict_convert_data_parallel, TOMOSIPO_AVAILABLE,
        TorchRayTrafoParallel2DModule, TorchRayTrafoParallel2DAdjointModule)
import numpy as np
import odl
from dival import get_standard_dataset
from dival.datasets import Dataset
from dival.datasets.ellipses_dataset import EllipsesDataset
try:
    import astra
except ImportError:
    ASTRA_CUDA_AVAILABLE = False
else:
    ASTRA_CUDA_AVAILABLE = astra.use_cuda()


def get_parallel_beam_dataset():
    ellipses_dataset = EllipsesDataset(image_size=128,
                                       min_pt=[-20., -20.],
                                       max_pt=[20., 20.],
                                       fixed_seeds=True)

    NUM_ANGLES = 30

    geometry = odl.tomo.parallel_beam_geometry(ellipses_dataset.space,
                                               num_angles=NUM_ANGLES)

    ray_trafo = odl.tomo.RayTransform(ellipses_dataset.space,
                                      geometry,
コード例 #9
0
class TestAstraConeBeamProjectors(unittest.TestCase):
    def setUp(self):
        #%% Setup Geometry
        voxel_num_xy = 255
        voxel_num_z = 15
        self.cs_ind = (voxel_num_z - 1) // 2

        mag = 2
        src_to_obj = 50
        src_to_det = src_to_obj * mag

        pix_size = 0.2
        det_pix_x = voxel_num_xy
        det_pix_y = voxel_num_z

        num_projections = 180
        angles = np.linspace(0, np.pi, num=num_projections, endpoint=False)

        self.ag = AcquisitionGeometry.create_Cone3D([0,-src_to_obj,0],[0,src_to_det-src_to_obj,0])\
                                     .set_angles(angles, angle_unit='radian')\
                                     .set_panel((det_pix_x,det_pix_y), (pix_size,pix_size))\
                                     .set_labels(['vertical','angle','horizontal'])

        self.ag_slice = AcquisitionGeometry.create_Cone2D([0,-src_to_obj],[0,src_to_det-src_to_obj])\
                                           .set_angles(angles, angle_unit='radian')\
                                           .set_panel(det_pix_x, pix_size)\
                                           .set_labels(['angle','horizontal'])

        self.ig_2D = self.ag_slice.get_ImageGeometry()
        self.ig_3D = self.ag.get_ImageGeometry()

        #%% Create phantom
        kernel_size = voxel_num_xy
        kernel_radius = (kernel_size - 1) // 2
        y, x = np.ogrid[-kernel_radius:kernel_radius + 1,
                        -kernel_radius:kernel_radius + 1]

        circle1 = [5, 0, 0]  #r,x,y
        dist1 = ((x - circle1[1])**2 + (y - circle1[2])**2)**0.5

        circle2 = [5, 100, 0]  #r,x,y
        dist2 = ((x - circle2[1])**2 + (y - circle2[2])**2)**0.5

        circle3 = [25, 0, 100]  #r,x,y
        dist3 = ((x - circle3[1])**2 + (y - circle3[2])**2)**0.5

        mask1 = (dist1 - circle1[0]).clip(0, 1)
        mask2 = (dist2 - circle2[0]).clip(0, 1)
        mask3 = (dist3 - circle3[0]).clip(0, 1)
        phantom = 1 - np.logical_and(np.logical_and(mask1, mask2), mask3)

        self.golden_data = self.ig_3D.allocate(0)
        for i in range(4):
            self.golden_data.fill(array=phantom, vertical=7 + i)

        self.golden_data_cs = self.golden_data.subset(vertical=self.cs_ind,
                                                      force=True)

    @unittest.skipUnless(has_astra, "Astra not available")
    def test_consistency(self):

        # #%% AstraProjectorSimple cpu
        ig = self.ig_2D.copy()
        ag = self.ag_slice.copy()

        A = AstraProjectorSimple(ig, ag, device='cpu')
        fp = A.direct(self.golden_data_cs)
        bp = A.adjoint(fp)

        # #%% AstraProjectorFlexible
        ig = self.ig_3D.copy()
        ag = self.ag.copy()

        A = AstraProjector3DSimple(ig, ag)
        flex_fp = A.direct(self.golden_data)
        flex_bp = A.adjoint(flex_fp)

        #comparision foward projection
        fp_flex_0 = flex_fp.subset(vertical=self.cs_ind, force=True)
        fp_flex_2 = flex_fp.subset(vertical=self.cs_ind - 3, force=True)

        zeros = self.ag_slice.allocate(0)
        np.testing.assert_allclose(fp_flex_0.as_array(),
                                   fp.as_array(),
                                   atol=0.8)
        np.testing.assert_allclose(fp_flex_2.as_array(), zeros.as_array())

        #comparision back projection
        bp_flex_0 = flex_bp.subset(vertical=self.cs_ind, force=True)
        bp_flex_1 = flex_bp.subset(vertical=self.cs_ind + 3, force=True)
        bp_flex_2 = flex_bp.subset(vertical=self.cs_ind - 3, force=True)

        zeros = self.ig_2D.allocate(0)
        np.testing.assert_allclose(bp_flex_0.as_array(),
                                   bp.as_array(),
                                   atol=12)
        np.testing.assert_allclose(bp_flex_1.as_array(),
                                   bp.as_array(),
                                   atol=25)
        np.testing.assert_allclose(bp_flex_2.as_array(), zeros.as_array())

    @unittest.skipUnless(has_astra and astra.use_cuda(),
                         "Astra GPU not available")
    def test_3D(self):
        #%% AstraProjectorSimple gpu
        ig = self.ig_3D.copy()
        ag = self.ag.copy()

        A = AstraProjector3DSimple(ig, ag)
        fp = A.direct(self.golden_data)
        bp = A.adjoint(fp)

        # #%% AstraProjectorFlexible
        ig = self.ig_3D.copy()
        ag = self.ag.copy()

        A = AstraProjector3DSimple(ig, ag)
        flex_fp = A.direct(self.golden_data)
        flex_bp = A.adjoint(fp)

        #comparision foward projection
        fp_0 = fp.subset(vertical=self.cs_ind, force=True)
        fp_1 = fp.subset(vertical=self.cs_ind + 3, force=True)
        fp_2 = fp.subset(vertical=self.cs_ind - 3, force=True)

        fp_flex_0 = flex_fp.subset(vertical=self.cs_ind, force=True)
        fp_flex_1 = flex_fp.subset(vertical=self.cs_ind + 3, force=True)
        fp_flex_2 = flex_fp.subset(vertical=self.cs_ind - 3, force=True)

        np.testing.assert_allclose(fp_flex_0.as_array(), fp_0.as_array())
        np.testing.assert_allclose(fp_flex_1.as_array(), fp_1.as_array())
        np.testing.assert_allclose(fp_flex_2.as_array(), fp_2.as_array())

        #comparision back projection
        bp_0 = bp.subset(vertical=self.cs_ind, force=True)
        bp_1 = bp.subset(vertical=self.cs_ind + 3, force=True)
        bp_2 = bp.subset(vertical=self.cs_ind - 3, force=True)

        bp_flex_0 = flex_bp.subset(vertical=self.cs_ind, force=True)
        bp_flex_1 = flex_bp.subset(vertical=self.cs_ind + 3, force=True)
        bp_flex_2 = flex_bp.subset(vertical=self.cs_ind - 3, force=True)

        np.testing.assert_allclose(bp_flex_0.as_array(), bp_0.as_array())
        np.testing.assert_allclose(bp_flex_1.as_array(), bp_1.as_array())
        np.testing.assert_allclose(bp_flex_2.as_array(), bp_2.as_array())

    @unittest.skipUnless(has_astra and astra.use_cuda(),
                         "Astra not built with CUDA")
    def test_2D(self):

        # #%% AstraProjectorSimple cpu
        ig = self.ig_2D.copy()
        ag = self.ag_slice.copy()

        A = AstraProjectorSimple(ig, ag, device='cpu')
        fp = A.direct(self.golden_data_cs)
        bp = A.adjoint(fp)

        #%% AstraProjectorSimple gpu
        ig = self.ig_2D.copy()
        ag = self.ag_slice.copy()

        A = AstraProjectorSimple(ig, ag, device='gpu')
        fp_gpu = A.direct(self.golden_data_cs)
        bp_gpu = A.adjoint(fp_gpu)

        np.testing.assert_allclose(fp_gpu.as_array(), fp.as_array(), atol=0.8)
        np.testing.assert_allclose(bp_gpu.as_array(), bp.as_array(), atol=12)

        # #%% AstraProjectorFlexible as a 2D
        ig = self.ig_2D.copy()
        ag = self.ag_slice.copy()

        A = AstraProjectorFlexible(ig, ag)
        fp_flex = A.direct(self.golden_data_cs)
        bp_flex = A.adjoint(fp_flex)

        np.testing.assert_allclose(fp_flex.as_array(), fp.as_array(), atol=0.8)
        np.testing.assert_allclose(bp_flex.as_array(), bp.as_array(), atol=12)
コード例 #10
0
    def test_align(self,
                   xshift=0.0,
                   angle=0.0,
                   slices=None,
                   thickness=None,
                   method='FBP',
                   iterations=50,
                   constrain=True,
                   cuda=None,
                   thresh=0):
        """
        Reconstruct three slices from the input data for visual inspection.

        Args
        ----------
        xshift : float
            Number of pixels by which to shift the input data.
        angle : float
            Angle by which to rotate stack prior to reconstruction
        slices : list
            Position of slices to use for the reconstruction.  If None,
            positions at 1/4, 1/2, and 3/4 of the full size of the stack are
            chosen.
        thickness : integer
            Size of the output volume (in pixels) in the projection direction.
        cuda : bool
            If True, use CUDA-accelerated Astra algorithms.  If None, use
            CUDA if astra.use_cuda() is True.
        """
        if slices is None:
            mid = np.int32(self.data.shape[1] / 2)
            slices = np.int32([mid / 2, mid, mid + mid / 2])

        if (xshift != 0.0) or (angle != 0.0):
            shifted = self.trans_stack(xshift=xshift, yshift=0, angle=angle)
        else:
            shifted = self.deepcopy()
        shifted.data = shifted.data[:, slices, :]

        shifted.axes_manager[0].axis = self.axes_manager[0].axis
        if not cuda:
            if astra.use_cuda():
                logger.info('CUDA detected with Astra')
                cuda = True
            else:
                cuda = False
                logger.info('CUDA not detected with Astra')
        rec = shifted.reconstruct(method=method,
                                  iterations=iterations,
                                  constrain=constrain,
                                  thickness=thickness,
                                  cuda=cuda,
                                  thresh=thresh)

        if 'ipympl' in mpl.get_backend().lower():
            fig, (ax1, ax2, ax3) = plt.subplots(1, 3, figsize=(7, 3))
        elif 'nbagg' in mpl.get_backend().lower():
            fig, (ax1, ax2, ax3) = plt.subplots(1, 3, figsize=(8, 4))
        else:
            fig, (ax1, ax2, ax3) = plt.subplots(1, 3, figsize=(12, 4))

        minvals = rec.data.mean((1, 2)) - 3 * rec.data.std((1, 2))
        minvals[minvals < 0] = 0
        maxvals = rec.data.mean((1, 2)) + 3 * rec.data.std((1, 2))

        for i in range(0, 3):
            if maxvals[i] > rec.data[i].max():
                maxvals[i] = rec.data[i].max()
        ax1.imshow(rec.data[0, :, :],
                   cmap='afmhot',
                   vmin=minvals[0],
                   vmax=maxvals[0])
        ax1.set_title('Slice %s' % str(slices[0]))
        ax1.set_axis_off()

        ax2.imshow(rec.data[1, :, :],
                   cmap='afmhot',
                   vmin=minvals[1],
                   vmax=maxvals[1])
        ax2.set_title('Slice %s' % str(slices[1]))
        ax2.set_axis_off()

        ax3.imshow(rec.data[2, :, :],
                   cmap='afmhot',
                   vmin=minvals[2],
                   vmax=maxvals[2])
        ax3.set_title('Slice %s' % str(slices[2]))
        ax3.set_axis_off()
        fig.tight_layout()
        return
コード例 #11
0
    def reconstruct(self,
                    method='FBP',
                    iterations=None,
                    constrain=False,
                    thresh=0,
                    cuda=None,
                    thickness=None):
        """
        Reconstruct a TomoStack series using one of the available methods.

        astraWBP, astraSIRT, astraSIRT_GPU

        Args
        ----------
        method : string
            Reconstruction algorithm to use.  Must be either 'FBP' (default)
            or 'SIRT'
        iterations : integer
            Number of iterations for the SIRT reconstruction (for astraSIRT
            and astraSIRT_GPU, methods only)
        constrain : boolean
            If True, output reconstruction is constrained above value given
            by 'thresh'
        thresh : integer or float
            Value above which to constrain the reconstructed data
        cuda : boolean
            If True, use the CUDA-accelerated reconstruction algorithm
        thickness : integer
            Size of the output volume (in pixels) in the projection direction.

        Returns
        ----------
        out : TomoStack object
            TomoStack containing the reconstructed volume

        Examples
        ----------
        Filtered backprojection (FBP) reconstruction
        >>> import tomotools.datasets as ds
        >>> stack = ds.get_needle_data(True)
        >>> slices = stack.isig[:, 120:121].deepcopy()
        >>> rec = slices.reconstruct('FBP')

        Simultaneous iterative reconstruction technique (SIRT) reconstruction
        >>> import tomotools.datasets as ds
        >>> stack = ds.get_needle_data(True)
        >>> slices = stack.isig[:, 120:121].deepcopy()
        >>> rec = slices.reconstruct('SIRT',iterations=5)

        Simultaneous iterative reconstruction technique (SIRT) reconstruction
        with positivity constraint
        >>> import tomotools.datasets as ds
        >>> stack = ds.get_needle_data(True)
        >>> slices = stack.isig[:, 120:121].deepcopy()
        >>> iterations = 5
        >>> constrain = True
        >>> thresh = 0
        >>> rec = slices.reconstruct('SIRT',iterations, constrain, thresh)

        """
        if not cuda:
            if astra.use_cuda():
                logger.info('CUDA detected with Astra')
                cuda = True
            else:
                cuda = False
                logger.info('CUDA not detected with Astra')

        out = copy.deepcopy(self)
        out.data = recon.run(self, method, iterations, constrain, thresh, cuda,
                             thickness)

        out.axes_manager[0].name = 'y'
        out.axes_manager[0].size = out.data.shape[0]
        out.axes_manager[0].offset = self.axes_manager['y'].offset
        out.axes_manager[0].scale = self.axes_manager['y'].scale
        out.axes_manager[0].units = self.axes_manager['y'].units

        out.axes_manager[2].name = 'z'
        out.axes_manager[2].size = out.data.shape[1]
        out.axes_manager[2].offset = self.axes_manager['x'].offset
        out.axes_manager[2].scale = self.axes_manager['x'].scale
        out.axes_manager[2].units = self.axes_manager['x'].units

        out.axes_manager[1].name = 'x'
        out.axes_manager[1].size = out.data.shape[2]
        out.axes_manager[1].offset = self.axes_manager['x'].offset
        out.axes_manager[1].scale = self.axes_manager['x'].scale
        out.axes_manager[1].units = self.axes_manager['x'].units
        return out
コード例 #12
0
    def tilt_align(self,
                   method,
                   limit=10,
                   delta=0.3,
                   locs=None,
                   axis=0,
                   show_progressbar=False):
        """
        Align the tilt axis of a TomoStack.

        Uses either a center-of-mass approach or a maximum image approach

        Available options are 'CoM' and 'Error'

        CoM: track the center of mass (CoM) of the projections at three
        locations.  Fit the motion of the CoM as a function of tilt to that
        expected for an ideal cylinder to calculate an X-shift at each
        location. Perform a  linear fit of the three X-shifts to calculate an
        ideal rotation.

        MaxImage: Perform automated determination of the tilt axis of a
        TomoStack by measuring the rotation of the projected maximum image.
        Maximum image is rotated positively and negatively, filtered using a
        Hamming window, and the rotation angle is determined by iterative
        histogram analysis

        minimize: Perform automated determination of the tilt axis of a
        TomoStack by minimizing the difference between the reconstruction and
        the input dataset usign scipy.optimize.differential_evolution.

        Args
        ----------
        method : string
            Algorithm to use for registration alignment. Must be either 'CoM',
            'MaxImage', or 'minimize'.
        limit : integer
            Position in tilt series to use as starting point for the
            alignment. If None, the central projection is used.
        delta : integer
            Position i
        limit : integer or float
            Maximum rotation angle to use for MaxImage calculation
        delta : float
            Angular increment for MaxImage calculation
        locs : list
            Image coordinates indicating the locations at which to calculate
            the alignment
        axis : integer
            Axis along which to extract sinograms. Value of 0 means tilt axis
            is horizontally oriented.  1 means vertically oriented.
        show_progressbar : boolean
            Enable/disable progress bar

        Returns
        ----------
        out : TomoStack object
            Copy of the input stack rotated by calculated angle

        Examples
        ----------
        Align tilt axis using the center of mass (CoM) method
        >>> import tomotools.datasets as ds
        >>> stack = ds.get_needle_data()
        >>> reg = stack.stack_register('ECC',show_progressbar=False)
        >>> method = 'CoM'
        >>> ali = reg.tilt_align(method, locs=[50,100,160])

        Align tilt axis using the maximum image method
        >>> import tomotools.datasets as ds
        >>> stack = ds.get_needle_data()
        >>> reg = stack.stack_register('ECC',show_progressbar=False)
        >>> method = 'MaxImage'
        >>> ali = reg.tilt_align(method, show_progressbar=False)

        """
        method = method.lower()
        if axis == 1:
            self = self.swap_axes(1, 2)
        if method == 'com':
            out = align.tilt_com(self, locs)
        elif method == 'maximage':
            out = align.tilt_maximage(self, limit, delta, show_progressbar)
        elif method == 'minimize':
            out = align.tilt_minimize(self, cuda=astra.use_cuda())
        else:
            raise ValueError("Invalid alignment method: %s."
                             "Must be 'CoM', 'MaxImage', or 'Minimize'" %
                             method)

        if axis == 1:
            self = self.swap_axes(2, 1)
        return out
コード例 #13
0
    def recon_error(self,
                    nslice=None,
                    iterations=50,
                    constrain=True,
                    cuda=None,
                    thresh=0):
        """
        Determine the optimum number of iterations for reconstruction.

        Evaluates the difference between reconstruction and input data
        at each iteration and terminates when the change between iterations is
        below tolerance.

        Args
        ----------
        algorithm : str
            Reconstruction algorithm use.
        nslice : int
            Location at which to perform the evaluation.
        constrain : boolean
            If True, perform SIRT reconstruction with a non-negativity
            constraint.  Default is True
        cuda : boolean
            If True, perform reconstruction using the GPU-accelrated algorithm.
            Default is True
        thresh : integer or float
            Value above which to constrain the reconstructed data

        Returns
        ----------
        rec_stack : Hyperspy Signal2D
            Signal containing the SIRT reconstruction at each iteration
            for visual inspection.
        error : Hyperspy Signal1D
            Sum of squared difference between the forward-projected
            reconstruction and the input sinogram at each iteration

        Examples
        ----------
        >>> import tomotools.datasets as ds
        >>> stack = ds.get_needle_data(True)
        >>> rec_stack, error = stack.recon_error(iterations=5)

        """
        if not nslice:
            nslice = np.int32(self.data.shape[1] / 2)

        if not cuda:
            if astra.use_cuda():
                logger.info('CUDA detected with Astra')
                cuda = True
            else:
                cuda = False
                logger.info('CUDA not detected with Astra')
        sinogram = self.isig[:, nslice:nslice + 1].deepcopy()
        angles = self.metadata.Tomography.tilts
        rec_stack, error = recon.astra_sirt_error(sinogram,
                                                  angles,
                                                  iterations=iterations,
                                                  constrain=constrain,
                                                  thresh=thresh,
                                                  cuda=cuda)
        rec_stack = Signal2D(rec_stack)
        rec_stack.axes_manager[0].name = 'z'
        rec_stack.axes_manager[0].scale = self.axes_manager[1].scale
        rec_stack.axes_manager[0].scale = self.axes_manager[1].scale
        rec_stack.axes_manager[1].name = 'x'
        rec_stack.axes_manager[1].scale = self.axes_manager[1].scale
        rec_stack.axes_manager[1].scale = self.axes_manager[1].scale

        error = Signal1D(error)
        error.axes_manager[0].name = 'SIRT Iteration'
        error.metadata.Signal.quantity = 'Sum of Squared Difference'
        return rec_stack, error
コード例 #14
0
class TestAstraFlexible(unittest.TestCase):
    def setUp(self): 
        N = 128
        angles = np.linspace(0, np.pi, 180, dtype='float32')

        ag = AcquisitionGeometry.create_Parallel2D()\
                                .set_angles(angles, angle_unit='radian')\
                                .set_panel(N, 0.1)\
                                .set_labels(['angle', 'horizontal'])
        
        ig = ag.get_ImageGeometry()

        
        ag3 = AcquisitionGeometry.create_Parallel3D()\
                                .set_angles(angles, angle_unit='radian')\
                                .set_panel((N, N), (0.1, 0.1))\
                                .set_labels(['vertical', 'angle', 'horizontal'])

        ig3 = ag3.get_ImageGeometry()

        self.ig = ig
        self.ag = ag
        self.ig3 = ig3
        self.ag3 = ag3
        self.norm = 14.85

    @unittest.skipUnless(has_astra and astra.use_cuda(), "Astra not built with CUDA")
    def test_norm_flexible2D_gpu(self):
        # test exists
        # Create projection operator using Astra-Toolbox. Available CPU/CPU
        A = AstraProjectorFlexible(self.ig, self.ag)
        n = A.norm()
        print ("norm A GPU", n)
        self.assertTrue(True)
        self.assertAlmostEqual(n, self.norm, places=2)
    
        ag_2 = self.ag.copy()
        ag_2.dimension_labels = ['horizontal','angle']
        with self.assertRaises(ValueError):
            A = AstraProjectorFlexible(self.ig, ag_2)

        ig_2 = self.ig3.copy()
        ig_2.dimension_labels = ['horizontal_x','horizontal_y']
        with self.assertRaises(ValueError):
            A = AstraProjectorFlexible(ig_2, self.ag)

    @unittest.skipUnless(has_astra and astra.use_cuda(), "Astra not built with CUDA")
    def test_norm_flexible3D_gpu(self):
        # test exists
        A3 = AstraProjectorFlexible(self.ig3, self.ag3)
        n = A3.norm()
        print ("norm A3", n)
        self.assertTrue(True)
        self.assertAlmostEqual(n, self.norm, places=2)    

        ag3_2 = self.ag3.copy()
        ag3_2.dimension_labels = ['angle','vertical','horizontal']
        with self.assertRaises(ValueError):
            A3 = AstraProjectorFlexible(self.ig3, ag3_2)

        ig3_2 = self.ig3.copy()
        ig3_2.dimension_labels = ['horizontal_y','vertical','horizontal_x']
        with self.assertRaises(ValueError):
            A3 = AstraProjectorFlexible(ig3_2, self.ag3)
コード例 #15
0
class TestProjectionOperator(unittest.TestCase):
    def setUp(self): 
        # Define image geometry.
        N = 128
        angles = np.linspace(0, np.pi, 180, dtype='float32')

        ag = AcquisitionGeometry.create_Parallel2D()\
                                .set_angles(angles, angle_unit='radian')\
                                .set_panel(N, 0.1)\
                                .set_labels(['angle', 'horizontal'])
        
        ig = ag.get_ImageGeometry()

        
        ag3 = AcquisitionGeometry.create_Parallel3D()\
                                .set_angles(angles, angle_unit='radian')\
                                .set_panel((N, N), (0.1, 0.1))\
                                .set_labels(['vertical', 'angle', 'horizontal'])

        ig3 = ag3.get_ImageGeometry()

  
        ag_channel = AcquisitionGeometry.create_Parallel2D()\
                                .set_angles(angles, angle_unit='radian')\
                                .set_panel(N, 0.1)\
                                .set_labels(['channel', 'angle', 'horizontal'])\
                                .set_channels(2)

        ig_channel = ag_channel.get_ImageGeometry()

        
        ag3_channel = AcquisitionGeometry.create_Parallel3D()\
                                .set_angles(angles, angle_unit='radian')\
                                .set_panel((N, N), (0.1, 0.1))\
                                .set_labels(['channel','vertical', 'angle', 'horizontal'])\
                                .set_channels(2)

        ig3_channel = ag3_channel.get_ImageGeometry()

        self.ig = ig
        self.ag = ag
        self.ig_channel = ig_channel
        self.ag_channel = ag_channel       
        self.ig3 = ig3
        self.ag3 = ag3
        self.ig3_channel = ig3_channel
        self.ag3_channel = ag3_channel
        self.norm = 14.85

    @unittest.skipUnless(has_astra, "Astra not built with CUDA")
    def test_cpu(self):
        A = ProjectionOperator(self.ig, self.ag, device='cpu')
        n = A.norm()
        print ("norm A GPU", n)
        self.assertAlmostEqual(n, self.norm, places=2)

        A = ProjectionOperator(self.ig_channel, self.ag_channel, device='cpu')
        n = A.norm()
        print ("norm A GPU", n)
        self.assertAlmostEqual(n, self.norm, places=2)

        with self.assertRaises(NotImplementedError):
            A = ProjectionOperator(self.ig3, self.ag3, device='cpu')

    @unittest.skipUnless(has_astra and astra.use_cuda(), "Astra not built with CUDA")
    def test_gpu(self):
        A = ProjectionOperator(self.ig, self.ag)
        n = A.norm()
        print ("norm A GPU", n)
        self.assertAlmostEqual(n, self.norm, places=2)

        A = ProjectionOperator(self.ig_channel, self.ag_channel)
        n = A.norm()
        print ("norm A GPU", n)
        self.assertAlmostEqual(n, self.norm, places=2)

        A3 = ProjectionOperator(self.ig3, self.ag3)
        n = A3.norm()
        print ("norm A3", n)
        self.assertAlmostEqual(n, self.norm, places=2)    

        A3_channel = ProjectionOperator(self.ig3_channel, self.ag3_channel)
        n = A3_channel.norm()
        print ("norm A4", n)
        self.assertAlmostEqual(n, self.norm, places=2)  
          
コード例 #16
0
class TestProcessors(unittest.TestCase):
    def setUp(self): 
        #%% Setup Geometry
        voxel_num_xy = 255
        voxel_num_z = 15
        self.cs_ind = (voxel_num_z-1)//2


        src_to_obj = 500
        src_to_det = src_to_obj

        pix_size = 0.2
        det_pix_x = voxel_num_xy
        det_pix_y = voxel_num_z

        num_projections = 360
        angles = np.linspace(0, 2*np.pi, num=num_projections, endpoint=False)

        self.ag_cone = AcquisitionGeometry.create_Cone3D([0,-src_to_obj,0],[0,src_to_det-src_to_obj,0])\
                                     .set_angles(angles, angle_unit='radian')\
                                     .set_panel((det_pix_x,det_pix_y), (pix_size,pix_size))\
                                     .set_labels(['vertical','angle','horizontal'])

        self.ag_parallel = AcquisitionGeometry.create_Parallel3D()\
                                     .set_angles(angles, angle_unit='radian')\
                                     .set_panel((det_pix_x,det_pix_y), (pix_size,pix_size))\
                                     .set_labels(['vertical','angle','horizontal'])

        self.ig_3D = self.ag_parallel.get_ImageGeometry()

        #%% Create phantom
        kernel_size = voxel_num_xy
        kernel_radius = (kernel_size - 1) // 2
        y, x = np.ogrid[-kernel_radius:kernel_radius+1, -kernel_radius:kernel_radius+1]

        circle1 = [5,0,0] #r,x,y
        dist1 = ((x - circle1[1])**2 + (y - circle1[2])**2)**0.5

        circle2 = [5,100,0] #r,x,y
        dist2 = ((x - circle2[1])**2 + (y - circle2[2])**2)**0.5

        circle3 = [25,0,100] #r,x,y
        dist3 = ((x - circle3[1])**2 + (y - circle3[2])**2)**0.5

        mask1 =(dist1 - circle1[0]).clip(0,1) 
        mask2 =(dist2 - circle2[0]).clip(0,1) 
        mask3 =(dist3 - circle3[0]).clip(0,1) 
        phantom = 1 - np.logical_and(np.logical_and(mask1, mask2),mask3)

        self.golden_data = self.ig_3D.allocate(0)
        for i in range(4):
            self.golden_data.fill(array=phantom, vertical=7+i)

        self.golden_data_cs = self.golden_data.subset(vertical=self.cs_ind)


    @unittest.skipUnless(has_astra and astra.use_cuda(), "Astra not built with CUDA")
    def test_FBPgpu(self):

        #2D cone
        ag = self.ag_cone.subset(vertical='centre')
        ig = ag.get_ImageGeometry()
        A = ProjectionOperator(ig, ag, device='gpu')
        fp_2D = A.direct(self.golden_data_cs)

        fbp = FBP(ig, ag, 'gpu')
        fbp.set_input(fp_2D)
        fbp_2D_cone = fbp.get_output()
        np.testing.assert_allclose(fbp_2D_cone.as_array(),self.golden_data_cs.as_array(),atol=0.6)

        #3D cone
        ag = self.ag_cone
        ig = ag.get_ImageGeometry()
        A = ProjectionOperator(ig, ag, device='gpu')
        fp_3D = A.direct(self.golden_data)

        fbp = FBP(ig, ag, 'gpu')
        fbp.set_input(fp_3D)
        fbp_3D_cone = fbp.get_output()
        np.testing.assert_allclose(fbp_3D_cone.as_array(),self.golden_data.as_array(),atol=0.6)

        #2D parallel
        ag = self.ag_parallel.subset(vertical='centre')
        ig = ag.get_ImageGeometry()
        A = ProjectionOperator(ig, ag, device='gpu')
        fp_2D = A.direct(self.golden_data_cs)

        fbp = FBP(ig, ag, 'gpu')
        fbp.set_input(fp_2D)
        fbp_2D_parallel = fbp.get_output()
        np.testing.assert_allclose(fbp_2D_parallel.as_array(),self.golden_data_cs.as_array(), atol=0.6)

        #3D parallel
        ag = self.ag_parallel
        ig = ag.get_ImageGeometry()
        A = ProjectionOperator(ig, ag, device='gpu')
        fp_3D = A.direct(self.golden_data)

        fbp = FBP(ig, ag, 'gpu')
        fbp.set_input(fp_3D)
        fbp_3D_parallel = fbp.get_output()
        np.testing.assert_allclose(fbp_3D_parallel.as_array(),self.golden_data.as_array(),atol=0.6)
    
    @unittest.skipUnless(has_astra, "Astra not built with CUDA")
    def test_FBPcpu(self):
        #2D parallel
        ag = self.ag_parallel.subset(vertical='centre')
        ig = ag.get_ImageGeometry()
        A = ProjectionOperator(ig, ag, device='cpu')
        fp_2D = A.direct(self.golden_data_cs)

        fbp = FBP(ig, ag, 'cpu')
        fbp.set_input(fp_2D)
        fbp_2D_parallel = fbp.get_output()

        np.testing.assert_allclose(fbp_2D_parallel.as_array(),self.golden_data_cs.as_array(),atol=0.6)