TomoJAX

tomojax

TomoJAX: tomography, laminography and lab cone-beam CT reconstruction and alignment.

The workflow API takes a Scan (projections and their geometry) and returns results that carry their geometry:

import tomojax as tj

scan = tj.load("scan.nxs")  # or a Nikon .xtekct
recon = tj.reconstruct(scan)  # Geometry-aware automatic reconstruction
recon = tj.reconstruct(scan, method="cgls", iterations=50)
result = tj.align(scan, mode="cor-then-pose")  # result.scan carries the corrections
tj.save("recon.nxs", tj.reconstruct(result.scan))

Build a scan from arrays with tj.Scan(projections, geometry) and the geometry classes below; tj.project simulates projections for any geometry. The subpackages (tomojax.recon, tomojax.alignment, tomojax.geometry, tomojax.io) hold the building blocks these use. Names load on first use, so import tomojax does not import JAX. Importing sets growing GPU allocation defaults for future JAX backends; explicit allocator environment settings are preserved. See docs/large-scans.md for process-wide memory configuration.

NameSummary
loadLoad line integrals from a dataset or recognised raw acquisition.
load_framesLoad detector frames and acquisition metadata from supported scan formats.
reconstructReconstruct scan with method.
alignEstimate scan's geometry corrections and reconstruct with them.
projectProject a volume through the supplied geometry.
backprojectApply the exact transpose of the forward projector.
saveSave a scan, reconstruction or alignment as a TomoJAX dataset.
load_reconstructionLoad a reconstruction saved by save or tomojax recon.
ScanProjections and the geometry that produced them.
FramesDetector frames as recorded, with the geometry of each sample view.
ReconstructionA reconstructed volume, the scan it came from and how it was made.
AlignmentThe result of align.
ConeBeamSource and detector placement in the lab frame, shared by every view.
ConeGeometryCone-beam scan of a sample rotating about +z, or a tilted axis.
DetectorRegular detector plane metadata.
GridRegular voxel grid metadata.
LaminographyGeometryLaminography geometry with tilted rotation axis (parallel-ray model).
ParallelGeometryParallel-beam CT geometry with axis-aligned detector.
RegionEstimateThe resized scan and the evidence/uncertainty behind its reconstruction grid.
estimate_centerEstimate a parallel scan's rotation centre without reconstructing a volume.
estimate_regionSelect a reconstruction region from an already calibrated laminography scan.
reconstruct_slabsCorrect raw frames and reconstruct bounded z slabs.

load

load(path: str | PathLike[str], *, poses: bool = True) -> Scan
Defined in src/tomojax/_loading.py:46

Load line integrals from a dataset or recognised raw acquisition.

A file of raw detector frames (an NXtomo image_key marking flats or darks, or a Nikon or Zeiss acquisition) is corrected with the standard chain, as load_frames(path).corrected(): dark subtraction, flat division and -log; Scan.corrections records it. For other corrections, load the frames with load_frames. The scan carries the per-view corrections saved with it (by align or tomojax align) unless poses is False. Frames that image_key marks as other than sample views are left out.

Parameters

path : str or path-like Dataset or recognised acquisition file or directory. poses : bool, optional Apply the saved per-view pose corrections; default is True.

Returns

Scan Line-integral projections with geometry and correction records.

Raises

FileNotFoundError If the input does not exist. ValueError If TIFFs need geometry, counts lack calibration, or metadata are invalid.

Examples

import tomojax as tj scan = tj.load("scan.nxs") # doctest: +SKIP

load_frames

load_frames(
    path: str | PathLike[str],
    *,
    flats: np.ndarray | float | str | PathLike[str] | None = None,
    darks: np.ndarray | float | str | PathLike[str] | None = None,
    angles: Sequence[float] | np.ndarray | None = None,
    detector: Detector | None = None,
    grid: Grid | None = None,
    geometry: ScanGeometry | None = None,
    exposure_times: np.ndarray | float | None = None,
    flat_exposure_times: np.ndarray | float | None = None,
    data_path: str | None = None,
    image_key_path: str | None = None,
    angles_path: str | None = None,
) -> Frames
Defined in src/tomojax/_loading.py:361

Load detector frames and acquisition metadata from supported scan formats.

An HDF5 file's image_key marks its flats (1) and darks (2), and its sample, flat and dark frames are read only as they are corrected (including a few sampled rows when an absent axial rotation centre needs estimating). The frames, key and angles are found at their NXtomo paths or as the file's only datasets of that name (data, image_key, rotation_angle), or their paired GDA imaging paths; data_path, image_key_path and angles_path name them otherwise. Nikon, SkyScan, Zeiss and ESRF acquisitions are recognized by content and supply their own geometry and calibration. SkyScan logs require geometrically and flat-field corrected TIFF exports; their storage bit depth is not a measured white level, so supply flats= (frames or one level) explicitly. Zeiss Xradia projection files keep their embedded reference images, physical calibration and per-view image shifts in the geometry. A GDA command mislabeled as mm is read in degrees with a warning; discovered paths and this correction stay in source metadata. Generic TIFF stacks without acquisition metadata need angles (degrees), flats (frames or one level) and their detector (including pixel sizes and centre). Missing detector pixel pitch is never replaced by unit pixels. Axial acquisitions with recorded pitch use the opposite-view correlation estimator for an absent rotation centre, recording inferred provenance; failed estimates require detector=. Missing dark fields require darks=; use darks=0 only for already dark-corrected counts.

flats and darks (arrays, HDF5 stacks, TIFF files or folders, Zeiss XRM images, or one level for every pixel), angles, detector, grid and a whole geometry (of every sample view; then TIFFs need no angles) replace what the file holds. HDF5 calibration paths use the same automatic dataset discovery as the input and stay lazy; every frame in their stack contributes to the calibration mean.

Parameters

