SliceRecon
Overview
The SliceRecon project defines three main objects:
- A projection server, that listens to incoming projection data.
- A reconstructor, that can reconstruct arbitrarily oriented slices from projection data.
- A visualization server, that listens to requests from a visualization server, and fulfils them by calling the reconstructor.
Furthermore, it has a notion of a plugin, which is a stand alone server that can postprocess reconstructed slices before sending them to the visualization server.
The incoming, internal, and outgoing communication is all handled by the TomoPackets library.
Projection server
The projection server listens for incoming data packets. It expects first packets that describe the tomographic scan. This is done using:
GeometrySpecification
: information on where the object is in relation to the acquisition geometry.ScanSettings
packet: information on the number of darks and flats.- A packet describing the acquisition geometry, such as a
ConeVecGeometry
packet.
After receiving these packets, the server is able to process ProjectionData
packets. First the darks and flats should be sent, after which standard
projections can be streamed to the projection server.
Reconstructor
The reconstructor is an internal object that decouples the projection server from the visualization server, and has no public interface. It receives projection data from the projection server, and fulfills reconstruction requests from the visualization server.
Visualization server
The visualization server registers itself to the visualization software by
sending a MakeScene
packet. It then waits to receive KillScene
, SetSlice
and RemoveSlice
packets. If it receives a SetSlice
packet, it requests a new
slice reconstruction from the reconstructor. It sends this reconstructed slice
back either to the visualization software using a SliceData
packet if there
are no active plugins, or to the first plugin.
Plugin
A plugin is a simple server, that registers itself to the visualization server,
and listens to incoming SliceData
packets. It then manipulates the data in
this SliceData
packet, before sending it along to the next plugin in line, or
to the visualization software. The plugin system thus has the following structure:
There can be more than one plugin, but they are assumed to be applied one after the other. The dashed line is only used if there are no plugins.
Conventions
Multi-dimensional arrays
- Volume data is stored in x-y-z order (from major to minor).
- Projection data is stored in row-column order (from major to minor).
SliceRecon architecture
An overview of the design of SliceRecon is as follows.
When projection data comes into SliceRecon, it gets put into an ‘inactive buffer’. As soon as enough projection data is processed and in main RAM, we ‘upload’ to the GPU. This happens in a number of steps:
- pre-process
- flat fielding
- FDK scaling
- filtering
- phase retrieval
- …
- transpose sinogram
- upload to GPU
There are two modes, alternating and continuous. In ‘alternating’ mode, we always reconstruct from the last complete set of projections. In ‘continuous mode’ we reconstruct with for each projection the most recent data.
Data flowing in/out of SliceRecon
Solid lines happen within SliceRecon, while dashed lines are communicated using TomoPackets.
Solver implementation
The solver can reconstruct an arbitrarily oriented slice from the full 3D projection data.
Instead of considering the full 3D volume, we setup our geometry by constructing an object volume that consists of the central axial slice C only. If we want to reconstruct an arbitrary slice S, we can transform S into C using a combination of a translation vector \delta from the center of slice S onto the center of C (and thus the full 3D volume), a rotation \mathcal{R}, and optionally a scale factor which does not have to be used when slices are of fixed size.
For a cone-beam geometry, we can define each projection by a source position \vec{s}, a detector position \vec{d}, and two axes \vec{u} and \vec{v} that define pixel distances on the detector.
We then transform each projection according to:
If we then reconstruct with the transformed geometry, we are effectively using a geometry in which the arbitrary slice S has become the central slice, without having to adjust the projection data. This is the basic idea behind the solver implementation: we adjust the geometry on the fly for each slice that we are interested in, and then run a standard backprojection algorithm.