Tutorial

We offer some examples on GitHub. To run them, git clone the whole repository. Then do:

(@v1.9) pkg> activate examples/
  Activating project at `~/.julia/dev/RadonKA.jl/examples`

julia> using Pluto; Pluto.run()

Radon transform

The radon transform only requires the image (or volume) and some angles:

using RadonKA, ImageShow, ImageIO, TestImages

img = Float32.(testimage("resolution_test_512"))

angles = range(0f0, 2f0π, 500)[begin:end-1]

# 0.196049 seconds (145 allocations: 1009.938 KiB)
@time sinogram = radon(img, angles);

adjoint Radon (backproject) transform

# 0.268649 seconds (147 allocations: 1.015 MiB)
@time backproject = RadonKA.backproject(sinogram, angles);

# in Pluto or Jupyter
simshow(sinogram)

[simshow(img) simshow(backproject)]

Left is the original sample and right the simple backprojection.

Odd sized arrays

For the backproject of an odd-sized array is an ambiguity since we don't know whether the original array was even-sized or odd. As default, we return an even-sized array. But this can be changed with the following:

julia> x = randn((5,5));

julia> y = radon(x, range(0,2π, 5))
5×5 view(::Array{Float64, 3}, :, :, 1) with eltype Float64:
 -0.428792   -2.37766   -0.0232206  -1.71798   -0.428792
  0.887089    2.63651   -0.342234    0.831      0.887089
 -1.62588    -0.519691   0.751784   -0.496471   0.0921012
 -0.40562    -0.508413   0.301532    3.64494   -0.40562
 -0.0232206  -1.71798   -0.428792   -2.37766   -0.0232206

julia> backproject(y, range(0, 2π, 5))
6×6 view(::Array{Float64, 3}, :, :, 1) with eltype Float64:
 0.0   0.0       0.0        0.0        0.0        0.0
 0.0   0.0       0.220737  -4.31006   -0.250533   0.0
 0.0   0.608334  2.3983    -0.459407  -0.830887  -0.372184
 0.0  -2.30254   1.05955   -1.79816   -2.16964   -0.589353
 0.0   2.66828   8.35716    5.49946    5.12798    1.93006
 0.0   0.0       1.29879   -5.53732   -0.593869   0.0

julia> backproject(y, range(0, 2π, 5), geometry=RadonParallelCircle(5, -size(y,1)÷2:size(y,1)÷2))
5×5 view(::Array{Float64, 3}, :, :, 1) with eltype Float64:
  0.0       0.220737  -4.31006   -0.250533   0.0
  0.608334  2.3983    -0.459407  -0.830887  -0.372184
 -2.30254   1.05955   -1.79816   -2.16964   -0.589353
  2.66828   8.35716    5.49946    5.12798    1.93006
  0.0       1.29879   -6.28911   -0.593869   0.0

Filtered Backprojection

In the absence of noise, the filtered backprojection works well:

#   0.252915 seconds (171 allocations: 13.664 MiB)
@time filtered_backproject = RadonKA.backproject_filtered(sinogram, angles);

CUDA Support

RadonKA.jl supports CUDA and usually provides a 10-20x speedup on typical RTX 3xxx or 4xxx GPUs. Pay attention that the element type of the array/img should be Float32 for good speedup. In my case we used a AMD Ryzen 5 5600X 6-Core Processor and a CUDA RTX 3060 Super.

using CUDA

img_c = CuArray(img);
angles_c = CuArray(angles);

# 0.005611 seconds (8.95 k CPU allocations: 363.828 KiB) (2 GPU allocations: 998.047 KiB, 0.26% memmgmt time)
CUDA.@time CUDA.@sync sinogram_c = radon(img_c, angles_c);

3D example

Simply attach a third trailing dimension to the array. The radon transform is computed along the first and second dimension. The third dimension is just a batch dimension.

volume = randn(Float32,(512, 512, 512));
volume_c = CuArray(randn(Float32,(512, 512, 512)));

# 86.795338 seconds (153 allocations: 498.039 MiB, 0.02% gc time)
@time radon(volume, angles);

# 2.527153 seconds (8.95 k CPU allocations: 363.703 KiB) (2 GPU allocations: 498.027 MiB, 0.06% memmgmt time)
CUDA.@time CUDA.@sync radon(volume_c, angles_c);