CERN / TIGRE

TIGRE: Tomographic Iterative GPU-based Reconstruction Toolbox
BSD 3-Clause "New" or "Revised" License
527 stars 180 forks source link

Twin Robotic Computed Tomography Geometries / ASTRA #515

Closed wittlsn closed 5 months ago

wittlsn commented 5 months ago

Hello TIGRE team! I am a PhD student at the Deggendorf Institute of Technology where we are working with a twin robotic computed tomography scanner. I usually use the astra toolbox for reconstruction, but I wanted to try out the many algorithms implemented in the TIGRE toolbox and the cool features like the multi GPU! I found it rather unintuitive to convert the complex arbitrary geometry into TIGRE, so I've added a utility function. I tested the results and made a short colab example with the conversion from astra to TIGRE (I thought it might be interesting for others).

https://colab.research.google.com/drive/1c6tEySsv63zIdkHvo6agg3O2vJoKYTC1?usp=sharing

With our twin robot CT system we have correction values for each projection. I found the TIGRE interface rather unintuitive, especially compared to the Astra 'cone_vec' interface. I took a quick look at the TIGRE cuda files and found that in the forward and backprojector the interface is more or less the same as the Astra 'cone_vec' geometry. Is it worth looking into this and maybe making a more "arbitrary" python interface for TIGRE? I might look into it when I have some spare time.

Greetings Simon

AnderBiguri commented 5 months ago

Hi Simon,

Thanks, this is fantastic work, and indeed super useful. #383 mentions this, because indeed, if you have a standard CBCT, TIGRE geometry is more intuitive, but with arbitrary motions TIGRE becomes quite complex to define, and ASTRA is quite good for that.

I am correct then assuming that your function ArbitrarySourceDetectorFixedObject is essentially equivalent to from_ASTRA_geo_to_TIGRE_geo()?

Also: what do you mean to make a more arbitrary interface? you mean changing the TIGRE geo in general to be more vector like, as ASTRA does?

wittlsn commented 5 months ago

Hi, the ArbitrarySourceDetectorFixedObject function allows reconstruction with the astra geometries (tested on real data from our system), this is correct but the result is not 100% the same. I calculate a virtual origin with the source and detector positions (should be stable for limit data acquisitions). This is why the volumes can vary with a constant offset.

I just had a quick look at the cuda files, but it seems that in the projector the 3D position of the source and detector is needed?

https://github.com/CERN/TIGRE/blob/master/Common/CUDA/ray_interpolated_projection.cu#L142

So I thought it might be worth looking into whether an interface can be made for this geometry / data? I am new to the framework so I do not have a good overview :D

AnderBiguri commented 5 months ago

the ArbitrarySourceDetectorFixedObject function allows reconstruction with the astra geometries

This is wonderful!

This is why the volumes can vary with a constant offset.

What do you mean here?

I just had a quick look at the cuda files, but it seems that in the projector the 3D position of the source and detector is needed?

That parameter you are linking there is the location of the origin of the detector in "projection geometry". Basically encoding the detector offset. Its the world coordinates in "projection geometry" for pixel (0,0) in the detector. Note that the "projection geometry" is this slightly strange geometry where the first voxel of the volume is always at (0,0,0) and the voxel sizes are always (1,1,1). The entire rest of the world is rotated and scaled accordingly. It makes the main loop at L193 much more efficient.

So I thought it might be worth looking into whether an interface can be made for this geometry / data?

To have an interface in this "projection geometry" may be possible, but no sure if desirable, as its a bit complex and not human readable easily. However, this geometry is computed from the TIGRE geometry at: https://github.com/CERN/TIGRE/blob/master/Common/CUDA/ray_interpolated_projection.cu#L632 So it would be possible to change the type of geometry that the CUDA code takes in. However I think that the best way to do so is still to do it directly in python, as you did in this PR.

wittlsn commented 5 months ago

What do you mean here?

We do not know exactly the origin of our CT trajectory because we use a pose estimation algorithm and get the projection geometries relative to a phantom. So I implemented this function:

https://github.com/wittlsn/TIGRE/blob/roboct_thd/Python/tigre/utilities/common_geometry.py#L301

If the origin is known, the source and detector positions should be transformed before using the function. Then the volumes should be reconstructed on the same volume grid.

So it would be possible to change the type of geometry that the CUDA code takes in. However I think that the best way to do so is still to do it directly in python, as you did in this PR.

OK!

AnderBiguri commented 5 months ago

If the origin is known, the source and detector positions should be transformed before using the function

Would it make perhaps more sense to have as an input trajectory_center_mm (I assume this is the location of the axis of rotation?) with a default value that is the most common (e.g. (0,0,0)). Then have the possibility for the user to input either a value, or None. If a value is input, then the correction happens inside. If None, your function is called.

This would keep a functionality (correcting for trajectory center) locate in a single place, making it hopefully more intuitive to use. What do you think?

AnderBiguri commented 5 months ago

Thanks! Are you OK with me merging this?

wittlsn commented 5 months ago

Yes! Thanks for the quick replies! I have also updated the colab example.

AnderBiguri commented 5 months ago

Fantastic :) And thanks again for contributing, TIGRE keeps alive thanks of people like you :)