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 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_mr_fbp(im, angles, cor_shift): """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)) # Projection geometry with shifted center of rotation (doesn't work apparently): #proj_geom = astra.geom_postalignment(proj_geom, cor_shift); # 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 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 pid(number_of_angles): """Return projector ID. :param number_of_angles: :return: """ return astra.create_projector('cuda', astra.create_proj_geom('parallel', 1.0, vshape[0], np.linspace(0, np.pi, number_of_angles, False)), vol_geom)
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 FBP_reconstruction(projections, scanner_params, proj_vecs, voxel_size=.1, rec_shape=501, vol_center=0, **kwargs): astra.astra.set_gpu_index(globals().get('GPU_ID', kwargs.get('gpu_id', -1))) # from [proj_slc,rows,cols] to [rows,proj_slc,cols] projections = np.transpose(projections, (1,0,2)) proj_geom = astra.create_proj_geom('cone_vec', *scanner_params.detector_effective_size, proj_vecs) projections_id = astra.data3d.create('-sino', proj_geom, projections) # [z,x,y] to [y,x,z] axis transposition vol_center = tuple([vol_center[i] for i in [2,1,0]]) if isinstance(vol_center, tuple) else (vol_center,) *3 reconstructed_shape = tuple([rec_shape[i] for i in [2,1,0]]) if isinstance(rec_shape, tuple) else (rec_shape,) *3 vol_geom = astra.creators.create_vol_geom(*reconstructed_shape, *[center+sign*size/2*voxel_size for center, size in zip(vol_center, reconstructed_shape) for sign in [-1, 1]] ) reconstruction_id = astra.data3d.create('-vol', vol_geom, data=0) alg_cfg = astra.astra_dict('BP3D_CUDA') alg_cfg['ProjectionDataId'] = projections_id alg_cfg['ReconstructionDataId'] = reconstruction_id algorithm_id = astra.algorithm.create(alg_cfg) astra.algorithm.run(algorithm_id) reconstruction = astra.data3d.get(reconstruction_id) # Free ressources astra.algorithm.delete(algorithm_id) astra.data3d.delete([projections_id, reconstruction_id]) return reconstruction
def run_soft_ineq(data, name, alpha, bound): d_pr, M, m = check_bounds(data['data'], bound, 0) pixel_size = 1.0 proj_geom = astra.create_proj_geom( 'parallel', pixel_size, d_pr.shape[1], data['angles'] ) rec_pix = d_pr.shape[1] vol_geom = astra.create_vol_geom(rec_pix, rec_pix) projector = astra.create_projector('linear', proj_geom, vol_geom) res = ineq_linear_least_squares(1.0, proj_geom, vol_geom, np.exp(-d_pr), projector, np.exp(-bound), alpha) plt.figure() plt.imshow(res, cmap=plt.cm.viridis) plt.colorbar(orientation='horizontal') name_suffix = '%s_a%.1f' % (name, alpha) plt.title("%s, alpha %.1f" % (name, alpha)) plt.savefig('soft_ineq_' + name_suffix + '.png') # plt.show(block=False) np.savetxt(name_suffix, res)
def astra_rec_cuda(tomo, center, recon, theta, vol_geom, niter, proj_type, gpu_index, opts): # Lazy import ASTRA import astra as astra_mod nslices, nang, ndet = tomo.shape cfg = astra_mod.astra_dict(opts['method']) if 'extra_options' in opts: # NOTE: we are modifying 'extra_options' and so need to make a copy cfg['option'] = copy.deepcopy(opts['extra_options']) else: cfg['option'] = {} if gpu_index is not None: cfg['option']['GPUindex'] = gpu_index oc = None const_theta = np.ones(nang) proj_geom = astra_mod.create_proj_geom( 'parallel', 1.0, ndet, theta.astype(np.float64)) for i in range(nslices): if center[i] != oc: oc = center[i] proj_geom['option'] = { 'ExtraDetectorOffset': (center[i] - ndet / 2.) * const_theta} pid = astra_mod.create_projector(proj_type, proj_geom, vol_geom) cfg['ProjectorId'] = pid sid = astra_mod.data2d.link('-sino', proj_geom, tomo[i]) cfg['ProjectionDataId'] = sid 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, niter) astra_mod.algorithm.delete(alg_id) astra_mod.data2d.delete(vid) astra_mod.data2d.delete(sid) astra_mod.projector.delete(pid)
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 run_fbp(data, bound): d_pr, M, m = check_bounds(data['data'], bound, 0) pixel_size = 1.0 proj_geom = astra.create_proj_geom( 'parallel', pixel_size, d_pr.shape[1], data['angles'] ) rec_pix = d_pr.shape[1] vol_geom = astra.create_vol_geom(rec_pix, rec_pix) projector = astra.create_projector('linear', proj_geom, vol_geom) res = fbp(1.0, proj_geom, vol_geom, np.exp(-d_pr), projector, np.exp(-bound)) plt.figure() plt.imshow(res, cmap=plt.cm.viridis) plt.colorbar(orientation='vertical') name_suffix = 'FBP' plt.title("FBP") plt.savefig(name_suffix + '.png') np.savetxt(name_suffix, res) return res
def __init__(self, angles, img_size, det_count, sdist, ddist, det_spacing): self.angles = angles self.vol_geom = astra.create_vol_geom(img_size, img_size) self.proj_geom = astra.create_proj_geom('fanflat', det_spacing, det_count, self.angles, sdist, ddist) self.proj_id = astra.create_projector('cuda', self.proj_geom, self.vol_geom) self.data2d = []
def __init__(self, angles, img_size, det_count): self.angles = angles self.vol_geom = astra.create_vol_geom(img_size, img_size) self.proj_geom = astra.create_proj_geom('parallel', 1.0, det_count, self.angles) self.proj_id = astra.create_projector('cuda', self.proj_geom, self.vol_geom) self.data2d = []
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 gen_random_geometry_parallel(): if not NONUNITDET: w = 1.0 else: w = 0.8 + 0.4 * np.random.random() pg = astra.create_proj_geom('parallel', w, np.random.randint(*range2d), np.linspace(0, 2*np.pi, np.random.randint(*range2d), endpoint=False)) return pg
def fbp(sinogram, geo): vol_geom = astra.create_vol_geom(geo["nVoxelY"], geo["nVoxelX"], -1 * geo["sVoxelY"] / 2, geo["sVoxelY"] / 2, -1 * geo["sVoxelX"] / 2, geo["sVoxelX"] / 2) proj_geom = astra.create_proj_geom( geo["mode"], geo["dDetecU"], geo["nDetecU"], np.linspace(geo["start_angle"], geo["end_angle"], geo["sino_views"], False), geo["DSO"], geo["DOD"]) if geo["mode"] is "parallel": proj_id = astra.create_projector("linear", proj_geom, vol_geom) elif geo["mode"] is "fanflat": proj_id = astra.create_projector("line_fanflat", proj_geom_full, vol_geom) rec_id = astra.data2d.create('-vol', vol_geom) sinogram_id = astra.data2d.create('-sino', proj_geom, sinogram) cfg = astra.astra_dict('FBP') cfg['ProjectorId'] = proj_id cfg["FilterType"] = "Ram-Lak" cfg['ReconstructionDataId'] = rec_id cfg['ProjectionDataId'] = sinogram_id alg_id = astra.algorithm.create(cfg) astra.algorithm.run(alg_id) image_recon = astra.data2d.get(rec_id) astra.algorithm.delete(alg_id) astra.data2d.delete(rec_id) astra.data2d.delete(sinogram_id) return image_recon
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 gen_random_geometry_fanflat(): if not NONUNITDET: w = 1.0 else: w = 0.6 + 0.8 * np.random.random() pg = astra.create_proj_geom('fanflat', w, np.random.randint(*range2d), np.linspace(0, 2*np.pi, np.random.randint(*range2d), endpoint=False), 256 * (0.5 + np.random.random()), 256 * np.random.random()) return pg
def _initialize_astra(self, sz=None, pixel_size=None, det2obj=None, src2obj=None, theta=None): if sz is None: sz = self._parent.data.shape() if pixel_size is None: pixel_size = self._parent.meta.geometry['det_pixel'] if det2obj is None: det2obj = self._parent.meta.geometry['det2obj'] if src2obj is None: src2obj = self._parent.meta.geometry['src2obj'] if theta is None: theta = self._parent.meta.theta # Initialize ASTRA (3D): det_count_x = sz[2] det_count_z = sz[0] # Make volume count x > detector count to include corneres of the object: vol_count_x = sz[2] vol_count_z = sz[0] tot_dist = det2obj + src2obj magnification = tot_dist / src2obj self.vol_geom = astra.create_vol_geom(vol_count_x, vol_count_x, vol_count_z) self.proj_geom = astra.create_proj_geom( 'cone', magnification, magnification, det_count_z, det_count_x, theta, (src2obj * magnification) / pixel_size, (det2obj * magnification) / pixel_size)
def single_sino(sino: np.ndarray, cor: ScalarCoR, proj_angles: ProjectionAngles, recon_params: ReconstructionParameters, progress: Optional[Progress] = None) -> np.ndarray: assert sino.ndim == 2, "Sinogram must be a 2D image" sino = BaseRecon.prepare_sinogram(sino, recon_params) image_width = sino.shape[1] if astra_mutex.locked(): LOG.warning("Astra recon already in progress. Waiting") with astra_mutex: vectors = vec_geom_init2d(proj_angles, 1.0, cor.to_vec(image_width).value) vol_geom = astra.create_vol_geom((image_width, image_width)) proj_geom = astra.create_proj_geom('parallel_vec', image_width, vectors) cfg = astra.astra_dict(recon_params.algorithm) cfg['FilterType'] = recon_params.filter_name with _managed_recon(sino, cfg, proj_geom, vol_geom) as (alg_id, rec_id): astra.algorithm.run(alg_id, iterations=recon_params.num_iter) return astra.data2d.get(rec_id)
def astra_rec_cuda(tomo, center, recon, theta, vol_geom, niter, proj_type, gpu_index, opts): # Lazy import ASTRA import astra as astra_mod nslices, nang, ndet = tomo.shape cfg = astra_mod.astra_dict(opts['method']) if 'extra_options' in opts: #NOTE: we are modifying 'extra_options' and so need to make a copy cfg['option'] = copy.deepcopy(opts['extra_options']) else: cfg['option'] = {} if gpu_index is not None: cfg['option']['GPUindex'] = gpu_index oc = None const_theta = np.ones(nang) proj_geom = astra_mod.create_proj_geom('parallel', 1.0, ndet, theta.astype(np.float64)) for i in range(nslices): if center[i] != oc: oc = center[i] proj_geom['option'] = { 'ExtraDetectorOffset': (center[i] - ndet / 2.) * const_theta } pid = astra_mod.create_projector(proj_type, proj_geom, vol_geom) cfg['ProjectorId'] = pid sid = astra_mod.data2d.link('-sino', proj_geom, tomo[i]) cfg['ProjectionDataId'] = sid 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, niter) astra_mod.algorithm.delete(alg_id) astra_mod.data2d.delete(vid) astra_mod.data2d.delete(sid) astra_mod.projector.delete(pid)
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 astra_rec_cpu(tomo, center, recon, theta, vol_geom, niter, proj_type, opts): # Lazy import ASTRA import astra as astra_mod nslices, nang, ndet = tomo.shape cfg = astra_mod.astra_dict(opts['method']) if 'extra_options' in opts: cfg['option'] = opts['extra_options'] proj_geom = astra_mod.create_proj_geom('parallel', 1.0, ndet, theta.astype(np.float64)) pid = astra_mod.create_projector(proj_type, proj_geom, vol_geom) sino = np.zeros((nang, ndet), dtype=np.float32) sid = astra_mod.data2d.link('-sino', proj_geom, sino) cfg['ProjectorId'] = pid cfg['ProjectionDataId'] = sid for i in range(nslices): shft = int(np.round(ndet / 2. - center[i])) if not shft == 0: sino[:] = np.roll(tomo[i], shft) l = shft r = ndet + shft if l < 0: l = 0 if r > ndet: r = ndet sino[:, :l] = 0 sino[:, r:] = 0 else: sino[:] = tomo[i] 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, niter) astra_mod.algorithm.delete(alg_id) astra_mod.data2d.delete(vid) astra_mod.data2d.delete(sid) astra_mod.projector.delete(pid)
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 main(): parser = argparse.ArgumentParser() parser.add_argument('--width', type=int, required=True) parser.add_argument('--num-projections', type=int, required=True) parser.add_argument('--num-slices', type=int, required=True) args = parser.parse_args() angles = np.linspace(0, np.pi, args.num_projections, False, dtype=np.float64) vol_geom = astra.create_vol_geom(args.width, args.width, args.num_slices) proj_geom = astra.create_proj_geom('parallel3d', 1.0, 1.0, args.num_slices, args.width, angles) vid = astra.data3d.create('-vol', vol_geom) pid = astra.data3d.create('-proj3d', proj_geom, 0.0) config = astra.astra_dict('BP3D_CUDA') config['ProjectionDataId'] = pid config['ReconstructionDataId'] = vid aid = astra.algorithm.create(config) astra.algorithm.run(aid)
def create_example_parallel3d(example_type=''): """ :brief: create an example of a parallel3d geometry :param example_type: for the examples, there are different options - '' or 'normal': example of a standard parallel geometry with 100 angles - 'vec': same geometry as for normal, but converted to a vector geometry this gives a different plot visualizing the individual angles on top of the geometry :return: the example geometry """ det_spacing = [0.035, 0.035] detector_px = [1000, 1000] angles = np.linspace(0, 2 * np.pi, 100) if example_type == '' or example_type == 'normal': proj_geom = astra.create_proj_geom('parallel3d', det_spacing[0], det_spacing[1], detector_px[0], detector_px[1], angles) elif example_type == 'vec': proj_geom = astra.geom_2vec(create_example_parallel3d()) else: raise ValueError( "ASTRA: example type {0} not recognized for parallel3d geometry". format(example_type)) return proj_geom
def __init__(self, DetColumnCount, DetRowCount, AnglesVec, CenterRotOffset, ObjSize, OS): self.ObjSize = ObjSize self.DetectorsDimV = DetRowCount if type(ObjSize) == tuple: Y, X, Z = [int(i) for i in ObjSize] else: Y = X = ObjSize Z = DetRowCount self.vol_geom = astra.create_vol_geom(Y, X, Z) ################ 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_init3D(AnglesVec, 1.0, 1.0, CenterRotOffset) self.proj_geom = astra.create_proj_geom('parallel3d_vec', DetRowCount, DetColumnCount, vectors) # create OS-specific ASTRA geometry self.proj_geom_OS = {} for sub_ind in range(OS): self.indVec = self.newInd_Vec[sub_ind, :] if (self.indVec[self.NumbProjBins - 1] == 0): self.indVec = self.indVec[:-1] #shrink vector size anglesOS = AnglesVec[self.indVec] # OS-specific angles if np.ndim(CenterRotOffset) == 0: # CenterRotOffset is a _scalar_ vectors = vec_geom_init3D(anglesOS, 1.0, 1.0, CenterRotOffset) else: # CenterRotOffset is a _vector_ vectors = vec_geom_init3D(anglesOS, 1.0, 1.0, CenterRotOffset[self.indVec]) self.proj_geom_OS[sub_ind] = astra.create_proj_geom( 'parallel3d_vec', DetRowCount, DetColumnCount, vectors)
def FDK_reconstruction(projections, scanner_params, proj_vecs, voxel_size=.1, rec_shape=501, **kwargs): """Uses FDK method to reconstruct CT volume from CB projections Args: ----- projections (np.ndarray): [proj_slc, rows, cols] CBCT projections scanner_params (class): class containing scanner data proj_vecs (np.ndarray): vects describing the scanning used for reconstruction voxel_size (float): size of the voxels in the reconstructed volume rec_shape (int/tuple): shape of the reconstructed volume tuple with 3 dims [z,x,y] or int if isotropic --optional-- gpu_id (int): GPU for astra to use if not set globaly, defaults to -1 Returns: -------- reconstruction (np.ndarray): [z,x,y] recontructed CT volume """ astra.astra.set_gpu_index(globals().get('GPU_ID', kwargs.get('gpu_id', -1))) # from [proj_slc,rows,cols] to [rows,proj_slc,cols] projections = np.transpose(projections, (1, 0, 2)) proj_geom = astra.create_proj_geom('cone_vec', *scanner_params.detector_binned_size, proj_vecs) projections_id = astra.data3d.create('-sino', proj_geom, projections) # [z,x,y] to [y,x,z] axis transposition reconstructed_shape = tuple([rec_shape[i] for i in [2, 1, 0]]) if isinstance( rec_shape, tuple) else (rec_shape, ) * 3 vol_geom = astra.creators.create_vol_geom( *reconstructed_shape, *[ sign * size / 2 * voxel_size for size in reconstructed_shape for sign in [-1, 1] ]) reconstruction_id = astra.data3d.create('-vol', vol_geom, data=0) alg_cfg = astra.astra_dict('FDK_CUDA') alg_cfg['ProjectionDataId'] = projections_id alg_cfg['ReconstructionDataId'] = reconstruction_id alg_cfg['option'] = {'ShortScan': False} algorithm_id = astra.algorithm.create(alg_cfg) astra.algorithm.run(algorithm_id) reconstruction = astra.data3d.get(reconstruction_id) # Free ressources astra.algorithm.delete(algorithm_id) astra.data3d.delete([projections_id, reconstruction_id]) return reconstruction
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 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, angles, img_size): self.angles = angles self.vol_geom = astra.create_vol_geom(img_size, img_size) self.proj_geom = astra.create_proj_geom('fanflat', 1.0, img_size, self.angles, img_size, img_size) self.proj_id = astra.create_projector('cuda', self.proj_geom, self.vol_geom)
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 DT(W,p, vol_size, proj_size, angles, Ngv, lamb=10, PU = 'cuda', K = 4, Niter = 50, epsilon=1e-4): [Nx,Nz] = vol_size [Ndetx, Ndety] = proj_size Nan = len(angles) if Ndety==1: sinogram = p.reshape([Nan, Ndetx]) else: sinogram = p.reshape([Nan, Ndetx, Ndety]) # create projection geometry and operator print('TVR-DART ...') print('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(PU,proj_geom,vol_geom) W = astra.OpTomo(proj_id) # initial reconstruction print('Initial reconstruction...') recsirt = SIRT.recon(sinogram, 200, proj_geom, vol_geom, PU) sf = np.max(recsirt) p = p/sf if Ndety==1: sinogram = p.reshape([Nan, Ndetx]) else: sinogram = p.reshape([Nan, Ndetx, Ndety]) recsirt = recsirt/sf # set initial TVR-DART parameters K = K*np.ones(Ngv-1) gv = np.linspace(0, 1, Ngv,True) param0 = gv2param(gv,K) # Esimating parameter using a small section of the dataset print('Estimation of optimal parameters...') if Ndety==1: Segrec,param_esti = joint(W,p, recsirt, param0 ,lamb) else: Elist = np.sum(recsirt,axis=(0,2)) index = np.argmax(Elist) index1 = np.max(np.hstack((0,index-1))) index2 = np.min(np.hstack((index+1,Ndety-1))) x0_esti = recsirt[:,index1:index2+1,:] sinogram_esti = sinogram[:,:,index1:index2+1] p_esti = sinogram_esti.reshape(Nan*Ndetx*(index2-index1+1)) Segrec,param_esti = joint(W,p_esti, x0_esti, param0 ,lamb) # Reconstruction with estimated parameter print('Reconstruction with estimated parameters...') Segrec,rec = recon(W,p, recsirt, param_esti, lamb, Niter, epsilon) [gv,K] = param2gv(param_esti) param_esti = gv2param(gv*sf,K) Segrec = Segrec*sf; return Segrec, param_esti;
def astra_project(obj, angles, cuda=False): """ Calculate projection of a 3D object using Astra-toolbox. Args ---------- obj : NumPy array Either a 2D or 3D array containing the object to project. If 2D, the structure is of the form [z, x] where z is the projection axis. If 3D, the strucutre is [y, z, x] where y is the tilt axis. angles : list or NumPy array The projection angles in degrees cuda : boolean If True, perform reconstruction using the GPU-accelerated algorithm. Returns ---------- sino : Numpy array 3D array of the form [y, angle, x] containing the projection of the input object """ if len(obj.shape) == 2: obj = np.expand_dims(obj, 0) thetas = np.pi * angles / 180. y_pix, thickness, x_pix = obj.shape if cuda: vol_geom = astra.create_vol_geom(thickness, x_pix, y_pix) proj_geom = astra.create_proj_geom('parallel3d', 1.0, 1.0, y_pix, x_pix, thetas) sino_id, sino = astra.create_sino3d_gpu(obj, proj_geom, vol_geom) astra.data3d.delete(sino_id) else: sino = np.zeros([y_pix, len(angles), x_pix], np.float32) vol_geom = astra.create_vol_geom(thickness, x_pix) proj_geom = astra.create_proj_geom('parallel', 1.0, x_pix, thetas) proj_id = astra.create_projector('strip', proj_geom, vol_geom) for i in range(0, y_pix): sino_id, sino[i, :, :] = astra.create_sino(obj[i, :, :], proj_id, vol_geom) astra.data2d.delete(sino_id) sino = np.rollaxis(sino, 1) return sino
def __init__(self, vol_shape, angles, beam_shape="parallel"): if len(vol_shape) > 2: raise ValueError("Only 2D volumes") self.proj_id = [] self.dispose_projector() self.vol_geom = astra.create_vol_geom(vol_shape) self.proj_geom = astra.create_proj_geom(beam_shape, 1, np.max(vol_shape), angles)
def forward_single(self, x): vol_geom = astra.create_vol_geom(x.shape[0], x.shape[1]) proj_geom = astra.create_proj_geom('parallel', 1.0, x.shape[0], self.angles) proj_id = astra.create_projector('cuda', proj_geom, vol_geom) self.projectors.append(proj_id) return astra.create_sino(x, proj_id)
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 __init__(self, DetRows, DetColumns, AnglesVec, ObjSize): self.ObjSize = ObjSize self.proj_geom = astra.create_proj_geom('parallel3d', 1.0, 1.0, DetRows, DetColumns, AnglesVec) if type(ObjSize) == tuple: N1, N2, N3 = [int(i) for i in ObjSize] else: N1 = N2 = N3 = ObjSize self.vol_geom = astra.create_vol_geom(N3, N2, N1)
def check_recon(folder, alg, iterations, bin_num): raw_data = np.load(os.path.join(directory, folder, 'Data', 'data_corr.npy'))[:, :, :, 6] raw_data = np.transpose(raw_data, axes=(1, 0, 2)) # Transpose to (rows, angles, columns) # Change if isocentre is not directly in the center of the detector # raw_data = np.roll(raw_data, -2, axis=2) # Create a 3D projection geometry with our cone-beam data # Parameters: 'acquisition type', number of detector rows, number of detector columns, data ndarray proj_geom = astra.create_proj_geom('cone', pixel_pitch, pixel_pitch, det_row_count, det_col_count, angles, source_origin, origin_det) proj_id = astra.data3d.create('-proj3d', proj_geom, raw_data) # Create a 3D volume geometry. # Parameter order: rows, columns, slices (y, x, z) vol_geom = astra.create_vol_geom(det_col_count, det_col_count, det_row_count) # Create a data object for the reconstruction if alg == 'FDK_CUDA': recon_id = astra.data3d.create('-vol', vol_geom) else: ct_data = np.load(os.path.join(directory, folder, 'CT', 'FDK_CT.npy')) recon_id = astra.data3d.create('-vol', vol_geom, data=ct_data) # Set up the parameters for a reconstruction algorithm using the GPU cfg = astra.astra_dict(alg) cfg['ReconstructionDataId'] = recon_id cfg['ProjectionDataId'] = proj_id # Create the algorithm object from the configuration structure alg_id = astra.algorithm.create(cfg) # Run the specified number of iterations of the algorithm rec_data = np.zeros((iterations // 5, 576, 576)) for i in range(0, iterations, 5): astra.algorithm.run(alg_id, 5) # Get the result rec = astra.data3d.get(recon_id)[11] print(alg[0:4] + f': {i + 5} Iterations') rec_data[i // 5] = rec np.save( os.path.join(directory, folder, 'CT', alg[0:4] + '_iteration_check.npy'), rec_data) # 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(recon_id) astra.data3d.delete(proj_id)
def test_fanbeam_error(device, batch_size, image_size, angles, spacing, distances, det_count, clip_to_circle): # generate random images # generate random images det_count = int(det_count * image_size) mask_radius = det_count / 2.0 if clip_to_circle else -1 x = generate_random_images(1, image_size, mask_radius)[0] s_dist, d_dist = distances s_dist *= image_size d_dist *= image_size # astra vol_geom = astra.create_vol_geom(x.shape[0], x.shape[1]) proj_geom = astra.create_proj_geom('fanflat', spacing, det_count, angles, s_dist, d_dist) proj_id = astra.create_projector('cuda', proj_geom, vol_geom) id, astra_y = astra.create_sino(x, proj_id) _, astra_bp = astra.create_backprojection(astra_y, proj_id) if clip_to_circle: astra_bp *= circle_mask(image_size, mask_radius) # TODO clean astra structures # our implementation radon = RadonFanbeam(image_size, angles, s_dist, d_dist, det_count=det_count, det_spacing=spacing, clip_to_circle=clip_to_circle) x = torch.FloatTensor(x).to(device).view(1, x.shape[0], x.shape[1]) # repeat data to fill batch size x = torch.cat([x] * batch_size, dim=0) our_fp = radon.forward(x) our_bp = radon.backprojection(our_fp) forward_error = relative_error(astra_y, our_fp[0].cpu().numpy()) back_error = relative_error(astra_bp, our_bp[0].cpu().numpy()) # if back_error > 5e-3: # plt.imshow(astra_bp) # plt.figure() # plt.imshow(our_bp[0].cpu().numpy()) # plt.show() print(np.max(our_fp.cpu().numpy()), np.max(our_bp.cpu().numpy())) print( f"batch: {batch_size}, size: {image_size}, angles: {len(angles)}, spacing: {spacing}, distances: {distances} circle: {clip_to_circle}, forward: {forward_error}, back: {back_error}" ) # TODO better checks assert_less(forward_error, 1e-2) assert_less(back_error, 5e-3)
def pid(number_of_angles): """Return projector ID. :param number_of_angles: :return: """ return astra.create_projector( 'cuda', astra.create_proj_geom('parallel', 1.0, vshape[0], np.linspace(0, np.pi, number_of_angles, False)), vol_geom)
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 __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 _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 gen_random_geometry_fanflat_vec(): Vectors = np.zeros([16,6]) # We assume constant detector width in these tests if not NONUNITDET: w = 1.0 else: w = 0.6 + 0.8 * np.random.random() for i in range(Vectors.shape[0]): angle1 = 2*np.pi*np.random.random() if OBLIQUE: angle2 = angle1 + 0.5 * np.random.random() else: angle2 = angle1 dist1 = 256 * (0.5 + np.random.random()) detc = 10 * np.random.random(size=2) detu = [ math.cos(angle1) * w, math.sin(angle1) * w ] src = [ math.sin(angle2) * dist1, -math.cos(angle2) * dist1 ] Vectors[i, :] = [ src[0], src[1], detc[0], detc[1], detu[0], detu[1] ] pg = astra.create_proj_geom('fanflat_vec', np.random.randint(*range2d), Vectors) return pg
def gen_random_geometry_parallel_vec(): Vectors = np.zeros([16,6]) # We assume constant detector width in these tests if not NONUNITDET: w = 1.0 else: w = 0.6 + 0.8 * np.random.random() for i in range(Vectors.shape[0]): l = 0.6 + 0.8 * np.random.random() angle1 = 2*np.pi*np.random.random() if OBLIQUE: angle2 = angle1 + 0.5 * np.random.random() else: angle2 = angle1 detc = 10 * np.random.random(size=2) detu = [ math.cos(angle1) * w, math.sin(angle1) * w ] ray = [ math.sin(angle2) * l, -math.cos(angle2) * l ] Vectors[i, :] = [ ray[0], ray[1], detc[0], detc[1], detu[0], detu[1] ] pg = astra.create_proj_geom('parallel_vec', np.random.randint(*range2d), Vectors) return pg
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 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)
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)