def __init__(self, pitch=0.784, hi_res=True): # ,det): # Two options for phantoms here if hi_res: self.phantom = np.load( os.path.join( data_path, "phantoms", "catphan_sensiometry_512_10cm_mod.npy", )) # 10cm.npy')) self.geomet = tigre.geometry_default(nVoxel=self.phantom.shape) self.geomet.sVoxel = np.array((160, 200, 200)) #160 ???? # self.scatter = 'scatter_updated.npy' self.geomet.DSD = 1500 # 1520 JO dec 2020 1500 + 20 for det casing else: self.phantom = np.load( os.path.join(data_path, "phantoms", "catphan_sensiometry_512_8cm.npy")) # 10cm.npy')) self.geomet = tigre.geometry_default(nVoxel=self.phantom.shape) self.geomet.sVoxel = np.array((160, 160, 160)) #160 ???? self.geomet.dVoxel = self.geomet.sVoxel / self.geomet.nVoxel self.scatter = 'scatter_updated.npy' self.geomet.DSD = 1520 # 1520 JO dec 2020 1500 + 20 for det casing logging.info("Phantom is low resolution") self.scatter_coords = np.linspace(-256 * 0.0784 - 0.0392, 256 * 0.0784 - 0.0392, 512) # The 10cm is really the 8cm equivalent self.geomet.DSO = 1000 self.geomet.nDetector = np.array([64, 512]) self.geomet.dDetector = np.array([ pitch, pitch ]) # det.pitch, det.pitch]) #TODO: Change this to get phantom # I think I can get away with this self.geomet.sDetector = self.geomet.dDetector * self.geomet.nDetector self.geomet.dVoxel = self.geomet.sVoxel / self.geomet.nVoxel self.phan_map = [ "air", "G4_POLYSTYRENE", "G4_POLYVINYL_BUTYRAL", "G4_POLYVINYL_BUTYRAL", "CATPHAN_Delrin", "G4_POLYVINYL_BUTYRAL", "CATPHAN_Teflon_revised", "air", "CATPHAN_PMP", "G4_POLYVINYL_BUTYRAL", "CATPHAN_LDPE", "G4_POLYVINYL_BUTYRAL", "CATPHAN_Polystyrene", "air", "CATPHAN_Acrylic", "air", "CATPHAN_Teflon", "air", "air", "air", "air", ]
def __init__(self): # ,det): self.phantom = np.load( os.path.join(data_path, "phantoms", "catphan_low_contrast_512_8cm.npy") ) # 'catphan_low_contrast_512_8cm.npy')) # Paper 2 uses the 8cm btw self.geomet = tigre.geometry_default(nVoxel=self.phantom.shape) self.geomet.DSD = 1520 # 1500 + 20 for det casing self.geomet.nDetector = np.array([64, 512]) self.geomet.dDetector = np.array([ 0.784, 0.784 ]) # det.pitch, det.pitch]) #TODO: Change this to get phantom # I think I can get away with this self.geomet.sDetector = self.geomet.dDetector * self.geomet.nDetector self.geomet.sVoxel = np.array((160, 160, 160)) self.geomet.dVoxel = self.geomet.sVoxel / self.geomet.nVoxel self.phan_map = [ "air", "water", "G4_LUNG_ICRP", "G4_BONE_COMPACT_ICRU", "G4_BONE_CORTICAL_ICRP", "G4_ADIPOSE_TISSUE_ICRP", "G4_BRAIN_ICRP", "G4_B-100_BONE", ]
def geometry(mode='cone', nVoxel=None, default_geo=False, high_quality=True): if mode == 'cone': if default_geo: return tigre.geometry_default(high_quality, nVoxel) else: return Geometry() if mode == 'parallel': return ParallelGeo(nVoxel) else: raise ValueError('mode: ' + mode + ' not recognised.')
def __init__(self): self.phantom = np.load( os.path.join(data_path, "phantoms", "MTF_phantom_1024.npy")) self.geomet = tigre.geometry_default(nVoxel=self.phantom.shape) self.geomet.nDetector = np.array([64, 512]) self.geomet.dDetector = np.array([0.784, 0.784]) self.phan_map = ["air", "water", "G4_BONE_COMPACT_ICRU"] self.geomet.DSD = 1500 # I think I can get away with this self.geomet.sDetector = self.geomet.dDetector * self.geomet.nDetector self.geomet.sVoxel = np.array((160, 160, 160)) self.geomet.dVoxel = self.geomet.sVoxel / self.geomet.nVoxel
def __init__(self, pitch=0.33, hi_res=True): if hi_res: self.phantom = np.load( os.path.join( data_path, "phantoms", "catphan_sensiometry_512_10cm_mod.npy", )) # 10cm.npy')) else: self.phantom = np.load( os.path.join(data_path, "phantoms", "catphan_sensiometry_512_8cm.npy")) logging.info("Phantom is low resolution") self.scatter = 'devon_total.npy' self.scatter_coords = np.linspace(-288 * 0.033 - 0.0165, 288 * 0.033 - 0.165, 576) # The 10cm is really the 8cm equivalent self.geomet = tigre.geometry_default(nVoxel=self.phantom.shape) self.geomet.DSO = 322 self.geomet.DSD = 322 + 266 # 1520 JO dec 2020 1500 + 20 for det casing self.geomet.nDetector = np.array([64, 576]) self.geomet.dDetector = np.array([pitch, pitch]) # I think I can get away with this self.geomet.sDetector = self.geomet.dDetector * self.geomet.nDetector self.geomet.sVoxel = np.array((50, 100, 100)) self.geomet.dVoxel = self.geomet.sVoxel / self.geomet.nVoxel self.phan_map = [ "air", "G4_POLYSTYRENE", "G4_POLYVINYL_BUTYRAL", "G4_POLYVINYL_BUTYRAL", "CATPHAN_Delrin", "G4_POLYVINYL_BUTYRAL", "CATPHAN_Teflon_revised", "air", "CATPHAN_PMP", "G4_POLYVINYL_BUTYRAL", "CATPHAN_LDPE", "G4_POLYVINYL_BUTYRAL", "CATPHAN_Polystyrene", "air", "CATPHAN_Acrylic", "air", "CATPHAN_Teflon", "air", "air", "air", "air", ]
def geometry(mode="cone", nVoxel=None, default=False, high_quality=True): # noqa: N803 """ Constructor for geometry used in reconstruction of images in TIGRE Parameters ---------- :param mode: (str) 'cone' or 'parallel' :param nVoxel: (np.ndarray) number of voxels the reconstruction is composed of :param default: (bool) calculates other parameters in geometry. is by default true for parallel geometry :param high_quality: (bool) preset values for geometry in mode=cone. WARNING: for smaller tests it is better to use this rather than setting nVoxel manually. if true: nVoxel = np.array([512,512,512]) if false: nVoxel = np.array([64,64,64]) :return: (tigre.geometry.Geometry) Usage ----- >>> import tigre >>> #Cone beam with no preset parameters >>> geo_cone = tigre.geometry(mode='cone') >>> # Cone beam default, low quality >>> geo_cone_default = tigre.geometry(mode='cone',high_quality=False) >>> # Cone beam with specific nVoxel requirements >>> geo_cone__default2 = tigre.geometry(nVoxel=np.array([64,64,64]), >>> mode='cone' >>> default=True) >>> # Parallel beam >>> geo_par = tigre.geometry(mode='parallel', >>> nVoxel=np.array([64,64,64])) """ if mode == "cone": if default: return tigre.geometry_default(high_quality, nVoxel) else: return Geometry() if mode == "parallel": return ParallelGeo(nVoxel) else: raise ValueError("mode: " + mode + " not recognised.")
def __init__(self): self.phantom = np.load( os.path.join(data_path, "phantoms", "catphan_projection_512_10cm.npy")).T self.geomet = tigre.geometry_default(nVoxel=self.phantom.shape) self.geomet.nDetector = np.array([512, 512]) self.geomet.dDetector = np.array([0.784, 0.784]) self.phan_map = [ "air", "water", "CB2-30", "adipose", "water", "water", "G4_LUNG_ICRP", "tissue4", "testis", "brain", "tissue", "tissue4", "testis", "brain", "breast", "muscle", "G4_MUSCLE_SKELETAL_ICRP", "G4_MUSCLE_STRIATED_ICRU", "G4_SKIN_ICRP", "G4_TISSUE-PROPANE", "G4_TISSUE-METHANE", "G4_TISSUE_SOFT_ICRP", "G4_TISSUE_SOFT_ICRU-4", "G4_BLOOD_ICRP", "G4_BODY", "G4_BONE_COMPACT_ICRU", "G4_BONE_CORTICAL_ICRP", ] self.geomet.DSD = 1500 # I think I can get away with this self.geomet.sDetector = self.geomet.dDetector * self.geomet.nDetector self.geomet.sVoxel = np.array((160, 160, 150)) self.geomet.dVoxel = self.geomet.sVoxel / self.geomet.nVoxel
# # License: Open Source under BSD. # See the full license at # https://github.com/CERN/TIGRE/blob/master/LICENSE # # Contact: [email protected] # Codes: https://github.com/CERN/TIGRE/ # Coded by: Ander Biguri #%%Initialize import tigre import numpy as np from tigre.utilities import sample_loader import time #%% Geometry geo = tigre.geometry_default(high_resolution=False) #%% This parameter is key for the accuracy of the interpolated FWD projection. geo.accuracy = 0.5 # Accuracy of FWD proj (vx/sample) # lets do just one angles angles = np.array([0]) #%% Description # The difference between them is that `Siddon` will compute the # intersection of a ray crossing each voxel, and the `interpolated` will # sample the voxels at a given sample rate. #%% Main difference
import tigre import numpy as np from tigre import Ax from tigre.demos.Test_data import data_loader from cil.utilities.display import plotter2D geo = tigre.geometry_default(high_quality=False) print(geo.dDetector) geo.nDetector[0] = 1 print(geo.nDetector) geo.sDetector = geo.dDetector * geo.nDetector print(geo.sDetector) geo.nVoxel[0] = 1 geo.sVoxel = geo.nVoxel * geo.dVoxel # print (geo) # define angles angles = np.linspace(0, 2 * np.pi, dtype=np.float32) # load head phantom data head = data_loader.load_head_phantom(number_of_voxels=geo.nVoxel) # generate projections projections = Ax(head, geo, angles, 'interpolated') print(geo.nVoxel, head.shape, projections.shape) # plotter2D([head[0], projections[:,0,:]])
# correction (mm) # This can also be defined per # angle geo.rotDetector = np.array([0, 0, 0]) # Rotation of the detector, by # X,Y and Z axis respectively. (rad) # This can also be defined per # angle geo.mode = "cone" # Or 'parallel'. Geometry type. #%% Print the Geometry print(geo) #%% Alternatively, # # if you are just experimenting with TIGRE and you dont care too much about the geometry, you can generate default geometries as: geo = tigre.geometry_default() # Default cone beam geometry geo = tigre.geometry( mode="cone", default=True ) # default=True calculates all parameters for the geometry for you, so you can do: geo = tigre.geometry( mode="cone", default=True, nVoxel=np.array([256, 256, 256]) ) # This will calculate a reasonable geometry for this number of voxels geo = tigre.geometry( mode="cone", default=True, high_resolution=True ) # high_resolution will result on an image 512^3, while false will result on a 128^3 image. nVoxel overrides these values. geo = tigre.geometry( mode="parallel", nVoxel=np.array([512, 512, 512]) ) # Parallel beam geometry does not require anything other than the image size. #%% Plot your geometry geo = tigre.geometry_default() # Default cone beam geometry
def __init__(self): head = True if head: self.phantom = np.load( os.path.join(data_path, "phantoms", "ct_scan_head_mandible.npy")) else: self.phantom = np.load( os.path.join(data_path, "phantoms", "ct_scan_smaller.npy")) self.geomet = tigre.geometry_default(nVoxel=self.phantom.shape) self.geomet.nDetector = np.array([124, 512]) self.geomet.dDetector = np.array([0.784, 0.784]) if head: self.phan_map = [ "air", "G4_LUNG_LD_ICRP", "G4_ADIPOSE_TISSUE_ICRP2", "water", "RED_MARROW_ICRP", "G4_BRAIN_ICRP", "G4_MUSCLE_SKELETAL_ICRP", "THYROID_ICRP", "blood", "G4_EYE_LENS_ICRP", "CARTILAGE_ICRP", "C4_Vertebra_ICRP", "SKULL_ICRP", 'air', '47' ] else: self.phan_map = [ "air", "air", "G4_LUNG_LD_ICRP", "G4_ADIPOSE_TISSUE_ICRP2", "water", "RED_MARROW_ICRP", "INTESTINE_ICRP", "PANCREAS_ICRP", "G4_MUSCLE_SKELETAL_ICRP", "KIDNEY_ICRP", "HEART_ICRP", "THYROID_ICRP", "LIVER_ICRP", "blood", "SPLEEN_ICRP", "CARTILAGE_ICRP", "C4_Vertebra_ICRP", "SKULL_ICRP", "RIB_BONE_ICRP", ] self.geomet.DSD = 1500 # I think I can get away with this self.geomet.sDetector = self.geomet.dDetector * self.geomet.nDetector if head: self.geomet.sVoxel = np.array(( self.phantom.shape[0] * 3.125, self.phantom.shape[1] / 2, self.phantom.shape[2] / 2, )) else: self.geomet.sVoxel = np.array(( self.phantom.shape[0] * 3.125, self.phantom.shape[1], self.phantom.shape[2], )) self.geomet.dVoxel = self.geomet.sVoxel / self.geomet.nVoxel