path : str or path-like HDF5, NPZ, Nikon, SkyScan, Zeiss or ESRF acquisition, or generic TIFF stack. flats : array-like, float, str, path-like or None, optional Replacement flat frames, calibration stack path or constant open-beam level. darks : array-like, float, str, path-like or None, optional Replacement dark frames, calibration stack path or constant dark level. angles : array-like or None, optional Sample-view angles in degrees, replacing file metadata. detector : Detector or None, optional Replacement detector dimensions, pixel sizes and physical centre. grid : Grid or None, optional Replacement reconstruction grid. geometry : ScanGeometry or None, optional Complete sample-view geometry, overriding individual metadata. exposure_times : numpy.ndarray or float or None, optional Sample exposure durations in seconds, replacing file metadata. flat_exposure_times : numpy.ndarray or float or None, optional Flat exposure durations in seconds, replacing file metadata. data_path : str or None, optional Explicit HDF5 frame dataset path; None discovers it. image_key_path : str or None, optional Explicit HDF5 sample/flat/dark key path; None discovers it. angles_path : str or None, optional Explicit HDF5 rotation-angle path; None discovers it.

Returns

Frames Raw sample and calibration frames with geometry; HDF5/Zeiss/TIFF reads stay lazy.

Raises

FileNotFoundError If the input does not exist. ValueError If required angles are absent or metadata and frame shapes disagree. KeyError If a required dataset cannot be found in the file.

Examples

import tomojax as tj frames = tj.load_frames("raw_scan.nxs") # doctest: +SKIP scan = frames.corrected(binning=4) # doctest: +SKIP

reconstruct

reconstruct(
    scan: Scan,
    method: Method = 'auto',
    *,
    grid: Grid | None = None,
    out: np.ndarray | None = None,
    config: MethodConfig | None = None,
    filter: str | None = None,
    iterations: int | None = None,
    tv_weight: float | None = None,
    nonnegative: bool | None = None,
    warm_start: bool | None = None,
    seed: int | None = None,
    devices: Device | Sequence[Device] | None = None,
) -> Reconstruction
Defined in src/tomojax/_workflow.py:251

Reconstruct scan with method.

auto (default) chooses Fourier inversion for unposed axial half-turn scans, the guarded laminography workflow for oblique scans, matched CGLS for segmented cone geometry, and FBP/FDK otherwise. An explicitly unrecorded axial centre may be inferred; oblique auto may infer setup and support on a coarse grid before native refinement. An explicit grid fixes the region and final voxel sampling instead; automatic setup and motion still run. The scan and info["automatic"] record those choices and limitations. Explicit methods bypass this policy.

  • fbp: Filtered backprojection: FDK for cone beams, with Parker weights for short scans and Wang's for offset detectors. filter is ramp (default), shepp-logan or hann. Volumes too large for the device are reconstructed in slabs on the host.
  • fourier: Fourier-slice inversion of parallel-beam half-turn scans, with nonuniform or repeated angles and translation-only poses; no cone beams or tilted axes. Input and output stay on the host; FourierConfig selects NumPy or CuPy CUDA.
  • cgls: Least squares by conjugate gradients, iterations (default 50).
  • fista: Least squares with total-variation weight tv_weight (default 0.005), iterations (default 50), optionally nonnegative.
  • sirt: SIRT, OS-SART, bounds and support via SIRTConfig.
  • spdhg: The same objective as fista by stochastic primal-dual updates: iterations (default 400) each update one block of views, in an order drawn with seed.

mlem is linear Poisson MLEM/OSEM, not transmission counts (MLEMConfig). warm_start uses FBP/FDK for least squares; grid overrides the scan's output grid.

out is a writable float32 array or memmap of shape (grid.nx, grid.ny, grid.nz)` for `fbp`, `fourier`, and `cgls`, `sirt` and `mlem on cone beams: the volume is made in host slabs straight into it and returned as volume. It must not overlap the scan, and a later failure can leave it partly written. Cone CGLS, SIRT and MLEM also use host slabs on their own when their volumes would not fit on the device; with a memmapped out, CGLS keeps its three work volumes in temporary files beside it.

config is from tomojax.recon; keywords replace its fields. Mismatched config classes or unknown keywords raise ValueError.

devices (fbp, cgls and fista; one or several, jax.devices() for all) shares the views among them: each projects its own views and holds the whole volume, and their backprojections are summed. The volume, on the first device, is the one-device result up to the order of that sum. Host slabs use the first device only.

Reconstruction.info holds config and solver records (iterations, termination, losses). Fourier's backend records the actual selected implementation separately from the requested configuration.

Parameters

scan : Scan Measured line integrals with their acquisition geometry. method : str, optional One of auto, fbp, fourier, cgls, fista, spdhg, sirt or mlem. grid : Grid or None, optional Output grid; None retains the scan's grid. out : numpy.ndarray or None, optional Writable float32 output or memmap for fbp/fourier and cone cgls/sirt/mlem; must not overlap input. config : reconstruction config or None, optional Method-specific settings; explicit keywords replace its fields. filter : str or None, optional FBP filter: ramp, shepp-logan or hann; None uses the configuration. iterations : int or None, optional Iteration count; None uses the method default or configuration. tv_weight : float or None, optional Total-variation weight for fista/spdhg; None uses the configuration. nonnegative : bool or None, optional Nonnegative constraint where supported; None uses the configuration. warm_start : bool or None, optional Use FBP/FDK initialization for supported iterative methods. seed : int or None, optional Random seed for stochastic view ordering where supported. devices : jax.Device or sequence of jax.Device or None, optional Devices sharing views for supported methods; None uses the default device.

Returns

Reconstruction Volume with the actual scan geometry, method and solver records.

Raises

ValueError If the method, configuration or options are incompatible.

Examples

import tomojax as tj scan = tj.load("scan.nxs") # doctest: +SKIP recon = tj.reconstruct(scan, "cgls", iterations=50) # doctest: +SKIP

align

align(
    scan: Scan,
    *,
    mode: AlignmentMode | Literal['auto'] = 'auto',
    quality: QualityTier = 'fast',
    levels: Iterable[int] | None = None,
    freeze: Iterable[str] = (),
    grid: Grid | None = None,
    checkpoint: str | PathLike[str] | None = None,
    config: AlignConfig | ProjectionMatchingConfig | None = None,
    devices: Device | Sequence[Device] | None = None,
) -> Alignment
Defined in src/tomojax/_workflow.py:722

Estimate scan's geometry corrections and reconstruct with them.

