def __init__(self, proj, geo, angles, niter, **kwargs): # Don't precompute V and W. kwargs.update(dict(W=None, V=None)) kwargs.update(dict(blocksize=angles.shape[0])) self.log_parameters = False self.re_init_at_iteration = 0 IterativeReconAlg.__init__(self, proj, geo, angles, niter, **kwargs) if self.log_parameters: parameter_history = {} iterations = self.niter parameter_history['alpha'] = np.zeros([iterations], dtype=np.float32) parameter_history['beta'] = np.zeros([iterations], dtype=np.float32) parameter_history['gamma'] = np.zeros([iterations], dtype=np.float32) parameter_history['q_norm'] = np.zeros([iterations], dtype=np.float32) parameter_history['s_norm'] = np.zeros([iterations], dtype=np.float32) self.parameter_history = parameter_history self.__r__ = self.proj - \ Ax(self.res, self.geo, self.angles, 'Siddon', gpuids = self.gpuids) self.__p__ = Atb(self.__r__, self.geo, self.angles, gpuids=self.gpuids) p_norm = np.linalg.norm(self.__p__.ravel(), 2) self.__gamma__ = p_norm * p_norm
def reinitialise_cgls(self): self.__r__ = self.proj - Ax( self.res, self.geo, self.angles, "Siddon", gpuids=self.gpuids) self.__p__ = Atb(self.__r__, self.geo, self.angles, backprojection_type="matched", gpuids=self.gpuids) p_norm = np.linalg.norm(self.__p__.ravel(), 2) self.__gamma__ = p_norm * p_norm
def run_main_iter(self): self.res[self.res < 0.0] = 0.0 for i in range(self.niter): self._estimate_time_until_completion(i) den = Ax(self.res, self.geo, self.angles, "interpolated", gpuids=self.gpuids) # toc = time.process_time() # print('Ax time: {}'.format(toc-tic)) den[den == 0.0] = np.inf auxmlem = self.proj / den # auxmlem[auxmlem == np.nan] = 0. # auxmlem[auxmlem == np.inf] = 0. # update # tic = time.process_time() img = Atb(auxmlem, self.geo, self.angles, backprojection_type="matched", gpuids=self.gpuids) / self.W # toc = time.process_time() # print('Atb time: {}'.format(toc-tic)) # img[img == np.nan] = 0. # img[img == np.inf] = 0. self.res = self.res * img self.res[self.res < 0.0] = 0.0
def update_image(self, geo, angle, iteration): """ VERBOSE: for j in range(angleblocks): angle = np.array([alpha[j]], dtype=np.float32) proj_err = proj[angle_index[j]] - Ax(res, geo, angle, 'Siddon') weighted_err = W[angle_index[j]] * proj_err backprj = Atb(weighted_err, geo, angle, 'FDK') weighted_backprj = 1 / V[angle_index[j]] * backprj res += weighted_backprj res[res<0]=0 :return: None """ ang_index = self.angle_index[iteration].astype(np.int) self.res += ( self.lmbda * 1.0 / self.V[iteration] * Atb( self.W[ang_index] * (self.proj[ang_index] - Ax(self.res, geo, angle, "Siddon", gpuids=self.gpuids)), geo, angle, "FDK", gpuids=self.gpuids, ) )
def run_main_iter(self): self.res[self.res < 0.0] = 0.0 for i in range(self.niter): if self.Quameasopts is not None: res_prev = copy.deepcopy(self.res) self._estimate_time_until_completion(i) den = Ax(self.res, self.geo, self.angles, "interpolated", gpuids=self.gpuids) den[den == 0.0] = np.inf auxmlem = self.proj / den # update img = Atb(auxmlem, self.geo, self.angles, backprojection_type="matched", gpuids=self.gpuids) / self.W self.res = self.res * img self.res[self.res < 0.0] = 0.0 if self.Quameasopts is not None: self.error_measurement(res_prev, i)
def run_main_iter(self): self.res[self.res < 0.] = 0. for i in range(self.niter): if i == 0: if self.verbose: print("MLEM Algorithm in progress.") toc = default_timer() if i == 1: tic = default_timer() if self.verbose: print( 'Esitmated time until completetion (s): {:.4f}'.format( (self.niter - 1) * (tic - toc))) # tic = time.process_time() den = Ax(self.res, self.geo, self.angles, 'interpolated') # toc = time.process_time() # print('Ax time: {}'.format(toc-tic)) den[den == 0.] = np.inf auxmlem = self.proj / den # auxmlem[auxmlem == np.nan] = 0. # auxmlem[auxmlem == np.inf] = 0. # update # tic = time.process_time() img = Atb(auxmlem, self.geo, self.angles) / self.W # toc = time.process_time() # print('Atb time: {}'.format(toc-tic)) # img[img == np.nan] = 0. # img[img == np.inf] = 0. self.res = self.res * img self.res[self.res < 0.] = 0.
def set_v(self): """ Computes value of V parameter if this is not given. :return: None """ geo = self.geo V = np.ones((self.angleblocks.shape[0], geo.nVoxel[1], geo.nVoxel[2]), dtype=np.float32) for i in range(self.angleblocks.shape[0]): if geo.mode != 'parallel': geox = copy.deepcopy(self.geo) geox.angles = self.angleblocks[i] # shrink the volume size to avoid zeros in backprojection geox.sVoxel = geox.sVoxel * np.max( geox.sVoxel[1:] / np.linalg.norm(geox.sVoxel[1:])) * 0.9 geox.dVoxel = geox.sVoxel / geox.nVoxel proj_one = np.ones((len( self.angleblocks[i]), geo.nDetector[0], geo.nDetector[1]), dtype=np.float32) V[i] = Atb(proj_one, geox, self.angleblocks[i], 'FDK').mean(axis=0) else: V[i] *= len(self.angleblocks[i]) setattr(self, 'V', V)
def run_main_iter(self): self.l2l = np.zeros([self.niter], dtype=np.float32) for i in range(self.niter): if i == 0: print("CGLS Algorithm in progress.") toc = time.clock() if i == 1: tic = time.clock() print('Esitmated time until completetion (s): ' + str((self.niter - 1) * (tic - toc))) q = Ax(self._p, self.geo, self.angles, 'ray-voxel') q_norm = np.linalg.norm(q.ravel(), 2) alpha = self._gamma / (q_norm * q_norm) self.res += alpha * self._p error = False for item in self.__dict__: if type(getattr(self,item)) == np.ndarray: if np.isnan(getattr(self,item)).any(): print(item, i) error = True if error: break aux = self.proj - Ax(self.res, self.geo, self.angles, 'ray-voxel') self.l2l[i] = np.linalg.norm(aux.ravel(), 2) if i > 0 and self.l2l[i] > self.l2l[i - 1]: print('re-initialization was called at iter:' + str(i)) self.res -= alpha * self._p self.initialise_cgls() self._r -= alpha * q s = Atb(self._r, self.geo, self.angles) s_norm = np.linalg.norm(s.ravel(), 2) gamma1 = s_norm * s_norm beta = gamma1 / self._gamma if self.log_parameters: self.parameter_history['alpha'][i] = alpha self.parameter_history['beta'][i] = beta self.parameter_history['gamma'][i] = self._gamma self.parameter_history['q_norm'][i] = q_norm self.parameter_history['s_norm'][i] = s_norm self._gamma = gamma1 self._p = s + beta * self._p
def test_backproj_parallel_spherical_shape(self): setattr(self.geo, 'mode', 'parallel') angles_1 = self.angles angles_2 = np.ones( (len(angles_1)), dtype=np.float32) * np.array([np.pi / 4], dtype=np.float32) angles_3 = np.zeros((len(angles_1)), dtype=np.float32) new_angles = np.vstack((angles_1, angles_2, angles_3)).T self.assertTupleEqual( Atb(self.proj, self.geo, new_angles).shape, (63, 62, 61))
def fbp(proj,geo,angles,filter=None,verbose=False): if geo.mode != 'parallel': raise ValueError("Only use FBP for parallel beam. Check geo.mode.") geox = copy.deepcopy(geo) geox.check_geo(angles) proj_filt = filtering(proj,geox,angles,parker=False,verbose=verbose) res = Atb(proj_filt,geo,angles)*geo.DSO/geo.DSD return res
def __init__(self, proj, geo, angles, niter, **kwargs): # Don't precompute V and W. kwargs.update(dict(W=None, V=None)) kwargs.update(dict(blocksize=angles.shape[0])) IterativeReconAlg.__init__(self, proj, geo, angles, niter, **kwargs) if self.init is None: self.res += 1. self.W = Atb(np.ones(proj.shape, dtype=np.float32), geo, angles) self.W[self.W <= 0.] = np.inf
def run_main_iter(self): self.l2l = np.zeros([self.niter], dtype=np.float32) for i in range(self.niter): if i == 0: print("CGLS Algorithm in progress.") toc = time.clock() if i == 1: tic = time.clock() print('Esitmated time until completetion (s): ' + str((self.niter - 1) * (tic - toc))) q = Ax(self.__p__, self.geo, self.angles, 'ray-voxel') q_norm = np.linalg.norm(q.ravel(), 2) alpha = self.__gamma__ / (q_norm * q_norm) self.res += alpha * self.__p__ for item in self.__dict__: if type(getattr(self, item)) == np.ndarray: if np.isnan(getattr(self, item)).any(): raise ValueError('nan found for ' + item + ' at iteraton ' + str(i)) aux = self.proj - Ax(self.res, self.geo, self.angles, 'ray-voxel') self.l2l[i] = np.linalg.norm(aux.ravel(), 2) if i > 0 and self.l2l[i] > self.l2l[i - 1]: print('re-initialization was called at iter:' + str(i)) self.res -= alpha * self.__p__ self.reinitialise_cgls() self.__r__ -= alpha * q s = Atb(self.__r__, self.geo, self.angles) s_norm = np.linalg.norm(s.ravel(), 2) gamma1 = s_norm * s_norm beta = gamma1 / self.__gamma__ if self.log_parameters: self.parameter_history['alpha'][i] = alpha self.parameter_history['beta'][i] = beta self.parameter_history['gamma'][i] = self.__gamma__ self.parameter_history['q_norm'][i] = q_norm self.parameter_history['s_norm'][i] = s_norm self.__gamma__ = gamma1 self.__p__ = s + beta * self.__p__
def fbp(proj, geo, angles, **kwargs): # noqa: D103 __doc__ = FDK.__doc__ # noqa: F841 if geo.mode != "parallel": raise ValueError("Only use FBP for parallel beam. Check geo.mode.") geox = copy.deepcopy(geo) geox.check_geo(angles) verbose = kwargs["verbose"] if "verbose" in kwargs else False gpuids = kwargs["gpuids"] if "gpuids" in kwargs else None proj_filt = filtering(copy.deepcopy(proj), geox, angles, parker=False, verbose=verbose) return Atb(proj_filt, geo, angles, gpuids=gpuids) * geo.DSO / geo.DSD
def update_image(self, geo, angle, iteration): """ VERBOSE: for j in range(angleblocks): angle = np.array([alpha[j]], dtype=np.float32) proj_err = proj[angle_index[j]] - Ax(res, geo, angle, 'ray-voxel') weighted_err = W[angle_index[j]] * proj_err backprj = Atb(weighted_err, geo, angle, 'FDK') weighted_backprj = 1 / V[angle_index[j]] * backprj res += weighted_backprj res[res<0]=0 :return: None """ self.res += self.lmbda * 1. / self.V[iteration] * Atb(self.W[self.angle_index[iteration]] * ( self.proj[self.angle_index[iteration]] - Ax(self.res, geo, angle, 'interpolated')), geo, angle, 'FDK')
def fbp(proj, geo, angles, **kwargs): __doc__ = FDK.__doc__ if geo.mode != 'parallel': raise ValueError("Only use FBP for parallel beam. Check geo.mode.") geox = copy.deepcopy(geo) geox.check_geo(angles) if 'verbose' in kwargs: verbose = kwargs['verbose'] else: verbose = False proj_filt = filtering(copy.deepcopy(proj), geox, angles, parker=False, verbose=verbose) res = Atb(proj_filt, geo, angles) * geo.DSO / geo.DSD return res
def set_v(self): """ Computes value of V parameter if this is not given. :return: None """ block_count = len(self.angleblocks) geo = self.geo V = np.ones((block_count, geo.nVoxel[1], geo.nVoxel[2]), dtype=np.float32) for i in range(block_count): if geo.mode != "parallel": geox = copy.deepcopy(self.geo) geox.angles = self.angleblocks[i] geox.DSD = geo.DSD[self.angle_index[i]] geox.DSO = geo.DSO[self.angle_index[i]] geox.offOrigin = geo.offOrigin[self.angle_index[i], :] geox.offDetector = geo.offDetector[self.angle_index[i], :] geox.rotDetector = geo.rotDetector[self.angle_index[i], :] geox.COR = geo.COR[self.angle_index[i]] # shrink the volume size to avoid zeros in backprojection geox.sVoxel = (geox.sVoxel * np.max( geox.sVoxel[1:] / np.linalg.norm(geox.sVoxel[1:])) * 0.9) geox.dVoxel = geox.sVoxel / geox.nVoxel proj_one = np.ones((len( self.angleblocks[i]), geo.nDetector[0], geo.nDetector[1]), dtype=np.float32) V[i] = Atb(proj_one, geox, self.angleblocks[i], "FDK", gpuids=self.gpuids).mean(axis=0) else: V[i] *= len(self.angleblocks[i]) V[V == 0.0] = np.inf self.V = V
def __init__(self, proj, geo, angles, niter, **kwargs): # Don't precompute V and W. kwargs.update(dict(W=None, V=None)) kwargs.update(dict(blocksize=angles.shape[0])) self.log_parameters = False IterativeReconAlg.__init__(self, proj, geo, angles, niter, **kwargs) if self.log_parameters: parameter_history = {} iterations = self.niter parameter_history['alpha'] = np.zeros([iterations], dtype=np.float32) parameter_history['beta'] = np.zeros([iterations], dtype=np.float32) parameter_history['gamma'] = np.zeros([iterations], dtype=np.float32) parameter_history['q_norm'] = np.zeros([iterations], dtype=np.float32) parameter_history['s_norm'] = np.zeros([iterations], dtype=np.float32) self.parameter_history = parameter_history self.__r__ = self.proj - Ax(self.res, self.geo, self.angles, 'ray-voxel') self.__p__ = Atb(self.__r__, self.geo, self.angles) p_norm = np.linalg.norm(self.__p__.ravel(), 2) self.__gamma__ = p_norm * p_norm
def art_data_minimizing(self): """ VERBOSE: for j in range(angleblocks): angle = np.array([alpha[j]], dtype=np.float32) proj_err = proj[angle_index[j]] - Ax(res, geo, angle, 'ray-voxel') weighted_err = W[angle_index[j]] * proj_err backprj = Atb(weighted_err, geo, angle, 'FDK') weighted_backprj = 1 / V[angle_index[j]] * backprj res += weighted_backprj res[res<0]=0 :return: None """ geo = copy.deepcopy(self.geo) for j in range(len(self.angleblocks)): if self.blocksize == 1: angle = np.array([self.angleblocks[j]], dtype=np.float32) else: angle = self.angleblocks[j] if geo.offOrigin.shape[0] == self.angles.shape[0]: geo.offOrigin = self.geo.offOrigin[j] if geo.offDetector.shape[0] == self.angles.shape[0]: geo.offOrin = self.geo.offDetector[j] if geo.rotDetector.shape[0] == self.angles.shape[0]: geo.rotDetector = self.geo.rotDetector[j] if hasattr(geo.DSD, 'shape'): if geo.DSD.shape[0] == self.angles.shape[0]: geo.DSD = self.geo.DSD[j] if hasattr(geo.DSO, 'shape'): if geo.DSO.shape[0] == self.angles.shape[0]: geo.DSO = self.geo.DSO[j] self.res += self.lmbda * 1 / self.third_dim_sum( self.V[:, :, self.angle_index[j]]) * Atb( self.W[self.angle_index[j]] * (self.proj[self.angle_index[j]] - Ax(self.res, geo, angle, 'interpolated')), geo, angle, 'FDK') if self.noneg: self.res = self.res.clip(min=0)
def reinitialise_cgls(self): self.__r__ = self.proj - \ Ax(self.res, self.geo, self.angles, 'Siddon', gpuids = self.gpuids) self.__p__ = Atb(self.__r__, self.geo, self.angles, gpuids=self.gpuids) p_norm = np.linalg.norm(self.__p__.ravel(), 2) self.__gamma__ = p_norm * p_norm
class CGLS(IterativeReconAlg): __doc__ = ( " CGLS_CBCT solves the CBCT problem using the conjugate gradient least\n" " squares\n" " \n" " CGLS_CBCT(PROJ,GEO,ANGLES,NITER) solves the reconstruction problem\n" " using the projection data PROJ taken over ALPHA angles, corresponding\n" " to the geometry descrived in GEO, using NITER iterations." ) + IterativeReconAlg.__doc__ def __init__(self, proj, geo, angles, niter, **kwargs): # Don't precompute V and W. kwargs.update(dict(W=None, V=None)) kwargs.update(dict(blocksize=angles.shape[0])) self.log_parameters = False self.re_init_at_iteration = 0 IterativeReconAlg.__init__(self, proj, geo, angles, niter, **kwargs) if self.log_parameters: parameter_history = {} iterations = self.niter parameter_history['alpha'] = np.zeros([iterations], dtype=np.float32) parameter_history['beta'] = np.zeros([iterations], dtype=np.float32) parameter_history['gamma'] = np.zeros([iterations], dtype=np.float32) parameter_history['q_norm'] = np.zeros([iterations], dtype=np.float32) parameter_history['s_norm'] = np.zeros([iterations], dtype=np.float32) self.parameter_history = parameter_history self.__r__ = self.proj - \ Ax(self.res, self.geo, self.angles, 'Siddon', gpuids = self.gpuids) self.__p__ = Atb(self.__r__, self.geo, self.angles, gpuids=self.gpuids) p_norm = np.linalg.norm(self.__p__.ravel(), 2) self.__gamma__ = p_norm * p_norm def reinitialise_cgls(self): self.__r__ = self.proj - \ Ax(self.res, self.geo, self.angles, 'Siddon', gpuids = self.gpuids) self.__p__ = Atb(self.__r__, self.geo, self.angles, gpuids=self.gpuids) p_norm = np.linalg.norm(self.__p__.ravel(), 2) self.__gamma__ = p_norm * p_norm # Overide def run_main_iter(self): self.l2l = np.zeros([self.niter], dtype=np.float32) avgtime = [] for i in range(self.niter): if i == 0: if self.verbose: print("CGLS Algorithm in progress.") toc = default_timer() if i == 1: tic = default_timer() if self.verbose: print('Esitmated time until completetion (s): ' + str((self.niter - 1) * (tic - toc))) avgtic = default_timer() q = tigre.Ax(self.__p__, self.geo, self.angles, 'Siddon', gpuids=self.gpuids) q_norm = np.linalg.norm(q) alpha = self.__gamma__ / (q_norm * q_norm) self.res += alpha * self.__p__ avgtoc = default_timer() avgtime.append(abs(avgtic - avgtoc)) for item in self.__dict__: if isinstance(getattr(self, item), np.ndarray): if np.isnan(getattr(self, item)).any(): raise ValueError('nan found for ' + item + ' at iteraton ' + str(i)) aux = self.proj - \ tigre.Ax(self.res, self.geo, self.angles, 'Siddon', gpuids = self.gpuids) self.l2l[i] = np.linalg.norm(aux) if i > 0 and self.l2l[i] > self.l2l[i - 1]: if self.verbose: print('re-initilization of CGLS called at iteration:' + str(i)) if self.re_init_at_iteration + 1 == i: if self.verbose: print( 'Algorithm exited with two consecutive reinitializations.' ) return self.res self.res -= alpha * self.__p__ self.reinitialise_cgls() self.re_init_at_iteration = i self.__r__ -= alpha * q s = tigre.Atb(self.__r__, self.geo, self.angles, gpuids=self.gpuids) s_norm = np.linalg.norm(s) gamma1 = s_norm * s_norm beta = gamma1 / self.__gamma__ if self.log_parameters: self.parameter_history['alpha'][i] = alpha self.parameter_history['beta'][i] = beta self.parameter_history['gamma'][i] = self.__gamma__ self.parameter_history['q_norm'][i] = q_norm self.parameter_history['s_norm'][i] = s_norm self.__gamma__ = gamma1 self.__p__ = s + beta * self.__p__ if self.verbose: print('Average time taken for each iteration for CGLS:' + str(sum(avgtime) / len(avgtime)) + '(s)')
class CGLS(IterativeReconAlg): __doc__ = ( " CGLS_CBCT solves the CBCT problem using the conjugate gradient least\n" " squares\n" " \n" " CGLS_CBCT(PROJ,GEO,ANGLES,NITER) solves the reconstruction problem\n" " using the projection data PROJ taken over ALPHA angles, corresponding\n" " to the geometry descrived in GEO, using NITER iterations." ) + IterativeReconAlg.__doc__ def __init__(self, proj, geo, angles, niter, **kwargs): # Don't precompute V and W. kwargs.update(dict(W=None, V=None)) self.log_parameters = False # Avoid typo checking IterativeReconAlg.__init__(self, proj, geo, angles, niter, **kwargs) self.initialise_cgls() if self.log_parameters: parameter_history = {} iterations = self.niter parameter_history['alpha'] = np.zeros([iterations], dtype=np.float32) parameter_history['beta'] = np.zeros([iterations], dtype=np.float32) parameter_history['gamma'] = np.zeros([iterations], dtype=np.float32) parameter_history['q_norm'] = np.zeros([iterations], dtype=np.float32) parameter_history['s_norm'] = np.zeros([iterations], dtype=np.float32) self.parameter_history = parameter_history def initialise_cgls(self): self._r = self.proj - Ax(self.res, self.geo, self.angles, 'ray-voxel') self._p = Atb(self._r, self.geo, self.angles) p_norm = np.linalg.norm(self._p.ravel(), 2) self._gamma = p_norm * p_norm # Overide def run_main_iter(self): self.l2l = np.zeros([self.niter], dtype=np.float32) for i in range(self.niter): if i == 0: print("CGLS Algorithm in progress.") toc = time.clock() if i == 1: tic = time.clock() print('Esitmated time until completetion (s): ' + str((self.niter - 1) * (tic - toc))) q = Ax(self._p, self.geo, self.angles, 'ray-voxel') q_norm = np.linalg.norm(q.ravel(), 2) alpha = self._gamma / (q_norm * q_norm) self.res += alpha * self._p aux = self.proj - Ax(self.res, self.geo, self.angles, 'ray-voxel') self.l2l[i] = np.linalg.norm(aux.ravel(), 2) if i > 0 and self.l2l[i] > self.l2l[i - 1]: print('re-initialization was called at iter:' + str(i)) self.res -= alpha * self._p self.initialise_cgls() self._r -= alpha * q s = Atb(self._r, self.geo, self.angles) s_norm = np.linalg.norm(s.ravel(), 2) gamma1 = s_norm * s_norm beta = gamma1 / self._gamma if self.log_parameters: self.parameter_history['alpha'][i] = alpha self.parameter_history['beta'][i] = beta self.parameter_history['gamma'][i] = self._gamma self.parameter_history['q_norm'][i] = q_norm self.parameter_history['s_norm'][i] = s_norm self._gamma = gamma1 self._p = s + beta * self._p
def initialise_cgls(self): self._r = self.proj - Ax(self.res, self.geo, self.angles, 'ray-voxel') self._p = Atb(self._r, self.geo, self.angles) p_norm = np.linalg.norm(self._p.ravel(), 2) self._gamma = p_norm * p_norm
def FDK(proj, geo, angles, **kwargs): """ solves CT image reconstruction. :param proj: np.array(dtype=float32), Data input in the form of 3d :param geo: tigre.utilities.geometry.Geometry Geometry of detector and image (see examples/Demo code) :param angles: np.array(dtype=float32) Angles of projection, shape = (nangles,3) or (nangles,) :param filter: str Type of filter used for backprojection opts: "shep_logan" "cosine" "hamming" "hann" :param verbose: bool Feedback print statements for algorithm progress :param kwargs: dict keyword arguments :return: np.array(dtype=float32) Usage: ------- >>> import tigre >>> import tigre.algorithms as algs >>> import numpy >>> from tigre.demos.Test_data import data_loader >>> geo = tigre.geometry(mode='cone',default_geo=True, >>> nVoxel=np.array([64,64,64])) >>> angles = np.linspace(0,2*np.pi,100) >>> src_img = data_loader.load_head_phantom(geo.nVoxel) >>> proj = tigre.Ax(src_img,geo,angles) >>> output = algs.FDK(proj,geo,angles) tigre.demos.run() to launch ipython notebook file with examples. -------------------------------------------------------------------- This file is part of the TIGRE Toolbox Copyright (c) 2015, University of Bath and CERN-European Organization for Nuclear Research All rights reserved. License: Open Source under BSD. See the full license at https://github.com/CERN/TIGRE/license.txt Contact: [email protected] Codes: https://github.com/CERN/TIGRE/ -------------------------------------------------------------------- Coded by: MATLAB (original code): Ander Biguri PYTHON : Reuben Lindroos """ if "niter" in kwargs: kwargs.pop("niter") if "verbose" in kwargs: verbose = kwargs["verbose"] else: verbose = False if "gpuids" in kwargs: gpuids = kwargs["gpuids"] else: gpuids = None geo = copy.deepcopy(geo) geo.check_geo(angles) geo.checknans() if "filter" in kwargs: filter = kwargs["filter"] else: filter = None if filter is not None: geo.filter = kwargs["filter"] # Weight proj_filt = np.zeros(proj.shape, dtype=np.float32) for ii in range(angles.shape[0]): xv = (np.arange((-geo.nDetector[1] / 2) + 0.5, 1 + (geo.nDetector[1] / 2) - 0.5) * geo.dDetector[1]) yv = (np.arange((-geo.nDetector[0] / 2) + 0.5, 1 + (geo.nDetector[0] / 2) - 0.5) * geo.dDetector[0]) (yy, xx) = np.meshgrid(xv, yv) w = geo.DSD[0] / np.sqrt((geo.DSD[0]**2 + xx**2 + yy**2)) proj_filt[ii] = copy.deepcopy(proj[ii]) * w proj_filt = filtering(proj_filt, geo, angles, parker=False, verbose=verbose) # m = { # 'py_projfilt': proj_filt, # # } # scipy.io.savemat('Tests/Filter_data', m) res = Atb(proj_filt, geo, geo.angles, "FDK", gpuids=gpuids) # res = 0 # res = Atb(proj,geo,angles,'FDK') return res
def gradient_descent(self, geo, angle, iteration): self.res += self.lmbda * 1. / self.V[iteration] * Atb( self.W[self.angle_index[iteration]] * (self.proj[self.angle_index[iteration]] - Ax(self.res, geo, angle, 'interpolated')), geo, angle, 'FDK')
class CGLS(IterativeReconAlg): # noqa: D101 __doc__ = ( " CGLS solves the CBCT problem using the conjugate gradient least\n" " squares\n" " \n" " CGLS(PROJ,GEO,ANGLES,NITER) solves the reconstruction problem\n" " using the projection data PROJ taken over ALPHA angles, corresponding\n" " to the geometry descrived in GEO, using NITER iterations." ) + IterativeReconAlg.__doc__ def __init__(self, proj, geo, angles, niter, **kwargs): # Don't precompute V and W. kwargs.update(dict(W=None, V=None)) kwargs.update(dict(blocksize=angles.shape[0])) self.log_parameters = False self.re_init_at_iteration = 0 IterativeReconAlg.__init__(self, proj, geo, angles, niter, **kwargs) if self.log_parameters: parameter_history = {} iterations = self.niter parameter_history["alpha"] = np.zeros([iterations], dtype=np.float32) parameter_history["beta"] = np.zeros([iterations], dtype=np.float32) parameter_history["gamma"] = np.zeros([iterations], dtype=np.float32) parameter_history["q_norm"] = np.zeros([iterations], dtype=np.float32) parameter_history["s_norm"] = np.zeros([iterations], dtype=np.float32) self.parameter_history = parameter_history self.__r__ = self.proj - Ax( self.res, self.geo, self.angles, "Siddon", gpuids=self.gpuids) self.__p__ = Atb(self.__r__, self.geo, self.angles, backprojection_type="matched", gpuids=self.gpuids) p_norm = np.linalg.norm(self.__p__.ravel(), 2) self.__gamma__ = p_norm * p_norm def reinitialise_cgls(self): self.__r__ = self.proj - Ax( self.res, self.geo, self.angles, "Siddon", gpuids=self.gpuids) self.__p__ = Atb(self.__r__, self.geo, self.angles, backprojection_type="matched", gpuids=self.gpuids) p_norm = np.linalg.norm(self.__p__.ravel(), 2) self.__gamma__ = p_norm * p_norm # Overide def run_main_iter(self): self.l2l = np.zeros((1, self.niter), dtype=np.float32) avgtime = [] for i in range(self.niter): if self.verbose: self._estimate_time_until_completion(i) if self.Quameasopts is not None: res_prev = copy.deepcopy(self.res) avgtic = default_timer() q = tigre.Ax(self.__p__, self.geo, self.angles, "Siddon", gpuids=self.gpuids) q_norm = np.linalg.norm(q) alpha = self.__gamma__ / (q_norm * q_norm) self.res += alpha * self.__p__ avgtoc = default_timer() avgtime.append(abs(avgtic - avgtoc)) for item in self.__dict__: if (isinstance(getattr(self, item), np.ndarray) and np.isnan(getattr(self, item)).any()): raise ValueError("nan found for " + item + " at iteraton " + str(i)) aux = self.proj - tigre.Ax( self.res, self.geo, self.angles, "Siddon", gpuids=self.gpuids) self.l2l[0, i] = np.linalg.norm(aux) if i > 0 and self.l2l[0, i] > self.l2l[0, i - 1]: if self.verbose: print("re-initilization of CGLS called at iteration:" + str(i)) if self.re_init_at_iteration + 1 == i: if self.verbose: print( "Algorithm exited with two consecutive reinitializations." ) return self.res self.res -= alpha * self.__p__ self.reinitialise_cgls() self.re_init_at_iteration = i self.__r__ -= alpha * q s = tigre.Atb(self.__r__, self.geo, self.angles, backprojection_type="matched", gpuids=self.gpuids) s_norm = np.linalg.norm(s) gamma1 = s_norm * s_norm beta = gamma1 / self.__gamma__ if self.log_parameters: self.parameter_history["alpha"][i] = alpha self.parameter_history["beta"][i] = beta self.parameter_history["gamma"][i] = self.__gamma__ self.parameter_history["q_norm"][i] = q_norm self.parameter_history["s_norm"][i] = s_norm self.__gamma__ = gamma1 self.__p__ = s + beta * self.__p__ if self.Quameasopts is not None: self.error_measurement(res_prev, i) if self.verbose: print("Average time taken for each iteration for CGLS:" + str(sum(avgtime) / len(avgtime)) + "(s)")
def reinitialise_cgls(self): self.__r__ = self.proj - Ax(self.res, self.geo, self.angles, 'ray-voxel') self.__p__ = Atb(self.__r__, self.geo, self.angles) p_norm = np.linalg.norm(self.__p__.ravel(), 2) self.__gamma__ = p_norm * p_norm
def test_backproj_parallel_shape(self): setattr(self.geo, 'mode', 'parallel') self.assertTupleEqual( Atb(self.proj, self.geo, self.angles, 'matched').shape, (63, 62, 61))
def FDK(proj, geo, angles, filter=None,verbose=False): ('\n' 'FDK solves Cone Beam CT image reconstruction' '\n' 'Parameters \n' '-------------------------------------------------------------------\n' '\n' 'proj: Data input in the form of 3d, np.array(dtype=float32)\n' '\n' 'geo: Geometry of detector and image (see examples/Demo code)\n' '\n' 'alpha: 1d array of angles corresponding to image data, np.array(dtype=float32)\n' '\n' 'filter: default="ram_lak" \n' ' opts: \n' ' "shep_logan"' ' "cosine" ' ' "hamming" ' ' "hann" ' 'Examples \n' '---------------------------------------------------------------------------\n' 'See Demos/Example code for further instructions.\n' '---------------------------------------------------------------------------' '\n' """This file is part of the TIGRE Toolbox Copyright (c) 2015, University of Bath and CERN-European Organization for Nuclear Research All rights reserved. License: Open Source under BSD. See the full license at https://github.com/CERN/TIGRE/license.txt Contact: [email protected] Codes: https://github.com/CERN/TIGRE/ -------------------------------------------------------------------------- Coded by: MATLAB (original code): Ander Biguri PYTHON : Reuben Lindroos,Sam Loescher, """) geo = copy.deepcopy(geo) geo.check_geo(angles) if filter is not None: geo.filter = filter # Weight proj_filt = np.zeros(proj.shape, dtype=np.float32) for ii in range(angles.shape[0]): xv = np.arange((-geo.nDetector[1] / 2) + 0.5, 1 + (geo.nDetector[1] / 2) - 0.5) * geo.dDetector[1] yv = np.arange((-geo.nDetector[0] / 2) + 0.5, 1 + (geo.nDetector[0] / 2) - 0.5) * geo.dDetector[0] (xx, yy) = np.meshgrid(xv, yv) w = geo.DSD[0] / np.sqrt((geo.DSD[0] ** 2 + xx ** 2 + yy ** 2)) proj_filt[ii] = proj[ii] * w proj_filt = filtering(proj_filt, geo, angles, parker=False,verbose=verbose) # m = { # 'py_projfilt': proj_filt, # # } # scipy.io.savemat('Tests/Filter_data', m) res = Atb(proj_filt, geo, geo.angles, 'FDK') # res = 0 # res = Atb(proj,geo,angles,'FDK') return res
class CGLS(IterativeReconAlg): __doc__ = (" CGLS_CBCT solves the CBCT problem using the conjugate gradient least\n" " squares\n" " \n" " CGLS_CBCT(PROJ,GEO,ANGLES,NITER) solves the reconstruction problem\n" " using the projection data PROJ taken over ALPHA angles, corresponding\n" " to the geometry descrived in GEO, using NITER iterations.") + IterativeReconAlg.__doc__ def __init__(self, proj, geo, angles, niter, **kwargs): # Don't precompute V and W. kwargs.update(dict(W=None, V=None)) kwargs.update(dict(blocksize=angles.shape[0])) self.log_parameters = False IterativeReconAlg.__init__(self, proj, geo, angles, niter, **kwargs) if self.log_parameters: parameter_history = {} iterations = self.niter parameter_history['alpha'] = np.zeros([iterations], dtype=np.float32) parameter_history['beta'] = np.zeros([iterations], dtype=np.float32) parameter_history['gamma'] = np.zeros([iterations], dtype=np.float32) parameter_history['q_norm'] = np.zeros([iterations], dtype=np.float32) parameter_history['s_norm'] = np.zeros([iterations], dtype=np.float32) self.parameter_history = parameter_history self.__r__ = self.proj - Ax(self.res, self.geo, self.angles, 'ray-voxel') self.__p__ = Atb(self.__r__, self.geo, self.angles) p_norm = np.linalg.norm(self.__p__.ravel(), 2) self.__gamma__ = p_norm * p_norm def reinitialise_cgls(self): self.__r__ = self.proj - Ax(self.res, self.geo, self.angles, 'ray-voxel') self.__p__ = Atb(self.__r__, self.geo, self.angles) p_norm = np.linalg.norm(self.__p__.ravel(), 2) self.__gamma__ = p_norm * p_norm # Overide def run_main_iter(self): self.l2l = np.zeros([self.niter], dtype=np.float32) for i in range(self.niter): if i == 0: print("CGLS Algorithm in progress.") toc = time.clock() if i == 1: tic = time.clock() print('Esitmated time until completetion (s): ' + str((self.niter - 1) * (tic - toc))) q = Ax(self.__p__, self.geo, self.angles, 'ray-voxel') q_norm = np.linalg.norm(q.ravel(), 2) alpha = self.__gamma__ / (q_norm * q_norm) self.res += alpha * self.__p__ for item in self.__dict__: if type(getattr(self, item)) == np.ndarray: if np.isnan(getattr(self, item)).any(): raise ValueError('nan found for ' + item + ' at iteraton ' + str(i)) aux = self.proj - Ax(self.res, self.geo, self.angles, 'ray-voxel') self.l2l[i] = np.linalg.norm(aux.ravel(), 2) if i > 0 and self.l2l[i] > self.l2l[i - 1]: print('re-initialization was called at iter:' + str(i)) self.res -= alpha * self.__p__ self.reinitialise_cgls() self.__r__ -= alpha * q s = Atb(self.__r__, self.geo, self.angles) s_norm = np.linalg.norm(s.ravel(), 2) gamma1 = s_norm * s_norm beta = gamma1 / self.__gamma__ if self.log_parameters: self.parameter_history['alpha'][i] = alpha self.parameter_history['beta'][i] = beta self.parameter_history['gamma'][i] = self.__gamma__ self.parameter_history['q_norm'][i] = q_norm self.parameter_history['s_norm'][i] = s_norm self.__gamma__ = gamma1 self.__p__ = s + beta * self.__p__
def test_backproj_FDK_cone_shape(self): setattr(self.geo, 'mode', 'cone') self.assertTupleEqual( Atb(self.proj, self.geo, self.angles, 'FDK').shape, (63, 62, 61))