Reference manual
For the experimental operator-based interface, see Operator syntax.
Definition of geometry
A cornerstone in applying projection methods is to define for which geometry the projection has to be computed.
Thus, the first step in using gratopy is always creating an instance of gratopy.ProjectionSettings defining the geometry, and thus internally precomputing relevant quantities.
- class gratopy.ProjectionSettings(queue: CommandQueue, geometry: GeometryType, img_shape: tuple[int, int], angles: int | list[float] | ndarray | list[tuple[int | list[float] | ndarray, float, float]], n_detectors: int | None = None, angle_weights: float | list[float] | ndarray | None = None, detector_width: float = 2.0, image_width: float | None = None, R: float | None = None, RE: float | None = None, detector_shift: float = 0.0, midpoint_shift: tuple[float, float] = (0.0, 0.0), reverse_detector: bool = False)[source]
Creates and stores all relevant information concerning the projection geometry. Serves as a parameter for virtually all gratopy’s functions.
- Parameters:
queue (
pyopencl.CommandQueue) – The OpenCL command queue with which the computations are associated.geometry (
GeometryType) – Determines whether parallel beam (gratopy.RADON) or fanbeam geometry (gratopy.FANBEAM) is considered.img_shape (
tuple\((N_x,N_y)\)) – The number of pixels of the image in x- and y-direction respectively, i.e., the image dimension. It is assumed that by default, the center of rotation is in the middle of the grid of quadratic pixels. The midpoint can, however, be shifted, see the midpoint_shift parameter.angles (
int,list[float]/numpy.ndarray,list[tuple(int/list[float]/numpy.ndarray, float, float)]) –Determines which angles are considered for the projection. An integer is interpreted as the number \(N_a\) of uniformly distributed angles in the angular range \([0,\pi[\), \([0,2\pi[\) for Radon and fanbeam transform, respectively, where for negative integers the same angles according to its modulus but with reversed order are generated. Alternatively, the angles can be given explicitly as a
listornumpy.ndarray. These two options also imply a full angle setting (as opposed to limited angle setting).A limited angle setting can be specified in two ways. First, a list of angular range sections can be passed as input. An angular range section is a
tuplewith either an integer or a list/array of angles (first element) together with a pair specifying the lower and upper bound of the angular range interval (second and third element), i.e., of typetuple(int, float, float)ortuple(list[float], float, float). If the first element is an integer, the angular interval will be uniformly partitioned into the modulus number of angles (note that the first and last angles are not the lower/upper bounds to ensure uniform angle weights) again in increasing or decreasing order, depending on the sign. Otherwise, a list or array specifying the individual angles is expected. In particular, multiple angular sections can be specified, by passing a list of angular range sections.Alternatively, one can use a list of angles and set angle_weigths (see below) manually to suitable values by passing a scalar, a list or an array.
n_detectors (
int, defaultNone) – The number \(N_s\) of (equi-spaced) detector pixels considered. WhenNone, \(N_s\) will be chosen as \(\sqrt{N_x^2+N_y^2}\).angle_weights (
None,float,list[float]ornumpy.ndarray, defaultNone) – The weights \((\Delta_a)_a\) associated with the angles, which influences the weighting of the rays for the backprojection. See Adjointness in gratopy for a more detailed description. IfNone(by default), the weights are computed automatically based on the angles parameter. In the full angle setting, this automatism considers a partition of the half circle for parallel beam and the full circle for fanbeam geometry based on the given angles and sets the angle weight to the average of the distances from of an angle to its two neighbors (in the sense of a circle). Similarly, in the limited angle case, each angle section is partitioned by the angles associated with this section and the weights are chosen taking additionally the boundary of the section into account. In case of a scalar input, this scalar will be used as the (constant) angle weight for all angles. Further, all angle weights can directly be set by passing an input of typelist[float]ornumpy.ndarrayof suitable length.detector_width (
float, default 2.0) – Physical length of the detector. For standard Radon transformation this can usually remain fixed at the default value (together with image_width).image_width (
float, defaultNone) – Physical size of the image indicated by the length of the longer side of the rectangular image domain. For parallel beam geometry, whenNone, image_width is chosen as 2.0. For fanbeam geometry, whenNone, image_width is chosen such that the projections exactly capture the image domain. To illustrate, choosing image_width = detector_width results in the standard Radon transform with each projection touching the entire object, while img_width = 2 detector_width results in each projection capturing only half of the image.R (
float, must be set for fanbeam geometry) – Physical (orthogonal) distance from source to detector line. Has no impact for parallel beam geometry.RE (
float, must be set for fanbeam geometry) – Physical distance from source to origin (center of rotation). Has no impact for parallel beam geometry.detector_shift (
float, default 0.0) – Physical shift of all detector pixels along the detector line. Defaults to the application of no shift, i.e., the detector pixels span the range [-detector_width/2, detector_width/2].midpoint_shift (
list, default [0.0, 0.0]) – Two-dimensional vector representing the shift of the image away from center of rotation. Defaults to the application of no shift, i.e., the center of rotation is also the center of the image.reverse_detector (
bool, defaultFalse) – WhenTrue, the detector direction is flipped in case of fanbeam geometry, i.e., the positive and negative detector positions are swapped. This parameter has no effect for parallel geometry. When activated together with swapping the sign of the angles, this has the same effect for projection as mirroring the image.
These input parameters create attributes of the same name in an instance of
ProjectionSettings, though the corresponding values might be slightly restructured by internal processes. Further useful attributes are listed below. It is advised not to set these attributes directly but rather to choose suitable input parameters for the initialization.- Variables:
is_parallel (
bool) –Trueif the geometry is for parallel beams,Falseotherwise.is_fan (
bool) –Trueif the geometry is for fanbeam geometry,Falseotherwise.angles (
numpy.ndarray) – Angles from which projections are considered.n_angles (
int) – Number of all angles \(N_a\).sinogram_shape (
tuple\((N_s,N_a)\)) – Represents the number of considered detectors (n_detectors) and angles (n_angles).delta_x (
float) – Physical width and height \(\delta_x\) of the image pixels.delta_s (
float) – Physical width \(\delta_s\) of a detector pixel.delta_ratio (
float) – Ratio \({\delta_s}/{\delta_x}\), i.e. the detector pixel width relative to unit image pixels.angle_weights (
numpy.ndarray) – Represents the angular discretization width for each angle which are used to weight the projections, see parameter angle_weights above. When none was given as input, the angle_weights chosen by the automatism will be written to this variable.prg (
gratopy.Program) – OpenCL program containing the gratopy OpenCL kernels. For the corresponding code, seegratopy.create_codestruct (
dictseeradon_struct()andfanbeam_struct()returns) – Data used in the projection operator. Contains in particular dictionaries ofnumpy.ndarrayassociated to precision single and double with the angular information necessary for computations.
- backprojection(img: Array, sino: Array, projectionsetting: ProjectionSettings, wait_for: list[Event] = [])[source]
Calls the appropriate back projection given the configured geometry.
- create_sparse_matrix(dtype: DTypeLike = dtype('float32'), order: Literal['C', 'F'] = 'F') coo_matrix[source]
Creates a sparse matrix representation of the associated forward projection.
- Parameters:
dtype (
numpy.dtype, defaultnumpy.float32) – Precision to compute the sparse representation in.order (
str, defaultF) – Contiguity of the image and sinogram array to the transform, can beForC.
- Returns:
Sparse matrix corresponding to the forward projection.
- Return type:
Note that for high resolution projection operators, this may require infeasibly much time and memory.
- forwardprojection(sino: Array, img: Array, projectionsetting: ProjectionSettings, wait_for: list[Event] = []) None[source]
Calls the appropriate forward projection given the configured geometry.
- property geometry: GeometryType
Returns the configured geometry.
- get_projection_kernel(sinogram: Array, image: Array, adjoint: bool = False) Kernel[source]
Returns the compiled projection function for the given sinogram and image. If adjoint is True, the adjoint projection function is returned.
- Parameters:
sinogram (
pyopencl.array.Array) – The sinogram to be used in the projection.image (
pyopencl.array.Array) – The image to be used in the projection.adjoint (
bool, defaultFalse) – If True, returns the adjoint projection function.
- Returns:
The projection function.
- Return type:
callable
- show_geometry(angle: float, figure: Figure | None = None, axes: Axes | None = None, show: bool = True)[source]
Visualize the geometry associated with the projection settings. This can be useful in checking that indeed, the correct input for the desired geometry was given.
- Parameters:
angle (
float) – The angle for which the projection is considered.figure (
matplotlib.figure.Figure, defaultNone) – Figure in which to plot. If neither figure nor axes are given, a new figure (figure(0)) will be created.axes (
matplotlib.axes.Axes, defaultNone) – Axes to plot into. IfNone, a new axes inside the figure is created.show (
bool, defaultTrue) – Determines whether the resulting plot is immediately shown (True). IfFalse,matplotlib.pyplot.show()can be used at a later point to show the figure.
- Returns:
Figure and axes in which the geometry visualization is plotted.
- Return type:
Transforms
The functions forwardprojection() and backprojection() perform the projection operations based on the geometry defined in projectionsetting. The images img and the sinograms sino need to be interpreted and
behave as described in Getting started.
- gratopy.forwardprojection(img: Array, projectionsetting: ProjectionSettings, sino: Array | None = None, wait_for: list[Event] = [])[source]
Performs the forward projection (either for the Radon or the fanbeam transform) of a given image using the given projection settings.
- Parameters:
img (
pyopencl.array.Arraywith compatible dimensions) – The image to be transformed.projectionsetting (
gratopy.ProjectionSettings) – The geometry settings for which the forward transform is computed.sino (
pyopencl.array.Arraywith compatible dimensions, defaultNone) – The array in which the result of transformation is saved. IfNone(per default) is given, a new array will be created and returned.wait_for (
list[pyopencl.Event], default[]) – The events to wait for before performing the computation in order to avoid, e.g., race conditions, seepyopencl.Event. This program will always wait for img.events and sino.events (so you need not add them to wait_for).
- Returns:
The sinogram associated with the projection of the image. If the sino is not
None, the samepyopenclarray is returned with the values in its data overwritten.- Return type:
The forward projection can be performed for single or double precision arrays. The dtype (precision) of img and sino (if given) have to coincide and the output will be of the same precision. It respects any combination of C and F contiguous arrays where output will be of the same contiguity as img if no sino is given. The OpenCL events associated with the transform will be added to the output’s events. In case the output array is created, it will use the allocator of img. If the image and sinogram have a third dimension (z-direction) the operator is applied slicewise.
- gratopy.backprojection(sino: Array, projectionsetting: ProjectionSettings, img: Array | None = None, wait_for: list[Event] = [])[source]
Performs the backprojection (either for the Radon or the fanbeam transform) of a given sinogram using the given projection settings.
- Parameters:
sino (
pyopencl.array.Arraywith compatible dimensions) – Sinogram to be backprojected.projectionsetting (
gratopy.ProjectionSettings) – The geometry settings for which the forward transform is computed.img (
pyopencl.array.Arraywith compatible dimensions, defaultNone) – The array in which the result of backprojection is saved. IfNoneis given, a new array will be created and returned.wait_for (
list[pyopencl.Event], default[]) – The events to wait for before performing the computation in order to avoid, e.g., race conditions, seepyopencl.Event. This program will always wait for img.events and sino.events (so you need not add them to wait_for).
- Returns:
The image associated with the backprojected sinogram, coinciding with the img if not
None, with the values in its data overwritten.- Return type:
The backprojection can be performed for single or double precision arrays. The dtype (precision) of img and sino have to coincide. If no img is given, the output precision coincides with sino’s. The operation respects any combination of C and F contiguous arrays, where if img is
None, the result’s contiguity coincides with sino’s. The OpenCL events associated with the transform will be added to the output’s events. In case the output array is created, it will use the allocator of sino. If the sinogram and image have a third dimension (z-direction), the operator is applied slicewise.
Solvers
Based on these forward and backward operators, one can implement a variety of reconstruction algorithms, where the toolbox’s focus is on iterative methods (as those in particular are dependent on efficient implementation).
The following constitute a few easy-to-use examples which also serve as illustration on how gratopy can be included in custom pyopencl implementations.
- gratopy.landweber(sino: Array, projectionsetting: ProjectionSettings, number_iterations: int = 100, w: float = 1.0) Array[source]
Performs a Landweber iteration [L1951] to approximate a solution to the image reconstruction problem associated with a projection and sinogram. This method is also known as SIRT.
- Parameters:
sino (
pyopencl.array.Array) – Sinogram data to reconstruct from.projectionsetting (
gratopy.ProjectionSettings) – The geometry settings for which the projection is considered.number_iterations (
int, default 100) – Number of iteration steps to be performed.w (
float, default 1) – Relaxation parameter weighted by the norm of the projection operator (w<1 guarantees convergence).
- Returns:
Reconstruction from given sinogram gained via Landweber iteration.
- Return type:
[L1951]Landweber, L. “An iteration formula for Fredholm integral equations of the first kind.” Amer. J. Math. 73, 615–624 (1951). https://doi.org/10.2307/2372313
- gratopy.conjugate_gradients(sino: Array, projectionsetting: ProjectionSettings, number_iterations: int = 20, epsilon: float = 0.0, x0: Array | None = None)[source]
Performs a conjugate gradients iteration [HS1952] to approximate a solution to the image reconstruction problem associated with a projection and sinogram.
- Parameters:
sino (
pyopencl.array.Array) – Sinogram data to invert.projectionsetting (
gratopy.ProjectionSettings) – The geometry settings for which the projection is considered.number_iterations (
float, default 20) – Maximal number of iteration steps to be performed.x0 (
pyopencl.array.Array, defaultNone) – Initial guess for iteration (defaults to zeros ifNone).epsilon (
float, default 0.00) – Tolerance parameter, the iteration stops if relative residual<epsilon.
- Returns:
Reconstruction gained via conjugate gradients iteration.
- Return type:
[HS1952]Hestenes, M. R., Stiefel, E. “Methods of Conjugate Gradients for Solving Linear Systems.” Journal of Research of the National Bureau of Standards, 49:409–436 (1952). https://doi.org/10.6028/jres.049.044
- gratopy.total_variation(sino: Array, projectionsetting: ProjectionSettings, mu: float, number_iterations: int = 1000, slice_thickness: float = 1.0, stepsize_weighting: float = 10.0)[source]
Performs a primal-dual algorithm [CP2011] to solve a total-variation regularized reconstruction problem associated with a given projection operator and sinogram. This corresponds to the approximate solution of \(\min_{u} {\frac\mu2}\|\mathcal{P}u-f\|_{L^2}^2+\mathrm{TV}(u)\) for \(\mathcal{P}\) the projection operator, \(f\) the sinogram and \(\mu\) a positive regularization parameter (i.e., an \(L^2-\mathrm{TV}\) reconstruction approach).
- Parameters:
sino (
pyopencl.array.Array) – Sinogram data to invert.projectionsetting (
gratopy.ProjectionSettings) – The geometry settings for which the projection is considered.mu (
float) – Regularization parameter, the smaller the stronger the applied regularization.number_iterations (
int, default 1000) – Number of iterations to be performed.slice_thickness (
float, default 1.0, i.e., isotropic voxels) – When 3-dimensional data sets are considered, regularization is also applied across slices. This parameter represents the ratio of the slice thickness to the length of one pixel within a slice. The choice slice_thickness =0 results in no coupling across slices.stepsize_weighting (
float, default 10.0) – Allows to weight the primal-dual algorithm’s step sizes \(\sigma\) (stepsize for dual update) and \(\tau\) (stepsize for primal update) (with \(\sigma\tau\|\mathcal{P}\|^2\leq 1\)) by multiplication and division, respectively, with the given value.
- Returns:
Reconstruction gained via primal-dual iteration for the total-variation regularized reconstruction problem.
- Return type:
[CP2011]Chambolle, A., Pock, T. “A First-Order Primal-Dual Algorithm for Convex Problems with Applications to Imaging.” J Math Imaging Vis 40, 120–145 (2011). https://doi.org/10.1007/s10851-010-0251-1
- gratopy.normest(projectionsetting: ProjectionSettings, number_iterations: int = 50, dtype: DTypeLike = 'float32', allocator: AllocatorBase = None)[source]
Estimate the spectral norm of the projection operator via power iteration, i.e., the operator norm with respect to the norms discussed in section concerning adjointness. Useful for iterative methods that require such an estimate, e.g.,
landweber()ortotal_variation().- Parameters:
projectionsetting (
gratopy.ProjectionSettings) – The geometry settings for which the projection is considered.number_iterations (
int, default 50) – The number of iterations to terminate after.dtype (
numpy.dtype, defaultnumpy.float32) – Precision for which to apply the projection operator (which is not supposed to impact the estimate significantly).
- Returns:
An estimate of the spectral norm for the projection operator.
- Return type:
- gratopy.weight_sinogram(sino: Array, projectionsetting: ProjectionSettings, sino_out: Array | None = None, divide: bool = False, wait_for: list[Event] = []) Array[source]
Performs an angular rescaling of a given sinogram via multiplication (or division) with the projection’s angle weights (size of projections in angle dimension, see attributes of
ProjectionSettings) to the respective projections. This can be useful, e.g., for computing norms or dual pairings in the appropriate Hilbert space.- Parameters:
sino (
pyopencl.array.Array) – The sinogram whose rescaling is computed. This array itself remains unchanged unless the same array is given as sino_out.projectionsetting (
gratopy.ProjectionSettings) – The geometry settings for which the rescaling is computed.sino_out (
pyopencl.array.ArraydefaultNone) – The array in which the result of rescaling is saved. IfNone(per default) is given, a new array will be created and returned. When giving the same array as sino, the values in sino will be overwritten.divide (
bool, defaultFalse) – Determines whether the sinogram is divided (instead of multiplied) by the angular weights. IfTrue, a division is performed, otherwise, the weights are multiplied.wait_for (
list[pyopencl.Event], default[]) – The events to wait for before performing the computation in order to avoid, e.g., race conditions, seepyopencl.Event. This program will always wait for img.events and sino.events (so you need not add them to wait_for).
- Returns:
The weighted sinogram. If sino_out is not
None, it is returned with the values in its data overwritten. In particular, giving the same array for sino and sino_out will overwrite this array.- Return type:
Data generation
For convenient testing, a phantom generator is included which creates a modified two-dimensional phantom of arbitrary size.
- gratopy.phantom(queue: CommandQueue, N: int | tuple[int, int] | ndarray, modified: bool = True, E: ndarray | None = None, ret_E: bool = False, dtype: str | DTypeLike = 'double', allocator: AllocatorBase | None = None)
Generate an OpenCL Shepp-Logan phantom of size (N, N).
- Parameters:
queue (
pyopencl.CommandQueue) – The OpenCL command queue.N (
intorarray_like) – Matrix size, (N, N) or (M, N).modified (
bool) – Use original gray-scale values as given in [SL1974]. Most implementations use modified values for better contrast (for example, see [2] and [3]).E (
array_likeorNone) –\(e \times 6\) numeric matrix defining \(e\) ellipses. The six columns of E are:
Gray value of the ellipse (in [0, 1])
Length of the horizontal semi-axis of the ellipse
Length of the vertical semi-axis of the ellipse
x-coordinate of the center of the ellipse (in [-1, 1])
y-coordinate of the center of the ellipse (in [-1, 1])
Angle between the horizontal semi-axis of the ellipse and the x-axis of the image (in rad)
ret_E (
bool) – Return the matrix E used to generate the phantom.dtype (
strornumpy.dtype) – Thepyopencldata type in which the phantom is created.allocator (An implementation of
pyopencl.tools.AllocatorInterfaceorNone) – Thepyopenclallocator used for memory allocation.
- Returns:
Phantom/parameter pair (ph [, E]).
- Variables:
ph (
pyopencl.array.Array) – The Shepp-Logan phantom.E (
array_like, optional) – The ellipse parameters used to generate ph.
This much abused phantom is due to [SL1974]. The tabulated values in the paper are reproduced in the Wikipedia entry [1]. The original values do not produce great contrast, so modified values are used by default (see Table B.1 in [TS1996] or implementations [2] and [3]).
Internal functions
The following contains the documentation for a set of internal functions which could be of interest for developers. Note that these might be subject to change in the future.
- gratopy.radon(sino: Array, img: Array, projectionsetting: ProjectionSettings, wait_for: list[Event] = [])[source]
Performs the Radon transform of a given image using the given projectionsetting.
- Parameters:
sino (
pyopencl.array.Array) – The array in which the resulting sinogram is written.img (
pyopencl.array.Array) – The image to transform.projectionsetting (
gratopy.ProjectionSettings) – The geometry settings for which the Radon transform is performed.wait_for (
list[pyopencl.Event], default []) – The events to wait for before performing the computation in order to avoid, e.g., race conditions, seepyopencl.Event. This program will always wait for img.events and sino.events (so you need not add them to wait_for).
- Returns:
Event associated with the computation of the Radon transform (which is also added to the events of sino).
- Return type:
- gratopy.radon_ad(img: Array, sino: Array, projectionsetting: ProjectionSettings, wait_for: list[Event] = [])[source]
Performs the Radon backprojection of a given sinogram using the given projectionsetting.
- Parameters:
img (
pyopencl.array.Array) – The array in which the resulting backprojection is written.sino (
pyopencl.array.Array) – The sinogram to transform.projectionsetting (
gratopy.ProjectionSettings) – The geometry settings for which the Radon backprojection is performed.wait_for (
list[pyopencl.Event], default []) – The events to wait for before performing the computation in order to avoid, e.g., race conditions, seepyopencl.Event. This program will always wait for img.events and sino.events (so you need not add them to wait_for).
- Returns:
Event associated with the computation of the Radon backprojection (which is also added to the events of img).
- Return type:
- gratopy.radon_struct(queue: CommandQueue, img_shape: tuple[int, int], angles: ndarray, angle_weights: ndarray, n_detectors: int | None = None, detector_width: float = 2.0, image_width: float = 2.0, midpoint_shift: tuple[float, float] = (0.0, 0.0), detector_shift: float = 0.0)[source]
Creates the structure storing geometry information required for the Radon transform and its adjoint.
- Parameters:
queue (
pyopencl.CommandQueue) – OpenCL command queue in which context the computations are to be performed.img_shape (
tuple\((N_x,N_y)\)) – The number of pixels of the image in x- and y-direction respectively, i.e., the image size. It is assumed that by default, the center of rotation is in the middle of the grid of quadratic pixels. The midpoint can, however, be shifted, see the midpoint_shift parameter.angles (
numpy.ndarray) – Determines which angles are considered for the projection.angle_weights (
numpy.ndarray) – The weights associated to the angles, e.g., how much of the angular range is covered by this angle. This impacts the weighting of rays for the backprojection.n_detectors (
int, defaultNone) – The number \(N_s\) of considered (equi-spaced) detectors. IfNone, \(N_s\) will be chosen as \(\sqrt{N_x^2+N_y^2}\).detector_width (
float, default 2.0) – Physical length of the detector line.image_width (
float, default 2.0) – Physical size of the image indicated by the length of the longer side of the rectangular image domain. Choosing image_width = detector_width results in the standard Radon transform with each projection touching the entire object, while img_width = 2 detector_width results in each projection capturing only half of the image.midpoint_shift (
list[float], default [0.0, 0.0]) – Two-dimensional vector representing the shift of the image away from center of rotation. Defaults to the application of no shift.detector_shift (
float, default 0.0) – Physical shift of the detector along the detector line in detector pixel offsets. Defaults to the application of no shift, i.e., the detector reaches from [- detector_width/2, detector_width/2].
- Returns:
Struct dictionary with the following variables as entries, where the keys are strings of the same names:
- Return type:
- Variables:
ofs_dict (
dict{numpy.dtype: numpy.ndarray}) –Dictionary containing the relevant angular information as
numpy.ndarrayfor the data typesnumpy.float32andnumpy.float64. The arrays have dimension \((8, N_a)\) with columns:0
weighted cosine
1
weighted sine
2
detector offset
3
inverse of cosine/sine
4
angular weight
5
flipped
The remaining columns are unused. The value flipped indicates whether the x and y axis are flipped (1) or not (0), which is done for reasons of numerical stability. The 4th entry contains the inverse of sine if the axes are flipped and the inverse of cosine otherwise.
shape (
tuple) – Tuple of integers \((N_x,N_y)\) representing the size of the image.sinogram_shape (
tuple) – Tuple of integers \((N_s,N_a)\) representing the size of the sinogram.geo_dict (
dict{numpy.dtype: numpy.ndarray}) – Dictionary mapping the allowed data types to an array containing the values [\(\delta_x, \delta_s, N_x, N_y, N_s, N_a\)].angles_diff_buf – Dictionary containing the same values as in ofs_dict [4] representing the weights associated with the angles (i.e., the length of sinogram pixels in the angular direction).
- gratopy.fanbeam(sino: Array, img: Array, projectionsetting: ProjectionSettings, wait_for: list[Event] = [])[source]
Performs the fanbeam transform of a given image using the given projectionsetting.
- Parameters:
sino (
pyopencl.array.Array) – The array in which the resulting sinogram is written.img (
pyopencl.array.Array) – The image to transform.projectionsetting (
gratopy.ProjectionSettings) – The geometry settings for which the fanbeam transform is performed.wait_for (
list[pyopencl.Event], default []) – The events to wait for before performing the computation in order to avoid, e.g., race conditions, seepyopencl.Event. This program will always wait for img.events and sino.events (so you need not add them to wait_for).
- Returns:
Event associated with the computation of the fanbeam transform (which is also added to the events of sino).
- Return type:
- gratopy.fanbeam_ad(img: Array, sino: Array, projectionsetting: ProjectionSettings, wait_for: list[Event] = [])[source]
Performs the fanbeam backprojection of a given sinogram using the given projectionsetting.
- Parameters:
img (
pyopencl.array.Array) – The array in which the resulting backprojection is written.sino (
pyopencl.array.Array) – The sinogram to transform.projectionsetting (
gratopy.ProjectionSettings) – The geometry settings for which the fanbeam backprojection is performed.wait_for (
list[pyopencl.Event], default []) – The events to wait for before performing the computation in order to avoid, e.g., race conditions, seepyopencl.Event. This program will always wait for img.events and sino.events (so you need not add them to wait_for).
- Returns:
Event associated with the computation of the fanbeam backprojection (which is also added to the events of img).
- Return type:
- gratopy.fanbeam_struct(queue: CommandQueue, img_shape: tuple[int, int], angles: ndarray, detector_width: float, source_detector_dist: float, source_origin_dist: float, angle_weights: ndarray, n_detectors: int | None = None, detector_shift: float = 0.0, image_width: float | None = None, midpoint_shift: tuple[float, float] = (0.0, 0.0), reverse_detector: bool = False)[source]
Creates the structure storing geometry information required for the fanbeam transform and its adjoint.
- Parameters:
queue (
pyopencl.CommandQueue) – OpenCL command queue in which context the computations are to be performed.img_shape (
tuple\((N_x,N_y)\)) – The number of pixels of the image in x- and y-direction respectively, i.e., the image size. It is assumed that by default, the center of rotation is in the middle of the grid of quadratic pixels. The midpoint can, however, be shifted, see the midpoint_shift parameter.angles (
numpy.ndarray) – Determines which angles are considered for the projection.detector_width (
float, default 2.0) – Physical length of the detector line.source_detector_dist (
float) – Physical (orthogonal) distance R from the source to the detector line.source_origin_dist (
float) – Physical distance RE from the source to the origin (center of rotation).angle_weights (
numpy.ndarray) – The weights associated to the angles, e.g., how much of the angular range is covered by this angle. This impacts the weighting of rays for the backprojection.n_detectors (
intorNone, defaultNone) – The number \(N_s\) of considered (equi-spaced) detectors. IfNone, \(N_s\) will be chosen as \(\sqrt{N_x^2+N_y^2}\).detector_shift (
float, default 0.0) – Physical shift of the detector along the detector line in detector pixel offsets. Defaults to the application of no shift, i.e., the detector reaches from [- detector_width/2, detector_width/2].image_width (
float, defaultNone) – Physical size of the image indicated by the length of the longer side of the rectangular image domain. IfNone, image_width is chosen to capture just all rays.midpoint_shift (
list[float], default [0.0, 0.0]) – Two-dimensional vector representing the shift of the image away from center of rotation. Defaults to the application of no shift.reverse_detector (
bool, defaultFalse) – WhenTrue, the detector direction is flipped.
- Returns:
Struct dictionary with the following variables as entries, where the keys are strings of the same names:
- Return type:
- Variables:
img_shape (
tuple) – Tuple of integers \((N_x,N_y)\) representing the size of the image.sinogram_shape (
tuple) – Tuple of integers \((N_s,N_a)\) representing the size of the sinogram.ofs_dict (
dict{numpy.dtype: numpy.ndarray}) –Dictionary containing the relevant angular information as
numpy.ndarrayfor the data typesnumpy.float32andnumpy.float64. The arrays have dimension \((8, N_a)\) with columns:0 1
vector of length \(\delta_s\) pointing in positive detector direction
2 3
vector connecting source and center of rotation
4 5
vector connection the origin and its projection onto the detector line
6
angular weight
The remaining column is unused.
sdpd_dict (
dict{numpy.dtype: numpy.ndarray}) – Dictionary mappingnumpy.float32andnumpy.float64to anumpy.ndarrayrepresenting the values \(\sqrt{(s^2+R^2)}\) for the weighting in the fanbeam transform (weighted by delta_ratio, i.e., \(\delta_s/\delta_x\)).image_width – Physical size of the image. Equal to the input parameter if given, or to the determined image size if image_width is
None(see parameter image_width).geo_dict (
dict{numpy.dtype: numpy.ndarray}) – Dictionary mapping the allowed data types to an array containing the values [source detector distance/\(\delta_x\), source origin distance/\(\delta_x\), width of a detector_pixel relative to width of image_pixels i.e. \(\delta_s\)/\(\delta_x\), image midpoint x-coordinate (in pixels), image midpoint y-coordinate (in pixels), detector line midpoint (in detector-pixels), \(N_x\), \(N_y\), \(N_s\), \(N_a\), width of an image pixel (\(\delta_x\))].angles_diff (
dict{numpy.dtype: numpy.ndarray}) – Dictionary containing the same values as in ofs_dict [6] representing the weights associated with the angles (i.e., the length of sinogram pixels in the angular direction).
- gratopy.create_code(cl_context: Context | None = None)[source]
Reads and creates CL code containing all OpenCL kernels of the gratopy toolbox.
- Parameters:
cl_context – The OpenCL context in which the code is to be compiled. Used for checking support for double precision floating point numbers.
- Returns:
The toolbox’s CL code.
- Return type:
Operator package
The operator package provides an experimental operator-oriented interface to a subset of gratopy’s functionality.
Operator algebra
Generic implementation of operators including basic arithmetic.
- class gratopy.operator.base.Operator(name: str | None = None, scalar: float | int | int64 | float32 | float64 = 1, state: dict[str, Any] | None = None, arithmetic_operation: OperatorArithmeticOperation | None = None, operands: list[Operator] | None = None, input_shape: tuple[int, ...] | None = None, output_shape: tuple[int, ...] | None = None)[source]
Bases:
objectBase class for all operators.
- apply_to(argument: Any, output: Any | None = None, **kwargs: Any) Any[source]
Application of this operator to some given argument.
For composite products,
outputis passed only to the final child operator. Intermediate results are computed normally while the final result can reuse the caller-provided array.
Projection operators
Gratopy projection operators.
This module contains concrete operator implementations for gratopy’s
experimental operator interface, most notably Radon.
The focus is currently on a compositional, operator-style interface for Radon transforms and their adjoints. Fanbeam support is not yet implemented at the same level.
Examples
>>> import numpy as np
>>> import pyopencl as cl
>>> import gratopy
>>> ctx = cl.create_some_context(interactive=False)
>>> queue = cl.CommandQueue(ctx)
>>> Nx = 300
>>> img = np.zeros((Nx, Nx), dtype=np.float32)
>>> R = gratopy.operator.Radon(image_domain=Nx, angles=180)
>>> sinogram = R.apply_to(img, queue=queue)
>>> backprojection = R.T.apply_to(sinogram)
The same forward and adjoint applications can also be written via operator syntax:
>>> sinogram = R * img
>>> backprojection = R.T * sinogram
- class gratopy.operator.projection.Fanbeam(source_distances: float | tuple[float, float], image_domain: int | tuple[int, int] | ImageDomain, angles: Angles | int, detectors: Detectors | int | None = None, adjoint: bool = False)[source]
Bases:
Operator
- class gratopy.operator.projection.Radon(image_domain: int | tuple[int, int] | ImageDomain, angles: Angles | int, detectors: Detectors | int | None = None, adjoint: bool = False, kernel_spec: OpenCLKernelSpec | None = None)[source]
Bases:
_OpenCLOperatorParallel-beam Radon transform operator.
This class provides the main entry point to gratopy’s experimental operator-based projection interface. A
Radonobject represents either the forward projection operator or, when created throughT, its adjoint.Parameters
image_domain:Description of the image grid and its physical extent. This can be given as:
an
intfor a square image domain of that size,a
(Nx, Ny)tuple for a rectangular grid,or an explicit
gratopy.utilities.ImageDomaininstance.
Plain integer and tuple inputs are converted to
ImageDomainwith a default extent of2.0.angles:Angular sampling of the operator. This can be given either as an integer or as an explicit
gratopy.utilities.Anglesobject.If an integer is given, uniformly weighted angles are created via
gratopy.utilities.Angles.uniform()with thehalf_circleparameter set toTrue.detectors:Detector configuration. This can be given as:
Noneto use the default detector countceil(hypot(Nx, Ny)),an integer specifying the number of detector pixels,
or an explicit
gratopy.utilities.Detectorsobject.
Plain integer inputs are converted to
Detectorswith default extent handling.adjoint:If
False(the default), construct the forward Radon transform. IfTrue, construct the adjoint operator directly. In practice, the adjoint is typically accessed viaT.kernel_spec:Optional
gratopy.operator.opencl.OpenCLKernelSpecdescribing which OpenCL kernel bundle to use. When omitted, the operator uses the Radon kernels shipped with gratopy.
Notes
The operator accepts both
pyopencl.array.Arrayinputs and NumPy arrays. When applying the operator to a NumPy array, a queue must be available so that the data can be transferred to the device.The operator supports 2D as well as slicewise 3D data. For example, a forward operator with image shape
(Nx, Ny)maps:(Nx, Ny)to(Ns, Na),(Nx, Ny, Nz)to(Ns, Na, Nz).
Correspondingly, the adjoint maps:
(Ns, Na)to(Nx, Ny),(Ns, Na, Nz)to(Nx, Ny, Nz).
Extent placeholders are supported experimentally for Radon geometry when exactly one extent is fixed numerically and the other is given as
gratopy.utilities.ExtentPlaceholder. The operator can resolve an image extent from a fixed detector extent, or a detector extent from a fixed image extent. Passing placeholders for both extents at once remains unsupported and raisesNotImplementedError; geometries for which no valid placeholder resolution exists raiseValueError.Examples
>>> import numpy as np >>> import pyopencl as cl >>> import gratopy >>> ctx = cl.create_some_context(interactive=False) >>> queue = cl.CommandQueue(ctx) >>> img = np.zeros((128, 128), dtype=np.float32) >>> R = gratopy.operator.Radon(image_domain=128, angles=180) >>> sino = R.apply_to(img, queue=queue) >>> backproj = R.T.apply_to(sino)
Operator algebra is also supported:
>>> G = R.T * R >>> gram_img = G.apply_to(img, queue=queue)
- apply_to(argument: Any, output: Any | None = None, queue: CommandQueue | None = None, return_event: bool = False, **kwargs: Any) Array | tuple[Array, list[Event]][source]
Standard OpenCL-backed operator execution pipeline.
Passing
outputlets callers provide a preallocated device array and avoid allocating a new OpenCL array for the result.
- property image_domain: ImageDomain
OpenCL-backed operator helpers
OpenCL helpers for gratopy operators.
This module contains small building blocks for OpenCL-backed operators:
OpenCLKernelSpecdescribes where kernels are loaded from._OpenCLOperatorprovides shared execution helpers.
The classes in this module are intentionally lightweight. They are meant to
support concrete operators such as gratopy.operator.Radon without
pulling OpenCL-specific concerns into gratopy.operator.base.Operator.
- class gratopy.operator.opencl.OpenCLKernelSpec(paths: tuple[str, ...], base_name: str, build_options: tuple[str, ...] = ())[source]
Bases:
objectDescription of an OpenCL kernel bundle.
This class describes the OpenCL source files used by an experimental gratopy operator as well as the kernel base name used for lookup.
Parameters
paths:One or more kernel source files. Paths are normalized to absolute paths during initialization.
base_name:Base name used for generated kernel lookup. With the current naming convention, forward and adjoint kernels are expected to follow the pattern
{base_name}_{dtype}_{out_order}{in_order}and
{base_name}_ad_{dtype}_{out_order}{in_order},respectively.
build_options:Optional extra compiler flags forwarded to
cl.Program.build().
Notes
The current operator implementation expects gratopy-style template placeholders in the source files, most notably
\my_variable_type,\order1, and\order2.The
signatureproperty is content-based: it depends on the file contents, their order, the base name, and the build options. This is used as part of the OpenCL program cache key so that changing a kernel file on disk automatically leads to recompilation when needed.Examples Use the default shipped Radon kernels implicitly via
gratopy.operator.projection.Radon, or provide an explicit custom kernel bundle:>>> from gratopy.operator import OpenCLKernelSpec >>> spec = OpenCLKernelSpec.from_path("scratch/my_radon.cl", base_name="radon")
The resulting spec can then be passed to a custom or built-in operator.
- classmethod from_path(path: str | Path, base_name: str, build_options: tuple[str, ...] = ()) OpenCLKernelSpec[source]
Create a kernel spec from a single source file.
- gratopy.operator.opencl.invalidate_kernel_cache() None[source]
Clear the internal operator OpenCL program cache.
- class gratopy.operator.opencl._OpenCLOperator(*, name: str | None = None, kernel_spec: OpenCLKernelSpec | None = None, **operator_kwargs: Any)[source]
Bases:
OperatorInternal base class for OpenCL-backed operators.
This class intentionally only implements shared execution helpers. Concrete subclasses are still responsible for geometry handling and for deciding which kernels to load.
- static _allocate_output(queue: CommandQueue, shape: tuple[int, ...], dtype: DTypeLike, order: Literal['C', 'F'] = 'F', allocator: Any = None) Array[source]
Allocate an output array on the device.
- static _coerce_argument(argument: ArrayLike | Array, queue: CommandQueue) Array[source]
Coerce a NumPy/array-like input to a device array.
- _default_kernel_spec() OpenCLKernelSpec[source]
Return the default kernel spec for this operator.
Concrete subclasses are expected to override this if they want to rely on _OpenCLOperator construction directly.
- _expected_output_shape(argument_shape: tuple[int, ...]) tuple[int, ...][source]
Return the expected output shape for a given input shape.
- _get_kernel(output: Array, argument: Array, queue: CommandQueue) Kernel[source]
Return the kernel used for standard OpenCL operator execution.
- _global_shape(output: Array, argument: Array) tuple[int, ...][source]
Return the global shape used for kernel execution.
- _infer_queue(argument: ArrayLike | Array | None = None, output: Array | None = None, queue: CommandQueue | None = None) CommandQueue[source]
Infer the queue to use for computation.
- _kernel_arguments(output: Array, argument: Array, queue: CommandQueue) tuple[Any, ...][source]
Return additional kernel arguments beyond output/input buffers.
- _validate_argument(argument: Array) None[source]
Validate an input argument before kernel execution.
- _validate_output(output: Array, argument: Array) Array[source]
Validate and normalize an output array before kernel execution.
- apply_to(argument: Any, output: Any | None = None, queue: CommandQueue | None = None, return_event: bool = False, **kwargs: Any) Array | tuple[Array, list[Event]][source]
Standard OpenCL-backed operator execution pipeline.
Passing
outputlets callers provide a preallocated device array and avoid allocating a new OpenCL array for the result.
Utility geometry classes
The experimental operator API uses a small collection of helper classes for image domains, detector geometry, angular sampling, and extent placeholders.
Miscellaneous utility functions for gratopy.
- class gratopy.utilities.Angles(angles: ArrayLike, weights: ArrayLike, half_circle: bool = False)[source]
Angular sampling together with associated weights.
An
Anglesobject stores the projection angles in radians and the corresponding angle weights used, for instance, in the adjoint operator. It serves as the main explicit representation of angular geometry in the experimental operator API.Parameters
angles:One-dimensional array-like object containing angles in radians.
weights:One-dimensional array-like object containing the weights associated with the given angles.
half_circle:Whether the angular sampling should be interpreted with half-circle (\(\pi\)) periodicity instead of full-circle (\(2\pi\)) periodicity. For constructors that generate a complete equispaced sampling, this also determines whether angles are generated in \([0, \pi)\) or \([0, 2\pi)\). For limited-angle or explicit samplings, it is stored as metadata for downstream code.
Notes
The static constructors on this class provide a few common ways of constructing angular samplings:
sparse()for unweighted equispaced angles,uniform()for equispaced angles with uniform weights,uniform_interval()for one limited-angle interval,intervals()for multiple limited-angle intervals,from_list()for explicit angles with automatically inferred natural weights.
- static from_list(angles: ArrayLike, half_circle: bool = False) Angles[source]
Automatically compute natural weights for a given list of angles.
- Parameters:
angles – List of angles.
half_circle – If False (the default), angles are in \([0, 2\pi)\). Otherwise, angles are in \([0, \pi)\).
- Returns:
Angles object with unitary weights.
- static intervals(number_list: list[int], start_list: list[float], end_list: list[float], half_circle: bool = False) Angles[source]
Create angles uniformly distributed across multiple intervals.
- Parameters:
number_list – List of numbers of angles for each interval.
start_list – List of start points for each interval.
end_list – List of end points for each interval.
half_circle – Angular periodicity metadata. If True, the sampling is marked as using \(\pi\) periodicity; otherwise, it is marked as using \(2\pi\) periodicity.
- Returns:
Angles object with angles and weights across all intervals.
- static sparse(number: int, half_circle: bool = False) Angles[source]
Store a list of angles with all weights set to 1.
- Parameters:
number – Number of angles.
half_circle – If False (the default), angles are in \([0, 2\pi)\). Otherwise, angles are in \([0, \pi)\).
- Returns:
Angles object with unitary weights.
- static uniform(number: int, half_circle: bool = False) Angles[source]
Generate uniformly distributed and weighted angles.
- Parameters:
number – Number of angles.
half_circle – If False (the default), angles are in \([0, 2\pi)\). Otherwise, angles are in \([0, \pi)\).
- Returns:
Angles object with uniform angles and weights.
- static uniform_interval(start: float, end: float, number: int, half_circle: bool = False) Angles[source]
Generate uniformly distributed and weighted angles in a specified interval.
- Parameters:
start – Start of the interval.
end – End of the interval.
number – Number of angles.
half_circle – Angular periodicity metadata. If True, the sampling is marked as using \(\pi\) periodicity; otherwise, it is marked as using \(2\pi\) periodicity.
- Returns:
Angles object with uniform angles and weights.
- class gratopy.utilities.Detectors(number: int, extent: float | ExtentPlaceholder = ExtentPlaceholder.FULL, center: float = 0.0, reversed: bool | None = None)[source]
Detector discretization and physical placement.
This class describes the detector line used by an operator:
numberis the number of detector pixels,extentis the physical detector width or an extent placeholder,centershifts the detector along its detector axis,reversedflips the detector orientation.
Parameters
number:Number of detector pixels. Negative values are accepted as a shorthand for
reversed=Truewithabs(number)detector pixels.extent:Physical detector width or an
ExtentPlaceholder.center:Physical shift of the detector center along the detector axis.
reversed:Whether the detector orientation is reversed. If omitted, the sign of
numberis used to infer the orientation.
Notes
In the experimental Radon operator,
ExtentPlaceholder.FULLandExtentPlaceholder.VALIDcan be used here to resolve the detector extent from a fixed image extent. Passing placeholders for both detector and image extents at once is unsupported and raisesNotImplementedError.- extent: float | ExtentPlaceholder = 'full'
- class gratopy.utilities.ExtentPlaceholder(*values)[source]
Placeholder values for image and detector extents.
These placeholders are primarily intended for the experimental operator API, where image and detector extents can be specified independently. They express geometric intent rather than an immediate numerical value.
The placeholder mechanism in the experimental operator API is still evolving. The experimental Radon operator can resolve one placeholder extent at a time: either the image extent from a fixed detector extent, or the detector extent from a fixed image extent. Passing placeholders for both extents at once is unsupported and raises
NotImplementedError.- FULL = 'full'
From the perspective of the detector: smallest detector extent such that each ray hitting the image domain also hits the detector. From the perspective of the image domain: largest image extent such that each ray hitting the image domain also hits the detector.
- VALID = 'valid'
From the perspective of the detector: the largest extent such that each ray hitting the detector also hits the image domain. From the perspective of the image domain: the smallest extent such that each ray hitting the detector also hits the image domain.
- class gratopy.utilities.ImageDomain(size: int | tuple[int, int], extent: float | ExtentPlaceholder = 2.0, center: tuple[float, float] = (0.0, 0.0))[source]
Image grid and physical image extent.
This class bundles the discrete image shape together with the physical extent and center shift used by an operator.
Parameters
size:Image grid size. An integer is interpreted as a square domain of shape
(N, N); a tuple specifies(Nx, Ny)directly.extent:Physical extent of the image domain or an
ExtentPlaceholder. In gratopy’s conventions, this corresponds to the longer side length of the rectangular image domain.center:Physical shift of the image center relative to the rotation center.
Notes
In the experimental Radon operator,
ExtentPlaceholder.FULLandExtentPlaceholder.VALIDcan be used here to resolve the image extent from a fixed detector extent. Passing placeholders for both image and detector extents at once is unsupported and raisesNotImplementedError.- extent: float | ExtentPlaceholder = 2.0