# simply does not have any way of storing the information (Zeiss Xradia # does not store anything but the projecions) # if this is the case, the general way of tackling the problem is: # Step 1: define your geometry and angles geo=tigre.geometry() angles= # Step 2: Load projections: #store in NP array. Use whichever python lirbary will help you get the data loaded. # Step 3: validate tigre.plotproj(proj,angles) # you need to make sure that: # 1) white=metal/bone/high density and black=air. # If this is not the case proj=-np.log(proj/(np.max(proj+1)); # Beer-Lanbert law # 2) rotation happens left-right instead of top-bottom. # If its top bottom permute your data as required # Step 4: test imgfdk=algs.fdk(proj,geo,angles) tigre.plotimg(imgFDK,dim='z') # If this does not look good, possible things to check: # - Are the angles in the right direction? maybe they need to be inverted. # - Is your geometry properly defined? mistake on geometry will be # detrimental to image quality # - if microCT: halos around the features? COR correction needed.
# sample the voxels at a given sample rate. #%% Main difference head = sample_loader.load_head_phantom(geo.nVoxel) start_time = time.time() projInterp = tigre.Ax(head, geo, angles, "interpolated") interptime = time.time() - start_time start_time = time.time() projray = tigre.Ax(head, geo, angles, "Siddon") raytime = time.time() - start_time # It is relatively clear that discretization artefacts appear with the # ray-voxel approach (middle one) tigre.plotproj( np.concatenate([np.abs(projInterp - projray), projray, projInterp], axis=1), angles) # But also the ray voxel approach is faster (more obvious at bigger sizes) print("Time interpolated: " + str(interptime)) print("Time Siddon : " + str(raytime)) #%% With small voxel the errors are more obvious geo.nVoxel = np.array([32, 32, 32]) # number of voxels (vx) geo.sVoxel = np.array([256, 256, 256]) # total size of the image (mm) geo.dVoxel = geo.sVoxel / geo.nVoxel # size of each voxel (mm) head = sample_loader.load_head_phantom(geo.nVoxel) geo.accuracy = 3 projInterp3 = tigre.Ax(head, geo, angles, "interpolated") geo.accuracy = 1 projInterp1 = tigre.Ax(head, geo, angles, "interpolated")
roll = angles pitch = 0.7 * np.linspace(0, 1, len(angles)) yaw = 0.7 * np.linspace(0, 1, len(angles)) geo.rotDetector = np.array(np.vstack([roll, pitch, yaw])).T #%% # Load thorax phatom data head = sample_loader.load_head_phantom(geo.nVoxel) # generate projections projections = tigre.Ax(head, geo, angles) # add noise noise_projections = CTnoise.add(projections, Poisson=1e5, Gaussian=np.array([0, 10])) tigre.plotproj(projections, angles) #%% recon imgRotDet = algs.ossart(projections, geo, angles, 50) #% No rotation geo.rotDetector = np.array([0, 0, 0]) projections2 = tigre.Ax(head, geo, angles) imgnoRot = algs.ossart(projections2, geo, angles, 50) # %% Plot to show that indeed the reconstruction is right tigre.plotimg(np.concatenate([imgRotDet, imgnoRot], axis=1), dim="z")
geo = tigre.geometry_default(high_resolution=False) #%% Define angles of projection and load phatom image # define projection angles (in radians) angles = np.linspace(0, 2 * np.pi, 50) # load phatnom image head = sample_loader.load_head_phantom(geo.nVoxel) # Simulate forward projection. # To match with mathematical notation, the projection operation is called Ax projections = tigre.Ax(head, geo, angles) # Add realistic noise. Adds photon scattering noise ('Poisson') and # electronic noise of the detector ('Gaussian'). # # 'Poisson' is related to the maximum photon count in the detector. 1e5 is # a standard clinical nuber, reduce it for more noise # 'Gaussian' is related to possible electronic noise in the detector. mean # of 0 and std of 10 is common in clinical scenario. Increase std for more # noise. noise_projections = CTnoise.add(projections, Poisson=1e5, Gaussian=np.array([0, 10])) #%% Plot Projections tigre.plotproj(projections) # plot noise tigre.plotproj(projections - noise_projections)
clims = [0, 200] # 'Savegif': allows to save the plotted figure as an animated gif, # specified by the given filename. giffilename = "demo5projections.gif" # 'Slice': allows to plot a single projection .Will overwrite the behaviour # of 'Step' slice = 5 # Lets try out. tigre.plotproj(noise_projections, angles, step=step, colormap=colormap, clims=clims, savegif=giffilename) # not using 'Step' # Remember you can also plot errors, for example the added noise by: noise = np.abs(noise_projections - projections) # abs is what we are interested in plotting tigre.plotproj(noise, angles, clims=[0, 2]) #%% PlotImg # plotImg plots the image slice by slice. # # List of optional parameters:
#%% Load data and generate projections # define angles angles = np.linspace(0, 2 * np.pi, 100) ## Define angles numProjs = 100 anglesY = np.linspace(0, 2 * np.pi, numProjs) anglesZ2 = anglesY anglesZ1 = np.pi * np.sin(np.linspace(0, 2 * np.pi, numProjs)) angles = np.vstack([anglesZ1, anglesY, anglesZ2]).T ## Get Image head = sample_loader.load_head_phantom(geo.nVoxel) ## Project projections = tigre.Ax(head, geo, angles) tigre.plotproj(projections, anglesY) # angle information not right in the title ## Reconstruct: # Note, FDK will not work. imgSIRT = algs.sirt(projections, geo, angles, 50) imgCGLS = algs.cgls(projections, geo, angles, 10) tigre.plotimg(np.concatenate([head, imgSIRT, imgCGLS], axis=1), dim="z")