Tomos is a library with many tools for tomographic reconstruction, with the following features:
- Modular system, where projectors, geometries, volumes and algorithmic skeletons are all independent and can be mixed and matched.
- Tomos supports a general model for distributed computing, enabling the resulting algorithms to run on clusters
- It is not bound to CUDA, MATLAB, or Python, although Python bindings and GPU computing are supported
- Written in modern C++, with OO / generic programming style like STL, enabling abstractions without performance penalties.
- It has efficient CPU implementations for the algorithms.
- Support for 2D, 3D or higher dimensional reconstructions.
Reconstructing a Shepp-Logan phantom using SIRT:
#include "tomos/tomos.hpp"
int main() {
using T = float;
constexpr tomo::dimension D = 2_D;
int size = 128;
auto v = tomo::volume<D, T>(size);
auto g = tomo::geometry::parallel<D, T>(v, size, size);
auto f = tomo::modified_shepp_logan_phantom<T>(v);
auto k = tomo::dim::joseph<D, T>(v);
auto p = tomo::forward_projection<D, T>(f, g, k);
auto x = tomo::reconstruction::sirt(v, g, k, p);
tomo::ascii_plot(x);
}
The following libraries are required:
External:
- glm header only mathematics library mimicking GLSL
- boost::program_options for portable program options
- (optional) zeromq for communicating with visualization servers
- (optional) boost::hana is used to generate the Python bindings.
- (optional) CUDA (>= 7.0)
Provided as submodules
- Catch, for unit tests
- fmt as an iostream replacement
- bulk for distributed computing
- cpptoml for reading specification and configuration files
- (optional) RECAST3D as an visualization server
- (optional) pybind11 to generate Python bindings
The following build tools should be available:
- CMake (>= 3.0)
- Modern C++ compiler (with support for at least C++17), e.g. GCC >= 7.0 or clang >= 4.0
The library is being tested on Fedora 24 and Arch Linux, but the code should be portable to other platforms.
The core of the library is header only, so it does not have to be built itself. We start with initializing the submodules:
git submodule init
git submodule update --remote
To build the examples:
cd build
cmake ..
make
The resulting binaries will be in the bin
folder.
To generate the Python bindings:
cd python/build
cmake .
make
The Python bindings can be used through tomo.py
in the Python
folder, which also adds some rudimentary plotting functionality on top of the bindings.
To build with ZMQ (and MPI), run instead of cmake .
:
cmake -DWITH_MPI=on -DWITH_ZMQ=on .
CUDA support is experimental and has no public build interface.
First of all, have a look at the examples provided in the examples
folder.
There are four core components that are used for reconstruction:
tomo::volume
represents the volume geometry, i.e. the part of space in which the image object resides.tomo::dim
is the namespace for the 'discrete integration methods' (also called interpolators, projectors or kernels).closest
projects any point on the ray to the closest voxellinear
does D-dimensional linear interpolation around the ray point to the surrounding voxelsjoseph
does (D-1) dimensional linear interpolation by considering points on the ray that have integer coordinates in one fixed dimension.
tomo::geometry
is the namespace for the various acquisition geometriescone_beam
dual_axis_parallel
dynamic_cone_beam
fan
helical_cone_beam
laminography
list
is a list of lines without any implied stucture.parallel<2_D>
parallel<3_D>
tomosynthesis
trajectory
is the base class for cone-beam-like geometries where the source and the (position and tilt of the) detector follow a given path.
tomo::image
represents the image data, there is only one phantomshepp_logan<2_D>
shepp_logan<3_D>
modified_shepp_logan<2_D>
modified_shepp_logan<3_D>
These can be used together completely independently. The reason is that we take the following approach to these concepts:
- A geometry acts as nothing more than a container of lines, so you can write:
for (auto line : geometry) {
// use line
}
- A discrete integration method takes a line, and produces a number of 'matrix elements', that contain the voxel (as an index), and the attenuation coefficient (value of the matrix element):
for (auto element : projector(line)) {
// element.index is the voxel
// element.value is the coefficient
}
Using this approach, many interesting algorithms can be written in an efficient but flexible manner.
There are also some standard algorithms implemented, including ART
, SART
, and SIRT
.
The Python bindings expose the different concepts (images, volumes, geometries and dims) as well as the standard implemented algorithms.