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)
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)
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
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)
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
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)
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)
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)
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]]
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)
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)
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)
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
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
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
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
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
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
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
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
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
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
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)
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
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))
#(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()
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
# 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
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
# 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)
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
#(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()
# 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])
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]]
#-*-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
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
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)
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()
# (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']
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
# 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
# # 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
# # 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)
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
# 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)
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
#(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
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:
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)
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
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
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)
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)