def create_example_parallel3d(example_type=''): """ :brief: create an example of a parallel3d geometry :param example_type: for the examples, there are different options - '' or 'normal': example of a standard parallel geometry with 100 angles - 'vec': same geometry as for normal, but converted to a vector geometry this gives a different plot visualizing the individual angles on top of the geometry :return: the example geometry """ det_spacing = [0.035, 0.035] detector_px = [1000, 1000] angles = np.linspace(0, 2 * np.pi, 100) if example_type == '' or example_type == 'normal': proj_geom = astra.create_proj_geom('parallel3d', det_spacing[0], det_spacing[1], detector_px[0], detector_px[1], angles) elif example_type == 'vec': proj_geom = astra.geom_2vec(create_example_parallel3d()) else: raise ValueError( "ASTRA: example type {0} not recognized for parallel3d geometry". format(example_type)) return proj_geom
def create_example_fanflat(example_type=''): """ :brief: create an example geometry of type fanflat :param example_type: - '' or 'normal': example of a standard fanflat geometry with 100 angles - 'vec': same geometry as for normal, but converted to a vector geometry this gives a different plot visualizing the individual angles on top of the geometry :return: the example geometry """ def make_normal_geometry(): det_spacing = 0.035 detector_px = 1200 angles = np.linspace(0, 2 * np.pi, 100) source_origin = 30 origin_det = 200 phantom_size = 5 phantom_px = 150 # voxels for the phantom vx_size = phantom_size / phantom_px # voxel size # now express all measurements in terms of the voxel size det_spacing = det_spacing / vx_size origin_det = origin_det / vx_size source_origin = source_origin / vx_size geom = astra.create_proj_geom('fanflat', det_spacing, detector_px, angles, source_origin, origin_det) return geom if example_type == '' or example_type == 'normal': proj_geom = make_normal_geometry() elif example_type == 'vec': proj_geom = astra.geom_2vec(make_normal_geometry()) else: raise ValueError( "ASTRA: example type {0} not recognized for parallel3d geometry". format(example_type)) return proj_geom
def to_vector(self): return ConeVectorGeometry.from_astra(astra.geom_2vec(self.to_astra()))
def generate_parallel_pg(det_spacing, det_shape, num_angles): angles = np.linspace(0, 2 * np.pi, num_angles, False) pg = astra.create_proj_geom("parallel3d", *det_spacing, *det_shape, angles) return astra.geom_2vec(pg)
def generate_cone_pg(det_spacing, det_shape, num_angles, SOD, SDD): angles = np.linspace(0, 2 * np.pi, num_angles, False) pg = astra.create_proj_geom("cone", *det_spacing, *det_shape, angles, SOD, SDD - SOD) return astra.geom_2vec(pg)
def _modify_astra_vector_(proj_geom, geometry): """ Modify ASTRA vector using known offsets from the geometry records. """ # Even if the geometry is of the type 'simple' (GEOM_SYMPLE), we need to generate ASTRA vector to be able to rotate the reconstruction volume if needed. proj_geom = astra.geom_2vec(proj_geom) vectors = proj_geom['Vectors'] theta_count = vectors.shape[0] det_pixel = geometry['det_pixel'] * numpy.array(geometry.get('proj_sample')) # Modify vector and apply it to astra projection geometry: for ii in range(0, theta_count): # Compute current offsets (for this angle): if geometry.get('type') == GEOM_SIMPLE: det_vrt = 0 det_hrz = 0 det_mag = 0 det_rot = 0 src_vrt = 0 src_hrz = 0 src_mag = 0 axs_hrz = 0 axs_mag = 0 # Compute current offsets: elif geometry.get('type') == GEOM_STAOFF: det_vrt = geometry['det_vrt'] det_hrz = geometry['det_hrz'] det_mag = geometry['det_mag'] det_rot = geometry['det_rot'] src_vrt = geometry['src_vrt'] src_hrz = geometry['src_hrz'] src_mag = geometry['src_mag'] axs_hrz = geometry['axs_hrz'] axs_mag = geometry['axs_mag'] # Use linear offsets: elif geometry.get('type') == GEOM_LINOFF: b = (ii / (theta_count - 1)) a = 1 - b det_vrt = geometry['det_vrt'][0] * a + geometry['det_vrt'][1] * b det_hrz = geometry['det_hrz'][0] * a + geometry['det_hrz'][1] * b det_mag = geometry['det_mag'][0] * a + geometry['det_mag'][1] * b det_rot = geometry['det_rot'][0] * a + geometry['det_rot'][1] * b src_vrt = geometry['src_vrt'][0] * a + geometry['src_vrt'][1] * b src_hrz = geometry['src_hrz'][0] * a + geometry['src_hrz'][1] * b src_mag = geometry['src_mag'][0] * a + geometry['src_mag'][1] * b axs_hrz = geometry['axs_hrz'][0] * a + geometry['axs_hrz'][1] * b axs_mag = geometry['axs_mag'][0] * a + geometry['axs_mag'][1] * b else: raise ValueError('Wrong geometry type: ' + geometry.get('type')) # Define vectors: src_vect = vectors[ii, 0:3] det_vect = vectors[ii, 3:6] det_axis_hrz = vectors[ii, 6:9] det_axis_vrt = vectors[ii, 9:12] #Precalculate vector perpendicular to the detector plane: det_normal = numpy.cross(det_axis_hrz, det_axis_vrt) det_normal = det_normal / numpy.sqrt(numpy.dot(det_normal, det_normal)) # Translations relative to the detecotor plane: #Detector shift (V): det_vect += det_vrt * det_axis_vrt / det_pixel[0] #Detector shift (H): det_vect += det_hrz * det_axis_hrz / det_pixel[1] #Detector shift (M): det_vect += det_mag * det_normal / det_pixel[1] #Source shift (V): src_vect += src_vrt * det_axis_vrt / det_pixel[0] #Source shift (H): src_vect += src_hrz * det_axis_hrz / det_pixel[1] #Source shift (M): src_vect += src_mag * det_normal / det_pixel[1] # Rotation axis shift: det_vect -= axs_hrz * det_axis_hrz / det_pixel[1] src_vect -= axs_hrz * det_axis_hrz / det_pixel[1] det_vect -= axs_mag * det_normal / det_pixel[1] src_vect -= axs_mag * det_normal / det_pixel[1] # Rotation relative to the detector plane: # Compute rotation matrix T = transforms3d.axangles.axangle2mat(det_normal, det_rot) det_axis_hrz[:] = numpy.dot(T.T, det_axis_hrz) det_axis_vrt[:] = numpy.dot(T, det_axis_vrt) # Global transformation: # Rotation matrix based on Euler angles: R = transforms3d.euler.euler2mat(geometry['vol_rot'][0], geometry['vol_rot'][1], geometry['vol_rot'][2], 'rzyx') # Apply transformation: det_axis_hrz[:] = numpy.dot(det_axis_hrz, R) det_axis_vrt[:] = numpy.dot(det_axis_vrt, R) src_vect[:] = numpy.dot(src_vect,R) det_vect[:] = numpy.dot(det_vect,R) # Add translation: vect_norm = numpy.sqrt((det_axis_vrt ** 2).sum()) # Take into account that the center of rotation should be in the center of reconstruction volume: T = numpy.array([geometry['vol_tra'][1] * vect_norm / det_pixel[1], geometry['vol_tra'][2] * vect_norm / det_pixel[1], geometry['vol_tra'][0] * vect_norm / det_pixel[0]]) src_vect[:] -= numpy.dot(T, R) det_vect[:] -= numpy.dot(T, R) proj_geom['Vectors'] = vectors return proj_geom
def get_geometry(dset_path, projs_shape, beam_geometry="cone", vol_shift_mm=0.0, vol_size_add=None, detector_tilt_deg=None): config = get_scanner_conf(dset_path) sdd = float(config["CT-parameters IN"]["SDD"][1:-1]) sod = float(config["CT-parameters IN"]["SOD"][1:-1]) first_angle = float(config["CT-parameters IN"]["Start angle"][1:-1]) last_angle = float(config["CT-parameters IN"]["Last angle"][1:-1]) voxsize = float(config["CT-parameters IN"]["Voxel size"][1:-1]) pixsize = float(config["CT-parameters IN"]["Pixel size"][1:-1]) angles = np.linspace(first_angle, last_angle, projs_shape[1]) angles = angles / 180 * np.pi if beam_geometry.lower() == "cone": sdd = sdd / voxsize sod = sod / voxsize odd = sdd - sod rel_pixsize = pixsize / voxsize vol_shift = -vol_shift_mm / pixsize proj_geom = astra.create_proj_geom("cone", rel_pixsize, rel_pixsize, projs_shape[0], projs_shape[2], angles, sod, odd) proj_geom = astra.geom_2vec(proj_geom) V = proj_geom["Vectors"] V[:, 3:6] = V[:, 3:6] + vol_shift * V[:, 6:9] V[:, 0:3] = V[:, 0:3] + vol_shift * V[:, 6:9] elif beam_geometry.lower() == "parallel": vol_shift = -vol_shift_mm / voxsize proj_geom = astra.create_proj_geom("parallel3d", 1, 1, projs_shape[0], projs_shape[2], angles) proj_geom = astra.geom_postalignment(proj_geom, [vol_shift, 0]) if detector_tilt_deg is not None: if proj_geom["type"] in ("cone", "parallel"): proj_geom = astra.geom_2vec(proj_geom) V = proj_geom["Vectors"] dir_proj = V[:, 3:6] - V[:, 0:3] dir_proj = dir_proj / np.sqrt(np.sum(dir_proj**2, axis=1))[..., np.newaxis] for ii in range(V.shape[0]): t = geometry.GeometryTransformation.get_rototranslation( dir_proj[ii, :], detector_tilt_deg) V[ii, 6:9] = np.transpose(t.apply_direction(np.transpose(V[ii, 6:9]))) V[ii, 9:12] = np.transpose(t.apply_direction(np.transpose(V[ii, 9:12]))) vol_size = np.array((projs_shape[2], projs_shape[2], projs_shape[0]), dtype=np.int) if vol_size_add is not None: vol_size = (vol_size + vol_size_add).astype(np.int) vol_geom = astra.create_vol_geom(vol_size) return (proj_geom, vol_geom, vol_shift)