mode="auto" selects centre estimation for axial parallel scans and guarded setup/support/motion selection for unposed laminography. Its conditional outcome and limitations are in info["automatic"]. Centre estimation records its input/output physical detector coordinates; its success resolves only the reconstruction-only calibration limitation. Explicit mode is pose (per-view motion), cor (detector centre, or a cone beam's axis offset and detector roll), cor-then-pose or full (setup geometry, then motion, coarse to fine); see tomojax.alignment. quality is fast or reference (slower, more conservative). freeze keeps named parameters fixed (for example ("dy",)); levels sets the coarse-to-fine binning factors. config (a tomojax.alignment.AlignConfig) holds expert solver settings and replaces the quality profile's defaults. ProjectionMatchingConfig instead selects native-texture, translation-only joint refinement for unposed axial scans, without resampling the input. It may fit noise or model mismatch as motion; inspect poses and image quality. Its image uses Fourier. Checkpoints and level/quality overrides are unsupported. A spectral_setup initializer does not reconstruct; reconstruct its returned scan.

grid overrides the scan's reconstruction grid, as reconstruct does. In automatic laminography it fixes the region and final voxel sampling, while setup and motion remain automatic; it is not inferred support.

checkpoint is a file the alignment saves its progress to after each outer iteration. When that file holds a checkpoint of the same alignment (the same projections and geometry, mode, levels, grid and settings, from the same TomoJAX version), the alignment resumes from it, and a finished one returns its result at once. Any other file there raises ValueError saying how it differs, and is left as it is. A cone beam's cor mode runs no outer iterations and writes none.

devices (one or several, jax.devices() for all) shares the views among them, as reconstruct does, in the joint pose and volume update of pose alignment and in cone-beam reconstruction steps; the rest runs on the first. The devices change only the order of sums, so a checkpoint made on some resumes on others.

A scan that already carries poses (an ASTRA import's, say, or an earlier alignment's) is corrected on top of them, and multi-orbit ConeSegments scans are aligned as one, so their orbits come into register; only pose alignment takes either.

The returned Alignment.scan carries the corrections, and the grid, so tomojax.reconstruct(result.scan) reconstructs with them; Alignment.poses are the scan's poses, its own included. Alignment.info holds the mode, levels and resolved config with the solver's record (losses, gauge, any calibrated setup geometry).

Parameters

scan : Scan Measured line integrals with their acquisition geometry. mode : str, optional Alignment mode: auto, pose, cor, cor-then-pose or full. quality : {'fast', 'reference'} Quality profile; reference is slower and more conservative. levels : iterable of int or None, optional Coarse-to-fine binning factors; None uses the mode's defaults. freeze : iterable of str, optional Names of parameters to keep fixed, such as ("dy",). grid : Grid or None, optional Alignment and reconstruction grid; None keeps the scan's grid. checkpoint : str, path-like or None, optional Progress file; compatible existing checkpoints resume automatically. config : AlignConfig or None, optional Expert solver settings, replacing the quality profile's defaults. devices : jax.Device or sequence of jax.Device or None, optional Devices sharing supported pose and reconstruction updates.

Returns

Alignment Reconstruction, corrected scan, full pose table and solver records.

Raises

ValueError If options, geometry or an existing checkpoint are incompatible.

Examples

import tomojax as tj scan = tj.load("scan.nxs") # doctest: +SKIP result = tj.align(scan, mode="cor-then-pose") # doctest: +SKIP recon = tj.reconstruct(result.scan) # doctest: +SKIP

project

project(
    geometry: Geometry,
    volume: np.ndarray | jax.Array,
    *,
    grid: Grid | None = None,
    devices: Device | Sequence[Device] | None = None,
) -> jax.Array
Defined in src/tomojax/_workflow.py:169

Project a volume through the supplied geometry.

Parameters

geometry : Geometry Per-view geometry defining the matched projector. volume : numpy.ndarray or jax.Array Volume in (x, y, z) order. grid : Grid or None, optional Voxel grid; None uses the geometry's grid. devices : jax.Device or sequence of jax.Device or None, optional Devices sharing the views; None uses the current default device.

Returns

jax.Array Line-integral projections, shape (views, detector.nv, detector.nu).

Raises

ValueError If dimensions or geometry metadata do not match the operation.

Examples

import tomojax as tj scan = tj.load("scan.nxs") # doctest: +SKIP projections = tj.project(scan.geometry, tj.reconstruct(scan).volume) # doctest: +SKIP

backproject

backproject(
    geometry: Geometry,
    projections: np.ndarray | jax.Array,
    *,
    grid: Grid | None = None,
    devices: Device | Sequence[Device] | None = None,
) -> jax.Array
Defined in src/tomojax/_workflow.py:210

Apply the exact transpose of the forward projector.

Parameters

geometry : Geometry Per-view geometry defining the matched projector. projections : numpy.ndarray or jax.Array Line integrals in (view, v, u) order. grid : Grid or None, optional Voxel grid; None uses the geometry's grid. devices : jax.Device or sequence of jax.Device or None, optional Devices sharing the views; None uses the current default device.

Returns

jax.Array Adjoint volume, shape (grid.nx, grid.ny, grid.nz).

Raises

ValueError If dimensions or geometry metadata do not match the operation.

Examples

import tomojax as tj scan = tj.load("scan.nxs") # doctest: +SKIP volume = tj.backproject(scan.geometry, scan.projections) # doctest: +SKIP

save

save(path: str | PathLike[str], item: Scan | Reconstruction | Alignment) -> None
Defined in src/tomojax/_workflow.py:102

Save a scan, reconstruction or alignment as a TomoJAX dataset.

Reconstructions and alignments are saved with their scan (projections, geometry and any pose corrections), so the file reloads with load and load_reconstruction.

Parameters

path : str or path-like Output dataset path; an existing file is overwritten. item : Scan, Reconstruction or Alignment Scan or result to save with its geometry and metadata.

Returns

None Write the dataset to disk.

Raises

TypeError If item is not a scan, reconstruction or alignment. ValueError If the output format is unsupported.

Examples

import tomojax as tj scan = tj.load("scan.nxs") # doctest: +SKIP tj.save("copy.nxs", scan) # doctest: +SKIP

load_reconstruction

load_reconstruction(path: str | PathLike[str]) -> Reconstruction
Defined in src/tomojax/_workflow.py:63

Load a reconstruction saved by save or tomojax recon.

Parameters

path : str or path-like Saved reconstruction dataset.

Returns

Reconstruction Volume, source scan and stored reconstruction settings.

Raises

ValueError If the dataset has no reconstructed volume. FileNotFoundError If the input does not exist.

Examples

import tomojax as tj recon = tj.load_reconstruction("recon.nxs") # doctest: +SKIP

Scan

class Scan(
    projections: np.ndarray | jax.Array,
    geometry: ScanGeometry,
    name: str = 'sample',
    corrections: tuple[Correction, ...] = (),
    source: ProjectionDataset | None = None,
)
Defined in src/tomojax/_scan.py:49

Projections and the geometry that produced them.

projections are (views, rows, columns) line integrals (absorption, not intensities); geometry describes every view, and carries the reconstruction grid and the detector. A scan loaded from a file or returned by align may carry per-view pose corrections, which every operation applies (see poses). corrections records how its projections were made from detector frames (see tomojax.corrections), and is saved with it.

Parameters

projections : numpy.ndarray or jax.Array Line integrals, not intensities, shaped (views, rows, columns). geometry : ScanGeometry Per-view geometry carrying the reconstruction grid and detector. name : str, optional Sample name. corrections : tuple of Correction, optional Record of corrections already applied to the projections. source : ProjectionDataset or None, optional Source metadata retained for saving and provenance.

Raises

ValueError If projection dimensions disagree with the detector or view count.

Examples

import numpy as np import tomojax as tj grid = tj.Grid(8, 8, 1, 1.0, 1.0, 1.0) detector = tj.Detector(8, 1, 1.0, 1.0) geometry = tj.ParallelGeometry(grid, detector, [0.0, 90.0]) scan = tj.Scan(np.zeros((2, 1, 8), dtype=np.float32), geometry)

Scan.corrected

corrected(*steps: Step, batch_views: int | None = None) -> Scan

The scan with line-integral steps applied (see tomojax.corrections).

Steps on counts or transmission need the frames: use load_frames and Frames.corrected.

Parameters

*steps : Step Line-integral correction steps, applied in order. batch_views : int or None, optional Positive views per batch; None chooses automatically.

Returns

Scan Corrected projections and geometry, with appended correction records.

Raises

ValueError If a step needs raw counts or transmission, or settings are invalid.

Scan.cropped

cropped(rows: slice, cols: slice) -> Scan

Crop a contiguous detector window and move the detector to match.

Parameters

rows : slice Nonempty contiguous detector row window. cols : slice Nonempty contiguous detector column window.

Returns

Scan Cropped projections with the detector centre moved to match.

Raises

ValueError If a window is empty or has a step other than one.

Scan.selected

selected(views: slice | Sequence[int] | np.ndarray) -> Scan

Select views and their geometry in acquisition order.

Parameters

views : slice, sequence of int or numpy.ndarray Forward slice, increasing indices or nonempty boolean view mask.

Returns

Scan Selected projections and their geometry, in acquisition order.

Raises

ValueError If indices are empty, unordered, repeated or out of bounds.

Scan.grid

@property
grid: Grid

The reconstruction grid.

Returns

Grid Reconstruction grid carried by the geometry.

Scan.detector

@property
detector: Detector

The detector.

Returns

Detector Detector carried by the geometry.

Scan.angles

@property
angles: np.ndarray

Rotation angle of each view, in degrees.

Returns

numpy.ndarray One rotation angle per view, in degrees.

Scan.poses

@property
poses: np.ndarray | None

Per-view pose corrections, (views, 6) as alpha, beta, phi, dx, dz, dy.

Rotations in radians, translations in the geometry's length unit, in the detector frame. None when the scan carries no corrections.

Returns

numpy.ndarray or None Pose corrections with shape (views, 6), or None when absent.

Scan.with_poses

with_poses(poses: np.ndarray | None) -> Scan

The scan with its per-view corrections replaced by poses.

The table has one row per view and six columns, in poses's order, units and detector translation frame. It is relative to the calibrated geometry, not to the scan's current corrections: applying the same table twice does not double the motion. None removes corrections while retaining the calibrated axis, detector and grid.

Use this to attach externally estimated or interpolated poses to a full scan after fitting selected views. Interpolate small corrections in acquisition order, not wrapped rotation angle; no interpolation or additional alignment is performed here.

Parameters

poses : numpy.ndarray or None Replacement (views, 6) correction table; None removes all corrections.

Returns

Scan Scan with replacement poses and unchanged calibrated geometry.

Raises

ValueError If the pose table does not have shape (views, 6).

Scan.from_astra

@classmethod
from_astra(
    projections: np.ndarray,
    proj_geom: Mapping[str, Any],
    vol_geom: Mapping[str, Any],
    *,
    name: str = 'sample',
) -> Scan

A scan from ASTRA Toolbox data and geometries.

projections are in ASTRA's (rows, views, columns) layout; proj_geom is a cone or cone_vec geometry and vol_geom a 3-D volume geometry, as astra.create_proj_geom and astra.create_vol_geom make them. The scan's grid is the ASTRA volume, and its volumes are ASTRA's (z, y, x) arrays transposed to (x, y, z). The fitted circular orbit is the scan's geometry; any departure from it (tilts, wobble, per-view corrections) becomes poses. ASTRA turns the source and detector about the object and TomoJAX the object, so angles run the other way.

Parameters

projections : numpy.ndarray ASTRA line integrals in (rows, views, columns) order. proj_geom : mapping ASTRA cone or cone_vec projection geometry. vol_geom : mapping ASTRA three-dimensional volume geometry. name : str, optional Sample name.

Returns

Scan Imported cone-beam scan, including departures from its fitted orbit as poses.

Raises

ValueError If ASTRA geometry or data shape is unsupported or inconsistent.

Scan.combine

@classmethod
combine(scans: Sequence[Scan], *, name: str | None = None) -> Scan

One scan of the same object from several cone-beam scans, view after view.

For scans that differ in their source and detector arrangement (a multi-orbit scan, a tall sample scanned in stacked sections): each becomes a ConeSegments segment. They share scans[0]'s grid and need equal detector pixel counts.

Parameters

scans : sequence of Scan Nonempty cone-beam scans with equal detector pixel counts. name : str or None, optional Combined sample name; None keeps the first scan's name.

Returns

Scan Concatenated views on the first scan's reconstruction grid.

Raises

ValueError If scans are empty or their geometry and detector counts are incompatible.

Scan.binned

binned(factor: int) -> Scan

The scan with factor x factor detector pixels averaged into one.

Use it when the detector samples finer than the reconstruction grid (a pixel's footprint at the rotation axis smaller than a voxel): projection cost falls by factor**2 for little change in the volume. Pixels that do not fill a block at the detector's edges are dropped, and the detector centre moves to match.

Parameters

factor : int Positive detector-block side length, in pixels.

Returns

Scan Block-averaged projections and detector geometry; the grid is unchanged.

Raises

ValueError If factor is less than one or leaves no complete detector block.

Scan.to_astra

to_astra() -> tuple[np.ndarray, dict[str, Any], dict[str, Any]]

Export projections and cone-beam geometry for ASTRA.

The inverse of from_astra, for cone-beam scans; transpose a volume (x, y, z) -> (z, y, x) to use it with ASTRA.

Returns

projections : numpy.ndarray Line integrals in ASTRA (rows, views, columns) order. proj_geom : dict ASTRA cone_vec projection geometry. vol_geom : dict ASTRA three-dimensional volume geometry.

Raises

ValueError If the scan is not a supported cone-beam geometry.

Frames

class Frames(
    counts: Any,
    geometry: ScanGeometry,
    flats: Any = None,
    darks: Any = None,
    flat_positions: np.ndarray | None = None,
    white_level: float | None = None,
    view_positions: np.ndarray | None = None,
    exposure_times: np.ndarray | float | None = None,
    flat_exposure_times: np.ndarray | float | None = None,
    name: str = 'sample',
    source: ProjectionDataset | None = None,
)
Defined in src/tomojax/_loading.py:129

Detector frames as recorded, with the geometry of each sample view.

counts are the sample frames, (views, rows, columns), in memory, a memmap or read lazily from the file; flats the frames of the beam alone, with flat_positions the number of views recorded before each (flats taken before and after a scan are interpolated between); darks the frames with the beam off, both in memory or lazy like counts. Scanners that calibrate their flat field record a white_level instead. view_positions places each view among the flats, in the units of flat_positions (by default view i at i + 1/2; selected keeps it). corrected makes the Scan of line integrals. Made by load_frames.

Parameters

counts : array-like Sample detector frames, shape (views, rows, columns); may be lazy. geometry : ScanGeometry Geometry of every sample view, including the grid and detector. flats : array-like or None, optional Open-beam calibration frames; may be lazy. darks : array-like or None, optional Beam-off calibration frames; may be lazy. flat_positions : numpy.ndarray or None, optional Number of sample views preceding each flat frame. white_level : float or None, optional Calibrated open-beam count level, instead of flat frames. view_positions : numpy.ndarray or None, optional Sample positions in flat-position units; default is i + 1/2. exposure_times : numpy.ndarray or float or None, optional Sample exposure durations in seconds, one per view or a common duration. flat_exposure_times : numpy.ndarray or float or None, optional Flat exposure durations in seconds, one per flat or a common duration. name : str, optional Sample name. source : ProjectionDataset or None, optional Original dataset metadata retained when loading from a file.

Raises

ValueError If frame shape or view-position count does not match the geometry.

Frames.views

@property
views: int

The number of sample views.

Returns

int Number of sample frames.

Frames.corrected

corrected(
    *steps: Step,
    epsilon: float = 1e-06,
    batch_views: int | None = None,
    binning: int = 1,
) -> Scan

Correct detector counts to line integrals with the requested steps.

Steps run by the data they act on: counts steps first, then the flat and dark fields, transmission steps, the log, and line-integral steps, each in the order given (see tomojax.corrections). epsilon must be finite and positive; it bounds the flat field and transmission below. Views are corrected on the device in batches of batch_views, a positive integer. Automatic view batches target 32 MiB for simple pipelines, or 256 MiB including additional workspace such as the padded FFT arrays needed for Paganin phase retrieval.

binning averages blocks of binning x binning detector pixels of the line integrals, as Scan.binned does, without holding the unbinned stack on the host unless a step such as RejectViews or a non-row step needs it. Pixels where the flat does not exceed the dark by three standard errors of their means take no absorption; the flat-field record counts them. Detector-derived output grids follow this resolution; grids supplied by the file or caller remain unchanged.

Parameters

*steps : Step Corrections applied in domain order, then in the order supplied. epsilon : float, optional Positive finite lower bound for flat field and transmission. batch_views : int or None, optional Positive views per device batch; None selects a workspace-based size. binning : int, optional Positive factor for averaging detector blocks after correction.

Returns

Scan Corrected line integrals with matching geometry and correction records.

Raises

ValueError If calibration, correction settings or batch dimensions are invalid.

Frames.cropped

cropped(rows: slice, cols: slice) -> Frames

These frames' block of detector rows and cols, the detector moved to match.

A lazily read file reads only that block, of the flats and darks too. An automatically chosen axial-parallel output grid follows the window; an explicit grid, or a non-axial output box, is retained.

Parameters

rows : slice Nonempty contiguous detector row window. cols : slice Nonempty contiguous detector column window.

Returns

Frames Selected frames with matching geometry and calibration.

Raises

ValueError If the selection is empty, out of bounds or not ordered as required.

Frames.selected

selected(views: slice | Sequence[int] | np.ndarray) -> Frames

These sample views only, with their geometry.

Take a forward slice, increasing integer indices or a nonempty mask. Each view keeps its place among the flats (view_positions), so its flat is interpolated as before.

Parameters

views : slice, sequence of int or numpy.ndarray Forward slice, increasing indices or nonempty boolean sample-view mask.

Returns

Frames Selected frames with matching geometry and calibration.

Raises

ValueError If the selection is empty, out of bounds or not ordered as required.

Reconstruction

class Reconstruction(
    volume: np.ndarray | jax.Array,
    scan: Scan,
    method: str,
    info: Mapping[str, object],
)
Defined in src/tomojax/_scan.py:766

A reconstructed volume, the scan it came from and how it was made.

volume is (nx, ny, nz) on grid, in the reciprocal of the geometry's length unit (a NumPy or JAX array; np.asarray gives NumPy). info records the method's settings.

Parameters

volume : numpy.ndarray or jax.Array Volume in (x, y, z) order and reciprocal geometry-length units. scan : Scan Input scan, including the output grid and any inferred geometry. method : str Reconstruction method used. info : mapping Resolved method settings and solver records.

Reconstruction.grid

@property
grid: Grid

The grid the volume is on, the scan's.

Returns

Grid Reconstruction grid carried by the scan.

Alignment

class Alignment(
    volume: np.ndarray | jax.Array,
    scan: Scan,
    poses: np.ndarray,
    info: Mapping[str, object],
)
Defined in src/tomojax/_scan.py:803

The result of align.

volume is the reconstruction the alignment converged with. scan is the input scan with the estimated geometry and per-view poses applied: reconstruct it, align it again or save it. poses are its (views, 6) poses (see Scan.poses), always a table, zero where nothing moved; info is the solver's record.

Parameters

volume : numpy.ndarray or jax.Array Reconstruction used by the alignment, in (x, y, z) order. scan : Scan Scan with estimated geometry and per-view corrections applied. poses : numpy.ndarray Complete (views, 6) correction table, zero where nothing moved. info : mapping Solver record and resolved alignment settings.

ConeBeam

class ConeBeam(
    source_to_axis: float,
    source_to_detector: float,
    detector_roll_deg: float = 0.0,
    detector_pitch_deg: float = 0.0,
    detector_yaw_deg: float = 0.0,
    axis_offset: float = 0.0,
    *,
    source_height: float = 0.0,
)
Defined in src/tomojax/core/geometry/cone.py:22

Source and detector placement in the lab frame, shared by every view.

The beam travels along +y. The source sits at (0, -source_to_axis, source_height) and the detector plane at y = source_to_detector - source_to_axis; the rotation axis passes through (axis_offset, 0, 0), so the magnification at the axis is source_to_detector / source_to_axis. axis_offset is the lab-CT centre-of-rotation offset: the axis's lateral distance from the line through the source and the unshifted detector centre, in physical units. source_height is the calibrated lab-frame z position of the source and unshifted detector centre, not an editable per-view object correction. Detector.center offsets the detector relative to that centre. Roll, pitch and yaw rotate the detector about its centre: roll about the beam (y), pitch about detector u (x) and yaw about detector v (z), applied in that order.

Parameters

source_to_axis : float Source-to-axis distance in physical units; strictly positive. source_to_detector : float Source-to-detector distance, greater than source_to_axis. detector_roll_deg : float, optional Detector roll about the lab y axis, in degrees. detector_pitch_deg : float, optional Detector pitch about the x axis, in degrees. detector_yaw_deg : float, optional Detector yaw about the z axis, in degrees. axis_offset : float, optional Lateral x displacement of the rotation axis, in physical units. source_height : float, optional Lab-frame z position of the source and unshifted detector centre, in physical units.

Raises

ValueError If 0 < source_to_axis < source_to_detector does not hold.

ConeBeam.magnification

@property
magnification: float

Magnification of the rotation axis on the detector.

Returns

float Source-to-detector divided by source-to-axis distance.

ConeBeam.source

source() -> np.ndarray

Source position in the lab frame.

Returns

numpy.ndarray Lab-frame source (x, y, z) position, in physical units.

ConeBeam.detector_frame

detector_frame(detector: Detector) -> tuple[np.ndarray, np.ndarray, np.ndarray]

Lab position of the detector centre and its unit u and v directions.

Parameters

detector : Detector Detector with its physical in-plane centre offset.

Returns

centre : numpy.ndarray Lab-frame detector-centre position in physical units. u_dir : numpy.ndarray Lab-frame unit direction of increasing detector columns. v_dir : numpy.ndarray Lab-frame unit direction of increasing detector rows.

ConeBeam.to_dict

to_dict() -> dict[str, float]

Return JSON-compatible metadata.

Returns

dict Source distances, axis offset and detector rotations, ready for JSON.

ConeGeometry

class ConeGeometry(
    grid: Grid,
    detector: Detector,
    angles: Sequence[float],
    beam: ConeBeam,
    tilt_deg: float = 0.0,
    tilt_about: str = 'x',
    axis_unit: tuple[float, float, float] | None = None,
)
Defined in src/tomojax/core/geometry/cone.py:154

Cone-beam scan of a sample rotating about +z, or a tilted axis.

Poses follow ParallelGeometry (tilt_deg == 0) or LaminographyGeometry: pose_for_view returns world_from_object, and the object's +z axis is the rotation axis, turned by angles[i] degrees at view i. axis_unit, a lab-frame unit vector, replaces the tilt for an arbitrary calibrated axis. The beam is described by beam; projectors read it to trace rays from the source to each pixel.

Parameters

grid : Grid Reconstruction voxel grid. detector : Detector Detector dimensions, pitches and physical centre. angles : sequence of float View rotation angles in degrees, in acquisition order. beam : ConeBeam Source and detector placement in the lab frame. tilt_deg : float, optional Axis tilt away from +z, in degrees; defaults to zero. tilt_about : {'x', 'z'} Tilt convention used when axis_unit is absent. axis_unit : tuple of float or None, optional Explicit lab-frame rotation axis, replacing the tilt settings.

ConeGeometry.pose_for_view

pose_for_view(i: int) -> PoseMatrix

Return the world-from-object pose for one view.

Parameters

i : int Zero-based view index.

Returns

tuple of tuple of float Row-major 4 x 4 homogeneous world-from-object transform.

Raises

IndexError If the view index is outside the angle sequence.

ConeGeometry.poses

poses(*, angles: np.ndarray | None = None) -> np.ndarray

Return every view's world-from-object pose as an (n, 4, 4) FP64 array.

angles, in degrees, replaces the geometry's own view angles.

Parameters

angles : numpy.ndarray or None, optional Replacement view angles in degrees; None uses this geometry's angles.

Returns

numpy.ndarray World-from-object poses with shape (views, 4, 4), in float64.

ConeGeometry.rotation_axis

rotation_axis() -> np.ndarray

Return the lab-frame unit rotation axis.

Returns

numpy.ndarray Three-component lab-frame unit rotation axis.

Raises

ValueError If the tilt convention is unsupported for a nonzero tilt.

ConeGeometry.geometry_metadata

geometry_metadata() -> dict[str, object]

Return the metadata that reconstructs this geometry from a saved dataset.

Returns

dict Serializable beam and rotation-axis metadata.

ConeGeometry.rays_for_view

rays_for_view(i: int) -> RayPair

Return world-frame ray callbacks (source origin, unit direction) for inspection.

Parameters

i : int Zero-based view index.

Returns

tuple of callable Origin and unit-direction callbacks taking detector pixel indices (u, v).

Detector

class Detector(
    nu: int,
    nv: int,
    du: float,
    dv: float,
    center: Vec2 = (lambda: (0.0, 0.0))(),
)
Defined in src/tomojax/core/geometry/base.py:221

Regular detector plane metadata.

center is the detector centre's (u, v) offset in its plane, in the same physical units as du and dv.

Parameters

nu, nv : int Detector column and row counts. du, dv : float Pixel pitches along u and v, in the geometry's physical length unit. center : tuple of float, optional Detector-plane (u, v) centre offset in physical units; defaults to zero.

Raises

TypeError If counts are not integers or centre coordinates are not real numbers. ValueError If center does not have two components.

Detector.to_dict

to_dict() -> DetectorDict

Return JSON-compatible detector metadata.

Returns

dict Pixel counts, pitches and centre under the file key det_center.

Detector.from_dict

@classmethod
from_dict(data: Mapping[str, Any]) -> Detector

Return the detector that a to_dict mapping describes.

Parameters

data : mapping Complete metadata written by to_dict, including det_center.

Returns

Detector Detector described by the metadata.

Raises

KeyError If pixel counts or pitches are missing. ValueError If the centre is missing or has the wrong number of coordinates.

Grid

class Grid(
    nx: int,
    ny: int,
    nz: int,
    vx: float,
    vy: float,
    vz: float,
    vol_origin: Vec3 | None = None,
    vol_center: Vec3 | None = None,
)
Defined in src/tomojax/core/geometry/base.py:73

Regular voxel grid metadata.

TomoJAX treats vol_origin as the physical location of voxel (0, 0, 0)'s centre. When vol_origin is omitted, the default centred convention places voxel centres on coordinates (i - (n/2 - 0.5)) * v along each axis. vol_center can override that default centre while still deriving the voxel (0, 0, 0) location from the grid dimensions and voxel sizes. If both are provided, vol_origin is the authoritative placement.

Parameters

nx, ny, nz : int Voxel counts along x, y and z. vx, vy, vz : float Voxel pitches in a consistent physical length unit. vol_origin : tuple of float or None, optional Physical centre of voxel (0, 0, 0); takes precedence over vol_center. vol_center : tuple of float or None, optional Physical grid centre when vol_origin is absent; defaults to (0, 0, 0).

Raises

TypeError If counts are not integers or placement coordinates are not real numbers. ValueError If a placement vector does not have three components.

Grid.resampled

resampled(shape: tuple[int, int, int]) -> Grid

Return a grid with new voxel counts and the same physical extent.

Voxel pitches change to preserve the outer cell edges and centre, not the positions of the first and last voxel centres. Explicit origins remain authoritative over vol_center. No volume data is resampled.

Parameters

shape : tuple of int Positive voxel counts (nx, ny, nz) for the returned grid.

Returns

Grid Grid covering the same physical box at the requested resolution.

Raises

ValueError If shape does not contain three positive counts. TypeError If a count is not an integer.

Examples

Grid(100, 80, 60, 0.2, 0.3, 0.4).resampled((50, 40, 30)).vx 0.4

Grid.to_dict

to_dict() -> GridDict

Return JSON-compatible grid metadata.

Returns

dict Grid counts, voxel pitches and any explicit placement, ready for JSON.

LaminographyGeometry

class LaminographyGeometry(
    grid: Grid,
    detector: Detector,
    angles: Sequence[float],
    tilt_deg: float = 30.0,
    tilt_about: str = 'x',
)
Defined in src/tomojax/core/geometry/lamino.py:38

Laminography geometry with tilted rotation axis (parallel-ray model).

  • Beam direction is fixed along +y (as in ParallelGeometry).
  • Rotation axis is tilted away from +z by tilt_deg within a chosen plane. With tilt_about='x' the axis leans towards +y (beam-aligned laminography); with tilt_about='z' the axis leans towards +x. Each view rotates the object around this axis by angles[i], in degrees.

Frame convention:

  • pose_for_view(i) returns T_world_from_obj for the sample frame, where the object's +z axis equals the nominal rotation axis. At theta=0, T is the fixed alignment S (generally not identity) that maps e_z -> axis.

Parameters

grid : Grid Reconstruction voxel grid. detector : Detector Detector dimensions, pitches and physical centre. angles : sequence of float View rotation angles in degrees, in acquisition order. tilt_deg : float, optional Axis tilt away from +z, in degrees; defaults to 30. tilt_about : {'x', 'z'} Tilt convention: x leans towards +y; z leans towards +x.

LaminographyGeometry.axis_unit_lab

@property
axis_unit_lab: np.ndarray

The rotation axis in the lab frame, a unit vector.

Returns

numpy.ndarray Three-component unit rotation axis in lab coordinates.

Raises

ValueError If tilt_about is unsupported for a nonzero tilt.

LaminographyGeometry.pose_for_view

pose_for_view(i: int) -> PoseMatrix

World-from-object pose in sample frame; rotation about object +z.

We align the object's +z axis to the laminography axis once via S, then rotate around +z by view angle theta: R = S @ R_z(theta). The returned 4x4 poses are suitable for the projector contract (world_from_object).

Parameters

i : int Zero-based view index.

Returns

tuple of tuple of float Row-major 4 x 4 homogeneous world-from-object transform.

Raises

IndexError If the view index is outside the angle sequence.

LaminographyGeometry.rays_for_view

rays_for_view(i: int) -> RayPair

Return detector ray callbacks for inspection tools.

Parameters

i : int Zero-based view index.

Returns

tuple of callable Origin and unit-direction callbacks taking detector pixel indices (u, v).

ParallelGeometry

class ParallelGeometry(grid: Grid, detector: Detector, angles: Sequence[float])
Defined in src/tomojax/core/geometry/parallel.py:17

Parallel-beam CT geometry with axis-aligned detector.

  • World frame: detector lies in (x,z) plane; rays along +y.
  • angles are the view angles, in degrees. View i rotates the object around +z by phi = angles[i]; pose_for_view returns T_world_from_obj = Rz(phi). At phi=0, T = I.

Parameters

grid : Grid Reconstruction voxel grid. detector : Detector Detector dimensions, pitches and physical centre. angles : sequence of float View rotation angles in degrees, in acquisition order.

ParallelGeometry.pose_for_view

pose_for_view(i: int) -> PoseMatrix

Return the world-from-object pose for one view.

Parameters

i : int Zero-based view index.

Returns

tuple of tuple of float Row-major 4 x 4 homogeneous world-from-object transform.

Raises

IndexError If the view index is outside the angle sequence.

ParallelGeometry.rays_for_view

rays_for_view(i: int) -> RayPair

Return detector rays for one view.

Parameters

i : int Zero-based view index.

Returns

tuple of callable Origin and unit-direction callbacks taking detector pixel indices (u, v).

RegionEstimate

class RegionEstimate(scan: Scan, info: Mapping[str, object])
Defined in src/tomojax/_region.py:27

The resized scan and the evidence/uncertainty behind its reconstruction grid.

Projection samples, detector calibration and per-view poses are unchanged. info distinguishes a conditionally selected region from a broad survey; neither is a certificate of the object's physical support.

Parameters

scan : Scan Scan with the proposed reconstruction grid; measurements are unchanged. info : mapping Selection evidence, uncertainty, memory budget and limitations.

RegionEstimate.grid

@property
grid: Grid

The proposed reconstruction grid, also carried by scan.

Returns

Grid Proposed reconstruction grid carried by the scan.

estimate_center

estimate_center(scan: Scan) -> Scan
Defined in src/tomojax/_workflow.py:657

Estimate a parallel scan's rotation centre without reconstructing a volume.

Returns the scan with its absolute physical detector-u centre set, available as result.detector.center[0]; no pixels are shifted. For a cropped or binned preview, add result.detector.center[0] - preview.detector.center[0] to the full scan's centre rather than copying the preview's. Needs corrected projections of an unposed axial ParallelGeometry with usable near-opposite views (within two degrees). The estimate uses row-wise gradient correlations and can be ambiguous for repetitive structure. Source metadata, when present, records pair offsets, conditional uncertainty, alternative matches and row trends without changing the input. Physical centre and sample motion are aliases; conditional matching intervals do not cover motion.

Parameters

scan : Scan Unposed axial parallel projections with near-opposite views.

Returns

Scan Scan with the inferred absolute physical detector-u centre; pixels are unchanged.

Raises

ValueError If geometry is unsupported or no usable near-opposite views exist.

Examples

import tomojax as tj scan = tj.estimate_center(tj.load("scan.nxs")) # doctest: +SKIP recon = tj.reconstruct(scan) # doctest: +SKIP

estimate_region

estimate_region(scan: Scan) -> RegionEstimate
Defined in src/tomojax/_region.py:279

Select a reconstruction region from an already calibrated laminography scan.

A broad FBP preview tests axial focus isolation. Sixty-step positive reconstructions on balanced fitting/validation views then compare candidate depths using ordinary and high-pass projection error. Disagreement or multiple strong focus peaks returns a broad detector-derived survey instead of inventing a thin object.

Detector-pitch isotropic voxels are preferred. The output may be coarser to budget eight volume work arrays plus measured data on the working device; info reports this explicitly. The region is a conditional reconstruction choice, not physical support or an accuracy certificate. Inspect the reconstruction and independent views. No measured projections, poses, detector calibration or solver defaults are changed.

Parameters

scan : Scan Calibrated oblique laminography scan of corrected line integrals.

Returns

RegionEstimate Resized scan and evidence distinguishing a selected region from a broad survey.

Raises

ValueError If the geometry is not calibrated oblique laminography.

Examples

import tomojax as tj scan = tj.load("laminography.nxs") # doctest: +SKIP region = tj.estimate_region(scan) # doctest: +SKIP recon = tj.reconstruct(region.scan, "cgls") # doctest: +SKIP

reconstruct_slabs

reconstruct_slabs(
    frames: Frames,
    method: Literal['fbp', 'fourier', 'sirt', 'mlem'],
    *,
    grid: Grid | None = None,
    corrections: Sequence[Step] = (),
    config: FBPConfig | FourierConfig | SIRTConfig | MLEMConfig | None = None,
    warm_start: bool | None = None,
    epsilon: float = 1e-06,
) -> Iterator[Iterator[tuple[slice, Reconstruction]]]
Defined in src/tomojax/_workflow.py:514

Correct raw frames and reconstruct bounded z slabs.

Use with reconstruct_slabs(frames, "fbp", ...) as slabs: and iterate over (z_slice, reconstruction). The slice indexes the requested output grid; each reconstruction retains its physical global grid, genuine corrected source rows (including interpolation neighbors), and correction records. Volumes are owned float32 host arrays. Results remain valid after advancing or closing the iterator; collecting them retains their volume and projections.

This supports cone-beam FDK, unposed axial parallel beams and whole-row line-integral corrections such as Stripes, not Paganin or view rejection. SIRT/OSEM also require matching detector and voxel planes; warm_start=True uses FBP. Method configurations retain the same meaning as in reconstruct. CUDA consumes corrected rows without a corrected-projection host round trip. Raw reads are prefetched within bounded storage and calibration is reused. The context drains pending work on normal completion, early exit or failure. Raw frames and calibration arrays must remain unchanged inside the context. Cone FDK corrects host row bands in device-sized view batches and retains the complete acquisition's weights while reconstructing each slab.

Parameters

frames : Frames Raw detector frames for cone FDK or unposed axial parallel-beam geometry. method : {'fbp', 'fourier', 'sirt', 'mlem'} Slab reconstruction method. grid : Grid or None, optional Output grid; None uses the frames' grid. corrections : sequence of Step, optional Whole-row line-integral corrections applied before reconstruction. config : FBPConfig or FourierConfig or SIRTConfig or MLEMConfig or None, optional Method-specific settings, as for reconstruct. warm_start : bool or None, optional Start SIRT/OSEM from FBP; None uses the method's default. epsilon : float, optional Positive finite lower bound for flat field and transmission.

Yields

iterator of tuple of (slice, Reconstruction) Context-managed slab iterator; each z slice indexes the requested grid.

Raises

ValueError If geometry, method, corrections or configuration do not support slabs.

Examples

import tomojax as tj frames = tj.load_frames("raw_scan.nxs") # doctest: +SKIP with tj.reconstruct_slabs(frames, "fbp") as slabs: # doctest: +SKIP ... for z_slice, recon in slabs: ... print(z_slice, recon.volume.shape)

On this page