def load_projections(self): ''' Load projections and return AcquisitionData container ''' # get path to projections path_projection = os.path.dirname(self.xtek_file) # get number of projections num_projections = numpy.shape(self._ag.angles)[0] # allocate array to store projections data = numpy.zeros( (num_projections, self._ag.pixel_num_v, self._ag.pixel_num_h), dtype=float) for i in range(num_projections): filename = (path_projection + '/' + self._experiment_name + '_{:04d}.tif').format(i + 1) try: tmp = numpy.asarray(Image.open(filename), dtype=float) except: print('Error reading\n {}\n file.'.format(filename)) raise if (self.binning == [1, 1]): data[i, :, :] = tmp[self._roi_par[0][0]:self._roi_par[0][1], self._roi_par[1][0]:self._roi_par[1][1]] else: shape = (self._ag.pixel_num_v, self.binning[0], self._ag.pixel_num_h, self.binning[1]) data[i, :, :] = tmp[self._roi_par[0][0]:(self._roi_par[0][0] + (((self._roi_par[0][1] - self._roi_par[0][0]) // self.binning[0]) * self.binning[0])), \ self._roi_par[1][0]:(self._roi_par[1][0] + (((self._roi_par[1][1] - self._roi_par[1][0]) // self.binning[1]) * self.binning[1]))].reshape(shape).mean(-1).mean(1) if (self.normalize): data /= self._white_level data[data > 1] = 1 if self.flip: return AcquisitionData(array = data[:, :, ::-1], deep_copy = False, geometry = self._ag, dimension_labels = ['angle', \ 'vertical', \ 'horizontal']) else: return AcquisitionData(array = data, deep_copy = False, geometry = self._ag, dimension_labels = ['angle', \ 'vertical', \ 'horizontal'])
def process(self): IM = self.get_input() DATA = AcquisitionData(geometry=self.sinogram_geometry, dimension_labels=self.output_axes_order) sinogram_id, DATA.array = astra.create_sino3d_gpu( IM.as_array(), self.proj_geom, self.vol_geom) astra.data3d.delete(sinogram_id) # 3D CUDA FP does not need scaling return DATA
def allocate_direct(self): if issubclass(type(self.geometry), ImageGeometry): return ImageData(geometry=self.geometry) elif issubclass(type(self.geometry), AcquisitionGeometry): return AcquisitionData(geometry=self.geometry) else: raise ValueError( "Wrong geometry type: expected ImageGeometry of AcquisitionGeometry, got ", type(self.geometry))
def test_AcquisitionData(self): sgeometry = AcquisitionGeometry(dimension=2, angles=numpy.linspace(0, 180, num=10), geom_type='parallel', pixel_num_v=3, pixel_num_h=5, channels=2) sino = AcquisitionData(geometry=sgeometry) self.assertEqual(sino.shape, (2, 10, 3, 5))
def process(self): IM = self.get_input() #create the output AcquisitionData DATA = AcquisitionData(geometry=self.sinogram_geometry) for k in range(DATA.geometry.channels): sinogram_id, DATA.as_array()[k] = astra.create_sino( IM.as_array()[k], self.proj_id) astra.data2d.delete(sinogram_id) if self.device == 'cpu': return DATA else: if self.sinogram_geometry.geom_type == 'cone': return DATA else: scaling = (1.0 / self.volume_geometry.voxel_size_x) return scaling * DATA
def setupCCPiGeometries(voxel_num_x, voxel_num_y, voxel_num_z, angles, counter): vg = ImageGeometry(voxel_num_x=voxel_num_x,voxel_num_y=voxel_num_y, voxel_num_z=voxel_num_z) Phantom_ccpi = ImageData(geometry=vg, dimension_labels=['horizontal_x','horizontal_y','vertical']) #.subset(['horizontal_x','horizontal_y','vertical']) # ask the ccpi code what dimensions it would like voxel_per_pixel = 1 geoms = pbalg.pb_setup_geometry_from_image(Phantom_ccpi.as_array(), angles, voxel_per_pixel ) pg = AcquisitionGeometry('parallel', '3D', angles, geoms['n_h'], 1.0, geoms['n_v'], 1.0 #2D in 3D is a slice 1 pixel thick ) center_of_rotation = Phantom_ccpi.get_dimension_size('horizontal_x') / 2 ad = AcquisitionData(geometry=pg,dimension_labels=['angle','vertical','horizontal']) geoms_i = pbalg.pb_setup_geometry_from_acquisition(ad.as_array(), angles, center_of_rotation, voxel_per_pixel ) counter+=1 if counter < 4: if (not ( geoms_i == geoms )): print ("not equal and {0}".format(counter)) X = max(geoms['output_volume_x'], geoms_i['output_volume_x']) Y = max(geoms['output_volume_y'], geoms_i['output_volume_y']) Z = max(geoms['output_volume_z'], geoms_i['output_volume_z']) return setupCCPiGeometries(X,Y,Z,angles, counter) else: return geoms else: return geoms_i
def process(self): IM = self.get_input() DATA = AcquisitionData(geometry=self.sinogram_geometry) #sinogram_id, DATA = astra.create_sino( IM.as_array(), # self.proj_id) sinogram_id, DATA.array = astra.create_sino(IM.as_array(), self.proj_id) astra.data2d.delete(sinogram_id) if self.device == 'cpu': return DATA else: if self.sinogram_geometry.geom_type == 'cone': return DATA else: scaling = 1.0 / self.volume_geometry.voxel_size_x return scaling * DATA
def get_acquisition_data(self, dimensions=None): ''' This method load the acquisition data and given dimension and returns an AcquisitionData Object ''' data = self.load_projection(dimensions) dims = self.get_projection_dimensions() geometry = AcquisitionGeometry('parallel', '3D', self.get_projection_angles(), pixel_num_h=dims[2], pixel_size_h=1, pixel_num_v=dims[1], pixel_size_v=1, dist_source_center=None, dist_center_detector=None, channels=1) return AcquisitionData( data, geometry=geometry, dimension_labels=['angle', 'vertical', 'horizontal'])
def test_AcquisitionGeometry_allocate(self): ageometry = AcquisitionGeometry(dimension=2, angles=numpy.linspace(0, 180, num=10), geom_type='parallel', pixel_num_v=3, pixel_num_h=5, channels=2) sino = ageometry.allocate() shape = sino.shape print ("shape", shape) self.assertEqual(0,sino.as_array()[0][0][0][0]) self.assertEqual(0,sino.as_array()[shape[0]-1][shape[1]-1][shape[2]-1][shape[3]-1]) sino = ageometry.allocate(1) self.assertEqual(1,sino.as_array()[0][0][0][0]) self.assertEqual(1,sino.as_array()[shape[0]-1][shape[1]-1][shape[2]-1][shape[3]-1]) print (sino.dimension_labels, sino.shape, ageometry) default_order = ['channel' , 'angle' , 'vertical' , 'horizontal'] self.assertEqual(default_order[0], sino.dimension_labels[0]) self.assertEqual(default_order[1], sino.dimension_labels[1]) self.assertEqual(default_order[2], sino.dimension_labels[2]) self.assertEqual(default_order[3], sino.dimension_labels[3]) order = ['vertical' , 'horizontal', 'channel' , 'angle' ] sino = ageometry.allocate(0,dimension_labels=order) print (sino.dimension_labels, sino.shape, ageometry) self.assertEqual(order[0], sino.dimension_labels[0]) self.assertEqual(order[1], sino.dimension_labels[1]) self.assertEqual(order[2], sino.dimension_labels[2]) self.assertEqual(order[2], sino.dimension_labels[2]) try: z = AcquisitionData(numpy.random.randint(10, size=(2,3)), geometry=ageometry) self.assertTrue(False) except ValueError as ve: print (ve) self.assertTrue(True)
def process(self): volume = self.get_input() volume_axes = volume.get_data_axes_order(new_order=self.default_image_axes_order) if not volume_axes == [0,1,2]: volume.array = numpy.transpose(volume.array, volume_axes) pixel_per_voxel = 1 # should be estimated from image_geometry and # acquisition_geometry if self.acquisition_geometry.geom_type == 'parallel': pixels = pbalg.pb_forward_project(volume.as_array(), self.acquisition_geometry.angles, pixel_per_voxel) out = AcquisitionData(geometry=self.acquisition_geometry, label_dimensions=self.default_acquisition_axes_order) out.fill(pixels) out_axes = out.get_data_axes_order(new_order=self.output_axes_order) if not out_axes == [0,1,2]: out.array = numpy.transpose(out.array, out_axes) return out else: raise ValueError('Cannot process cone beam')
def get_acquisition_data(self, dimensions=None): ''' This method load the acquisition data and given dimension and returns an AcquisitionData Object ''' data = self.load_projection(dimensions) return AcquisitionData(data, geometry=self.geometry)
def get_acquisition_data_batch(self, bmin=None, bmax=None): if not h5pyAvailable: raise Exception("Error: h5py is not installed") if self.filename is None: return try: with NexusFile(self.filename, 'r') as file: try: dims = self.get_projection_dimensions() except KeyError: dims = file[self.data_path].shape if bmin is None or bmax is None: raise ValueError( 'get_acquisition_data_batch: please specify fastest index batch limits' ) if bmin >= 0 and bmin < bmax and bmax <= dims[0]: data = np.array(file[self.data_path][bmin:bmax]) else: raise ValueError( 'get_acquisition_data_batch: bmin {0}>0 bmax {1}<{2}'. format(bmin, bmax, dims[0])) except: print("Error reading nexus file") raise try: angles = self.get_projection_angles()[bmin:bmax] except KeyError as ke: n = data.shape[0] angles = np.linspace(0, n, n + 1, dtype=np.float32)[bmin:bmax] if bmax - bmin > 1: geometry = AcquisitionGeometry('parallel', '3D', angles, pixel_num_h=dims[2], pixel_size_h=1, pixel_num_v=bmax - bmin, pixel_size_v=1, dist_source_center=None, dist_center_detector=None, channels=1) return AcquisitionData( data, False, geometry=geometry, dimension_labels=['angle', 'vertical', 'horizontal']) elif bmax - bmin == 1: geometry = AcquisitionGeometry('parallel', '2D', angles, pixel_num_h=dims[2], pixel_size_h=1, dist_source_center=None, dist_center_detector=None, channels=1) return AcquisitionData(data.squeeze(), False, geometry=geometry, dimension_labels=['angle', 'horizontal'])
def get_acquisition_data_subset(self, ymin=None, ymax=None): ''' This method load the acquisition data and given dimension and returns an AcquisitionData Object ''' if not h5pyAvailable: raise Exception("Error: h5py is not installed") if self.filename is None: return try: with NexusFile(self.filename, 'r') as file: try: dims = self.get_projection_dimensions() except KeyError: pass dims = file[self.data_path].shape if ymin is None and ymax is None: data = np.array(file[self.data_path]) else: if ymin is None: ymin = 0 if ymax > dims[1]: raise ValueError('ymax out of range') data = np.array(file[self.data_path][:, :ymax, :]) elif ymax is None: ymax = dims[1] if ymin < 0: raise ValueError('ymin out of range') data = np.array(file[self.data_path][:, ymin:, :]) else: if ymax > dims[1]: raise ValueError('ymax out of range') if ymin < 0: raise ValueError('ymin out of range') data = np.array(file[self.data_path][:, ymin:ymax, :]) except: print("Error reading nexus file") raise try: angles = self.get_projection_angles() except KeyError as ke: n = data.shape[0] angles = np.linspace(0, n, n + 1, dtype=np.float32) if ymax - ymin > 1: geometry = AcquisitionGeometry('parallel', '3D', angles, pixel_num_h=dims[2], pixel_size_h=1, pixel_num_v=ymax - ymin, pixel_size_v=1, dist_source_center=None, dist_center_detector=None, channels=1) return AcquisitionData( data, False, geometry=geometry, dimension_labels=['angle', 'vertical', 'horizontal']) elif ymax - ymin == 1: geometry = AcquisitionGeometry('parallel', '2D', angles, pixel_num_h=dims[2], pixel_size_h=1, dist_source_center=None, dist_center_detector=None, channels=1) return AcquisitionData(data.squeeze(), False, geometry=geometry, dimension_labels=['angle', 'horizontal'])
plt.show() ig = ImageGeometry(voxel_num_x = N, voxel_num_y = N, channels = np.shape(phantom_2Dt)[0]) data = ImageData(phantom_2Dt, geometry=ig) detectors = N angles = np.linspace(0,np.pi,180) ag = AcquisitionGeometry('parallel','2D', angles, detectors, channels = np.shape(phantom_2Dt)[0]) Aop = AstraProjectorMC(ig, ag, dev) sin = Aop.direct(data) scale = 2 n1 = scale * np.random.poisson(sin.as_array()/scale) noisy_data = AcquisitionData(n1, ag) # Regularisation Parameter alpha = 10 # Create operators #op1 = Gradient(ig) op1 = Gradient(ig, correlation='SpaceChannels') op2 = Aop # Create BlockOperator operator = BlockOperator(op1, op2, shape=(2,1) ) # Create functions f1 = alpha * MixedL21Norm()
ag = AcquisitionGeometry( 'cone', '3D', angles, pixel_num_h=num_pixels_h, pixel_size_h=0.25, pixel_num_v=num_pixels_v, pixel_size_v=0.25, dist_source_center=233.0, dist_center_detector=245.0, channels=num_channels, dimension_labels=['channel', 'vertical', 'angle', 'horizontal']) # AcquisitionData 3D + channels data = AcquisitionData( X, ag, dimension_labels=['channel', 'vertical', 'angle', 'horizontal']) # First need the geometric magnification to scale the voxel size relative # to the detector pixel size. # magnification factor = 250/1.76 # dist_source , dist center do not matter ig = ImageGeometry(voxel_num_x=ag.pixel_num_h, voxel_num_y=ag.pixel_num_h, voxel_num_z=ag.pixel_num_h, voxel_size_x=0.142, voxel_size_y=0.142, voxel_size_z=0.142, channels=num_channels) # Setup Astra Projector for 3DMC
# Set angles to use angles = numpy.linspace(-numpy.pi, numpy.pi, num_angles, endpoint=False) # Define full 3D acquisition geometry and data container. # Geometric info is taken from the txt-file in the same dir as the mat-file ag = AcquisitionGeometry('cone', '3D', angles, pixel_num_h=num_pixels_h, pixel_size_h=0.25, pixel_num_v=num_pixels_v, pixel_size_v=0.25, dist_source_center=233.0, dist_center_detector=245.0, channels=num_channels) data = AcquisitionData(X, geometry=ag) # Reduce to central slice by extracting relevant parameters from data and its # geometry. Perhaps create function to extract central slice automatically? data2d = data.subset(vertical=40) ag2d = AcquisitionGeometry('cone', '2D', ag.angles, pixel_num_h=ag.pixel_num_h, pixel_size_h=ag.pixel_size_h, pixel_num_v=1, pixel_size_v=ag.pixel_size_h, dist_source_center=ag.dist_source_center, dist_center_detector=ag.dist_center_detector, channels=ag.channels) data2d.geometry = ag2d
def process(self, out=None): projections = self.get_input() w = projections.get_dimension_size('horizontal') delta = w - 2 * self.center_of_rotation padded_width = int(numpy.ceil(abs(delta)) + w) delta_pix = padded_width - w voxel_per_pixel = 1 geom = pbalg.pb_setup_geometry_from_acquisition( projections.as_array(), self.acquisition_geometry.angles, self.center_of_rotation, voxel_per_pixel) padded_geometry = self.acquisition_geometry.clone() padded_geometry.pixel_num_h = geom['n_h'] padded_geometry.pixel_num_v = geom['n_v'] delta_pix_h = padded_geometry.pixel_num_h - self.acquisition_geometry.pixel_num_h delta_pix_v = padded_geometry.pixel_num_v - self.acquisition_geometry.pixel_num_v if delta_pix_h == 0: delta_pix_h = delta_pix padded_geometry.pixel_num_h = padded_width #initialize a new AcquisitionData with values close to 0 out = AcquisitionData(geometry=padded_geometry) out = out + self.pad_value #pad in the horizontal-vertical plane -> slice on angles if delta > 0: #pad left of middle command = "out.array[" for i in range(out.number_of_dimensions): if out.dimension_labels[i] == 'horizontal': value = '{0}:{1}'.format(delta_pix_h, delta_pix_h + w) command = command + str(value) else: if out.dimension_labels[i] == 'vertical': value = '{0}:'.format(delta_pix_v) command = command + str(value) else: command = command + ":" if i < out.number_of_dimensions - 1: command = command + ',' command = command + '] = projections.array' #print (command) else: #pad right of middle command = "out.array[" for i in range(out.number_of_dimensions): if out.dimension_labels[i] == 'horizontal': value = '{0}:{1}'.format(0, w) command = command + str(value) else: if out.dimension_labels[i] == 'vertical': value = '{0}:'.format(delta_pix_v) command = command + str(value) else: command = command + ":" if i < out.number_of_dimensions - 1: command = command + ',' command = command + '] = projections.array' #print (command) #cleaned = eval(command) exec(command) return out
if device == '1': dev = 'gpu' else: dev = 'cpu' Aop = AstraProjectorSimple(ig, ag, dev) sin = Aop.direct(data) # Create noisy data. Apply Gaussian noise noises = ['gaussian', 'poisson'] noise = noises[which_noise] if noise == 'poisson': scale = 5 eta = 0 noisy_data = AcquisitionData( np.random.poisson(scale * (eta + sin.as_array())) / scale, ag) elif noise == 'gaussian': n1 = np.random.normal(0, 1, size=ag.shape) noisy_data = AcquisitionData(n1 + sin.as_array(), ag) else: raise ValueError('Unsupported Noise ', noise) # Show Ground Truth and Noisy Data plt.figure(figsize=(10, 10)) plt.subplot(1, 2, 2) plt.imshow(data.as_array()) plt.title('Ground Truth') plt.colorbar() plt.subplot(1, 2, 1) plt.imshow(noisy_data.as_array()) plt.title('Noisy Data')
# Apply centering correction by zero padding, amount found manually cor_pad = 30 sino_pad = np.zeros((sino.shape[0],sino.shape[1]+cor_pad)) sino_pad[:,cor_pad:] = sino # Extract AcquisitionGeometry for central slice for 2D fanbeam reconstruction ag2d = AcquisitionGeometry('cone', '2D', angles=-np.pi/180*data.geometry.angles, pixel_num_h=data.geometry.pixel_num_h + cor_pad, pixel_size_h=data.geometry.pixel_size_h, dist_source_center=-data.geometry.dist_source_center, dist_center_detector=data.geometry.dist_center_detector) # Set up AcquisitionData object for central slice 2D fanbeam data2d = AcquisitionData(sino_pad,geometry=ag2d) # Choose the number of voxels to reconstruct onto as number of detector pixels N = data.geometry.pixel_num_h # Geometric magnification mag = (np.abs(data.geometry.dist_center_detector) + \ np.abs(data.geometry.dist_source_center)) / \ np.abs(data.geometry.dist_source_center) # Voxel size is detector pixel size divided by mag voxel_size_h = data.geometry.pixel_size_h / mag # Construct the appropriate ImageGeometry ig2d = ImageGeometry(voxel_num_x=N, voxel_num_y=N,
path = os.path.dirname(tomophantom.__file__) path_library2D = os.path.join(path, "Phantom2DLibrary.dat") phantom_2D = TomoP2D.Model(model, N, path_library2D) ig = ImageGeometry(voxel_num_x=N, voxel_num_y=N) data = ImageData(phantom_2D) detectors = N angles = np.linspace(0, np.pi, 128, dtype=np.float32) ag = AcquisitionGeometry('parallel', '2D', angles, detectors) Aop = AstraProjectorSimple(ig, ag, dev) sin = Aop.direct(data) #noisy_data = AcquisitionData( sin.as_array() + np.random.normal(0,1,ag.shape)) noisy_data = AcquisitionData(sin.as_array()) # Show Ground Truth and Noisy Data plt.figure(figsize=(10, 10)) plt.subplot(2, 1, 1) plt.imshow(data.as_array()) plt.title('Ground Truth') plt.colorbar() plt.subplot(2, 1, 2) plt.imshow(noisy_data.as_array()) plt.title('Noisy Data') plt.colorbar() plt.show() # Setup and run the CGLS algorithm alpha = 2
from ccpi.io.reader import XTEKReader import numpy as np import matplotlib.pyplot as plt from ccpi.framework import ImageGeometry, AcquisitionData, ImageData from ccpi.astra.ops import AstraProjector3DSimple from ccpi.optimisation.algs import CGLS import numpy # Set up reader object and read the data datareader = XTEKReader("REPLACE_THIS_BY_PATH_TO_DATASET/SophiaBeads_256_averaged.xtekct") data = datareader.get_acquisition_data() # Crop data and fix dimension labels data = AcquisitionData(data.array[:,:,901:1101], geometry=data.geometry, dimension_labels=['angle','horizontal','vertical']) data.geometry.pixel_num_v = 200 # Scale and negative-log transform data.array = -np.log(data.as_array()/60000.0) # Apply centering correction by zero padding, amount found manually cor_pad = 30 data_pad = np.zeros((data.shape[0],data.shape[1]+cor_pad,data.shape[2])) data_pad[:,cor_pad:,:] = data.array data.geometry.pixel_num_h = data.geometry.pixel_num_h + cor_pad data.array = data_pad # Choose the number of voxels to reconstruct onto as number of detector pixels N = data.geometry.pixel_num_h
angles = np.linspace(0, np.pi, 180, dtype=np.float32) ag = AcquisitionGeometry('parallel', '2D', angles, detectors) device = input('Available device: GPU==1 / CPU==0 ') if device == '1': dev = 'gpu' else: dev = 'cpu' Aop = AstraProjectorSimple(ig, ag, dev) sin = Aop.direct(data) np.random.seed(10) noisy_data = AcquisitionData(sin.as_array() + np.random.normal(0, 1, ag.shape)) # Show Ground Truth and Noisy Data plt.figure(figsize=(10, 10)) plt.subplot(2, 1, 1) plt.imshow(data.as_array()) plt.title('Ground Truth') plt.colorbar() plt.subplot(2, 1, 2) plt.imshow(noisy_data.as_array()) plt.title('Noisy Data') plt.colorbar() plt.show() # Setup and run the simple CGLS algorithm x_init = ig.allocate()
def load_data(self): ''' Parse NEXUS file and returns either ImageData or Acquisition Data depending on file content ''' try: with h5py.File(self.nexus_file, 'r') as file: if np.string_(file.attrs['creator']) != np.string_( 'NEXUSDataWriter.py'): raise Exception( 'We can parse only files created by NEXUSDataWriter.py' ) ds_data = file['entry1/tomo_entry/data/data'] data = np.array(ds_data, dtype='float32') dimension_labels = [] for i in range(data.ndim): dimension_labels.append(ds_data.attrs['dim{}'.format(i)]) if ds_data.attrs['data_type'] == 'ImageData': self._geometry = ImageGeometry( voxel_num_x=ds_data.attrs['voxel_num_x'], voxel_num_y=ds_data.attrs['voxel_num_y'], voxel_num_z=ds_data.attrs['voxel_num_z'], voxel_size_x=ds_data.attrs['voxel_size_x'], voxel_size_y=ds_data.attrs['voxel_size_y'], voxel_size_z=ds_data.attrs['voxel_size_z'], center_x=ds_data.attrs['center_x'], center_y=ds_data.attrs['center_y'], center_z=ds_data.attrs['center_z'], channels=ds_data.attrs['channels']) return ImageData(array=data, deep_copy=False, geometry=self._geometry, dimension_labels=dimension_labels) else: # AcquisitionData if ds_data.attrs.__contains__('dist_source_center'): dist_source_center = ds_data.attrs[ 'dist_source_center'] else: dist_source_center = None if ds_data.attrs.__contains__('dist_center_detector'): dist_center_detector = ds_data.attrs[ 'dist_center_detector'] else: dist_center_detector = None self._geometry = AcquisitionGeometry( geom_type=ds_data.attrs['geom_type'], dimension=ds_data.attrs['dimension'], dist_source_center=dist_source_center, dist_center_detector=dist_center_detector, pixel_num_h=ds_data.attrs['pixel_num_h'], pixel_size_h=ds_data.attrs['pixel_size_h'], pixel_num_v=ds_data.attrs['pixel_num_v'], pixel_size_v=ds_data.attrs['pixel_size_v'], channels=ds_data.attrs['channels'], angles=np.array( file['entry1/tomo_entry/data/rotation_angle'], dtype='float32')) #angle_unit = file['entry1/tomo_entry/data/rotation_angle'].attrs['units']) return AcquisitionData(array=data, deep_copy=False, geometry=self._geometry, dimension_labels=dimension_labels) except: print("Error reading nexus file") raise
plt.imshow(b.array) plt.title('Simulated data') plt.colorbar() plt.show() plt.imshow(z.array) plt.title('Backprojected data') plt.colorbar() plt.show() One = ImageData(geometry=ig) xOne = One.as_array() xOne[:,:] = 1.0 OneD = AcquisitionData(geometry=ag) y1 = OneD.as_array() y1[:,:] = 1.0 s1 = (OneD*(Aop.direct(One))).sum() s2 = (One*(Aop.adjoint(OneD))).sum() print(s1) print(s2) print(s2/s1) print((b*b).sum()) print((z*Phantom).sum()) print((z*Phantom).sum() / (b*b).sum()) #print(N/det_num) #print(0.5*det_w/dx)
def SIRT(x_init, operator, data, opt=None, constraint=None): '''Simultaneous Iterative Reconstruction Technique Parameters: x_init: initial guess operator: operator for forward/backward projections data: data to operate on opt: additional algorithm constraint: func of Indicator type specifying convex constraint. ''' if opt is None: opt = {'tol': 1e-4, 'iter': 1000} else: try: max_iter = opt['iter'] except KeyError as ke: opt[ke] = 1000 try: opt['tol'] = 1000 except KeyError as ke: opt[ke] = 1e-4 tol = opt['tol'] max_iter = opt['iter'] # Set default constraint to unconstrained if constraint == None: constraint = Function() x = x_init.clone() timing = numpy.zeros(max_iter) criter = numpy.zeros(max_iter) # Relaxation parameter must be strictly between 0 and 2. For now fix at 1.0 relax_par = 1.0 # Set up scaling matrices D and M. im1 = ImageData(geometry=x_init.geometry) im1.array[:] = 1.0 M = 1 / operator.direct(im1) del im1 aq1 = AcquisitionData(geometry=M.geometry) aq1.array[:] = 1.0 D = 1 / operator.adjoint(aq1) del aq1 # algorithm loop for it in range(0, max_iter): t = time.time() r = data - operator.direct(x) x = constraint.prox(x + relax_par * (D * operator.adjoint(M * r)), None) timing[it] = time.time() - t if it > 0: criter[it - 1] = (r**2).sum() r = data - operator.direct(x) criter[it] = (r**2).sum() return x, it, timing, criter
OrigDetec = 0 angles = np.linspace(0, 2 * np.pi, angles_num) ag = AcquisitionGeometry('cone', '2D', angles, detectors, det_w, dist_source_center=SourceOrig, dist_center_detector=OrigDetec) else: NotImplemented Aop = AstraProjectorSimple(ig, ag, dev) sin = Aop.direct(data) eta = 0 noisy_data = AcquisitionData(sin.as_array() + np.random.normal(0, 1, ag.shape)) back_proj = Aop.adjoint(noisy_data) # Define Least Squares f = FunctionOperatorComposition(L2NormSquared(b=noisy_data), Aop) # Allocate solution x_init = ig.allocate() # Run FISTA for least squares fista = FISTA(x_init=x_init, f=f, g=ZeroFunction()) fista.max_iteration = 10 fista.update_objective_interval = 2 fista.run(100, verbose=True) # Run FISTA for least squares with lower/upper bound
data_rel = -numpy.log(data) # Permute order to get: angles, vertical, horizontal, as default in framework. data_rel = numpy.transpose(data_rel,(0,2,1)) # Set angles to use angles = numpy.linspace(-numpy.pi,numpy.pi,num_angles,endpoint=False) # Create 3D acquisition geometry and acquisition data ag = AcquisitionGeometry('parallel', '3D', angles, pixel_num_h=imsize, pixel_num_v=imsize) b = AcquisitionData(data_rel, geometry=ag) # Reduce to single (noncentral) slice by extracting relevant parameters from data and its # geometry. Perhaps create function to extract central slice automatically? b2d = b.subset(vertical=128) ag2d = AcquisitionGeometry('parallel', '2D', ag.angles, pixel_num_h=ag.pixel_num_h) b2d.geometry = ag2d # Create 2D image geometry ig2d = ImageGeometry(voxel_num_x=ag2d.pixel_num_h, voxel_num_y=ag2d.pixel_num_h) # Create GPU projector/backprojector operator with ASTRA.
ig = data.geometry detectors = N angles = np.linspace(0, np.pi, N, dtype=np.float32) ag = AcquisitionGeometry('parallel', '2D', angles, detectors) device = input('Available device: GPU==1 / CPU==0 ') if device == '1': dev = 'gpu' else: dev = 'cpu' Aop = AstraProjectorSimple(ig, ag, dev) sin = Aop.direct(data) noisy_data = AcquisitionData(sin.as_array() + np.random.normal(0, 3, ig.shape)) # Setup and run the CGLS algorithm alpha = 50 Grad = Gradient(ig) # Form Tikhonov as a Block CGLS structure op_CGLS = BlockOperator(Aop, alpha * Grad, shape=(2, 1)) block_data = BlockDataContainer(noisy_data, Grad.range_geometry().allocate()) x_init = ig.allocate() cgls = CGLS(x_init=x_init, operator=op_CGLS, data=block_data) cgls.max_iteration = 1000 cgls.update_objective_interval = 200 cgls.run(1000, verbose=False)
# Create Acquisition data detectors = N angles = np.linspace(0, np.pi, 180, dtype=np.float32) ag = AcquisitionGeometry('parallel', '2D', angles, detectors) device = input('Available device: GPU==1 / CPU==0 ') if device == '1': dev = 'gpu' else: dev = 'cpu' Aop = AstraProjectorSimple(ig, ag, dev) sin = Aop.direct(data) projection_data = AcquisitionData(sin.as_array()) # Show Ground Truth and Noisy Data plt.figure(figsize=(10, 10)) plt.subplot(2, 1, 1) plt.imshow(data.as_array()) plt.title('Ground Truth') plt.colorbar() plt.subplot(2, 1, 2) plt.imshow(projection_data.as_array()) plt.title('Projection Data') plt.colorbar() plt.show() # Setup and run the CGLS algorithm x_init = ig.allocate()