def __init__(self, geometry, vol_space, proj_space): """Initialize a new instance. Parameters ---------- geometry : `Geometry` Geometry defining the tomographic setup. vol_space : `DiscretizedSpace` Reconstruction space, the space of the images to be forward projected. proj_space : `DiscretizedSpace` Projection space, the space of the result. """ if not isinstance(geometry, Geometry): raise TypeError( '`geometry` must be a `Geometry` instance, got {!r}' ''.format(geometry)) if not isinstance(vol_space, DiscretizedSpace): raise TypeError( '`vol_space` must be a `DiscretizedSpace` instance, got {!r}' ''.format(vol_space)) if not isinstance(proj_space, DiscretizedSpace): raise TypeError( '`proj_space` must be a `DiscretizedSpace` instance, got {!r}' ''.format(proj_space)) # Print a warning if the detector midpoint normal vector at any # angle is perpendicular to the geometry axis in parallel 3d # single-axis geometry -- this is broken in some ASTRA versions if (isinstance(geometry, Parallel3dAxisGeometry) and not astra_supports('par3d_det_mid_pt_perp_to_axis')): req_ver = astra_versions_supporting( 'par3d_det_mid_pt_perp_to_axis') axis = geometry.axis mid_pt = geometry.det_params.mid_pt for i, angle in enumerate(geometry.angles): if abs(np.dot(axis, geometry.det_to_src(angle, mid_pt))) < 1e-4: warnings.warn( 'angle {}: detector midpoint normal {} is ' 'perpendicular to the geometry axis {} in ' '`Parallel3dAxisGeometry`; this is broken in ' 'ASTRA {}, please upgrade to ASTRA {}' ''.format(i, geometry.det_to_src(angle, mid_pt), axis, ASTRA_VERSION, req_ver), RuntimeWarning) break self.geometry = geometry self._vol_space = vol_space self._proj_space = proj_space self.create_ids() # ASTRA projectors are not thread-safe, thus we need to lock manually self._mutex = Lock()
def test_vol_geom_3d(): """Check correctness of ASTRA 3D volume geometies.""" x_pts = 10 y_pts = 20 z_pts = 30 # Isotropic voxel case discr_dom = _discrete_domain(3, 'nearest') # x = columns, y = rows, z = slices correct_dict = { 'GridColCount': z_pts, 'GridRowCount': y_pts, 'GridSliceCount': x_pts, 'option': { 'WindowMinX': -3.0, # z_min 'WindowMaxX': 3.0, # z_max 'WindowMinY': -2.0, # y_min 'WindowMaxY': 2.0, # y_amx 'WindowMinZ': -1.0, # x_min 'WindowMaxZ': 1.0 } } # x_amx vol_geom = odl.tomo.astra_volume_geometry(discr_dom) assert vol_geom == correct_dict discr_dom = _discrete_domain_anisotropic(3, 'nearest') # x = columns, y = rows, z = slices correct_dict = { 'GridColCount': z_pts, 'GridRowCount': y_pts, 'GridSliceCount': x_pts, 'option': { 'WindowMinX': -1.0, # z_min 'WindowMaxX': 1.0, # z_max 'WindowMinY': -1.0, # y_min 'WindowMaxY': 1.0, # y_amx 'WindowMinZ': -1.0, # x_min 'WindowMaxZ': 1.0 } } # x_amx if astra_supports('anisotropic_voxels_3d'): vol_geom = odl.tomo.astra_volume_geometry(discr_dom) assert vol_geom == correct_dict else: with pytest.raises(NotImplementedError): odl.tomo.astra_volume_geometry(discr_dom)
def test_vol_geom_2d(): """Check correctness of ASTRA 2D volume geometries.""" x_pts = 10 # x_pts = Rows y_pts = 20 # y_pts = Columns # Isotropic voxel case discr_dom = _discrete_domain(2, 'nearest') correct_dict = { 'GridColCount': y_pts, 'GridRowCount': x_pts, 'option': { 'WindowMinX': -2.0, # y_min 'WindowMaxX': 2.0, # y_max 'WindowMinY': -1.0, # x_min 'WindowMaxY': 1.0 } } # x_amx vol_geom = odl.tomo.astra_volume_geometry(discr_dom) assert vol_geom == correct_dict # Anisotropic voxel case discr_dom = _discrete_domain_anisotropic(2, 'nearest') correct_dict = { 'GridColCount': y_pts, 'GridRowCount': x_pts, 'option': { 'WindowMinX': -1.0, # y_min 'WindowMaxX': 1.0, # y_max 'WindowMinY': -1.0, # x_min 'WindowMaxY': 1.0 } } # x_amx if astra_supports('anisotropic_voxels_2d'): vol_geom = odl.tomo.astra_volume_geometry(discr_dom) assert vol_geom == correct_dict else: with pytest.raises(NotImplementedError): odl.tomo.astra_volume_geometry(discr_dom)