TomographyWithAstra#
- class deepinv.physics.TomographyWithAstra(img_size, num_angles=180, num_detectors=None, angular_range=(0, torch.pi), detector_spacing=1.0, object_spacing=(1.0, 1.0), bounding_box=None, angles=None, geometry_type='parallel', geometry_parameters={'source_radius': 80.0, 'detector_radius': 20.0}, geometry_vectors=None, normalize=False, device=torch.device('cuda'), **kwargs)[source]#
Bases:
LinearPhysics
Computed Tomography operator with astra-toolbox backend. It is more memory efficient than the
deepinv.physics.Tomography
operator and support 3D geometries. See documentation ofdeepinv.physics.functional.XrayTransform
for more information on theastra
wrapper.Mathematically, it is described as a ray transform \(A\) which linearly integrates an object \(x\) along straight lines
\[y = \forw{x}\]where \(y\) is the set of line integrals, called sinogram in 2D, or radiographs in 3D. An object is typically scanned using a surrounding circular trajectory. Given different acquisition systems, the lines along which the integrals are computed follow different geometries:
- parallel. (2D and 3D)
Per view, all rays intersecting the object are parallel. In 2D, all rays live on the same plane, perpendicular to the axis of rotation.
- fanbeam. (2D)
Per view, all rays come from a single source and intersect the object at a certain angle. The detector consists of a 1d line of cells. Similar to the 2D “parallel”, all rays live on the same plane, perpendicular to the axis of rotation.
- conebeam. (3D)
Per view, all rays come from a single source. The detector consists of a 2D grid of cells. Apart from the central plane, the set of rays coming onto a line of cells live on a tilted plane.
Note
The pseudo-inverse is computed using the filtered back-projection algorithm with a Ramp filter, and its equivalent for conebeam 3D, the Feldkamp-Davis-Kress algorithm. This is not the exact linear pseudo-inverse of the Ray Transform, but it is a good approximation which is robust to noise.
Note
In the default configuration, reconstruction cells and detector cells are set to have isotropic unit lengths. The geometry is set to 2D parallel and matches the default configuration of the
deepinv.physics.Tomography
operator withcircle=False
.Warning
Due to computational efficiency reasons, the projector and backprojector implemented in
astra
are not matched. The projector is typically ray-driven, while the backprojector is pixel-driven. The adjoint of the forward Ray Transform is approximated by rescaling the backprojector.Warning
The
deepinv.physics.functional.XrayTransform
used indeepinv.physics.TomographyWithAstra
sequentially processes batch elements, which can make the 2D parallel beam operator significantly slower than its native torch counterpart withdeepinv.physics.Tomography
(though still more memory-efficient).- Parameters:
img_size (tuple[int, ...]) – Shape of the object grid, either a 2 or 3-element tuple, for respectively 2D or 3D.
num_angles (int) – Number of angular positions sampled uniformly in
angular_range
. (default: 180)num_detectors (int | tuple[int, ...], None) – In 2D, specify an integer for a single line of detector cells. In 3D, specify a 2-element tuple for (row,col) shape of the detector. (default: None)
angular_range (tuple[float, float]) – Angular range, defaults to
(0, torch.pi)
.detector_spacing (float | tuple[float, float]) – In 2D the width of a detector cell. In 3D a 2-element tuple specifying the (vertical, horizontal) dimensions of a detector cell. (default: 1.0)
object_spacing (tuple[float, ...]) – In 2D, the (x,y) dimensions of a pixel in the reconstructed image. In 3D, the (x,y,z) dimensions of a voxel. (default:
(1.,1.)
)bounding_box (tuple[float, ...], None) – Axis-aligned bounding-box of the reconstruction area [min_x, max_x, min_y, max_y, …]. Optional argument, if specified, overrides argument
object_spacing
. (default: None)angles (torch.Tensor, None) – Tensor containing angular positions in radii. Optional, if specified, overrides arguments
num_angles
andangular_range
. (default: None)geometry_type (str) – The type of geometry among
'parallel'
,'fanbeam'
in 2D and'parallel'
and'conebeam'
in 3D. (default:'parallel'
)geometry_parameters (dict[str, Any]) –
Contains extra parameters specific to certain geometries. When
geometry_type='fanbeam'
or'conebeam'
, the dictionnary should contains the keys"source_radius"
: the distance between the x-ray source and the rotation axis, denoted \(D_{s0}\), (default: 80.),"detector_radius"
: the distance between the x-ray detector and the rotation axis, denoted \(D_{0d}\). (default: 20.)
geometry_vectors (torch.Tensor, None) –
Alternative way to describe a 3D geometry. It is a torch.Tensor of shape [num_angles, 12], where for each angular position of index
i
the row consists of a vector of size (12,) with(sx, sy, sz)
: the position of the source,(dx, dy, dz)
: the center of the detector,(ux, uy, uz)
: the horizontal unit vector of the detector,(vx, vy, vz)
: the vertical unit vector of the detector.
When specified,
geometry_vectors
overridesdetector_spacing
,num_angles
/angles
andgeometry_parameters
. It is particularly useful to build the geometry for the Walnut-CBCT dataset, where the acquisition parameters are provided via such vectors.normalize (bool) – If
True
A()
andA_adjoint()
are normalized so that the operator has unit norm. (default:False
)device (torch.device | str) – The operator only supports CUDA computation. (default:
torch.device('cuda')
)
- Examples:
Tomography operator with a 2D
'fanbeam'
geometry, 10 uniformly sampled angles in[0,2*torch.pi]
, a detector line of 5 cells with length 2., a source-radius of 20.0 and a detector_radius of 20.0 for 5x5 image:>>> from deepinv.physics import TomographyWithAstra >>> seed = torch.manual_seed(0) # Random seed for reproducibility >>> x = torch.randn(1, 1, 5, 5, device='cuda') # Define random 5x5 image >>> physics = TomographyWithAstra( ... img_size=(5,5), ... num_angles=10, ... angular_range=(0, 2*torch.pi), ... num_detectors=5, ... detector_spacing=2.0, ... geometry_type='fanbeam', ... geometry_parameters={ ... 'source_radius': 20., ... 'detector_radius': 20. ... } ... ) >>> sinogram = physics(x) >>> print(sinogram) tensor([[[[-2.4262, -0.3840, -2.1681, -1.1024, 1.8009], [-2.4597, -0.0198, -1.6027, 0.1117, 1.0543], [-3.8424, -2.5034, 1.8132, 2.4666, -1.0440], [-3.0843, -2.0380, 2.2693, 2.4964, -2.7098], [ 0.6441, -2.2355, -0.2281, 0.2533, -1.3641], [ 1.7683, -0.9205, -2.1681, -0.2436, -2.5756], [ 0.4655, 0.3250, -1.6027, -0.6839, -2.4529], [-2.4195, 3.1875, 1.8132, -2.3952, -3.5968], [-1.6350, 1.4374, 2.2693, -2.2185, -3.7328], [-1.9789, 0.1986, -0.2281, -1.7952, -0.3667]]]], device='cuda:0')
Tomography operator with a 3D
'conebeam'
geometry, 10 uniformly sampled angles in[0,2*torch.pi]
, a detector grid of 5x5 cells of size (2.,2.), a source-radius of 20.0 and a detector_radius of 20.0 for a 5x5x5 volume:>>> seed = torch.manual_seed(0) # Random seed for reproducibility >>> x = torch.randn(1, 1, 5, 5, 5, device='cuda') # Define random 5x5x5 volume >>> angles = torch.linspace(0, 2*torch.pi, steps=4)[:-1] >>> physics = TomographyWithAstra( ... img_size=(5,5,5), ... angles = angles, ... num_detectors=(5,5), ... object_spacing=(1.0,1.0,1.0), ... detector_spacing=(2.0,2.0), ... geometry_type='conebeam', ... geometry_parameters={ ... 'source_radius': 20., ... 'detector_radius': 20. ... } ... ) >>> sinogram = physics(x) >>> print(sinogram) tensor([[[[[-2.0464, 0.4064, -1.5184, -0.9225, 1.5369], [-2.3398, -0.9323, 2.0437, 0.5806, -1.5659], [-1.0852, 2.0659, 1.1105, -1.7271, -2.6104]], [[ 1.4757, -0.2731, 0.9386, 0.5791, 0.2995], [-0.8362, 2.5918, 1.0941, 1.0576, -1.4501], [-1.1313, 3.8354, -0.9572, -2.3721, 3.5149]], [[ 0.6392, 0.1564, -0.8063, -3.8958, 1.2547], [ 0.5294, -1.0241, -0.1792, -0.5054, -1.4253], [-1.1961, -1.6911, 0.4279, -1.3608, 0.9488]], [[ 0.5134, 2.1534, -3.8697, 0.3571, 0.1060], [ 0.4687, -3.0669, 1.5911, 1.5235, -0.8031], [-1.1990, 0.2637, 2.0889, -0.8894, 0.2550]], [[-1.4643, -0.2128, 1.3425, 2.8803, -0.6605], [ 0.9605, 1.1056, 4.2324, -3.5795, -0.1718], [ 0.9207, 1.6948, 1.6556, -1.6624, 0.9960]]]]], device='cuda:0')
- A(x, **kwargs)[source]#
Forward projection.
- Parameters:
x (torch.Tensor) – input of shape [B,C,…,H,W]
- Returns:
projection of shape [B,C,…,A,N]
- Return type:
- A_adjoint(y, **kwargs)[source]#
Approximation of the adjoint.
- Parameters:
y (torch.Tensor) – input of shape [B,C,…,A,N]
- Returns:
torch.Tensor filtered back-projection of shape [B,C,…,H,W]
- Return type:
- A_dagger(y, **kwargs)[source]#
Pseudo-inverse estimated using filtered back-projection.
- Parameters:
y (torch.Tensor) – input of shape [B,C,…,A,N]
- Returns:
torch.Tensor filtered back-projection of shape [B,C,…,H,W]
- Return type:
- fbp_weighting(sinogram)[source]#
Scales the computation by the inverse number of views and object-to-dector cell ratio.
In conebeam 3D, compute FDK weights to correct inflated distances due to tilted rays. Given coordinate \((x,y)\) of a detector cell, the corresponding weight is \(\omega(x,y) = \frac{D_{s0}}{\sqrt{D_{sd}^2 + x^2 + y^2}}\).
- Parameters:
sinogram (torch.Tensor) – Sinogram of shape [B,C,…,A,N].
- Returns:
Weighted sinogram.
- Return type:
Examples using TomographyWithAstra
:#

Low-dose CT with ASTRA backend and Total-Variation (TV) prior