Пример #1
0
 def run(self, iterations):
     self.fn = getFilterFile(self.fd, self.pg, iterations, self.rg, self.osz)
     if os.path.exists(self.fn):
         flt = np.load(self.fn)
         self.v[:] = self.customFBP(flt)
         return
     nd = self.nd
     if self.osz:
         nds = self.osz
     else:
         nds = nd
     na = len(self.ang)
     pgc = astra.create_proj_geom('parallel',1.0,nd,self.ang)
     vgc = astra.create_vol_geom((nds,nds))
     pidc = astra.create_projector('strip',pgc,vgc)
     x = np.zeros((nds,nds))
     xs = np.zeros((nds,nds))
     sf = np.zeros((na,nd))
     vid = astra.data2d.create('-vol',vgc)
     sid = astra.data2d.create('-sino',pgc)
     cfg = astra.astra_dict('FP')
     cfg['ProjectorId']=pidc
     cfg['ProjectionDataId']=sid
     cfg['VolumeDataId']=vid
     fpid = astra.algorithm.create(cfg)
     cfg = astra.astra_dict('BP')
     cfg['ProjectorId']=pidc
     cfg['ProjectionDataId']=sid
     cfg['ReconstructionDataId']=vid
     bpid = astra.algorithm.create(cfg)
     vc = astra.data2d.get_shared(vid)
     sc = astra.data2d.get_shared(sid)
     x[nds//2,nds//2]=1
     alp = 1./(na*nds)
     if self.rg:
         if self.rg*alp >=0.1:
             alp = 0.1/self.rg
     astra.log.info('Computing filter...')
     for i in range(iterations):
         if i%10==0: astra.log.info('{:.2f} % done'.format(100*float(i)/iterations))
         xs+=x
         vc[:] = x
         astra.algorithm.run(fpid)
         astra.algorithm.run(bpid)
         if self.rg:
             dx = x[:-1,:] - x[1:,:]
             dy = x[:,:-1] - x[:,1:]
             x[:-1,:] -= self.rg*dx*alp
             x[1:,:] += self.rg*dx*alp
             x[:,:-1] -= self.rg*dy*alp
             x[:,1:] += self.rg*dy*alp
         x -= vc*alp
     vc[:] = xs
     astra.algorithm.run(fpid)
     flt = sc.copy()*alp
     astra.algorithm.delete([fpid,bpid])
     astra.algorithm.delete([vid,sid])
     np.save(self.fn,flt)
     self.v[:] = self.customFBP(flt)
     astra.projector.delete(pidc)
Пример #2
0
    def __init__(self,
                 geometry_obj=Geometry(1),
                 vol_vector=None,
                 proj_vector=None, gpu_index=0):
        self.geom = geometry_obj
        if vol_vector is None:
            self.vol = Rn(self.geom.vol_size)
        else:
            self.vol = vol_vector
        if proj_vector is None:
            self.proj = Rn(self.geom.proj_size)
        else:
            self.proj = proj_vector
        self.gpu_index = gpu_index
        self.bp_id = None
        self.fp_id = None

        # Create volume geometry
        self.vol_geom = astra.create_vol_geom(self.geom.vol_shape)

        # Create projection geometry
        self.proj_geom = astra.create_proj_geom(
            self.geom.geom_type,
            self.geom.detector_spacing_x, self.geom.detector_spacing_y,
            self.geom.det_row_count, self.geom.det_col_count,
            self.geom.angles,
            self.geom.source_origin, self.geom.origin_detector)

        # Allocate ASTRA memory for volume data
        self.volume_id = astra.data3d.create('-vol', self.vol_geom)

        # Allocate ASTRA memory for projection data
        self.proj_id = astra.data3d.create('-sino', self.proj_geom)
Пример #3
0
def bp0(sino, det_col=111, num_angles=222, voxel_size_mm=1):
    """Wrapper for astra forward projector

    :param sino:
    :param projector_id:
    :return: backprojected sinogram
    """

    vol_geom = astra.create_vol_geom(sino.shape)
    proj_id = astra.create_projector(
        'cuda',
        astra.create_proj_geom('parallel', 1.0, det_col,
                               np.linspace(0, np.pi, num_angles, False)),
        vol_geom)


    rec_id, backprojection = astra.create_backprojection(sino * voxel_size_mm,
                                                   proj_id)

    # rec_id, backprojection = astra.create_backprojection(sino, projector_id)

    # backprojection /= sino.shape[0]
    # backprojection *= np.pi
    astra.data2d.delete(rec_id)
    astra.projector.delete(proj_id)

    return backprojection
Пример #4
0
 def init(self, volume_data=1, projection_data=1):
     # Create volume geometry
     self.volume_geom = astra.create_vol_geom(self.num_voxel)
 
     # Create projection geometry
     self.projection_geom = astra.create_proj_geom(self.geometry_type,
                                        self.detector_spacing_x, self.detector_spacing_y,
                                        self.det_row_count, self.det_col_count,
                                        self.angles,
                                        self.source_origin, self.origin_detector)
 
     # Allocate and store volume data in ASTRA memory
     self.volume_id = astra.data3d.create('-vol', self.volume_geom, volume_data)
 
     # Allocate and store projection data in ASTRA memeory
     self.projection_id = astra.data3d.create('-sino', self.projection_geom, projection_data)
     
     # Create algorithm object: forward projector
     cfg = astra.astra_dict('FP3D_CUDA')
     cfg['option'] = {'GPUindex': self.gpu_index}
     cfg['ProjectionDataId'] = self.projection_id
     cfg['VolumeDataId'] = self.volume_id
     self.forward_alg_id = astra.algorithm.create(cfg)
     
     # Create algorithm object: backward projector
     cfg = astra.astra_dict('BP3D_CUDA')
     cfg['option'] = {'GPUindex': self.gpu_index}
     cfg['ProjectionDataId'] = self.projection_id
     cfg['ReconstructionDataId'] = self.volume_id
     self.backward_alg_id = astra.algorithm.create(cfg)
Пример #5
0
 def geom_setup_2D(self, sino, angles, shape, cors):
     p_low, p_high = self.array_pad(cors, self.nCols)
     sino = np.pad(sino, ((0, 0), (p_low, p_high)), mode='reflect')
     vol_geom = astra.create_vol_geom(shape[0], shape[1])
     proj_geom = astra.create_proj_geom('parallel', 1.0, sino.shape[1],
                                        np.deg2rad(angles))
     return sino, vol_geom, proj_geom
Пример #6
0
def recon_sirt_fbp(im, angles, iter, temppath ):
	"""Reconstruct a sinogram with the SIRT-FBP algorithm (Pelt, 2015).

	Parameters
	----------
	im : array_like
		Sinogram image data as numpy array.

    iter : int
		Number of iterations to be used for the computation of SIRT filter.

	angles : double
		Value in radians representing the number of angles of the input sinogram.
	
	"""
	# Create ASTRA geometries:
	vol_geom = astra.create_vol_geom(im.shape[1] , im.shape[1])
	proj_geom = astra.create_proj_geom('parallel', 1.0, im.shape[1], linspace(0,angles,im.shape[0],False))
	proj = astra.create_projector('cuda', proj_geom, vol_geom)
	p = astra.OpTomo(proj)

	# Register plugin with ASTRA
	astra.plugin.register(sirtfbp.plugin)

	# Create the ASTRA projector
	im_rec = p.reconstruct('SIRT-FBP',im, iter, extraOptions={'filter_dir':temppath})
	
	return im_rec.astype(float32)
Пример #7
0
def recon_mr_fbp(im, angles):
	"""Reconstruct a sinogram with the Minimum Residual FBP algorithm (Pelt, 2013).

	Parameters
	----------
	im : array_like
		Sinogram image data as numpy array.

	angles : double
		Value in radians representing the number of angles of the input sinogram.
	
	"""
	# Create ASTRA geometries:
	vol_geom = astra.create_vol_geom(im.shape[1] , im.shape[1])
	proj_geom = astra.create_proj_geom('parallel', 1.0, im.shape[1], linspace(0,angles,im.shape[0],False))

	# Create the ASTRA projector:
	p = mrfbp.ASTRAProjector.ASTRAProjector2D(proj_geom,vol_geom)
	
	# Create the MR-FBP Reconstructor:
	rec = mrfbp.Reconstructor(p)

	# Reconstruct the image using MR-FBP:
	im_rec = rec.reconstruct(im)
	
	return im_rec.astype(float32)
Пример #8
0
def astrarecon(tilt_data,tilt_angles,iterations=1,geometry='parallel3d',SO_dist=1.0,OD_dist=1.0):
    proj_shape = np.shape(tilt_data)
    recon_shape = (proj_shape[2],proj_shape[2],proj_shape[1])
    
    vol_geom = astra.create_vol_geom(recon_shape)

    angles = np.pi*tilt_angles/180
    
    if geometry == 'parallel3d':
        proj_geom = astra.create_proj_geom(geometry, 1.0, 1.0, proj_shape[1], proj_shape[2], angles)
        cfg = astra.astra_dict('SIRT3D_CUDA')
    elif geometry == 'cone':
        proj_geom = astra.create_proj_geom(geometry, 1.0, 1.0, proj_shape[1], proj_shape[2], angles, SO_dist, OD_dist)
        cfg = astra.astra_dict('FDK_CUDA')
        
    proj_id = astra.data3d.create('-proj3d', proj_geom, np.swapaxes(tilt_data,0,1))
    
    rec_id = astra.data3d.create('-vol', vol_geom)
    
    cfg['ReconstructionDataId'] = rec_id
    cfg['ProjectionDataId'] = proj_id
    
    alg_id = astra.algorithm.create(cfg)
    
    astra.algorithm.run(alg_id, iterations)
    
    rec = astra.data3d.get(rec_id)
    
    astra.algorithm.delete(alg_id)
    astra.data3d.delete(rec_id)
    astra.data3d.delete(proj_id)
    
    return(rec)
Пример #9
0
def astrafp(im, ang, prj="cuda"):
    proj_geom = astra.create_proj_geom("parallel", 1.0, im.shape[0], np.array([ang, 0]))
    vol_geom = astra.create_vol_geom(im.shape)
    pid = astra.create_projector(prj, proj_geom, vol_geom)
    w = astra.OpTomo(pid)
    fpim = w * im
    astra.projector.delete(pid)
    return fpim[0 : im.shape[0]]
Пример #10
0
 def __init__(self, n_pixels, n_angles, rayperdetec=None):
     '''
     Initialize the ASTRA toolbox with a simple parallel configuration.
     The image is assumed to be square, and the detector count is equal to the number of rows/columns.
     '''
     self.vol_geom = astra.create_vol_geom(n_pixels, n_pixels)
     self.proj_geom = astra.create_proj_geom('parallel', 1.0, n_pixels, np.linspace(0,np.pi,n_angles,False))
     self.proj_id = astra.create_projector('cuda', self.proj_geom, self.vol_geom)
Пример #11
0
    def _vol_geom(self):
        """Create ASTRA volume geometry object according to geometry."""

        vol_shape = self.geom.vol_shape

        assert len(vol_shape) in (2, 3)

        return astra.create_vol_geom(vol_shape)
Пример #12
0
    def __init__(self, geometry_type='cone',
                 num_voxel=(100, 100, 100),
                 det_row_count=100, det_col_count=100,
                 angles=np.linspace(0, 2 * np.pi, 180, endpoint=False),
                 det_col_spacing=1.0, det_row_spacing=1.0,
                 source_origin=100.0, origin_detector=10.0,
                 volume_data=1, projection_data=1,
                 gpu_index=0):
        self.geometry_type = geometry_type
        self.num_voxel = num_voxel
        self.detector_spacing_x = det_col_spacing
        self.detector_spacing_y = det_row_spacing
        self.det_row_count = det_row_count
        self.det_col_count = det_col_count
        self.angles = angles
        self.source_origin = source_origin
        self.origin_detector = origin_detector
        self.volume_data = volume_data
        self.projection_data = projection_data
        self.gpu_index = gpu_index

        # Create volume geometry
        self.volume_geom = astra.create_vol_geom(self.num_voxel)

        # Create projection geometry
        self.projection_geom = astra.create_proj_geom(
            self.geometry_type,
            self.detector_spacing_x, self.detector_spacing_y,
            self.det_row_count, self.det_col_count,
            self.angles,
            self.source_origin, self.origin_detector)

        # Allocate and store volume data in ASTRA memory
        self.volume_id = astra.data3d.create(
            '-vol',
            self.volume_geom,
            self.volume_data)

        # Allocate and store projection data in ASTRA memory
        self.projection_id = astra.data3d.create(
            '-sino',
            self.projection_geom,
            self.projection_data)

        # Create algorithm object: forward projector
        cfg = astra.astra_dict('FP3D_CUDA')
        cfg['option'] = {'GPUindex': self.gpu_index}
        cfg['ProjectionDataId'] = self.projection_id
        cfg['VolumeDataId'] = self.volume_id
        self.forward_alg_id = astra.algorithm.create(cfg)

        # Create algorithm object: backward projector
        cfg = astra.astra_dict('BP3D_CUDA')
        # classmethod?
        cfg['option'] = {'GPUindex': self.gpu_index}
        cfg['ProjectionDataId'] = self.projection_id
        cfg['ReconstructionDataId'] = self.volume_id
        self.backward_alg_id = astra.algorithm.create(cfg)
Пример #13
0
    def reconstruct(self, sinogram, centre_of_rotation, angles, shape, center):

        ctr = centre_of_rotation
        width = sinogram.shape[1]
        pad = 50

        sino = np.nan_to_num(sinogram)

        # pad the array so that the centre of rotation is in the middle
        alen = ctr
        blen = width - ctr
        mid = width / 2.0

        if (ctr > mid):
            plow = pad
            phigh = (alen - blen) + pad
        else:
            plow = (blen - alen) + pad
            phigh = pad

        logdata = np.log(sino+1)
        sinogram = np.pad(logdata, ((0, 0), (int(plow), int(phigh))),
                          mode='reflect')

        width = sinogram.shape[1]

        vol_geom = astra.create_vol_geom(shape[0], shape[1])
        proj_geom = astra.create_proj_geom('parallel', 1.0, width,
                                           np.deg2rad(angles))

        sinogram_id = astra.data2d.create("-sino", proj_geom, sinogram)

        # Create a data object for the reconstruction
        rec_id = astra.data2d.create('-vol', vol_geom)

        proj_id = astra.create_projector('strip', proj_geom, vol_geom)

        cfg = astra.astra_dict(self.parameters['reconstruction_type'])
        cfg['ReconstructionDataId'] = rec_id
        cfg['ProjectionDataId'] = sinogram_id
        cfg['ProjectorId'] = proj_id

        # Create the algorithm object from the configuration structure
        alg_id = astra.algorithm.create(cfg)
        # Run 20 iterations of the algorithm
        itterations = int(self.parameters['number_of_iterations'])
        # This will have a runtime in the order of 10 seconds.
        astra.algorithm.run(alg_id, itterations)
        # Get the result
        rec = astra.data2d.get(rec_id)

        # Clean up.
        astra.algorithm.delete(alg_id)
        astra.data2d.delete(rec_id)
        astra.data2d.delete(sinogram_id)

        return rec
Пример #14
0
def _basic_par3d_fp():
  import astra
  import numpy as np
  vg = astra.create_vol_geom(2, 32, 32)
  pg = astra.create_proj_geom('parallel3d', 1, 1, 32, 32, [0])
  vol = np.random.rand(32, 2, 32)
  (sino_id, sino) = astra.create_sino3d_gpu(vol, pg, vg)
  astra.data3d.delete(sino_id)
  err = np.max(np.abs(sino[:,0,:] - np.sum(vol,axis=1)))
  return err < 1e-6
Пример #15
0
def _basic_par2d_fp(type):
  import astra
  import numpy as np
  vg = astra.create_vol_geom(2, 32)
  pg = astra.create_proj_geom('parallel', 1, 32, [0])
  proj_id = astra.create_projector(type, pg, vg)
  vol = np.random.rand(2, 32)
  (sino_id, sino) = astra.create_sino(vol, proj_id)
  astra.data2d.delete(sino_id)
  astra.projector.delete(proj_id)
  err = np.max(np.abs(sino[0,:] - np.sum(vol,axis=0)))
  return err < 1e-6
Пример #16
0
    def geom_setup_3D(self, sino, angles, shape, cors):
        nSinos = sino.shape[self.slice_dim]
        length = len(angles)
        angles = np.deg2rad(angles)

        vectors = np.zeros((length, 12))
        for i in range(len(angles)):
            # ray direction
            vectors[i, 0] = np.sin(angles[i])
            vectors[i, 1] = -np.cos(angles[i])
            vectors[i, 2] = 0

            # center of detector
            vectors[i, 3:6] = 0

            # vector from detector pixel (0,0) to (0,1)
            vectors[i, 6] = np.cos(angles[i])
            vectors[i, 7] = np.sin(angles[i])
            vectors[i, 8] = 0

            # vector from detector pixel (0,0) to (1,0)
            vectors[i, 9] = 0
            vectors[i, 10] = 0
            vectors[i, 11] = 1

#        i = range(length)
#        # ray direction
#        vectors[i, 0] = np.sin(theta[i])
#        vectors[i, 1] = -np.cos(theta[i])
#        vectors[i, 2] = 0
#        # detector centre (use this for translation)
#        # assuming all sinograms are translated by the same amount for now
#        #det_vec = [cors[0], 0, 0]
#        det_vec = [0, 0, 0]
#        vectors[i, 3:6] = det_vec
#        # (use the following vectors for rotation)
#        # vector from detector pixel (0,0) to (0,1)
#        vectors[i, 6] = np.cos(theta[i])
#        vectors[i, 7] = np.sin(theta[i])
#        vectors[i, 8] = 0
#        # vector from detector pixel (0,0) to (1,0)
#        vectors[i, 9:12] = [0, 0, 1]

        # Parameters: #rows, #columns, vectors
        vol_geom = astra.create_vol_geom(nSinos, shape[0], shape[2])
        proj_geom = astra.create_proj_geom('parallel3d_vec', sino.shape[1],
                                           sino.shape[2], vectors)
        return vol_geom, proj_geom
Пример #17
0
    def astra_2D_recon(self, data):
        sino = data[0]
        cor, angles, vol_shape, init = self.get_frame_params()
        angles = np.deg2rad(angles)
        if self.res:
            res = np.zeros(self.len_res)
        # create volume geom
        vol_geom = astra.create_vol_geom(vol_shape)
        # create projection geom
        det_width = sino.shape[self.dim_detX]
        proj_geom = astra.create_proj_geom('parallel', 1.0, det_width, angles)
        sino = np.transpose(sino, (self.dim_rot, self.dim_detX))

        # create sinogram id
        sino_id = astra.data2d.create("-sino", proj_geom, sino)
        # create reconstruction id
        if init is not None:
            rec_id = astra.data2d.create('-vol', vol_geom, init)
        else:
            rec_id = astra.data2d.create('-vol', vol_geom)

#        if self.mask_id:
#            self.mask_id = astra.data2d.create('-vol', vol_geom, self.mask)
        # setup configuration options
        cfg = self.set_config(rec_id, sino_id, proj_geom, vol_geom)
        # create algorithm id
        alg_id = astra.algorithm.create(cfg)
        # run algorithm
        if self.res:
            for j in range(self.iters):
                # Run a single iteration
                astra.algorithm.run(alg_id, 1)
                res[j] = astra.algorithm.get_res_norm(alg_id)
        else:
            astra.algorithm.run(alg_id, self.iters)
        # get reconstruction matrix

        if self.manual_mask is not False:
            recon = self.manual_mask*astra.data2d.get(rec_id)
        else:
            recon = astra.data2d.get(rec_id)

        # delete geometry
        self.delete(alg_id, sino_id, rec_id, False)
        return [recon, res] if self.res else recon
Пример #18
0
    def reconstruct3D(self, sinogram, angles, shape, depth, alg_name, iterations):
        
        det_rows = sinogram.shape[0]
        det_cols = sinogram.shape[2]

#        sinogram = np.transpose(sinogram, (2,1,0))
                      
        vol_geom = astra.create_vol_geom(shape[0], depth, shape[1])
        
        proj_geom = astra.create_proj_geom('parallel3d', 1.0, 1.0, det_cols, \
                                            det_rows, np.deg2rad(angles))
                                            
        sinogram_id = astra.data3d.create("-sino", proj_geom, sinogram)

        # Create a data object for the reconstruction
        rec_id = astra.data3d.create('-vol', vol_geom)
                
        cfg = astra.astra_dict(alg_name)
        cfg['ReconstructionDataId'] = rec_id
        cfg['ProjectionDataId'] = sinogram_id
         
        # Create the algorithm object from the configuration structure
        alg_id = astra.algorithm.create(cfg)
        
        # This will have a runtime in the order of 10 seconds.
        astra.algorithm.run(alg_id, iterations)
        
        
        #if "CUDA" in params[0] and "FBP" not in params[0]:
        #self.res += astra.algorithm.get_res_norm(alg_id)**2
        #print math.sqrt(self.res)
        
        # Get the result
        rec = astra.data3d.get(rec_id)

        astra.algorithm.delete(alg_id)
        astra.data3d.delete(rec_id)
        astra.data3d.delete(sinogram_id)

        rec = rec[:160,:160,1]                

        return rec
Пример #19
0
    def geom_setup_2D(self, dim_det_cols):
        in_pData = self.get_plugin_in_datasets()[0]
        cor = self.cor + self.pad_amount

        sino_shape = in_pData.get_shape()
        nCols = sino_shape[dim_det_cols]
        self.p_low, self.p_high = \
            self.array_pad(cor[0], nCols + 2*self.pad_amount)
        sino_width = \
            sino_shape[1] + self.p_low + self.p_high + 2*self.pad_amount

        vol_geom = astra.create_vol_geom(self.vol_shape[0], self.vol_shape[1])
        self.proj_geom = astra.create_proj_geom('parallel', 1.0, sino_width,
                                                np.deg2rad(self.angles))

        self.rec_id = self.astra_function.create('-vol', vol_geom)
        self.cfg = self.cfg_setup()
        if self.alg_type is '2D' and "CUDA" not in self.name:
            proj_id = astra.create_projector('strip', self.proj_geom, vol_geom)
            self.cfg['ProjectorId'] = proj_id
Пример #20
0
    def __init__(self,
                 geometry_obj=Geometry(),
                 volume_space=Rn(Geometry().vol_size),
                 projections_space=Rn(Geometry().proj_size),
                 gpu_index=0):
        self.geom = geometry_obj
        self.vol_space = volume_space
        self.proj_space = projections_space
        self.gpu_index = gpu_index
        self.bp_id = None
        self.fp_id = None

        # Create volume geometry
        self.vol_geom = astra.create_vol_geom(self.geom.vol_shape)

        # Create projection geometry
        if self.geom.geom_type == 'cone':
            self.proj_geom = astra.create_proj_geom(
                self.geom.geom_type,
                self.geom.detector_spacing_x, self.geom.detector_spacing_y,
                self.geom.det_row_count, self.geom.det_col_count,
                self.geom.angles,
                self.geom.source_origin, self.geom.origin_detector)
        elif self.geom.geom_type == 'parallel':
            self.proj_geom = astra.create_proj_geom(
                'parallel', self.geom.detector_spacing_x,
                self.geom.det_col_count, self.geom.angles)

        # Allocate ASTRA memory for volume data and projection data
        if self.geom.vol_ndim == 2:
            self.volume_id = astra.data2d.create('-vol', self.vol_geom)
            self.proj_id = astra.data2d.create('-sino', self.proj_geom)
        elif self.geom.vol_ndim == 3:
            self.volume_id = astra.data3d.create('-vol', self.vol_geom)
            self.proj_id = astra.data3d.create('-sino', self.proj_geom)
        else:
            raise Exception("Invalid number of dimensions 'ndim'.")

        # self.scal_fac = self.geom.full_angle_rad / self.geom.angles.size
        # self.scal_fac = 1.0 / self.geom.angles.size
        self.scal_fac = self.geom.voxel_size[0] / self.geom.angles.size
Пример #21
0
def fp0(image, det_col=111, num_angles=222, voxel_size_mm=1):
    """Wrapper for astra forward projector

    :param image:
    :return: sinogram
    """

    vol_geom = astra.create_vol_geom(image.shape)
    proj_id = astra.create_projector(
        'cuda',
        astra.create_proj_geom('parallel', 1.0, det_col,
                               np.linspace(0, np.pi, num_angles, False)),
        vol_geom)

    sino_id, sino = astra.create_sino(image, proj_id)
    sino *= voxel_size_mm

    astra.data2d.delete(sino_id)
    astra.projector.delete(proj_id)

    return sino
Пример #22
0
    def reconstruct2D(self, sinogram, angles, shape, alg_name, iterations):
        
        vol_geom = astra.create_vol_geom(shape[0], shape[1])
        
        proj_geom = astra.create_proj_geom('parallel', 1.0, sinogram.shape[1],
                                           np.deg2rad(angles))

        sinogram_id = astra.data2d.create("-sino", proj_geom, sinogram)

        # Create a data object for the reconstruction
        rec_id = astra.data2d.create('-vol', vol_geom)
        
        cfg = astra.astra_dict(alg_name)
        cfg['ReconstructionDataId'] = rec_id
        cfg['ProjectionDataId'] = sinogram_id
        
        if not "CUDA" in alg_name:
            proj_id = astra.create_projector('strip', proj_geom, vol_geom)
            cfg['ProjectorId'] = proj_id
         
        # Create the algorithm object from the configuration structure
        alg_id = astra.algorithm.create(cfg)
        
        # This will have a runtime in the order of 10 seconds.
        astra.algorithm.run(alg_id, iterations)
        
        if "CUDA" in alg_name and "FBP" not in alg_name:
                self.res += astra.algorithm.get_res_norm(alg_id)**2
                print math.sqrt(self.res)
        
        # Get the result
        rec = astra.data2d.get(rec_id)

        astra.algorithm.delete(alg_id)
        astra.data2d.delete(rec_id)
        astra.data2d.delete(sinogram_id)
        
        return rec
Пример #23
0
def recon_fista_tv(im, angles, lam, fista_iter, iter):
	"""Reconstruct the input sinogram by using the FISTA-TV algorithm

    Parameters
    ----------
    im : array_like
		Image data (sinogram) as numpy array. 

	angles : double
		Value in radians representing the number of angles of the input sinogram.

	lam : double
		Regularization parameter of the FISTA algorithm.

	fista_iter : int
		Number of iterations of the FISTA algorihtm.

	iter : int
		Number of iterations of the TV minimization.	
	
    """	

	# Create ASTRA geometries:
	vol_geom = astra.create_vol_geom(im.shape[1] , im.shape[1])
	proj_geom = astra.create_proj_geom('parallel', 1.0, im.shape[1], linspace(0, angles, im.shape[0], False))

	# Create the ASTRA projector:
	p = tvtomo.ProjectorASTRA2D(proj_geom,vol_geom)	
	
	# Define parameters and FISTA object that performs reconstruction:
	#lam = 1**-14
	f = tvtomo.FISTA(p, lam, fista_iter)

	# Actual reconstruction (takes time):
	im_rec = f.reconstruct(im.astype(float32), iter)
	
	return im_rec.astype(float32)
#along with the Python interface to the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
#
#-----------------------------------------------------------------------

import astra
import numpy as np

# Set up multi-GPU usage.
# This only works for 3D GPU forward projection and back projection.
astra.astra.set_gpu_index([0,1])

# Optionally, you can also restrict the amount of GPU memory ASTRA will use.
# The line commented below sets this to 1GB.
#astra.astra.set_gpu_index([0,1], memory=1024*1024*1024)

vol_geom = astra.create_vol_geom(1024, 1024, 1024)

angles = np.linspace(0, np.pi, 1024,False)
proj_geom = astra.create_proj_geom('parallel3d', 1.0, 1.0, 1024, 1024, angles)

# Create a simple hollow cube phantom
cube = np.zeros((1024,1024,1024))
cube[128:895,128:895,128:895] = 1
cube[256:767,256:767,256:767] = 0

# Create projection data from this
proj_id, proj_data = astra.create_sino3d_gpu(cube, proj_geom, vol_geom)

# Backproject projection data
bproj_id, bproj_data = astra.create_backprojection3d_gpu(proj_data, proj_geom, vol_geom)
Пример #25
0
def astra_reconstruction(sinogram,
                         center,
                         angles=None,
                         ratio=1.0,
                         method="FBP_CUDA",
                         num_iter=1,
                         filter_name="hann",
                         pad=None,
                         apply_log=True):
    """
    Wrapper of reconstruction methods implemented in the astra toolbox package.
    https://www.astra-toolbox.com/docs/algs/index.html
    Users must install Astra Toolbox before using this function.

    Parameters
    ----------
    sinogram : array_like
        2D array. Sinogram image.
    center : float
        Center of rotation.
    angles : array_like
        1D array. List of angles (radian) corresponding to the sinogram.
    ratio : float
        To apply a circle mask to the reconstructed image.
    method : str
        Reconstruction algorithms. for CPU: 'FBP', 'SIRT', 'SART', 'ART',
        'CGLS'. for GPU: 'FBP_CUDA', 'SIRT_CUDA', 'SART_CUDA', 'CGLS_CUDA'.
    num_iter : int
        Number of iterations if using iteration methods.
    filter_name : str
        Apply filter if using FBP method. Options: 'hamming', 'hann',
        'lanczos', 'kaiser', 'parzen',...
    pad : int
        Padding to reduce the side effect of FFT.
    apply_log : bool
        Apply the logarithm function to the sinogram before reconstruction.

    Returns
    -------
    array_like
        Square array.
    """
    try:
        import astra
    except ImportError:
        print("!!!!!! Error !!!!!!!")
        print("You must install Astra Toolbox before using this function!")
        raise
    if apply_log is True:
        sinogram = -np.log(sinogram)
    if pad is None:
        pad = int(0.1 * sinogram.shape[1])
    sinogram = np.pad(sinogram, ((0, 0), (pad, pad)), mode='edge')
    (nrow, ncol) = sinogram.shape
    if angles is None:
        angles = np.linspace(0.0, 180.0, nrow) * np.pi / 180.0
    proj_geom = astra.create_proj_geom('parallel', 1, ncol, angles)
    vol_geom = astra.create_vol_geom(ncol, ncol)
    cen_col = (ncol - 1.0) / 2.0
    sinogram = shift(sinogram, (0, cen_col - (center + pad)), mode='nearest')
    sino_id = astra.data2d.create('-sino', proj_geom, sinogram)
    rec_id = astra.data2d.create('-vol', vol_geom)
    if "CUDA" not in method:
        proj_id = astra.create_projector('line', proj_geom, vol_geom)
    cfg = astra.astra_dict(method)
    cfg['ProjectionDataId'] = sino_id
    cfg['ReconstructionDataId'] = rec_id
    if "CUDA" not in method:
        cfg['ProjectorId'] = proj_id
    if (method == "FBP_CUDA") or (method == "FBP"):
        cfg["FilterType"] = filter_name
    alg_id = astra.algorithm.create(cfg)
    astra.algorithm.run(alg_id, num_iter)
    recon = astra.data2d.get(rec_id)
    astra.algorithm.delete(alg_id)
    astra.data2d.delete(sino_id)
    astra.data2d.delete(rec_id)
    recon = recon[pad:ncol - pad, pad:ncol - pad]
    if ratio is not None:
        ncol0 = ncol - 2 * pad
        if ratio == 0.0:
            ratio = min(center, ncol0 - center) / (0.5 * ncol0)
        mask = util.make_circle_mask(ncol0, ratio)
        recon = recon * mask
    return recon
Пример #26
0
try:
    from cvxpy import *
    cvx = True
except ImportError:
    cvx = False

if not cvx:
    print("Install CVXPY module to compare with CVX solution")
else:
    ##Construct problem
    u = Variable(N * N)
    DY = SparseFiniteDiff(ig, direction=0, bnd_cond='Neumann')
    DX = SparseFiniteDiff(ig, direction=1, bnd_cond='Neumann')

    # create matrix representation for Astra operator
    vol_geom = astra.create_vol_geom(N, N)
    proj_geom = astra.create_proj_geom('parallel', 1.0, detectors, angles)

    proj_id = astra.create_projector('line', proj_geom, vol_geom)

    matrix_id = astra.projector.matrix(proj_id)

    ProjMat = astra.matrix.get(matrix_id)

    tmp = noisy_data.as_array().ravel()

    fidelity = sum_squares(ProjMat * u - tmp)

    regulariser = alpha**2 * sum_squares(
        norm(vstack([DX.matrix() * vec(u),
                     DY.matrix() * vec(u)]), 2, axis=0))
Пример #27
0
#(at your option) any later version.
#
#The Python interface to the ASTRA Toolbox is distributed in the hope that it will be useful,
#but WITHOUT ANY WARRANTY; without even the implied warranty of
#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
#GNU General Public License for more details.
#
#You should have received a copy of the GNU General Public License
#along with the Python interface to the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
#
#-----------------------------------------------------------------------

import astra
import numpy as np
import matplotlib.pyplot as plt
vol_geom = astra.create_vol_geom(128, 128, 128)

angles = np.linspace(0, np.pi, 180,False)
proj_geom = astra.create_proj_geom('parallel3d', 1.0, 1.0, 128, 192, angles)

# Create a simple hollow cube phantom
cube = np.zeros((128,128,128))
cube[17:113,17:113,17:113] = 1
cube[33:97,33:97,33:97] = 0

# Create projection data from this
proj_id, proj_data = astra.create_sino3d_gpu(cube, proj_geom, vol_geom)

# Display a single projection image

plt.gray()
Пример #28
0
    def astra_3D_recon(self, sino, cors, angles, vol_shape, init):
#        while len(cors) is not self.sino_shape[self.slice_dir]:
#            cors.append(0)
        proj_id = False
        sslice = [slice(None)]*self.nDims
        recon = np.zeros(self.vol_shape)
        recon = np.expand_dims(recon, axis=self.slice_dir)
        if self.res:
            res = np.zeros((self.vol_shape[self.slice_dir], self.iters))

        # create volume geometry
        vol_geom = \
            astra.create_vol_geom(vol_shape[0], vol_shape[2], vol_shape[1])
        # pad the sinogram
        # Don't pad the sinogram if 3d
        # Originally in pad_sino:
        # centre_pad = (0, 0) if '3D' in self.alg else \
        # self.array_pad(cor, sino.shape[self.dim_detX])

        pad_sino = self.pad_sino(self.slice_func(sino, sslice), cors)
        nDets = pad_sino.shape[self.slice_dir]
        trans = (self.slice_dir, self.det_rot, self.sino_dim_detX)
        pad_sino = np.transpose(pad_sino, trans)

        # create projection geom
        vectors = self.create_3d_vector_geom(angles, cors,
                                             sino.shape[self.sino_dim_detX])
        proj_geom = astra.create_proj_geom('parallel3d_vec', nDets,
                                           pad_sino.shape[self.sino_dim_detX],
                                           vectors)
        # create sinogram id
        sino_id = astra.data3d.create("-sino", proj_geom, pad_sino)

        # create reconstruction id
        if init is not None:
            #init = np.transpose(init, (0, 2, 1))  # make this general
            rec_id = astra.data3d.create('-vol', vol_geom, init)
        else:
            rec_id = astra.data3d.create('-vol', vol_geom)

        # setup configuration options
        cfg = self.set_config(rec_id, sino_id, proj_geom, vol_geom)

        # create algorithm id
        alg_id = astra.algorithm.create(cfg)

        # run algorithm
        if self.res:
            for j in range(self.iters):
                # Run a single iteration
                astra.algorithm.run(alg_id, 1)
                res[j] = astra.algorithm.get_res_norm(alg_id)
        else:
            astra.algorithm.run(alg_id, self.iters)

        # get reconstruction matrix
        if self.manual_mask:
            recon = self.mask*astra.data3d.get(rec_id)
        else:
            recon = astra.data3d.get(rec_id)

        #recon = astra.data3d.get(rec_id)
        recon = np.transpose(astra.data3d.get(rec_id), (2, 0, 1))
        # delete geometry
        self.delete(alg_id, sino_id, rec_id, proj_id)

        self.start += 1
        if self.res:
            return [recon, res]
        else:
            return recon
Пример #29
0
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
#
# -----------------------------------------------------------------------

import astra
import numpy as np
from astra.experimental import do_composite_FP

astra.log.setOutputScreen(astra.log.STDERR, astra.log.DEBUG)

# low res part (voxels of 4x4x4)
vol_geom1 = astra.create_vol_geom(32, 16, 32, -64, 0, -64, 64, -64, 64)

# high res part (voxels of 1x1x1)
vol_geom2 = astra.create_vol_geom(128, 64, 128, 0, 64, -64, 64, -64, 64)


# Split the output in two parts as well, for demonstration purposes
angles1 = np.linspace(0, np.pi/2, 90, False)
angles2 = np.linspace(np.pi/2, np.pi, 90, False)
proj_geom1 = astra.create_proj_geom('parallel3d', 1.0, 1.0, 128, 192, angles1)
proj_geom2 = astra.create_proj_geom('parallel3d', 1.0, 1.0, 128, 192, angles2)

# Create a simple hollow cube phantom
cube1 = np.zeros((32,32,16))
cube1[4:28,4:28,4:16] = 1
def astra_volume_geometry(vol_space):
    """Create an ASTRA volume geometry from the discretized domain.

    From the ASTRA documentation:

    In all 3D geometries, the coordinate system is defined around the
    reconstruction volume. The center of the reconstruction volume is the
    origin, and the sides of the voxels in the volume have length 1.

    All dimensions in the projection geometries are relative to this unit
    length.


    Parameters
    ----------
    vol_space : `DiscretizedSpace`
        Discretized space where the reconstruction (volume) lives.
        It must be 2- or 3-dimensional and uniformly discretized.

    Returns
    -------
    astra_geom : dict

    Raises
    ------
    NotImplementedError
        If the cell sizes are not the same in each dimension.
    """
    if not isinstance(vol_space, DiscretizedSpace):
        raise TypeError('`vol_space` {!r} is not a DiscretizedSpace instance'
                        ''.format(vol_space))

    if not vol_space.is_uniform:
        raise ValueError('`vol_space` {} is not uniformly discretized')

    vol_shp = vol_space.partition.shape
    vol_min = vol_space.partition.min_pt
    vol_max = vol_space.partition.max_pt

    if vol_space.ndim == 2:
        # ASTRA does in principle support custom minimum and maximum
        # values for the volume extent also in earlier versions, but running
        # the algorithm fails if voxels are non-isotropic.
        if (
            not vol_space.partition.has_isotropic_cells
            and not astra_supports('anisotropic_voxels_2d')
        ):
            req_ver = astra_versions_supporting('anisotropic_voxels_2d')
            raise NotImplementedError(
                'support for non-isotropic pixels in 2d volumes requires '
                'ASTRA {}'.format(req_ver)
            )
        # Given a 2D array of shape (x, y), a volume geometry is created as:
        #    astra.create_vol_geom(x, y, y_min, y_max, x_min, x_max)
        # yielding a dictionary:
        #   {'GridRowCount': x,
        #    'GridColCount': y,
        #    'WindowMinX': y_min,
        #    'WindowMaxX': y_max,
        #    'WindowMinY': x_min,
        #    'WindowMaxY': x_max}
        #
        # NOTE: this setting is flipped with respect to x and y. We do this
        # as part of a global rotation of the geometry by -90 degrees, which
        # avoids rotating the data.
        # NOTE: We need to flip the sign of the (ODL) x component since
        # ASTRA seems to move it in the other direction. Not quite clear
        # why.
        vol_geom = astra.create_vol_geom(vol_shp[0], vol_shp[1],
                                         vol_min[1], vol_max[1],
                                         -vol_max[0], -vol_min[0])
    elif vol_space.ndim == 3:
        # Not supported in all versions of ASTRA
        if (
            not vol_space.partition.has_isotropic_cells
            and not astra_supports('anisotropic_voxels_3d')
        ):
            req_ver = astra_versions_supporting('anisotropic_voxels_3d')
            raise NotImplementedError(
                'support for non-isotropic pixels in 3d volumes requires '
                'ASTRA {}'.format(req_ver)
            )
        # Given a 3D array of shape (x, y, z), a volume geometry is created as:
        #    astra.create_vol_geom(y, z, x, z_min, z_max, y_min, y_max,
        #                          x_min, x_max),
        # yielding a dictionary:
        #   {'GridColCount': z,
        #    'GridRowCount': y,
        #    'GridSliceCount': x,
        #    'WindowMinX': z_max,
        #    'WindowMaxX': z_max,
        #    'WindowMinY': y_min,
        #    'WindowMaxY': y_min,
        #    'WindowMinZ': x_min,
        #    'WindowMaxZ': x_min}
        vol_geom = astra.create_vol_geom(vol_shp[1], vol_shp[2], vol_shp[0],
                                         vol_min[2], vol_max[2],
                                         vol_min[1], vol_max[1],
                                         vol_min[0], vol_max[0])
    else:
        raise ValueError('{}-dimensional volume geometries not supported '
                         'by ASTRA'.format(vol_space.ndim))
    return vol_geom
Пример #31
0
def astra_recon(sino, th, algorithm='FBP', num_iter=10, px=1.0,
                flag_matlab_crop=True):
    """
    ASTRA Reconstruction

    The function will reconstruct the sinogram using the ASTRA-Toolbox

    Parameters
    ----------
    sino -- 2D NumPy array
        a sinogram with each row representing a different angle
    th -- 1D NumPy array
        the angle (in degrees) corresponding to each row in the sinogram
    algorithm -- string
        the algorithm to use for the reconstruction
    num_iter -- integer (default=10)
        the number of iterations to perform for iterative techniques
    px -- float
        the pixel size
    flag_matlab_crop -- boolean (default=True)
        crop the image similar to MATLAB's reconstruction code

    Returns
    -------
    recon -- 2D NumPy array
        the reconstructed slice

    """

    # Check the algorithm

    # Check CUDA compatibility
    if (algorithm.endswith('_CUDA')):
        if (not astra.astra.use_cuda()):
            print('\nCUDA is not enabled on this system.')
            print('Please check the algorithm.')
            raise SystemExit
    else:
        if (astra.astra.use_cuda()):
            print('\nThe algorithm may run faster using the GPU.')
            print('Consider running %s_CUDA instead.' % (algorithm))

    # Convert the angles to radians
    th = np.deg2rad(th)
    (num_angles, num_col) = np.shape(sino)

    # Create the geometries
    proj_geom = astra.create_proj_geom('parallel', px, num_col, th)
    vol_geom = astra.create_vol_geom(num_col, num_col)
    if (not algorithm.endswith('CUDA')):
        proj_id = astra.create_projector('strip', proj_geom, vol_geom)

    # Move the loaded sinogram into ASTRA memory
    sino_id = astra.data2d.create('-sino', proj_geom, sino)

    # Perform the reconstruction
    recon_id = astra.data2d.create('-vol', vol_geom, 0)
    cfg = astra.astra_dict(algorithm)
    cfg['ProjectionDataId'] = sino_id
    cfg['ReconstructionDataId'] = recon_id
    if (not algorithm.endswith('CUDA')):
        cfg['ProjectorId'] = proj_id
    cfg['MinConstraint'] = 0
    alg_id = astra.algorithm.create(cfg)

    if (algorithm == 'FBP' or algorithm == 'FBP_CUDA'):
        astra.algorithm.run(alg_id)
    else:
        astra.algorithm.run(alg_id, iterations=num_iter)

    # Get and crop the reconstructed slice
    recon = astra.data2d.get(recon_id)
    if (flag_matlab_crop):
        ML_recon_size = 2.0 * np.floor(num_col / (2.0 * np.sqrt(2)))
        minX = np.int(np.ceil(0.5 * (num_col - ML_recon_size)))
        maxX = np.int(num_col - minX + 1)
        minY = minX
        maxY = maxX
        recon = recon[minX:maxX, minY:maxY]

    # Garbage clean up
    astra.data2d.delete((sino_id, recon_id))
    if (not algorithm.endswith('CUDA')):
        astra.data2d.delete((proj_id))
    astra.algorithm.delete(alg_id)

    # Return the reconstructed slice
    return recon
Пример #32
0
# In this example we will create a reconstruction in a circular region,
# instead of the usual rectangle.

# This is done by placing a circular mask on the square reconstruction volume:

c = np.linspace(-127.5,127.5,256)
x, y = np.meshgrid(c,c)
mask = np.array((x**2 + y**2 < 127.5**2),dtype=np.float)

import pylab
pylab.gray()
pylab.figure(1)
pylab.imshow(mask)

vol_geom = astra.create_vol_geom(256, 256)
proj_geom = astra.create_proj_geom('parallel', 1.0, 384, np.linspace(0,np.pi,50,False))

# As before, create a sinogram from a phantom
import scipy.io
P = scipy.io.loadmat('phantom.mat')['phantom256']
proj_id = astra.create_projector('line',proj_geom,vol_geom)
sinogram_id, sinogram = astra.create_sino(P, proj_id,useCUDA=True)

pylab.figure(2)
pylab.imshow(P)
pylab.figure(3)
pylab.imshow(sinogram)

# Create a data object for the reconstruction
rec_id = astra.data2d.create('-vol', vol_geom)
Пример #33
0
reco_space = odl.uniform_discr(-domain_size / 2, domain_size / 2, domain_size)

# Create geometry
apart = odl.uniform_partition(0, 2 * np.pi, n_angles)
dpart = odl.uniform_partition([-500, -500], [500, 500], [det_size, det_size])
geometry = odl.tomo.ConeFlatGeometry(apart,
                                     dpart,
                                     src_radius=500,
                                     det_radius=500)

phantom = odl.phantom.shepp_logan(reco_space, modified=True).asarray()

# --- ASTRA ---

# Define ASTRA geometry
astra_vol_geom = astra.create_vol_geom(*domain_size)
det_row_count = geometry.det_partition.shape[1]
det_col_count = geometry.det_partition.shape[0]
vec = odl.tomo.backends.astra_setup.astra_conebeam_3d_geom_to_vec(geometry)
astra_proj_geom = astra.create_proj_geom('cone_vec', det_row_count,
                                         det_col_count, vec)

# Create ASTRA projector
proj_cfg = {}
proj_cfg['type'] = 'cuda3d'
proj_cfg['VolumeGeometry'] = astra_vol_geom
proj_cfg['ProjectionGeometry'] = astra_proj_geom
proj_cfg['options'] = {}
proj_id = astra.projector3d.create(proj_cfg)

# Create sinogram
strg = fl.read()
fl.close()

oplist = json.loads(strg)

ang = np.linspace(0, np.pi, 256, False)
sz = 256

fp, imgs = lorentzphantom.generate.fp(oplist,
                                      np.linspace(0, 1, len(ang)),
                                      ang, (sz, sz),
                                      fpfunc=lorentzphantom.forwproj.astrafp)
fp = astra.add_noise_to_sino(fp, 10**3)

proj_geom = astra.create_proj_geom('parallel', 1.0, sz, ang)
vol_geom = astra.create_vol_geom(sz)
pid = astra.create_projector('cuda', proj_geom, vol_geom)

w = astra.OpTomo(pid)

rec = w.reconstruct('FBP_CUDA', fp, iterations=1)

import pylab as pl
pl.gray()
pl.imshow(fp)
pl.show()
pl.imshow(rec)
pl.show()
pl.imshow(imgs[0] + imgs[-1])
pl.show()
#(at your option) any later version.
#
#The Python interface to the ASTRA Toolbox is distributed in the hope that it will be useful,
#but WITHOUT ANY WARRANTY; without even the implied warranty of
#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
#GNU General Public License for more details.
#
#You should have received a copy of the GNU General Public License
#along with the Python interface to the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
#
#-----------------------------------------------------------------------

import astra
import numpy as np

vol_geom = astra.create_vol_geom(128, 128, 128)

angles = np.linspace(0, np.pi, 180, False)
proj_geom = astra.create_proj_geom('parallel3d', 1.0, 1.0, 128, 192, angles)

# Create a simple hollow cube phantom
cube = np.zeros((128, 128, 128))
cube[17:113, 17:113, 17:113] = 1
cube[33:97, 33:97, 33:97] = 0

# Create projection data from this
proj_id, proj_data = astra.create_sino3d_gpu(cube, proj_geom, vol_geom)

# Display a single projection image
import pylab
Пример #36
0
#(at your option) any later version.
#
#The Python interface to the ASTRA Toolbox is distributed in the hope that it will be useful,
#but WITHOUT ANY WARRANTY; without even the implied warranty of
#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
#GNU General Public License for more details.
#
#You should have received a copy of the GNU General Public License
#along with the Python interface to the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
#
#-----------------------------------------------------------------------

import astra

# Create two volume geometries
vol_geom1 = astra.create_vol_geom(256, 256)
vol_geom2 = astra.create_vol_geom(512, 256)

# Create volumes
v0 = astra.data2d.create('-vol', vol_geom1)
v1 = astra.data2d.create('-vol', vol_geom2)
v2 = astra.data2d.create('-vol', vol_geom2)

# Show the currently allocated volumes
astra.data2d.info()


astra.data2d.delete(v2)
astra.data2d.info()

astra.data2d.clear()
Пример #37
0
        # vector from detector pixel (0,0) to (1,0)
        vectors[i, 9] = np.cos(omi)
        vectors[i, 10] = np.sin(omi)
        vectors[i, 11] = 0

    return vectors


def adjustcenter(dataarray, mp):
    new_array = dataarray[mp[0] - 100:mp[0] + 100, :, mp[1] - 100:mp[1] + 100]
    return new_array


# Create volume geometry
vol_geom = astra.create_vol_geom(150, 150, 150)

# Omega angles, create vector array
# angles = np.linspace(0, 2 * np.pi, 721, True)
angles = np.load('/home/gpu/astra_input/recon4x4/omega.npy')
vectors = makevectors(angles)

# Create projection geometry from vector array
proj_geom = astra.create_proj_geom('parallel3d_vec', 150, 150, vectors)
# proj_geom = astra.create_proj_geom('parallel3d', 1.0, 1.0, 180, 180, angles)

# Import dataset as (u, angles, v). u and v are columns and rows.
proj_data = np.load('/home/gpu/astra_input/recon4x4/dataarray.npy')
# proj_data = np.load('/u/data/andcj/astra-recon-data/recon90/dataarray.npy')
# proj_data = adjustcenter(proj_data, [128, 125])
Пример #38
0
def fp(im, ang):
    proj_geom = astra.create_proj_geom('parallel', 1.0, im.shape[0], np.array([ang,0]))
    vol_geom = astra.create_vol_geom(im.shape)
    w = astra.OpTomo('cuda',proj_geom,vol_geom)
    fpim = w*im
    return w[0:im.shape[0]]
Пример #39
0
#-*-coding:utf-8_*_
from PIL import Image
import numpy as np
import matplotlib.pyplot as plt
import astra

# 1. load sinogram
sinogram = Image.open('sinogram_remove_line.tiff')
sinogram = np.array(sinogram, dtype=np.float)
plt.figure(), plt.imshow(sinogram, cmap='gray')

# 2. creat geometries
# proj_geom = astra.create_proj_geom('fanflat', 0.13, sinogram.shape[1], np.linspace(0, np.pi, sinogram.shape[0]), 132, 148)
proj_geom = astra.create_proj_geom('parallel', 0.25, sinogram.shape[1],
                                   np.linspace(0, np.pi, sinogram.shape[0]))
vol_geom = astra.create_vol_geom(512, 512)

# 3. creat data id
recon_id = astra.data2d.create('-vol', vol_geom)
proj_id = astra.data2d.create('-sino', proj_geom, sinogram)

projector_id = astra.create_projector('line', proj_geom, vol_geom)

# 4. config and creat algorithm
cfg = astra.astra_dict('FBP_CUDA')
cfg['ReconstructionDataId'] = recon_id
cfg['ProjectionDataId'] = proj_id
cfg['ProjectorId'] = projector_id
alg_id = astra.algorithm.create(cfg)

# 5. run algorithm
Пример #40
0
def recon_astra(sinogram,
                center,
                angles=None,
                ratio=1.0,
                method="FBP_CUDA",
                num_iter=1,
                filter_type="hann",
                pad=0):
    """
    Wrapper of reconstruction methods implemented in the astra toolbox package.
    https://www.astra-toolbox.com/docs/algs/index.html

    Parameters
    ----------
    sinogram : float
        2D tomographic data.
    center : float
        Center of rotation.
    angles : float
        1D array. Tomographic angles in radian.
    ratio : float
        To apply a circle mask to the reconstructed image.
    method : str
        Reconstruction algorithms. for CPU: 'FBP', 'SIRT', 'SART', 'ART',
        'CGLS'. for GPU: 'FBP_CUDA', 'SIRT_CUDA', 'SART_CUDA', 'CGLS_CUDA'.
    num_iter : int
        Number of iterations if using iteration methods.
    filter_type : str
        Apply filter if using FBP method. Options: 'hamming', 'hann', 
        'lanczos', 'kaiser', 'parzen',...
    pad : int
        Padding to reduce the side effect of FFT.

    Returns
    -------
    float
        Square array.
    """
    if pad > 0:
        sinogram = np.pad(sinogram, ((0, 0), (pad, pad)), mode='edge')
        center = center + pad
    (nrow, ncol) = sinogram.shape
    if angles is None:
        angles = np.linspace(0.0, 180.0, nrow) * np.pi / 180.0
    proj_geom = astra.create_proj_geom('parallel', 1, ncol, angles)
    vol_geom = astra.create_vol_geom(ncol, ncol)
    cen_col = (ncol - 1.0) / 2.0
    shift = cen_col - center
    sinogram = interpolation.shift(sinogram, (0, shift), mode='nearest')
    sino_id = astra.data2d.create('-sino', proj_geom, sinogram)
    rec_id = astra.data2d.create('-vol', vol_geom)
    if "CUDA" not in method:
        proj_id = astra.create_projector('line', proj_geom, vol_geom)
    cfg = astra.astra_dict(method)
    cfg['ProjectionDataId'] = sino_id
    cfg['ReconstructionDataId'] = rec_id
    if "CUDA" not in method:
        cfg['ProjectorId'] = proj_id
    if (method == "FBP_CUDA") or (method == "FBP"):
        cfg["FilterType"] = filter_type
    alg_id = astra.algorithm.create(cfg)
    astra.algorithm.run(alg_id, num_iter)
    rec = astra.data2d.get(rec_id)
    astra.algorithm.delete(alg_id)
    astra.data2d.delete(sino_id)
    astra.data2d.delete(rec_id)
    if pad > 0:
        rec = rec[pad:-pad, pad:-pad]
    if ratio is not None:
        rec = rec * cirle_mask(rec.shape[0], ratio)
    return rec
Пример #41
0
import pylab
import six

import sirt3d_plugin
import time

if __name__ == '__main__':

    pylab.gray()
    #Setup ASTRA logging
    #astra.log.setOutputScreen(astra.log.STDOUT,astra.log.DEBUG)
    #astra.log.setOutputFile("sirt3d.txt", astra.log.DEBUG)

    X = 128

    vol_geom = astra.create_vol_geom(X, X, X)
    angles = np.linspace(0, np.pi, 180, False)
    proj_geom = astra.create_proj_geom('parallel3d', 1.0, 1.0, 128, 192,
                                       angles)

    # Create a simple hollow cube phantom
    cube = np.zeros((X, X, X))
    cube[17:113, 17:113, 17:113] = 1
    cube[33:97, 33:97, 33:97] = 0

    # Modify the geometry to support distributed execution and then proceed as before
    proj_geom, vol_geom = mpi.create(proj_geom, vol_geom)

    # Create projection data from this volume
    proj_id, proj_data = astra.create_sino3d_gpu(cube, proj_geom, vol_geom)
Пример #42
0
    def __init__(self, datadir, centre_est):

        centre_est = centre_est.split(',')
        mp = [int(centre_est[0]), int(centre_est[1])]

        def makevectors(om):
            vectors = np.zeros((len(om), 12))
            mu = np.radians(10.2)
            factor = np.sin(mu) / np.tan(mu)

            for i, omi in enumerate(om):

                # ray direction
                vectors[i, 0] = np.cos(omi) * np.cos(mu)
                vectors[i, 1] = np.sin(mu)
                vectors[i, 2] = -np.sin(omi) * np.cos(mu)

                # center of detector
                vectors[i, 3] = 0
                vectors[i, 4] = 0
                vectors[i, 5] = 0

                # vector from detector pixel (0,0) to (0,1)
                vectors[i, 6] = np.sin(omi)
                vectors[i, 7] = 0
                vectors[i, 8] = np.cos(omi)

                # vector from detector pixel (0,0) to (1,0)
                vectors[i, 9] = np.cos(omi)
                vectors[i, 10] = np.cos(mu)
                vectors[i, 11] = -np.sin(mu) * np.sin(omi)

            return vectors

        def adjustcenter(dataarray, mp):
            new_array = dataarray[int(mp[0]) - 100:int(mp[0]) + 100, :,
                                  int(mp[1]) - 100:int(mp[1]) + 100]
            return new_array

        # Create volume geometry
        vol_geom = astra.create_vol_geom(300, 300, 300)

        # Omega angles, create vector array
        # angles = np.linspace(0, 2 * np.pi, 721, True)
        angles = np.load(datadir + 'omega.npy')
        vectors = makevectors(angles)

        # Import dataset as (u, angles, v). u and v are columns and rows.
        proj_data = np.load(datadir + 'summed_data_astra.npy')
        # proj_data = np.load('/u/data/andcj/astra-recon-data/recon90/dataarray.npy')
        #proj_data = adjustcenter(proj_data, [128, 125])

        # Create projection geometry from vector array
        proj_geom = astra.create_proj_geom('parallel3d_vec',
                                           proj_data.shape[0],
                                           proj_data.shape[2], vectors)
        # proj_geom = astra.create_proj_geom('parallel3d', 1.0, 1.0, 180, 180, angles)

        # Create projection ID.
        proj_id = astra.data3d.create('-proj3d', proj_geom, proj_data)

        # Create reconstruction ID.
        rec_id = astra.data3d.create('-vol', vol_geom)
        cfg = astra.astra_dict('SIRT3D_CUDA')
        cfg['ReconstructionDataId'] = rec_id
        cfg['ProjectionDataId'] = proj_id
        # cfg['option'] = {}
        # cfg['option']['GPUindex'] = [0, 1, 2]

        # Create algorithm.
        alg_id = astra.algorithm.create(cfg)

        steps = 250
        print "Running algorithm, {} steps.".format(steps)
        astra.algorithm.run(alg_id, steps)

        # Get the result
        rec = astra.data3d.get(rec_id)

        rec = (rec - np.min(rec)) / (-np.min(rec) + np.max(rec))

        # fig = pl.figure(3, figsize=pl.figaspect(1.0))
        # ax = p3.Axes3D(fig)

        # for ix in range(np.shape(rec)[0]):
        # 	print 'line {}'.format(ix)
        # 	for iy in range(np.shape(rec)[1]):
        # 		for iz in range(np.shape(rec)[2]):
        # 			if rec[ix, iy, iz] < 0.7 and rec[ix, iy, iz] > 0.2:
        # 				cax = ax.scatter3D(
        # 					ix, iy, iz, s=2, c=rec[ix, iy, iz])

        rs = np.shape(rec)
        b_frame = 10

        cropped_rec = rec[b_frame:rs[0] - b_frame, b_frame:rs[1] - b_frame,
                          b_frame:rs[2] - b_frame]

        fig = plt.figure(frameon=False)

        for i, image in enumerate(cropped_rec):
            fig.set_size_inches(1, 1)
            ax = plt.Axes(fig, [0., 0., 1., 1.])
            # ax.set_axis_off()
            fig.add_axes(ax)
            ax.set_axis_off()
            extent = ax.get_window_extent().transformed(
                plt.gcf().dpi_scale_trans.inverted())

            ax.imshow(image, interpolation="none")
            fig.savefig('output/slice{:04d}.png'.format(i),
                        dpi=np.shape(cropped_rec)[0])
            ax.clear()
Пример #43
0
# (at your option) any later version.
#
# The ASTRA Toolbox is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
#
# -----------------------------------------------------------------------

import astra
import numpy as np

vol_geom = astra.create_vol_geom(256, 256)

proj_geom = astra.create_proj_geom('parallel', 1.0, 384,
                                   np.linspace(0, np.pi, 180, False))

# Create volumes

# initialized to zero
v0 = astra.data2d.create('-vol', vol_geom)

# initialized to 3.0
v1 = astra.data2d.create('-vol', vol_geom, 3.0)

# initialized to a matrix. A may be a single, double or logical (0/1) array.
import scipy.io
A = scipy.io.loadmat('phantom.mat')['phantom256']
Пример #44
0
    def __init__(self,
                 slice_shape,
                 angles,
                 dwidth=None,
                 rot_center=None,
                 fullscan=False,
                 cudafbp=False,
                 super_sampling=None):
        """
        Create a tomography parallel beam geometry.

        Parameters
        -----------
        slice_shape: int or tuple
            Shape of the slice. Can be in the form (n_x, n_y) or N.
            If the argument is an integer N, the slice is assumed to be square of dimensions (N, N).
            Mind that if providing (n_x, n_y), n_x is the number of columns of the image.
        angles: integer or numpy.ndarray
            Projection angles in radians.
            If this argument is an integer, the projections angles are linear between [0, pi[ if fullscan=False,
            or in [0, 2*pi[ if fullscan=True.
            If this argument is a 1D array, this means that custom angles (in radians) are provided.
        dwidth: (optional) integer
            detector width (number of pixels). If not provided, max(n_x, n_y) is taken.
        rot_center: (optional) float
            user-defined rotation center. If not provided, dwidth/2 is taken.
        fullscan: (optional) boolean, default is False
            if True, use a 360 scan geometry.
        cudafbp: (optionnal) boolean, default is False
            If True, use the built-in FBP of ASTRA instead of using Python to filter the projections.
        super_sampling: integer
            Detector and Pixel supersampling
        """

        if isinstance(slice_shape, int):
            n_x, n_y = slice_shape, slice_shape
        else:
            slice_shape = tuple(slice_shape)
            n_x, n_y = slice_shape
        if dwidth is None: dwidth = max(n_x, n_y)
        angle_max = np.pi
        if fullscan: angle_max *= 2

        if isinstance(angles, int):
            angles = np.linspace(0, angle_max, angles, False)
        n_angles = angles.shape[0]

        self.vol_geom = astra.create_vol_geom(n_x, n_y)
        self.proj_geom = astra.create_proj_geom('parallel', 1.0, dwidth,
                                                angles)

        if rot_center:
            o_angles = np.ones(n_angles) if isinstance(
                n_angles, int) else np.ones_like(n_angles)
            self.proj_geom['option'] = {
                'ExtraDetectorOffset': (rot_center - n_x / 2.) * o_angles
            }
        self.proj_id = astra.create_projector('cuda', self.proj_geom,
                                              self.vol_geom)

        # vg : Volume geometry
        self.vg = astra.projector.volume_geometry(self.proj_id)
        # pg : projection geometry
        self.pg = astra.projector.projection_geometry(self.proj_id)

        # ---- Configure Projector ------
        # sinogram shape
        self.sshape = astra.functions.geom_size(self.pg)
        # Configure projector
        self.cfg_proj = astra.creators.astra_dict('FP_CUDA')
        self.cfg_proj['ProjectorId'] = self.proj_id
        if super_sampling:
            self.cfg_proj['option'] = {'DetectorSuperSampling': super_sampling}

        # ---- Configure Backprojector ------
        # volume shape
        self.vshape = astra.functions.geom_size(self.vg)
        # Configure backprojector
        if cudafbp:
            self.cfg_backproj = astra.creators.astra_dict('FBP_CUDA')
            self.cfg_backproj['FilterType'] = 'Ram-Lak'
        else:
            self.cfg_backproj = astra.creators.astra_dict('BP_CUDA')
        self.cfg_backproj['ProjectorId'] = self.proj_id
        if super_sampling:
            self.cfg_backproj['option'] = {
                'PixelSuperSampling': super_sampling
            }
        # -------------------
        self.n_x = n_x
        self.n_y = n_y
        self.dwidth = dwidth
        self.n_a = angles.shape[0]
        self.rot_center = rot_center if rot_center else dwidth // 2
        self.angles = angles
        self.cudafbp = cudafbp
        if not (cudafbp):
            _ramp = self.compute_ramp_filter(
                dwidth * 2) * 2.0  # *2: compat. with PyHST2
            self.rampfilter = np.abs(np.fft.fft(_ramp))
        else:
            self.rampfilter = None
Пример #45
0
# The ASTRA Toolbox is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
#
# -----------------------------------------------------------------------

import astra
import numpy as np

# Create a 3D volume geometry.
# Parameter order: rows, colums, slices (y, x, z)
vol_geom = astra.create_vol_geom(64, 48, 32)

# Create volumes

# initialized to zero
v0 = astra.data3d.create('-vol', vol_geom)

# initialized to 3.0
v1 = astra.data3d.create('-vol', vol_geom, 3.0)

# initialized to a matrix. A may be a single or double array.
# Coordinate order: slice, row, column (z, y, x)
A = np.zeros((32, 64, 48))
v2 = astra.data3d.create('-vol', vol_geom, A)

# Projection data
Пример #46
0
#
# You should have received a copy of the GNU General Public License
# along with the Python interface to the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
#
# -----------------------------------------------------------------------

import astra
import numpy as np

# Create numpy array
shape = (10, 20, 30)
x, y, z = shape
A = np.zeros(shape)

# Create a 3D volume geometry.
vol_geom = astra.create_vol_geom(y, z, x)
print(vol_geom)
vol_geom = astra.create_vol_geom(
    y,
    z,
    x,
    -30 / 2,
    30 / 2,
    -20 / 2,
    20 / 2,
    -10 / 2,
    10 / 2,
)
print(vol_geom)

# Create volumes
Пример #47
0
#
# You should have received a copy of the GNU General Public License
# along with the Python interface to the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
#
# -----------------------------------------------------------------------

try:
    from six.moves import range
except ImportError:
    # six 1.3.0
    from six.moves import xrange as range
import astra
import numpy as np
import matplotlib.pyplot as plt

vol_geom = astra.create_vol_geom(64, 64, 64)

# There are two main 3d projection geometry types: cone beam and parallel beam.
# Each has a regular variant, and a 'vec' variant.
# The 'vec' variants are completely free in the placement of source/detector,
# while the regular variants assume circular trajectories around the z-axis.

# -------------
# Parallel beam
# -------------

# Circular

# Parameters: width of detector column, height of detector row, #rows, #columns
angles = np.linspace(0, 2 * np.pi, 48, False)
proj_geom = astra.create_proj_geom('parallel3d', 1.0, 1.0, 32, 64, angles)
Пример #48
0
def convert_geometry_to_astra(volume_geometry, sinogram_geometry):
    '''Set up ASTRA Volume and projection geometry, not stored

       :param volume_geometry: ccpi.framework.ImageGeometry
       :param sinogram_geometry: ccpi.framework.AcquisitionGeometry
       
       :returns ASTRA volume and sinogram geometry'''

    # determine if the geometry is 2D or 3D
    horiz = sinogram_geometry.pixel_num_h
    vert = sinogram_geometry.pixel_num_v
    if vert >= 1:
        dimension = '3D'
    elif vert == 0:
        dimension = '2D'
    else:
        raise ValueError(
            'Number of pixels at detector on the vertical axis must be >= 0. Got {}'
            .format(vert))

    if dimension == '2D':
        vol_geom = astra.create_vol_geom(volume_geometry.voxel_num_x,
                                         volume_geometry.voxel_num_y,
                                         volume_geometry.get_min_x(),
                                         volume_geometry.get_max_x(),
                                         volume_geometry.get_min_y(),
                                         volume_geometry.get_max_y())

        if sinogram_geometry.geom_type == 'parallel':
            proj_geom = astra.create_proj_geom('parallel',
                                               sinogram_geometry.pixel_size_h,
                                               sinogram_geometry.pixel_num_h,
                                               sinogram_geometry.angles)
        elif sinogram_geometry.geom_type == 'cone':
            proj_geom = astra.create_proj_geom(
                'fanflat', sinogram_geometry.pixel_size_h,
                sinogram_geometry.pixel_num_h, sinogram_geometry.angles,
                np.abs(sinogram_geometry.dist_source_center),
                np.abs(sinogram_geometry.dist_center_detector))
        else:
            NotImplemented

    elif dimension == '3D':
        vol_geom = astra.create_vol_geom(volume_geometry.voxel_num_x,
                                         volume_geometry.voxel_num_y,
                                         volume_geometry.voxel_num_z,
                                         volume_geometry.get_min_x(),
                                         volume_geometry.get_max_x(),
                                         volume_geometry.get_min_y(),
                                         volume_geometry.get_max_y(),
                                         volume_geometry.get_min_z(),
                                         volume_geometry.get_max_z())

        if sinogram_geometry.geom_type == 'parallel':
            proj_geom = astra.create_proj_geom('parallel3d',
                                               sinogram_geometry.pixel_size_h,
                                               sinogram_geometry.pixel_size_v,
                                               sinogram_geometry.pixel_num_v,
                                               sinogram_geometry.pixel_num_h,
                                               sinogram_geometry.angles)
        elif sinogram_geometry.geom_type == 'cone':
            proj_geom = astra.create_proj_geom(
                'cone', sinogram_geometry.pixel_size_h,
                sinogram_geometry.pixel_size_v, sinogram_geometry.pixel_num_v,
                sinogram_geometry.pixel_num_h, sinogram_geometry.angles,
                np.abs(sinogram_geometry.dist_source_center),
                np.abs(sinogram_geometry.dist_center_detector))
        else:
            NotImplemented

    else:
        NotImplemented

    return vol_geom, proj_geom
Пример #49
0
# along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
#
# -----------------------------------------------------------------------

import astra
import numpy as np

# Set up multi-GPU usage.
# This only works for 3D GPU forward projection and back projection.
astra.astra.set_gpu_index([0,1])

# Optionally, you can also restrict the amount of GPU memory ASTRA will use.
# The line commented below sets this to 1GB.
#astra.astra.set_gpu_index([0,1], memory=1024*1024*1024)

vol_geom = astra.create_vol_geom(1024, 1024, 1024)

angles = np.linspace(0, np.pi, 1024,False)
proj_geom = astra.create_proj_geom('parallel3d', 1.0, 1.0, 1024, 1024, angles)

# Create a simple hollow cube phantom
cube = np.zeros((1024,1024,1024))
cube[128:895,128:895,128:895] = 1
cube[256:767,256:767,256:767] = 0

# Create projection data from this
proj_id, proj_data = astra.create_sino3d_gpu(cube, proj_geom, vol_geom)

# Backproject projection data
bproj_id, bproj_data = astra.create_backprojection3d_gpu(proj_data, proj_geom, vol_geom)
Пример #50
0
def NNFDK_astra(g,
                NW,
                geom,
                reco_space,
                w_du,
                Exp_op,
                node_output,
                ang_freq=None):
    # %% Create geometry
    # Make a circular scanning geometry
    ang, u, v = g.shape
    minvox = reco_space.min_pt[0]
    maxvox = reco_space.max_pt[0]
    vox = np.shape(reco_space)[0]
    vol_geom = astra.create_vol_geom(vox, vox, vox, minvox, maxvox, minvox,
                                     maxvox, minvox, maxvox)

    if type(geom) == np.ndarray:
        vecs = geom
        proj_geom = astra.create_proj_geom('cone_vec', v, u, vecs)
    elif type(geom) == odl.tomo.geometry.conebeam.ConeFlatGeometry:
        angles = np.linspace((1 / ang) * np.pi, (2 + 1 / ang) * np.pi, ang,
                             False)
        w_du, w_dv = 2 * geom.detector.partition.max_pt / [u, v]
        proj_geom = astra.create_proj_geom('cone', w_dv, w_du, v, u, angles,
                                           geom.src_radius, geom.det_radius)

    g = np.transpose(np.asarray(g), (2, 0, 1))
    # %%
    proj_id = astra.data3d.create('-proj3d', proj_geom, g)
    rec = np.zeros(astra.geom_size(vol_geom), dtype=np.float32)

    rec_tot = np.zeros(astra.geom_size(vol_geom), dtype=np.float32)

    rec_id = astra.data3d.link('-vol', vol_geom, rec)

    fullFilterSize = int(2**(np.ceil(np.log2(u)) + 1))
    halfFilterSize = fullFilterSize // 2 + 1
    filter2d = np.zeros((ang, halfFilterSize))
    Resize_Op = odl.ResizingOperator(Exp_op.range, ran_shp=(fullFilterSize, ))
    # %% Make a filter geometry

    filter_geom = astra.create_proj_geom('parallel', w_du, halfFilterSize,
                                         np.zeros(ang))

    cfg = astra.astra_dict('FDK_CUDA')
    cfg['ReconstructionDataId'] = rec_id
    cfg['ProjectionDataId'] = proj_id

    # Create the algorithm object from the configuration structure
    # %%
    # Set a container list for the learned filters
    h_e = []
    if node_output:
        mid = v // 2
        node_output_axis = []

    for i in range(NW['nNodes']):
        h = NW['l1'][:-1, i] * 2 * NW['sc1'][0, :]
        h_e += [h]
        b = NW['l1'][-1, i] + np.sum(
            NW['l1'][:-1, i]) + 2 * np.dot(NW['l1'][:-1, i], NW['sc1'][1, :])
        filter2d = Exp_op_FFT(Exp_op, h, filter2d, Resize_Op, w_du)

        filter_id = astra.data2d.create('-sino', filter_geom, filter2d)
        cfg['option'] = {'FilterSinogramId': filter_id}
        alg_id = astra.algorithm.create(cfg)
        astra.algorithm.run(alg_id)
        rec_tot = hidden_layer(rec, rec_tot, NW['l2'][i], b)
        if node_output:
            rec2 = hidden_layer(rec, 0, NW['l2'][i], b)
            node_output_axis += [
                rec2[:, :, mid], rec2[:, mid, :], rec2[mid, :, :]
            ]

    # Make a numpy array of the filter list
    h_e = np.asarray(h_e)
    # b_o = self.network['l2'][-1]
    rec_tot = outer_layer(rec_tot, NW['l2'][-1], NW['sc2'][0], NW['sc2'][1])
    rec_tot = np.transpose(rec_tot, (2, 1, 0))

    # %% Make the matrix columns of the matrix B

    # %%
    # Clean up. Note that GPU memory is tied up in the algorithm object,
    # and main RAM in the data objects.
    astra.algorithm.delete(alg_id)
    astra.data3d.delete(rec_id)
    astra.data3d.delete(proj_id)
    if node_output:
        return rec_tot, h_e, node_output_axis
    else:
        return rec_tot, h_e
Пример #51
0
#(at your option) any later version.
#
#The Python interface to the ASTRA Toolbox is distributed in the hope that it will be useful,
#but WITHOUT ANY WARRANTY; without even the implied warranty of
#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
#GNU General Public License for more details.
#
#You should have received a copy of the GNU General Public License
#along with the Python interface to the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
#
#-----------------------------------------------------------------------

import astra
import numpy as np

vol_geom = astra.create_vol_geom(64, 64, 64)


# There are two main 3d projection geometry types: cone beam and parallel beam.
# Each has a regular variant, and a 'vec' variant.
# The 'vec' variants are completely free in the placement of source/detector,
# while the regular variants assume circular trajectories around the z-axis.


# -------------
# Parallel beam
# -------------


# Circular
Пример #52
0
def astra_volume_geometry(discr_reco):
    """Create an ASTRA volume geometry from the discretized domain.

    From the ASTRA documentation:

    In all 3D geometries, the coordinate system is defined around the
    reconstruction volume. The center of the reconstruction volume is the
    origin, and the sides of the voxels in the volume have length 1.

    All dimensions in the projection geometries are relative to this unit
    length.


    Parameters
    ----------
    discr_reco : `DiscreteLp`
        Discretization of an L2 space on the reconstruction domain.
        It must be 2- or 3-dimensional and uniformly discretized.

    Returns
    -------
    astra_geom : dict
        The ASTRA volume geometry

    Raises
    ------
    NotImplementedError
        if the cell sizes are not the same in each dimension
    """
    # TODO: allow other discretizations?
    if not isinstance(discr_reco, DiscreteLp):
        raise TypeError('`discr_reco` {!r} is not a DiscreteLp instance'
                        ''.format(discr_reco))

    if not discr_reco.is_uniform:
        raise ValueError('`discr_reco` {} is not uniformly discretized')

    vol_shp = discr_reco.partition.shape
    vol_min = discr_reco.partition.min_pt
    vol_max = discr_reco.partition.max_pt

    if discr_reco.ndim == 2:
        # ASTRA does in principle support custom minimum and maximum
        # values for the volume extent, but projector creation fails
        # if voxels are non-isotropic. We raise an exception here in
        # the meanwhile.
        if not np.allclose(discr_reco.partition.cell_sides[1:],
                           discr_reco.partition.cell_sides[:-1]):
            raise NotImplementedError('non-isotropic voxels not supported by '
                                      'ASTRA')
        # given a 2D array of shape (x, y), a volume geometry is created as:
        #    astra.create_vol_geom(x, y, y_min, y_max, x_min, x_max)
        # yielding a dictionary:
        #   'GridColCount': y,
        #   'GridRowCount': x
        #   'WindowMaxX': y_max
        #   'WindowMaxY': x_max
        #   'WindowMinX': y_min
        #   'WindowMinY': x_min
        vol_geom = astra.create_vol_geom(vol_shp[0], vol_shp[1],
                                         vol_min[1], vol_max[1],
                                         vol_min[0], vol_max[0])
    elif discr_reco.ndim == 3:
        # Non-isotropic voxels are not yet supported in 3d ASTRA
        if not np.allclose(discr_reco.partition.cell_sides[1:],
                           discr_reco.partition.cell_sides[:-1]):
            # TODO: for parallel geometries, one can work around this issue
            raise NotImplementedError('non-isotropic voxels not supported by '
                                      'ASTRA')
        # given a 3D array of shape (x, y, z), a volume geometry is created as:
        #    astra.create_vol_geom(y, z, x, )
        # yielding a dictionary:
        #   'GridColCount': z
        #   'GridRowCount': y
        #   'GridSliceCount': x
        #   'WindowMinX': z_max
        #   'WindowMaxX': z_max
        #   'WindowMinY': y_min
        #   'WindowMaxY': y_min
        #   'WindowMinZ': x_min
        #   'WindowMaxZ': x_min
        vol_geom = astra.create_vol_geom(vol_shp[1], vol_shp[2], vol_shp[0],
                                         vol_min[2], vol_max[2],
                                         vol_min[1], vol_max[1],
                                         vol_min[0], vol_max[0])
    else:
        raise ValueError('{}-dimensional volume geometries not supported '
                         'by ASTRA'.format(discr_reco.ndim))
    return vol_geom
    pylab.gray()
    pylab.imshow(rec_low[0.50*vol_size_low,:,:])
    pylab.figure()
    pylab.imshow(rec_low[:,0.50*vol_size_low,:]) 
    pylab.show()
#

rec_low_temp=np.zeros((vol_size_low,vol_size_low,vol_size_low),dtype= np.float16)


##################################HERE Multi resolution starts
ii=0

x_parts,y_parts, z_parts=create_parts(nr_subvol_x,nr_subvol_y,nr_subvol_z) 

vol_geom_low = astra.create_vol_geom(vol_size_low, vol_size_low, vol_size_low)
proj_geom_low = astra.create_proj_geom('cone',  det_spacing_x_low, det_spacing_y_low, det_row_count, det_col_count, angles, source_origin, origin_det)
algon_high=raw_input("Algo high: ")
for n_x in x_parts:
    for n_y in y_parts:
        for n_z in z_parts: ## nr_subvol_z
            rec_low_temp[:,:,:]=rec_low[:,:,:]
            rec_low_temp[x_sub_boundaries[n_x,1] / vol_size_ratio:x_sub_boundaries[n_x+1,2] / vol_size_ratio, y_sub_boundaries[n_y,1] / vol_size_ratio:y_sub_boundaries[n_y+1,2] / vol_size_ratio, z_sub_boundaries[n_z,1] / vol_size_ratio:z_sub_boundaries[n_z+1,2] / vol_size_ratio] = 0

            proj_id_low, proj_data_low = astra.create_sino3d_gpu(rec_low_temp, proj_geom_low, vol_geom_low)
            astra.data3d.delete(proj_id_low)
            x_start=x_sub_boundaries[n_x,1]
            x_stop=x_sub_boundaries[n_x+1,2]
            h_start=FOV/2 - x_start
            h_stop=FOV/2 - x_stop  #height
            if x_start==0:
Пример #54
0
    def __init__(self, DetectorsDim, AnglesVec, CenterRotOffset, ObjSize, OS,
                 device):
        self.DetectorsDim = DetectorsDim
        self.AnglesVec = AnglesVec
        self.ObjSize = ObjSize

        ################ arrange ordered-subsets ################
        import numpy as np
        AnglesTot = np.size(AnglesVec)  # total number of angles
        self.NumbProjBins = (int)(np.ceil(
            float(AnglesTot) /
            float(OS)))  # get the number of projections per bin (subset)
        self.newInd_Vec = np.zeros(
            [OS, self.NumbProjBins],
            dtype='int')  # 2D array of OS-sorted indeces
        for sub_ind in range(OS):
            ind_sel = 0
            for proj_ind in range(self.NumbProjBins):
                indexS = ind_sel + sub_ind
                if (indexS < AnglesTot):
                    self.newInd_Vec[sub_ind, proj_ind] = indexS
                    ind_sel += OS

        # create full ASTRA geometry (to calculate Lipshitz constant)
        vectors = vec_geom_init2D(AnglesVec, 1.0, CenterRotOffset)
        self.proj_geom = astra.create_proj_geom('parallel_vec', DetectorsDim,
                                                vectors)
        self.vol_geom = astra.create_vol_geom(ObjSize, ObjSize)
        if device == 'cpu':
            self.proj_id = astra.create_projector('line', self.proj_geom,
                                                  self.vol_geom)  # for CPU
            self.device = 1
        elif device == 'gpu':
            self.proj_id = astra.create_projector('cuda', self.proj_geom,
                                                  self.vol_geom)  # for GPU
            self.device = 0
        else:
            print("Select between 'cpu' or 'gpu' for device")
        # create OS-specific ASTRA geometry
        self.proj_geom_OS = {}
        self.proj_id_OS = {}
        for sub_ind in range(OS):
            self.indVec = self.newInd_Vec[sub_ind, :]  # OS-specific indices
            if (self.indVec[self.NumbProjBins - 1] == 0):
                self.indVec = self.indVec[:-1]  #shrink vector size
            anglesOS = self.AnglesVec[self.indVec]  # OS-specific angles

            if np.ndim(CenterRotOffset) == 0:  # CenterRotOffset is a _scalar_
                vectorsOS = vec_geom_init2D(anglesOS, 1.0, CenterRotOffset)
                #self.proj_geom_OS[sub_ind] = astra.create_proj_geom('parallel', 1.0, DetectorsDim, anglesOS)
            else:  # CenterRotOffset is a _vector_
                vectorsOS = vec_geom_init2D(anglesOS, 1.0,
                                            CenterRotOffset[self.indVec])
            self.proj_geom_OS[sub_ind] = astra.create_proj_geom(
                'parallel_vec', DetectorsDim, vectorsOS)
            if self.device == 1:
                self.proj_id_OS[sub_ind] = astra.create_projector(
                    'line', self.proj_geom_OS[sub_ind],
                    self.vol_geom)  # for CPU
            if self.device == 0:
                self.proj_id_OS[sub_ind] = astra.create_projector(
                    'cuda', self.proj_geom_OS[sub_ind],
                    self.vol_geom)  # for GPU
#GNU General Public License for more details.
#
#You should have received a copy of the GNU General Public License
#along with the Python interface to the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
#
#-----------------------------------------------------------------------

try:
    from six.moves import range
except ImportError:
    # six 1.3.0
    from six.moves import xrange as range
import astra
import numpy as np

vol_geom = astra.create_vol_geom(64, 64, 64)

# There are two main 3d projection geometry types: cone beam and parallel beam.
# Each has a regular variant, and a 'vec' variant.
# The 'vec' variants are completely free in the placement of source/detector,
# while the regular variants assume circular trajectories around the z-axis.

# -------------
# Parallel beam
# -------------

# Circular

# Parameters: width of detector column, height of detector row, #rows, #columns
angles = np.linspace(0, 2 * np.pi, 48, False)
proj_geom = astra.create_proj_geom('parallel3d', 1.0, 1.0, 32, 64, angles)
Пример #56
0
data = np.load('nanotube2d.npy')
[Nan,Ndetx] = data.shape
angles = np.linspace(-50,50,Nan,True) * (np.pi/180)

# Intensity-offset correction
print('Intensity-offset correction...')
offset = -0.00893
data -= offset

# Setting reconstruction geometry
print('Configure projection and volume geometry...')
Nx = Ndetx
Nz = Ndetx
# create projection geometry and operator
proj_geom = astra.create_proj_geom('parallel', 1.0, Ndetx, angles)
vol_geom = astra.create_vol_geom(Nz,Nx)
proj_id = astra.create_projector('cuda',proj_geom,vol_geom)
W = astra.OpTomo(proj_id)

# Configuration of TVR-DART parameters
Ngv = 2 # number of material composition in the specimen (including vacuum)
K = 4*np.ones(Ngv-1) # sharpness of soft segmentation function
lamb = 10 # weight of TV
Niter = 50 # number of iterations

# Initial reconstruction and normalization
print('Initial reconstruction...')
import SIRT
recsirt = SIRT.recon(data, 50, proj_geom, vol_geom, 'cuda')
sf = np.max(recsirt)
data = data/sf
Пример #57
0
#(at your option) any later version.
#
#The Python interface to the ASTRA Toolbox is distributed in the hope that it will be useful,
#but WITHOUT ANY WARRANTY; without even the implied warranty of
#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
#GNU General Public License for more details.
#
#You should have received a copy of the GNU General Public License
#along with the Python interface to the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
#
#-----------------------------------------------------------------------

import astra

# Create two volume geometries
vol_geom1 = astra.create_vol_geom(256, 256)
vol_geom2 = astra.create_vol_geom(512, 256)

# Create volumes
v0 = astra.data2d.create('-vol', vol_geom1)
v1 = astra.data2d.create('-vol', vol_geom2)
v2 = astra.data2d.create('-vol', vol_geom2)

# Show the currently allocated volumes
astra.data2d.info()


astra.data2d.delete(v2)
astra.data2d.info()

astra.data2d.clear()
Пример #58
0
def convert_geometry_to_astra_vec(volume_geometry, sinogram_geometry_in):
    '''Set up ASTRA Volume and projection geometry, not stored

       :param volume_geometry: ccpi.framework.ImageGeometry
       :param sinogram_geometry: ccpi.framework.AcquisitionGeometry
       
       :returns ASTRA volume and sinogram geometry'''

    sinogram_geometry = sinogram_geometry_in.copy()
    sinogram_geometry.config.system.update_reference_frame()

    angles = sinogram_geometry.config.angles
    system = sinogram_geometry.config.system
    panel = sinogram_geometry.config.panel

    #get units
    degrees = False
    if angles.angle_unit == sinogram_geometry.DEGREE:
        degrees = True

    if sinogram_geometry.dimension == '2D':
        #create a 3D astra geom from 2D CIL geometry
        volume_geometry_temp = volume_geometry.copy()
        volume_geometry_temp.voxel_num_z = 1
        volume_geometry_temp.voxel_size_z = volume_geometry_temp.voxel_size_x

        if panel.pixel_size[1] != panel.pixel_size[0]:
            panel.pixel_size[1] = panel.pixel_size[0]

        row = numpy.zeros((3, 1))
        row[0] = panel.pixel_size[0] * system.detector.direction_x[0]
        row[1] = panel.pixel_size[0] * system.detector.direction_x[1]

        if 'right' in panel.origin:
            row *= -1

        col = numpy.zeros((3, 1))
        col[2] = panel.pixel_size[1]

        det = numpy.zeros((3, 1))
        det[0] = system.detector.position[0]
        det[1] = system.detector.position[1]

        src = numpy.zeros((3, 1))
        if sinogram_geometry.geom_type == 'parallel':
            src[0] = system.ray.direction[0]
            src[1] = system.ray.direction[1]
            projector = 'parallel3d_vec'
        else:
            src[0] = system.source.position[0]
            src[1] = system.source.position[1]
            projector = 'cone_vec'

    else:
        volume_geometry_temp = volume_geometry.copy()

        row = panel.pixel_size[0] * system.detector.direction_x.reshape(3, 1)
        col = panel.pixel_size[1] * system.detector.direction_y.reshape(3, 1)
        det = system.detector.position.reshape(3, 1)

        if 'right' in panel.origin:
            row *= -1
        if 'top' in panel.origin:
            col *= -1

        if sinogram_geometry.geom_type == 'parallel':
            src = system.ray.direction.reshape(3, 1)
            projector = 'parallel3d_vec'
        else:
            src = system.source.position.reshape(3, 1)
            projector = 'cone_vec'

    #Build for astra 3D only
    vectors = numpy.zeros((angles.num_positions, 12))

    for i, theta in enumerate(angles.angle_data):
        ang = -angles.initial_angle - theta
        rotation_matrix = Rotation.from_euler('z', ang,
                                              degrees=degrees).as_dcm()

        vectors[i, :3] = rotation_matrix.dot(src).reshape(3)
        vectors[i, 3:6] = rotation_matrix.dot(det).reshape(3)
        vectors[i, 6:9] = rotation_matrix.dot(row).reshape(3)
        vectors[i, 9:] = rotation_matrix.dot(col).reshape(3)

    proj_geom = astra.creators.create_proj_geom(projector, panel.num_pixels[1],
                                                panel.num_pixels[0], vectors)
    vol_geom = astra.create_vol_geom(volume_geometry_temp.voxel_num_y,
                                     volume_geometry_temp.voxel_num_x,
                                     volume_geometry_temp.voxel_num_z,
                                     volume_geometry_temp.get_min_x(),
                                     volume_geometry_temp.get_max_x(),
                                     volume_geometry_temp.get_min_y(),
                                     volume_geometry_temp.get_max_y(),
                                     volume_geometry_temp.get_min_z(),
                                     volume_geometry_temp.get_max_z())

    return vol_geom, proj_geom
Пример #59
0
def astra(*args):
    """
    Reconstruct object using the ASTRA toolbox

    Extra options
    ----------
    method : str
        ASTRA reconstruction method to use.
    num_iter : int, optional
        Number of algorithm iterations performed.
    proj_type : str, optional
        ASTRA projector type to use: 'line', 'linear', or 'strip' (CPU only).
    extra_options : dict, optional
        Extra options for the ASTRA config (i.e. those in cfg['option'])

    Warning
    -------
    When using CUDA, only 1 CPU core can be used.

    Example
    -------
    >>> import tomopy
    >>> obj = tomopy.shepp3d() # Generate an object.
    >>> ang = tomopy.angles(180) # Generate uniformly spaced tilt angles.
    >>> sim = tomopy.project(obj, ang) # Calculate projections.
    >>>
    >>> # Reconstruct object:
    >>> rec = tomopy.recon(sim, ang, algorithm=tomopy.astra,
    >>>       options={'method':'SART', 'num_iter':10*180, 'proj_type':'linear',
    >>>       'extra_options':{'MinConstraint':0}})
    >>>
    >>> # Show 64th slice of the reconstructed object.
    >>> import pylab
    >>> pylab.imshow(rec[64], cmap='gray')
    >>> pylab.show()
    """
    # Lazy import ASTRA
    import astra as astra_mod

    # Get shared arrays
    tomo = mproc.SHARED_TOMO
    recon = mproc.SHARED_ARRAY

    # Unpack arguments
    nang = args[0]
    nslices = args[1]
    ndet = args[2]
    centers = args[3]
    angles = args[4]
    num_gridx = args[5]['num_gridx']
    num_gridy = args[5]['num_gridy']
    opts = args[5]['options']
    istart = args[6]
    iend = args[7]

    # Check options
    for o in needed_options['astra']:
        if not o in opts:
            logger.error("Option %s needed for ASTRA reconstruction." % (o,))
            raise ValueError()
    for o in default_options['astra']:
        if not o in opts:
            opts[o] = default_options['astra'][o]

    # Create ASTRA geometries
    vol_geom = astra_mod.create_vol_geom((num_gridx,num_gridy))
    proj_geom = astra_mod.create_proj_geom('parallel',1.0,ndet,angles.astype(np.float64))

    # Create ASTRA data id
    sino = np.zeros((nang, ndet), dtype=np.float32)

    # Create ASTRA config
    cfg = astra_mod.astra_dict(opts['method'])

    if opts['proj_type']!='cuda':
        pi = astra_mod.create_projector(opts['proj_type'], proj_geom, vol_geom)
        sid = astra_mod.data2d.link('-sino', proj_geom, sino)
        cfg['ProjectorId'] = pi
        cfg['ProjectionDataId'] = sid
        use_cuda=False
    else:
        use_cuda=True

    if 'extra_options' in opts:
        cfg['option'] = opts['extra_options']
    else:
        cfg['option'] = {}

    # Perform reconstruction
    for i in xrange(istart, iend):
        sino[:] = tomo[:,i,:]

        cfg['option']['z_id']=i

        # Fix center of rotation
        if use_cuda:
            proj_geom['option'] = {'ExtraDetectorOffset': (centers[i]-ndet/2.)*np.ones(nang)}
            sid = astra_mod.data2d.link('-sino', proj_geom, sino)
            cfg['ProjectionDataId'] = sid
            pi = astra_mod.create_projector(opts['proj_type'], proj_geom, vol_geom)
            cfg['ProjectorId'] = pi
        else:
            # Temporary workaround, will be fixed in later ASTRA version
            shft = int(np.round(ndet/2.-centers[i]))
            sino[:] = np.roll(sino,shft)
            l = shft
            r = sino.shape[1]+shft
            if l<0: l=0
            if r>sino.shape[1]: r=sino.shape[1]
            sino[:,0:l]=0
            sino[:,r:sino.shape[1]]=0

        vid = astra_mod.data2d.link('-vol', vol_geom, recon[i])
        cfg['ReconstructionDataId'] = vid
        alg_id = astra_mod.algorithm.create(cfg)
        astra_mod.algorithm.run(alg_id, opts['num_iter'])
        astra_mod.algorithm.delete(alg_id)
        astra_mod.data2d.delete(vid)
        if use_cuda:
            astra_mod.projector.delete(pi)
            astra_mod.data2d.delete(sid)

    # Clean up
    if not use_cuda:
        astra_mod.projector.delete(pi)
        astra_mod.data2d.delete(sid)
Пример #60
0
def astra(tomo, center, recon, theta, **kwargs):
    """
    Reconstruct object using the ASTRA toolbox

    Extra options
    ----------
    method : str
        ASTRA reconstruction method to use.
    num_iter : int, optional
        Number of algorithm iterations performed.
    proj_type : str, optional
        ASTRA projector type to use (see ASTRA docs for more information):
            - 'cuda' (for GPU algorithms)
            - 'line', 'linear', or 'strip' (for CPU algorithms)
    gpu_list : list, optional
        List of GPU indices to use
    extra_options : dict, optional
        Extra options for the ASTRA config (i.e. those in cfg['option'])

    Example
    -------
    >>> import tomopy
    >>> obj = tomopy.shepp3d() # Generate an object.
    >>> ang = tomopy.angles(180) # Generate uniformly spaced tilt angles.
    >>> sim = tomopy.project(obj, ang) # Calculate projections.
    >>>
    >>> # Reconstruct object:
    >>> rec = tomopy.recon(sim, ang, algorithm=tomopy.astra,
    >>>       options={'method':'SART', 'num_iter':10*180,
    >>>       'proj_type':'linear',
    >>>       'extra_options':{'MinConstraint':0}})
    >>>
    >>> # Show 64th slice of the reconstructed object.
    >>> import pylab
    >>> pylab.imshow(rec[64], cmap='gray')
    >>> pylab.show()
    """
    # Lazy import ASTRA
    import astra as astra_mod

    # Unpack arguments
    nslices = tomo.shape[0]
    num_gridx = kwargs['num_gridx']
    num_gridy = kwargs['num_gridy']
    opts = kwargs['options']

    # Check options
    for o in needed_options['astra']:
        if o not in opts:
            logger.error("Option %s needed for ASTRA reconstruction." % (o, ))
            raise ValueError()
    for o in default_options['astra']:
        if o not in opts:
            opts[o] = default_options['astra'][o]

    niter = opts['num_iter']
    proj_type = opts['proj_type']

    # Create ASTRA geometries
    vol_geom = astra_mod.create_vol_geom((num_gridx, num_gridy))

    # Number of GPUs to use
    if proj_type == 'cuda':
        if opts['gpu_list'] is not None:
            import concurrent.futures as cf
            gpu_list = opts['gpu_list']
            ngpu = len(gpu_list)
            _, slcs = mproc.get_ncore_slices(nslices, ngpu)
            # execute recon on a thread per GPU
            with cf.ThreadPoolExecutor(ngpu) as e:
                for gpu, slc in zip(gpu_list, slcs):
                    e.submit(astra_rec_cuda, tomo[slc], center[slc],
                             recon[slc], theta, vol_geom, niter, proj_type,
                             gpu, opts)
        else:
            astra_rec_cuda(tomo, center, recon, theta, vol_geom, niter,
                           proj_type, None, opts)
    else:
        astra_rec_cpu(tomo, center, recon, theta, vol_geom, niter, proj_type,
                      opts)