# \[ANN\] RadonKA.jl - A simple (exponential) Radon Transform in Julia

**URL:** https://discourse.julialang.org/t/ann-radonka-jl-a-simple-exponential-radon-transform-in-julia/107127
**Category:** Package Announcements
**Created:** [December 4, 2023, 5:50pm UTC](https://discourse.julialang.org/t/ann-radonka-jl-a-simple-exponential-radon-transform-in-julia/107127 "2023-12-04T17:50:55Z")
**Posts on this page:** 4
**Page:** 1

<div class="post-metadata">

### Author: ![roflmaostc](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/roflmaostc/32/30123_2.png) [@roflmaostc](https://discourse.julialang.org/u/roflmaostc)
#### Post date: [December 4, 2023, 5:50pm UTC](https://discourse.julialang.org/t/ann-radonka-jl-a-simple-exponential-radon-transform-in-julia/107127/1 "2023-12-04T17:50:55Z")

</div>

Hi!

I created a package called [RadonKA.jl](https://github.com/roflmaostc/RadonKA.jl) which provides a parallel [Radon](https://en.wikipedia.org/wiki/Radon_transform) and inverse Radon pair.

## What can it do?

Further, it provides an [exponential Radon transform](https://www.jstor.org/stable/2101055) which does not only calculate the line integral but also weights each value with an exponential decreasing factor depending on the distance to a circular boundary.

It’s all based on tracing rays through the pixel grid and weighting the absorption according to the length of the intersection with a cell.

## Performance

The implementation is rather naive and totally ignores cache efficiency. But, based on [KernelAbstractions.jl](https://github.com/JuliaGPU/KernelAbstractions.jl) we utilize CPU threading and we also tested the CUDA backend.  
I’m surprised that the performance is very similiar to Matlab’s Radon transform and [the Astra toolbox](https://www.astra-toolbox.com/). See details of the benchmark [here](https://roflmaostc.github.io/RadonKA.jl/dev/benchmark/).

## Simple example

It’s not registered yet (in 3 days), but try it out with:

```julia
julia> ]add https://github.com/roflmaostc/RadonKA.jl

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);

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

```

 ![sinogram](https://global.discourse-cdn.com/julialang/original/3X/d/a/dab00e0df34cbab9ad0069f4c1d959be38ceee1d.png)

## What’s next?

This package is relatively young and experimental, so please try it out and report bugs (also the reason why I post it here 🙂)! I’m willing to improve it. I provide [some examples](https://github.com/roflmaostc/RadonKA.jl/tree/main/examples).  
Further, I will work on an interface where rays don’t need to be parallel but ray angles can be specified separately. This include special cases such as Fan Beam Tomography.  
Cone Beam would be more tricky, since I don’t trace 3D paths currently, only 2D slices in a 3D volume.

So yes I’m excited since it really helps already with my work regarding [Volumetric Additive Manufacturing](https://www.nature.com/articles/s41467-020-14630-4). Especially, the exponential Radon transform was important for my work, and I didn’t find any efficient implementation in any framework.

Best,

Felix

---

<div class="post-metadata">

### Author: ![roflmaostc](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/roflmaostc/32/30123_2.png) [@roflmaostc](https://discourse.julialang.org/u/roflmaostc)
#### Post date: [February 6, 2024, 11:15pm UTC](https://discourse.julialang.org/t/ann-radonka-jl-a-simple-exponential-radon-transform-in-julia/107127/2 "2024-02-06T23:15:13Z")

</div>

I just tagged a new release of RadonKA.jl. The new features are [documented here](https://roflmaostc.github.io/RadonKA.jl/dev/geometries/)

There is some performance improvements but most notably there is now a way to specify the geometry of your ray propagation.  
For that you describe the entrance and exit point of each ray inside the `RadonFlexibleCircle` constructor.

For example:

```julia
using RadonKA, ImageShow

angles = [0]

# output image size
N = 200

sinogram = zeros((N - 1, length(angles)))
sinogram[1:5:end] .= 1
geometry_cone = RadonFlexibleCircle(N, 
                          -(N-1)÷2:(N-1)÷2, # entrance position
                          range(-(N-1)÷4, (N-1)÷4, N-1)) # exit position

projected_cone = iradon(sinogram, angles; geometry=geometry_cone);

simshow(projected_cone, γ=0.01)

```

![parallel_geometry_cone](https://global.discourse-cdn.com/julialang/original/3X/7/f/7f8505944f08e4a8a324a1bc50b8bf383e79cfa6.png)

And also the attenuated (or exponential) Radon transform got some documentation.  
Rays are getting attenuated with \exp(-x \cdot \mu) depending on the distance to the circle.

```julia
projected_exp = iradon(sinogram, angles; geometry=geometry_extreme, μ=0.04);

simshow(projected_exp)

```

![parallel_geometry_mu](https://global.discourse-cdn.com/julialang/original/3X/0/6/06be17b0573469396d0990ffcdafaec5bf84e2ee.png)

Of course registered reverse rules for automatic differentation are available for both `radon` and `iradon`.

---

<div class="post-metadata">

### Author: ![roflmaostc](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/roflmaostc/32/30123_2.png) [@roflmaostc](https://discourse.julialang.org/u/roflmaostc)
#### Post date: [April 12, 2024, 10:23pm UTC](https://discourse.julialang.org/t/ann-radonka-jl-a-simple-exponential-radon-transform-in-julia/107127/3 "2024-04-12T22:23:44Z")

</div>

Just a bit of an update:

# Rename of iradon

`iradon` was renamed to `backproject` to indicate that no filtering is done.  
There is also `backproject_filtered` to do the classical filtered backprojection.

# Spatially Varying Absorption

Also I’m going to add [soon](https://github.com/roflmaostc/RadonKA.jl/pull/12) the option that the absorption can be spatially varying. In this example we place a small box which absorbs a lot of light intensity.

```julia-auto
μ = 0.5 .* box((N, N), (2, 50));

projected_1 = backproject(sinogram, angles, μ=μ);
projected_2 = backproject(sinogram, angles .+ π / 4, μ=μ);

[simshow(projected_1) simshow(projected_2)]

```

 ![mu_spatially_backprojected](https://global.discourse-cdn.com/julialang/original/3X/8/b/8b0392e93ca7c02179e684217667db5b268998d8.png)

# Benchmarks

I’m a bit disappointed that [torch-radon](https://github.com/carterbox/torch-radon) beats us by a factor of 5-10 on both GPUs and CPUs.  
From reading the source code I don’t see really why.  
Maybe some motivated people spot performance penalties in [my critical lines](https://github.com/roflmaostc/RadonKA.jl/blob/6bdc4509edd2792c3519ab49a95b7422999632ff/src/radon.jl#L180). 😃

---

<div class="post-metadata">

### Author: ![sepehr](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/sepehr/32/210542_2.png) [@sepehr](https://discourse.julialang.org/u/sepehr)
#### Post date: [July 11, 2024, 2:27pm UTC](https://discourse.julialang.org/t/ann-radonka-jl-a-simple-exponential-radon-transform-in-julia/107127/4 "2024-07-11T14:27:54Z")

</div>

Looks cool!
