def FISTA(projections, volume, geometry, iterations): ''' FISTA reconstruction. Right now there is no TV minimization substep here! ''' global settings preview = settings['preview'] norm_update = settings['norm_update'] # Sampling: samp = geometry['proj_sample'] anisotropy = geometry['vol_sample'] shp = numpy.array(projections.shape) shp //= samp prj_weight = 1 / (shp[1] * numpy.prod(anisotropy) * max(volume.shape)) # Initialize L2: settings['norm'] = [] t = 1 volume_t = volume.copy() volume_old = volume.copy() print('FISTING in progress...') sleep(0.5) # Switch off progress bar if preview is on... if preview: ncols = 0 else: ncols = 50 for ii in tqdm(range(iterations), ncols=ncols): # Update volume: if sum(samp) > 3: proj = projections[::samp[0], ::samp[1], ::samp[2]] FISTA_step(proj, prj_weight, volume, volume_old, volume_t, t, geometry) else: FISTA_step(projections, volume, volume_old, volume_t, t, geometry) # Preview if preview: display.display_slice(volume, dim=1) if norm_update: display.plot(settings['norm'], semilogy=True, title='Resudual norm')
def SIRT(projections, volume, geometry, iterations): """ Simultaneous Iterative Reconstruction Technique. """ global settings preview = settings['preview'] norm_update = settings['norm_update'] # Sampling: samp = geometry['proj_sample'] shp = numpy.array(projections.shape) shp //= samp # Initialize L2: settings['norm'] = [] print('Feeling SIRTy...') sleep(0.5) # Switch off progress bar if preview is on... if preview: ncols = 0 else: ncols = 50 # Iterate: for ii in tqdm(range(iterations), ncols=ncols): # Update volume: if sum(samp) > 3: L2_step(projections[::samp[0], ::samp[1], ::samp[2]], volume, geometry) else: L2_step(projections, volume, geometry) # Preview if preview: display.display_slice(volume, dim=1) if norm_update: display.plot(settings['norm'], semilogy=True, title='Resudual L2')
def MULTI_SIRT(projections, volume, geometries, iterations): """ A multi-dataset version of SIRT. Here prjections and geometries are lists. """ global settings preview = settings['preview'] norm_update = settings['norm_update'] norm = settings['norm'] # Make sure array is contiguous (if not memmap): # if not isinstance(projections, numpy.memmap): # projections = numpy.ascontiguousarray(projections) # Initialize L2: norm = [] print('Doing SIRT`y things...') sleep(0.5) # Switch off progress bar if preview is on... if preview: ncols = 0 else: ncols = 50 for ii in tqdm(range(iterations), ncols=ncols): norm = 0 for ii, proj in enumerate(projections): # This weight is half of the normal weight to make sure convergence is ok: #prj_weight = 1 / (proj.shape[1] * max(volume.shape)) # Update volume: L2_step(proj, volume, geometries[ii]) # Preview if preview: display.display_slice(volume, dim=1) if norm_update: display.plot(norm, semilogy=True, title='Resudual norm')
def EM(projections, volume, geometry, iterations): """ Expectation Maximization """ global settings preview = settings['preview'] norm_update = settings['norm_update'] # Make sure that the volume is positive: if volume.max() <= 0: volume *= 0 volume += 1 elif volume.min() < 0: volume[volume < 0] = 0 projections[projections < 0] = 0 # Initialize L2: settings['norm'] = [] print('Em Emm Emmmm...') sleep(0.5) # Switch off progress bar if preview is on... if preview: ncols = 0 else: ncols = 50 # Go! for ii in tqdm(range(iterations), ncols=ncols): # Update volume: EM_step(projections, volume, geometry) # Preview if preview: display.display_slice(volume, dim=1) if norm_update: display.plot(settings['norm'], semilogy=True, title='Resudual norm')
import numpy #%% Create volume and forward project: # Initialize images: proj = numpy.zeros([1, 361, 512], dtype = 'float32') # Define a simple projection geometry: geometry = io.init_geometry(src2obj = 100, det2obj = 100, det_pixel = 0.01, theta_range = [0, 360], geom_type = 'simple') print('Volume width is:', 512 * geometry['img_pixel']) # Create phantom and project into proj: vol = phantom.abstract_nudes([1, 512, 512], geometry, complexity = 10) display.display_slice(vol, title = 'Phantom') # Forward project: project.forwardproject(proj, vol, geometry) display.display_slice(proj, title = 'Sinogram') #%% Unfiltered back-project # Make volume: vol_rec = numpy.zeros_like(vol) # Backproject: project.settings['block_number'] = 1 project.backproject(proj, vol_rec, geometry) display.display_slice(vol_rec, title = 'Backprojection')
from flexcalc import spectrum from flexcalc import process import numpy #%% Define a simple projection geometry: geometry = io.init_geometry(src2obj = 100, det2obj = 100, det_pixel = 0.2, theta_range = [0, 360], geom_type = 'simple') #%% Short version of the spectral modeling: # This is our phantom: vol = phantom.cuboid([1,128,128], geometry, 8,8,8) display.display_slice(vol , title = 'Phantom') # Spectrum of the scanner: kv = 90 filtr = {'material':'Cu', 'density':8, 'thickness':0.1} detector = {'material':'Si', 'density':5, 'thickness':1} E, S = spectrum.effective_spectrum(kv = 90, filtr = filtr, detector = detector) # Display: display.plot(E,S, title ='Spectrum') # Materials list that corresponds to the number of labels in our phantom: mats = [{'material':'Al', 'density':2.7},] # Sinogram that will be simultated: counts = numpy.zeros([1, 128, 128], dtype = 'float32')
path = '/ufs/ciacc/flexbox/al_test/90KV_no_filt/' dark = io.read_tiffs(path, 'di00') flat = io.read_tiffs(path, 'io00') proj = io.read_tiffs(path, 'scan_') meta = io.read_meta(path, 'flexray') #%% Prepro: proj = (proj - dark) / (flat.mean(0) - dark) proj = -numpy.log(proj) proj = array.raw2astra(proj) display.display_slice(proj, title='Sinogram. What else?') #%% FDK Recon vol = project.init_volume(proj) project.FDK(proj, vol, meta['geometry']) display.display_slice(vol, bounds=[], title='FDK') #%% EM vol = numpy.ones([10, 2000, 2000], dtype='float32') project.EM(proj, vol, meta['geometry'], iterations=3) display.display_slice(vol, title='EM')
# Compute the spectrum of the system using data @ path: # It is assumed that the data provided has a sample made of a single material (see 'compound' parameter) energy, spectrum = process.data_to_spectrum(path, compound = 'Al', density = 2.7) #%% Read data, reconstruct uncorrected: # Read: proj, meta = process.process_flex(path, sample = 2, skip = 2) # Reconstruct: vol = project.init_volume(proj) project.FDK(proj, vol, meta['geometry']) display.display_slice(vol, title = 'Uncorrected FDK') a,b = process.histogram(vol, rng = [-0.05, 0.15]) #%% Calibrate: proj = process.equivalent_density(proj, meta, energy, spectrum, compound = 'Al', density = 2.7) #%% Reconstruct corrected: vol = project.init_volume(proj) project.FDK(proj, vol, meta['geometry']) display.display_slice(vol, title = 'Corrected FDK')
path = '/ufs/ciacc/flexbox/al_test/90KV_no_filt/' dark = io.read_tiffs(path, 'di00') flat = io.read_tiffs(path, 'io00') proj = io.read_tiffs(path, 'scan_') meta = io.read_meta(path, 'flexray') #%% Prepro: proj = (proj - dark) / (flat.mean(0) - dark) proj = -numpy.log(proj) proj = array.raw2astra(proj) display.display_slice(proj, title='Sinogram. What else?') #%% Recon: vol = numpy.zeros([50, 2000, 2000], dtype='float32') # Initialize ASTRA geometries: vol_geom = io.astra_vol_geom(meta['geometry'], vol.shape) proj_geom = io.astra_proj_geom(meta['geometry'], proj.shape) # This is ASTRAAA!!! sin_id = astra.data3d.link('-sino', proj_geom, numpy.ascontiguousarray(proj)) vol_id = astra.data3d.link('-vol', vol_geom, numpy.ascontiguousarray(vol)) cfg = astra.astra_dict('FDK_CUDA') cfg['ReconstructionDataId'] = vol_id
meta = io.read_meta(path, 'flexray') #%% Prepro: # Now, since the data is on the harddisk, we shouldn't lose the pointer to it! # Be careful which operations to apply. Implicit are OK. proj -= dark proj /= (flat.mean(0) - dark) numpy.log(proj, out=proj) proj *= -1 proj = array.raw2astra(proj) display.display_slice(proj) #%% Recon vol = numpy.zeros([50, 1000, 1000], dtype='float32') # Split the data into 20 subsets: project.settings['block_number'] = 20 project.FDK(proj, vol, meta['geometry']) display.display_slice(vol) #%% SIRT vol = numpy.ones([50, 1000, 1000], dtype='float32')
# Name and range of the parameter to optimize: key = 'det_rot' trial_values = numpy.linspace(-0.01, 0.01, 11) # Subsampling of data (vertical x 10) samp = [5, 1, 1] # Optimization: guess = process.optimize_modifier(trial_values, proj, meta['geometry'], samp=samp, key=key, preview=True) #%% Reconstruct uncorrected: vol = project.init_volume(proj) project.FDK(proj, vol, meta['geometry']) display.display_slice(vol, bounds=[], title='FDK Corrected') #%% REconstruct corrected: meta['geometry'][key] = guess vol = project.init_volume(proj) project.FDK(proj, vol, meta['geometry']) display.display_slice(vol, bounds=[], title='FDK Corrected')
#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ Load a standard CT scan. Use flexCALC.process to preprocess the data. """ #%% Imports from flexcalc import process from flexdata import display from flextomo import project #%% Read data: path = '/ufs/ciacc/flexbox/al_test/90KV_no_filt/' proj, meta = process.process_flex(path, skip=4, sample=4) #%% FDK: vol = project.init_volume(proj) project.FDK(proj, vol, meta['geometry']) display.display_slice(vol, bounds=[], title='FDK')
vol = numpy.zeros([1, h, h], dtype='float32') proj = numpy.zeros([1, 361, h], dtype='float32') # Define a simple projection geometry: src2obj = 100 # mm det2obj = 100 # mm det_pixel = 0.001 / x # mm (1 micron) geometry = io.init_geometry(src2obj, det2obj, det_pixel, [0, 360]) # Create phantom (150 micron wide, 15 micron wall thickness): vol = phantom.sphere(vol.shape, geometry, 0.08) vol -= phantom.sphere(vol.shape, geometry, 0.07) # Show: display.display_slice(vol, title='Phantom') # Project: project.forwardproject(proj, vol, geometry) #%% # Get the material refraction index: c = spectrum.find_nist_name('Calcium Carbonate') rho = c['density'] / 10 energy = 30 # KeV n = spectrum.material_refraction(energy, 'CaCO3', rho) #%% Proper Fresnel propagation for phase-contrast: # Create Contrast Transfer Functions for phase contrast effect and detector blurring
#%% Read the data path = '/ufs/ciacc/flexbox/JINR_data/projections/SPos0/Energy150000/' proj = io.read_tiffs(path, '00') # Transpose for ASTRA compatibility: proj = array.raw2astra(proj) # Get rid of funny values: proj[(~numpy.isfinite(proj)) | (proj < 0.1)] = 1 proj[proj > 1] = 1 # Da Holy LOG: proj = -numpy.log(proj) display.display_slice(proj, title='Sinogram') display.display_slice(proj, dim=1, title='Projection') #%% Create geometry: # We don't have a dedicated parser for JINR geometry description file. # so we will simply make an ASTRA geometry by hand ''' Mode = cone beam Last angle = 360� Pixel size = 0.055 mm Centre of rotation = 1034.82 Source object distance = 120 mm Source detector distance = 220 mm Direction of rotation = counter-clockwise Vertical centre = 203