def test_AcquisitionDataSubset(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) # expected dimension_labels self.assertListEqual([AcquisitionGeometry.CHANNEL , AcquisitionGeometry.ANGLE , AcquisitionGeometry.VERTICAL , AcquisitionGeometry.HORIZONTAL], sgeometry.dimension_labels) sino = sgeometry.allocate() # test reshape new_order = [AcquisitionGeometry.HORIZONTAL , AcquisitionGeometry.CHANNEL , AcquisitionGeometry.VERTICAL , AcquisitionGeometry.ANGLE] ss = sino.subset(new_order) self.assertListEqual(new_order, ss.geometry.dimension_labels) ss1 = ss.subset(vertical = 0) self.assertListEqual([AcquisitionGeometry.HORIZONTAL , AcquisitionGeometry.CHANNEL , AcquisitionGeometry.ANGLE], ss1.geometry.dimension_labels) ss2 = ss.subset(vertical = 0, channel=0) self.assertListEqual([AcquisitionGeometry.HORIZONTAL , AcquisitionGeometry.ANGLE], ss2.geometry.dimension_labels)
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])
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) sino = sgeometry.allocate() self.assertEqual(sino.shape, (2, 10, 3, 5)) ag = AcquisitionGeometry (pixel_num_h=2,pixel_num_v=3,channels=4, dimension=2, angles=numpy.linspace(0, 180, num=10), geom_type='parallel', ) print (ag.shape) print (ag.dimension_labels) data = ag.allocate() self.assertNumpyArrayEqual(numpy.asarray(data.shape), numpy.asarray(ag.shape)) self.assertNumpyArrayEqual(numpy.asarray(data.shape), data.as_array().shape) print (data.shape, ag.shape, data.as_array().shape) ag2 = AcquisitionGeometry (pixel_num_h=2,pixel_num_v=3,channels=4, dimension=2, angles=numpy.linspace(0, 180, num=10), geom_type='parallel', dimension_labels=[AcquisitionGeometry.VERTICAL , AcquisitionGeometry.ANGLE, AcquisitionGeometry.HORIZONTAL, AcquisitionGeometry.CHANNEL]) data = ag2.allocate() print (data.shape, ag2.shape, data.as_array().shape) self.assertNumpyArrayEqual(numpy.asarray(data.shape), numpy.asarray(ag2.shape)) self.assertNumpyArrayEqual(numpy.asarray(data.shape), data.as_array().shape)
def setUp(self): self.ig = ImageGeometry(1, 2, 3, channels=4) angles = numpy.asarray([90., 0., -90.], dtype=numpy.float32) self.ag = AcquisitionGeometry('cone', 'edo', pixel_num_h=20, pixel_num_v=2, angles=angles, dist_source_center=312.2, dist_center_detector=123., channels=4)
def __init__(self, geomv, geomp, default=False): super(CCPiProjectorSimple, self).__init__() # Store volume and sinogram geometries. self.acquisition_geometry = geomp self.volume_geometry = geomv if geomp.geom_type == "cone": raise TypeError('Can only handle parallel beam') # set-up the geometries if compatible geoms = setupCCPiGeometries(geomv, geomp, 0) vg = ImageGeometry(voxel_num_x=geoms['output_volume_x'], voxel_num_y=geoms['output_volume_y'], voxel_num_z=geoms['output_volume_z']) pg = AcquisitionGeometry('parallel', '3D', geomp.angles, geoms['n_h'], geomp.pixel_size_h, geoms['n_v'], geomp.pixel_size_v #2D in 3D is a slice 1 pixel thick ) if not default: # check if geometry is the same (on the voxels) if not ( vg.voxel_num_x == geomv.voxel_num_x and \ vg.voxel_num_y == geomv.voxel_num_y and \ vg.voxel_num_z == geomv.voxel_num_z ): msg = 'The required volume geometry will not work\nThe following would\n' msg += vg.__str__() raise ValueError(msg) if not (pg.pixel_num_h == geomp.pixel_num_h and \ pg.pixel_num_v == geomp.pixel_num_v and \ len( pg.angles ) == len( geomp.angles ) ) : msg = 'The required acquisition geometry will not work\nThe following would\n' msg += pg.__str__() raise ValueError(msg) self.fp = CCPiForwardProjector(image_geometry=vg, acquisition_geometry=pg, output_axes_order=['angle','vertical','horizontal']) self.bp = CCPiBackwardProjector(image_geometry=vg, acquisition_geometry=pg, output_axes_order=[ ImageGeometry.HORIZONTAL_X, ImageGeometry.HORIZONTAL_Y, ImageGeometry.VERTICAL]) # Initialise empty for singular value. self.s1 = None self.ag = pg self.vg = vg
def setupCCPiGeometries(ig, ag, counter): Phantom_ccpi = ig.allocate(dimension_labels=[ ImageGeometry.HORIZONTAL_X, ImageGeometry.HORIZONTAL_Y, ImageGeometry.VERTICAL ]) voxel_per_pixel = 1 angles = ag.angles 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']) ad = pg.allocate(dimension_labels=[ AcquisitionGeometry.ANGLE, AcquisitionGeometry.VERTICAL, AcquisitionGeometry.HORIZONTAL ]) geoms_i = pbalg.pb_setup_geometry_from_acquisition(ad.as_array(), angles, center_of_rotation, voxel_per_pixel) counter += 1 if counter < 4: print(geoms, geoms_i) if (not (geoms_i == geoms)): print("not equal and {} {} {}".format(counter, geoms['output_volume_z'], geoms_i['output_volume_z'])) 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: print("happy now {} {} {}".format(counter, geoms['output_volume_z'], geoms_i['output_volume_z'])) return geoms else: return geoms_i
def load(self): pixel_num_h = 0 pixel_num_v = 0 xpixel_size = 0 ypixel_size = 0 source_x = 0 detector_x = 0 with open(self.filename) as f: content = f.readlines() content = [x.strip() for x in content] for line in content: if line.startswith("SrcToObject"): source_x = float(line.split('=')[1]) elif line.startswith("SrcToDetector"): detector_x = float(line.split('=')[1]) elif line.startswith("DetectorPixelsY"): pixel_num_v = int(line.split('=')[1]) #self.num_of_vertical_pixels = self.calc_v_alighment(self.num_of_vertical_pixels, self.pixels_per_voxel) elif line.startswith("DetectorPixelsX"): pixel_num_h = int(line.split('=')[1]) elif line.startswith("DetectorPixelSizeX"): xpixel_size = float(line.split('=')[1]) elif line.startswith("DetectorPixelSizeY"): ypixel_size = float(line.split('=')[1]) elif line.startswith("Projections"): self.num_projections = int(line.split('=')[1]) elif line.startswith("InitialAngle"): self.initial_angle = float(line.split('=')[1]) elif line.startswith("Name"): self.experiment_name = line.split('=')[1] elif line.startswith("Scattering"): self.scattering = float(line.split('=')[1]) elif line.startswith("WhiteLevel"): self.white_level = float(line.split('=')[1]) elif line.startswith("MaskRadius"): self.mask_radius = float(line.split('=')[1]) #Read Angles angles = self.read_angles() self.geometry = AcquisitionGeometry( 'cone', '3D', angles, pixel_num_h, xpixel_size, pixel_num_v, ypixel_size, -1 * source_x, detector_x - source_x, )
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 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, dimension_labels=['angle', 'vertical', 'horizontal']) out = geometry.allocate() out.fill(data) return out
def range_geometry(self): return AcquisitionGeometry(self.ag.geom_type, self.ag.dimension, self.ag.angles, self.ag.pixel_num_h, self.ag.pixel_size_h, self.ag.pixel_num_v, self.ag.pixel_size_v, self.ag.dist_source_center, self.ag.dist_center_detector, self.ag.channels, )
def testwriteAcquisitionData(self): im_size = 5 ag2d = AcquisitionGeometry(geom_type = 'parallel', dimension = '2D', angles = numpy.array([0, 1]), pixel_num_h = im_size, pixel_size_h = 1, pixel_num_v = im_size, pixel_size_v = 1) ad2d = ag2d.allocate() writer = NEXUSDataWriter() writer.set_up(file_name = os.path.join(os.getcwd(), 'test_nexus_ad2d.nxs'), data_container = ad2d) writer.write_file() ag3d = AcquisitionGeometry(geom_type = 'cone', dimension = '3D', angles = numpy.array([0, 1]), pixel_num_h = im_size, pixel_size_h = 1, pixel_num_v = im_size, pixel_size_v = 1, dist_source_center = 1, dist_center_detector = 1, channels = im_size) ad3d = ag3d.allocate() writer = NEXUSDataWriter() writer.set_up(file_name = os.path.join(os.getcwd(), 'test_nexus_ad3d.nxs'), data_container = ad3d) writer.write_file() self.stestreadAcquisitionData()
def stestreadAcquisitionData(self): im_size = 5 ag2d_test = AcquisitionGeometry(geom_type = 'parallel', dimension = '2D', angles = numpy.array([0, 1]), pixel_num_h = im_size, pixel_size_h = 1, pixel_num_v = im_size, pixel_size_v = 1) ad2d_test = ag2d_test.allocate() reader2d = NEXUSDataReader() reader2d.set_up(nexus_file = os.path.join(os.getcwd(), 'test_nexus_ad2d.nxs')) ad2d = reader2d.load_data() ag2d = reader2d.get_geometry() numpy.testing.assert_array_equal(ad2d.as_array(), ad2d_test.as_array(), 'Loaded image is not correct') self.assertEqual(ag2d.geom_type, ag2d_test.geom_type, 'ImageGeometry.geom_type is not correct') numpy.testing.assert_array_equal(ag2d.angles, ag2d_test.angles, 'ImageGeometry.angles is not correct') self.assertEqual(ag2d.pixel_num_h, ag2d_test.pixel_num_h, 'ImageGeometry.pixel_num_h is not correct') self.assertEqual(ag2d.pixel_size_h, ag2d_test.pixel_size_h, 'ImageGeometry.pixel_size_h is not correct') self.assertEqual(ag2d.pixel_num_v, ag2d_test.pixel_num_v, 'ImageGeometry.pixel_num_v is not correct') self.assertEqual(ag2d.pixel_size_v, ag2d_test.pixel_size_v, 'ImageGeometry.pixel_size_v is not correct') ag3d_test = AcquisitionGeometry(geom_type = 'cone', dimension = '3D', angles = numpy.array([0, 1]), pixel_num_h = im_size, pixel_size_h = 1, pixel_num_v = im_size, pixel_size_v = 1, dist_source_center = 1, dist_center_detector = 1, channels = im_size) ad3d_test = ag3d_test.allocate() reader3d = NEXUSDataReader() reader3d.set_up(nexus_file = os.path.join(os.getcwd(), 'test_nexus_ad3d.nxs')) ad3d = reader3d.load_data() ag3d = reader3d.get_geometry() numpy.testing.assert_array_equal(ad3d.as_array(), ad3d_test.as_array(), 'Loaded image is not correct') numpy.testing.assert_array_equal(ag3d.angles, ag3d_test.angles, 'AcquisitionGeometry.angles is not correct') self.assertEqual(ag3d.geom_type, ag3d_test.geom_type, 'AcquisitionGeometry.geom_type is not correct') self.assertEqual(ag3d.dimension, ag3d_test.dimension, 'AcquisitionGeometry.dimension is not correct') self.assertEqual(ag3d.pixel_num_h, ag3d_test.pixel_num_h, 'AcquisitionGeometry.pixel_num_h is not correct') self.assertEqual(ag3d.pixel_size_h, ag3d_test.pixel_size_h, 'AcquisitionGeometry.pixel_size_h is not correct') self.assertEqual(ag3d.pixel_num_v, ag3d_test.pixel_num_v, 'AcquisitionGeometry.pixel_num_v is not correct') self.assertEqual(ag3d.pixel_size_v, ag3d_test.pixel_size_v, 'AcquisitionGeometry.pixel_size_v is not correct') self.assertEqual(ag3d.dist_source_center, ag3d_test.dist_source_center, 'AcquisitionGeometry.dist_source_center is not correct') self.assertEqual(ag3d.dist_center_detector, ag3d_test.dist_center_detector, 'AcquisitionGeometry.dist_center_detector is not correct') self.assertEqual(ag3d.channels, ag3d_test.channels, 'AcquisitionGeometry.channels is not correct') def tearDown(self): os.remove(os.path.join(os.getcwd(), 'test_nexus_im.nxs')) os.remove(os.path.join(os.getcwd(), 'test_nexus_ad2d.nxs')) os.remove(os.path.join(os.getcwd(), 'test_nexus_ad3d.nxs'))
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
return self.volume_geometry def range_geometry(self): return self.sinogram_geometry def norm(self): x0 = self.volume_geometry.allocate('random') self.s1, sall, svec = LinearOperator.PowerMethod(self, 50, x0) return self.s1 if __name__ == '__main__': N = 30 angles = np.linspace(0, np.pi, 180) ig = ImageGeometry(N, N, N) ag = AcquisitionGeometry('parallel', '3D', angles, pixel_num_h=N, pixel_num_v=5) A = AstraProjector3DSimple(ig, ag) print(A.norm()) x = ig.allocate('random_int') sin = A.direct(x) y = ag.allocate('random_int') im = A.adjoint(y)
def set_up(self, xtek_file=None, roi=-1, binning=[1, 1], normalize=False, flip=False): self.xtek_file = xtek_file self.roi = roi self.binning = binning self.normalize = normalize self.flip = flip if self.xtek_file == None: raise Exception('Path to xtek file is required.') # check if xtek file exists if not (os.path.isfile(self.xtek_file)): raise Exception('File\n {}\n does not exist.'.format( self.xtek_file)) # check that PIL library is installed if (pilAvailable == False): raise Exception( "PIL (pillow) is not available, cannot load TIFF files.") # parse xtek file with open(self.xtek_file, 'r') as f: content = f.readlines() content = [x.strip() for x in content] for line in content: # filename of TIFF files if line.startswith("Name"): self._experiment_name = line.split('=')[1] # number of projections elif line.startswith("Projections"): num_projections = int(line.split('=')[1]) # white level - used for normalization elif line.startswith("WhiteLevel"): self._white_level = float(line.split('=')[1]) # number of pixels along Y axis elif line.startswith("DetectorPixelsY"): pixel_num_v_0 = int(line.split('=')[1]) # number of pixels along X axis elif line.startswith("DetectorPixelsX"): pixel_num_h_0 = int(line.split('=')[1]) # pixel size along X axis elif line.startswith("DetectorPixelSizeX"): pixel_size_h_0 = float(line.split('=')[1]) # pixel size along Y axis elif line.startswith("DetectorPixelSizeY"): pixel_size_v_0 = float(line.split('=')[1]) # source to center of rotation distance elif line.startswith("SrcToObject"): source_x = float(line.split('=')[1]) # source to detector distance elif line.startswith("SrcToDetector"): detector_x = float(line.split('=')[1]) # initial angular position of a rotation stage elif line.startswith("InitialAngle"): initial_angle = float(line.split('=')[1]) # angular increment (in degrees) elif line.startswith("AngularStep"): angular_step = float(line.split('=')[1]) if self.roi == -1: self._roi_par = [(0, pixel_num_v_0), \ (0, pixel_num_h_0)] else: self._roi_par = self.roi.copy() if self._roi_par[0] == -1: self._roi_par[0] = (0, pixel_num_v_0) if self._roi_par[1] == -1: self._roi_par[1] = (0, pixel_num_h_0) # calculate number of pixels and pixel size if (self.binning == [1, 1]): pixel_num_v = self._roi_par[0][1] - self._roi_par[0][0] pixel_num_h = self._roi_par[1][1] - self._roi_par[1][0] pixel_size_v = pixel_size_v_0 pixel_size_h = pixel_size_h_0 else: pixel_num_v = (self._roi_par[0][1] - self._roi_par[0][0]) // self.binning[0] pixel_num_h = (self._roi_par[1][1] - self._roi_par[1][0]) // self.binning[1] pixel_size_v = pixel_size_v_0 * self.binning[0] pixel_size_h = pixel_size_h_0 * self.binning[1] ''' Parse the angles file .ang or _ctdata.txt file and returns the angles as an numpy array. ''' input_path = os.path.dirname(self.xtek_file) angles_ctdata_file = os.path.join(input_path, '_ctdata.txt') angles_named_file = os.path.join(input_path, self._experiment_name + '.ang') angles = numpy.zeros(num_projections, dtype='float') # look for _ctdata.txt if os.path.exists(angles_ctdata_file): # read txt file with angles with open(angles_ctdata_file) as f: content = f.readlines() # skip firt three lines # read the middle value of 3 values in each line as angles in degrees index = 0 for line in content[3:]: angles[index] = float(line.split(' ')[1]) index += 1 angles = angles + initial_angle # look for ang file elif os.path.exists(angles_named_file): # read the angles file which is text with first line as header with open(angles_named_file) as f: content = f.readlines() # skip first line index = 0 for line in content[1:]: angles[index] = float(line.split(':')[1]) index += 1 angles = numpy.flipud( angles + initial_angle) # angles are in the reverse order else: # calculate angles based on xtek file angles = initial_angle + angular_step * range(num_projections) # fill in metadata self._ag = AcquisitionGeometry(geom_type='cone', dimension='3D', angles=angles, pixel_num_h=pixel_num_h, pixel_size_h=pixel_size_h, pixel_num_v=pixel_num_v, pixel_size_v=pixel_size_v, dist_source_center=source_x, dist_center_detector=detector_x - source_x, channels=1, angle_unit='degree')
igtmp.shape = self.volume_geometry.shape[1:] igtmp.dimension_labels = ['horizontal_y', 'horizontal_x'] igtmp.channels = 1 agtmp = self.sinogram_geometry.clone() agtmp.shape = self.sinogram_geometry.shape[1:] agtmp.dimension_labels = ['angle', 'horizontal'] agtmp.channels = 1 Atmp = AstraProjectorSimple(igtmp, agtmp, device=self.device) return Atmp.norm() if __name__ == '__main__': from ccpi.framework import ImageGeometry, AcquisitionGeometry import numpy as np N = 30 angles = np.linspace(0, np.pi, 180) ig = ImageGeometry(N, N, channels=5) ag = AcquisitionGeometry('parallel', '2D', angles, pixel_num_h=N, channels=5) A = AstraProjectorMC(ig, ag, 'gpu') print(A.norm())
# set to 0 to simulate a "virtual detector" with same detector pixel size as # object pixel size). angles_num = 40 det_num = 400 SourceOrig = 20 OrigDetec = 100 geo_mag = (SourceOrig+OrigDetec)/SourceOrig det_w = geo_mag*dx*1 if test_case==1: angles = np.linspace(0,np.pi,angles_num,endpoint=False) ag = AcquisitionGeometry('parallel', '2D', angles, det_num,det_w) elif test_case==2: angles = np.linspace(0,2*np.pi,angles_num,endpoint=False) ag = AcquisitionGeometry('cone', '2D', angles, det_num, det_w, dist_source_center=SourceOrig, dist_center_detector=OrigDetec) else: NotImplemented # Set up Operator object combining the ImageGeometry and AcquisitionGeometry # wrapping calls to ASTRA as well as specifying whether to use CPU or GPU.
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
fig = plt.figure() ims1 = [] for sl in range(0,np.shape(phantom_2Dt)[0]): im1 = plt.imshow(phantom_2Dt[sl,:,:], animated=True, vmin=0, vmax=1) ims1.append([im1]) ani1 = animation.ArtistAnimation(fig, ims1, interval=500,repeat_delay=10) 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
class XTEKReader(object): ''' Reader class for loading XTEK files ''' def __init__(self, xtek_config_filename=None): ''' This takes in the xtek config filename and loads the dataset and the required geometry parameters ''' self.projections = None self.geometry = {} self.filename = xtek_config_filename self.load() def load(self): pixel_num_h = 0 pixel_num_v = 0 xpixel_size = 0 ypixel_size = 0 source_x = 0 detector_x = 0 with open(self.filename) as f: content = f.readlines() content = [x.strip() for x in content] for line in content: if line.startswith("SrcToObject"): source_x = float(line.split('=')[1]) elif line.startswith("SrcToDetector"): detector_x = float(line.split('=')[1]) elif line.startswith("DetectorPixelsY"): pixel_num_v = int(line.split('=')[1]) #self.num_of_vertical_pixels = self.calc_v_alighment(self.num_of_vertical_pixels, self.pixels_per_voxel) elif line.startswith("DetectorPixelsX"): pixel_num_h = int(line.split('=')[1]) elif line.startswith("DetectorPixelSizeX"): xpixel_size = float(line.split('=')[1]) elif line.startswith("DetectorPixelSizeY"): ypixel_size = float(line.split('=')[1]) elif line.startswith("Projections"): self.num_projections = int(line.split('=')[1]) elif line.startswith("InitialAngle"): self.initial_angle = float(line.split('=')[1]) elif line.startswith("Name"): self.experiment_name = line.split('=')[1] elif line.startswith("Scattering"): self.scattering = float(line.split('=')[1]) elif line.startswith("WhiteLevel"): self.white_level = float(line.split('=')[1]) elif line.startswith("MaskRadius"): self.mask_radius = float(line.split('=')[1]) #Read Angles angles = self.read_angles() self.geometry = AcquisitionGeometry( 'cone', '3D', angles, pixel_num_h, xpixel_size, pixel_num_v, ypixel_size, -1 * source_x, detector_x - source_x, ) def read_angles(self): """ Read the angles file .ang or _ctdata.txt file and returns the angles as an numpy array. """ input_path = os.path.dirname(self.filename) angles_ctdata_file = os.path.join(input_path, '_ctdata.txt') angles_named_file = os.path.join(input_path, self.experiment_name + '.ang') angles = np.zeros(self.num_projections, dtype='f') #look for _ctdata.txt if os.path.exists(angles_ctdata_file): #read txt file with angles with open(angles_ctdata_file) as f: content = f.readlines() #skip firt three lines #read the middle value of 3 values in each line as angles in degrees index = 0 for line in content[3:]: self.angles[index] = float(line.split(' ')[1]) index += 1 angles = np.deg2rad(self.angles + self.initial_angle) elif os.path.exists(angles_named_file): #read the angles file which is text with first line as header with open(angles_named_file) as f: content = f.readlines() #skip first line index = 0 for line in content[1:]: angles[index] = float(line.split(':')[1]) index += 1 angles = np.flipud( angles + self.initial_angle) #angles are in the reverse order else: raise RuntimeError("Can't find angles file") return angles def load_projection(self, dimensions=None): ''' This method reads the projection images from the directory and returns a numpy array ''' if not pilAvailable: raise ImportError('Image library pillow is not installed') if dimensions != None: raise NotImplementedError( 'Extracting subset of data is not implemented') input_path = os.path.dirname(self.filename) pixels = np.zeros((self.num_projections, self.geometry.pixel_num_h, self.geometry.pixel_num_v), dtype='float32') for i in range(1, self.num_projections + 1): im = Image.open( os.path.join(input_path, self.experiment_name + "_%04d" % i + ".tif")) pixels[i - 1, :, :] = np.fliplr(np.transpose(np.array( im))) ##Not sure this is the correct way to populate the image #normalising the data #TODO: Move this to a processor pixels = pixels - (self.white_level * self.scattering) / 100.0 pixels[ pixels < 0.0] = 0.000001 # all negative values to approximately 0 as the std log of zero and non negative number is not defined return pixels 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) out = self.geometry.allocate() out.fill(data) return out
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: try: image_keys = self.get_image_keys() print("image_keys", image_keys) projections = np.array(file[self.data_path]) data = projections[image_keys == 0] except KeyError as ke: print(ke) data = np.array(file[self.data_path]) else: image_keys = self.get_image_keys() print("image_keys", image_keys) projections = np.array( file[self.data_path])[image_keys == 0] if ymin is None: ymin = 0 if ymax > dims[1]: raise ValueError('ymax out of range') data = projections[:, :ymax, :] elif ymax is None: ymax = dims[1] if ymin < 0: raise ValueError('ymin out of range') data = projections[:, ymin:, :] else: if ymax > dims[1]: raise ValueError('ymax out of range') if ymin < 0: raise ValueError('ymin out of range') data = projections[:, 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, dimension_labels=['angle', 'vertical', 'horizontal']) out = geometry.allocate() out.fill(data) return out 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, dimension_labels=['angle', 'horizontal']) out = geometry.allocate() out.fill(data.squeeze()) return out
def calculate_norm(self): return self.A3D.norm() if __name__ == '__main__': from ccpi.framework import ImageGeometry, AcquisitionGeometry N = 30 channels = 5 angles = np.linspace(0, np.pi, 180) ig = ImageGeometry(N, N, N, channels=channels) ag = AcquisitionGeometry('parallel', '3D', angles, pixel_num_h=N, pixel_num_v=5, channels=channels) A3DMC = AstraProjector3DMC(ig, ag) z = A3DMC.norm() # igtmp3D = A3DMC.volume_geometry.clone() # igtmp3D.channels = 1 # igtmp3D.shape = A3DMC.volume_geometry.shape[1:] # igtmp3D.dimension_labels = ['vertical', 'horizontal_y', 'horizontal_x'] # # agtmp3D = A3DMC.sinogram_geometry.clone() # agtmp3D.channels = 1 # agtmp3D.shape = A3DMC.sinogram_geometry.shape[1:] # agtmp3D.dimension_labels = ['vertical', 'angle', 'horizontal']
def __init__(self, volume_geometry, sinogram_geometry, device='cpu', filter_type='ram-lak', **kwargs): if sinogram_geometry.dimension == '3D': # For 3D FBP and parallel goemetry, we perform 2D FBP per slice # Therofore, we need vol_geom2D, porj_geom2D attributes to setup in the DataProcessor. # There are both CPU/GPU options for this case if sinogram_geometry.geom_type == 'parallel': # By default, we select GPU device super(FBP, self).__init__(volume_geometry=volume_geometry, sinogram_geometry=sinogram_geometry, device='gpu', proj_id=None, vol_geom2D=None, proj_geom2D=None, filter_type=filter_type) # we need a 2D image and acquisition geometry ig2D = ImageGeometry( voxel_num_x=self.volume_geometry.voxel_num_x, voxel_num_y=self.volume_geometry.voxel_num_y, voxel_size_x=self.volume_geometry.voxel_size_x, voxel_size_y=self.volume_geometry.voxel_size_y) ag2D = AcquisitionGeometry( geom_type=self.sinogram_geometry.geom_type, dimension='2D', angles=self.sinogram_geometry.angles, pixel_num_h=self.sinogram_geometry.pixel_num_h, pixel_size_h=self.sinogram_geometry.pixel_size_h) # Convert to Astra Geometries self.vol_geom2D, self.proj_geom2D = convert_geometry_to_astra( ig2D, ag2D) if self.device == 'gpu': self.set_projector( astra.create_projector('cuda', self.proj_geom2D, self.vol_geom2D)) else: self.set_projector( astra.create_projector('line', self.proj_geom2D, self.vol_geom2D)) elif sinogram_geometry.geom_type == 'cone': # For 3D cone we do not need ASTRA proj_id super(FBP, self).__init__(volume_geometry=volume_geometry, sinogram_geometry=sinogram_geometry, device='gpu', filter_type='ram-lak') #Raise an error if the user select a filter other than ram-lak if self.filter_type != 'ram-lak': raise NotImplementedError( 'Currently in astra, FDK has only ram-lak available') else: # Setup for 2D case super(FBP, self).__init__(volume_geometry=volume_geometry, sinogram_geometry=sinogram_geometry, device=device, proj_id=None, filter_type=filter_type) # Raise an error if the user select a filter other than ram-lak, for 2D case if self.filter_type != 'ram-lak' and self.device == 'cpu': raise NotImplementedError( 'Currently in astra, 2D FBP is using only the ram-lak filter, switch to gpu for other filters' ) if (self.sinogram_geometry.geom_type == 'cone' and self.device == 'gpu') and self.sinogram_geometry.channels >= 1: warnings.warn( "For FanFlat geometry there is a mismatch between CPU & GPU filtered back projection. Currently, only CPU case provides a reasonable result." ) self.set_ImageGeometry(volume_geometry) self.set_AcquisitionGeometry(sinogram_geometry) # Set up ASTRA Volume and projection geometry, not to be stored in self vol_geom, proj_geom = convert_geometry_to_astra( self.volume_geometry, self.sinogram_geometry) # Here we define proj_id that will be used for ASTRA # ASTRA projector, to be stored if self.device == 'cpu': # Note that 'line' only one option if self.sinogram_geometry.geom_type == 'parallel': self.set_projector( astra.create_projector('line', proj_geom, vol_geom)) elif self.sinogram_geometry.geom_type == 'cone': self.set_projector( astra.create_projector('line_fanflat', proj_geom, vol_geom)) else: NotImplemented elif self.device == 'gpu': self.set_projector( astra.create_projector('cuda', proj_geom, vol_geom)) else: NotImplemented
def domain_geometry(self): return self.volume_geometry def range_geometry(self): return self.sinogram_geometry if __name__ == '__main__': from ccpi.framework import ImageGeometry, AcquisitionGeometry import numpy as np N = 30 angles = np.linspace(0, np.pi, 180) ig = ImageGeometry(N, N) ag = AcquisitionGeometry('parallel', '2D', angles, pixel_num_h=N) A = ProjectionOperator(ig, ag, 'cpu') print(A.norm()) ig = ImageGeometry(N, N, N) ag = AcquisitionGeometry( 'parallel', '3D', angles, pixel_num_v=N, pixel_num_h=N, dimension_labels=['vertical', 'angle', 'horizontal']) A = ProjectionOperator(ig, ag, 'gpu') print(A.norm()) ig = ImageGeometry(N, N, channels=2)
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, dimension_labels=['angle', 'vertical', 'horizontal']) out = geometry.allocate() out.fill(data) return out 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, dimension_labels=['angle', 'horizontal']) out = geometry.allocate() out.fill(data.squeeze()) return out
nonzero] = ProjAngleChannels[ll, i, nonzero] / flat1[nonzero] eqzero = ProjAngleChannels == 0 ProjAngleChannels[eqzero] = 1 ProjAngleChannels_NormLog = -np.log( ProjAngleChannels) # normalised and neg-log data # extact sinogram over energy channels selectedVertical_slice = 256 sino_all_channels = ProjAngleChannels_NormLog[:, :, :, selectedVertical_slice] # Set angles to use angles = np.linspace(-np.pi, np.pi, totalAngles, endpoint=False) # set the geometry ig = ImageGeometry(n, n) ag = AcquisitionGeometry('parallel', '2D', angles, n, 1) Aop = AstraProjectorSimple(ig, ag, 'gpu') # loop to reconstruct energy channels REC_chan = np.zeros((totChannels, n, n), 'float32') for i in range(0, totChannels, 1): sino_channel = sino_all_channels[:, i, :] # extract a sinogram for i-th channel print("Initial guess") x_init = ImageData(geometry=ig) # Create least squares object instance with projector and data. print("Create least squares object instance with projector and data.") f = Norm2sq(Aop, DataContainer(sino_channel), c=0.5)
# Set angles to use #angles = numpy.linspace(-numpy.pi,numpy.pi,num_angles,endpoint=False) angles = np.linspace(-180, 180, num_angles, endpoint=False) * np.pi / 180 # Define full 3D acquisition geometry and data container. # NOTE: Default order of labels of the acquisition geometry is # [channel, angle, vertical, horizontal] # Here, we have data with an order of ['channel', vertical, angle, horizontal] # hence we use the dimension_labels as a last argument 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
class TestSubset(unittest.TestCase): def setUp(self): self.ig = ImageGeometry(1, 2, 3, channels=4) angles = numpy.asarray([90., 0., -90.], dtype=numpy.float32) self.ag = AcquisitionGeometry('cone', 'edo', pixel_num_h=20, pixel_num_v=2, angles=angles, dist_source_center=312.2, dist_center_detector=123., channels=4) def test_ImageDataAllocate1a(self): data = self.ig.allocate() default_dimension_labels = [ ImageGeometry.CHANNEL, ImageGeometry.VERTICAL, ImageGeometry.HORIZONTAL_Y, ImageGeometry.HORIZONTAL_X ] self.assertTrue( default_dimension_labels == list(data.dimension_labels.values())) def test_ImageDataAllocate1b(self): data = self.ig.allocate() default_dimension_labels = [ ImageGeometry.CHANNEL, ImageGeometry.VERTICAL, ImageGeometry.HORIZONTAL_Y, ImageGeometry.HORIZONTAL_X ] self.assertTrue(data.shape == (4, 3, 2, 1)) def test_ImageDataAllocate2a(self): non_default_dimension_labels = [ ImageGeometry.HORIZONTAL_X, ImageGeometry.VERTICAL, ImageGeometry.HORIZONTAL_Y, ImageGeometry.CHANNEL ] data = self.ig.allocate(dimension_labels=non_default_dimension_labels) self.assertTrue(non_default_dimension_labels == list( data.dimension_labels.values())) def test_ImageDataAllocate2b(self): non_default_dimension_labels = [ ImageGeometry.HORIZONTAL_X, ImageGeometry.VERTICAL, ImageGeometry.HORIZONTAL_Y, ImageGeometry.CHANNEL ] data = self.ig.allocate(dimension_labels=non_default_dimension_labels) self.assertTrue(data.shape == (1, 3, 2, 4)) def test_AcquisitionDataAllocate1a(self): data = self.ag.allocate() default_dimension_labels = [ AcquisitionGeometry.CHANNEL, AcquisitionGeometry.ANGLE, AcquisitionGeometry.VERTICAL, AcquisitionGeometry.HORIZONTAL ] self.assertTrue( default_dimension_labels == list(data.dimension_labels.values())) def test_AcquisitionDataAllocate1b(self): data = self.ag.allocate() default_dimension_labels = [ AcquisitionGeometry.CHANNEL, AcquisitionGeometry.ANGLE, AcquisitionGeometry.VERTICAL, AcquisitionGeometry.HORIZONTAL ] self.assertTrue(data.shape == (4, 3, 2, 20)) def test_AcquisitionDataAllocate2a(self): non_default_dimension_labels = [ AcquisitionGeometry.CHANNEL, AcquisitionGeometry.HORIZONTAL, AcquisitionGeometry.VERTICAL, AcquisitionGeometry.ANGLE ] data = self.ag.allocate(dimension_labels=non_default_dimension_labels) self.assertTrue(non_default_dimension_labels == list( data.dimension_labels.values())) def test_AcquisitionDataAllocate2b(self): non_default_dimension_labels = [ AcquisitionGeometry.CHANNEL, AcquisitionGeometry.HORIZONTAL, AcquisitionGeometry.VERTICAL, AcquisitionGeometry.ANGLE ] data = self.ag.allocate(dimension_labels=non_default_dimension_labels) self.assertTrue(data.shape == (4, 20, 2, 3)) def test_AcquisitionDataSubset1a(self): non_default_dimension_labels = [ AcquisitionGeometry.CHANNEL, AcquisitionGeometry.HORIZONTAL, AcquisitionGeometry.VERTICAL, AcquisitionGeometry.ANGLE ] data = self.ag.allocate(dimension_labels=non_default_dimension_labels) #self.assertTrue( data.shape == (4,20,2,3)) sub = data.subset(vertical=0) self.assertTrue(sub.shape == (4, 20, 3)) def test_AcquisitionDataSubset1b(self): non_default_dimension_labels = [ AcquisitionGeometry.CHANNEL, AcquisitionGeometry.HORIZONTAL, AcquisitionGeometry.VERTICAL, AcquisitionGeometry.ANGLE ] data = self.ag.allocate(dimension_labels=non_default_dimension_labels) #self.assertTrue( data.shape == (4,20,2,3)) sub = data.subset(channel=0) self.assertTrue(sub.shape == (20, 2, 3)) def test_AcquisitionDataSubset1c(self): non_default_dimension_labels = [ AcquisitionGeometry.CHANNEL, AcquisitionGeometry.HORIZONTAL, AcquisitionGeometry.VERTICAL, AcquisitionGeometry.ANGLE ] data = self.ag.allocate(dimension_labels=non_default_dimension_labels) #self.assertTrue( data.shape == (4,20,2,3)) sub = data.subset(horizontal=0) self.assertTrue(sub.shape == (4, 2, 3)) def test_AcquisitionDataSubset1d(self): non_default_dimension_labels = [ AcquisitionGeometry.CHANNEL, AcquisitionGeometry.HORIZONTAL, AcquisitionGeometry.VERTICAL, AcquisitionGeometry.ANGLE ] data = self.ag.allocate(dimension_labels=non_default_dimension_labels) #self.assertTrue( data.shape == (4,20,2,3)) sliceme = 1 sub = data.subset(angle=sliceme) #print (sub.shape , sub.dimension_labels) self.assertTrue(sub.shape == (4, 20, 2)) self.assertTrue( sub.geometry.angles[0] == data.geometry.angles[sliceme]) def test_AcquisitionDataSubset1e(self): non_default_dimension_labels = [ AcquisitionGeometry.CHANNEL, AcquisitionGeometry.HORIZONTAL, AcquisitionGeometry.VERTICAL, AcquisitionGeometry.ANGLE ] data = self.ag.allocate(dimension_labels=non_default_dimension_labels) #self.assertTrue( data.shape == (4,20,2,3)) sliceme = 1 sub = data.subset(angle=sliceme) self.assertTrue( sub.geometry.angles[0] == data.geometry.angles[sliceme]) def test_AcquisitionDataSubset1f(self): data = self.ag.allocate() #self.assertTrue( data.shape == (4,20,2,3)) sliceme = 1 sub = data.subset(angle=sliceme) self.assertTrue( sub.geometry.angles[0] == data.geometry.angles[sliceme])
from ccpi.optimisation.functions import ZeroFunction, BlockFunction, L2NormSquared from ccpi.astra.operators import AstraProjectorSimple from ccpi.framework import TestData import os, sys loader = TestData(data_dir=os.path.join(sys.prefix, 'share', 'ccpi')) # Create Ground truth phantom and Sinogram N = 150 M = 150 data = loader.load(TestData.SIMPLE_PHANTOM_2D, size=(N, M), scale=(0, 1)) 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)
eqzero = data == 0 data[eqzero] = 1 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,